ICU-7502 fix ASCIIsms - merge from branch /branches/srl/ascii7502

X-SVN-Rev: 28382
This commit is contained in:
Steven R. Loomis 2010-07-28 16:08:12 +00:00
parent d5d873c99d
commit 592b73e980
23 changed files with 566 additions and 195 deletions

View file

@ -1,7 +1,7 @@
/*
*******************************************************************************
*
* Copyright (C) 1999-2009, International Business Machines
* Copyright (C) 1999-2010, International Business Machines
* Corporation and others. All Rights Reserved.
*
*******************************************************************************
@ -534,3 +534,51 @@ uprv_compareInvEbcdicAsAscii(const char *s1, const char *s2) {
}
}
}
U_INTERNAL uint8_t* U_EXPORT2
uprv_aestrncpy(uint8_t *dst, const uint8_t *src, int32_t n)
{
uint8_t *orig_dst = dst;
if(n==-1) {
n = uprv_strlen((const char*)src)+1; /* copy NUL */
}
/* copy non-null */
while(*src && n>0) {
*(dst++) = asciiFromEbcdic[*(src++)];
n--;
}
/* pad */
while(n>0) {
*(dst++) = 0;
n--;
}
return orig_dst;
}
U_INTERNAL uint8_t* U_EXPORT2
uprv_eastrncpy(uint8_t *dst, const uint8_t *src, int32_t n)
{
uint8_t *orig_dst = dst;
if(n==-1) {
n = uprv_strlen((const char*)src)+1; /* copy NUL */
}
/* copy non-null */
while(*src && n>0) {
char ch = ebcdicFromAscii[*(src++)];
if(ch == 0) {
ch = ebcdicFromAscii[0x3f]; /* questionmark (subchar) */
}
*(dst++) = ch;
n--;
}
/* pad */
while(n>0) {
*(dst++) = 0;
n--;
}
return orig_dst;
}

View file

@ -1,7 +1,7 @@
/*
*******************************************************************************
*
* Copyright (C) 1999-2009, International Business Machines
* Copyright (C) 1999-2010, International Business Machines
* Corporation and others. All Rights Reserved.
*
*******************************************************************************
@ -83,4 +83,23 @@ uprv_compareInvEbcdicAsAscii(const char *s1, const char *s2);
# error Unknown charset family!
#endif
/**
* Copy EBCDIC to ASCII
* @internal
* @see uprv_strncpy
*/
U_INTERNAL uint8_t* U_EXPORT2
uprv_aestrncpy(uint8_t *dst, const uint8_t *src, int32_t n);
/**
* Copy ASCII to EBCDIC
* @internal
* @see uprv_strncpy
*/
U_INTERNAL uint8_t* U_EXPORT2
uprv_eastrncpy(uint8_t *dst, const uint8_t *src, int32_t n);
#endif

View file

@ -281,22 +281,44 @@
#define ULOC_KEYWORD_AND_VALUES_CAPACITY 100
/**
* Character separating keywords from the locale string
* different for EBCDIC - TODO
* Invariant character separating keywords from the locale string
* @stable ICU 2.8
*/
#define ULOC_KEYWORD_SEPARATOR '@'
/**
* Character for assigning value to a keyword
* Unicode code point for '@' separating keywords from the locale string.
* @see ULOC_KEYWORD_SEPARATOR
* @internal
*/
#define ULOC_KEYWORD_SEPARATOR_UNICODE 0x40
/**
* Invariant character for assigning value to a keyword
* @stable ICU 2.8
*/
#define ULOC_KEYWORD_ASSIGN '='
/**
* Character separating keywords
* Unicode code point for '=' for assigning value to a keyword.
* @see ULOC_KEYWORD_ASSIGN
* @internal
*/
#define ULOC_KEYWORD_ASSIGN_UNICODE 0x3D
/**
* Invariant character separating keywords
* @stable ICU 2.8
*/
#define ULOC_KEYWORD_ITEM_SEPARATOR ';'
/**
* Unicode code point for ';' separating keywords
* @see ULOC_KEYWORD_ITEM_SEPARATOR
* @internal
*/
#define ULOC_KEYWORD_ITEM_SEPARATOR_UNICODE 0x3B
/**
* Constants for *_getLocale()
* Allow user to select whether she wants information on

View file

@ -3414,7 +3414,7 @@ DecimalFormat::toPattern(UnicodeString& result, UBool localized) const
}
if (fRoundingIncrement != NULL) {
for(i=0; i<fRoundingIncrement->getCount(); ++i) {
roundingDigits.append((UChar)fRoundingIncrement->getDigit(i));
roundingDigits.append(zero+(fRoundingIncrement->getDigitValue(i))); // Convert to Unicode digit
}
roundingDecimalPos = fRoundingIncrement->getDecimalAt();
}

View file

@ -47,6 +47,7 @@
/**
* This is the zero digit. The base for the digits returned by getDigit()
* Note that it is the platform invariant digit, and is not Unicode.
*/
#define kZero '0'
@ -329,6 +330,14 @@ DigitList::getDigit(int32_t i) {
return fDecNumber->lsu[count-i-1] + '0';
}
// copied from DigitList::getDigit()
uint8_t
DigitList::getDigitValue(int32_t i) {
int32_t count = fDecNumber->digits;
U_ASSERT(i<count);
return fDecNumber->lsu[count-i-1];
}
// -------------------------------------
// Appends the digit to the digit list if it's not out of scope.
// Ignores the digit, otherwise.

