Add aggressive cancellation for auto suggestion

- Add ring buffer
- Count separator for auto suggestion
- Add a test for ring buffer

Change-Id: Id4a0aa00ceb1b055b8fc96c45e100d318cceb2ab
main
satok 2010-06-01 19:58:36 +09:00
parent ac2b332e94
commit 928ebfeaf8
7 changed files with 176 additions and 38 deletions

View File

@ -1,7 +1,7 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android" <manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.google.android.inputmethod.latin" package="com.google.android.inputmethod.latin"
android:versionCode="9" android:versionCode="9"
android:versionName="0.12"> android:versionName="0.14">
<original-package android:name="com.android.inputmethod.latin" /> <original-package android:name="com.android.inputmethod.latin" />

View File

@ -219,7 +219,7 @@ public class LatinIME extends InputMethodService
private final float FX_VOLUME = -1.0f; private final float FX_VOLUME = -1.0f;
private boolean mSilentMode; private boolean mSilentMode;
private String mWordSeparators; /* package */ String mWordSeparators;
private String mSentenceSeparators; private String mSentenceSeparators;
private VoiceInput mVoiceInput; private VoiceInput mVoiceInput;
private VoiceResults mVoiceResults = new VoiceResults(); private VoiceResults mVoiceResults = new VoiceResults();
@ -955,7 +955,7 @@ public class LatinIME extends InputMethodService
case Keyboard.KEYCODE_DELETE: case Keyboard.KEYCODE_DELETE:
handleBackspace(); handleBackspace();
mDeleteCount++; mDeleteCount++;
LatinImeLogger.logOnDelete(1); LatinImeLogger.logOnDelete();
break; break;
case Keyboard.KEYCODE_SHIFT: case Keyboard.KEYCODE_SHIFT:
handleShift(); handleShift();
@ -996,12 +996,12 @@ public class LatinIME extends InputMethodService
if (primaryCode != KEYCODE_ENTER) { if (primaryCode != KEYCODE_ENTER) {
mJustAddedAutoSpace = false; mJustAddedAutoSpace = false;
} }
LatinImeLogger.logOnInputChar((char)primaryCode);
if (isWordSeparator(primaryCode)) { if (isWordSeparator(primaryCode)) {
handleSeparator(primaryCode); handleSeparator(primaryCode);
} else { } else {
handleCharacter(primaryCode, keyCodes); handleCharacter(primaryCode, keyCodes);
} }
LatinImeLogger.logOnInputChar(1);
// Cancel the just reverted state // Cancel the just reverted state
mJustRevertedSeparator = null; mJustRevertedSeparator = null;
} }

View File

