aboutsummaryrefslogtreecommitdiffstats
path: root/java/src
diff options
context:
space:
mode:
Diffstat (limited to 'java/src')
-rw-r--r--java/src/com/android/inputmethod/keyboard/KeyDetector.java185
-rw-r--r--java/src/com/android/inputmethod/keyboard/Keyboard.java36
-rw-r--r--java/src/com/android/inputmethod/keyboard/LatinKeyboardView.java1
-rw-r--r--java/src/com/android/inputmethod/keyboard/MoreKeysDetector.java28
-rw-r--r--java/src/com/android/inputmethod/keyboard/ProximityInfo.java35
-rw-r--r--java/src/com/android/inputmethod/latin/InputAttributes.java1
-rw-r--r--java/src/com/android/inputmethod/latin/SettingsValues.java1
-rw-r--r--java/src/com/android/inputmethod/latin/WordComposer.java9
-rw-r--r--java/src/com/android/inputmethod/latin/suggestions/MoreSuggestions.java3
-rw-r--r--java/src/com/android/inputmethod/latin/suggestions/SuggestionsView.java1
10 files changed, 13 insertions, 287 deletions
diff --git a/java/src/com/android/inputmethod/keyboard/KeyDetector.java b/java/src/com/android/inputmethod/keyboard/KeyDetector.java
index c2ad56d9f..13e909c7e 100644
--- a/java/src/com/android/inputmethod/keyboard/KeyDetector.java
+++ b/java/src/com/android/inputmethod/keyboard/KeyDetector.java
@@ -16,17 +16,9 @@
package com.android.inputmethod.keyboard;
-import android.util.Log;
-
-import java.util.Arrays;
-import java.util.List;
public class KeyDetector {
- private static final String TAG = KeyDetector.class.getSimpleName();
- private static final boolean DEBUG = false;
-
public static final int NOT_A_CODE = -1;
- private static final int ADDITIONAL_PROXIMITY_CHAR_DELIMITER_CODE = 2;
private final int mKeyHysteresisDistanceSquared;
@@ -34,12 +26,6 @@ public class KeyDetector {
private int mCorrectionX;
private int mCorrectionY;
private boolean mProximityCorrectOn;
- private int mProximityThresholdSquare;
-
- // working area
- private static final int MAX_NEARBY_KEYS = 12;
- private final int[] mDistances = new int[MAX_NEARBY_KEYS];
- private final Key[] mNeighborKeys = new Key[MAX_NEARBY_KEYS];
/**
* This class handles key detection.
@@ -57,8 +43,6 @@ public class KeyDetector {
mCorrectionX = (int)correctionX;
mCorrectionY = (int)correctionY;
mKeyboard = keyboard;
- final int threshold = keyboard.mMostCommonKeyWidth;
- mProximityThresholdSquare = threshold * threshold;
}
public int getKeyHysteresisDistanceSquared() {
@@ -87,169 +71,11 @@ public class KeyDetector {
return mProximityCorrectOn;
}
- public void setProximityThreshold(int threshold) {
- mProximityThresholdSquare = threshold * threshold;
- }
-
public boolean alwaysAllowsSlidingInput() {
return false;
}
/**
- * Computes maximum size of the array that can contain all nearby key codes returned by
- * {@link #getNearbyCodes}.
- *
- * @return Returns maximum size of the array that can contain all nearby key codes returned
- * by {@link #getNearbyCodes}.
- */
- protected int getMaxNearbyKeys() {
- return MAX_NEARBY_KEYS;
- }
-
- /**
- * Allocates array that can hold all key codes returned by {@link #getNearbyCodes}
- * method. The maximum size of the array should be computed by {@link #getMaxNearbyKeys}.
- *
- * @return Allocates and returns an array that can hold all key codes returned by
- * {@link #getNearbyCodes} method. All elements in the returned array are
- * initialized by {@link #NOT_A_CODE} value.
- */
- public int[] newCodeArray() {
- int[] codes = new int[getMaxNearbyKeys()];
- Arrays.fill(codes, NOT_A_CODE);
- return codes;
- }
-
- private void initializeNearbyKeys() {
- Arrays.fill(mDistances, Integer.MAX_VALUE);
- Arrays.fill(mNeighborKeys, null);
- }
-
- /**
- * Insert the key into nearby keys buffer and sort nearby keys by ascending order of distance.
- * If the distance of two keys are the same, the key which the point is on should be considered
- * as a closer one.
- *
- * @param key the key to be inserted into the nearby keys buffer.
- * @param distance distance between the key's edge and user touched point.
- * @param isOnKey true if the point is on the key.
- * @return order of the key in the nearby buffer, 0 if it is the nearest key.
- */
- private int sortNearbyKeys(Key key, int distance, boolean isOnKey) {
- final int[] distances = mDistances;
- final Key[] neighborKeys = mNeighborKeys;
- for (int insertPos = 0; insertPos < distances.length; insertPos++) {
- final int comparingDistance = distances[insertPos];
- if (distance < comparingDistance || (distance == comparingDistance && isOnKey)) {
- final int nextPos = insertPos + 1;
- if (nextPos < distances.length) {
- System.arraycopy(distances, insertPos, distances, nextPos,
- distances.length - nextPos);
- System.arraycopy(neighborKeys, insertPos, neighborKeys, nextPos,
- neighborKeys.length - nextPos);
- }
- distances[insertPos] = distance;
- neighborKeys[insertPos] = key;
- return insertPos;
- }
- }
- return distances.length;
- }
-
- private void getNearbyKeyCodes(final int primaryCode, final int[] allCodes) {
- final Key[] neighborKeys = mNeighborKeys;
- final int maxCodesSize = allCodes.length;
-
- // allCodes[0] should always have the key code even if it is a non-letter key.
- if (neighborKeys[0] == null) {
- allCodes[0] = NOT_A_CODE;
- return;
- }
-
- int numCodes = 0;
- for (int j = 0; j < neighborKeys.length && numCodes < maxCodesSize; j++) {
- final Key key = neighborKeys[j];
- if (key == null)
- break;
- final int code = key.mCode;
- // filter out a non-letter key from nearby keys
- if (code < Keyboard.CODE_SPACE)
- continue;
- allCodes[numCodes++] = code;
- }
- if (maxCodesSize <= numCodes) {
- return;
- }
-
- final int code = (primaryCode == NOT_A_CODE) ? allCodes[0] : primaryCode;
- if (code == NOT_A_CODE) {
- return;
- }
- final List<Integer> additionalChars = mKeyboard.getAdditionalProximityChars().get(code);
- if (additionalChars == null || additionalChars.size() == 0) {
- return;
- }
- int currentCodesSize = numCodes;
- allCodes[numCodes++] = ADDITIONAL_PROXIMITY_CHAR_DELIMITER_CODE;
- if (maxCodesSize <= numCodes) {
- return;
- }
- // TODO: This is O(N^2). Assuming additionalChars.size() is up to 4 or 5.
- for (int i = 0; i < additionalChars.size(); ++i) {
- final int additionalChar = additionalChars.get(i);
- boolean contains = false;
- for (int j = 0; j < currentCodesSize; ++j) {
- if (additionalChar == allCodes[j]) {
- contains = true;
- break;
- }
- }
- if (!contains) {
- allCodes[numCodes++] = additionalChar;
- if (maxCodesSize <= numCodes) {
- return;
- }
- }
- }
- }
-
- /**
- * Finds all possible nearby key codes around a touch event point and returns the nearest key.
- * The algorithm to determine the nearby keys depends on the threshold set by
- * {@link #setProximityThreshold(int)} and the mode set by
- * {@link #setProximityCorrectionEnabled(boolean)}.
- *
- * @param x The x-coordinate of a touch point
- * @param y The y-coordinate of a touch point
- * @param allCodes All nearby key codes except functional key are returned in this array
- */
- // TODO: Move this method to native code.
- public void getNearbyCodes(int x, int y, final int[] allCodes) {
- final int touchX = getTouchX(x);
- final int touchY = getTouchY(y);
-
- initializeNearbyKeys();
- Key primaryKey = null;
- for (final Key key : mKeyboard.getNearestKeys(touchX, touchY)) {
- final boolean isOnKey = key.isOnKey(touchX, touchY);
- final int distance = key.squaredDistanceToEdge(touchX, touchY);
- if (isOnKey || (mProximityCorrectOn && distance < mProximityThresholdSquare)) {
- final int insertedPosition = sortNearbyKeys(key, distance, isOnKey);
- if (insertedPosition == 0 && isOnKey) {
- primaryKey = key;
- }
- }
- }
-
- getNearbyKeyCodes(primaryKey != null ? primaryKey.mCode : NOT_A_CODE, allCodes);
- if (DEBUG) {
- Log.d(TAG, "x=" + x + " y=" + y
- + " primary=" + printableCode(primaryKey)
- + " codes=" + printableCodes(allCodes));
- }
- }
-
- /**
* Detect the key whose hitbox the touch point is in.
*
* @param x The x-coordinate of a touch point
@@ -284,14 +110,9 @@ public class KeyDetector {
boolean addDelimiter = false;
for (final int code : codes) {
if (code == NOT_A_CODE) break;
- if (code == ADDITIONAL_PROXIMITY_CHAR_DELIMITER_CODE) {
- sb.append(" | ");
- addDelimiter = false;
- } else {
- if (addDelimiter) sb.append(", ");
- sb.append(Keyboard.printableCode(code));
- addDelimiter = true;
- }
+ if (addDelimiter) sb.append(", ");
+ sb.append(Keyboard.printableCode(code));
+ addDelimiter = true;
}
return "[" + sb + "]";
}
diff --git a/java/src/com/android/inputmethod/keyboard/Keyboard.java b/java/src/com/android/inputmethod/keyboard/Keyboard.java
index 973f64b4d..2b1cc43cd 100644
--- a/java/src/com/android/inputmethod/keyboard/Keyboard.java
+++ b/java/src/com/android/inputmethod/keyboard/Keyboard.java
@@ -20,7 +20,6 @@ import android.content.Context;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.content.res.XmlResourceParser;
-import android.text.TextUtils;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.util.Log;
@@ -42,8 +41,6 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
/**
* Loads an XML description of a keyboard and stores the attributes of the keys. A keyboard
@@ -133,8 +130,6 @@ public class Keyboard {
private final ProximityInfo mProximityInfo;
- private final Map<Integer, List<Integer>> mAdditionalProximityChars;
-
public Keyboard(Params params) {
mId = params.mId;
mThemeId = params.mThemeId;
@@ -153,12 +148,10 @@ public class Keyboard {
mAltCodeKeysWhileTyping = params.mAltCodeKeysWhileTyping.toArray(
new Key[params.mAltCodeKeysWhileTyping.size()]);
mIconsSet = params.mIconsSet;
- mAdditionalProximityChars = params.mAdditionalProximityChars;
mProximityInfo = new ProximityInfo(params.mId.mLocale.toString(),
params.GRID_WIDTH, params.GRID_HEIGHT, mOccupiedWidth, mOccupiedHeight,
- mMostCommonKeyWidth, mMostCommonKeyHeight, mKeys, params.mTouchPositionCorrection,
- params.mAdditionalProximityChars);
+ mMostCommonKeyWidth, mMostCommonKeyHeight, mKeys, params.mTouchPositionCorrection);
}
public ProximityInfo getProximityInfo() {
@@ -230,9 +223,6 @@ public class Keyboard {
public final ArrayList<Key> mShiftKeys = new ArrayList<Key>();
public final ArrayList<Key> mAltCodeKeysWhileTyping = new ArrayList<Key>();
public final KeyboardIconsSet mIconsSet = new KeyboardIconsSet();
- // TODO: Should be in Key instead of Keyboard.Params?
- public final Map<Integer, List<Integer>> mAdditionalProximityChars =
- new HashMap<Integer, List<Integer>>();
public KeyboardSet.KeysCache mKeysCache;
@@ -368,10 +358,6 @@ public class Keyboard {
return mProximityInfo.getNearestKeys(adjustedX, adjustedY);
}
- public Map<Integer, List<Integer>> getAdditionalProximityChars() {
- return mAdditionalProximityChars;
- }
-
public static String printableCode(int code) {
switch (code) {
case CODE_SHIFT: return "shift";
@@ -630,7 +616,6 @@ public class Keyboard {
mParams = params;
setTouchPositionCorrectionData(context, params);
- setAdditionalProximityChars(context, params);
params.GRID_WIDTH = res.getInteger(R.integer.config_keyboard_grid_width);
params.GRID_HEIGHT = res.getInteger(R.integer.config_keyboard_grid_height);
@@ -653,25 +638,6 @@ public class Keyboard {
params.mTouchPositionCorrection.load(data);
}
- private static void setAdditionalProximityChars(Context context, Params params) {
- final String[] additionalChars =
- context.getResources().getStringArray(R.array.additional_proximitychars);
- int currentPrimaryIndex = 0;
- for (int i = 0; i < additionalChars.length; ++i) {
- final String additionalChar = additionalChars[i];
- if (TextUtils.isEmpty(additionalChar)) {
- currentPrimaryIndex = 0;
- } else if (currentPrimaryIndex == 0) {
- currentPrimaryIndex = additionalChar.charAt(0);
- params.mAdditionalProximityChars.put(
- currentPrimaryIndex, new ArrayList<Integer>());
- } else if (currentPrimaryIndex != 0) {
- final int c = additionalChar.charAt(0);
- params.mAdditionalProximityChars.get(currentPrimaryIndex).add(c);
- }
- }
- }
-
public void setAutoGenerate(KeyboardSet.KeysCache keysCache) {
mParams.mKeysCache = keysCache;
}
diff --git a/java/src/com/android/inputmethod/keyboard/LatinKeyboardView.java b/java/src/com/android/inputmethod/keyboard/LatinKeyboardView.java
index 343842552..b869059e4 100644
--- a/java/src/com/android/inputmethod/keyboard/LatinKeyboardView.java
+++ b/java/src/com/android/inputmethod/keyboard/LatinKeyboardView.java
@@ -480,7 +480,6 @@ public class LatinKeyboardView extends KeyboardView implements PointerTracker.Ke
super.setKeyboard(keyboard);
mKeyDetector.setKeyboard(
keyboard, -getPaddingLeft(), -getPaddingTop() + mVerticalCorrection);
- mKeyDetector.setProximityThreshold(keyboard.mMostCommonKeyWidth);
PointerTracker.setKeyDetector(mKeyDetector);
mTouchScreenRegulator.setKeyboard(keyboard);
mMoreKeysPanelCache.clear();
diff --git a/java/src/com/android/inputmethod/keyboard/MoreKeysDetector.java b/java/src/com/android/inputmethod/keyboard/MoreKeysDetector.java
index 6c8d02016..cd4e3001e 100644
--- a/java/src/com/android/inputmethod/keyboard/MoreKeysDetector.java
+++ b/java/src/com/android/inputmethod/keyboard/MoreKeysDetector.java
@@ -33,34 +33,6 @@ public class MoreKeysDetector extends KeyDetector {
}
@Override
- protected int getMaxNearbyKeys() {
- // No nearby key will be returned.
- return 1;
- }
-
- @Override
- public void getNearbyCodes(int x, int y, final int[] allCodes) {
- final int touchX = getTouchX(x);
- final int touchY = getTouchY(y);
-
- Key nearestKey = null;
- int nearestDist = (y < 0) ? mSlideAllowanceSquareTop : mSlideAllowanceSquare;
- for (final Key key : getKeyboard().mKeys) {
- final int dist = key.squaredDistanceToEdge(touchX, touchY);
- if (dist < nearestDist) {
- nearestKey = key;
- nearestDist = dist;
- }
- }
-
- if (nearestKey != null) {
- allCodes[0] = nearestKey.mCode;
- } else {
- allCodes[0] = NOT_A_CODE;
- }
- }
-
- @Override
public Key detectHitKey(int x, int y) {
final int touchX = getTouchX(x);
final int touchY = getTouchY(y);
diff --git a/java/src/com/android/inputmethod/keyboard/ProximityInfo.java b/java/src/com/android/inputmethod/keyboard/ProximityInfo.java
index 61d75e278..442413c0c 100644
--- a/java/src/com/android/inputmethod/keyboard/ProximityInfo.java
+++ b/java/src/com/android/inputmethod/keyboard/ProximityInfo.java
@@ -24,10 +24,7 @@ import com.android.inputmethod.latin.JniUtils;
import com.android.inputmethod.latin.spellcheck.SpellCheckerProximityInfo;
import java.util.Arrays;
-import java.util.Collections;
import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
public class ProximityInfo {
public static final int MAX_PROXIMITY_CHARS_SIZE = 16;
@@ -50,8 +47,7 @@ public class ProximityInfo {
ProximityInfo(String localeStr, int gridWidth, int gridHeight, int minWidth, int height,
int mostCommonKeyWidth, int mostCommonKeyHeight, final Key[] keys,
- TouchPositionCorrection touchPositionCorrection,
- Map<Integer, List<Integer>> additionalProximityChars) {
+ TouchPositionCorrection touchPositionCorrection) {
if (TextUtils.isEmpty(localeStr)) {
mLocaleStr = "";
} else {
@@ -72,12 +68,11 @@ public class ProximityInfo {
return;
}
computeNearestNeighbors(
- mostCommonKeyWidth, keys, touchPositionCorrection, additionalProximityChars);
+ mostCommonKeyWidth, keys, touchPositionCorrection);
}
public static ProximityInfo createDummyProximityInfo() {
- return new ProximityInfo("", 1, 1, 1, 1, 1, 1, EMPTY_KEY_ARRAY, null,
- Collections.<Integer, List<Integer>> emptyMap());
+ return new ProximityInfo("", 1, 1, 1, 1, 1, 1, EMPTY_KEY_ARRAY, null);
}
public static ProximityInfo createSpellCheckerProximityInfo(final int[] proximity) {
@@ -184,8 +179,7 @@ public class ProximityInfo {
}
private void computeNearestNeighbors(int defaultWidth, final Key[] keys,
- TouchPositionCorrection touchPositionCorrection,
- Map<Integer, List<Integer>> additionalProximityChars) {
+ TouchPositionCorrection touchPositionCorrection) {
final HashMap<Integer, Key> keyCodeMap = new HashMap<Integer, Key>();
for (final Key key : keys) {
keyCodeMap.put(key.mCode, key);
@@ -207,27 +201,6 @@ public class ProximityInfo {
neighborKeys[count++] = key;
}
}
- int currentCodesSize = count;
- for (int i = 0; i < currentCodesSize; ++i) {
- final int c = neighborKeys[i].mCode;
- final List<Integer> additionalChars = additionalProximityChars.get(c);
- if (additionalChars == null || additionalChars.size() == 0) {
- continue;
- }
- for (int j = 0; j < additionalChars.size(); ++j) {
- final int additionalChar = additionalChars.get(j);
- boolean contains = false;
- for (int k = 0; k < count; ++k) {
- if(additionalChar == neighborKeys[k].mCode) {
- contains = true;
- break;
- }
- }
- if (!contains) {
- neighborKeys[count++] = keyCodeMap.get(additionalChar);
- }
- }
- }
mGridNeighbors[(y / mCellHeight) * mGridWidth + (x / mCellWidth)] =
Arrays.copyOfRange(neighborKeys, 0, count);
}
diff --git a/java/src/com/android/inputmethod/latin/InputAttributes.java b/java/src/com/android/inputmethod/latin/InputAttributes.java
index f7afed2a5..06c70c42c 100644
--- a/java/src/com/android/inputmethod/latin/InputAttributes.java
+++ b/java/src/com/android/inputmethod/latin/InputAttributes.java
@@ -95,6 +95,7 @@ public class InputAttributes {
}
}
+ @SuppressWarnings("unused")
private void dumpFlags(final int inputType) {
Log.i(TAG, "Input class:");
final int inputClass = inputType & InputType.TYPE_MASK_CLASS;
diff --git a/java/src/com/android/inputmethod/latin/SettingsValues.java b/java/src/com/android/inputmethod/latin/SettingsValues.java
index 020b57caf..9fc047b75 100644
--- a/java/src/com/android/inputmethod/latin/SettingsValues.java
+++ b/java/src/com/android/inputmethod/latin/SettingsValues.java
@@ -23,7 +23,6 @@ import android.os.Build;
import android.util.Log;
import android.view.inputmethod.EditorInfo;
-import com.android.inputmethod.compat.InputMethodInfoCompatWrapper;
import com.android.inputmethod.compat.InputTypeCompatUtils;
import com.android.inputmethod.compat.VibratorCompatWrapper;
import com.android.inputmethod.keyboard.internal.KeySpecParser;
diff --git a/java/src/com/android/inputmethod/latin/WordComposer.java b/java/src/com/android/inputmethod/latin/WordComposer.java
index 251063ec4..9f23f174f 100644
--- a/java/src/com/android/inputmethod/latin/WordComposer.java
+++ b/java/src/com/android/inputmethod/latin/WordComposer.java
@@ -141,6 +141,7 @@ public class WordComposer {
keyY = y;
} else {
final Key key = keyDetector.detectHitKey(x, y);
+ // TODO: Pass an integer instead of an integer array
codes = new int[] { key != null ? key.mCode : NOT_A_CODE };
keyX = keyDetector.getTouchX(x);
keyY = keyDetector.getTouchY(y);
@@ -202,9 +203,8 @@ public class WordComposer {
if (key.mCode == codePoint) {
final int x = key.mX + key.mWidth / 2;
final int y = key.mY + key.mHeight / 2;
- final int[] codes = keyDetector.newCodeArray();
- keyDetector.getNearbyCodes(x, y, codes);
- add(codePoint, codes, x, y);
+ // TODO: Pass an integer instead of an integer array
+ add(codePoint, new int[] { key.mCode }, x, y);
return;
}
}
@@ -216,7 +216,7 @@ public class WordComposer {
* Set the currently composing word to the one passed as an argument.
* This will register NOT_A_COORDINATE for X and Ys, and use the passed keyboard for proximity.
*/
- public void setComposingWord(final CharSequence word, final Keyboard keyboard,
+ private void setComposingWord(final CharSequence word, final Keyboard keyboard,
final KeyDetector keyDetector) {
reset();
final int length = word.length();
@@ -233,7 +233,6 @@ public class WordComposer {
final KeyDetector keyDetector = new KeyDetector(0);
keyDetector.setKeyboard(keyboard, 0, 0);
keyDetector.setProximityCorrectionEnabled(true);
- keyDetector.setProximityThreshold(keyboard.mMostCommonKeyWidth);
setComposingWord(word, keyboard, keyDetector);
}
diff --git a/java/src/com/android/inputmethod/latin/suggestions/MoreSuggestions.java b/java/src/com/android/inputmethod/latin/suggestions/MoreSuggestions.java
index c9c88fd23..3a17f1f64 100644
--- a/java/src/com/android/inputmethod/latin/suggestions/MoreSuggestions.java
+++ b/java/src/com/android/inputmethod/latin/suggestions/MoreSuggestions.java
@@ -25,7 +25,6 @@ import com.android.inputmethod.keyboard.Keyboard;
import com.android.inputmethod.keyboard.KeyboardSwitcher;
import com.android.inputmethod.keyboard.KeyboardView;
import com.android.inputmethod.keyboard.internal.KeyboardIconsSet;
-import com.android.inputmethod.latin.LatinImeLogger;
import com.android.inputmethod.latin.R;
import com.android.inputmethod.latin.SuggestedWords;
import com.android.inputmethod.latin.Utils;
@@ -38,8 +37,6 @@ public class MoreSuggestions extends Keyboard {
}
public static class Builder extends Keyboard.Builder<Builder.MoreSuggestionsParam> {
- private static final boolean DBG = LatinImeLogger.sDBG;
-
private final MoreSuggestionsView mPaneView;
private SuggestedWords mSuggestions;
private int mFromPos;
diff --git a/java/src/com/android/inputmethod/latin/suggestions/SuggestionsView.java b/java/src/com/android/inputmethod/latin/suggestions/SuggestionsView.java
index 286bf0aea..06fda44fa 100644
--- a/java/src/com/android/inputmethod/latin/suggestions/SuggestionsView.java
+++ b/java/src/com/android/inputmethod/latin/suggestions/SuggestionsView.java
@@ -62,7 +62,6 @@ import com.android.inputmethod.latin.R;
import com.android.inputmethod.latin.StaticInnerHandlerWrapper;
import com.android.inputmethod.latin.Suggest;
import com.android.inputmethod.latin.SuggestedWords;
-import com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo;
import com.android.inputmethod.latin.Utils;
import java.util.ArrayList;