View file

@ -113,7 +113,7 @@ template class U_I18N_API MaybeStackHeaderAndArray<decNumber, char, DEFAULT_DIGI
*
* digitList exponent = decNumber exponent + digit count
*
* digitList, digits are chars, '0' - '9'
* digitList, digits are platform invariant chars, '0' - '9'
* decNumber, digits are binary, one per byte, 0 - 9.
*
* (decNumber library is configurable in how digits are stored, ICU has configured
@ -174,6 +174,7 @@ public:
* inefficient, and the interaction with the exponent value is confusing.
* Best avoided.
* TODO: remove this function once all use has been replaced.
* TODO: describe alternative to append()
* @param digit The digit to be appended.
*/
void append(char digit);
@ -318,10 +319,30 @@ public:
void setCount(int32_t c);
int32_t getCount() const;
/**
* Set the digit in platform (invariant) format, from '0'..'9'
* @param i index of digit
* @param v digit value, from '0' to '9' in platform invariant format
*/
void setDigit(int32_t i, char v);
/**
* Get the digit in platform (invariant) format, from '0'..'9' inclusive
* @param i index of digit
* @return invariant format of the digit
*/
char getDigit(int32_t i);
/**
* Get the digit's value, as an integer from 0..9 inclusive.
* Note that internally this value is a decNumberUnit, but ICU configures it to be a uint8_t.
* @param i index of digit
* @return value of that digit
*/
uint8_t getDigitValue(int32_t i);
private:
/*
* These data members are intentionally public and can be set directly.

View file

@ -1319,7 +1319,7 @@ SimpleDateFormat::processOverrideString(const Locale &locale, const UnicodeStrin
UBool moreToProcess = TRUE;
while (moreToProcess) {
int32_t delimiterPosition = str.indexOf((UChar)ULOC_KEYWORD_ITEM_SEPARATOR,start);
int32_t delimiterPosition = str.indexOf(ULOC_KEYWORD_ITEM_SEPARATOR_UNICODE,start);
if (delimiterPosition == -1) {
moreToProcess = FALSE;
len = str.length() - start;
@ -1327,7 +1327,7 @@ SimpleDateFormat::processOverrideString(const Locale &locale, const UnicodeStrin
len = delimiterPosition - start;
}
UnicodeString currentString(str,start,len);
int32_t equalSignPosition = currentString.indexOf((UChar)ULOC_KEYWORD_ASSIGN,0);
int32_t equalSignPosition = currentString.indexOf(ULOC_KEYWORD_ASSIGN_UNICODE,0);
if (equalSignPosition == -1) { // Simple override string such as "hebrew"
nsName.setTo(currentString);
ovrField.setToBogus();

View file

@ -875,9 +875,8 @@ collectCurrencyNames(const char* locale,
// Add currency ISO code.
(*currencySymbols)[*total_currency_symbol_count].IsoCode = iso;
(*currencySymbols)[*total_currency_symbol_count].currencyName = (UChar*)uprv_malloc(sizeof(UChar)*3);
(*currencySymbols)[*total_currency_symbol_count].currencyName[0] = iso[0];
(*currencySymbols)[*total_currency_symbol_count].currencyName[1] = iso[1];
(*currencySymbols)[*total_currency_symbol_count].currencyName[2] = iso[2];
// Must convert iso[] into Unicode
u_charsToUChars(iso, (*currencySymbols)[*total_currency_symbol_count].currencyName, 3);
(*currencySymbols)[*total_currency_symbol_count].flag = NEED_TO_BE_DELETED;
(*currencySymbols)[(*total_currency_symbol_count)++].currencyNameLen = 3;

View file

@ -22,6 +22,9 @@
#include "cstring.h"
#include "putilimp.h"
#include "toolutil.h"
#include "uinvchar.h"
#include <stdio.h>
static UBool compareWithNAN(double x, double y);
static void doAssert(double expect, double got, const char *message);
@ -452,6 +455,56 @@ static void TestErrorName(void){
}
}
#define AESTRNCPY_SIZE 13
static const char * dump_binline(uint8_t *bytes) {
static char buf[512];
int32_t i;
for(i=0;i<13;i++) {
sprintf(buf+(i*3), "%02x ", bytes[i]);
}
return buf;
}
static void Test_aestrncpy(int32_t line, const uint8_t *expect, const uint8_t *src, int32_t len)
{
uint8_t str_buf[AESTRNCPY_SIZE] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
uint8_t *ret;
log_verbose("\n%s:%d: Beginning test of uprv_aestrncpy(dst, src, %d)\n", __FILE__, line, len);
ret = uprv_aestrncpy(str_buf, src, len);
if(ret != str_buf) {
log_err("\n%s:%d: FAIL: uprv_aestrncpy returned %p expected %p\n", __FILE__, line, (void*)ret, (void*)str_buf);
}
if(!uprv_memcmp(str_buf, expect, AESTRNCPY_SIZE)) {
log_verbose("\n%s:%d: OK - compared OK.", __FILE__, line);
log_verbose("\n%s:%d: expected: %s", __FILE__, line, dump_binline(expect));
log_verbose("\n%s:%d: got : %s\n", __FILE__, line, dump_binline(str_buf));
} else {
log_err ("\n%s:%d: FAIL: uprv_aestrncpy output differs", __FILE__, line);
log_err ("\n%s:%d: expected: %s", __FILE__, line, dump_binline(expect));
log_err ("\n%s:%d: got : %s\n", __FILE__, line, dump_binline(str_buf));
}
}
static void TestString(void)
{
uint8_t str_tst[AESTRNCPY_SIZE] = { 0x81, 0x4b, 0x5c, 0x82, 0x25, 0x00, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f };
uint8_t str_exp1[AESTRNCPY_SIZE] = { 0x61, 0x2e, 0x2a, 0x62, 0x0a, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
uint8_t str_exp2[AESTRNCPY_SIZE] = { 0x61, 0x2e, 0x2a, 0x62, 0x0a, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
uint8_t str_exp3[AESTRNCPY_SIZE] = { 0x61, 0x2e, 0x2a, 0x62, 0x0a, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff };
/* test #1- copy with -1 length */
Test_aestrncpy(__LINE__, str_exp1, str_tst, -1);
Test_aestrncpy(__LINE__, str_exp1, str_tst, 6);
Test_aestrncpy(__LINE__, str_exp2, str_tst, 5);
Test_aestrncpy(__LINE__, str_exp3, str_tst, 8);
}
void addPUtilTest(TestNode** root);
static void addToolUtilTests(TestNode** root);
@ -464,7 +517,7 @@ addPUtilTest(TestNode** root)
/* addTest(root, &testIEEEremainder, "putiltst/testIEEEremainder"); */
addTest(root, &TestErrorName, "putiltst/TestErrorName");
addTest(root, &TestPUtilAPI, "putiltst/TestPUtilAPI");
addTest(root, &TestString, "putiltst/TestString");
addToolUtilTests(root);
}

