aboutsummaryrefslogtreecommitdiffstats
path: root/main/src/cgeo/geocaching/utils
diff options
context:
space:
mode:
Diffstat (limited to 'main/src/cgeo/geocaching/utils')
-rw-r--r--main/src/cgeo/geocaching/utils/AngleUtils.java8
-rw-r--r--main/src/cgeo/geocaching/utils/CryptUtils.java18
-rw-r--r--main/src/cgeo/geocaching/utils/HtmlUtils.java25
-rw-r--r--main/src/cgeo/geocaching/utils/IOUtils.java22
-rw-r--r--main/src/cgeo/geocaching/utils/ImageHelper.java11
-rw-r--r--main/src/cgeo/geocaching/utils/LazyInitializedList.java98
-rw-r--r--main/src/cgeo/geocaching/utils/LeastRecentlyUsedMap.java2
-rw-r--r--main/src/cgeo/geocaching/utils/LeastRecentlyUsedSet.java21
-rw-r--r--main/src/cgeo/geocaching/utils/Log.java34
-rw-r--r--main/src/cgeo/geocaching/utils/LogTemplateProvider.java22
-rw-r--r--main/src/cgeo/geocaching/utils/MatcherWrapper.java91
-rw-r--r--main/src/cgeo/geocaching/utils/PeriodicHandler.java5
-rw-r--r--main/src/cgeo/geocaching/utils/TranslationUtils.java5
-rw-r--r--main/src/cgeo/geocaching/utils/XmlUtils.java41
14 files changed, 289 insertions, 114 deletions
diff --git a/main/src/cgeo/geocaching/utils/AngleUtils.java b/main/src/cgeo/geocaching/utils/AngleUtils.java
index e2b4a66..6e59a91 100644
--- a/main/src/cgeo/geocaching/utils/AngleUtils.java
+++ b/main/src/cgeo/geocaching/utils/AngleUtils.java
@@ -8,9 +8,11 @@ public class AngleUtils {
/**
* Return the angle to turn of to go from an angle to the other
- *
- * @param from the origin angle in degrees
- * @param to the target angle in degreees
+ *
+ * @param from
+ * the origin angle in degrees
+ * @param to
+ * the target angle in degrees
* @return a value in degrees, in the [-180, 180[ range
*/
public static float difference(final float from, final float to) {
diff --git a/main/src/cgeo/geocaching/utils/CryptUtils.java b/main/src/cgeo/geocaching/utils/CryptUtils.java
index f04327e..df2baa0 100644
--- a/main/src/cgeo/geocaching/utils/CryptUtils.java
+++ b/main/src/cgeo/geocaching/utils/CryptUtils.java
@@ -46,16 +46,14 @@ public final class CryptUtils {
boolean plaintext = false;
final int length = text.length();
- int c;
- int capitalized;
for (int index = 0; index < length; index++) {
- c = text.charAt(index);
+ int c = text.charAt(index);
if (c == '[') {
plaintext = true;
} else if (c == ']') {
plaintext = false;
} else if (!plaintext) {
- capitalized = c & 32;
+ int capitalized = c & 32;
c &= ~capitalized;
c = ((c >= 'A') && (c <= 'Z') ? ((c - 'A' + 13) % 26 + 'A') : c)
| capitalized;
@@ -73,7 +71,7 @@ public final class CryptUtils {
digest.update(text.getBytes(), 0, text.length());
hashed = new BigInteger(1, digest.digest()).toString(16);
} catch (Exception e) {
- Log.e("cgBase.md5: " + e.toString());
+ Log.e("cgBase.md5", e);
}
return hashed;
@@ -87,7 +85,7 @@ public final class CryptUtils {
digest.update(text.getBytes(), 0, text.length());
hashed = new BigInteger(1, digest.digest()).toString(16);
} catch (Exception e) {
- Log.e("cgBase.sha1: " + e.toString());
+ Log.e("cgBase.sha1", e);
}
return hashed;
@@ -102,7 +100,7 @@ public final class CryptUtils {
mac.init(secretKeySpec);
macBytes = mac.doFinal(text.getBytes());
} catch (Exception e) {
- Log.e("cgBase.hashHmac: " + e.toString());
+ Log.e("cgBase.hashHmac", e);
}
return macBytes;
@@ -116,16 +114,14 @@ public final class CryptUtils {
boolean plaintext = false;
final int length = span.length();
- int c;
- int capitalized;
for (int index = 0; index < length; index++) {
- c = span.charAt(index);
+ int c = span.charAt(index);
if (c == '[') {
plaintext = true;
} else if (c == ']') {
plaintext = false;
} else if (!plaintext) {
- capitalized = c & 32;
+ int capitalized = c & 32;
c &= ~capitalized;
c = ((c >= 'A') && (c <= 'Z') ? ((c - 'A' + 13) % 26 + 'A') : c)
| capitalized;
diff --git a/main/src/cgeo/geocaching/utils/HtmlUtils.java b/main/src/cgeo/geocaching/utils/HtmlUtils.java
index a54ba57..30aa19b 100644
--- a/main/src/cgeo/geocaching/utils/HtmlUtils.java
+++ b/main/src/cgeo/geocaching/utils/HtmlUtils.java
@@ -53,4 +53,29 @@ public class HtmlUtils {
return StringUtils.replace(result, "<br />", "\n").trim();
}
+ /**
+ * Convert any non-Latin characters into HTML unicode entities
+ *
+ * @param input
+ * String
+ * @return output String
+ */
+ public static String convertNonLatinCharactersToHTML(final String input) {
+ final int inputLen = input.length();
+ final StringBuilder output = new StringBuilder();
+
+ for (int i = 0; i < inputLen; i++) {
+ char c = input.charAt(i);
+
+ if (c > 300) {
+ output.append("&#");
+ output.append(Integer.toString(c));
+ output.append(';');
+ } else {
+ output.append(c);
+ }
+ }
+
+ return output.toString();
+ }
}
diff --git a/main/src/cgeo/geocaching/utils/IOUtils.java b/main/src/cgeo/geocaching/utils/IOUtils.java
new file mode 100644
index 0000000..df90da3
--- /dev/null
+++ b/main/src/cgeo/geocaching/utils/IOUtils.java
@@ -0,0 +1,22 @@
+package cgeo.geocaching.utils;
+
+import java.io.Closeable;
+import java.io.IOException;
+
+final public class IOUtils {
+
+ private IOUtils() {
+ // utility class
+ }
+
+ public static void closeQuietly(final Closeable closeable) {
+ if (closeable != null) {
+ try {
+ closeable.close();
+ } catch (final IOException e) {
+ Log.w("closeQuietly: unable to close " + closeable, e);
+ }
+ }
+ }
+
+}
diff --git a/main/src/cgeo/geocaching/utils/ImageHelper.java b/main/src/cgeo/geocaching/utils/ImageHelper.java
index 4c18b06..98cad64 100644
--- a/main/src/cgeo/geocaching/utils/ImageHelper.java
+++ b/main/src/cgeo/geocaching/utils/ImageHelper.java
@@ -1,13 +1,12 @@
package cgeo.geocaching.utils;
import cgeo.geocaching.cgeoapplication;
+import cgeo.geocaching.compatibility.Compatibility;
-import android.content.Context;
import android.graphics.Bitmap;
+import android.graphics.Point;
import android.graphics.Rect;
import android.graphics.drawable.BitmapDrawable;
-import android.view.Display;
-import android.view.WindowManager;
public class ImageHelper {
@@ -24,9 +23,9 @@ public class ImageHelper {
*/
public static BitmapDrawable scaleBitmapToFitDisplay(final Bitmap image) {
final cgeoapplication app = cgeoapplication.getInstance();
- final Display display = ((WindowManager) app.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay();
- final int maxWidth = display.getWidth() - 25;
- final int maxHeight = display.getHeight() - 25;
+ Point displaySize = Compatibility.getDisplaySize();
+ final int maxWidth = displaySize.x - 25;
+ final int maxHeight = displaySize.y - 25;
Bitmap result = image;
int width = image.getWidth();
diff --git a/main/src/cgeo/geocaching/utils/LazyInitializedList.java b/main/src/cgeo/geocaching/utils/LazyInitializedList.java
index 25af811..27649e8 100644
--- a/main/src/cgeo/geocaching/utils/LazyInitializedList.java
+++ b/main/src/cgeo/geocaching/utils/LazyInitializedList.java
@@ -1,103 +1,63 @@
package cgeo.geocaching.utils;
+import java.util.AbstractList;
import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Iterator;
import java.util.List;
+import java.util.concurrent.Callable;
-public abstract class LazyInitializedList<ElementType> implements Iterable<ElementType> {
+public abstract class LazyInitializedList<ElementType> extends AbstractList<ElementType> implements Callable<List<ElementType>> {
private volatile List<ElementType> list;
- private void initializeList() {
+ private List<ElementType> getList() {
if (list == null) {
- synchronized (this) {
- if (list == null) {
- list = loadFromDatabase();
+ synchronized(this) {
+ try {
+ list = call();
+ if (list == null) {
+ Log.e("LazyInitializedList.getList: null result");
+ }
+ } catch (final Exception e) {
+ Log.e("LazyInitializedList.getList", e);
}
}
}
+ return list;
}
- protected abstract List<ElementType> loadFromDatabase();
-
- public void add(final ElementType element) {
- initializeList();
- list.add(element);
- }
-
- public void prepend(final ElementType element) {
- initializeList();
- list.add(0, element);
- }
-
- public void set(final List<ElementType> elements) {
- if (elements != null) {
- list = new ArrayList<ElementType>(elements);
- } else {
- list = new ArrayList<ElementType>();
- }
- }
-
- public void set(LazyInitializedList<ElementType> other) {
- if (other != null) {
- list = new ArrayList<ElementType>(other.asList());
- } else {
- list = new ArrayList<ElementType>();
- }
+ @Override
+ public boolean add(final ElementType element) {
+ return getList().add(element);
}
- public boolean isEmpty() {
- initializeList();
- return list.isEmpty();
+ @Override
+ public ElementType set(final int index, final ElementType element) {
+ return getList().set(index, element);
}
+ @Override
public ElementType remove(final int index) {
- initializeList();
- return list.remove(index);
+ return getList().remove(index);
}
+ @Override
public void add(int index, final ElementType element) {
- initializeList();
- list.add(index, element);
+ getList().add(index, element);
}
+ @Override
public int size() {
- initializeList();
- return list.size();
+ return getList().size();
}
@Override
- public Iterator<ElementType> iterator() {
- initializeList();
- return list.iterator();
- }
-
public ElementType get(final int index) {
- initializeList();
- return list.get(index);
+ return getList().get(index);
}
- public boolean contains(final ElementType element) {
- initializeList();
- return list.contains(element);
- }
-
- public boolean isNotEmpty() {
- initializeList();
- return !list.isEmpty();
- }
-
- /**
- * @return an unmodifiable list of the elements
- */
- public List<ElementType> asList() {
- initializeList();
- return Collections.unmodifiableList(list);
+ @Override
+ public void clear() {
+ list = new ArrayList<ElementType>();
}
- public int indexOf(ElementType element) {
- initializeList();
- return list.indexOf(element);
- }
}
diff --git a/main/src/cgeo/geocaching/utils/LeastRecentlyUsedMap.java b/main/src/cgeo/geocaching/utils/LeastRecentlyUsedMap.java
index f0bc4f5..6122532 100644
--- a/main/src/cgeo/geocaching/utils/LeastRecentlyUsedMap.java
+++ b/main/src/cgeo/geocaching/utils/LeastRecentlyUsedMap.java
@@ -16,7 +16,7 @@ import java.util.Map;
*/
public abstract class LeastRecentlyUsedMap<K, V> extends LinkedHashMap<K, V> {
- private static enum OperationModes {
+ private enum OperationModes {
LRU_CACHE, BOUNDED
}
diff --git a/main/src/cgeo/geocaching/utils/LeastRecentlyUsedSet.java b/main/src/cgeo/geocaching/utils/LeastRecentlyUsedSet.java
index b654fd6..698d38a 100644
--- a/main/src/cgeo/geocaching/utils/LeastRecentlyUsedSet.java
+++ b/main/src/cgeo/geocaching/utils/LeastRecentlyUsedSet.java
@@ -9,7 +9,7 @@ import java.util.List;
/**
* Synchronized set wrapper for the LeastRecentlyUsedMap.
- *
+ *
* This code is heavily based on the HashSet code that represent Map as a Set.
* Unfortunately HashSet does not allow to use a custom Map as its Storage.
* Therefore overriding removeEldestEntry() is impossible for a normal LinkedHashSet.
@@ -50,7 +50,7 @@ public class LeastRecentlyUsedSet<E> extends AbstractSet<E>
/**
* Synchronized access to set size
* Copy of the HashSet code if size()
- *
+ *
* @see HashSet
*/
@Override
@@ -61,7 +61,7 @@ public class LeastRecentlyUsedSet<E> extends AbstractSet<E>
/**
* Synchronized check of set emptiness
* Copy of the HashSet code if isEmpty()
- *
+ *
* @see HashSet
*/
@Override
@@ -72,7 +72,7 @@ public class LeastRecentlyUsedSet<E> extends AbstractSet<E>
/**
* Synchronized check for containment
* Copy of the HashSet code if contains()
- *
+ *
* @see HashSet
*/
@Override
@@ -83,18 +83,21 @@ public class LeastRecentlyUsedSet<E> extends AbstractSet<E>
/**
* Synchronized addition of an item
* Copy of the HashSet code if add()
- *
+ *
* @see HashSet
*/
@Override
public synchronized boolean add(E e) {
+ if (e == null) {
+ throw new IllegalArgumentException("LeastRecentlyUsedSet cannot take null element");
+ }
return map.put(e, PRESENT) == null;
}
/**
* Synchronized removal of a contained item
* Copy of the HashSet code if remove()
- *
+ *
* @see HashSet
*/
@Override
@@ -117,7 +120,7 @@ public class LeastRecentlyUsedSet<E> extends AbstractSet<E>
/**
* Synchronized clearing of the set
* Copy of the HashSet code if clear()
- *
+ *
* @see HashSet
*/
@Override
@@ -128,12 +131,12 @@ public class LeastRecentlyUsedSet<E> extends AbstractSet<E>
/**
* (synchronized) Clone of the set
* Copy of the HashSet code if clone()
- *
+ *
* @see HashSet
*/
@Override
@SuppressWarnings("unchecked")
- public Object clone() {
+ public Object clone() throws CloneNotSupportedException {
try {
synchronized (this) {
final LeastRecentlyUsedSet<E> newSet = (LeastRecentlyUsedSet<E>) super.clone();
diff --git a/main/src/cgeo/geocaching/utils/Log.java b/main/src/cgeo/geocaching/utils/Log.java
index 6213661..6d57b75 100644
--- a/main/src/cgeo/geocaching/utils/Log.java
+++ b/main/src/cgeo/geocaching/utils/Log.java
@@ -1,5 +1,11 @@
package cgeo.geocaching.utils;
+import android.os.Environment;
+
+import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.Writer;
final public class Log {
@@ -9,6 +15,7 @@ final public class Log {
* the debug flag is cached here so that we don't need to access the settings every time we have to evaluate it
*/
private static boolean isDebug = true;
+ private static boolean first = true;
public static boolean isDebug() {
return isDebug;
@@ -74,4 +81,31 @@ final public class Log {
public static void e(final String msg, final Throwable t) {
android.util.Log.e(TAG, msg, t);
}
+
+ /**
+ * Log the whole content of a string into "/sdcard/cgeo-debug.log".
+ * <br/>
+ * Sometimes, the string we want to work on while debugging or developing a new feature is too long to
+ * be fully stored in Android logcat. This method will log the content of the string in a file named
+ * "/sdcard/cgeo-debug.log". The file will be reset at every run, and if called several times during a run,
+ * the contents will be appended to one another.
+ * <br/>
+ * <strong>This method should never be called in production.</strong>
+ *
+ * @param msg the message to log, or to add to the log if other messages have been stored in the same run
+ */
+ public synchronized static void logToFile(final String msg) {
+ final File file = new File(Environment.getExternalStorageDirectory(), "cgeo-debug.log");
+ if (first) {
+ first = false;
+ file.delete();
+ }
+ try {
+ final Writer writer = new FileWriter(file, true);
+ writer.write(msg);
+ writer.close();
+ } catch (final IOException e) {
+ Log.e("logToFile: cannot write to " + file, e);
+ }
+ }
}
diff --git a/main/src/cgeo/geocaching/utils/LogTemplateProvider.java b/main/src/cgeo/geocaching/utils/LogTemplateProvider.java
index 7cacd9d..0a8e547 100644
--- a/main/src/cgeo/geocaching/utils/LogTemplateProvider.java
+++ b/main/src/cgeo/geocaching/utils/LogTemplateProvider.java
@@ -2,8 +2,8 @@ package cgeo.geocaching.utils;
import cgeo.geocaching.R;
import cgeo.geocaching.Settings;
-import cgeo.geocaching.cgCache;
-import cgeo.geocaching.cgTrackable;
+import cgeo.geocaching.Trackable;
+import cgeo.geocaching.Geocache;
import cgeo.geocaching.connector.gc.GCConstants;
import cgeo.geocaching.connector.gc.Login;
import cgeo.geocaching.network.Network;
@@ -28,15 +28,15 @@ public class LogTemplateProvider {
*
*/
public static class LogContext {
- private cgCache cache;
- private cgTrackable trackable;
+ private Geocache cache;
+ private Trackable trackable;
private boolean offline = false;
- public LogContext(final cgCache cache) {
+ public LogContext(final Geocache cache) {
this(cache, false);
}
- public LogContext(final cgTrackable trackable) {
+ public LogContext(final Trackable trackable) {
this.trackable = trackable;
}
@@ -44,16 +44,16 @@ public class LogTemplateProvider {
this(null, offline);
}
- public LogContext(final cgCache cache, boolean offline) {
+ public LogContext(final Geocache cache, boolean offline) {
this.cache = cache;
this.offline = offline;
}
- public cgCache getCache() {
+ public Geocache getCache() {
return cache;
}
- public cgTrackable getTrackable() {
+ public Trackable getTrackable() {
return trackable;
}
@@ -148,11 +148,11 @@ public class LogTemplateProvider {
@Override
public String getValue(final LogContext context) {
- cgTrackable trackable = context.getTrackable();
+ Trackable trackable = context.getTrackable();
if (trackable != null) {
return trackable.getOwner();
}
- cgCache cache = context.getCache();
+ Geocache cache = context.getCache();
if (cache != null) {
return cache.getOwnerDisplayName();
}
diff --git a/main/src/cgeo/geocaching/utils/MatcherWrapper.java b/main/src/cgeo/geocaching/utils/MatcherWrapper.java
new file mode 100644
index 0000000..c3c1663
--- /dev/null
+++ b/main/src/cgeo/geocaching/utils/MatcherWrapper.java
@@ -0,0 +1,91 @@
+package cgeo.geocaching.utils;
+
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * Wrapper around the regex {@link Matcher} class. This implementation optimizes the memory usage of the matched
+ * Strings.
+ *
+ */
+public class MatcherWrapper {
+ private final Matcher matcher;
+
+ public MatcherWrapper(Pattern pattern, String input) {
+ this.matcher = pattern.matcher(input);
+ }
+
+ /**
+ * see {@link Matcher#find()}
+ */
+ public boolean find() {
+ return matcher.find();
+ }
+
+ /**
+ * see {@link Matcher#group(int)}
+ */
+ public String group(int index) {
+ return newString(matcher.group(index));
+ }
+
+ /**
+ * This method explicitly creates a new String instance from an already existing String. This is necessary to avoid
+ * huge memory leaks in our parser. If we do regular expression matching on large Strings, the returned matches are
+ * otherwise memory mapped substrings of the huge original String, therefore blocking the garbage collector from
+ * removing the huge input String.
+ * <p>
+ * Do not change this method, even if Findbugs and other tools will report a violation for that line!
+ *
+ * @param input
+ * @return
+ */
+ private static String newString(String input) {
+ if (input == null) {
+ return null;
+ }
+ return new String(input); // DON'T REMOVE THE "new String" HERE!
+ }
+
+ /**
+ * see {@link Matcher#groupCount()}
+ */
+ public int groupCount() {
+ return matcher.groupCount();
+ }
+
+ /**
+ * see {@link Matcher#group()}
+ */
+ public String group() {
+ return newString(matcher.group());
+ }
+
+ /**
+ * see {@link Matcher#start()}
+ */
+ public int start() {
+ return matcher.start();
+ }
+
+ /**
+ * see {@link Matcher#replaceAll(String)}
+ */
+ public String replaceAll(String replacement) {
+ return newString(matcher.replaceAll(replacement));
+ }
+
+ /**
+ * see {@link Matcher#matches()}
+ */
+ public boolean matches() {
+ return matcher.matches();
+ }
+
+ /**
+ * see {@link Matcher#replaceFirst(String)}
+ */
+ public String replaceFirst(String replacement) {
+ return newString(matcher.replaceFirst(replacement));
+ }
+}
diff --git a/main/src/cgeo/geocaching/utils/PeriodicHandler.java b/main/src/cgeo/geocaching/utils/PeriodicHandler.java
index 3f6c345..2759580 100644
--- a/main/src/cgeo/geocaching/utils/PeriodicHandler.java
+++ b/main/src/cgeo/geocaching/utils/PeriodicHandler.java
@@ -26,7 +26,7 @@ abstract public class PeriodicHandler extends Handler {
* @param period
* The period in milliseconds.
*/
- public PeriodicHandler(final long period) {
+ protected PeriodicHandler(final long period) {
this.period = period;
}
@@ -48,6 +48,9 @@ abstract public class PeriodicHandler extends Handler {
case ACT:
sendEmptyMessageDelayed(ACT, period);
act();
+ break;
+ default:
+ throw new UnsupportedOperationException();
}
}
diff --git a/main/src/cgeo/geocaching/utils/TranslationUtils.java b/main/src/cgeo/geocaching/utils/TranslationUtils.java
index a29c5a7..4d318f0 100644
--- a/main/src/cgeo/geocaching/utils/TranslationUtils.java
+++ b/main/src/cgeo/geocaching/utils/TranslationUtils.java
@@ -1,12 +1,11 @@
package cgeo.geocaching.utils;
import cgeo.geocaching.activity.AbstractActivity;
+import cgeo.geocaching.network.Network;
import android.content.Intent;
import android.net.Uri;
-import java.net.URLEncoder;
-
/**
* Utilities used for translating
*/
@@ -30,7 +29,7 @@ public final class TranslationUtils {
* @return URI ready to be parsed
*/
private static String buildTranslationURI(final String toLang, final String text) {
- String content = URLEncoder.encode(text);
+ String content = Network.encode(text);
// the app works better without the "+", the website works better with "+", therefore assume using the app if installed
if (ProcessUtils.isInstalled(TRANSLATION_APP)) {
content = content.replace("+", "%20");
diff --git a/main/src/cgeo/geocaching/utils/XmlUtils.java b/main/src/cgeo/geocaching/utils/XmlUtils.java
new file mode 100644
index 0000000..4e08f42
--- /dev/null
+++ b/main/src/cgeo/geocaching/utils/XmlUtils.java
@@ -0,0 +1,41 @@
+package cgeo.geocaching.utils;
+
+import org.xmlpull.v1.XmlSerializer;
+
+import java.io.IOException;
+
+public class XmlUtils {
+
+ private XmlUtils() {
+ // Do not instantiate
+ }
+
+ /**
+ * Insert an attribute-less tag with enclosed text in a XML serializer output.
+ *
+ * @param serializer an XML serializer
+ * @param prefix an XML prefix, see {@link XmlSerializer#startTag(String, String)}
+ * @param tag an XML tag
+ * @param text some text to insert
+ * @throws IOException
+ */
+ public static void simpleText(final XmlSerializer serializer, final String prefix, final String tag, final String text) throws IOException {
+ serializer.startTag(prefix, tag);
+ serializer.text(text);
+ serializer.endTag(prefix, tag);
+ }
+
+ /**
+ * Insert pairs of attribute-less tags and enclosed texts in a XML serializer output
+ *
+ * @param serializer an XML serializer
+ * @param prefix an XML prefix, see {@link XmlSerializer#startTag(String, String)} shared by all tags
+ * @param tagAndText an XML tag, the corresponding text, another XML tag, the corresponding text, …
+ * @throws IOException
+ */
+ public static void multipleTexts(final XmlSerializer serializer, final String prefix, final String... tagAndText) throws IOException {
+ for (int i = 0; i < tagAndText.length; i += 2) {
+ simpleText(serializer, prefix, tagAndText[i], tagAndText[i+1]);
+ }
+ }
+}