@ -33,7 +33,8 @@ import java.util.Collections;
public class LatinImeLogger implements SharedPreferences.OnSharedPreferenceChangeListener { public class LatinImeLogger implements SharedPreferences.OnSharedPreferenceChangeListener {
private static final String TAG = "LatinIMELogs"; private static final String TAG = "LatinIMELogs";
private static boolean sDBG = false; private static final boolean DBG = true;
private static boolean sLOGPRINT = false;
// SUPPRESS_EXCEPTION should be true when released to public. // SUPPRESS_EXCEPTION should be true when released to public.
private static final boolean SUPPRESS_EXCEPTION = false; private static final boolean SUPPRESS_EXCEPTION = false;
// DEFAULT_LOG_ENABLED should be false when released to public. // DEFAULT_LOG_ENABLED should be false when released to public.
@ -43,6 +44,7 @@ public class LatinImeLogger implements SharedPreferences.OnSharedPreferenceChang
private static final long MINIMUMCOUNTINTERVAL = 20 * DateUtils.SECOND_IN_MILLIS; // 20 sec private static final long MINIMUMCOUNTINTERVAL = 20 * DateUtils.SECOND_IN_MILLIS; // 20 sec
private static final long MINIMUMSENDSIZE = 40; private static final long MINIMUMSENDSIZE = 40;
private static final char SEPARATER = ';'; private static final char SEPARATER = ';';
private static final char NULL_CHAR = '\uFFFC';
private static final int ID_CLICKSUGGESTION = 0; private static final int ID_CLICKSUGGESTION = 0;
private static final int ID_AUTOSUGGESTIONCANCELLED = 1; private static final int ID_AUTOSUGGESTIONCANCELLED = 1;
private static final int ID_AUTOSUGGESTION = 2; private static final int ID_AUTOSUGGESTION = 2;
@ -60,14 +62,17 @@ public class LatinImeLogger implements SharedPreferences.OnSharedPreferenceChang
private static final String PREF_AUTO_COMPLETE = "auto_complete"; private static final String PREF_AUTO_COMPLETE = "auto_complete";
public static boolean sLogEnabled = true; public static boolean sLogEnabled = true;
private static LatinImeLogger sLatinImeLogger = new LatinImeLogger(); /* package */ static LatinImeLogger sLatinImeLogger = new LatinImeLogger();
// Store the last auto suggested word. // Store the last auto suggested word.
// This is required for a cancellation log of auto suggestion of that word. // This is required for a cancellation log of auto suggestion of that word.
private static String sLastAutoSuggestBefore; /* package */ static String sLastAutoSuggestBefore;
private static String sLastAutoSuggestAfter; /* package */ static String sLastAutoSuggestAfter;
/* package */ static String sLastAutoSuggestSeparator;
private ArrayList<LogEntry> mLogBuffer = null; private ArrayList<LogEntry> mLogBuffer = null;
private ArrayList<LogEntry> mPrivacyLogBuffer = null; private ArrayList<LogEntry> mPrivacyLogBuffer = null;
/* package */ RingCharBuffer mRingCharBuffer = null;
private Context mContext = null; private Context mContext = null;
private DropBoxManager mDropBox = null; private DropBoxManager mDropBox = null;
private long mLastTimeActive; private long mLastTimeActive;
@ -116,11 +121,12 @@ public class LatinImeLogger implements SharedPreferences.OnSharedPreferenceChang
mActualCharCount = 0; mActualCharCount = 0;
mLogBuffer = new ArrayList<LogEntry>(); mLogBuffer = new ArrayList<LogEntry>();
mPrivacyLogBuffer = new ArrayList<LogEntry>(); mPrivacyLogBuffer = new ArrayList<LogEntry>();
mRingCharBuffer = new RingCharBuffer(context);
final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context); final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
sLogEnabled = prefs.getBoolean(PREF_ENABLE_LOG, DEFAULT_LOG_ENABLED); sLogEnabled = prefs.getBoolean(PREF_ENABLE_LOG, DEFAULT_LOG_ENABLED);
mThemeId = prefs.getString(KeyboardSwitcher.PREF_KEYBOARD_LAYOUT, mThemeId = prefs.getString(KeyboardSwitcher.PREF_KEYBOARD_LAYOUT,
KeyboardSwitcher.DEFAULT_LAYOUT_ID); KeyboardSwitcher.DEFAULT_LAYOUT_ID);
sDBG = prefs.getBoolean(PREF_DEBUG_MODE, sDBG); sLOGPRINT = prefs.getBoolean(PREF_DEBUG_MODE, sLOGPRINT);
prefs.registerOnSharedPreferenceChangeListener(this); prefs.registerOnSharedPreferenceChangeListener(this);
} }
@ -134,13 +140,14 @@ public class LatinImeLogger implements SharedPreferences.OnSharedPreferenceChang
mActualCharCount = 0; mActualCharCount = 0;
mLogBuffer.clear(); mLogBuffer.clear();
mPrivacyLogBuffer.clear(); mPrivacyLogBuffer.clear();
mRingCharBuffer.reset();
} }
/** /**
* Check if the input string is safe as an entry or not. * Check if the input string is safe as an entry or not.
*/ */
private static boolean checkStringDataSafe(String s) { private static boolean checkStringDataSafe(String s) {
if (sDBG) { if (DBG) {
Log.d(TAG, "Check String safety: " + s); Log.d(TAG, "Check String safety: " + s);
} }
for (int i = 0; i < s.length(); ++i) { for (int i = 0; i < s.length(); ++i) {
@ -152,7 +159,7 @@ public class LatinImeLogger implements SharedPreferences.OnSharedPreferenceChang
} }
private void addCountEntry(long time) { private void addCountEntry(long time) {
if (sDBG) { if (sLOGPRINT) {
Log.d(TAG, "Log counts. (4)"); Log.d(TAG, "Log counts. (4)");
} }
mLogBuffer.add(new LogEntry (time, ID_DELETE_COUNT, mLogBuffer.add(new LogEntry (time, ID_DELETE_COUNT,
@ -171,7 +178,7 @@ public class LatinImeLogger implements SharedPreferences.OnSharedPreferenceChang
} }
private void addThemeIdEntry(long time) { private void addThemeIdEntry(long time) {
if (sDBG) { if (sLOGPRINT) {
Log.d(TAG, "Log theme Id. (1)"); Log.d(TAG, "Log theme Id. (1)");
} }
mLogBuffer.add(new LogEntry (time, ID_THEME_ID, mLogBuffer.add(new LogEntry (time, ID_THEME_ID,
@ -179,7 +186,7 @@ public class LatinImeLogger implements SharedPreferences.OnSharedPreferenceChang
} }
private void addSettingsEntry(long time) { private void addSettingsEntry(long time) {
if (sDBG) { if (sLOGPRINT) {
Log.d(TAG, "Log settings. (1)"); Log.d(TAG, "Log settings. (1)");
} }
final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(mContext); final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(mContext);
@ -189,7 +196,7 @@ public class LatinImeLogger implements SharedPreferences.OnSharedPreferenceChang
} }
private void addVersionNameEntry(long time) { private void addVersionNameEntry(long time) {
if (sDBG) { if (sLOGPRINT) {
Log.d(TAG, "Log Version. (1)"); Log.d(TAG, "Log Version. (1)");
} }
try { try {
@ -203,15 +210,15 @@ public class LatinImeLogger implements SharedPreferences.OnSharedPreferenceChang
} }
private void addExceptionEntry(long time, String[] data) { private void addExceptionEntry(long time, String[] data) {
if (sDBG) { if (sLOGPRINT) {
Log.d(TAG, "Log Exception. (1)"); Log.d(TAG, "Log Exception. (1)");
} }
mLogBuffer.add(new LogEntry(time, ID_EXCEPTION, data)); mLogBuffer.add(new LogEntry(time, ID_EXCEPTION, data));
} }
private void flushPrivacyLogSafely() { private void flushPrivacyLogSafely() {
if (sDBG) { if (sLOGPRINT) {
Log.d(TAG, "Log theme Id. (" + mPrivacyLogBuffer.size() + ")"); Log.d(TAG, "Log obfuscated data. (" + mPrivacyLogBuffer.size() + ")");
} }
long now = System.currentTimeMillis(); long now = System.currentTimeMillis();
Collections.sort(mPrivacyLogBuffer); Collections.sort(mPrivacyLogBuffer);
@ -248,7 +255,7 @@ public class LatinImeLogger implements SharedPreferences.OnSharedPreferenceChang
++mWordCount; ++mWordCount;
String[] dataStrings = (String[]) data; String[] dataStrings = (String[]) data;
if (dataStrings.length < 2) { if (dataStrings.length < 2) {
if (sDBG) { if (DBG) {
Log.e(TAG, "The length of logged string array is invalid."); Log.e(TAG, "The length of logged string array is invalid.");
} }
break; break;
@ -258,7 +265,7 @@ public class LatinImeLogger implements SharedPreferences.OnSharedPreferenceChang
mPrivacyLogBuffer.add( mPrivacyLogBuffer.add(
new LogEntry (System.currentTimeMillis(), tag, dataStrings)); new LogEntry (System.currentTimeMillis(), tag, dataStrings));
} else { } else {
if (sDBG) { if (DBG) {
Log.d(TAG, "Skipped to add an entry because data is unsafe."); Log.d(TAG, "Skipped to add an entry because data is unsafe.");
} }
} }
@ -267,7 +274,7 @@ public class LatinImeLogger implements SharedPreferences.OnSharedPreferenceChang
--mWordCount; --mWordCount;
dataStrings = (String[]) data; dataStrings = (String[]) data;
if (dataStrings.length < 2) { if (dataStrings.length < 2) {
if (sDBG) { if (DBG) {
Log.e(TAG, "The length of logged string array is invalid."); Log.e(TAG, "The length of logged string array is invalid.");
} }
break; break;
@ -277,7 +284,7 @@ public class LatinImeLogger implements SharedPreferences.OnSharedPreferenceChang
mPrivacyLogBuffer.add( mPrivacyLogBuffer.add(
new LogEntry (System.currentTimeMillis(), tag, dataStrings)); new LogEntry (System.currentTimeMillis(), tag, dataStrings));
} else { } else {
if (sDBG) { if (DBG) {
Log.d(TAG, "Skipped to add an entry because data is unsafe."); Log.d(TAG, "Skipped to add an entry because data is unsafe.");
} }
} }
@ -285,7 +292,7 @@ public class LatinImeLogger implements SharedPreferences.OnSharedPreferenceChang
case ID_EXCEPTION: case ID_EXCEPTION:
dataStrings = (String[]) data; dataStrings = (String[]) data;
if (dataStrings.length < 2) { if (dataStrings.length < 2) {
if (sDBG) { if (DBG) {
Log.e(TAG, "The length of logged string array is invalid."); Log.e(TAG, "The length of logged string array is invalid.");
} }
break; break;
@ -293,7 +300,7 @@ public class LatinImeLogger implements SharedPreferences.OnSharedPreferenceChang
addExceptionEntry(System.currentTimeMillis(), dataStrings); addExceptionEntry(System.currentTimeMillis(), dataStrings);
break; break;
default: default:
if (sDBG) { if (DBG) {
Log.e(TAG, "Log Tag is not entried."); Log.e(TAG, "Log Tag is not entried.");
} }
break; break;
@ -301,7 +308,7 @@ public class LatinImeLogger implements SharedPreferences.OnSharedPreferenceChang
} }
private void commitInternal() { private void commitInternal() {
if (sDBG) { if (sLOGPRINT) {
Log.d(TAG, "Commit (" + mLogBuffer.size() + ")"); Log.d(TAG, "Commit (" + mLogBuffer.size() + ")");
} }
flushPrivacyLogSafely(); flushPrivacyLogSafely();
@ -312,7 +319,7 @@ public class LatinImeLogger implements SharedPreferences.OnSharedPreferenceChang
addVersionNameEntry(now); addVersionNameEntry(now);
String s = LogSerializer.createStringFromEntries(mLogBuffer); String s = LogSerializer.createStringFromEntries(mLogBuffer);
if (!TextUtils.isEmpty(s)) { if (!TextUtils.isEmpty(s)) {
if (sDBG) { if (sLOGPRINT) {
Log.d(TAG, "Commit log: " + s); Log.d(TAG, "Commit log: " + s);
} }
mDropBox.addText(TAG, s); mDropBox.addText(TAG, s);
@ -329,7 +336,7 @@ public class LatinImeLogger implements SharedPreferences.OnSharedPreferenceChang
private synchronized void sendLogToDropBox(int tag, Object s) { private synchronized void sendLogToDropBox(int tag, Object s) {
long now = System.currentTimeMillis(); long now = System.currentTimeMillis();
if (sDBG) { if (DBG) {
String out = ""; String out = "";
if (s instanceof String[]) { if (s instanceof String[]) {
for (String str: ((String[]) s)) { for (String str: ((String[]) s)) {
@ -367,7 +374,7 @@ public class LatinImeLogger implements SharedPreferences.OnSharedPreferenceChang
KeyboardSwitcher.DEFAULT_LAYOUT_ID); KeyboardSwitcher.DEFAULT_LAYOUT_ID);
addThemeIdEntry(mLastTimeActive); addThemeIdEntry(mLastTimeActive);
} else if (PREF_DEBUG_MODE.equals(key)) { } else if (PREF_DEBUG_MODE.equals(key)) {
sDBG = sharedPreferences.getBoolean(PREF_DEBUG_MODE, sDBG); sLOGPRINT = sharedPreferences.getBoolean(PREF_DEBUG_MODE, sLOGPRINT);
} }
} }
@ -403,7 +410,9 @@ public class LatinImeLogger implements SharedPreferences.OnSharedPreferenceChang
before = ""; before = "";
after = ""; after = "";
} }
String[] strings = new String[] {before, after}; sLastAutoSuggestSeparator =
String.valueOf(sLatinImeLogger.mRingCharBuffer.getLastChar());
String[] strings = new String[] {before, after, sLastAutoSuggestSeparator};
synchronized (LatinImeLogger.class) { synchronized (LatinImeLogger.class) {
sLastAutoSuggestBefore = before; sLastAutoSuggestBefore = before;
sLastAutoSuggestAfter = after; sLastAutoSuggestAfter = after;
@ -415,21 +424,33 @@ public class LatinImeLogger implements SharedPreferences.OnSharedPreferenceChang
public static void logOnAutoSuggestionCanceled() { public static void logOnAutoSuggestionCanceled() {
if (sLogEnabled) { if (sLogEnabled) {
if (sLastAutoSuggestBefore != null && sLastAutoSuggestAfter != null) { if (sLastAutoSuggestBefore != null && sLastAutoSuggestAfter != null) {
String[] strings = new String[] {sLastAutoSuggestBefore, sLastAutoSuggestAfter}; String[] strings = new String[] {
sLastAutoSuggestBefore, sLastAutoSuggestAfter, sLastAutoSuggestSeparator};
sLatinImeLogger.sendLogToDropBox(ID_AUTOSUGGESTIONCANCELLED, strings); sLatinImeLogger.sendLogToDropBox(ID_AUTOSUGGESTIONCANCELLED, strings);
} }
synchronized (LatinImeLogger.class) {
sLastAutoSuggestBefore = "";
sLastAutoSuggestAfter = "";
}
} }
} }
public static void logOnDelete(int length) { public static void logOnDelete() {
if (sLogEnabled) { if (sLogEnabled) {
sLatinImeLogger.sendLogToDropBox(ID_DELETE_COUNT, length); String mLastWord = sLatinImeLogger.mRingCharBuffer.getLastString();
if (!TextUtils.isEmpty(mLastWord)
&& mLastWord.equalsIgnoreCase(sLastAutoSuggestBefore)) {
logOnAutoSuggestionCanceled();
}
sLatinImeLogger.mRingCharBuffer.pop();
sLatinImeLogger.sendLogToDropBox(ID_DELETE_COUNT, 1);
} }
} }
public static void logOnInputChar(int length) { public static void logOnInputChar(char c) {
if (sLogEnabled) { if (sLogEnabled) {
sLatinImeLogger.sendLogToDropBox(ID_INPUT_COUNT, length); sLatinImeLogger.mRingCharBuffer.push(c);
sLatinImeLogger.sendLogToDropBox(ID_INPUT_COUNT, 1);
} }
} }
@ -478,4 +499,59 @@ public class LatinImeLogger implements SharedPreferences.OnSharedPreferenceChang
return sb.toString(); return sb.toString();
} }
} }
/* package */ static class RingCharBuffer {
final int BUFSIZE = 20;
private Context mContext;
private int mEnd = 0;
/* package */ int length = 0;
private char[] mCharBuf = new char[BUFSIZE];
public RingCharBuffer(Context context) {
mContext = context;
}
private int normalize(int in) {
int ret = in % BUFSIZE;
return ret < 0 ? ret + BUFSIZE : ret;
}
public void push(char c) {
mCharBuf[mEnd] = c;
mEnd = normalize(mEnd + 1);
if (length < BUFSIZE) {
++length;
}
}
public char pop() {
if (length < 1) {
return NULL_CHAR;
} else {
mEnd = normalize(mEnd - 1);
--length;
return mCharBuf[mEnd];
}
}
public char getLastChar() {
if (length < 1) {
return NULL_CHAR;
} else {
return mCharBuf[normalize(mEnd - 1)];
}
}
public String getLastString() {
StringBuffer sb = new StringBuffer();
for (int i = 0; i < length; ++i) {
char c = mCharBuf[normalize(mEnd - 1 - i)];
if (!((LatinIME)mContext).isWordSeparator(c)) {
sb.append(c);
} else {
break;
}
}
return sb.reverse().toString();
}
public void reset() {
length = 0;
}
}
} }

View File

@ -10,7 +10,7 @@ LOCAL_JAVA_LIBRARIES := android.test.runner
# Include all test java files. # Include all test java files.
LOCAL_SRC_FILES := $(call all-java-files-under, src) LOCAL_SRC_FILES := $(call all-java-files-under, src)
LOCAL_PACKAGE_NAME := LatinIMETests LOCAL_PACKAGE_NAME := LatinIME2Tests
LOCAL_INSTRUMENTATION_FOR := LatinIme2Google LOCAL_INSTRUMENTATION_FOR := LatinIme2Google

View File

@ -27,7 +27,7 @@
</application> </application>
<instrumentation android:name="android.test.InstrumentationTestRunner" <instrumentation android:name="android.test.InstrumentationTestRunner"
android:targetPackage="com.android.inputmethod.latin" android:targetPackage="com.google.android.inputmethod.latin"
android:label="LatinIME tests"> android:label="LatinIME tests">
</instrumentation> </instrumentation>
</manifest> </manifest>

View File

@ -0,0 +1,59 @@
package com.android.inputmethod.latin;
import android.test.ServiceTestCase;
public class ImeLoggerTests extends ServiceTestCase<LatinIME> {
private static final String WORD_SEPARATORS
= ".\u0009\u0020,;:!?\n()[]*&@{}<>;_+=|\\u0022";
public ImeLoggerTests() {
super(LatinIME.class);
}
static LatinImeLogger sLogger;
@Override
protected void setUp() {
try {
super.setUp();
} catch (Exception e) {
e.printStackTrace();
}
setupService();
// startService(null); // can't be started because VoiceInput can't be found.
final LatinIME context = getService();
context.mWordSeparators = WORD_SEPARATORS;
LatinImeLogger.init(context);
sLogger = LatinImeLogger.sLatinImeLogger;
}
/*********************** Tests *********************/
public void testRingBuffer() {
for (int i = 0; i < sLogger.mRingCharBuffer.BUFSIZE * 2; ++i) {
LatinImeLogger.logOnDelete();
}
assertEquals("", sLogger.mRingCharBuffer.getLastString());
LatinImeLogger.logOnInputChar('t');
LatinImeLogger.logOnInputChar('g');
LatinImeLogger.logOnInputChar('i');
LatinImeLogger.logOnInputChar('s');
LatinImeLogger.logOnInputChar(' ');
LatinImeLogger.logOnAutoSuggestion("tgis", "this");
LatinImeLogger.logOnInputChar(' ');
LatinImeLogger.logOnDelete();
assertEquals("", sLogger.mRingCharBuffer.getLastString());
LatinImeLogger.logOnDelete();
assertEquals("tgis", sLogger.mRingCharBuffer.getLastString());
assertEquals("tgis", LatinImeLogger.sLastAutoSuggestBefore);
LatinImeLogger.logOnAutoSuggestionCanceled();
assertEquals("", LatinImeLogger.sLastAutoSuggestBefore);
LatinImeLogger.logOnDelete();
assertEquals("tgi", sLogger.mRingCharBuffer.getLastString());
for (int i = 0; i < sLogger.mRingCharBuffer.BUFSIZE * 2; ++i) {
LatinImeLogger.logOnDelete();
}
assertEquals("", sLogger.mRingCharBuffer.getLastString());
for (int i = 0; i < sLogger.mRingCharBuffer.BUFSIZE * 2; ++i) {
LatinImeLogger.logOnInputChar('a');
}
assertEquals(sLogger.mRingCharBuffer.BUFSIZE, sLogger.mRingCharBuffer.length);
}
}

View File

@ -241,8 +241,11 @@ public class SuggestTests extends AndroidTestCase {
* Are accented forms of words suggested as corrections? * Are accented forms of words suggested as corrections?
*/ */
public void testAccents() { public void testAccents() {
assertTrue(isDefaultCorrection("nino", "ni\u00F1o")); // nio // ni<LATIN SMALL LETTER N WITH TILDE>o
assertTrue(isDefaultCorrection("nimo", "ni\u00F1o")); // nio assertTrue(isDefaultCorrection("nino", "ni\u00F1o"));
assertTrue(isDefaultCorrection("maria", "Mar\u00EDa")); // Mara // ni<LATIN SMALL LETTER N WITH TILDE>o
assertTrue(isDefaultCorrection("nimo", "ni\u00F1o"));
// Mar<LATIN SMALL LETTER I WITH ACUTE>a
assertTrue(isDefaultCorrection("maria", "Mar\u00EDa"));
} }
} }