View file

@ -482,7 +482,7 @@ UChar *DecimalFormatTest::ReadAndConvertFile(const char *fileName, int32_t &ulen
amtReadNoBOM = amtRead - 3;
if (fileSize<3 || uprv_strncmp(fileBuf, "\xEF\xBB\xBF", 3) != 0) {
// TODO: restore this check.
// errln("Test data file %s is missing its BOM", fileName);
errln("Test data file %s is missing its BOM", fileName);
fileBufNoBOM = fileBuf;
amtReadNoBOM = amtRead;
}

View file

@ -3244,19 +3244,22 @@ void DateFormatTest::Test6726(void)
strm = fmtm->format(dt, strm);
strs = fmts->format(dt, strs);
/* Locale data is not yet updated
if (strf.charAt(13) == UChar(' ')) {
errln((UnicodeString)"FAIL: Improper formated date: " + strf);
if (strf.charAt(13) == UChar(0x20)) {
errln((UnicodeString)"FAIL: Improper formatted date: " + strf);
}
if (strl.charAt(10) == UChar(' ')) {
errln((UnicodeString)"FAIL: Improper formated date: " + strl);
if (strl.charAt(10) == UChar(0x20)) {
errln((UnicodeString)"FAIL: Improper formatted date: " + strl);
}
*/
if (strm.charAt(10) != UChar(' ')) {
errln((UnicodeString)"FAIL: Improper formated date: " + strm);
logln("strm.charAt(10)=%04X wanted 0x20\n", strm.charAt(10));
if (strm.charAt(10) != UChar(0x0020)) {
errln((UnicodeString)"FAIL: Improper formatted date: " + strm );
}
if (strs.charAt(8) != UChar(' ')) {
errln((UnicodeString)"FAIL: Improper formated date: " + strs);
logln("strs.charAt(10)=%04X wanted 0x20\n", strs.charAt(8));
if (strs.charAt(8) != UChar(0x0020)) {
errln((UnicodeString)"FAIL: Improper formatted date: " + strs);
}
delete fmtf;

View file

@ -2841,6 +2841,7 @@ NumberFormatTest::TestCurrencyFormatForMixParsing() {
const CurrencyAmount* curramt = NULL;
for (uint32_t i = 0; i < sizeof(formats)/sizeof(formats[0]); ++i) {
UnicodeString stringToBeParsed = ctou(formats[i]);
logln(UnicodeString("stringToBeParsed: ") + stringToBeParsed);
Formattable result;
UErrorCode status = U_ZERO_ERROR;
curFmt->parseObject(stringToBeParsed, result, status);
@ -2961,12 +2962,8 @@ NumberFormatTest::TestCurrencyIsoPluralFormat() {
dataerrln((UnicodeString)"can not create instance, locale:" + localeString + ", style: " + k + " - " + u_errorName(status));
continue;
}
// TODO: need to be UChar*
UChar currencyCode[4];
currencyCode[0] = currencyISOCode[0];
currencyCode[1] = currencyISOCode[1];
currencyCode[2] = currencyISOCode[2];
currencyCode[3] = currencyISOCode[3];
u_charsToUChars(currencyISOCode, currencyCode, 4);
numFmt->setCurrency(currencyCode, status);
if (U_FAILURE(status)) {
delete numFmt;

View file

@ -2424,6 +2424,11 @@ void NumberFormatRegressionTest::Test4212072(void) {
errln(UnicodeString("FAIL: ") + type[j] + avail[i].getDisplayName(l) +
" -> \"" + pat +
"\" -> \"" + f2.toPattern(p) + "\"");
} else {
UnicodeString l, p;
logln(UnicodeString("PASS: ") + type[j] + avail[i].getDisplayName(l) +
" -> \"" + pat +
"\"");
}
// Test toLocalizedPattern/applyLocalizedPattern round trip

View file

@ -2250,7 +2250,16 @@ void RBBITest::runUnicodeTestData(const char *fileName, RuleBasedBreakIterator *
// Scan through each test case, building up the string to be broken in testString,
// and the positions that should be boundaries in the breakPositions vector.
//
int spin = 0;
while (tokenMatcher.find()) {
if(tokenMatcher.hitEnd()) {
/* Shouldnt Happen(TM). This means we didn't find the symbols we were looking for.
This occurred when the text file was corrupt (wasn't marked as UTF-8)
and caused an infinite loop here on EBCDIC systems!
*/
fprintf(stderr,"FAIL: hit end of file %s for the %8dth time- corrupt data file?\r", fileName, ++spin);
// return;
}
if (tokenMatcher.start(1, status) >= 0) {
// Scanned a divide sign, indicating a break position in the test data.
if (testString.length()>0) {

File diff suppressed because it is too large Load diff

View file

@ -46,10 +46,11 @@ public:
// The following functions are internal to the regexp tests.
virtual void assertUText(const char *expected, UText *actual, const char *file, int line);
virtual void assertUTextInvariant(const char *invariant, UText *actual, const char *file, int line);
virtual UBool doRegexLMTest(const char *pat, const char *text, UBool looking, UBool match, int32_t line);
virtual UBool doRegexLMTestUTF8(const char *pat, const char *text, UBool looking, UBool match, int32_t line);
virtual void regex_find(const UnicodeString &pat, const UnicodeString &flags,
const UnicodeString &input, int32_t line);
const UnicodeString &input, const char *srcPath, int32_t line);
virtual void regex_err(const char *pat, int32_t errline, int32_t errcol,
UErrorCode expectedStatus, int32_t line);
virtual UChar *ReadAndConvertFile(const char *fileName, int32_t &len, const char *charset, UErrorCode &status);

View file

@ -58,13 +58,13 @@ void IntlTestSimpleDateFormatAPI::testAPI(/*char *par*/)
}
status = U_ZERO_ERROR;
const UnicodeString pattern("yyyy.MM.dd G 'at' hh:mm:ss z");
const UnicodeString override("y=hebr;d=thai;s=arab");
const UnicodeString override_bogus("y=hebr;d=thai;s=bogus");
const UnicodeString pattern("yyyy.MM.dd G 'at' hh:mm:ss z", "");
const UnicodeString override("y=hebr;d=thai;s=arab", ""); /* use invariant converter */
const UnicodeString override_bogus("y=hebr;d=thai;s=bogus", "");
SimpleDateFormat pat(pattern, status);
if(U_FAILURE(status)) {
errln("ERROR: Could not create SimpleDateFormat (pattern)");
errln("ERROR: Could not create SimpleDateFormat (pattern) - %s", u_errorName(status));
}
status = U_ZERO_ERROR;
@ -93,18 +93,20 @@ void IntlTestSimpleDateFormatAPI::testAPI(/*char *par*/)
}
status = U_ZERO_ERROR;
logln(UnicodeString("Override with: ") + override);
SimpleDateFormat ovr1(pattern, override, status);
if(U_FAILURE(status)) {
errln("ERROR: Could not create SimpleDateFormat (pattern, override)");
errln("ERROR: Could not create SimpleDateFormat (pattern, override) - %s", u_errorName(status));
}
status = U_ZERO_ERROR;
SimpleDateFormat ovr2(pattern, override, Locale::getGerman(), status);
if(U_FAILURE(status)) {
errln("ERROR: Could not create SimpleDateFormat (pattern, override, locale)");
errln("ERROR: Could not create SimpleDateFormat (pattern, override, locale) - %s", u_errorName(status));
}
status = U_ZERO_ERROR;
logln(UnicodeString("Override with: ") + override_bogus);
SimpleDateFormat ovr3(pattern, override_bogus, Locale::getGerman(), status);
if(U_SUCCESS(status)) {
errln("ERROR: Should not have been able to create SimpleDateFormat (pattern, override, locale) with a bogus override");

View file

@ -14,12 +14,18 @@
#include "unicode/selfmt.h"
#include "stdio.h"
const UnicodeString SIMPLE_PATTERN = UnicodeString("feminine {feminineVerbValue} other{otherVerbValue}");
#define SIMPLE_PATTERN_STRING "feminine {feminineVerbValue} other{otherVerbValue}"
#define SELECT_PATTERN_DATA 4
#define SELECT_SYNTAX_DATA 10
#define EXP_FORMAT_RESULT_DATA 12
#define NUM_OF_FORMAT_ARGS 3
#define VERBOSE_INT(x) {logln("%s:%d: int %s=%d\n", __FILE__, __LINE__, #x, (x));}
#define VERBOSE_USTRING(text) {logln("%s:%d: UnicodeString %s(%d) = ", __FILE__, __LINE__, #text, text.length()); logln(UnicodeString(" \"")+text+UnicodeString("\";"));}
void SelectFormatTest::runIndexedTest( int32_t index, UBool exec, const char* &name, char* /*par*/ )
{
if (exec) logln("TestSuite SelectFormat");
@ -36,6 +42,8 @@ void SelectFormatTest::runIndexedTest( int32_t index, UBool exec, const char* &n
*/
void SelectFormatTest::selectFormatUnitTest(/*char *par*/)
{
const UnicodeString SIMPLE_PATTERN(SIMPLE_PATTERN_STRING); /* Don't static init this! */
UnicodeString patternTestData[SELECT_PATTERN_DATA] = {
UNICODE_STRING_SIMPLE("fem {femValue} other{even}"),
UNICODE_STRING_SIMPLE("other{odd or even}"),
@ -99,6 +107,7 @@ void SelectFormatTest::selectFormatUnitTest(/*char *par*/)
};
UErrorCode status = U_ZERO_ERROR;
VERBOSE_USTRING(SIMPLE_PATTERN);
SelectFormat* selFmt = new SelectFormat( SIMPLE_PATTERN , status);
if (U_FAILURE(status)) {
dataerrln("ERROR: SelectFormat Unit Test constructor failed in unit tests.- exitting");
@ -109,6 +118,8 @@ void SelectFormatTest::selectFormatUnitTest(/*char *par*/)
logln("SelectFormat Unit Test : Testing SelectFormat pattern syntax.");
for (int32_t i=0; i<SELECT_SYNTAX_DATA; ++i) {
status = U_ZERO_ERROR;
VERBOSE_INT(i);
VERBOSE_USTRING(checkSyntaxData[i]);
selFmt->applyPattern(checkSyntaxData[i], status);
if( status!= expErrorCodes[i] ){
errln("\nERROR: Unexpected result - SelectFormat Unit Test failed to detect syntax error with pattern: "+checkSyntaxData[i]+" and expected status="+ u_errorName(expErrorCodes[i]) + " and resulted status="+u_errorName(status));
@ -188,6 +199,7 @@ void SelectFormatTest::selectFormatUnitTest(/*char *par*/)
*/
void SelectFormatTest::selectFormatAPITest(/*char *par*/)
{
const UnicodeString SIMPLE_PATTERN(SIMPLE_PATTERN_STRING); /* Don't static init this! */
int numOfConstructors =3;
UErrorCode status[3];
SelectFormat* selFmt[3] = { NULL, NULL, NULL };
@ -200,7 +212,7 @@ void SelectFormatTest::selectFormatAPITest(/*char *par*/)
selFmt[0]= new SelectFormat(SIMPLE_PATTERN, status[0]);
if ( U_FAILURE(status[0]) ) {
errln("ERROR: SelectFormat API test constructor with pattern and status failed!");
errln("ERROR: SelectFormat API test constructor with pattern and status failed! with %s\n", u_errorName(status[0]));
return;
}

View file

@ -1,3 +1,4 @@
# Note: Please make sure that this utf-8 file contains a BOM.
# GraphemeBreakTest-5.2.0.txt
# Date: 2009-05-28, 20:37:56 GMT [MD]
#

View file

@ -1,3 +1,4 @@
# Note: Please make sure that this utf-8 file contains a BOM.
# LineBreakTest-5.2.0.txt
# Date: 2009-08-26, 01:14:01 GMT [MD]
#

View file

@ -1,3 +1,4 @@
# Note: Please make sure that this utf-8 file contains a BOM.
# SentenceBreakTest-5.2.0.txt
# Date: 2009-05-28, 20:38:05 GMT [MD]
#

View file

@ -1,3 +1,4 @@
# Note: Please make sure that this utf-8 file contains a BOM.
# WordBreakTest-5.2.0.txt
# Date: 2009-05-28, 20:38:06 GMT [MD]
#

View file

@ -1,4 +1,5 @@

# Note: Please make sure that this utf-8 file contains a BOM.
# Copyright (c) 2010, International Business Machines Corporation and
# others. All Rights Reserved.
#