From 846187d321a5bb3e8e054004d2ad78a8c10eb670 Mon Sep 17 00:00:00 2001
From: Francesco <franzbianconero@gmail.com>
Date: Sat, 23 Dec 2017 10:13:16 +0100
Subject: [PATCH] 6.4

---
 app/build.gradle                              |    7 +-
 app/proguard-rules.pro                        |    9 +-
 app/src/main/AndroidManifest.xml              |    2 +-
 .../consolelauncher/LauncherActivity.java     |  101 +-
 .../andre/consolelauncher/MainManager.java    |  120 +-
 .../ohi/andre/consolelauncher/UIManager.java  |  116 +-
 .../consolelauncher/commands/Command.java     |   12 +-
 .../commands/CommandAbstraction.java          |    2 -
 .../commands/CommandTuils.java                |    9 +-
 .../commands/CommandsPreferences.java         |   29 +-
 .../commands/main/MainPack.java               |    7 +-
 .../commands/main/raw/airplane.java           |    5 -
 .../commands/main/raw/apps.java               |   14 +-
 .../commands/main/raw/beep.java               |    5 -
 .../commands/main/raw/bluetooth.java          |    5 -
 .../commands/main/raw/calc.java               |    5 -
 .../commands/main/raw/call.java               |    5 -
 .../commands/main/raw/clear.java              |    5 -
 .../commands/main/raw/config.java             |   39 +-
 .../commands/main/raw/ctrlc.java              |    8 +-
 .../commands/main/raw/data.java               |    5 -
 .../commands/main/raw/donate.java             |    5 -
 .../commands/main/raw/exit.java               |    5 -
 .../commands/main/raw/flash.java              |    5 -
 .../commands/main/raw/help.java               |    5 -
 .../commands/main/raw/location.java           |    5 -
 .../commands/main/raw/notifications.java      |   89 +-
 .../commands/main/raw/open.java               |    5 -
 .../commands/main/raw/rate.java               |   32 +-
 .../commands/main/raw/refresh.java            |    5 -
 .../commands/main/raw/regex.java              |    6 +-
 .../commands/main/raw/restart.java            |    5 -
 .../commands/main/raw/rss.java                |  101 +-
 .../commands/main/raw/search.java             |    6 +-
 .../commands/main/raw/share.java              |    5 -
 .../commands/main/raw/shellcommands.java      |    5 -
 .../commands/main/raw/sms.java                |    5 -
 .../commands/main/raw/status.java             |    5 -
 .../commands/main/raw/time.java               |    7 +-
 .../commands/main/raw/tuixt.java              |    5 -
 .../commands/main/raw/tutorial.java           |    5 -
 .../commands/main/raw/uninstall.java          |    5 -
 .../commands/main/raw/vibrate.java            |    5 -
 .../commands/main/raw/wifi.java               |    5 -
 .../commands/specific/ParamCommand.java       |   18 +-
 .../commands/tuixt/TuixtActivity.java         |    3 +-
 .../commands/tuixt/raw/exit.java              |    5 -
 .../commands/tuixt/raw/help.java              |    5 -
 .../commands/tuixt/raw/save.java              |    5 -
 .../managers/AliasManager.java                |   41 +-
 .../consolelauncher/managers/AppsManager.java |  127 +-
 .../managers/ContactManager.java              |    3 +-
 .../managers/MessagesManager.java             |    6 +-
 .../managers/RegexManager.java                |  120 +-
 .../consolelauncher/managers/RssManager.java  |  829 ++++--
 .../managers/TerminalManager.java             |  119 +-
 .../managers/ThemesManager.java               |    2 +
 .../{tuils => managers}/TimeManager.java      |   53 +-
 .../managers/music/MusicManager2.java         |    3 +-
 .../managers/notifications/KeeperService.java |  220 ++
 .../notifications/NotificationManager.java    |  277 +-
 .../notifications/NotificationService.java    |  392 ++-
 .../suggestions/SuggestionsManager.java       |  310 +--
 .../managers/xml/XMLPrefsManager.java         |  345 ++-
 .../managers/xml/options/Apps.java            |   30 +
 .../managers/xml/options/Behavior.java        |  580 ++++-
 .../managers/xml/options/Cmd.java             |   10 +
 .../managers/xml/options/Notifications.java   |   59 +-
 .../managers/xml/options/Rss.java             |  125 +-
 .../managers/xml/options/Suggestions.java     |  135 +
 .../managers/xml/options/Theme.java           |  128 +-
 .../managers/xml/options/Toolbar.java         |   10 +
 .../managers/xml/options/Ui.java              |  444 +++-
 .../tuils/AllowEqualsSequence.java            |    4 +-
 .../tuils/InputOutputReceiver.java            |   50 +-
 .../consolelauncher/tuils/KeeperService.java  |   72 -
 .../tuils/LongClickMovementMethod.java        |  139 +
 .../tuils/LongClickableSpan.java              |  125 +
 .../tuils/StoppableThread.java                |   12 +-
 .../andre/consolelauncher/tuils/Tuils.java    |  211 +-
 .../Html4EscapeSymbolsInitializer.java        |  356 +++
 .../Html5EscapeSymbolsInitializer.java        | 2320 +++++++++++++++++
 .../tuils/html_escape/HtmlEscape.java         | 1283 +++++++++
 .../tuils/html_escape/HtmlEscapeLevel.java    |  138 +
 .../tuils/html_escape/HtmlEscapeSymbols.java  |  573 ++++
 .../tuils/html_escape/HtmlEscapeType.java     |  119 +
 .../tuils/html_escape/HtmlEscapeUtil.java     | 1368 ++++++++++
 .../tuils/interfaces/CommandExecuter.java     |    7 +-
 app/src/main/res/menu/notification_menu.xml   |    5 +
 app/src/main/res/values/strings.xml           |   45 +-
 build.gradle                                  |    1 +
 91 files changed, 10554 insertions(+), 1514 deletions(-)
 rename app/src/main/java/ohi/andre/consolelauncher/{tuils => managers}/TimeManager.java (68%)
 create mode 100755 app/src/main/java/ohi/andre/consolelauncher/managers/notifications/KeeperService.java
 delete mode 100755 app/src/main/java/ohi/andre/consolelauncher/tuils/KeeperService.java
 create mode 100644 app/src/main/java/ohi/andre/consolelauncher/tuils/LongClickMovementMethod.java
 create mode 100644 app/src/main/java/ohi/andre/consolelauncher/tuils/LongClickableSpan.java
 create mode 100755 app/src/main/java/ohi/andre/consolelauncher/tuils/html_escape/Html4EscapeSymbolsInitializer.java
 create mode 100755 app/src/main/java/ohi/andre/consolelauncher/tuils/html_escape/Html5EscapeSymbolsInitializer.java
 create mode 100755 app/src/main/java/ohi/andre/consolelauncher/tuils/html_escape/HtmlEscape.java
 create mode 100755 app/src/main/java/ohi/andre/consolelauncher/tuils/html_escape/HtmlEscapeLevel.java
 create mode 100755 app/src/main/java/ohi/andre/consolelauncher/tuils/html_escape/HtmlEscapeSymbols.java
 create mode 100755 app/src/main/java/ohi/andre/consolelauncher/tuils/html_escape/HtmlEscapeType.java
 create mode 100755 app/src/main/java/ohi/andre/consolelauncher/tuils/html_escape/HtmlEscapeUtil.java
 create mode 100644 app/src/main/res/menu/notification_menu.xml

diff --git a/app/build.gradle b/app/build.gradle
index cd8655d..991a1d7 100755
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -11,8 +11,8 @@ android {
         minSdkVersion 9
         targetSdkVersion 23
 
-        versionCode 137
-        versionName "6.3k"
+        versionCode 150
+        versionName "6.4"
     }
 
     buildTypes {
@@ -40,7 +40,9 @@ android {
 
     applicationVariants.all { variant ->
         def vn = variant.versionName
+
         def x = vn.substring(0, vn.length() - 1)
+        if (x.endsWith(".")) x = vn
 
         variant.outputs.each { output ->
             output.outputFile = new File(
@@ -56,4 +58,5 @@ android {
 }
 dependencies {
     compile 'com.google.firebase:firebase-database:9.0.0'
+    compile 'com.squareup.okhttp3:okhttp:3.9.0'
 }
\ No newline at end of file
diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro
index 2cc184a..3d30a1d 100755
--- a/app/proguard-rules.pro
+++ b/app/proguard-rules.pro
@@ -3,7 +3,7 @@
 -keep public class ohi.andre.consolelauncher.commands.tuixt.raw.* { public *; }
 
 -keep public class ohi.andre.consolelauncher.managers.notifications.NotificationService
--keep public class ohi.andre.consolelauncher.tuils.KeeperService
+-keep public class ohi.andre.consolelauncher.managers.notifications.KeeperService
 
 -keep public class ohi.andre.consolelauncher.managers.options.**
 
@@ -11,4 +11,9 @@
 
 -dontwarn javax.annotation.**
 -dontwarn javax.inject.**
--dontwarn sun.misc.Unsafe
\ No newline at end of file
+-dontwarn sun.misc.Unsafe
+
+-dontwarn okhttp3.**
+-dontwarn okio.**
+-dontwarn javax.annotation.**
+-keepnames class okhttp3.internal.publicsuffix.PublicSuffixDatabase
\ No newline at end of file
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 8c33c70..9b35847 100755
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -114,7 +114,7 @@
         </receiver>
 
         <service
-            android:name=".tuils.KeeperService"
+            android:name=".managers.notifications.KeeperService"
             android:enabled="true"
             android:exported="false" />
 
diff --git a/app/src/main/java/ohi/andre/consolelauncher/LauncherActivity.java b/app/src/main/java/ohi/andre/consolelauncher/LauncherActivity.java
index e282eab..b114ee4 100755
--- a/app/src/main/java/ohi/andre/consolelauncher/LauncherActivity.java
+++ b/app/src/main/java/ohi/andre/consolelauncher/LauncherActivity.java
@@ -6,7 +6,6 @@ import android.content.Intent;
 import android.content.IntentFilter;
 import android.content.SharedPreferences;
 import android.content.pm.PackageManager;
-import android.content.res.Configuration;
 import android.os.Build;
 import android.os.Bundle;
 import android.os.Handler;
@@ -28,7 +27,10 @@ import java.util.Queue;
 import ohi.andre.consolelauncher.commands.main.MainPack;
 import ohi.andre.consolelauncher.commands.tuixt.TuixtActivity;
 import ohi.andre.consolelauncher.managers.ContactManager;
+import ohi.andre.consolelauncher.managers.RegexManager;
 import ohi.andre.consolelauncher.managers.TerminalManager;
+import ohi.andre.consolelauncher.managers.TimeManager;
+import ohi.andre.consolelauncher.managers.notifications.KeeperService;
 import ohi.andre.consolelauncher.managers.notifications.NotificationManager;
 import ohi.andre.consolelauncher.managers.notifications.NotificationMonitorService;
 import ohi.andre.consolelauncher.managers.notifications.NotificationService;
@@ -40,9 +42,8 @@ import ohi.andre.consolelauncher.managers.xml.options.Theme;
 import ohi.andre.consolelauncher.managers.xml.options.Ui;
 import ohi.andre.consolelauncher.tuils.Assist;
 import ohi.andre.consolelauncher.tuils.InputOutputReceiver;
-import ohi.andre.consolelauncher.tuils.KeeperService;
+import ohi.andre.consolelauncher.tuils.LongClickableSpan;
 import ohi.andre.consolelauncher.tuils.SimpleMutableEntry;
-import ohi.andre.consolelauncher.tuils.TimeManager;
 import ohi.andre.consolelauncher.tuils.Tuils;
 import ohi.andre.consolelauncher.tuils.interfaces.CommandExecuter;
 import ohi.andre.consolelauncher.tuils.interfaces.Inputable;
@@ -53,6 +54,7 @@ import ohi.andre.consolelauncher.tuils.interfaces.Suggester;
 public class LauncherActivity extends AppCompatActivity implements Reloadable {
 
     private final String FIRSTACCESS_KEY = "x3";
+    private final String NEED_RESET_TIME = "t0";
 
     public static final int COMMAND_REQUEST_PERMISSION = 10;
     public static final int STARTING_PERMISSION = 11;
@@ -71,28 +73,34 @@ public class LauncherActivity extends AppCompatActivity implements Reloadable {
         @Override
         public void run() {
             finish();
+
+            Intent startMain = new Intent(Intent.ACTION_MAIN);
+            startMain.addCategory(Intent.CATEGORY_HOME);
+            startActivity(startMain);
         }
     };
 
     private CommandExecuter ex = new CommandExecuter() {
 
         @Override
-        public String exec(String cmd, String aliasName) {
+        public void exec(String cmd, String aliasName) {
             if(main != null) main.onCommand(cmd, aliasName);
-            return null;
         }
 
         @Override
-        public String exec(String input) {
+        public void exec(String input) {
             exec(input, false);
-            return null;
         }
 
         @Override
-        public String exec(String input, boolean needWriteInput) {
+        public void exec(String input, boolean needWriteInput) {
             if(ui != null && needWriteInput) ui.setOutput(input, TerminalManager.CATEGORY_INPUT);
             if(main != null) main.onCommand(input, null);
-            return null;
+        }
+
+        @Override
+        public void exec(String input, Object obj) {
+            if(main != null) main.onCommand(input, obj);
         }
 
     };
@@ -200,7 +208,7 @@ public class LauncherActivity extends AppCompatActivity implements Reloadable {
 
         @Override
         public void dispose() {
-            handler.removeCallbacksAndMessages(null);
+            if(handler != null) handler.removeCallbacksAndMessages(null);
         }
     };
 
@@ -234,23 +242,35 @@ public class LauncherActivity extends AppCompatActivity implements Reloadable {
 
     private void finishOnCreate() {
 
-//        Thread.currentThread().setUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
-//            @Override
-//            public void uncaughtException(Thread t, Throwable e) {
-//                Tuils.toFile(e);
-//            }
-//        });
+        RegexManager.create(this);
+
+        Thread.currentThread().setUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
+            @Override
+            public void uncaughtException(Thread t, Throwable e) {
+                Tuils.toFile(e);
+                Tuils.log(e);
+                System.exit(1);
+            }
+        });
 
         IntentFilter filter = new IntentFilter();
         filter.addAction(InputOutputReceiver.ACTION_CMD);
         filter.addAction(InputOutputReceiver.ACTION_OUTPUT);
+        filter.addAction(InputOutputReceiver.ACTION_INPUT);
 
-        ioReceiver = new InputOutputReceiver(ex, out);
+        ioReceiver = new InputOutputReceiver(ex, out, in);
         getApplicationContext().registerReceiver(ioReceiver, filter);
 
         try {
             XMLPrefsManager.create(this);
-            TimeManager.create();
+            new Thread() {
+                @Override
+                public void run() {
+                    super.run();
+
+                    TimeManager.create();
+                }
+            }.start();
         } catch (Exception e) {
             Tuils.log(Tuils.getStackTrace(e));
             Tuils.toFile(e);
@@ -269,6 +289,7 @@ public class LauncherActivity extends AppCompatActivity implements Reloadable {
         boolean showNotification = XMLPrefsManager.getBoolean(Behavior.tui_notification);
         Intent keeperIntent = new Intent(this, KeeperService.class);
         if (showNotification) {
+            keeperIntent.putExtra(KeeperService.PATH_KEY, XMLPrefsManager.get(Behavior.home_path));
             startService(keeperIntent);
         } else {
             try {
@@ -299,10 +320,7 @@ public class LauncherActivity extends AppCompatActivity implements Reloadable {
             Tuils.toFile(e);
         }
 
-
-        boolean notifications = XMLPrefsManager.getBoolean(Notifications.show_notifications) ||
-                XMLPrefsManager.get(Notifications.show_notifications).equalsIgnoreCase("enabled");
-
+        boolean notifications = XMLPrefsManager.getBoolean(Notifications.show_notifications) || XMLPrefsManager.get(Notifications.show_notifications).equalsIgnoreCase("enabled");
         if(notifications) {
             try {
                 ComponentName thisComponent = new ComponentName(this, NotificationService.class);
@@ -330,6 +348,8 @@ public class LauncherActivity extends AppCompatActivity implements Reloadable {
             }
         }
 
+        LongClickableSpan.longPressVibrateDuration = XMLPrefsManager.getInt(Behavior.long_click_vibration_duration);
+
         openKeyboardOnStart = XMLPrefsManager.getBoolean(Behavior.auto_show_keyboard);
         if (!openKeyboardOnStart) {
             this.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN | WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE);
@@ -339,7 +359,7 @@ public class LauncherActivity extends AppCompatActivity implements Reloadable {
 
         ViewGroup mainView = (ViewGroup) findViewById(R.id.mainview);
         main = new MainManager(this, in, out, sugg, ex);
-        ui = new UIManager(main.getMainPack(), this, mainView, ex, main.getMainPack(), canApplyTheme);
+        ui = new UIManager(this, mainView, ex, main.getMainPack(), canApplyTheme);
         main.setRedirectionListener(ui.buildRedirectionListener());
         main.setHintable(ui.getHintable());
         main.setRooter(ui.getRooter());
@@ -350,16 +370,25 @@ public class LauncherActivity extends AppCompatActivity implements Reloadable {
         if(fullscreen) Assist.assistActivity(this);
 
         SharedPreferences preferences = getPreferences(0);
+        SharedPreferences.Editor editor = preferences.edit();
+
         boolean firstAccess = preferences.getBoolean(FIRSTACCESS_KEY, true);
         if (firstAccess) {
-            SharedPreferences.Editor editor = preferences.edit();
             editor.putBoolean(FIRSTACCESS_KEY, false);
-            editor.commit();
 
             ui.setOutput(getString(R.string.firsthelp_text), TerminalManager.CATEGORY_OUTPUT);
             ui.setInput("tutorial");
         }
 
+        boolean needResetTime = preferences.getBoolean(NEED_RESET_TIME, true);
+        if(needResetTime) {
+            editor.putBoolean(NEED_RESET_TIME, false);
+
+            Behavior.time_format.parent().write(Behavior.time_format, Behavior.time_format.defaultValue());
+        }
+
+        editor.apply();
+
         System.gc();
     }
 
@@ -392,9 +421,9 @@ public class LauncherActivity extends AppCompatActivity implements Reloadable {
         super.onDestroy();
 
         try {
-            stopService(new Intent(this, KeeperService.class));
-            stopService(new Intent(this, NotificationMonitorService.class));
             getApplicationContext().unregisterReceiver(ioReceiver);
+            stopService(new Intent(this, NotificationMonitorService.class));
+            stopService(new Intent(this, KeeperService.class));
         } catch (NoClassDefFoundError | Exception e) {}
 
         overridePendingTransition(0,0);
@@ -431,10 +460,6 @@ public class LauncherActivity extends AppCompatActivity implements Reloadable {
             public void run() {
                 super.run();
 
-                try {
-                    sleep(1000);
-                } catch (InterruptedException e) {}
-
                 runOnUiThread(stopActivity);
             }
         }.start();
@@ -546,9 +571,15 @@ public class LauncherActivity extends AppCompatActivity implements Reloadable {
     }
 
     @Override
-    public void onConfigurationChanged(Configuration newConfig) {
-        super.onConfigurationChanged(newConfig);
-
-        if(ui != null) ui.scrollToEnd();
+    protected void onNewIntent(Intent intent) {
+        super.onNewIntent(intent);
+
+        String cmd = intent.getStringExtra(InputOutputReceiver.TEXT);
+        if(cmd != null) {
+            Intent i = new Intent(InputOutputReceiver.ACTION_CMD);
+            i.putExtra(InputOutputReceiver.TEXT, cmd);
+            i.putExtra(InputOutputReceiver.SHOW_CONTENT, true);
+            sendBroadcast(i);
+        }
     }
 }
diff --git a/app/src/main/java/ohi/andre/consolelauncher/MainManager.java b/app/src/main/java/ohi/andre/consolelauncher/MainManager.java
index 8a890cf..92c1908 100755
--- a/app/src/main/java/ohi/andre/consolelauncher/MainManager.java
+++ b/app/src/main/java/ohi/andre/consolelauncher/MainManager.java
@@ -22,13 +22,13 @@ import ohi.andre.consolelauncher.managers.AppsManager;
 import ohi.andre.consolelauncher.managers.ContactManager;
 import ohi.andre.consolelauncher.managers.RssManager;
 import ohi.andre.consolelauncher.managers.TerminalManager;
+import ohi.andre.consolelauncher.managers.TimeManager;
 import ohi.andre.consolelauncher.managers.music.MusicManager2;
 import ohi.andre.consolelauncher.managers.xml.XMLPrefsManager;
 import ohi.andre.consolelauncher.managers.xml.options.Behavior;
 import ohi.andre.consolelauncher.managers.xml.options.Theme;
 import ohi.andre.consolelauncher.tuils.Compare;
 import ohi.andre.consolelauncher.tuils.StoppableThread;
-import ohi.andre.consolelauncher.tuils.TimeManager;
 import ohi.andre.consolelauncher.tuils.Tuils;
 import ohi.andre.consolelauncher.tuils.interfaces.CommandExecuter;
 import ohi.andre.consolelauncher.tuils.interfaces.Hintable;
@@ -40,6 +40,7 @@ import ohi.andre.consolelauncher.tuils.interfaces.Rooter;
 import ohi.andre.consolelauncher.tuils.interfaces.Suggester;
 import ohi.andre.consolelauncher.tuils.libsuperuser.Shell;
 import ohi.andre.consolelauncher.tuils.libsuperuser.ShellHolder;
+import okhttp3.OkHttpClient;
 
 /*Copyright Francesco Andreuzzi
 
@@ -94,7 +95,7 @@ public class MainManager {
             new AliasTrigger(),
             new TuiCommandTrigger(),
             new AppTrigger(),
-            new SystemCommandTrigger()
+            new ShellCommandTrigger()
     };
     private MainPack mainPack;
 
@@ -140,9 +141,23 @@ public class MainManager {
         ShellHolder shellHolder = new ShellHolder(out);
         interactive = shellHolder.build();
 
-        RssManager rss = new RssManager(mContext);
+        OkHttpClient client = new OkHttpClient();
+        RssManager rss = new RssManager(mContext, client);
 
-        mainPack = new MainPack(mContext, group, aliasManager, appsMgr, music, cont, c, executer, redirectator, shellHolder, rss);
+        mainPack = new MainPack(mContext, group, aliasManager, appsMgr, music, cont, c, executer, redirectator, shellHolder, rss, client);
+    }
+
+    public void onCommand(String input, Object obj) {
+        if(obj == null || !(obj instanceof AppsManager.LaunchInfo)) {
+            onCommand(input, null);
+            return;
+        }
+
+        if(obj instanceof AppsManager.LaunchInfo && ((AppsManager.LaunchInfo) obj).publicLabel.equals(input)) {
+            performLaunch((AppsManager.LaunchInfo) obj);
+        } else {
+            onCommand(input, null);
+        }
     }
 
 //    command manager
@@ -202,13 +217,18 @@ public class MainManager {
     public void destroy() {
         mainPack.destroy();
 
-        new Thread() {
+        new StoppableThread() {
             @Override
             public void run() {
                 super.run();
 
-                interactive.kill();
-                interactive.close();
+                try {
+                    interactive.kill();
+                    interactive.close();
+                } catch (Exception e) {
+                    Tuils.log(e);
+                    Tuils.toFile(e);
+                }
             }
         }.start();
     }
@@ -225,6 +245,47 @@ public class MainManager {
         this.mainPack.rooter = rooter;
     }
 
+//
+    String appFormat;
+    int timeColor;
+    int outputColor;
+
+    Pattern pa = Pattern.compile("%a", Pattern.CASE_INSENSITIVE | Pattern.LITERAL);
+    Pattern pp = Pattern.compile("%p", Pattern.CASE_INSENSITIVE | Pattern.LITERAL);
+    Pattern pl = Pattern.compile("%l", Pattern.CASE_INSENSITIVE | Pattern.LITERAL);
+    Pattern pn = Pattern.compile("%n", Pattern.CASE_INSENSITIVE | Pattern.LITERAL);
+
+    public boolean performLaunch(AppsManager.LaunchInfo i) {
+        Intent intent = mainPack.appsManager.getIntent(i);
+        if (intent == null) {
+            return false;
+        }
+
+        if(showAppHistory) {
+            if(appFormat == null) {
+                appFormat = XMLPrefsManager.get(Behavior.app_launch_format);
+                timeColor = XMLPrefsManager.getColor(Theme.time_color);
+                outputColor = XMLPrefsManager.getColor(Theme.output_color);
+            }
+
+            String a = new String(appFormat);
+            a = pa.matcher(a).replaceAll(Matcher.quoteReplacement(intent.getComponent().getClassName()));
+            a = pp.matcher(a).replaceAll(Matcher.quoteReplacement(intent.getComponent().getPackageName()));
+            a = pl.matcher(a).replaceAll(Matcher.quoteReplacement(i.publicLabel));
+            a = pn.matcher(a).replaceAll(Matcher.quoteReplacement(Tuils.NEWLINE));
+
+            SpannableString text = new SpannableString(a);
+            text.setSpan(new ForegroundColorSpan(outputColor), 0, text.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
+            CharSequence s = TimeManager.replace(text, timeColor);
+
+            out.onOutput(s, TerminalManager.CATEGORY_OUTPUT);
+        }
+
+        mContext.startActivity(intent);
+        return true;
+    }
+//
+
     interface CmdTrigger {
         boolean trigger(ExecutePack info, String input) throws Exception;
     }
@@ -284,7 +345,7 @@ public class MainManager {
         }
     }
 
-    private class SystemCommandTrigger implements CmdTrigger {
+    private class ShellCommandTrigger implements CmdTrigger {
 
         final int CD_CODE = 10;
         final int PWD_CODE = 11;
@@ -314,7 +375,7 @@ public class MainManager {
         @Override
         public boolean trigger(final ExecutePack info, final String input) throws Exception {
 
-            new Thread() {
+            new StoppableThread() {
                 @Override
                 public void run() {
                     if(input.trim().equalsIgnoreCase("su")) {
@@ -336,49 +397,10 @@ public class MainManager {
 
     private class AppTrigger implements CmdTrigger {
 
-        String appFormat;
-        int timeColor;
-        int outputColor;
-
-        Pattern pa = Pattern.compile("%a", Pattern.CASE_INSENSITIVE | Pattern.LITERAL);
-        Pattern pp = Pattern.compile("%p", Pattern.CASE_INSENSITIVE | Pattern.LITERAL);
-        Pattern pl = Pattern.compile("%l", Pattern.CASE_INSENSITIVE | Pattern.LITERAL);
-        Pattern pn = Pattern.compile("%n", Pattern.CASE_INSENSITIVE | Pattern.LITERAL);
-
         @Override
         public boolean trigger(ExecutePack info, String input) {
             AppsManager.LaunchInfo i = mainPack.appsManager.findLaunchInfoWithLabel(input, AppsManager.SHOWN_APPS);
-            if (i == null) {
-                return false;
-            }
-
-            Intent intent = mainPack.appsManager.getIntent(i);
-            if (intent == null) {
-                return false;
-            }
-
-            if(showAppHistory) {
-                if(appFormat == null) {
-                    appFormat = XMLPrefsManager.get(Behavior.app_launch_format);
-                    timeColor = XMLPrefsManager.getColor(Theme.time_color);
-                    outputColor = XMLPrefsManager.getColor(Theme.output_color);
-                }
-
-                String a = new String(appFormat);
-                a = pa.matcher(a).replaceAll(Matcher.quoteReplacement(intent.getComponent().getClassName()));
-                a = pp.matcher(a).replaceAll(Matcher.quoteReplacement(intent.getComponent().getPackageName()));
-                a = pl.matcher(a).replaceAll(Matcher.quoteReplacement(i.publicLabel));
-                a = pn.matcher(a).replaceAll(Matcher.quoteReplacement(Tuils.NEWLINE));
-
-                SpannableString text = new SpannableString(a);
-                text.setSpan(new ForegroundColorSpan(outputColor), 0, text.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
-                CharSequence s = TimeManager.replace(text, timeColor);
-
-                out.onOutput(s, TerminalManager.CATEGORY_GENERAL);
-            }
-
-            mContext.startActivity(intent);
-            return true;
+            return i != null && performLaunch(i);
         }
     }
 
diff --git a/app/src/main/java/ohi/andre/consolelauncher/UIManager.java b/app/src/main/java/ohi/andre/consolelauncher/UIManager.java
index 8f9e4b9..c620d4b 100755
--- a/app/src/main/java/ohi/andre/consolelauncher/UIManager.java
+++ b/app/src/main/java/ohi/andre/consolelauncher/UIManager.java
@@ -41,11 +41,11 @@ import java.util.List;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
-import ohi.andre.consolelauncher.commands.ExecutePack;
 import ohi.andre.consolelauncher.commands.main.MainPack;
 import ohi.andre.consolelauncher.commands.specific.RedirectCommand;
 import ohi.andre.consolelauncher.managers.MessagesManager;
 import ohi.andre.consolelauncher.managers.TerminalManager;
+import ohi.andre.consolelauncher.managers.TimeManager;
 import ohi.andre.consolelauncher.managers.suggestions.SuggestionRunnable;
 import ohi.andre.consolelauncher.managers.suggestions.SuggestionsManager;
 import ohi.andre.consolelauncher.managers.xml.XMLPrefsManager;
@@ -57,7 +57,6 @@ import ohi.andre.consolelauncher.managers.xml.options.Ui;
 import ohi.andre.consolelauncher.tuils.AllowEqualsSequence;
 import ohi.andre.consolelauncher.tuils.NetworkUtils;
 import ohi.andre.consolelauncher.tuils.StoppableThread;
-import ohi.andre.consolelauncher.tuils.TimeManager;
 import ohi.andre.consolelauncher.tuils.Tuils;
 import ohi.andre.consolelauncher.tuils.interfaces.CommandExecuter;
 import ohi.andre.consolelauncher.tuils.interfaces.Hintable;
@@ -104,21 +103,14 @@ public class UIManager implements OnTouchListener {
 
     private String multipleCmdSeparator;
 
-//    private boolean selectFirstSuggestionEnter = false;
     private OnNewInputListener inputListener = new OnNewInputListener() {
         @Override
-        public void onNewInput(String input) {
+        public void onNewInput(String input, Object obj) {
             if(suggestionsView != null) {
-//                if(suggestionsView.getChildCount() > 0 && selectFirstSuggestionEnter) {
-//                    View v = suggestionsView.getChildAt(0);
-//                    v.performClick();
-//                    return;
-//                }
                 suggestionsView.removeAllViews();
-
             }
-            trigger.exec(input);
 
+            trigger.exec(input, obj);
         }
     };
 
@@ -435,6 +427,7 @@ public class UIManager implements OnTouchListener {
         final Pattern nl = Pattern.compile("%n", Pattern.CASE_INSENSITIVE | Pattern.LITERAL);
         final Pattern ip4 = Pattern.compile("%ip4", Pattern.CASE_INSENSITIVE | Pattern.LITERAL);
         final Pattern ip6 = Pattern.compile("%ip6", Pattern.CASE_INSENSITIVE | Pattern.LITERAL);
+        final Pattern dt = Pattern.compile("%dt", Pattern.CASE_INSENSITIVE | Pattern.LITERAL);
 
         final Pattern optionalWifi = Pattern.compile("%\\(([^/]*)/([^)]*)\\)", Pattern.CASE_INSENSITIVE);
         final Pattern optionalData = Pattern.compile("%\\[([^/]*)/([^\\]]*)\\]", Pattern.CASE_INSENSITIVE);
@@ -459,7 +452,7 @@ public class UIManager implements OnTouchListener {
             if(format == null) {
                 format = XMLPrefsManager.get(Behavior.network_info_format);
                 color = XMLPrefsManager.getColor(Theme.network_info_color);
-                maxDepth = XMLPrefsManager.getInt(Behavior.max_optional_depth_network_info);
+                maxDepth = XMLPrefsManager.getInt(Behavior.max_optional_depth);
 
                 updateTime = XMLPrefsManager.getInt(Behavior.network_info_update_ms);
                 if(updateTime < 1000) updateTime = Integer.parseInt(Behavior.network_info_update_ms.defaultValue());
@@ -478,12 +471,6 @@ public class UIManager implements OnTouchListener {
                 }
             }
 
-//            mobile data
-            boolean mobileOn = false;
-            try {
-                mobileOn = method != null && connectivityManager != null && (Boolean) method.invoke(connectivityManager);
-            } catch (Exception e) {}
-
 //            wifi
             boolean wifiOn = connectivityManager.getNetworkInfo(ConnectivityManager.TYPE_WIFI).isConnected();
             String wifiName = null;
@@ -494,6 +481,19 @@ public class UIManager implements OnTouchListener {
                 }
             }
 
+//            mobile data
+            boolean mobileOn = false;
+            try {
+                mobileOn = method != null && connectivityManager != null && (Boolean) method.invoke(connectivityManager);
+            } catch (Exception e) {}
+
+            String mobileType = null;
+            if(mobileOn) {
+                mobileType = Tuils.getNetworkType(mContext);
+            } else {
+                mobileType = "unknown";
+            }
+
 //            bluetooth
             boolean bluetoothOn = mBluetoothAdapter != null && mBluetoothAdapter.isEnabled();
 
@@ -523,6 +523,7 @@ public class UIManager implements OnTouchListener {
             copy = b4.matcher(copy).replaceAll(bluetoothOn ? TRUE : FALSE);
             copy = ip4.matcher(copy).replaceAll(NetworkUtils.getIPAddress(true));
             copy = ip6.matcher(copy).replaceAll(NetworkUtils.getIPAddress(false));
+            copy = dt.matcher(copy).replaceAll(mobileType);
             copy = nl.matcher(copy).replaceAll(Tuils.NEWLINE);
 
             int i = Label.network.ordinal();
@@ -648,10 +649,12 @@ public class UIManager implements OnTouchListener {
             if(suggestion.type == SuggestionsManager.Suggestion.TYPE_PERMANENT) {
                 mTerminalAdapter.setInput(input + text);
             } else {
+                boolean addSpace = suggestion.type != SuggestionsManager.Suggestion.TYPE_FILE && suggestion.type != SuggestionsManager.Suggestion.TYPE_COLOR;
+
                 if(multipleCmdSeparator.length() > 0) {
                     String[] split = input.split(multipleCmdSeparator);
                     if(split.length == 0) return;
-                    if(split.length == 1) mTerminalAdapter.setInput(text + (suggestion.type == SuggestionsManager.Suggestion.TYPE_FILE ? Tuils.EMPTYSTRING : Tuils.SPACE));
+                    if(split.length == 1) mTerminalAdapter.setInput(text + (addSpace ? Tuils.SPACE : Tuils.EMPTYSTRING), suggestion.object);
                     else {
                         split[split.length - 1] = Tuils.EMPTYSTRING;
 
@@ -660,10 +663,10 @@ public class UIManager implements OnTouchListener {
                             beforeInputs = beforeInputs + split[count] + multipleCmdSeparator;
                         }
 
-                        mTerminalAdapter.setInput(beforeInputs + text + (suggestion.type == SuggestionsManager.Suggestion.TYPE_FILE ? Tuils.EMPTYSTRING : Tuils.SPACE));
+                        mTerminalAdapter.setInput(beforeInputs + text + (addSpace ? Tuils.SPACE : Tuils.EMPTYSTRING), suggestion.object);
                     }
                 } else {
-                    mTerminalAdapter.setInput(text + (suggestion.type == SuggestionsManager.Suggestion.TYPE_FILE ? Tuils.EMPTYSTRING : Tuils.SPACE));
+                    mTerminalAdapter.setInput(text + (addSpace ? Tuils.SPACE : Tuils.EMPTYSTRING), suggestion.object);
                 }
             }
 
@@ -790,7 +793,7 @@ public class UIManager implements OnTouchListener {
         } catch (InternalError e) {}
     }
 
-    protected UIManager(ExecutePack info, final Context context, final ViewGroup rootView, final CommandExecuter tri, MainPack mainPack, boolean canApplyTheme) {
+    protected UIManager(final Context context, final ViewGroup rootView, final CommandExecuter tri, MainPack mainPack, boolean canApplyTheme) {
 
         policy = (DevicePolicyManager) context.getSystemService(Context.DEVICE_POLICY_SERVICE);
         component = new ComponentName(context, PolicyReceiver.class);
@@ -799,7 +802,7 @@ public class UIManager implements OnTouchListener {
 //        selectFirstSuggestionEnter = XMLPrefsManager.get(boolean.class, XMLPrefsManager.Behavior.enter_first_suggestion);
 
         mContext = context;
-        this.info = (MainPack) info;
+        this.info = mainPack;
 
         trigger = tri;
 
@@ -863,12 +866,12 @@ public class UIManager implements OnTouchListener {
         float nIndex = showNetwork ? XMLPrefsManager.getFloat(Ui.network_index) : Integer.MAX_VALUE;
 
         int[] pos = {
-                XMLPrefsManager.getInt(Ui.status_line0_position),
-                XMLPrefsManager.getInt(Ui.status_line1_position),
-                XMLPrefsManager.getInt(Ui.status_line2_position),
-                XMLPrefsManager.getInt(Ui.status_line3_position),
-                XMLPrefsManager.getInt(Ui.status_line4_position),
-                XMLPrefsManager.getInt(Ui.status_line5_position)
+                XMLPrefsManager.getInt(Ui.status_line0_alignment),
+                XMLPrefsManager.getInt(Ui.status_line1_alignment),
+                XMLPrefsManager.getInt(Ui.status_line2_alignment),
+                XMLPrefsManager.getInt(Ui.status_line3_alignment),
+                XMLPrefsManager.getInt(Ui.status_line4_alignment),
+                XMLPrefsManager.getInt(Ui.status_line5_alignment)
         };
 
         AllowEqualsSequence sequence = new AllowEqualsSequence(new float[] {rIndex, dIndex, bIndex, tIndex, sIndex, nIndex},
@@ -890,6 +893,7 @@ public class UIManager implements OnTouchListener {
             if(count >= sequence.getMinKey() && count <= sequence.getMaxKey() && os.length > 0) {
                 labelViews[count].setTypeface(Tuils.getTypeface(context));
 
+//                -1 = left     0 = center     1 = right
                 int p = pos[count];
                 if(p >= 0) labelViews[count].setGravity(p == 0 ? Gravity.CENTER_HORIZONTAL : Gravity.RIGHT);
             } else {
@@ -1049,36 +1053,38 @@ public class UIManager implements OnTouchListener {
 
         if(XMLPrefsManager.getBoolean(Behavior.show_hints)) {
             MessagesManager messagesManager = new MessagesManager(context,
-                    new MessagesManager.Message(context.getString(R.string.hint_alias)),
-                    new MessagesManager.Message(context.getString(R.string.hint_appgroups)),
-                    new MessagesManager.Message(context.getString(R.string.hint_clear)),
-                    new MessagesManager.Message(context.getString(R.string.hint_config)),
-                    new MessagesManager.Message(context.getString(R.string.hint_disable)),
-                    new MessagesManager.Message(context.getString(R.string.hint_donate)),
-                    new MessagesManager.Message(context.getString(R.string.hint_googlep)),
-                    new MessagesManager.Message(context.getString(R.string.hint_help)),
-                    new MessagesManager.Message(context.getString(R.string.hint_music)),
-                    new MessagesManager.Message(context.getString(R.string.hint_notifications)),
-                    new MessagesManager.Message(context.getString(R.string.hint_telegram)),
-                    new MessagesManager.Message(context.getString(R.string.hint_theme)),
-                    new MessagesManager.Message(context.getString(R.string.hint_theme2)),
-                    new MessagesManager.Message(context.getString(R.string.hint_tutorial)),
-                    new MessagesManager.Message(context.getString(R.string.hint_twitter)),
-                    new MessagesManager.Message(context.getString(R.string.hint_wallpaper)),
-                    new MessagesManager.Message(context.getString(R.string.hint_musicdisable)));
+                    new MessagesManager.Message(R.string.hint_alias),
+                    new MessagesManager.Message(R.string.hint_appgroups),
+                    new MessagesManager.Message(R.string.hint_clear),
+                    new MessagesManager.Message(R.string.hint_config),
+                    new MessagesManager.Message(R.string.hint_disable),
+                    new MessagesManager.Message(R.string.hint_donate),
+                    new MessagesManager.Message(R.string.hint_googlep),
+                    new MessagesManager.Message(R.string.hint_help),
+                    new MessagesManager.Message(R.string.hint_music),
+                    new MessagesManager.Message(R.string.hint_notifications),
+                    new MessagesManager.Message(R.string.hint_telegram),
+                    new MessagesManager.Message(R.string.hint_theme),
+                    new MessagesManager.Message(R.string.hint_theme2),
+                    new MessagesManager.Message(R.string.hint_tutorial),
+                    new MessagesManager.Message(R.string.hint_twitter),
+                    new MessagesManager.Message(R.string.hint_wallpaper),
+                    new MessagesManager.Message(R.string.hint_musicdisable),
+                    new MessagesManager.Message(R.string.hint_excludenotification)
+            );
 
             mTerminalAdapter.setMessagesManager(messagesManager);
         }
     }
 
     public void dispose() {
-        handler.removeCallbacksAndMessages(null);
+        if(handler != null) handler.removeCallbacksAndMessages(null);
     }
 
     public void openKeyboard() {
         mTerminalAdapter.requestInputFocus();
         imm.showSoftInput(mTerminalAdapter.getInputView(), InputMethodManager.SHOW_IMPLICIT);
-        mTerminalAdapter.scrollToEnd();
+//        mTerminalAdapter.scrollToEnd();
     }
 
     public void closeKeyboard() {
@@ -1135,10 +1141,6 @@ public class UIManager implements OnTouchListener {
         mTerminalAdapter.requestInputFocus();
     }
 
-    public void scrollToEnd() {
-        mTerminalAdapter.scrollToEnd();
-    }
-
     public Hintable getHintable() {
         return new Hintable() {
             @Override
@@ -1245,13 +1247,13 @@ public class UIManager implements OnTouchListener {
         };
     }
 
-    public interface SuggestionNavigator {
-        boolean isNavigating();
-        void onEnter();
-    }
+//    public interface SuggestionNavigator {
+//        boolean isNavigating();
+//        void onEnter();
+//    }
 
     public interface OnNewInputListener {
-        void onNewInput(String input);
+        void onNewInput(String input, Object obj);
     }
 
 //    public class PowerConnectionReceiver extends BroadcastReceiver {
diff --git a/app/src/main/java/ohi/andre/consolelauncher/commands/Command.java b/app/src/main/java/ohi/andre/consolelauncher/commands/Command.java
index e104cc4..340dbff 100755
--- a/app/src/main/java/ohi/andre/consolelauncher/commands/Command.java
+++ b/app/src/main/java/ohi/andre/consolelauncher/commands/Command.java
@@ -41,7 +41,7 @@ public class Command {
                 param.onArgNotFound(info, indexNotFound);
             }
 
-            if(pCmd.supportDefaultParam()) {
+            if(pCmd.defaultParamReference() != null) {
                 if(args.length > nArgs) {
                     return param.onNotArgEnough(info, nArgs);
                 }
@@ -53,8 +53,11 @@ public class Command {
         } else if(indexNotFound != -1) {
             return cmd.onArgNotFound(info, indexNotFound);
         }
-        else if (nArgs < cmd.minArgs() || (mArgs == null && cmd.minArgs() > 0)) {
-            return cmd.onNotArgEnough(info, nArgs);
+        else {
+            int[] args = cmd.argType();
+            if (nArgs < args.length || (mArgs == null && args.length > 0)) {
+                return cmd.onNotArgEnough(info, nArgs);
+            }
         }
 
         String output = cmd.exec(info);
@@ -80,8 +83,7 @@ public class Command {
         try {
             return args[useParamArgs ? nArgs - 1 : nArgs];
         } catch (ArrayIndexOutOfBoundsException e) {
-            nArgs -= 1;
-            return nextArg();
+            return 0;
         }
     }
 }
diff --git a/app/src/main/java/ohi/andre/consolelauncher/commands/CommandAbstraction.java b/app/src/main/java/ohi/andre/consolelauncher/commands/CommandAbstraction.java
index 1f4f9c6..4130ecd 100755
--- a/app/src/main/java/ohi/andre/consolelauncher/commands/CommandAbstraction.java
+++ b/app/src/main/java/ohi/andre/consolelauncher/commands/CommandAbstraction.java
@@ -27,8 +27,6 @@ public interface CommandAbstraction {
 
     String exec(ExecutePack pack) throws Exception;
 
-    int minArgs();
-
     int[] argType();
 
     int priority();
diff --git a/app/src/main/java/ohi/andre/consolelauncher/commands/CommandTuils.java b/app/src/main/java/ohi/andre/consolelauncher/commands/CommandTuils.java
index 9bec0aa..68b2e27 100755
--- a/app/src/main/java/ohi/andre/consolelauncher/commands/CommandTuils.java
+++ b/app/src/main/java/ohi/andre/consolelauncher/commands/CommandTuils.java
@@ -16,11 +16,13 @@ import ohi.andre.consolelauncher.managers.AppsManager;
 import ohi.andre.consolelauncher.managers.ContactManager;
 import ohi.andre.consolelauncher.managers.FileManager;
 import ohi.andre.consolelauncher.managers.FileManager.DirInfo;
+import ohi.andre.consolelauncher.managers.RssManager;
 import ohi.andre.consolelauncher.managers.xml.XMLPrefsManager;
 import ohi.andre.consolelauncher.managers.music.MusicManager2;
 import ohi.andre.consolelauncher.managers.notifications.NotificationManager;
 import ohi.andre.consolelauncher.managers.xml.options.Apps;
 import ohi.andre.consolelauncher.managers.xml.options.Notifications;
+import ohi.andre.consolelauncher.managers.xml.options.Rss;
 import ohi.andre.consolelauncher.tuils.SimpleMutableEntry;
 import ohi.andre.consolelauncher.tuils.Tuils;
 
@@ -366,9 +368,12 @@ public class CommandTuils {
         }
 
         String param = input.substring(0, indexOfFirstSpace).trim();
-        if(param.length() > 0 && !param.startsWith("-")) param = "-".concat(param);
+        if(!param.startsWith("-")) param = "-".concat(param);
+
+        Tuils.log(param);
 
         SimpleMutableEntry<Boolean, Param> sm = cmd.getParam(pack, param);
+        Tuils.log(sm.getKey(), sm.getValue());
         Param p = sm.getValue();
         boolean df = sm.getKey();
 
@@ -429,6 +434,7 @@ public class CommandTuils {
             }
             Collections.addAll(xmlPrefsEntrys, Apps.values());
             Collections.addAll(xmlPrefsEntrys, Notifications.values());
+            Collections.addAll(xmlPrefsEntrys, Rss.values());
         }
 
         String candidate = index == -1 ? input : input.substring(0,index);
@@ -447,6 +453,7 @@ public class CommandTuils {
                 xmlPrefsFiles.add(element.path);
             xmlPrefsFiles.add(AppsManager.PATH);
             xmlPrefsFiles.add(NotificationManager.PATH);
+            xmlPrefsFiles.add(RssManager.PATH);
         }
 
         for(String xs : xmlPrefsFiles) {
diff --git a/app/src/main/java/ohi/andre/consolelauncher/commands/CommandsPreferences.java b/app/src/main/java/ohi/andre/consolelauncher/commands/CommandsPreferences.java
index 6d5b429..ef73e1d 100755
--- a/app/src/main/java/ohi/andre/consolelauncher/commands/CommandsPreferences.java
+++ b/app/src/main/java/ohi/andre/consolelauncher/commands/CommandsPreferences.java
@@ -1,7 +1,5 @@
 package ohi.andre.consolelauncher.commands;
 
-import android.util.SparseArray;
-
 import java.util.HashMap;
 
 import ohi.andre.consolelauncher.managers.xml.XMLPrefsManager;
@@ -13,30 +11,19 @@ import ohi.andre.consolelauncher.managers.xml.options.Cmd;
 
 public class CommandsPreferences {
 
-    public static final int DEFAULT_PARAM = 10;
-
-    private HashMap<String, Preference> preferenceHashMap;
+    private HashMap<String, String> preferenceHashMap;
 
     public CommandsPreferences() {
         preferenceHashMap = new HashMap<>();
 
-//        search
-        Preference searchP = new Preference();
-        searchP.add(XMLPrefsManager.get(Cmd.default_search), DEFAULT_PARAM);
-        preferenceHashMap.put("search", searchP);
-    }
-
-    public Preference forCommand(String cmd) {
-        return preferenceHashMap.get(cmd);
+        for(XMLPrefsManager.XMLPrefsSave save : Cmd.values()) {
+            preferenceHashMap.put(save.label(), XMLPrefsManager.get(save));
+        }
     }
 
-    public class Preference {
-        SparseArray<String> prefs = new SparseArray<>();
-        public void add(String pref, int id) {
-            prefs.put(id, pref);
-        }
-        public String get(int id) {
-            return prefs.get(id);
-        }
+    public String get(XMLPrefsManager.XMLPrefsSave save) {
+        String v = preferenceHashMap.get(save.label());
+        if(v == null || v.length() == 0) v = save.defaultValue();
+        return v;
     }
 }
diff --git a/app/src/main/java/ohi/andre/consolelauncher/commands/main/MainPack.java b/app/src/main/java/ohi/andre/consolelauncher/commands/main/MainPack.java
index e247032..31881a6 100755
--- a/app/src/main/java/ohi/andre/consolelauncher/commands/main/MainPack.java
+++ b/app/src/main/java/ohi/andre/consolelauncher/commands/main/MainPack.java
@@ -25,6 +25,7 @@ import ohi.andre.consolelauncher.tuils.interfaces.Redirectator;
 import ohi.andre.consolelauncher.tuils.interfaces.Reloadable;
 import ohi.andre.consolelauncher.tuils.interfaces.Rooter;
 import ohi.andre.consolelauncher.tuils.libsuperuser.ShellHolder;
+import okhttp3.OkHttpClient;
 
 /**
  * Created by francescoandreuzzi on 24/01/2017.
@@ -81,8 +82,10 @@ public class MainPack extends ExecutePack {
 
     public RssManager rssManager;
 
+    public OkHttpClient client;
+
     public MainPack(Context context, CommandGroup commandGroup, AliasManager alMgr, AppsManager appmgr, MusicManager2 p,
-                    ContactManager c, Reloadable r, CommandExecuter executeCommand, Redirectator redirectator, ShellHolder shellHolder, RssManager rssManager) {
+                    ContactManager c, Reloadable r, CommandExecuter executeCommand, Redirectator redirectator, ShellHolder shellHolder, RssManager rssManager, OkHttpClient client) {
         super(commandGroup);
 
         this.currentDirectory = XMLPrefsManager.get(File.class, Behavior.home_path);
@@ -91,6 +94,8 @@ public class MainPack extends ExecutePack {
 
         this.rssManager = rssManager;
 
+        this.client = client;
+
         this.res = context.getResources();
 
         this.executer = executeCommand;
diff --git a/app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/airplane.java b/app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/airplane.java
index aed3878..56cd940 100755
--- a/app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/airplane.java
+++ b/app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/airplane.java
@@ -40,11 +40,6 @@ public class airplane extends APICommand {
         return 2;
     }
 
-    @Override
-    public int minArgs() {
-        return 0;
-    }
-
     @Override
     public int[] argType() {
         return new int[0];
diff --git a/app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/apps.java b/app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/apps.java
index f7600e9..03d6fe7 100755
--- a/app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/apps.java
+++ b/app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/apps.java
@@ -25,22 +25,32 @@ public class apps extends ParamCommand {
         ls {
             @Override
             public int[] args() {
-                return new int[0];
+                return new int[] {CommandAbstraction.PLAIN_TEXT};
             }
 
             @Override
             public String exec(ExecutePack pack) {
+                return ((MainPack) pack).appsManager.printApps(AppsManager.SHOWN_APPS, pack.getString());
+            }
+
+            @Override
+            public String onNotArgEnough(ExecutePack pack, int n) {
                 return ((MainPack) pack).appsManager.printApps(AppsManager.SHOWN_APPS);
             }
         },
         lsh {
             @Override
             public int[] args() {
-                return new int[0];
+                return new int[] {CommandAbstraction.PLAIN_TEXT};
             }
 
             @Override
             public String exec(ExecutePack pack) {
+                return ((MainPack) pack).appsManager.printApps(AppsManager.HIDDEN_APPS, pack.getString());
+            }
+
+            @Override
+            public String onNotArgEnough(ExecutePack pack, int n) {
                 return ((MainPack) pack).appsManager.printApps(AppsManager.HIDDEN_APPS);
             }
         },
diff --git a/app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/beep.java b/app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/beep.java
index b3b7f0a..81bd802 100755
--- a/app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/beep.java
+++ b/app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/beep.java
@@ -26,11 +26,6 @@ public class beep implements CommandAbstraction {
         return null;
     }
 
-    @Override
-    public int minArgs() {
-        return 0;
-    }
-
     @Override
     public int[] argType() {
         return new int[0];
diff --git a/app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/bluetooth.java b/app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/bluetooth.java
index dbf60b7..073f0ce 100755
--- a/app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/bluetooth.java
+++ b/app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/bluetooth.java
@@ -28,11 +28,6 @@ public class bluetooth implements CommandAbstraction {
         return R.string.help_bluetooth;
     }
 
-    @Override
-    public int minArgs() {
-        return 0;
-    }
-
     @Override
     public int[] argType() {
         return new int[0];
diff --git a/app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/calc.java b/app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/calc.java
index 12b4875..e79a936 100755
--- a/app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/calc.java
+++ b/app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/calc.java
@@ -22,11 +22,6 @@ public class calc extends PermanentSuggestionCommand {
         }
     }
 
-    @Override
-    public int minArgs() {
-        return 1;
-    }
-
     @Override
     public int[] argType() {
         return new int[] {CommandAbstraction.PLAIN_TEXT};
diff --git a/app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/call.java b/app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/call.java
index dd89f05..a82ac18 100755
--- a/app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/call.java
+++ b/app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/call.java
@@ -51,11 +51,6 @@ public class call implements CommandAbstraction {
         return R.string.help_call;
     }
 
-    @Override
-    public int minArgs() {
-        return 1;
-    }
-
     @Override
     public int[] argType() {
         return new int[]{CommandAbstraction.CONTACTNUMBER};
diff --git a/app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/clear.java b/app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/clear.java
index ec09b4f..e5c9790 100755
--- a/app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/clear.java
+++ b/app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/clear.java
@@ -16,11 +16,6 @@ public class clear implements CommandAbstraction {
         return CLEAR;
     }
 
-    @Override
-    public int minArgs() {
-        return 0;
-    }
-
     @Override
     public int[] argType() {
         return new int[0];
diff --git a/app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/config.java b/app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/config.java
index 3e8fbd6..7e62b13 100755
--- a/app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/config.java
+++ b/app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/config.java
@@ -10,8 +10,9 @@ import ohi.andre.consolelauncher.commands.ExecutePack;
 import ohi.andre.consolelauncher.commands.main.MainPack;
 import ohi.andre.consolelauncher.commands.specific.ParamCommand;
 import ohi.andre.consolelauncher.managers.AppsManager;
-import ohi.andre.consolelauncher.managers.xml.XMLPrefsManager;
+import ohi.andre.consolelauncher.managers.RssManager;
 import ohi.andre.consolelauncher.managers.notifications.NotificationManager;
+import ohi.andre.consolelauncher.managers.xml.XMLPrefsManager;
 import ohi.andre.consolelauncher.managers.xml.options.Apps;
 import ohi.andre.consolelauncher.managers.xml.options.Notifications;
 import ohi.andre.consolelauncher.tuils.Tuils;
@@ -47,6 +48,21 @@ public class config extends ParamCommand {
                 return set.exec(pack);
             }
         },
+        info {
+            @Override
+            public int[] args() {
+                return new int[] {CommandAbstraction.CONFIG_ENTRY};
+            }
+
+            @Override
+            public String exec(ExecutePack pack) {
+                XMLPrefsManager.XMLPrefsSave save = pack.getPrefsSave();
+
+                return "Type:" + Tuils.SPACE + save.type() + Tuils.NEWLINE
+                        + "Default:" + Tuils.SPACE + save.defaultValue() + Tuils.NEWLINE
+                        + save.info();
+            }
+        },
         file {
             @Override
             public int[] args() {
@@ -119,6 +135,27 @@ public class config extends ParamCommand {
                     }
                 }
 
+                if(name.equalsIgnoreCase(AppsManager.PATH)) {
+                    List<String> strings = AppsManager.instance.getValues().values();
+                    Tuils.addPrefix(strings, Tuils.DOUBLE_SPACE);
+                    strings.add(0, AppsManager.PATH);
+                    return Tuils.toPlanString(strings, Tuils.NEWLINE);
+                }
+
+                if(name.equalsIgnoreCase(NotificationManager.PATH)) {
+                    List<String> strings = NotificationManager.instance.getValues().values();
+                    Tuils.addPrefix(strings, Tuils.DOUBLE_SPACE);
+                    strings.add(0, NotificationManager.PATH);
+                    return Tuils.toPlanString(strings, Tuils.NEWLINE);
+                }
+
+                if(name.equalsIgnoreCase(RssManager.PATH)) {
+                    List<String> strings = NotificationManager.instance.getValues().values();
+                    Tuils.addPrefix(strings, Tuils.DOUBLE_SPACE);
+                    strings.add(0, RssManager.PATH);
+                    return Tuils.toPlanString(strings, Tuils.NEWLINE);
+                }
+
                 return "[]";
             }
 
diff --git a/app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/ctrlc.java b/app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/ctrlc.java
index ecff729..ea26d99 100644
--- a/app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/ctrlc.java
+++ b/app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/ctrlc.java
@@ -5,6 +5,7 @@ import ohi.andre.consolelauncher.R;
 import ohi.andre.consolelauncher.commands.CommandAbstraction;
 import ohi.andre.consolelauncher.commands.ExecutePack;
 import ohi.andre.consolelauncher.commands.main.MainPack;
+import ohi.andre.consolelauncher.tuils.StoppableThread;
 
 /**
  * Created by francescoandreuzzi on 26/07/2017.
@@ -14,7 +15,7 @@ public class ctrlc implements CommandAbstraction {
 
     @Override
     public String exec(final ExecutePack pack) throws Exception {
-        new Thread() {
+        new StoppableThread() {
             @Override
             public void run() {
                 super.run();
@@ -32,11 +33,6 @@ public class ctrlc implements CommandAbstraction {
         return null;
     }
 
-    @Override
-    public int minArgs() {
-        return 0;
-    }
-
     @Override
     public int[] argType() {
         return new int[0];
diff --git a/app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/data.java b/app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/data.java
index c1263a2..52fbc65 100755
--- a/app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/data.java
+++ b/app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/data.java
@@ -69,11 +69,6 @@ public class data extends APICommand {
         return R.string.help_data;
     }
 
-    @Override
-    public int minArgs() {
-        return 0;
-    }
-
     @Override
     public int[] argType() {
         return new int[0];
diff --git a/app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/donate.java b/app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/donate.java
index 4af9b04..abfc603 100755
--- a/app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/donate.java
+++ b/app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/donate.java
@@ -34,11 +34,6 @@ public class donate implements CommandAbstraction {
         return info.res.getString(R.string.output_rate);
     }
 
-    @Override
-    public int minArgs() {
-        return 0;
-    }
-
     @Override
     public int[] argType() {
         return new int[0];
diff --git a/app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/exit.java b/app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/exit.java
index 889db6a..73f0f94 100755
--- a/app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/exit.java
+++ b/app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/exit.java
@@ -16,11 +16,6 @@ public class exit implements CommandAbstraction {
         return null;
     }
 
-    @Override
-    public int minArgs() {
-        return 0;
-    }
-
     @Override
     public int[] argType() {
         return new int[0];
diff --git a/app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/flash.java b/app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/flash.java
index 6e1d05f..e6a31fd 100755
--- a/app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/flash.java
+++ b/app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/flash.java
@@ -129,11 +129,6 @@ public class flash implements CommandAbstraction {
         return R.string.help_flash;
     }
 
-    @Override
-    public int minArgs() {
-        return 0;
-    }
-
     @Override
     public int[] argType() {
         return new int[0];
diff --git a/app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/help.java b/app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/help.java
index 5644336..aac066c 100755
--- a/app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/help.java
+++ b/app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/help.java
@@ -27,11 +27,6 @@ public class help implements CommandAbstraction {
         return R.string.help_help;
     }
 
-    @Override
-    public int minArgs() {
-        return 1;
-    }
-
     @Override
     public int[] argType() {
         return new int[]{CommandAbstraction.COMMAND};
diff --git a/app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/location.java b/app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/location.java
index 592c1f7..a848ec4 100755
--- a/app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/location.java
+++ b/app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/location.java
@@ -73,11 +73,6 @@ public class location extends APICommand {
         return null;
     }
 
-    @Override
-    public int minArgs() {
-        return 0;
-    }
-
     @Override
     public int[] argType() {
         return new int[0];
diff --git a/app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/notifications.java b/app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/notifications.java
index 683132a..8823f80 100755
--- a/app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/notifications.java
+++ b/app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/notifications.java
@@ -23,8 +23,9 @@ public class notifications extends ParamCommand {
         inc {
             @Override
             public String exec(ExecutePack pack) {
-                NotificationManager.notificationsChangeFor(new NotificationManager.NotificatedApp(pack.getLaunchInfo().componentName.getPackageName(), null, true));
-                return null;
+                String output = NotificationManager.setState(pack.getLaunchInfo().componentName.getPackageName(), true);
+                if(output == null || output.length() == 0) return null;
+                return output;
             }
 
             @Override
@@ -40,8 +41,9 @@ public class notifications extends ParamCommand {
         exc {
             @Override
             public String exec(ExecutePack pack) {
-                NotificationManager.notificationsChangeFor(new NotificationManager.NotificatedApp(pack.getLaunchInfo().componentName.getPackageName(), null, false));
-                return null;
+                String output = NotificationManager.setState(pack.getLaunchInfo().componentName.getPackageName(), false);
+                if(output == null || output.length() == 0) return null;
+                return output;
             }
 
             @Override
@@ -54,15 +56,13 @@ public class notifications extends ParamCommand {
                 return pack.context.getString(R.string.output_appnotfound);
             }
         },
-        clr {
+        color {
             @Override
             public String exec(ExecutePack pack) {
-                try {
-                    String s = pack.getString();
-
-                    NotificationManager.notificationsChangeFor(new NotificationManager.NotificatedApp(pack.getLaunchInfo().componentName.getPackageName(), s, true));
-                } catch (Exception e) {}
-                return null;
+                String color = pack.getString();
+                String output = NotificationManager.setColor(pack.getLaunchInfo().componentName.getPackageName(), color);
+                if(output == null || output.length() == 0) return null;
+                return output;
             }
 
             @Override
@@ -79,12 +79,32 @@ public class notifications extends ParamCommand {
                 return pack.context.getString(res);
             }
         },
-        title_filter {
+        format {
+            @Override
+            public String exec(ExecutePack pack) {
+                String s = pack.getString();
+                String output = NotificationManager.setFormat(pack.getLaunchInfo().componentName.getPackageName(), s);
+                if(output == null || output.length() == 0) return null;
+                return output;
+            }
+
+            @Override
+            public int[] args() {
+                return new int[] {CommandAbstraction.NO_SPACE_STRING, CommandAbstraction.VISIBLE_PACKAGE};
+            }
+
+            @Override
+            public String onArgNotFound(ExecutePack pack, int index) {
+                return pack.context.getString(R.string.invalid_integer);
+            }
+        },
+        add_filter {
             @Override
             public String exec(ExecutePack pack) {
                 int id = pack.getInt();
-                NotificationManager.excludeRegex(pack.getString(), "title", id);
-                return null;
+                String output = NotificationManager.addFilter(pack.getString(), id);
+                if(output == null || output.length() == 0) return null;
+                return output;
             }
 
             @Override
@@ -97,12 +117,13 @@ public class notifications extends ParamCommand {
                 return pack.context.getString(R.string.invalid_integer);
             }
         },
-        text_filter {
+        add_format {
             @Override
             public String exec(ExecutePack pack) {
                 int id = pack.getInt();
-                NotificationManager.excludeRegex(pack.getString(), "text", id);
-                return null;
+                String output = NotificationManager.addFormat(pack.getString(), id);
+                if(output == null || output.length() == 0) return null;
+                return output;
             }
 
             @Override
@@ -115,26 +136,40 @@ public class notifications extends ParamCommand {
                 return pack.context.getString(R.string.invalid_integer);
             }
         },
-        apply_filter {
+        rm_filter {
+            @Override
+            public String exec(ExecutePack pack) {
+                String output = NotificationManager.rmFilter(pack.getInt());
+                if(output == null || output.length() == 0) return null;
+                return output;
+            }
+
             @Override
             public int[] args() {
-                return new int[] {CommandAbstraction.INT, CommandAbstraction.VISIBLE_PACKAGE};
+                return new int[] {CommandAbstraction.INT};
             }
 
+            @Override
+            public String onArgNotFound(ExecutePack pack, int index) {
+                return pack.context.getString(R.string.invalid_integer);
+            }
+        },
+        rm_format {
             @Override
             public String exec(ExecutePack pack) {
-                int id = pack.getInt();
-                NotificationManager.applyFilter(id, pack.getLaunchInfo().componentName.getPackageName());
-                return null;
+                String output = NotificationManager.rmFormat(pack.getInt());
+                if(output == null || output.length() == 0) return null;
+                return output;
             }
 
             @Override
-            public String onArgNotFound(ExecutePack pack, int index) {
-                int res;
-                if(index == 1) res = R.string.invalid_integer;
-                else res = R.string.output_appnotfound;
+            public int[] args() {
+                return new int[] {CommandAbstraction.INT};
+            }
 
-                return pack.context.getString(res);
+            @Override
+            public String onArgNotFound(ExecutePack pack, int index) {
+                return pack.context.getString(R.string.invalid_integer);
             }
         },
         file {
diff --git a/app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/open.java b/app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/open.java
index 1b330d1..d5a5d4c 100755
--- a/app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/open.java
+++ b/app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/open.java
@@ -29,11 +29,6 @@ public class open implements CommandAbstraction {
         return R.string.help_open;
     }
 
-    @Override
-    public int minArgs() {
-        return 1;
-    }
-
     @Override
     public int[] argType() {
         return new int[]{CommandAbstraction.FILE};
diff --git a/app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/rate.java b/app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/rate.java
index a04db5a..3141867 100755
--- a/app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/rate.java
+++ b/app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/rate.java
@@ -13,26 +13,13 @@ public class rate implements CommandAbstraction {
     @Override
     public String exec(ExecutePack pack) {
         final MainPack info = (MainPack) pack;
-        new Thread() {
-            @Override
-            public void run() {
-                super.run();
-
-                try {
-                    sleep(300);
-                } catch (InterruptedException e) {
-                }
-
-                try {
-                    info.context.startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("market://details?id=" +
-                            info.context.getPackageName())));
-                } catch (android.content.ActivityNotFoundException anfe) {
-                    info.context.startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("https://play.google.com/store/apps/details?id=" +
-                            info.context.getPackageName())));
-                }
-            }
-        }.start();
-
+        try {
+            info.context.startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("market://details?id=" +
+                    info.context.getPackageName())));
+        } catch (android.content.ActivityNotFoundException anfe) {
+            info.context.startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("https://play.google.com/store/apps/details?id=" +
+                    info.context.getPackageName())));
+        }
 
         return info.res.getString(R.string.output_rate);
     }
@@ -42,11 +29,6 @@ public class rate implements CommandAbstraction {
         return R.string.help_rate;
     }
 
-    @Override
-    public int minArgs() {
-        return 0;
-    }
-
     @Override
     public int[] argType() {
         return new int[0];
diff --git a/app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/refresh.java b/app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/refresh.java
index da18834..10be64a 100755
--- a/app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/refresh.java
+++ b/app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/refresh.java
@@ -24,11 +24,6 @@ public class refresh implements CommandAbstraction {
         return R.string.help_refresh;
     }
 
-    @Override
-    public int minArgs() {
-        return 0;
-    }
-
     @Override
     public int[] argType() {
         return new int[0];
diff --git a/app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/regex.java b/app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/regex.java
index 1440638..b14de39 100644
--- a/app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/regex.java
+++ b/app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/regex.java
@@ -21,7 +21,7 @@ public class regex extends ParamCommand {
             public String exec(ExecutePack pack) {
                 String output = RegexManager.add(pack.getInt(), pack.getString());
                 if(output == null) return null;
-                if(output.length() == 0) return pack.context.getString(R.string.regex_exists);
+                if(output.length() == 0) return pack.context.getString(R.string.id_already);
                 else return output;
             }
 
@@ -35,7 +35,7 @@ public class regex extends ParamCommand {
             public String exec(ExecutePack pack) {
                 String output = RegexManager.rm(pack.getInt());
                 if(output == null) return null;
-                if(output.length() == 0) return pack.context.getString(R.string.regex_not_found);
+                if(output.length() == 0) return pack.context.getString(R.string.id_notfound);
                 return output;
             }
 
@@ -50,7 +50,7 @@ public class regex extends ParamCommand {
                 RegexManager.Regex r = RegexManager.get(pack.getInt());
                 if(r == null) return pack.context.getString(R.string.id_notfound);
 
-                return r.value;
+                return r.regex != null ? r.regex.pattern() : r.literalPattern;
             }
 
             @Override
diff --git a/app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/restart.java b/app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/restart.java
index 4a4016c..b88c5b9 100755
--- a/app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/restart.java
+++ b/app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/restart.java
@@ -14,11 +14,6 @@ public class restart implements CommandAbstraction {
         return pack.context.getString(R.string.restarting);
     }
 
-    @Override
-    public int minArgs() {
-        return 0;
-    }
-
     @Override
     public int[] argType() {
         return new int[0];
diff --git a/app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/rss.java b/app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/rss.java
index dadca04..67e88a8 100644
--- a/app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/rss.java
+++ b/app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/rss.java
@@ -1,8 +1,10 @@
 package ohi.andre.consolelauncher.commands.main.raw;
 
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+
 import java.io.File;
-import java.text.DateFormat;
-import java.text.SimpleDateFormat;
+import java.util.regex.Pattern;
 
 import ohi.andre.consolelauncher.R;
 import ohi.andre.consolelauncher.commands.CommandAbstraction;
@@ -10,9 +12,9 @@ import ohi.andre.consolelauncher.commands.ExecutePack;
 import ohi.andre.consolelauncher.commands.main.MainPack;
 import ohi.andre.consolelauncher.commands.specific.ParamCommand;
 import ohi.andre.consolelauncher.managers.RssManager;
+import ohi.andre.consolelauncher.managers.TimeManager;
 import ohi.andre.consolelauncher.managers.xml.XMLPrefsManager;
 import ohi.andre.consolelauncher.managers.xml.options.Rss;
-import ohi.andre.consolelauncher.tuils.TimeManager;
 import ohi.andre.consolelauncher.tuils.Tuils;
 
 /**
@@ -68,8 +70,7 @@ public class rss extends ParamCommand {
             @Override
             public String exec(ExecutePack pack) {
                 int id = pack.getInt();
-                ((MainPack) pack).rssManager.l(id);
-                return null;
+                return ((MainPack) pack).rssManager.l(id);
             }
 
             @Override
@@ -91,7 +92,7 @@ public class rss extends ParamCommand {
                 return new int[] {CommandAbstraction.INT, CommandAbstraction.BOOLEAN};
             }
         },
-        time {
+        update_time {
             @Override
             public String exec(ExecutePack pack) {
                 int id = pack.getInt();
@@ -105,6 +106,17 @@ public class rss extends ParamCommand {
                 return new int[] {CommandAbstraction.INT, CommandAbstraction.LONG};
             }
         },
+        time_format {
+            @Override
+            public String exec(ExecutePack pack) {
+                return ((MainPack) pack).rssManager.setTimeFormat(pack.getInt(), pack.getString());
+            }
+
+            @Override
+            public int[] args() {
+                return new int[] {CommandAbstraction.INT, CommandAbstraction.PLAIN_TEXT};
+            }
+        },
         format {
             @Override
             public int[] args() {
@@ -139,6 +151,28 @@ public class rss extends ParamCommand {
                 return super.onArgNotFound(pack, index);
             }
         },
+        entry_tag {
+            @Override
+            public int[] args() {
+                return new int[] {CommandAbstraction.INT, CommandAbstraction.PLAIN_TEXT};
+            }
+
+            @Override
+            public String exec(ExecutePack pack) {
+                return ((MainPack) pack).rssManager.setEntryTag(pack.getInt(), pack.getString());
+            }
+        },
+        date_tag {
+            @Override
+            public int[] args() {
+                return new int[] {CommandAbstraction.INT, CommandAbstraction.PLAIN_TEXT};
+            }
+
+            @Override
+            public String exec(ExecutePack pack) {
+                return ((MainPack) pack).rssManager.setDateTag(pack.getInt(), pack.getString());
+            }
+        },
         last_check {
             @Override
             public int[] args() {
@@ -147,16 +181,19 @@ public class rss extends ParamCommand {
 
             @Override
             public String exec(ExecutePack pack) {
-                String output = XMLPrefsManager.attrValue(new File(Tuils.getFolder(), RssManager.PATH), RssManager.NAME,
-                        RssManager.RSS_LABEL, new String[] {RssManager.ID_ATTRIBUTE}, new String[] {String.valueOf(pack.getInt())},
-                        RssManager.LASTCHECKED_ATTRIBUTE);
-                if(output == null || output.length() == 0) return pack.context.getString(R.string.id_notfound);
+                Node n = XMLPrefsManager.findNode(new File(Tuils.getFolder(), RssManager.PATH), RssManager.RSS_LABEL, new String[] {RssManager.ID_ATTRIBUTE}, new String[] {String.valueOf(pack.getInt())});
+                if(n == null) return pack.context.getString(R.string.id_notfound);
+
+                Element el = (Element) n;
+
+                String value = el.hasAttribute(RssManager.LASTCHECKED_ATTRIBUTE) ? el.getAttribute(RssManager.LASTCHECKED_ATTRIBUTE) : null;
+                if(value == null) return pack.context.getString(R.string.rss_never_checked);
 
                 try {
-                    DateFormat defaultRSSDateFormat = new SimpleDateFormat("EEE, d MMM yyyy HH:mm:ss z");
-                    return TimeManager.replace(XMLPrefsManager.get(Rss.rss_time_format), defaultRSSDateFormat.parse(output).getTime(),
+                    return TimeManager.replace(XMLPrefsManager.get(Rss.rss_time_format), Long.parseLong(value),
                             Integer.MAX_VALUE).toString();
                 } catch (Exception e) {
+                    Tuils.log(e);
                     return pack.context.getString(R.string.output_error);
                 }
             }
@@ -169,6 +206,7 @@ public class rss extends ParamCommand {
 
             @Override
             public String exec(ExecutePack pack) {
+                if(!((MainPack) pack).rssManager.updateRss(pack.getInt(), false, true)) return pack.context.getString(R.string.id_notfound);
                 return null;
             }
         },
@@ -180,7 +218,10 @@ public class rss extends ParamCommand {
 
             @Override
             public String exec(ExecutePack pack) {
-                return null;
+                RssManager.Rss rss = ((MainPack) pack).rssManager.findId(pack.getInt());
+                if(rss == null) return pack.context.getString(R.string.id_notfound);
+
+                return rss.toString();
             }
         },
         include_if_matches {
@@ -211,6 +252,40 @@ public class rss extends ParamCommand {
                 return ((MainPack) pack).rssManager.setExcludeIfMatches(id, r);
             }
         },
+        add_command {
+            @Override
+            public int[] args() {
+                return new int[] {CommandAbstraction.INT, CommandAbstraction.NO_SPACE_STRING, CommandAbstraction.NO_SPACE_STRING, CommandAbstraction.PLAIN_TEXT};
+            }
+
+            @Override
+            public String exec(ExecutePack pack) {
+                int id = pack.getInt();
+
+                String on = pack.getString();
+                String regex = pack.getString();
+                String cmd = pack.getString();
+
+                try {
+                    Pattern.compile(regex);
+                } catch (Exception e) {
+                    return e.toString();
+                }
+
+                return ((MainPack) pack).rssManager.addRegexCommand(id, on, regex, cmd);
+            }
+        },
+        rm_command {
+            @Override
+            public int[] args() {
+                return new int[] {CommandAbstraction.INT};
+            }
+
+            @Override
+            public String exec(ExecutePack pack) {
+                return ((MainPack) pack).rssManager.rmRegexCommand(pack.getInt());
+            }
+        },
         wifi_only {
             @Override
             public int[] args() {
diff --git a/app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/search.java b/app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/search.java
index d695816..6cef058 100755
--- a/app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/search.java
+++ b/app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/search.java
@@ -11,6 +11,8 @@ import ohi.andre.consolelauncher.commands.CommandAbstraction;
 import ohi.andre.consolelauncher.commands.ExecutePack;
 import ohi.andre.consolelauncher.commands.main.MainPack;
 import ohi.andre.consolelauncher.commands.specific.ParamCommand;
+import ohi.andre.consolelauncher.managers.xml.XMLPrefsManager;
+import ohi.andre.consolelauncher.managers.xml.options.Cmd;
 import ohi.andre.consolelauncher.tuils.Tuils;
 
 public class search extends ParamCommand {
@@ -114,8 +116,8 @@ public class search extends ParamCommand {
     }
 
     @Override
-    public boolean supportDefaultParam() {
-        return true;
+    public XMLPrefsManager.XMLPrefsSave defaultParamReference() {
+        return Cmd.default_search;
     }
 
     @Override
diff --git a/app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/share.java b/app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/share.java
index a80432e..d2e4656 100755
--- a/app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/share.java
+++ b/app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/share.java
@@ -30,11 +30,6 @@ public class share implements CommandAbstraction {
         return R.string.help_share;
     }
 
-    @Override
-    public int minArgs() {
-        return 1;
-    }
-
     @Override
     public int[] argType() {
         return new int[]{CommandAbstraction.FILE};
diff --git a/app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/shellcommands.java b/app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/shellcommands.java
index 70fae98..04d23be 100755
--- a/app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/shellcommands.java
+++ b/app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/shellcommands.java
@@ -57,11 +57,6 @@ public class shellcommands implements CommandAbstraction {
         return commands;
     }
 
-    @Override
-    public int minArgs() {
-        return 0;
-    }
-
     @Override
     public int[] argType() {
         return new int[0];
diff --git a/app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/sms.java b/app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/sms.java
index 2f8fe26..4ff27ae 100755
--- a/app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/sms.java
+++ b/app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/sms.java
@@ -40,11 +40,6 @@ public class sms extends RedirectCommand {
         return null;
     }
 
-    @Override
-    public int minArgs() {
-        return 1;
-    }
-
     @Override
     public int[] argType() {
         return new int[] {CommandAbstraction.CONTACTNUMBER};
diff --git a/app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/status.java b/app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/status.java
index 613167b..33c7cd6 100755
--- a/app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/status.java
+++ b/app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/status.java
@@ -55,11 +55,6 @@ public class status implements CommandAbstraction {
                 info.res.getString(R.string.mobile_data) + Tuils.SPACE + mobileOn;
     }
 
-    @Override
-    public int minArgs() {
-        return 0;
-    }
-
     @Override
     public int[] argType() {
         return new int[0];
diff --git a/app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/time.java b/app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/time.java
index 8d94335..01620f8 100755
--- a/app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/time.java
+++ b/app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/time.java
@@ -3,7 +3,7 @@ package ohi.andre.consolelauncher.commands.main.raw;
 import ohi.andre.consolelauncher.R;
 import ohi.andre.consolelauncher.commands.CommandAbstraction;
 import ohi.andre.consolelauncher.commands.ExecutePack;
-import ohi.andre.consolelauncher.tuils.TimeManager;
+import ohi.andre.consolelauncher.managers.TimeManager;
 
 /**
  * Created by andre on 03/12/15.
@@ -15,11 +15,6 @@ public class time implements CommandAbstraction {
         return TimeManager.replace("%t" + index).toString();
     }
 
-    @Override
-    public int minArgs() {
-        return 1;
-    }
-
     @Override
     public int priority() {
         return 4;
diff --git a/app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/tuixt.java b/app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/tuixt.java
index fc3eb02..af4addf 100755
--- a/app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/tuixt.java
+++ b/app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/tuixt.java
@@ -37,11 +37,6 @@ public class tuixt implements CommandAbstraction {
         return Tuils.EMPTYSTRING;
     }
 
-    @Override
-    public int minArgs() {
-        return 1;
-    }
-
     @Override
     public int[] argType() {
         return new int[] {CommandAbstraction.FILE};
diff --git a/app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/tutorial.java b/app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/tutorial.java
index 1cab1a6..09c01f1 100644
--- a/app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/tutorial.java
+++ b/app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/tutorial.java
@@ -22,11 +22,6 @@ public class tutorial implements CommandAbstraction {
         return null;
     }
 
-    @Override
-    public int minArgs() {
-        return 0;
-    }
-
     @Override
     public int[] argType() {
         return new int[0];
diff --git a/app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/uninstall.java b/app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/uninstall.java
index e1c9543..a4f2155 100755
--- a/app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/uninstall.java
+++ b/app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/uninstall.java
@@ -29,11 +29,6 @@ public class uninstall implements CommandAbstraction {
         return R.string.help_uninstall;
     }
 
-    @Override
-    public int minArgs() {
-        return 1;
-    }
-
     @Override
     public int[] argType() {
         return new int[]{CommandAbstraction.VISIBLE_PACKAGE};
diff --git a/app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/vibrate.java b/app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/vibrate.java
index a3c6e51..f98c6ba 100755
--- a/app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/vibrate.java
+++ b/app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/vibrate.java
@@ -60,11 +60,6 @@ public class vibrate implements CommandAbstraction {
         return null;
     }
 
-    @Override
-    public int minArgs() {
-        return 1;
-    }
-
     @Override
     public int[] argType() {
         return new int[] {CommandAbstraction.PLAIN_TEXT};
diff --git a/app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/wifi.java b/app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/wifi.java
index d82ff97..93dafb9 100755
--- a/app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/wifi.java
+++ b/app/src/main/java/ohi/andre/consolelauncher/commands/main/raw/wifi.java
@@ -25,11 +25,6 @@ public class wifi implements CommandAbstraction {
         return R.string.help_wifi;
     }
 
-    @Override
-    public int minArgs() {
-        return 0;
-    }
-
     @Override
     public int[] argType() {
         return new int[0];
diff --git a/app/src/main/java/ohi/andre/consolelauncher/commands/specific/ParamCommand.java b/app/src/main/java/ohi/andre/consolelauncher/commands/specific/ParamCommand.java
index ef77f6e..606a498 100755
--- a/app/src/main/java/ohi/andre/consolelauncher/commands/specific/ParamCommand.java
+++ b/app/src/main/java/ohi/andre/consolelauncher/commands/specific/ParamCommand.java
@@ -2,10 +2,10 @@ package ohi.andre.consolelauncher.commands.specific;
 
 import ohi.andre.consolelauncher.R;
 import ohi.andre.consolelauncher.commands.CommandAbstraction;
-import ohi.andre.consolelauncher.commands.CommandsPreferences;
 import ohi.andre.consolelauncher.commands.ExecutePack;
 import ohi.andre.consolelauncher.commands.main.MainPack;
 import ohi.andre.consolelauncher.commands.main.Param;
+import ohi.andre.consolelauncher.managers.xml.XMLPrefsManager;
 import ohi.andre.consolelauncher.tuils.SimpleMutableEntry;
 import ohi.andre.consolelauncher.tuils.Tuils;
 
@@ -20,11 +20,6 @@ public abstract class ParamCommand implements CommandAbstraction {
         return new int[] {CommandAbstraction.PARAM};
     }
 
-    @Override
-    public int minArgs() {
-        return -1;
-    }
-
     @Override
     public final String exec(ExecutePack pack) throws Exception {
         String o = doThings(pack);
@@ -32,21 +27,22 @@ public abstract class ParamCommand implements CommandAbstraction {
 
         Param param = pack.get(Param.class);
         if(param == null) {
-            return pack.context.getString(R.string.output_invalid_param) + Tuils.SPACE + pack.get(String.class, 0);
+            Object o1 = pack.get(Object.class, 0);
+            return pack.context.getString(R.string.output_invalid_param) + Tuils.SPACE + (o1 != null ? o1.toString() : "null");
         }
         return param.exec(pack);
     }
 
     public SimpleMutableEntry<Boolean, Param> getParam(MainPack pack, String param) {
         Param p = paramForString(pack, param);
-        if(p == null && supportDefaultParam()) {
+        if(p == null && defaultParamReference() != null) {
             return new SimpleMutableEntry<>(true, paramForString(pack, defaultParam(pack)));
         }
         return new SimpleMutableEntry<>(false, p);
     }
 
     public String defaultParam(MainPack pack) {
-        String def = pack.cmdPrefs.forCommand(getClass().getSimpleName()).get(CommandsPreferences.DEFAULT_PARAM);
+        String def = pack.cmdPrefs.get(defaultParamReference());
         if(!def.startsWith("-")) def = "-" + def;
         return def;
     }
@@ -71,7 +67,7 @@ public abstract class ParamCommand implements CommandAbstraction {
     public abstract String[] params();
     protected abstract Param paramForString(MainPack pack, String param);
     protected abstract String doThings(ExecutePack pack);
-    public boolean supportDefaultParam() {
-        return false;
+    public XMLPrefsManager.XMLPrefsSave defaultParamReference() {
+        return null;
     }
 }
diff --git a/app/src/main/java/ohi/andre/consolelauncher/commands/tuixt/TuixtActivity.java b/app/src/main/java/ohi/andre/consolelauncher/commands/tuixt/TuixtActivity.java
index 092c5f1..4fe6aa3 100755
--- a/app/src/main/java/ohi/andre/consolelauncher/commands/tuixt/TuixtActivity.java
+++ b/app/src/main/java/ohi/andre/consolelauncher/commands/tuixt/TuixtActivity.java
@@ -34,6 +34,7 @@ import ohi.andre.consolelauncher.commands.CommandTuils;
 import ohi.andre.consolelauncher.managers.xml.XMLPrefsManager;
 import ohi.andre.consolelauncher.managers.xml.options.Theme;
 import ohi.andre.consolelauncher.managers.xml.options.Ui;
+import ohi.andre.consolelauncher.tuils.StoppableThread;
 import ohi.andre.consolelauncher.tuils.Tuils;
 
 /**
@@ -199,7 +200,7 @@ public class TuixtActivity extends Activity {
         pack = new TuixtPack(group, file, this, fileView);
 
         fileView.setText(getString(R.string.tuixt_reading) + Tuils.SPACE + path);
-        new Thread() {
+        new StoppableThread() {
 
             @Override
             public void run() {
diff --git a/app/src/main/java/ohi/andre/consolelauncher/commands/tuixt/raw/exit.java b/app/src/main/java/ohi/andre/consolelauncher/commands/tuixt/raw/exit.java
index b6fb29f..27f43a8 100755
--- a/app/src/main/java/ohi/andre/consolelauncher/commands/tuixt/raw/exit.java
+++ b/app/src/main/java/ohi/andre/consolelauncher/commands/tuixt/raw/exit.java
@@ -21,11 +21,6 @@ public class exit implements CommandAbstraction {
         return null;
     }
 
-    @Override
-    public int minArgs() {
-        return 0;
-    }
-
     @Override
     public int[] argType() {
         return new int[0];
diff --git a/app/src/main/java/ohi/andre/consolelauncher/commands/tuixt/raw/help.java b/app/src/main/java/ohi/andre/consolelauncher/commands/tuixt/raw/help.java
index 57a6ae5..4bb8db2 100755
--- a/app/src/main/java/ohi/andre/consolelauncher/commands/tuixt/raw/help.java
+++ b/app/src/main/java/ohi/andre/consolelauncher/commands/tuixt/raw/help.java
@@ -27,11 +27,6 @@ public class help implements CommandAbstraction {
         return pack.resources.getString(res);
     }
 
-    @Override
-    public int minArgs() {
-        return 1;
-    }
-
     @Override
     public int[] argType() {
         return new int[] {CommandAbstraction.COMMAND};
diff --git a/app/src/main/java/ohi/andre/consolelauncher/commands/tuixt/raw/save.java b/app/src/main/java/ohi/andre/consolelauncher/commands/tuixt/raw/save.java
index cb891f1..e7a9307 100755
--- a/app/src/main/java/ohi/andre/consolelauncher/commands/tuixt/raw/save.java
+++ b/app/src/main/java/ohi/andre/consolelauncher/commands/tuixt/raw/save.java
@@ -26,11 +26,6 @@ public class save implements CommandAbstraction {
         }
     }
 
-    @Override
-    public int minArgs() {
-        return 0;
-    }
-
     @Override
     public int[] argType() {
         return new int[0];
diff --git a/app/src/main/java/ohi/andre/consolelauncher/managers/AliasManager.java b/app/src/main/java/ohi/andre/consolelauncher/managers/AliasManager.java
index a16e414..5314d8f 100755
--- a/app/src/main/java/ohi/andre/consolelauncher/managers/AliasManager.java
+++ b/app/src/main/java/ohi/andre/consolelauncher/managers/AliasManager.java
@@ -11,11 +11,10 @@ import java.io.FileOutputStream;
 import java.io.FileReader;
 import java.io.FileWriter;
 import java.io.InputStreamReader;
+import java.util.AbstractMap;
 import java.util.ArrayList;
-import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
-import java.util.Set;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
@@ -29,7 +28,7 @@ public class AliasManager implements Reloadable {
 
     public static final String PATH = "alias.txt";
 
-    private Map<String, String> aliases;
+    private List<Map.Entry<String, String>> aliases;
     private String paramMarker, paramSeparator, aliasLabelFormat;
 
     private Context context;
@@ -46,7 +45,7 @@ public class AliasManager implements Reloadable {
 
     public String printAliases() {
         String output = Tuils.EMPTYSTRING;
-        for (Map.Entry<String, String> entry : aliases.entrySet()) {
+        for (Map.Entry<String, String> entry : aliases) {
             output = output.concat(entry.getKey() + " --> " + entry.getValue() + Tuils.NEWLINE);
         }
 
@@ -82,7 +81,7 @@ public class AliasManager implements Reloadable {
 
             String aliasValue = null;
             while (true) {
-                aliasValue = aliases.get(alias);
+                aliasValue = getALiasFor(alias);
                 if(aliasValue != null) break;
                 else {
                     int index = alias.lastIndexOf(Tuils.SPACE);
@@ -96,7 +95,7 @@ public class AliasManager implements Reloadable {
 
             return new String[] {aliasValue, alias, args};
         } else {
-            return new String[] {aliases.get(alias), alias, Tuils.EMPTYSTRING};
+            return new String[] {getALiasFor(alias), alias, Tuils.EMPTYSTRING};
         }
     }
 
@@ -113,6 +112,24 @@ public class AliasManager implements Reloadable {
         return aliasValue;
     }
 
+    private String getALiasFor(String name) {
+        for(Map.Entry<String, String> entry : aliases) {
+            if(name.equals(entry.getKey())) return entry.getValue();
+        }
+
+        return null;
+    }
+
+    private void removeAliasFor(String name) {
+        for(int c = 0; c < aliases.size(); c++) {
+            Map.Entry e = aliases.get(c);
+            if(name.equals(e.getKey())) {
+                aliases.remove(c);
+                return;
+            }
+        }
+    }
+
     private final Pattern pn = Pattern.compile("%n", Pattern.CASE_INSENSITIVE | Pattern.LITERAL);
     private final Pattern pv = Pattern.compile("%v", Pattern.CASE_INSENSITIVE | Pattern.LITERAL);
     private final Pattern pa = Pattern.compile("%a", Pattern.CASE_INSENSITIVE | Pattern.LITERAL);
@@ -127,7 +144,7 @@ public class AliasManager implements Reloadable {
     @Override
     public void reload() {
         if(aliases != null) aliases.clear();
-        else aliases = new HashMap();
+        else aliases = new ArrayList<>();
 
         File file = new File(Tuils.getFolder(), PATH);
 
@@ -159,7 +176,7 @@ public class AliasManager implements Reloadable {
                     Tuils.sendOutput(Color.RED, context,
                             context.getString(R.string.output_notaddingalias1) + Tuils.SPACE + name + Tuils.SPACE + context.getString(R.string.output_notaddingalias3));
                 } else {
-                    aliases.put(name, value);
+                    aliases.add(new AbstractMap.SimpleImmutableEntry<>(name, value));
                 }
             }
         } catch (Exception e) {}
@@ -173,7 +190,8 @@ public class AliasManager implements Reloadable {
             fos.write((Tuils.NEWLINE + name + "=" + value).getBytes());
             fos.close();
 
-            aliases.put(name, value);
+            aliases.add(new AbstractMap.SimpleImmutableEntry<>(name, value));
+
             return true;
         } catch (Exception e) {
             return false;
@@ -201,7 +219,7 @@ public class AliasManager implements Reloadable {
             reader.close();
 
 
-            aliases.remove(name);
+            removeAliasFor(name);
 
             return tempFile.renameTo(inputFile);
         } catch (Exception e) {
@@ -213,8 +231,7 @@ public class AliasManager implements Reloadable {
         List<String> aliasKeys = new ArrayList<>(0);
         if(aliases == null) return aliasKeys;
 
-        Set<String> keys = aliases.keySet();
-        for(String s : keys) aliasKeys.add(s);
+        for(Map.Entry<String, String> entry : aliases) aliasKeys.add(entry.getKey());
 
         return aliasKeys;
     }
diff --git a/app/src/main/java/ohi/andre/consolelauncher/managers/AppsManager.java b/app/src/main/java/ohi/andre/consolelauncher/managers/AppsManager.java
index b6bdbe7..63c0d41 100755
--- a/app/src/main/java/ohi/andre/consolelauncher/managers/AppsManager.java
+++ b/app/src/main/java/ohi/andre/consolelauncher/managers/AppsManager.java
@@ -25,6 +25,7 @@ import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collections;
 import java.util.Comparator;
+import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
 import java.util.regex.Pattern;
@@ -38,7 +39,7 @@ import ohi.andre.consolelauncher.managers.xml.options.Behavior;
 import ohi.andre.consolelauncher.managers.xml.options.Theme;
 import ohi.andre.consolelauncher.managers.xml.options.Ui;
 import ohi.andre.consolelauncher.tuils.Compare;
-import ohi.andre.consolelauncher.tuils.TimeManager;
+import ohi.andre.consolelauncher.tuils.StoppableThread;
 import ohi.andre.consolelauncher.tuils.Tuils;
 import ohi.andre.consolelauncher.tuils.interfaces.Suggester;
 
@@ -88,7 +89,7 @@ public class AppsManager implements XMLPrefsManager.XmlPrefsElement {
 
     @Override
     public void write(XMLPrefsManager.XMLPrefsSave save, String value) {
-        set(new File(Tuils.getFolder(), PATH), NAME, save.label(), new String[] {VALUE_ATTRIBUTE}, new String[] {value});
+        set(new File(Tuils.getFolder(), PATH), save.label(), new String[] {VALUE_ATTRIBUTE}, new String[] {value});
     }
 
     @Override
@@ -140,7 +141,7 @@ public class AppsManager implements XMLPrefsManager.XmlPrefsElement {
 
         initAppListener(context);
 
-        new Thread() {
+        new StoppableThread() {
             @Override
             public void run() {
                 super.run();
@@ -176,9 +177,12 @@ public class AppsManager implements XMLPrefsManager.XmlPrefsElement {
             Object[] o;
             try {
                 o = XMLPrefsManager.buildDocument(file, NAME);
+                if(o == null) {
+                    Tuils.sendXMLParseError(context, PATH);
+                    return;
+                }
             } catch (Exception e) {
-                Tuils.sendOutput(Color.RED, context, context.getString(R.string.output_xmlproblem1) + Tuils.SPACE + PATH + context.getString(R.string.output_xmlproblem2) +
-                                Tuils.NEWLINE + context.getString(R.string.output_errorlabel) + e.toString());
+                Tuils.sendXMLParseError(context, PATH, e);
                 return;
             }
 
@@ -215,7 +219,7 @@ public class AppsManager implements XMLPrefsManager.XmlPrefsElement {
                                 continue;
                             }
 
-                            new Thread() {
+                            new StoppableThread() {
                                 @Override
                                 public void run() {
                                     super.run();
@@ -434,6 +438,8 @@ public class AppsManager implements XMLPrefsManager.XmlPrefsElement {
     }
 
     public LaunchInfo findLaunchInfoWithLabel(String label, int type) {
+        if(appsHolder == null) return null;
+
         List<LaunchInfo> appList;
         if(type == SHOWN_APPS) {
             appList = appsHolder.getApps();
@@ -441,6 +447,8 @@ public class AppsManager implements XMLPrefsManager.XmlPrefsElement {
             appList = hiddenApps;
         }
 
+        if(appList == null) return null;
+
         LaunchInfo i = AppUtils.findLaunchInfoWithLabel(appList, label);
         if(i != null) return i;
 
@@ -460,11 +468,17 @@ public class AppsManager implements XMLPrefsManager.XmlPrefsElement {
         if(appsHolder != null) appsHolder.update(true);
     }
 
-    public Intent getIntent(LaunchInfo info) {
+    public Intent getIntent(final LaunchInfo info) {
         info.launchedTimes++;
-        appsHolder.requestSuggestionUpdate(info);
+        new StoppableThread() {
+            @Override
+            public void run() {
+                super.run();
 
-        writeLaunchTimes(info);
+                appsHolder.requestSuggestionUpdate(info);
+                writeLaunchTimes(info);
+            }
+        }.start();
 
         Intent intent = new Intent(Intent.ACTION_MAIN);
         intent.setComponent(info.componentName);
@@ -474,7 +488,7 @@ public class AppsManager implements XMLPrefsManager.XmlPrefsElement {
     }
 
     public String hideActivity(LaunchInfo info) {
-        set(file, NAME, info.write(), new String[] {SHOW_ATTRIBUTE}, new String[] {false + Tuils.EMPTYSTRING});
+        set(file, info.write(), new String[] {SHOW_ATTRIBUTE}, new String[] {false + Tuils.EMPTYSTRING});
 
         appsHolder.remove(info);
         appsHolder.update(true);
@@ -485,7 +499,7 @@ public class AppsManager implements XMLPrefsManager.XmlPrefsElement {
     }
 
     public String showActivity(LaunchInfo info) {
-        set(file, NAME, info.write(), new String[]{SHOW_ATTRIBUTE}, new String[]{true + Tuils.EMPTYSTRING});
+        set(file, info.write(), new String[]{SHOW_ATTRIBUTE}, new String[]{true + Tuils.EMPTYSTRING});
 
         hiddenApps.remove(info);
         appsHolder.add(info);
@@ -498,7 +512,7 @@ public class AppsManager implements XMLPrefsManager.XmlPrefsElement {
         int index = Tuils.find(name, groups);
         if(index == -1) {
             groups.add(new Group(name));
-            return XMLPrefsManager.set(file, NAME, name, new String[]{APPS_ATTRIBUTE}, new String[]{Tuils.EMPTYSTRING});
+            return XMLPrefsManager.set(file, name, new String[]{APPS_ATTRIBUTE}, new String[]{Tuils.EMPTYSTRING});
         }
 
         return context.getString(R.string.output_groupexists);
@@ -511,7 +525,7 @@ public class AppsManager implements XMLPrefsManager.XmlPrefsElement {
         }
 
         groups.get(index).setBgColor(Color.parseColor(color));
-        return XMLPrefsManager.set(file, NAME, name, new String[]{BGCOLOR_ATTRIBUTE}, new String[]{color});
+        return XMLPrefsManager.set(file, name, new String[]{BGCOLOR_ATTRIBUTE}, new String[]{color});
     }
 
     public String groupForeColor(String name, String color) {
@@ -521,11 +535,11 @@ public class AppsManager implements XMLPrefsManager.XmlPrefsElement {
         }
 
         groups.get(index).setForeColor(Color.parseColor(color));
-        return XMLPrefsManager.set(file, NAME, name, new String[]{FORECOLOR_ATTRIBUTE}, new String[]{color});
+        return XMLPrefsManager.set(file, name, new String[]{FORECOLOR_ATTRIBUTE}, new String[]{color});
     }
 
     public String removeGroup(String name) {
-        String output = XMLPrefsManager.removeNode(file, NAME, name);
+        String output = XMLPrefsManager.removeNode(file, name);
 
         if(output == null) return null;
         if(output.length() == 0) return context.getString(R.string.output_groupnotfound);
@@ -539,7 +553,11 @@ public class AppsManager implements XMLPrefsManager.XmlPrefsElement {
     public String addAppToGroup(String group, LaunchInfo app) {
         Object[] o;
         try {
-            o = XMLPrefsManager.buildDocument(file, NAME);
+            o = XMLPrefsManager.buildDocument(file, null);
+            if(o == null) {
+                Tuils.sendXMLParseError(context, PATH);
+                return null;
+            }
         } catch (Exception e) {
             return e.toString();
         }
@@ -571,7 +589,11 @@ public class AppsManager implements XMLPrefsManager.XmlPrefsElement {
     public String removeAppFromGroup(String group, LaunchInfo app) {
         Object[] o;
         try {
-            o = XMLPrefsManager.buildDocument(file, NAME);
+            o = XMLPrefsManager.buildDocument(file, null);
+            if(o == null) {
+                Tuils.sendXMLParseError(context, PATH);
+                return null;
+            }
         } catch (Exception e) {
             return e.toString();
         }
@@ -653,7 +675,11 @@ public class AppsManager implements XMLPrefsManager.XmlPrefsElement {
     public String listGroup(String group) {
         Object[] o;
         try {
-            o = XMLPrefsManager.buildDocument(file, NAME);
+            o = XMLPrefsManager.buildDocument(file, null);
+            if(o == null) {
+                Tuils.sendXMLParseError(context, PATH);
+                return null;
+            }
         } catch (Exception e) {
             return e.toString();
         }
@@ -701,7 +727,11 @@ public class AppsManager implements XMLPrefsManager.XmlPrefsElement {
     public String listGroups() {
         Object[] o;
         try {
-            o = XMLPrefsManager.buildDocument(file, NAME);
+            o = XMLPrefsManager.buildDocument(file, null);
+            if(o == null) {
+                Tuils.sendXMLParseError(context, PATH);
+                return null;
+            }
         } catch (Exception e) {
             return e.toString();
         }
@@ -740,8 +770,58 @@ public class AppsManager implements XMLPrefsManager.XmlPrefsElement {
     }
 
     public String printApps(int type) {
+        return printNApps(type, -1);
+    }
+
+    public String printApps(int type, String text) {
+        boolean ok;
+        int length = 0;
+        try {
+            length = Integer.parseInt(text);
+            ok = true;
+        } catch (NumberFormatException exc) {
+            ok = false;
+        }
+
+        if(ok) {
+            return printNApps(type, length);
+        } else {
+            return printAppsThatBegins(type, text);
+        }
+    }
+
+    private String printNApps(int type, int n) {
+        try {
+            List<String> labels = AppUtils.labelList(type == SHOWN_APPS ? appsHolder.getApps() : hiddenApps, true);
+
+            if(n >= 0) {
+                int toRemove = labels.size() - n;
+                if(toRemove <= 0) return "[]";
+
+                for(int c = 0; c < toRemove; c++) {
+                    labels.remove(labels.size() - 1);
+                }
+            }
+
+            return AppUtils.printApps(labels);
+        } catch (NullPointerException e) {
+            return "[]";
+        }
+    }
+
+    private String printAppsThatBegins(int type, String with) {
         try {
             List<String> labels = AppUtils.labelList(type == SHOWN_APPS ? appsHolder.getApps() : hiddenApps, true);
+
+            if(with != null && with.length() > 0) {
+                with = with.toLowerCase();
+
+                Iterator<String> it = labels.iterator();
+                while(it.hasNext()) {
+                    if(!it.next().toLowerCase().startsWith(with)) it.remove();
+                }
+            }
+
             return AppUtils.printApps(labels);
         } catch (NullPointerException e) {
             return "[]";
@@ -853,12 +933,13 @@ public class AppsManager implements XMLPrefsManager.XmlPrefsElement {
 
         public ComponentName componentName;
 
-        public String publicLabel;
+        public String publicLabel, unspacedLowercaseLabel;
         public int launchedTimes = 0;
 
         public LaunchInfo(String packageName, String activityName, String label) {
             this.componentName = new ComponentName(packageName, activityName);
             this.publicLabel = label;
+            this.unspacedLowercaseLabel = Tuils.removeSpaces(this.publicLabel).toLowerCase();
         }
 
         public boolean isInside(String apps) {
@@ -1196,17 +1277,15 @@ public class AppsManager implements XMLPrefsManager.XmlPrefsElement {
             return null;
         }
 
-        private static Pattern removeSpacePattern = Pattern.compile("\\s+");
         public static LaunchInfo findLaunchInfoWithLabel(List<LaunchInfo> appList, String label) {
-            label = removeSpacePattern.matcher(label).replaceAll(Tuils.EMPTYSTRING);
-            for(LaunchInfo i : appList) if(removeSpacePattern.matcher(i.publicLabel).replaceAll(Tuils.EMPTYSTRING).equalsIgnoreCase(label)) return i;
+            label = Tuils.removeSpaces(label);
+            for(LaunchInfo i : appList) if(i.unspacedLowercaseLabel.equalsIgnoreCase(label)) return i;
             return null;
         }
 
         private static List<LaunchInfo> findLaunchInfosWithPackage(String packageName, List<LaunchInfo> infos) {
             List<LaunchInfo> result = new ArrayList<>();
             for(LaunchInfo info : infos) if (info.componentName.getPackageName().equals(packageName)) result.add(info);
-
             return result;
         }
 
diff --git a/app/src/main/java/ohi/andre/consolelauncher/managers/ContactManager.java b/app/src/main/java/ohi/andre/consolelauncher/managers/ContactManager.java
index c92139d..ea9b64c 100755
--- a/app/src/main/java/ohi/andre/consolelauncher/managers/ContactManager.java
+++ b/app/src/main/java/ohi/andre/consolelauncher/managers/ContactManager.java
@@ -17,6 +17,7 @@ import java.util.List;
 
 import ohi.andre.consolelauncher.LauncherActivity;
 import ohi.andre.consolelauncher.tuils.Compare;
+import ohi.andre.consolelauncher.tuils.StoppableThread;
 import ohi.andre.consolelauncher.tuils.Tuils;
 
 public class ContactManager {
@@ -38,7 +39,7 @@ public class ContactManager {
             return;
         }
 
-        new Thread() {
+        new StoppableThread() {
             @Override
             public void run() {
                 super.run();
diff --git a/app/src/main/java/ohi/andre/consolelauncher/managers/MessagesManager.java b/app/src/main/java/ohi/andre/consolelauncher/managers/MessagesManager.java
index 7da2018..a4f03b7 100644
--- a/app/src/main/java/ohi/andre/consolelauncher/managers/MessagesManager.java
+++ b/app/src/main/java/ohi/andre/consolelauncher/managers/MessagesManager.java
@@ -58,15 +58,15 @@ public class MessagesManager {
                 return;
             }
 
-            Tuils.sendOutput(color, context, MARKER + Tuils.NEWLINE + copy.remove(index).msg + Tuils.NEWLINE + MARKER);
+            Tuils.sendOutput(color, context, MARKER + Tuils.NEWLINE + context.getString(copy.remove(index).msg) + Tuils.NEWLINE + MARKER);
         }
     }
 
     public static class Message {
-        String msg;
+        int msg;
 //        more coming
 
-        public Message(String msg) {
+        public Message(int msg) {
             this.msg = msg;
         }
     }
diff --git a/app/src/main/java/ohi/andre/consolelauncher/managers/RegexManager.java b/app/src/main/java/ohi/andre/consolelauncher/managers/RegexManager.java
index 646ace6..dbb5277 100644
--- a/app/src/main/java/ohi/andre/consolelauncher/managers/RegexManager.java
+++ b/app/src/main/java/ohi/andre/consolelauncher/managers/RegexManager.java
@@ -1,7 +1,6 @@
 package ohi.andre.consolelauncher.managers;
 
 import android.content.Context;
-import android.graphics.Color;
 import android.text.SpannableString;
 
 import org.w3c.dom.Document;
@@ -15,9 +14,9 @@ import java.util.List;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
-import ohi.andre.consolelauncher.R;
 import ohi.andre.consolelauncher.managers.xml.XMLPrefsManager;
 import ohi.andre.consolelauncher.managers.xml.options.Theme;
+import ohi.andre.consolelauncher.tuils.StoppableThread;
 import ohi.andre.consolelauncher.tuils.Tuils;
 
 /**
@@ -34,57 +33,74 @@ public class RegexManager {
     private RegexManager() {}
 
     private static boolean available = false;
-    public static void create(Context context) {
+    public static void create(final Context context) {
         if(available) return;
         available = true;
 
         if(regexes != null) regexes.clear();
         else regexes = new ArrayList<>();
 
-        try {
-            File file = new File(Tuils.getFolder(), PATH);
-            if(!file.exists()) {
-                file.createNewFile();
-                XMLPrefsManager.resetFile(file, ROOT);
-            }
+        new StoppableThread() {
 
-            Object[] o = XMLPrefsManager.buildDocument(file, ROOT);
+            @Override
+            public void run() {
+                super.run();
 
-            Element el = (Element) o[1];
-
-            List<Integer> busyIds = new ArrayList<>();
-
-            NodeList nodeList = el.getElementsByTagName(REGEX_LABEL);
-
-            Out:
-            for(int c = 0; c < nodeList.getLength(); c++) {
-                Element e = (Element) nodeList.item(c);
-
-                if(!e.hasAttribute(XMLPrefsManager.VALUE_ATTRIBUTE)) continue;
-                String value = e.getAttribute(XMLPrefsManager.VALUE_ATTRIBUTE);
-
-                int id;
                 try {
-                    id = Integer.parseInt(e.getAttribute(ID_ATTRIBUTE));
-                } catch (Exception exc) {
-                    continue;
-                }
-
-                for(int j = 0; j < busyIds.size(); j++) {
-                    if((int) busyIds.get(j) == id) continue Out;
-                }
-
-                busyIds.add(id);
-
-                if(value != null && value.length() > 0) {
-                    regexes.add(new Regex(value, id));
+                    File file = new File(Tuils.getFolder(), PATH);
+                    if(!file.exists()) {
+                        file.createNewFile();
+                        XMLPrefsManager.resetFile(file, ROOT);
+                    }
+
+                    Object[] o;
+                    try {
+                        o = XMLPrefsManager.buildDocument(file, ROOT);
+                        if(o == null) {
+                            Tuils.sendXMLParseError(context, PATH);
+                            return;
+                        }
+                    } catch (Exception e) {
+                        Tuils.sendXMLParseError(context, PATH, e);
+                        return;
+                    }
+
+                    Element el = (Element) o[1];
+
+                    List<Integer> busyIds = new ArrayList<>();
+
+                    NodeList nodeList = el.getElementsByTagName(REGEX_LABEL);
+
+                    Out:
+                    for(int c = 0; c < nodeList.getLength(); c++) {
+                        Element e = (Element) nodeList.item(c);
+
+                        if(!e.hasAttribute(XMLPrefsManager.VALUE_ATTRIBUTE)) continue;
+                        String value = e.getAttribute(XMLPrefsManager.VALUE_ATTRIBUTE);
+
+                        int id;
+                        try {
+                            id = Integer.parseInt(e.getAttribute(ID_ATTRIBUTE));
+                        } catch (Exception exc) {
+                            continue;
+                        }
+
+                        for(int j = 0; j < busyIds.size(); j++) {
+                            if((int) busyIds.get(j) == id) continue Out;
+                        }
+
+                        busyIds.add(id);
+
+                        if(value != null && value.length() > 0) {
+                            regexes.add(new Regex(value, id));
+                        }
+                    }
+                } catch (Exception e) {
+                    Tuils.sendXMLParseError(context, PATH, e);
+                    return;
                 }
             }
-        } catch (Exception e) {
-            Tuils.sendOutput(Color.RED, context, context.getString(R.string.output_xmlproblem1) + Tuils.SPACE + PATH + context.getString(R.string.output_xmlproblem2) +
-                    Tuils.NEWLINE + context.getString(R.string.output_errorlabel) + e.toString());
-            return;
-        }
+        }.start();
     }
 
     public static Regex get(int id) {
@@ -118,7 +134,7 @@ public class RegexManager {
 
         File file = new File(Tuils.getFolder(), PATH);
 
-        return XMLPrefsManager.add(file, ROOT, REGEX_LABEL, new String[] {ID_ATTRIBUTE, XMLPrefsManager.VALUE_ATTRIBUTE}, new String[] {String.valueOf(id), value});
+        return XMLPrefsManager.add(file, REGEX_LABEL, new String[] {ID_ATTRIBUTE, XMLPrefsManager.VALUE_ATTRIBUTE}, new String[] {String.valueOf(id), value});
     }
 
 //    null: all good
@@ -127,7 +143,10 @@ public class RegexManager {
         try {
             File file = new File(Tuils.getFolder(), PATH);
 
-            Object[] o = XMLPrefsManager.buildDocument(file, ROOT);
+            Object[] o = XMLPrefsManager.buildDocument(file, null);
+            if(o == null) {
+                return null;
+            }
 
             Document d = (Document) o[0];
             Element el = (Element) o[1];
@@ -166,10 +185,8 @@ public class RegexManager {
         Regex regex = get(id);
         if(regex == null) return Tuils.EMPTYSTRING;
 
-        String r = regex.value;
-
-        Pattern p = Pattern.compile(r);
-        Matcher m = p.matcher(test);
+        if(regex.regex == null) return "null";
+        Matcher m = regex.regex.matcher(test);
 
         int color = XMLPrefsManager.getColor(Theme.mark_color);
         int outputColor = XMLPrefsManager.getColor(Theme.output_color);
@@ -189,11 +206,14 @@ public class RegexManager {
     }
 
     public static class Regex {
-        public String value;
+        public Pattern regex;
+        public String literalPattern;
         public int id;
 
+        public Regex() {}
+
         public Regex(String value, int id) {
-            this.value = value;
+            this.regex = Pattern.compile(value);
             this.id = id;
         }
     }
diff --git a/app/src/main/java/ohi/andre/consolelauncher/managers/RssManager.java b/app/src/main/java/ohi/andre/consolelauncher/managers/RssManager.java
index 000076a..7375d18 100644
--- a/app/src/main/java/ohi/andre/consolelauncher/managers/RssManager.java
+++ b/app/src/main/java/ohi/andre/consolelauncher/managers/RssManager.java
@@ -5,7 +5,6 @@ import android.content.Intent;
 import android.graphics.Color;
 import android.net.ConnectivityManager;
 import android.os.Handler;
-import android.os.Message;
 import android.text.TextUtils;
 
 import org.w3c.dom.Document;
@@ -15,9 +14,6 @@ import org.w3c.dom.NodeList;
 
 import java.io.BufferedInputStream;
 import java.io.File;
-import java.net.HttpURLConnection;
-import java.net.URL;
-import java.text.DateFormat;
 import java.text.ParseException;
 import java.text.SimpleDateFormat;
 import java.util.ArrayList;
@@ -32,9 +28,15 @@ import javax.xml.parsers.DocumentBuilderFactory;
 
 import ohi.andre.consolelauncher.R;
 import ohi.andre.consolelauncher.managers.xml.XMLPrefsManager;
+import ohi.andre.consolelauncher.managers.xml.options.Theme;
 import ohi.andre.consolelauncher.tuils.InputOutputReceiver;
-import ohi.andre.consolelauncher.tuils.TimeManager;
+import ohi.andre.consolelauncher.tuils.StoppableThread;
 import ohi.andre.consolelauncher.tuils.Tuils;
+import ohi.andre.consolelauncher.tuils.html_escape.HtmlEscape;
+import okhttp3.OkHttpClient;
+import okhttp3.Request;
+import okhttp3.Response;
+import okhttp3.ResponseBody;
 
 import static ohi.andre.consolelauncher.managers.xml.XMLPrefsManager.VALUE_ATTRIBUTE;
 import static ohi.andre.consolelauncher.managers.xml.XMLPrefsManager.set;
@@ -51,22 +53,22 @@ public class RssManager implements XMLPrefsManager.XmlPrefsElement {
 //    etag
 //    last_checked_client
 
+    private final int RSS_CHECK_DELAY = 5000;
+
     private final String RSS_FOLDER = "rss";
 
-    public static final String TIME_ATTRIBUTE  = "time", SHOW_ATTRIBUTE = "show", URL_ATTRIBUTE = "url", LASTCHECKED_ATTRIBUTE = "lastChecked", LASTMODIFIED_ATTRIBUTE = "lastModified", ETAG_ATTRIBUTE = "etag",
+    public static final String TIME_ATTRIBUTE  = "updateTimeSec", SHOW_ATTRIBUTE = "show", URL_ATTRIBUTE = "url", LASTCHECKED_ATTRIBUTE = "lastChecked", LASTMODIFIED_ATTRIBUTE = "lastModified", ETAG_ATTRIBUTE = "etag",
                             LAST_SHOWN_ITEM_ATTRIBUTE = "lastShownItem", ID_ATTRIBUTE = "id", FORMAT_ATTRIBUTE = "format", INCLUDE_ATTRIBUTE = "includeIfMatches", EXCLUDE_ATTRIBUTE = "excludeIfMatches",
-                                COLOR_ATTRIBUTE = "color", WIFIONLY_ATTRIBUTE = "wifiOnly", COMMAND_ATTRIBUTE = "updateCommand";
-
-    public static final String RSS_LABEL = "rss", FORMAT_LABEL = "format";
+                            COLOR_ATTRIBUTE = "color", WIFIONLY_ATTRIBUTE = "wifiOnly", TIME_FORMAT_ATTRIBUTE = "timeFormat", DATE_TAG_ATTRIBUTE = "pubDateTag",
+                            ENTRY_TAG_ATTRIBUTE = "entryTag", ON_ATTRIBUTE = "on", CMD_ATTRIBUTE = "cmd";
 
-    private final String SEPARATOR = " - ";
-    private final String ID_LABEL = "ID: ", TIME_LABEL = "update time: ", SHOW_LABEL = "show: ", URL_LABEL = "url: ";
+    public static final String RSS_LABEL = "rss", FORMAT_LABEL = "format", REGEX_CMD_LABEL = "regex";
 
     private final String LAST_MODIFIED_FIELD = "Last-Modified", ETAG_FIELD = "ETag", IF_MODIFIED_SINCE_FIELD = "If-Modified-Since", IF_NONE_MATCH_FIELD = "If-None-Match", GET_LABEL = "GET";
 
-    private final String PUBDATE_CHILD = "pubDate";
+    private final String PUBDATE_CHILD = "pubDate", ENTRY_CHILD = "item", LINK_CHILD = "link", HREF_ATTRIBUTE = "href";
 
-    private DateFormat defaultRSSDateFormat = new SimpleDateFormat("EEE, d MMM yyyy HH:mm:ss z");
+    private SimpleDateFormat defaultRSSDateFormat = new SimpleDateFormat("EEE, d MMM yyyy HH:mm:ss Z");
 
     private static XMLPrefsManager.XMLPrefsList values;
 
@@ -87,72 +89,83 @@ public class RssManager implements XMLPrefsManager.XmlPrefsElement {
 
     @Override
     public void write(XMLPrefsManager.XMLPrefsSave save, String value) {
-        set(new File(Tuils.getFolder(), PATH), NAME, save.label(), new String[] {VALUE_ATTRIBUTE}, new String[] {value});
+        set(new File(Tuils.getFolder(), PATH), save.label(), new String[] {VALUE_ATTRIBUTE}, new String[] {value});
     }
 
-    private int defaultColor;
-    private String defaultFormat, timeFormat;
-    private boolean includeRssDefault;
+    private int defaultColor, timeColor, downloadMessageColor;
+    private String defaultFormat, timeFormat, downloadFormat;
+
+    private boolean includeRssDefault, showDownloadMessage, click;
 
     private Context context;
     private Handler handler;
 
-    private File root, rssFile;
+    private File root, rssIndexFile;
 
     private List<Rss> feeds;
-    private List<Format> formats;
+    private List<XMLPrefsManager.IdValue> formats;
+    private List<CmdableRegex> cmdRegexes;
 
-//    those will obscure the tag and its content
+    private OkHttpClient client;
+
+    //    those will obscure the tag and its content
     private Pattern[] hideTagPatterns;
 
+    private Pattern urlPattern, idPattern, bPattern, kbPattern, mbPattern, gbPattern;
+
     private ConnectivityManager connectivityManager;
 
-    public RssManager(Context context) {
+    public RssManager(Context context, OkHttpClient client) {
         instance = this;
         this.context = context;
 
         connectivityManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
 
-        RegexManager.create(context);
-
         root = new File(Tuils.getFolder(), RSS_FOLDER);
-        rssFile = new File(Tuils.getFolder(), PATH);
+        rssIndexFile = new File(Tuils.getFolder(), PATH);
+
+        this.client = client;
 
         prepare();
 
         values = new XMLPrefsManager.XMLPrefsList();
 
+        handler = new Handler();
         refresh();
     }
 
     public void refresh() {
         if(handler != null) {
             handler.removeCallbacksAndMessages(null);
-            handler = null;
         }
 
-        handler = new Handler() {
-            @Override
-            public void handleMessage(Message msg) {
-                super.handleMessage(msg);
-
-                
-            }
-        };
-
         if(feeds != null) feeds.clear();
         else feeds = new ArrayList<>();
 
         if(formats != null) formats.clear();
         else formats = new ArrayList<>();
 
-        new Thread() {
+        if(cmdRegexes != null) cmdRegexes.clear();
+        else cmdRegexes = new ArrayList<>();
+
+        new StoppableThread() {
             @Override
             public void run() {
                 super.run();
 
+                Object[] o;
+                try {
+                    o = XMLPrefsManager.buildDocument(rssIndexFile, NAME);
+                    if(o == null) {
+                        Tuils.sendXMLParseError(context, PATH);
+                        return;
+                    }
+                } catch (Exception e) {
+                    Tuils.sendXMLParseError(context, PATH, e);
+                    return;
+                }
+
                 try {
-                    Object[] o = XMLPrefsManager.buildDocument(rssFile, NAME);
 
                     Document document = (Document) o[0];
                     Element rootElement = (Element) o[1];
@@ -164,7 +177,6 @@ public class RssManager implements XMLPrefsManager.XmlPrefsElement {
                     String[] deleted = instance.deleted();
                     boolean needToWrite = false;
 
-                    Main:
                     for(int count = 0; count < nodes.getLength(); count++) {
                         Node node = nodes.item(count);
 
@@ -194,64 +206,47 @@ public class RssManager implements XMLPrefsManager.XmlPrefsElement {
                                 String name = node.getNodeName();
                                 if (name.equals(RSS_LABEL)) {
                                     Element t = (Element) node;
+                                    feeds.add(Rss.fromElement(t));
+                                } else if(name.equals(FORMAT_LABEL)) {
+                                    Element e = (Element) node;
 
                                     int id;
                                     try {
-                                        id = Integer.parseInt(t.getAttribute(ID_ATTRIBUTE));
+                                        id = Integer.parseInt(e.getAttribute(ID_ATTRIBUTE));
                                     } catch (Exception exc) {
-                                        continue Main;
+                                        id = -1;
                                     }
 
-                                    String url = t.getAttribute(URL_ATTRIBUTE);
-                                    long updateTime = Long.parseLong(t.getAttribute(TIME_ATTRIBUTE));
-                                    boolean show = Boolean.parseBoolean(t.getAttribute(SHOW_ATTRIBUTE));
+                                    if(id == -1) continue;
 
-                                    long lastChecked = t.hasAttribute(LASTCHECKED_ATTRIBUTE) ? Long.parseLong(t.getAttribute(LASTCHECKED_ATTRIBUTE)) : -1;
-                                    long lastShown = t.hasAttribute(LAST_SHOWN_ITEM_ATTRIBUTE) ? Long.parseLong(t.getAttribute(LAST_SHOWN_ITEM_ATTRIBUTE)) : -1;
-                                    String lastModified = t.hasAttribute(LASTMODIFIED_ATTRIBUTE) ? t.getAttribute(LASTMODIFIED_ATTRIBUTE) : null;
-                                    String etag = t.hasAttribute(ETAG_ATTRIBUTE) ? t.getAttribute(ETAG_ATTRIBUTE) : null;
+                                    String format = XMLPrefsManager.getStringAttribute(e, XMLPrefsManager.VALUE_ATTRIBUTE);
 
-                                    String format = t.hasAttribute(FORMAT_ATTRIBUTE) ? t.getAttribute(FORMAT_ATTRIBUTE) : null;
-                                    String includeIfMatches = t.hasAttribute(INCLUDE_ATTRIBUTE) ? t.getAttribute(INCLUDE_ATTRIBUTE) : null;
-                                    String excludeIfMatches = t.hasAttribute(EXCLUDE_ATTRIBUTE) ? t.getAttribute(EXCLUDE_ATTRIBUTE) : null;
-                                    int color;
-                                    try {
-                                        color = Color.parseColor(t.getAttribute(COLOR_ATTRIBUTE));
-                                    } catch (Exception exc) {
-                                        color = Integer.MAX_VALUE;
-                                    }
+                                    XMLPrefsManager.IdValue i = new XMLPrefsManager.IdValue(format, id);
+                                    formats.add(i);
+                                } else if(name.equals(REGEX_CMD_LABEL)) {
+                                    Element e = (Element) node;
 
-                                    boolean wifiOnly;
+                                    int id;
                                     try {
-                                        wifiOnly = Boolean.parseBoolean(t.getAttribute(WIFIONLY_ATTRIBUTE));
-                                    } catch (Exception e) {
-                                        wifiOnly = false;
+                                        id = Integer.parseInt(e.getAttribute(ID_ATTRIBUTE));
+                                    } catch (Exception exc) {
+                                        continue;
                                     }
 
-                                    String updateCommand = t.hasAttribute(COMMAND_ATTRIBUTE) ? t.getAttribute(COMMAND_ATTRIBUTE) : null;
-
-                                    final Rss r = new Rss(url, updateTime, lastChecked, lastShown, id, show, lastModified, etag, format, includeIfMatches, excludeIfMatches, color, wifiOnly, updateCommand);
-                                    feeds.add(r);
-                                } else if(name.equals(FORMAT_LABEL)) {
-                                        Element e = (Element) node;
+                                    String regex = XMLPrefsManager.getStringAttribute(e, XMLPrefsManager.VALUE_ATTRIBUTE);
+                                    if(regex == null || regex.length() == 0) continue;
 
-                                        int id;
-                                        try {
-                                            id = Integer.parseInt(e.getAttribute(ID_ATTRIBUTE));
-                                        } catch (Exception exc) {
-                                            id = -1;
-                                        }
+                                    String on = XMLPrefsManager.getStringAttribute(e, ON_ATTRIBUTE);
+                                    if(on == null || on.length() == 0) continue;
 
-                                        if(id == -1) continue;
+                                    String cmd = XMLPrefsManager.getStringAttribute(e, CMD_ATTRIBUTE);
+                                    if(cmd == null || cmd.length() == 0) continue;
 
-                                        String format = e.getAttribute(XMLPrefsManager.VALUE_ATTRIBUTE);
-
-                                        Format i = new Format(format, id);
-                                        formats.add(i);
-                                    }
+                                    cmdRegexes.add(new CmdableRegex(id, on, regex, cmd));
                                 }
                             }
                         }
+                    }
 
                     if (enums.size() > 0) {
                         for (XMLPrefsManager.XMLPrefsSave s : enums) {
@@ -264,19 +259,37 @@ public class RssManager implements XMLPrefsManager.XmlPrefsElement {
                             values.add(s.label(), value);
                         }
 
-                        writeTo(document, rssFile);
+                        writeTo(document, rssIndexFile);
                     } else if (needToWrite) {
-                        writeTo(document, rssFile);
+                        writeTo(document, rssIndexFile);
                     }
                 } catch (Exception e) {
                     Tuils.log(e);
                     Tuils.toFile(e);
                 }
 
+                click = XMLPrefsManager.getBoolean(ohi.andre.consolelauncher.managers.xml.options.Rss.click_rss);
+//                longClick = XMLPrefsManager.getBoolean(ohi.andre.consolelauncher.managers.xml.options.Rss.long_click_rss);
                 defaultFormat = XMLPrefsManager.get(ohi.andre.consolelauncher.managers.xml.options.Rss.rss_default_format);
                 defaultColor = XMLPrefsManager.getColor(ohi.andre.consolelauncher.managers.xml.options.Rss.rss_default_color);
                 includeRssDefault = XMLPrefsManager.getBoolean(ohi.andre.consolelauncher.managers.xml.options.Rss.include_rss_default);
                 timeFormat = XMLPrefsManager.get(ohi.andre.consolelauncher.managers.xml.options.Rss.rss_time_format);
+                showDownloadMessage = XMLPrefsManager.getBoolean(ohi.andre.consolelauncher.managers.xml.options.Rss.show_rss_download);
+                if(showDownloadMessage) {
+                    downloadFormat = XMLPrefsManager.get(ohi.andre.consolelauncher.managers.xml.options.Rss.rss_download_format);
+
+                    String size = "%s";
+
+                    idPattern = Pattern.compile("%id", Pattern.CASE_INSENSITIVE);
+                    urlPattern = Pattern.compile("%url", Pattern.CASE_INSENSITIVE);
+                    gbPattern = Pattern.compile(size + "gb", Pattern.CASE_INSENSITIVE);
+                    mbPattern = Pattern.compile(size + "mb", Pattern.CASE_INSENSITIVE);
+                    kbPattern = Pattern.compile(size + "kb", Pattern.CASE_INSENSITIVE);
+                    bPattern = Pattern.compile(size + "b", Pattern.CASE_INSENSITIVE);
+
+                    timeColor = XMLPrefsManager.getColor(Theme.time_color);
+                    downloadMessageColor = XMLPrefsManager.getColor(ohi.andre.consolelauncher.managers.xml.options.Rss.rss_download_message_color);
+                }
 
                 String hiddenTags = XMLPrefsManager.get(ohi.andre.consolelauncher.managers.xml.options.Rss.rss_hidden_tags).replaceAll(Tuils.SPACE, Tuils.EMPTYSTRING);
                 String[] split = null;
@@ -296,37 +309,49 @@ public class RssManager implements XMLPrefsManager.XmlPrefsElement {
                 }
 
                 for(Rss rss : feeds) {
-                    rss.updateFormat();
+                    rss.updateFormat(formats);
                     rss.updateIncludeIfMatches();
                     rss.updateExcludeIfMatches();
 
                     if(rss.color == Integer.MAX_VALUE) rss.color = defaultColor;
+                }
 
-                    queue(rss);
+                for(CmdableRegex rg : cmdRegexes) {
+                    try {
+                        int id = Integer.parseInt(rg.literalPattern);
+                        rg.regex = RegexManager.get(id).regex;
+                    } catch (Exception exc) {
+                        try {
+                            rg.regex = Pattern.compile(rg.literalPattern);
+                        } catch (Exception e) {
+                            Tuils.sendOutput(Color.RED, context, context.getString(R.string.invalid_regex) + Tuils.SPACE + rg.literalPattern);
+                            rg.regex = null;
+                        }
+                    }
                 }
+
+                handler.post(updateRunnable);
             }
         }.start();
     }
 
     public void dispose() {
-        handler.removeCallbacksAndMessages(null);
+        if(handler != null) handler.removeCallbacksAndMessages(null);
     }
 
     public String add(int id, long timeInSeconds, String url) {
-        String output = XMLPrefsManager.add(rssFile, NAME, RSS_LABEL, new String[] {ID_ATTRIBUTE, TIME_ATTRIBUTE, SHOW_ATTRIBUTE, URL_ATTRIBUTE},
-                new String[] {String.valueOf(id), String.valueOf(timeInSeconds * 1000), String.valueOf(true), url});
+        String output = XMLPrefsManager.add(rssIndexFile, RSS_LABEL, new String[] {ID_ATTRIBUTE, TIME_ATTRIBUTE, SHOW_ATTRIBUTE, URL_ATTRIBUTE},
+                new String[] {String.valueOf(id), String.valueOf(timeInSeconds), String.valueOf(true), url});
 
         if(output == null) {
             try {
-                Rss r = new Rss(url, timeInSeconds * 1000, id, true);
+                Rss r = new Rss(url, timeInSeconds, id, true);
 
                 r.lastShownItem = System.currentTimeMillis();
                 r.format = defaultFormat;
 
                 updateRss(r, true);
                 feeds.add(r);
-
-                queue(r);
             } catch (Exception e) {
                 Tuils.log(e);
                 return e.toString();
@@ -337,15 +362,15 @@ public class RssManager implements XMLPrefsManager.XmlPrefsElement {
     }
 
     public String addFormat(int id, String value) {
-        String output = XMLPrefsManager.add(rssFile, NAME, FORMAT_LABEL, new String[] {ID_ATTRIBUTE, XMLPrefsManager.VALUE_ATTRIBUTE}, new String[] {String.valueOf(id), value});
+        String output = XMLPrefsManager.add(rssIndexFile, FORMAT_LABEL, new String[] {ID_ATTRIBUTE, XMLPrefsManager.VALUE_ATTRIBUTE}, new String[] {String.valueOf(id), value});
         if(output == null) {
-            formats.add(new Format(value, id));
+            formats.add(new XMLPrefsManager.IdValue(value, id));
             return null;
         } else return output;
     }
 
     public String removeFormat(int id) {
-        String output = XMLPrefsManager.removeNode(rssFile, NAME, FORMAT_LABEL, new String[] {ID_ATTRIBUTE}, new String[] {String.valueOf(id)});;
+        String output = XMLPrefsManager.removeNode(rssIndexFile, FORMAT_LABEL, new String[] {ID_ATTRIBUTE}, new String[] {String.valueOf(id)});;
         if(output == null) {
             return null;
         } else {
@@ -355,7 +380,7 @@ public class RssManager implements XMLPrefsManager.XmlPrefsElement {
     }
 
     public String rm(int id) {
-        String output = XMLPrefsManager.removeNode(rssFile, NAME, RSS_LABEL, new String[] {ID_ATTRIBUTE}, new String[] {String.valueOf(id)});
+        String output = XMLPrefsManager.removeNode(rssIndexFile, RSS_LABEL, new String[] {ID_ATTRIBUTE}, new String[] {String.valueOf(id)});
         if(output == null) {
             File rss = new File(root, RSS_LABEL + id + ".xml");
             if(rss.exists()) rss.delete();
@@ -374,28 +399,33 @@ public class RssManager implements XMLPrefsManager.XmlPrefsElement {
     public String list() {
         StringBuilder builder = new StringBuilder();
         for(Rss r : feeds) {
-            builder.append(ID_LABEL).append(":").append(Tuils.SPACE).append(r.id).append(Tuils.NEWLINE).append(r.url).append(Tuils.NEWLINE);
+            builder.append(Rss.ID_LABEL).append(":").append(Tuils.SPACE).append(r.id).append(Tuils.NEWLINE).append(r.url).append(Tuils.NEWLINE);
         }
 
-        return builder.toString().trim();
+        String output = builder.toString().trim();
+        if(output.length() == 0) return "[]";
+        return output;
     }
 
-    public void l(int id) {
+    public String l(int id) {
         for(Rss feed : feeds) {
             if(feed.id == id) {
                 try {
                     parse(feed, false);
+                    return null;
                 } catch (Exception e) {
                     Tuils.log(e);
                     Tuils.toFile(e);
+                    return e.toString();
                 }
-                break;
             }
         }
+
+        return context.getString(R.string.rss_not_found);
     }
 
     public String setShow(int id, boolean show) {
-        String output = XMLPrefsManager.set(rssFile, NAME, RSS_LABEL, new String[] {ID_ATTRIBUTE}, new String[] {String.valueOf(id)}, new String[] {SHOW_ATTRIBUTE}, new String[] {String.valueOf(show)}, false);
+        String output = XMLPrefsManager.set(rssIndexFile, RSS_LABEL, new String[] {ID_ATTRIBUTE}, new String[] {String.valueOf(id)}, new String[] {SHOW_ATTRIBUTE}, new String[] {String.valueOf(show)}, false);
         if(output == null) {
             Rss r = findId(id);
             if(r != null) r.show = show;
@@ -408,7 +438,7 @@ public class RssManager implements XMLPrefsManager.XmlPrefsElement {
     }
 
     public String setTime(int id, long timeSeconds) {
-        String output = XMLPrefsManager.set(rssFile, NAME, RSS_LABEL, new String[] {ID_ATTRIBUTE}, new String[] {String.valueOf(id)}, new String[] {TIME_ATTRIBUTE}, new String[] {String.valueOf(timeSeconds)}, false);
+        String output = XMLPrefsManager.set(rssIndexFile, RSS_LABEL, new String[] {ID_ATTRIBUTE}, new String[] {String.valueOf(id)}, new String[] {TIME_ATTRIBUTE}, new String[] {String.valueOf(timeSeconds)}, false);
         if(output == null) {
             Rss r = findId(id);
             if(r != null) r.updateTimeSeconds = timeSeconds;
@@ -420,11 +450,24 @@ public class RssManager implements XMLPrefsManager.XmlPrefsElement {
         }
     }
 
+    public String setTimeFormat(int id, String format) {
+        String output = XMLPrefsManager.set(rssIndexFile, RSS_LABEL, new String[] {ID_ATTRIBUTE}, new String[] {String.valueOf(id)}, new String[] {TIME_FORMAT_ATTRIBUTE}, new String[] {format}, false);
+        if(output == null) {
+            Rss r = findId(id);
+            if(r != null) r.timeFormat = new SimpleDateFormat(format);
+            return null;
+        }
+        else {
+            if (output.length() > 0) return output;
+            return context.getString(R.string.rss_not_found);
+        }
+    }
+
     public String setFormat(int id, String format) {
-        String output = XMLPrefsManager.set(rssFile, NAME, RSS_LABEL, new String[] {ID_ATTRIBUTE}, new String[] {String.valueOf(id)}, new String[] {FORMAT_ATTRIBUTE}, new String[] {format}, false);
+        String output = XMLPrefsManager.set(rssIndexFile, RSS_LABEL, new String[] {ID_ATTRIBUTE}, new String[] {String.valueOf(id)}, new String[] {FORMAT_ATTRIBUTE}, new String[] {format}, false);
         if(output == null) {
             Rss r = findId(id);
-            if(r != null) r.setFormat(format);
+            if(r != null) r.setFormat(formats, format);
             return null;
         }
         else {
@@ -434,7 +477,7 @@ public class RssManager implements XMLPrefsManager.XmlPrefsElement {
     }
 
     public String setColor(int id, String color) {
-        String output = XMLPrefsManager.set(rssFile, NAME, RSS_LABEL, new String[] {ID_ATTRIBUTE}, new String[] {String.valueOf(id)}, new String[] {COLOR_ATTRIBUTE}, new String[] {color}, false);
+        String output = XMLPrefsManager.set(rssIndexFile, RSS_LABEL, new String[] {ID_ATTRIBUTE}, new String[] {String.valueOf(id)}, new String[] {COLOR_ATTRIBUTE}, new String[] {color}, false);
         if(output == null) {
             Rss r = findId(id);
             if(r != null) r.color = Color.parseColor(color);
@@ -446,8 +489,34 @@ public class RssManager implements XMLPrefsManager.XmlPrefsElement {
         }
     }
 
+    public String setDateTag(int id, String tag) {
+        String output = XMLPrefsManager.set(rssIndexFile, RSS_LABEL, new String[] {ID_ATTRIBUTE}, new String[] {String.valueOf(id)}, new String[] {DATE_TAG_ATTRIBUTE}, new String[] {tag}, false);
+        if(output == null) {
+            Rss r = findId(id);
+            if(r != null) r.dateTag = tag;
+            return null;
+        }
+        else {
+            if (output.length() > 0) return output;
+            return context.getString(R.string.rss_not_found);
+        }
+    }
+
+    public String setEntryTag(int id, String tag) {
+        String output = XMLPrefsManager.set(rssIndexFile, RSS_LABEL, new String[] {ID_ATTRIBUTE}, new String[] {String.valueOf(id)}, new String[] {ENTRY_TAG_ATTRIBUTE}, new String[] {tag}, false);
+        if(output == null) {
+            Rss r = findId(id);
+            if(r != null) r.entryTag = tag;
+            return null;
+        }
+        else {
+            if (output.length() > 0) return output;
+            return context.getString(R.string.rss_not_found);
+        }
+    }
+
     public String setIncludeIfMatches(int id, String regex) {
-        String output = XMLPrefsManager.set(rssFile, NAME, RSS_LABEL, new String[] {ID_ATTRIBUTE}, new String[] {String.valueOf(id)}, new String[] {INCLUDE_ATTRIBUTE}, new String[] {regex}, false);
+        String output = XMLPrefsManager.set(rssIndexFile, RSS_LABEL, new String[] {ID_ATTRIBUTE}, new String[] {String.valueOf(id)}, new String[] {INCLUDE_ATTRIBUTE}, new String[] {regex}, false);
         if(output == null) {
             Rss r = findId(id);
             if(r != null) r.setIncludeIfMatches(regex);
@@ -460,7 +529,7 @@ public class RssManager implements XMLPrefsManager.XmlPrefsElement {
     }
 
     public String setExcludeIfMatches(int id, String regex) {
-        String output = XMLPrefsManager.set(rssFile, NAME, RSS_LABEL, new String[] {ID_ATTRIBUTE}, new String[] {String.valueOf(id)}, new String[] {EXCLUDE_ATTRIBUTE}, new String[] {regex}, false);
+        String output = XMLPrefsManager.set(rssIndexFile, RSS_LABEL, new String[] {ID_ATTRIBUTE}, new String[] {String.valueOf(id)}, new String[] {EXCLUDE_ATTRIBUTE}, new String[] {regex}, false);
         if(output == null) {
             Rss r = findId(id);
             if(r != null) r.setExcludeIfMatches(regex);
@@ -473,7 +542,7 @@ public class RssManager implements XMLPrefsManager.XmlPrefsElement {
     }
 
     public String setWifiOnly(int id, boolean wifiOnly) {
-        String output = XMLPrefsManager.set(rssFile, NAME, RSS_LABEL, new String[] {ID_ATTRIBUTE}, new String[] {String.valueOf(id)}, new String[] {WIFIONLY_ATTRIBUTE}, new String[] {String.valueOf(wifiOnly)},
+        String output = XMLPrefsManager.set(rssIndexFile, RSS_LABEL, new String[] {ID_ATTRIBUTE}, new String[] {String.valueOf(id)}, new String[] {WIFIONLY_ATTRIBUTE}, new String[] {String.valueOf(wifiOnly)},
                 false);
         if(output == null) {
             Rss r = findId(id);
@@ -486,121 +555,177 @@ public class RssManager implements XMLPrefsManager.XmlPrefsElement {
         }
     }
 
-//    base methods
+    public String addRegexCommand(int id, String on, String regex, String cmd) {
+        String output = XMLPrefsManager.add(rssIndexFile, REGEX_CMD_LABEL, new String[] {ID_ATTRIBUTE, ON_ATTRIBUTE, XMLPrefsManager.VALUE_ATTRIBUTE, CMD_ATTRIBUTE},
+                new String[] {String.valueOf(id), on, regex, cmd});
+        if(output == null) {
+            cmdRegexes.add(new CmdableRegex(id, on, regex, cmd));
+            return null;
+        } else {
+            if(output.length() > 0) return output;
+            return context.getString(R.string.output_error);
+        }
+    }
 
-    private void queue(final Rss rss) {
-        Runnable rn = new Runnable() {
-            @Override
-            public void run() {
-                try {
-                    updateRss(rss, false);
-                    queue(rss);
-                } catch (Exception e1) {
-                    Tuils.log(e1);
-                }
+    public String rmRegexCommand(int id) {
+        String output = XMLPrefsManager.removeNode(rssIndexFile, REGEX_CMD_LABEL, new String[] {ID_ATTRIBUTE}, new String[] {String.valueOf(id)});
+        if(output == null) {
+            for(int i = 0; i < cmdRegexes.size(); i++) {
+                if(cmdRegexes.get(i).id == id) cmdRegexes.remove(i);
             }
-        };
-
-        long delay;
-        if(rss.lastCheckedClient == -1) delay = 0;
-        else delay = rss.updateTimeSeconds - (System.currentTimeMillis() - rss.lastCheckedClient);
 
-        if(delay <= 0) rn.run();
-        else {
-            handler.postDelayed(rn, delay);
+            return null;
+        } else {
+            if(output.length() > 0) return output;
+            return context.getString(R.string.id_notfound);
         }
     }
 
+//    base methods
+
+    private Runnable updateRunnable = new Runnable() {
+        @Override
+        public void run() {
+            for(Rss feed : feeds) {
+                if(feed.needUpdate()) updateRss(feed, false);
+            }
+
+            handler.postDelayed(this, RSS_CHECK_DELAY);
+        }
+    };
+
     final String quotes = "\"";
 
     private void updateRss(final Rss feed, final boolean firstTime) {
-        if(feed.wifiOnly && !connectivityManager.getNetworkInfo(ConnectivityManager.TYPE_WIFI).isConnected()) {
+        updateRss(feed, firstTime, false);
+    }
+
+    public boolean updateRss(int feed, final boolean firstTime, boolean force) {
+        Rss rss = findId(feed);
+        if(rss == null) return false;
+
+        updateRss(rss, firstTime, force);
+        return true;
+    }
+
+    private void updateRss(final Rss feed, final boolean firstTime, boolean force) {
+        if(!force && feed.wifiOnly && !connectivityManager.getNetworkInfo(ConnectivityManager.TYPE_WIFI).isConnected()) {
 
             feed.lastCheckedClient = System.currentTimeMillis();
-            feed.updateFile();
+            feed.updateFile(rssIndexFile);
 
             return;
         }
 
-        final Object o = new Object();
-
-        new Thread() {
+        new StoppableThread() {
             @Override
             public void run() {
                 super.run();
 
+                if(!Tuils.hasInternetAccess()) {
+                    return;
+                }
+
                 try {
-                    URL uObj = new URL(feed.url);
-                    HttpURLConnection urlConnection = (HttpURLConnection) uObj.openConnection();
-                    urlConnection.setRequestMethod(GET_LABEL);
+                    Request.Builder builder = new Request.Builder()
+                            .url(feed.url)
+                            .get();
 
-                    if(!firstTime) {
-                        urlConnection.setRequestProperty(IF_MODIFIED_SINCE_FIELD, feed.lMod);
-                        urlConnection.setRequestProperty(IF_NONE_MATCH_FIELD, quotes + feed.etag + quotes);
+                    if(!firstTime && feed.lMod != null && feed.etag != null) {
+                        builder.addHeader(IF_MODIFIED_SINCE_FIELD, feed.lMod);
+                        builder.addHeader(IF_NONE_MATCH_FIELD, quotes + feed.etag + quotes);
                     }
 
-                    urlConnection.connect();
+                    Response response = client.newCall(builder.build()).execute();
 
-                    if(firstTime || urlConnection.getResponseCode() != 304) {
-                        Tuils.download(new BufferedInputStream(uObj.openStream()), new File(root, RSS_LABEL + feed.id + ".xml"));
+                    if(firstTime || response.code() != 304) {
+                        ResponseBody body = response.body();
 
-                        feed.lMod = urlConnection.getHeaderField(LAST_MODIFIED_FIELD);
-                        feed.etag = urlConnection.getHeaderField(ETAG_FIELD);
-                        if(feed.etag != null) feed.etag = feed.etag.replaceAll("\"", Tuils.EMPTYSTRING);
+                        long bytes = 0;
+                        if(body != null) bytes = Tuils.download(new BufferedInputStream(body.byteStream()), new File(root, RSS_LABEL + feed.id + ".xml"));
+
+                        if(showDownloadMessage) {
+                            CharSequence c = Tuils.span(downloadFormat, downloadMessageColor);
+
+                            double kb = (double) bytes / (double) 1024;
+                            double mb = kb / (double) 1024;
+                            double gb = mb / (double) 1024;
+
+                            kb = Tuils.round(kb, 2);
+                            mb = Tuils.round(mb, 2);
+                            gb = Tuils.round(gb, 2);
+
+                            c = urlPattern.matcher(c).replaceAll(feed.url);
+                            c = idPattern.matcher(c).replaceAll(String.valueOf(feed.id));
+                            c = gbPattern.matcher(c).replaceAll(String.valueOf(gb));
+                            c = mbPattern.matcher(c).replaceAll(String.valueOf(mb));
+                            c = kbPattern.matcher(c).replaceAll(String.valueOf(kb));
+                            c = bPattern.matcher(c).replaceAll(String.valueOf(bytes));
 
-                        if(parse(feed, true) && feed.updateCommand != null) {
-                            Intent intent = new Intent(InputOutputReceiver.ACTION_CMD);
-                            intent.putExtra(InputOutputReceiver.SHOW_CONTENT, false);
-                            intent.putExtra(InputOutputReceiver.TEXT, feed.updateCommand);
-                            context.sendBroadcast(intent);
+                            c = TimeManager.replace(c, timeColor);
+
+                            Tuils.sendOutput(downloadMessageColor, context, c);
+                        }
+
+                        if(bytes == 0) {
+                            Tuils.sendOutput(Color.RED, context, context.getString(R.string.rss_invalid_empty) + Tuils.SPACE + feed.id);
+                            return;
                         }
+
+                        feed.lMod = response.header(LAST_MODIFIED_FIELD);
+                        feed.etag = response.header(ETAG_FIELD);
+                        if(feed.etag != null) feed.etag = feed.etag.replaceAll("\"", Tuils.EMPTYSTRING);
+
+                        response.close();
+
+                        if(feed.show) parse(feed, true);
                     } else {
 //                        not modified
                     }
 
                     feed.lastCheckedClient = System.currentTimeMillis();
-                    feed.updateFile();
+                    feed.updateFile(rssIndexFile);
 
                 } catch (Exception e) {
                     Tuils.log(e);
                     Tuils.toFile(e);
                 }
-
-                synchronized (o) {
-                    o.notify();
-                }
             }
         }.start();
-
-        synchronized (o) {
-            try {
-                o.wait();
-            } catch (InterruptedException e) {
-                Tuils.log(e);
-                Tuils.toFile(e);
-            }
-        }
     }
 
     private boolean parse(Rss feed, boolean time) throws Exception {
-        Tuils.log("parse");
-
         boolean updated = false;
 
         File rssFile = new File(root, RSS_LABEL + feed.id + ".xml");
-        if(!rssFile.exists()) return updated;
+        if(!rssFile.exists()) return false;
 
         DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
         DocumentBuilder dBuilder = dbFactory.newDocumentBuilder();
-        Document doc = dBuilder.parse(rssFile);
+
+        Document doc;
+        try {
+            doc = dBuilder.parse(rssFile);
+        } catch (Exception e) {
+            Tuils.sendXMLParseError(context, PATH, e);
+            return false;
+        }
 
         doc.getDocumentElement().normalize();
 
-        long lastShown = feed.lastShownItem;
+        long greatestTime = -1;
+        boolean foundOneDateAtLeast = false;
+
+        String entryTag = feed.entryTag != null ? feed.entryTag : ENTRY_CHILD;
+        String dateTag = feed.dateTag != null ? feed.dateTag : PUBDATE_CHILD;
+
+        NodeList list = doc.getElementsByTagName(entryTag);
+        if(list.getLength() == 0) {
+            Tuils.sendOutput(Color.RED, context, context.getString(R.string.rss_invalid_entry_tag) + Tuils.SPACE + (entryTag));
+            return false;
+        }
 
-        NodeList list = doc.getElementsByTagName("item");
         for(int c = list.getLength(); c >= 0; c--) {
-            Tuils.log("index: " + c);
 
             Element element = (Element) list.item(c);
             if(element == null) {
@@ -608,46 +733,60 @@ public class RssManager implements XMLPrefsManager.XmlPrefsElement {
             }
 
             if(time) {
-                Tuils.log("timing");
-                NodeList l = element.getElementsByTagName(PUBDATE_CHILD);
+                NodeList l = element.getElementsByTagName(dateTag);
                 if(l.getLength() == 0) continue;
 
+                foundOneDateAtLeast = true;
+
                 String date = l.item(0).getTextContent();
-                Date d = defaultRSSDateFormat.parse(date);
 
-                long timeLong = d.getTime();
-                if(c == 0) {
-                    feed.lastShownItem = d.getTime();
-                    feed.updateTime();
+                Date d;
+                try {
+                    d = feed.timeFormat != null ? feed.timeFormat.parse(date) : defaultRSSDateFormat.parse(date);
+                } catch (Exception e) {
+                    Tuils.sendOutput(Color.RED, context, rssFile.getName() + ": " + context.getString(R.string.rss_invalid_timeformat));
+                    return false;
                 }
 
-                Tuils.log("pubDate: " + timeLong);
-                Tuils.log("lastShown: " + lastShown);
+                long timeLong = d.getTime();
+                greatestTime = Math.max(greatestTime, timeLong);
 
-                if(lastShown < timeLong) {
+                if(feed.lastShownItem < timeLong) {
                     updated = true;
-
-                    Tuils.log("showing");
-                    showItem(feed, element);
+                    showItem(feed, element, false);
                 }
             } else {
+//                user - requested
                 updated = true;
-
-                Tuils.log("not timing");
-                showItem(feed, element);
+                showItem(feed, element, true);
             }
         }
 
+        if(time && !foundOneDateAtLeast) {
+            Tuils.sendOutput(Color.RED, context, context.getString(R.string.rss_invalid_date) + Tuils.SPACE + (dateTag));
+        } else if(greatestTime != -1) {
+            feed.lastShownItem = greatestTime;
+            feed.updateTime(rssIndexFile);
+        }
+
         return updated;
     }
 
-    private final Pattern formatPattern = Pattern.compile("%(?:\\[(\\d+)\\])?(?:\\[([^]]+)\\])?([^\\s]+)");
+    private final Pattern formatPattern = Pattern.compile("%(?:\\[(\\d+)\\])?(?:\\[([^]]+)\\])?([a-zA-Z]+)");
     private final Pattern removeTags = Pattern.compile("<[^>]+>");
     private final String THREE_DOTS = "...";
 
+    private final String OPEN_URL = "search -u ";
+    private final String PERCENTAGE = "%";
+
+    private Pattern nl = Pattern.compile("%n", Pattern.CASE_INSENSITIVE | Pattern.LITERAL);
+
 //    called when a new element is detected, it could be triggered many times again in some milliseconds
-    private void showItem(Rss feed, Element item) {
+    private void showItem(Rss feed, Element item, boolean userRequested) {
+        if(item == null) return;
+
         String cp = feed.format != null ? feed.format : defaultFormat;
+        cp = nl.matcher(cp).replaceAll(Tuils.NEWLINE);
 
         CharSequence s = Tuils.span(cp, feed.color);
 
@@ -665,19 +804,23 @@ public class RssManager implements XMLPrefsManager.XmlPrefsElement {
                 if(ls.getLength() == 0) value = Tuils.EMPTYSTRING;
                 else {
                     value = ls.item(0).getTextContent();
+                    if(value != null) value = value.trim();
+                    else value = Tuils.EMPTYSTRING;
 
-                    if(value.equals(PUBDATE_CHILD)) {
+                    if(feed.dateTag == null ? tag.equals(PUBDATE_CHILD) : (tag.equals(PUBDATE_CHILD) || tag.equals(feed.dateTag))) {
                         Date d;
                         try {
-                            d = defaultRSSDateFormat.parse(value);
+                            d = feed.timeFormat != null ? feed.timeFormat.parse(value) : defaultRSSDateFormat.parse(value);
                         } catch (ParseException e) {
+                            Tuils.log(e);
                             continue;
                         }
 
                         long timeLong = d.getTime();
                         value = TimeManager.replace(timeFormat, timeLong, Integer.MAX_VALUE).toString();
-
                     } else {
+                        value = HtmlEscape.unescapeHtml(value);
+
                         for(Pattern p : hideTagPatterns) {
                             value = p.matcher(value).replaceAll(Tuils.EMPTYSTRING);
                         }
@@ -689,7 +832,6 @@ public class RssManager implements XMLPrefsManager.XmlPrefsElement {
                             value = value.substring(0, l);
                             value = value.concat(THREE_DOTS);
                         } catch (Exception e) {}
-
                     }
 
                     try {
@@ -697,7 +839,6 @@ public class RssManager implements XMLPrefsManager.XmlPrefsElement {
                     } catch (Exception e) {
                         cl = feed.color;
                     }
-
                 }
 
                 CharSequence replace;
@@ -709,49 +850,143 @@ public class RssManager implements XMLPrefsManager.XmlPrefsElement {
 
                 s = TextUtils.replace(s, new String[] {m.group(0)}, new CharSequence[] {replace});
             }
-
         }
 
         if(includeRssDefault) {
-            if(feed.excludeIfMatches != null && feed.excludeIfMatches.length() > 0) {
-                Pattern p = Pattern.compile(feed.excludeIfMatches);
-                if (p.matcher(s.toString()).find()) {
-                    return;
-                }
-            }
+            if(feed.excludeIfMatches != null && feed.excludeIfMatches.matcher(s.toString()).find()) return;
         } else {
-            if(feed.includeIfMatches != null && feed.includeIfMatches.length() > 0) {
-                Pattern p = Pattern.compile(feed.includeIfMatches);
-                if (!p.matcher(s.toString()).find()) {
-                    return;
+            if(feed.includeIfMatches != null && feed.includeIfMatches.matcher(s.toString()).find()) return;
+        }
+
+        if(!userRequested) {
+            for(CmdableRegex r : cmdRegexes) {
+                if(r.regex == null || !Tuils.arrayContains(r.on, feed.id)) continue;
+
+                String cmd = r.cmd;
+
+                Matcher rssMatcher = r.regex.matcher(s.toString());
+                if(rssMatcher.matches() || rssMatcher.find()) {
+
+                    for(int c = 1; c < rssMatcher.groupCount() + 1; c++) {
+                        cmd = cmd.replaceAll(PERCENTAGE + c, rssMatcher.group(c));
+                    }
+
+                    Intent intent = new Intent(InputOutputReceiver.ACTION_CMD);
+                    intent.putExtra(InputOutputReceiver.SHOW_CONTENT, false);
+                    intent.putExtra(InputOutputReceiver.TEXT, cmd);
+                    context.sendBroadcast(intent);
                 }
             }
         }
 
-        Tuils.sendOutput(context, s);
+        String url = null;
+        NodeList list = item.getElementsByTagName(LINK_CHILD);
+        if(list.getLength() != 0) {
+            Node n = list.item(0);
+            url = n.getTextContent();
+
+            if(n.getNodeType() == Node.ELEMENT_NODE && (url == null || url.length() == 0)) {
+                url = ((Element) n).getAttribute(HREF_ATTRIBUTE);
+            }
+        }
+
+        String action;
+        if(url == null || url.length() == 0) action = null;
+        else action = OPEN_URL + url;
+
+        Tuils.sendOutput(context, s, TerminalManager.CATEGORY_RSS, click ? action : null);
     }
 
-    private class Rss {
-        String url;
-        long updateTimeSeconds, lastCheckedClient, lastShownItem;
-        int id;
-        boolean show;
-        String lMod, etag;
+    public static class Rss {
+        private static final String ID_LABEL = "ID", URL_LABEL = "URL", UPDATE_TIME_LABEL = "update time", SHOW_LABEL = "show";
+
+        public String url;
+        public long updateTimeSeconds, lastCheckedClient, lastShownItem;
+        public int id;
+        public boolean show;
+        public String lMod, etag;
+
+        public String entryTag, dateTag;
+
+        public String format;
 
-        String format;
-        String includeIfMatches, excludeIfMatches;
-        String updateCommand;
+        public Pattern includeIfMatches, excludeIfMatches;
+        public String tempInclude, tempExclude;
 
-        int color;
+        public int color;
 
-        boolean wifiOnly;
+        public long millisecondsLeft, lastUpdated;
+
+        public boolean wifiOnly;
+
+        public SimpleDateFormat timeFormat;
 
         public Rss(String url, long updateTimeSeconds, int id, boolean show) {
-            this(url, updateTimeSeconds, -1, -1, id, show, null, null, null, null, null, Integer.MAX_VALUE, false, null);
+            this(url, updateTimeSeconds, -1, -1, id, show, null, null, null, null, null, Integer.MAX_VALUE, false, null, null, null);
         }
 
         public Rss(String url, long updateTimeSeconds, long lastCheckedClient, long lastShownItem, int id, boolean show, String lMod, String etag, String format,
-                   String includeIfMatches, String excludeIfMatches, int color, boolean wifiOnly, String updateCommand) {
+                   String includeIfMatches, String excludeIfMatches, int color, boolean wifiOnly, String timeFormat, String rootNode, String timeNode) {
+            setAll(url, updateTimeSeconds, lastCheckedClient, lastShownItem, id, show, lMod, etag, format, includeIfMatches, excludeIfMatches, color, wifiOnly, timeFormat, rootNode, timeNode);
+
+            millisecondsLeft = updateTimeSeconds * 1000 - (System.currentTimeMillis() - lastCheckedClient);
+        }
+
+        public static Rss fromElement(Element t) {
+            int id;
+            try {
+                id = Integer.parseInt(t.getAttribute(ID_ATTRIBUTE));
+            } catch (Exception exc) {
+                return null;
+            }
+
+            String url = t.getAttribute(URL_ATTRIBUTE);
+            if(url == null) return null;
+
+            long updateTime;
+            try {
+                updateTime = Long.parseLong(t.getAttribute(TIME_ATTRIBUTE));
+            } catch (Exception e) {
+//                default: 1/2 h
+                updateTime = 60 * 30;
+            }
+
+            boolean show = true;
+            try {
+                show = Boolean.parseBoolean(t.getAttribute(SHOW_ATTRIBUTE));
+            } catch (Exception e) {}
+
+            long lastChecked = XMLPrefsManager.getLongAttribute(t, LASTCHECKED_ATTRIBUTE);
+            long lastShown = XMLPrefsManager.getLongAttribute(t, LAST_SHOWN_ITEM_ATTRIBUTE);
+            
+            String lastModified = XMLPrefsManager.getStringAttribute(t, LASTMODIFIED_ATTRIBUTE);
+            String etag = XMLPrefsManager.getStringAttribute(t, ETAG_ATTRIBUTE);
+
+            String format = XMLPrefsManager.getStringAttribute(t, FORMAT_ATTRIBUTE);
+            String includeIfMatches = XMLPrefsManager.getStringAttribute(t, INCLUDE_ATTRIBUTE);
+            String excludeIfMatches = XMLPrefsManager.getStringAttribute(t, EXCLUDE_ATTRIBUTE);
+            int color;
+            try {
+                color = Color.parseColor(t.getAttribute(COLOR_ATTRIBUTE));
+            } catch (Exception exc) {
+                color = Integer.MAX_VALUE;
+            }
+
+            boolean wifiOnly = false;
+            try {
+                wifiOnly = Boolean.parseBoolean(t.getAttribute(WIFIONLY_ATTRIBUTE));
+            } catch (Exception e) {}
+
+            String timeFormat = XMLPrefsManager.getStringAttribute(t, TIME_FORMAT_ATTRIBUTE);
+
+            String rootNode = XMLPrefsManager.getStringAttribute(t, ENTRY_TAG_ATTRIBUTE);
+            String timeNode = XMLPrefsManager.getStringAttribute(t, DATE_TAG_ATTRIBUTE);
+
+            return new Rss(url, updateTime, lastChecked, lastShown, id, show, lastModified, etag, format, includeIfMatches, excludeIfMatches, color, wifiOnly, timeFormat, rootNode, timeNode);
+        }
+
+        private void setAll(String url, long updateTimeSeconds, long lastCheckedClient, long lastShownItem, int id, boolean show, String lMod, String etag, String format,
+                            String includeIfMatches, String excludeIfMatches, int color, boolean wifiOnly, String timeFormat, String rootNode, String timeNode) {
             this.url = url;
             this.updateTimeSeconds = updateTimeSeconds;
             this.lastShownItem = lastShownItem;
@@ -762,48 +997,77 @@ public class RssManager implements XMLPrefsManager.XmlPrefsElement {
             this.etag = etag;
 
             this.format = format;
-            this.includeIfMatches = includeIfMatches;
-            this.excludeIfMatches = excludeIfMatches;
+
+            this.tempInclude = includeIfMatches;
+            this.tempExclude = excludeIfMatches;
 
             this.color = color;
 
             this.wifiOnly = wifiOnly;
 
-            this.updateCommand = updateCommand;
+            if(timeFormat == null) this.timeFormat = null;
+            else try {
+                this.timeFormat = new SimpleDateFormat(timeFormat);
+            } catch (Exception e) {
+                this.timeFormat = null;
+            }
+
+            this.entryTag = rootNode;
+            this.dateTag = timeNode;
         }
 
-        private void updateFile() {
-            XMLPrefsManager.set(rssFile, NAME, RSS_LABEL, new String[] {ID_ATTRIBUTE}, new String[] {String.valueOf(id)},
-                    new String[] {LASTCHECKED_ATTRIBUTE, LASTMODIFIED_ATTRIBUTE, ETAG_ATTRIBUTE}, new String[] {String.valueOf(lastCheckedClient), lMod, etag},
-                    false);
+        public boolean needUpdate() {
+            millisecondsLeft -= System.currentTimeMillis() - lastUpdated;
+
+            lastUpdated = System.currentTimeMillis();
+
+            if(millisecondsLeft <= 0) {
+                millisecondsLeft = updateTimeSeconds * 1000;
+
+                return true;
+            }
+
+            return false;
         }
 
-        @Override
-        public String toString() {
-            return new StringBuilder().append(ID_LABEL).append(id).append(SEPARATOR).append(TIME_LABEL).append(updateTimeSeconds).append(SEPARATOR).append(SHOW_LABEL).append(show).append(Tuils.NEWLINE)
-                    .append(URL_LABEL).append(url).toString();
+        public void updateTime(File rssFile) {
+            XMLPrefsManager.set(rssFile, RSS_LABEL, new String[] {ID_ATTRIBUTE}, new String[] {String.valueOf(id)}, new String[] {LAST_SHOWN_ITEM_ATTRIBUTE},
+                    new String[] {String.valueOf(lastShownItem)}, false);
         }
 
-        public void setFormat(String format) {
-            this.format = format;
-            updateFormat();
+        public void updateIncludeIfMatches() {
+            if(includeIfMatches != null) {
+                try {
+                    int id = Integer.parseInt(tempInclude);
+                    includeIfMatches = RegexManager.get(id).regex;
+                } catch (Exception exc) {
+                    includeIfMatches = Pattern.compile(tempInclude);
+                }
+            }
         }
 
-        public void setIncludeIfMatches(String includeIfMatches) {
-            this.includeIfMatches = includeIfMatches;
-            updateIncludeIfMatches();
+        public void updateExcludeIfMatches() {
+            if(excludeIfMatches != null) {
+                try {
+                    int id = Integer.parseInt(tempExclude);
+                    excludeIfMatches = RegexManager.get(id).regex;
+                } catch (Exception exc) {
+                    includeIfMatches = Pattern.compile(tempExclude);
+                }
+            }
         }
 
-        public void setExcludeIfMatches(String excludeIfMatches) {
-            this.excludeIfMatches = excludeIfMatches;
-            updateExcludeIfMatches();
+        private void updateFile(File rssFile) {
+            XMLPrefsManager.set(rssFile, RSS_LABEL, new String[] {ID_ATTRIBUTE}, new String[] {String.valueOf(id)},
+                    new String[] {LASTCHECKED_ATTRIBUTE, LASTMODIFIED_ATTRIBUTE, ETAG_ATTRIBUTE}, new String[] {String.valueOf(lastCheckedClient), lMod, etag},
+                    false);
         }
 
-        public void updateFormat() {
+        public void updateFormat(List<XMLPrefsManager.IdValue> formats) {
             if(format != null) {
                 try {
                     int id = Integer.parseInt(format);
-                    for(Format i : formats) {
+                    for(XMLPrefsManager.IdValue i : formats) {
                         if(id == i.id) format = i.value;
                     }
                 } catch (Exception exc) {
@@ -812,22 +1076,19 @@ public class RssManager implements XMLPrefsManager.XmlPrefsElement {
             }
         }
 
-        public void updateIncludeIfMatches() {
-            if(includeIfMatches != null) {
-                try {
-                    int id = Integer.parseInt(includeIfMatches);
-                    includeIfMatches = RegexManager.get(id).value;
-                } catch (Exception exc) {}
-            }
+        public void setFormat(List<XMLPrefsManager.IdValue> formats, String format) {
+            this.format = format;
+            updateFormat(formats);
         }
 
-        public void updateExcludeIfMatches() {
-            if(excludeIfMatches != null) {
-                try {
-                    int id = Integer.parseInt(excludeIfMatches);
-                    excludeIfMatches = RegexManager.get(id).value;
-                } catch (Exception exc) {}
-            }
+        public void setIncludeIfMatches(String includeIfMatches) {
+            tempInclude = includeIfMatches;
+            updateIncludeIfMatches();
+        }
+
+        public void setExcludeIfMatches(String excludeIfMatches) {
+            tempExclude = excludeIfMatches;
+            updateExcludeIfMatches();
         }
 
         @Override
@@ -837,19 +1098,14 @@ public class RssManager implements XMLPrefsManager.XmlPrefsElement {
             return false;
         }
 
-        public void updateTime() {
-            Tuils.log("updating time: " + XMLPrefsManager.set(rssFile, NAME, RSS_LABEL, new String[] {ID_ATTRIBUTE}, new String[] {String.valueOf(id)}, new String[] {LAST_SHOWN_ITEM_ATTRIBUTE},
-                    new String[] {String.valueOf(lastShownItem)}, false));
-        }
-    }
-
-    private static class Format {
-        String value;
-        int id;
-
-        public Format(String value, int id) {
-            this.value = value;
-            this.id = id;
+        @Override
+        public String toString() {
+            String dots = ":";
+            return new StringBuilder().append(ID_LABEL).append(dots).append(Tuils.SPACE).append(id).append(Tuils.SPACE)
+                    .append(URL_LABEL).append(dots).append(Tuils.SPACE).append(url).append(Tuils.SPACE)
+                    .append(UPDATE_TIME_LABEL).append(dots).append(Tuils.SPACE).append(updateTimeSeconds).append(Tuils.SPACE)
+                    .append(SHOW_LABEL).append(dots).append(Tuils.SPACE).append(show)
+                    .toString();
         }
     }
 
@@ -863,7 +1119,7 @@ public class RssManager implements XMLPrefsManager.XmlPrefsElement {
         }
     }
 
-    private Rss findId(int id) {
+    public Rss findId(int id) {
         for(int c = 0; c < feeds.size(); c++) {
             Rss r = feeds.get(c);
             if(r.id == id) {
@@ -880,10 +1136,10 @@ public class RssManager implements XMLPrefsManager.XmlPrefsElement {
             check = false;
             root.mkdir();
         }
-        if(!rssFile.exists()) {
+        if(!rssIndexFile.exists()) {
             try {
-                rssFile.createNewFile();
-                XMLPrefsManager.resetFile(rssFile, NAME);
+                rssIndexFile.createNewFile();
+                XMLPrefsManager.resetFile(rssIndexFile, NAME);
                 check = false;
 
                 return check && root.list().length > 1;
@@ -894,4 +1150,45 @@ public class RssManager implements XMLPrefsManager.XmlPrefsElement {
 
         return check;
     }
+
+    private class CmdableRegex extends RegexManager.Regex {
+        int[] on;
+        String cmd;
+
+        public CmdableRegex(int id, String on, String regex, String cmd) {
+            this.id = id;
+
+            this.literalPattern = regex;
+            this.cmd = cmd;
+
+            char separator = Tuils.firstNonDigit(on);
+            if(separator == 0) {
+                try {
+                    this.on = new int[] {Integer.parseInt(on)};
+                } catch (Exception e) {
+                    Tuils.log(e);
+                }
+            } else {
+                if(separator == ' ') {
+                    char s2 = Tuils.firstNonDigit(Tuils.removeSpaces(on));
+                    if(s2 != 0) {
+                        on = Tuils.removeSpaces(on);
+                        separator = s2;
+                    }
+                }
+
+                String[] split = on.split(Pattern.quote(separator + Tuils.EMPTYSTRING));
+                this.on = new int[split.length];
+
+                for(int c = 0; c < split.length; c++) {
+                    try {
+                        this.on[c] = Integer.parseInt(split[c]);
+                    } catch (Exception e) {
+                        Tuils.log(e);
+                        this.on[c] = Integer.MAX_VALUE;
+                    }
+                }
+            }
+        }
+    }
 }
diff --git a/app/src/main/java/ohi/andre/consolelauncher/managers/TerminalManager.java b/app/src/main/java/ohi/andre/consolelauncher/managers/TerminalManager.java
index 86025ad..ae96775 100644
--- a/app/src/main/java/ohi/andre/consolelauncher/managers/TerminalManager.java
+++ b/app/src/main/java/ohi/andre/consolelauncher/managers/TerminalManager.java
@@ -2,14 +2,15 @@ package ohi.andre.consolelauncher.managers;
 
 import android.app.Activity;
 import android.content.Context;
+import android.content.Intent;
+import android.graphics.Color;
 import android.os.IBinder;
-import android.text.InputFilter;
 import android.text.InputType;
 import android.text.Layout;
+import android.text.Spannable;
 import android.text.SpannableString;
 import android.text.Spanned;
 import android.text.TextUtils;
-import android.text.method.ScrollingMovementMethod;
 import android.text.style.ForegroundColorSpan;
 import android.view.KeyEvent;
 import android.view.View;
@@ -26,11 +27,14 @@ import java.util.List;
 import ohi.andre.consolelauncher.UIManager;
 import ohi.andre.consolelauncher.commands.main.MainPack;
 import ohi.andre.consolelauncher.commands.main.raw.clear;
+import ohi.andre.consolelauncher.managers.notifications.KeeperService;
 import ohi.andre.consolelauncher.managers.xml.XMLPrefsManager;
 import ohi.andre.consolelauncher.managers.xml.options.Behavior;
 import ohi.andre.consolelauncher.managers.xml.options.Theme;
 import ohi.andre.consolelauncher.managers.xml.options.Ui;
-import ohi.andre.consolelauncher.tuils.TimeManager;
+import ohi.andre.consolelauncher.tuils.InputOutputReceiver;
+import ohi.andre.consolelauncher.tuils.LongClickMovementMethod;
+import ohi.andre.consolelauncher.tuils.LongClickableSpan;
 import ohi.andre.consolelauncher.tuils.Tuils;
 import ohi.andre.consolelauncher.tuils.interfaces.Rooter;
 
@@ -56,7 +60,6 @@ public class TerminalManager {
     public static final int CATEGORY_INPUT = 10;
     public static final int CATEGORY_OUTPUT = 11;
     public static final int CATEGORY_NOTIFICATION = 12;
-    public static final int CATEGORY_GENERAL = 13;
     public static final int CATEGORY_RSS = 14;
 
     private long lastEnter;
@@ -89,7 +92,7 @@ public class TerminalManager {
 
     private MainPack mainPack;
 
-    private boolean defaultHint = true, autoLowerFirstChar;
+    private boolean defaultHint = true;
 
     private int clearCmdsCount= 0;
 
@@ -103,8 +106,10 @@ public class TerminalManager {
         }
     };
 
-    private String inputFormat;
-    private String outputFormat;
+    private String inputFormat, outputFormat;
+    private int inputColor, outputColor;
+
+    private boolean keeperServiceRunning, clickCommands, longClickCommands;
 
     private Context mContext;
 
@@ -117,7 +122,8 @@ public class TerminalManager {
 
         this.mainPack = mainPack;
 
-        this.autoLowerFirstChar = XMLPrefsManager.getBoolean(Behavior.autolower_firstchar);
+        this.clickCommands = XMLPrefsManager.getBoolean(Behavior.click_commands);
+        this.longClickCommands = XMLPrefsManager.getBoolean(Behavior.long_click_commands);
 
         this.clearAfterMs = XMLPrefsManager.getInt(Behavior.clear_after_seconds) * 1000;
         this.clearAfterCmds = XMLPrefsManager.getInt(Behavior.clear_after_cmds);
@@ -126,11 +132,16 @@ public class TerminalManager {
         inputFormat = XMLPrefsManager.get(Behavior.input_format);
         outputFormat = XMLPrefsManager.get(Behavior.output_format);
 
+        inputColor = XMLPrefsManager.getColor(Theme.input_color);
+        outputColor = XMLPrefsManager.getColor(Theme.output_color);
+
         prefix = XMLPrefsManager.get(Ui.input_prefix);
         suPrefix = XMLPrefsManager.get(Ui.input_root_prefix);
 
         int ioSize = XMLPrefsManager.getInt(Ui.input_output_size);
 
+        keeperServiceRunning = XMLPrefsManager.getBoolean(Behavior.tui_notification);
+
         prefixView.setTypeface(Tuils.getTypeface(context));
         prefixView.setTextColor(XMLPrefsManager.getColor(Theme.input_color));
         prefixView.setTextSize(ioSize);
@@ -195,7 +206,7 @@ public class TerminalManager {
         this.mTerminalView.setTypeface(Tuils.getTypeface(context));
         this.mTerminalView.setTextSize(ioSize);
         this.mTerminalView.setFocusable(false);
-        setupScroller();
+        this.mTerminalView.setMovementMethod(LongClickMovementMethod.getInstance(XMLPrefsManager.getInt(Behavior.long_click_duration)));
 
         if(clearAfterMs > 0) this.mTerminalView.postDelayed(clearRunnable, clearAfterMs);
         if(maxLines > 0) {
@@ -240,6 +251,8 @@ public class TerminalManager {
         this.mInputView.setTypeface(Tuils.getTypeface(context));
         this.mInputView.setHint(Tuils.getHint(mainPack.currentDirectory.getAbsolutePath()));
         this.mInputView.setInputType(InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS);
+        Tuils.setCursorDrawableColor(this.mInputView, XMLPrefsManager.getColor(Theme.cursor_color));
+        this.mInputView.setHighlightColor(Color.TRANSPARENT);
         this.mInputView.setOnEditorActionListener(new TextView.OnEditorActionListener() {
 
             @Override
@@ -263,26 +276,24 @@ public class TerminalManager {
                     onNewInput();
                 }
 
-//                if(event == null && actionId == EditorInfo.IME_NULL) onNewInput();
+//                if (event == null && actionId == EditorInfo.IME_NULL) onNewInput();
 //                if (event != null && event.getAction() == KeyEvent.ACTION_DOWN && event.getKeyCode() == KeyEvent.KEYCODE_ENTER) onNewInput();
 
                 return true;
             }
         });
-        if(autoLowerFirstChar) {
-            this.mInputView.setFilters(new InputFilter[] {new InputFilter() {
-                @Override
-                public CharSequence filter(CharSequence source, int start, int end, Spanned dest, int dstart, int dend) {
-                    if (dstart == 0 && dend == 0 && start == 0 && end == 1) {
-                        if(source.length() > 0) {
-                            return TextUtils.concat(source.toString().toLowerCase().charAt(0) + Tuils.EMPTYSTRING, source.subSequence(1,source.length()));
-                        }
-                    }
-
-                    return source;
-                }
-            }});
-        }
+//        if(autoLowerFirstChar) {
+//            this.mInputView.setFilters(new InputFilter[] {new InputFilter() {
+//                @Override
+//                public CharSequence filter(CharSequence source, int start, int end, Spanned dest, int dstart, int dend) {
+//                    if (dstart == 0 && dend == 0 && start == 0 && end == 1 && source.length() > 0) {
+//                        return TextUtils.concat(source.toString().toLowerCase().charAt(0) + Tuils.EMPTYSTRING, source.subSequence(1,source.length()));
+//                    }
+//
+//                    return source;
+//                }
+//            }});
+//        }
     }
 
     private void setupNewInput() {
@@ -300,7 +311,15 @@ public class TerminalManager {
             return false;
         }
 
-        String input = mInputView.getText().toString().trim();
+        CharSequence input = mInputView.getText();
+
+        String cmd = input.toString().trim();
+        Object obj = null;
+        try {
+            obj = ((Spannable) input).getSpans(0, input.length(), AppsManager.LaunchInfo.class)[0];
+        } catch (Exception e) {
+//            an error will probably be thrown everytime, but we don't need to track it
+        }
 
         if(input.length() > 0) {
             clearCmdsCount++;
@@ -314,13 +333,13 @@ public class TerminalManager {
             if(cmdList.size() == CMD_LIST_SIZE) {
                 cmdList.remove(0);
             }
-            cmdList.add(cmdList.size(), input);
+            cmdList.add(cmdList.size(), cmd);
             howBack = -1;
         }
 
-
+//        I tried to use intents and ioreceiver.class instead, but it wasn't better
         if (mInputListener != null) {
-            mInputListener.onNewInput(input);
+            mInputListener.onNewInput(cmd, obj);
         }
 
         setupNewInput();
@@ -387,12 +406,19 @@ public class TerminalManager {
         }
     }
 
-    final String FORMAT_INPUT = "%i";
-    final String FORMAT_OUTPUT = "%o";
-    final String FORMAT_PREFIX = "%p";
-    final String FORMAT_NEWLINE = "%n";
+    public static final String FORMAT_INPUT = "%i";
+    public static final String FORMAT_OUTPUT = "%o";
+    public static final String FORMAT_PREFIX = "%p";
+    public static final String FORMAT_NEWLINE = "%n";
 
     private void writeToView(CharSequence text, int type) {
+        if(type == CATEGORY_INPUT && keeperServiceRunning) {
+            Intent i = new Intent(mContext, KeeperService.class);
+            i.putExtra(KeeperService.CMD_KEY, text.toString());
+            i.putExtra(KeeperService.PATH_KEY, mainPack.currentDirectory.getAbsolutePath());
+            mContext.startService(i);
+        }
+
         text = getFinalText(text, type);
         text = TextUtils.concat(Tuils.NEWLINE, text);
         writeToView(text);
@@ -416,26 +442,28 @@ public class TerminalManager {
 
                 boolean su = t.toString().startsWith("su ") || suMode;
 
-                SpannableString si = Tuils.span(inputFormat, XMLPrefsManager.getColor(Theme.input_color));
+                SpannableString si = Tuils.span(inputFormat, inputColor);
+                if(clickCommands || longClickCommands) si.setSpan(new LongClickableSpan(clickCommands ? t.toString() : null, longClickCommands ? t.toString() : null, InputOutputReceiver.ACTION_INPUT), 0,
+                        si.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
 
                 s = TimeManager.replace(si,XMLPrefsManager.getColor(Theme.time_color));
                 s = TextUtils.replace(s,
-                        new String[] {FORMAT_INPUT, FORMAT_PREFIX, FORMAT_NEWLINE,
-                                FORMAT_INPUT.toUpperCase(), FORMAT_PREFIX.toUpperCase(), FORMAT_NEWLINE.toUpperCase()},
+                        new String[] {FORMAT_INPUT, FORMAT_PREFIX, FORMAT_NEWLINE, FORMAT_INPUT.toUpperCase(), FORMAT_PREFIX.toUpperCase(), FORMAT_NEWLINE.toUpperCase()},
                         new CharSequence[] {t, su ? suPrefix : prefix, Tuils.NEWLINE, t, su ? suPrefix : prefix, Tuils.NEWLINE});
 
                 break;
             case CATEGORY_OUTPUT:
                 t = t.toString().trim();
 
-                SpannableString so = Tuils.span(outputFormat, XMLPrefsManager.getColor(Theme.output_color));
+                SpannableString so = Tuils.span(outputFormat, outputColor);
 
                 s = TextUtils.replace(so,
                         new String[] {FORMAT_OUTPUT, FORMAT_NEWLINE, FORMAT_OUTPUT.toUpperCase(), FORMAT_NEWLINE.toUpperCase()},
                         new CharSequence[] {t, Tuils.NEWLINE, t, Tuils.NEWLINE});
 
                 break;
-            case CATEGORY_NOTIFICATION: case CATEGORY_GENERAL:case CATEGORY_RSS:
+//            already colored here
+            case CATEGORY_NOTIFICATION:case CATEGORY_RSS:
                 s = t;
                 break;
             default:
@@ -449,19 +477,24 @@ public class TerminalManager {
         onNewInput();
     }
 
-    public void setupScroller() {
-        this.mTerminalView.setMovementMethod(new ScrollingMovementMethod());
-    }
-
     public String getInput() {
         return mInputView.getText().toString();
     }
 
-    public void setInput(String input) {
-        mInputView.setText(input);
+    public void setInput(String input, Object obj) {
+        SpannableString spannable = new SpannableString(input);
+        if(obj != null) {
+            spannable.setSpan(obj, 0, input.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
+        }
+
+        mInputView.setText(spannable);
         focusInputEnd();
     }
 
+    public void setInput(String input) {
+        setInput(input, null);
+    }
+
     public void setHint(String hint) {
         defaultHint = false;
 
diff --git a/app/src/main/java/ohi/andre/consolelauncher/managers/ThemesManager.java b/app/src/main/java/ohi/andre/consolelauncher/managers/ThemesManager.java
index 63f3223..95a4ed5 100644
--- a/app/src/main/java/ohi/andre/consolelauncher/managers/ThemesManager.java
+++ b/app/src/main/java/ohi/andre/consolelauncher/managers/ThemesManager.java
@@ -140,6 +140,8 @@ public class ThemesManager {
                 return;
             }
 
+            if(o == null) return;
+
             Document d = (Document) o[0];
             Element root = (Element) o[1];
 
diff --git a/app/src/main/java/ohi/andre/consolelauncher/tuils/TimeManager.java b/app/src/main/java/ohi/andre/consolelauncher/managers/TimeManager.java
similarity index 68%
rename from app/src/main/java/ohi/andre/consolelauncher/tuils/TimeManager.java
rename to app/src/main/java/ohi/andre/consolelauncher/managers/TimeManager.java
index 8541399..22addaa 100644
--- a/app/src/main/java/ohi/andre/consolelauncher/tuils/TimeManager.java
+++ b/app/src/main/java/ohi/andre/consolelauncher/managers/TimeManager.java
@@ -1,19 +1,20 @@
-package ohi.andre.consolelauncher.tuils;
+package ohi.andre.consolelauncher.managers;
 
 import android.content.Context;
 import android.text.SpannableString;
 import android.text.Spanned;
 import android.text.TextUtils;
-import android.text.format.Time;
 import android.text.style.AbsoluteSizeSpan;
 import android.text.style.ForegroundColorSpan;
 
-import java.util.Arrays;
+import java.text.SimpleDateFormat;
+import java.util.Date;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
 import ohi.andre.consolelauncher.managers.xml.XMLPrefsManager;
 import ohi.andre.consolelauncher.managers.xml.options.Behavior;
+import ohi.andre.consolelauncher.tuils.Tuils;
 
 /**
  * Created by francescoandreuzzi on 26/07/2017.
@@ -21,28 +22,34 @@ import ohi.andre.consolelauncher.managers.xml.options.Behavior;
 
 public class TimeManager {
 
-    static String[] formats;
-    static Time time;
+    static SimpleDateFormat[] dateFormatList;
 
     static Pattern extractor = Pattern.compile("%t([0-9]+)", Pattern.CASE_INSENSITIVE);
 
     public static void create() {
+        final Pattern NEWLINE_PATTERN = Pattern.compile("%n");
+
         String format = XMLPrefsManager.get(Behavior.time_format);
         String separator = XMLPrefsManager.get(Behavior.time_format_separator);
 
-        time = new Time();
-
-        formats = format.split(separator);
-        if(formats.length == 0) formats = new String[] {Tuils.EMPTYSTRING};
+        String[] formats = format.split(separator);
+        dateFormatList = new SimpleDateFormat[formats.length];
 
-        Arrays.asList(formats);
+        for(int c = 0; c < dateFormatList.length; c++) {
+            try {
+                formats[c] = NEWLINE_PATTERN.matcher(formats[c]).replaceAll(Tuils.NEWLINE);
+                dateFormatList[c] = new SimpleDateFormat(formats[c]);
+            } catch (Exception e) {
+                dateFormatList[c] = dateFormatList[0];
+            }
+        }
     }
 
-    public static String get(int index) {
-        if(formats == null) return null;
+    private static SimpleDateFormat get(int index) {
+        if(index < 0 || index >= dateFormatList.length) index = 0;
+        if(index == 0 && dateFormatList.length == 0) return null;
 
-        if(index < 0 || index >= formats.length) index = 0;
-        return formats[index];
+        return dateFormatList[index];
     }
 
     public static CharSequence replace(CharSequence cs) {
@@ -63,18 +70,18 @@ public class TimeManager {
 
     public static CharSequence replace(Context context, int size, CharSequence cs, long tm, int color) {
         if(tm == -1) {
-            time.setToNow();
-        } else {
-            time.set(tm);
+            tm = System.currentTimeMillis();
         }
 
+        Date date = new Date(tm);
+
         Matcher matcher = extractor.matcher(cs.toString());
         if(matcher.find()) {
             for(int count = 1; count <= matcher.groupCount(); count++) {
-                String t = get(Integer.parseInt(matcher.group(count)));
-                if(t == null) continue;
+                SimpleDateFormat formatter = get(Integer.parseInt(matcher.group(count)));
+                if(formatter == null) return cs;
 
-                String tf = time.format(t);
+                String tf = formatter.format(date);
 
                 SpannableString spannableString = new SpannableString(tf);
                 if(color != Integer.MAX_VALUE) {
@@ -89,10 +96,10 @@ public class TimeManager {
             }
         }
 
-        String t = get(0);
-        if(t == null) return cs;
+        SimpleDateFormat formatter = get(0);
+        if(formatter == null) return cs;
 
-        String tf = time.format(t);
+        String tf = formatter.format(date);
 
         SpannableString spannableString = new SpannableString(tf);
         if(color != Integer.MAX_VALUE) {
diff --git a/app/src/main/java/ohi/andre/consolelauncher/managers/music/MusicManager2.java b/app/src/main/java/ohi/andre/consolelauncher/managers/music/MusicManager2.java
index ff93472..95bfdcc 100644
--- a/app/src/main/java/ohi/andre/consolelauncher/managers/music/MusicManager2.java
+++ b/app/src/main/java/ohi/andre/consolelauncher/managers/music/MusicManager2.java
@@ -18,6 +18,7 @@ import java.util.List;
 
 import ohi.andre.consolelauncher.managers.xml.XMLPrefsManager;
 import ohi.andre.consolelauncher.managers.xml.options.Behavior;
+import ohi.andre.consolelauncher.tuils.StoppableThread;
 import ohi.andre.consolelauncher.tuils.Tuils;
 
 /**
@@ -146,7 +147,7 @@ public class MusicManager2 implements MediaController.MediaPlayerControl {
     }
 
     public void updateSongs() {
-        loader = new Thread() {
+        loader = new StoppableThread() {
             @Override
             public void run() {
                 try {
diff --git a/app/src/main/java/ohi/andre/consolelauncher/managers/notifications/KeeperService.java b/app/src/main/java/ohi/andre/consolelauncher/managers/notifications/KeeperService.java
new file mode 100755
index 0000000..350a57d
--- /dev/null
+++ b/app/src/main/java/ohi/andre/consolelauncher/managers/notifications/KeeperService.java
@@ -0,0 +1,220 @@
+package ohi.andre.consolelauncher.managers.notifications;
+
+import android.app.Notification;
+import android.app.PendingIntent;
+import android.app.Service;
+import android.content.Context;
+import android.content.Intent;
+import android.os.Build;
+import android.os.IBinder;
+import android.support.v4.app.NotificationCompat;
+import android.support.v4.app.NotificationManagerCompat;
+import android.support.v4.app.RemoteInput;
+import android.text.SpannableString;
+import android.text.TextUtils;
+
+import ohi.andre.consolelauncher.R;
+import ohi.andre.consolelauncher.managers.TimeManager;
+import ohi.andre.consolelauncher.managers.xml.XMLPrefsManager;
+import ohi.andre.consolelauncher.managers.xml.options.Behavior;
+import ohi.andre.consolelauncher.managers.xml.options.Theme;
+import ohi.andre.consolelauncher.managers.xml.options.Ui;
+import ohi.andre.consolelauncher.tuils.InputOutputReceiver;
+import ohi.andre.consolelauncher.tuils.Tuils;
+
+import static ohi.andre.consolelauncher.managers.TerminalManager.FORMAT_INPUT;
+import static ohi.andre.consolelauncher.managers.TerminalManager.FORMAT_NEWLINE;
+import static ohi.andre.consolelauncher.managers.TerminalManager.FORMAT_PREFIX;
+
+public class KeeperService extends Service {
+
+//    private final String PATH = "reply.xml";
+//    public static final String BIND_NODE = "binding", ID_ATTRIBUTE = "id", APP_ATTRIBUTE = "pkg";
+
+    public static final int ONGOING_NOTIFICATION_ID = 1001;
+    public static final String CMD_KEY = "cmd", PATH_KEY = "path";
+
+    private String title, subtitle, clickCmd, inputFormat, prefix, suPrefix;
+    private boolean showHome, upDown;
+    private int inputColor, timeColor, priority;
+
+    private CharSequence[] lastCommands = null;
+
+    @Override
+    public IBinder onBind(Intent intent) {
+        return null;
+    }
+
+    @Override
+    public int onStartCommand(Intent intent, int flags, int startId) {
+        if(startId == 1 || startId == 0) {
+            title = XMLPrefsManager.get(Behavior.tui_notification_title);
+            subtitle = XMLPrefsManager.get(Behavior.tui_notification_subtitle);
+            clickCmd = XMLPrefsManager.get(Behavior.tui_notification_click_cmd);
+            inputFormat = XMLPrefsManager.get(Behavior.input_format);
+            showHome = XMLPrefsManager.getBoolean(Behavior.tui_notification_click_showhome);
+            inputColor = XMLPrefsManager.getColor(Theme.input_color);
+            timeColor = XMLPrefsManager.getColor(Theme.time_color);
+            prefix = XMLPrefsManager.get(Ui.input_prefix);
+            upDown = XMLPrefsManager.getBoolean(Behavior.tui_notification_lastcmds_updown);
+            suPrefix = XMLPrefsManager.get(Ui.input_root_prefix);
+
+            priority = XMLPrefsManager.getInt(Behavior.tui_notification_priority);
+            if(priority > 2) priority = 2;
+            if(priority < -2) priority = -2;
+
+            String path = intent.getStringExtra(PATH_KEY);
+
+            startForeground(ONGOING_NOTIFICATION_ID, buildNotification(getApplicationContext(), title, subtitle, Tuils.getHint(path),
+                    clickCmd, showHome, lastCommands, upDown, priority));
+
+            int lastCmdSize = XMLPrefsManager.getInt(Behavior.tui_notification_lastcmds_size);
+            if(lastCmdSize > 0) {
+                lastCommands = new CharSequence[lastCmdSize];
+            }
+
+
+        } else {
+//            new cmd
+//            update the list
+
+            if(lastCommands != null) updateCmds(intent.getStringExtra(CMD_KEY));
+
+            String path = intent.getStringExtra(PATH_KEY);
+
+            NotificationManagerCompat.from(getApplicationContext()).notify(KeeperService.ONGOING_NOTIFICATION_ID,
+                    KeeperService.buildNotification(getApplicationContext(), title, subtitle, Tuils.getHint(path),
+                            clickCmd, showHome, lastCommands, upDown, priority));
+        }
+
+        return super.onStartCommand(intent, flags, startId);
+    }
+
+//    0 = most recent
+//    4 = oldest
+
+//    * = null
+//    3 cases
+//    1: |*|*|*|*|*| -> lastNull = 0
+//    2: |a|b|c|*|*| -> lastNull = n < length
+//    3: |a|b|c|d|e| -> lastNull = -1
+    private void updateCmds(String cmd) {
+        try {
+            int lastNull = lastNull();
+            int toCopy = lastNull == -1 ? lastCommands.length - 1 : lastNull;
+            System.arraycopy(lastCommands, 0, lastCommands, 1, toCopy);
+            lastCommands[0] = formatInput(cmd, inputFormat, prefix, suPrefix, inputColor, timeColor);
+        } catch (Exception e) {
+            Tuils.log(e);
+        }
+    }
+
+    private static CharSequence formatInput(String cmd, String inputFormat, String prefix, String suPrefix, int inputColor, int timeColor) {
+        if(cmd == null) return null;
+        boolean su = cmd.startsWith("su ");
+
+        SpannableString si = Tuils.span(inputFormat, inputColor);
+
+        CharSequence s = TimeManager.replace(si, timeColor);
+        s = TextUtils.replace(s,
+                new String[] {FORMAT_INPUT, FORMAT_PREFIX, FORMAT_NEWLINE, FORMAT_INPUT.toUpperCase(), FORMAT_PREFIX.toUpperCase(), FORMAT_NEWLINE.toUpperCase()},
+                new CharSequence[] {cmd, su ? suPrefix : prefix, Tuils.NEWLINE, cmd, su ? suPrefix : prefix, Tuils.NEWLINE});
+
+        return s;
+    }
+
+    private int lastNull() {
+        for(int c = 0; c < lastCommands.length; c++) if(lastCommands[c] == null) return c;
+        return -1;
+    }
+
+    @Override
+    public boolean onUnbind(Intent intent) {
+        return true;
+    }
+
+    private static Notification buildNotification(Context c, String title, String subtitle, String cmdLabel, String clickCmd, boolean showHome, CharSequence[] lastCommands, boolean upDown, int priority) {
+
+        PendingIntent pendingIntent;
+        if(showHome) {
+            Intent startMain = new Intent(Intent.ACTION_MAIN);
+            startMain.addCategory(Intent.CATEGORY_HOME);
+            startMain.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+
+            if(clickCmd != null && clickCmd.length() > 0) {
+                startMain.putExtra(InputOutputReceiver.TEXT, clickCmd);
+            }
+
+            pendingIntent = PendingIntent.getActivity(
+                    c,
+                    0,
+                    startMain,
+                    PendingIntent.FLAG_CANCEL_CURRENT
+            );
+        } else if(clickCmd != null && clickCmd.length() > 0) {
+            Intent cmdIntent = new Intent(InputOutputReceiver.ACTION_CMD);
+            cmdIntent.putExtra(InputOutputReceiver.TEXT, clickCmd);
+            cmdIntent.putExtra(InputOutputReceiver.SHOW_CONTENT, true);
+
+            pendingIntent = PendingIntent.getBroadcast(
+                    c,
+                    0,
+                    cmdIntent,
+                    0
+            );
+        } else {
+            pendingIntent = null;
+        }
+
+        NotificationCompat.Style style = null;
+        if(lastCommands != null && lastCommands[0] != null) {
+            NotificationCompat.InboxStyle inboxStyle = new NotificationCompat.InboxStyle();
+
+            if(upDown) {
+                for (CharSequence lastCommand : lastCommands) {
+                    if (lastCommand == null) break;
+                    inboxStyle.addLine(lastCommand);
+                }
+            } else {
+                for(int j = lastCommands.length - 1; j >= 0; j--) {
+                    if(lastCommands[j] == null) continue;
+                    inboxStyle.addLine(lastCommands[j]);
+                }
+            }
+
+            style = inboxStyle;
+        }
+
+        NotificationCompat.Builder builder = new NotificationCompat.Builder(c)
+                .setSmallIcon(R.mipmap.ic_launcher)
+                .setTicker(c.getString(R.string.start_notification))
+                .setWhen(System.currentTimeMillis())
+                .setPriority(priority)
+                .setContentTitle(title)
+                .setContentIntent(pendingIntent);
+
+        if(style != null) builder.setStyle(style);
+        else {
+            builder.setContentTitle(title);
+            builder.setContentText(subtitle);
+        }
+
+        if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
+            RemoteInput remoteInput = new RemoteInput.Builder(InputOutputReceiver.TEXT)
+                    .setLabel(cmdLabel)
+                    .build();
+
+            Intent i = new Intent(InputOutputReceiver.ACTION_CMD);
+            i.putExtra(InputOutputReceiver.WAS_KEY, InputOutputReceiver.WAS_KEEPER_SERVICE);
+
+            NotificationCompat.Action action = new NotificationCompat.Action.Builder(R.mipmap.ic_launcher, cmdLabel,
+                    PendingIntent.getBroadcast(c.getApplicationContext(), 40, i, PendingIntent.FLAG_UPDATE_CURRENT))
+                    .addRemoteInput(remoteInput)
+                    .build();
+
+            builder.addAction(action);
+        }
+
+        return builder.build();
+    }
+}
diff --git a/app/src/main/java/ohi/andre/consolelauncher/managers/notifications/NotificationManager.java b/app/src/main/java/ohi/andre/consolelauncher/managers/notifications/NotificationManager.java
index 7d09624..0ad120e 100755
--- a/app/src/main/java/ohi/andre/consolelauncher/managers/notifications/NotificationManager.java
+++ b/app/src/main/java/ohi/andre/consolelauncher/managers/notifications/NotificationManager.java
@@ -2,9 +2,7 @@ package ohi.andre.consolelauncher.managers.notifications;
 
 import android.annotation.TargetApi;
 import android.content.Context;
-import android.graphics.Color;
 import android.os.Build;
-import android.util.SparseArray;
 
 import org.w3c.dom.Document;
 import org.w3c.dom.Element;
@@ -14,11 +12,11 @@ import org.w3c.dom.NodeList;
 import java.io.File;
 import java.util.ArrayList;
 import java.util.Arrays;
-import java.util.Collections;
 import java.util.List;
+import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
-import ohi.andre.consolelauncher.R;
+import ohi.andre.consolelauncher.managers.RegexManager;
 import ohi.andre.consolelauncher.managers.xml.XMLPrefsManager;
 import ohi.andre.consolelauncher.managers.xml.options.Notifications;
 import ohi.andre.consolelauncher.tuils.Tuils;
@@ -26,7 +24,6 @@ import ohi.andre.consolelauncher.tuils.Tuils;
 import static ohi.andre.consolelauncher.managers.xml.XMLPrefsManager.VALUE_ATTRIBUTE;
 import static ohi.andre.consolelauncher.managers.xml.XMLPrefsManager.resetFile;
 import static ohi.andre.consolelauncher.managers.xml.XMLPrefsManager.set;
-import static ohi.andre.consolelauncher.managers.xml.XMLPrefsManager.setMany;
 import static ohi.andre.consolelauncher.managers.xml.XMLPrefsManager.writeTo;
 
 /**
@@ -36,17 +33,7 @@ import static ohi.andre.consolelauncher.managers.xml.XMLPrefsManager.writeTo;
 @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR2)
 public class NotificationManager implements XMLPrefsManager.XmlPrefsElement {
 
-    private static int TITLE = 10;
-    private static int TEXT = 11;
-
-    private static final String COLOR_ATTRIBUTE = "color";
-    private static final String ENABLED_ATTRIBUTE = "enabled";
-    private static final String ID_ATTRIBUTE = "id";
-    private static final String ON_ATTRIBUTE = "on";
-    private static final String PACKAGE_ATTRIBUTE = "package";
-
-    private static final String FILTER_NODE = "filter";
-    private static final String APPLY_NODE = "apply";
+    private static final String COLOR_ATTRIBUTE = "color", ENABLED_ATTRIBUTE = "enabled", ID_ATTRIBUTE = "id", FORMAT_ATTRIBUTE = "format", FILTER_ATTRIBUTE = "filter";
 
     public static final String PATH = "notifications.xml";
     private static final String NAME = "NOTIFICATIONS";
@@ -68,13 +55,13 @@ public class NotificationManager implements XMLPrefsManager.XmlPrefsElement {
 
     @Override
     public void write(XMLPrefsManager.XMLPrefsSave save, String value) {
-        set(new File(Tuils.getFolder(), PATH), NAME, save.label(), new String[] {VALUE_ATTRIBUTE}, new String[] {value});
+        set(new File(Tuils.getFolder(), PATH), save.label(), new String[] {VALUE_ATTRIBUTE}, new String[] {value});
     }
 
     private static XMLPrefsManager.XMLPrefsList values;
     private static List<NotificatedApp> apps;
-    private static List<FilterGroup> groups;
-    private static SparseArray<List<String>> applies;
+    private static List<Pattern> filters;
+    private static List<XMLPrefsManager.IdValue> formats;
 
     private NotificationManager() {}
 
@@ -86,8 +73,8 @@ public class NotificationManager implements XMLPrefsManager.XmlPrefsElement {
         instance = new NotificationManager();
 
         apps = new ArrayList<>();
-        groups = new ArrayList<>();
-        applies = new SparseArray<>();
+        filters = new ArrayList<>();
+        formats = new ArrayList<>();
         values = new XMLPrefsManager.XMLPrefsList();
 
         try {
@@ -99,9 +86,12 @@ public class NotificationManager implements XMLPrefsManager.XmlPrefsElement {
             Object[] o;
             try {
                 o = XMLPrefsManager.buildDocument(file, NAME);
+                if(o == null) {
+                    Tuils.sendXMLParseError(context, PATH);
+                    return;
+                }
             } catch (Exception e) {
-                Tuils.sendOutput(Color.RED, context, context.getString(R.string.output_xmlproblem1) + Tuils.SPACE + PATH + context.getString(R.string.output_xmlproblem2) +
-                        Tuils.NEWLINE + context.getString(R.string.output_errorlabel) + e.toString());
+                Tuils.sendXMLParseError(context, PATH, e);
                 return;
             }
 
@@ -114,7 +104,6 @@ public class NotificationManager implements XMLPrefsManager.XmlPrefsElement {
             String[] deleted = instance.deleted();
             boolean needToWrite = false;
 
-            Main:
             for(int count = 0; count < nodes.getLength(); count++) {
                 Node node = nodes.item(count);
 
@@ -128,43 +117,34 @@ public class NotificationManager implements XMLPrefsManager.XmlPrefsElement {
                             break;
                         }
                     }
-                } else if (nn.equals(FILTER_NODE)) {
+                } else if (nn.equals(FILTER_ATTRIBUTE)) {
                     if (node.getNodeType() == Node.ELEMENT_NODE) {
                         Element e = (Element) node;
 
-                        String regex = e.hasAttribute(VALUE_ATTRIBUTE) ? e.getAttribute(VALUE_ATTRIBUTE) : null;
-                        if (regex == null) continue;
-
-                        String on = e.hasAttribute(ON_ATTRIBUTE) ? e.getAttribute(ON_ATTRIBUTE) : null;
-                        if (on == null) on = "text";
+                        Pattern pattern;
 
-                        int id;
+                        String regex = XMLPrefsManager.getStringAttribute(e, VALUE_ATTRIBUTE);
+                        if (regex == null) continue;
                         try {
-                            id = e.hasAttribute(ID_ATTRIBUTE) ? Integer.parseInt(e.getAttribute(ID_ATTRIBUTE)) : -1;
-                        } catch (NumberFormatException f) {
-                            id = -1;
-                        }
-
-                        Filter filter = Filter.getInstance(regex, on.equals("title") ? TITLE : TEXT);
-                        if (filter == null) continue;
-
-                        if (id != -1) {
-                            for (FilterGroup group : groups) {
-                                if (id == group.id) {
-                                    group.add(filter);
-                                    continue Main;
-                                }
+                            int id = Integer.parseInt(regex);
+                            pattern = RegexManager.get(id).regex;
+                        } catch (Exception exc) {
+                            try {
+                                pattern = Pattern.compile(regex);
+                            } catch (Exception exc2) {
+                                pattern = Pattern.compile(regex, Pattern.LITERAL);
                             }
                         }
 
-                        FilterGroup group = new FilterGroup(id);
-                        group.add(filter);
-                        groups.add(group);
+                        filters.add(pattern);
                     }
-                } else if (nn.equals(APPLY_NODE)) {
+                } else if(nn.equals(FORMAT_ATTRIBUTE)) {
                     if (node.getNodeType() == Node.ELEMENT_NODE) {
                         Element e = (Element) node;
 
+                        String format = XMLPrefsManager.getStringAttribute(e, VALUE_ATTRIBUTE);
+                        if(format == null) continue;
+
                         int id;
                         try {
                             id = e.hasAttribute(ID_ATTRIBUTE) ? Integer.parseInt(e.getAttribute(ID_ATTRIBUTE)) : -1;
@@ -172,18 +152,9 @@ public class NotificationManager implements XMLPrefsManager.XmlPrefsElement {
                             continue;
                         }
 
-                        String pkg = e.hasAttribute(PACKAGE_ATTRIBUTE) ? e.getAttribute(PACKAGE_ATTRIBUTE) : null;
-                        if (pkg == null) continue;
-
-                        List<String> at = applies.get(id);
-                        if(at == null) {
-                            at = new ArrayList<>();
-                            at.add(pkg);
-                            applies.put(id, at);
-                        } else at.add(pkg);
+                        formats.add(new XMLPrefsManager.IdValue(format, id));
                     }
                 } else {
-
                     int index = deleted == null ? -1 : Tuils.find(nn, deleted);
                     if(index != -1) {
                         deleted[index] = null;
@@ -198,13 +169,11 @@ public class NotificationManager implements XMLPrefsManager.XmlPrefsElement {
 
                         NotificatedApp app;
 
-                        boolean enabled = !e.hasAttribute(ENABLED_ATTRIBUTE) || Boolean.parseBoolean(e.getAttribute(ENABLED_ATTRIBUTE));
-
-                        String color = null;
-                        if (enabled)
-                            color = e.hasAttribute(COLOR_ATTRIBUTE) ? e.getAttribute(COLOR_ATTRIBUTE) : null;
+                        boolean enabled = XMLPrefsManager.getBooleanAttribute(e, ENABLED_ATTRIBUTE);
+                        String color = XMLPrefsManager.getStringAttribute(e, COLOR_ATTRIBUTE);
+                        String format = XMLPrefsManager.getStringAttribute(e, FORMAT_ATTRIBUTE);
 
-                        app = new NotificatedApp(nn, color, enabled);
+                        app = new NotificatedApp(nn, color, format, enabled);
                         apps.add(app);
                     }
                 }
@@ -230,70 +199,60 @@ public class NotificationManager implements XMLPrefsManager.XmlPrefsElement {
             Tuils.toFile(e);
         }
 
+        for(NotificatedApp app : apps) {
+            try {
+                int formatID = Integer.parseInt(app.format);
+
+                for(XMLPrefsManager.IdValue idValue : formats) {
+                    if(idValue.id == formatID) {
+                        app.format = idValue.value;
+                        break;
+                    }
+                }
+            } catch (Exception e) {}
+        }
+
         default_app_state = XMLPrefsManager.getBoolean(Notifications.app_notification_enabled_default);
         default_color = XMLPrefsManager.get(Notifications.default_notification_color);
+    }
 
-        Out:
-        for(int count = 0; count < applies.size(); count++) {
-            int id = applies.keyAt(count);
-            List<String> pkgs = applies.get(id);
-
-            for(FilterGroup g : groups) {
-                if(g.applyTo(id, pkgs)) continue Out;
-            }
-        }
+    public static String setState(String pkg, boolean state) {
+        return XMLPrefsManager.set(new File(Tuils.getFolder(), PATH), pkg, new String[] {ENABLED_ATTRIBUTE}, new String[] {String.valueOf(state)});
     }
 
-    public static void notificationsChangeFor(NotificatedApp app) {
-        notificationsChangeFor(new ArrayList<>(Collections.singletonList(app)));
+    public static String setColor(String pkg, String color) {
+        return XMLPrefsManager.set(new File(Tuils.getFolder(), PATH), pkg, new String[] {ENABLED_ATTRIBUTE, COLOR_ATTRIBUTE}, new String[] {String.valueOf(true), color});
     }
 
-    public static boolean match(String pkg, String text, String title) {
-//        if(pkg.equals(BuildConfig.APPLICATION_ID)) return true;
+    public static String setFormat(String pkg, String format) {
+        return XMLPrefsManager.set(new File(Tuils.getFolder(), PATH), pkg, new String[] {FORMAT_ATTRIBUTE}, new String[] {format});
+    }
 
-        for(FilterGroup group : groups) {
+    public static String addFilter(String pattern, int id) {
+        return XMLPrefsManager.add(new File(Tuils.getFolder(), PATH), FILTER_ATTRIBUTE, new String[] {ID_ATTRIBUTE, VALUE_ATTRIBUTE}, new String[] {String.valueOf(id), pattern});
+    }
 
-            if(group.pkgs != null && !group.pkgs.contains(pkg)) {
-                continue;
-            }
+    public static String addFormat(String format, int id) {
+        return XMLPrefsManager.add(new File(Tuils.getFolder(), PATH), FORMAT_ATTRIBUTE, new String[] {ID_ATTRIBUTE, VALUE_ATTRIBUTE}, new String[] {String.valueOf(id), format});
+    }
 
-            if(group.check(title, text)) {
-                return true;
-            }
-        }
-        return false;
+    public static String rmFilter(int id) {
+        return XMLPrefsManager.removeNode(new File(Tuils.getFolder(), PATH), FILTER_ATTRIBUTE, new String[] {ID_ATTRIBUTE}, new String[] {String.valueOf(id)});
     }
 
-    public static String getFormat() {
-        try {
-            return values.get(Notifications.notification_format).value;
-        } catch (Exception e) {
-            Tuils.toFile(e);
-            return Notifications.notification_format.defaultValue();
-        }
+    public static String rmFormat(int id) {
+        return XMLPrefsManager.removeNode(new File(Tuils.getFolder(), PATH), FORMAT_ATTRIBUTE, new String[] {ID_ATTRIBUTE}, new String[] {String.valueOf(id)});
     }
 
-    public static void notificationsChangeFor(List<NotificatedApp> apps) {
-        String[] names = new String[apps.size()];
-        final String[] attrNames = {ENABLED_ATTRIBUTE, COLOR_ATTRIBUTE};
-        String[][] values = new String[names.length][attrNames.length];
+    public static boolean match(String pkg, String text) {
+//        if(pkg.equals(BuildConfig.APPLICATION_ID)) return true;
 
-        for(int count = 0; count < apps.size(); count++) {
-            NotificatedApp app = apps.get(count);
-            names[count] = app.pkg;
-            values[count][0] = app.enabled + Tuils.EMPTYSTRING;
-            values[count][1] = app.color != null ? app.color : Tuils.EMPTYSTRING;
+        for(Pattern f : filters) {
+            Matcher m = f.matcher(text);
+            if(m.matches() || m.find()) return true;
         }
 
-        setMany(new File(Tuils.getFolder(), PATH), NAME, names, attrNames, values);
-    }
-
-    public static void excludeRegex(String regex, String on, int id) {
-        XMLPrefsManager.add(new File(Tuils.getFolder(), PATH), NAME, FILTER_NODE, new String[] {ON_ATTRIBUTE, VALUE_ATTRIBUTE, ID_ATTRIBUTE}, new String[] {on, regex, id + Tuils.EMPTYSTRING});
-    }
-
-    public static void applyFilter(int groupId, String packageName) {
-        XMLPrefsManager.add(new File(Tuils.getFolder(), PATH), NAME, APPLY_NODE, new String[] {ID_ATTRIBUTE, PACKAGE_ATTRIBUTE}, new String[] {groupId + Tuils.EMPTYSTRING, packageName});
+        return false;
     }
 
     public static int apps() {
@@ -308,14 +267,14 @@ public class NotificationManager implements XMLPrefsManager.XmlPrefsElement {
     }
 
     public static class NotificatedApp {
-        String pkg;
-        String color;
+        String pkg, color, format;
         boolean enabled;
 
-        public NotificatedApp(String pkg, String color, boolean enabled) {
+        public NotificatedApp(String pkg, String color, String format, boolean enabled) {
             this.pkg = pkg;
             this.color = color;
             this.enabled = enabled;
+            this.format = format;
         }
 
         @Override
@@ -328,92 +287,4 @@ public class NotificationManager implements XMLPrefsManager.XmlPrefsElement {
             return pkg;
         }
     }
-
-    public static class Filter {
-        Pattern pattern;
-        int on;
-
-        public static Filter getInstance(String p, int on) {
-            Filter filter = new Filter(p, on);
-            if(filter.pattern == null) return null;
-            return filter;
-        }
-
-        private Filter(String p, int on) {
-            this.on = on;
-
-            try {
-                this.pattern = Pattern.compile(p);
-            } catch (Exception e) {
-                this.pattern = null;
-            }
-        }
-    }
-
-    public static class FilterGroup {
-        List<Filter> brothers;
-        int id;
-
-        List<String> pkgs;
-
-        public FilterGroup(int id) {
-            this.id = id;
-
-            brothers = new ArrayList<>();
-        }
-
-        public void add(Filter filter) {
-            brothers.add(filter);
-        }
-
-        public boolean check(String title, String text) {
-            boolean matchTitle = false, matchText = false;
-            int titleCount = 0, textCount = 0;
-
-            for(Filter filter : brothers) {
-                String s;
-                if(filter.on == TITLE) {
-                    s = title;
-                    titleCount++;
-                } else {
-                    s = text;
-                    textCount++;
-                }
-
-                if(s == null) continue;
-
-                boolean b = filter.pattern.matcher(s).find();
-
-                if(filter.on == TITLE) matchTitle = matchTitle || b;
-                else matchText = matchText || b;
-            }
-
-            matchTitle = matchTitle || titleCount == 0;
-            matchText = matchText || textCount == 0;
-
-            return matchText && matchTitle;
-        }
-
-        public boolean applyTo(int id, String s) {
-            if(this.id == id) {
-                if(pkgs == null) pkgs = new ArrayList<>();
-
-                pkgs.add(s);
-                return true;
-            }
-
-            return false;
-        }
-
-        public boolean applyTo(int id, List<String> ss) {
-            if(this.id == id) {
-                if(pkgs == null) pkgs = new ArrayList<>();
-
-                pkgs.addAll(ss);
-                return true;
-            }
-
-            return false;
-        }
-    }
 }
diff --git a/app/src/main/java/ohi/andre/consolelauncher/managers/notifications/NotificationService.java b/app/src/main/java/ohi/andre/consolelauncher/managers/notifications/NotificationService.java
index ec316ba..b4d60a3 100755
--- a/app/src/main/java/ohi/andre/consolelauncher/managers/notifications/NotificationService.java
+++ b/app/src/main/java/ohi/andre/consolelauncher/managers/notifications/NotificationService.java
@@ -5,84 +5,275 @@ package ohi.andre.consolelauncher.managers.notifications;
  */
 
 import android.annotation.TargetApi;
-import android.app.Notification;
+import android.app.PendingIntent;
 import android.content.Intent;
 import android.content.pm.PackageManager;
 import android.graphics.Color;
 import android.os.Build;
 import android.os.Bundle;
 import android.os.Handler;
+import android.os.Parcel;
+import android.os.Parcelable;
 import android.service.notification.NotificationListenerService;
 import android.service.notification.StatusBarNotification;
 import android.support.v4.app.NotificationCompat;
-import android.text.Spannable;
-import android.text.SpannableString;
-import android.text.style.ForegroundColorSpan;
-import android.util.SparseArray;
+import android.text.TextUtils;
 
 import java.util.ArrayList;
-import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Queue;
+import java.util.concurrent.ArrayBlockingQueue;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
 import ohi.andre.consolelauncher.managers.TerminalManager;
+import ohi.andre.consolelauncher.managers.TimeManager;
 import ohi.andre.consolelauncher.managers.xml.XMLPrefsManager;
+import ohi.andre.consolelauncher.managers.xml.options.Behavior;
 import ohi.andre.consolelauncher.managers.xml.options.Notifications;
 import ohi.andre.consolelauncher.managers.xml.options.Theme;
-import ohi.andre.consolelauncher.tuils.TimeManager;
+import ohi.andre.consolelauncher.tuils.StoppableThread;
 import ohi.andre.consolelauncher.tuils.Tuils;
 
-import static ohi.andre.consolelauncher.managers.notifications.NotificationManager.NotificatedApp;
-import static ohi.andre.consolelauncher.managers.notifications.NotificationManager.default_color;
-
 
 @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR2)
 public class NotificationService extends NotificationListenerService {
 
-    private final int UPDATE_TIME = 1500;
+    private final int UPDATE_TIME = 2000;
+    private final String LINES_LABEL = "Lines", ANDROID_LABEL_PREFIX = "android.", NULL_LABEL = "null";
 
-    SparseArray<Long> ids = new SparseArray<>();
+    HashMap<String, List<Notification>> pastNotifications;
     Handler handler = new Handler();
 
+    String format;
+    int timeColor, color, maxOptionalDepth;
+    boolean enabled, click, longClick;
+
+    Queue<StatusBarNotification> queue;
+
+    final String PKG = "%pkg", APP = "%app", NEWLINE = "%n";
+    final Pattern timePattern = Pattern.compile("^%t[0-9]*$");
+
+    PackageManager manager;
+
+    private final Pattern formatPattern = Pattern.compile("%(?:\\[(\\d+)\\])?(?:\\[([^]]+)\\])?(?:(?:\\{)([a-zA-Z\\.\\:\\s]+)(?:\\})|([a-zA-Z\\.\\:]+))");
+
+    StoppableThread bgThread = new StoppableThread() {
+        @Override
+        public void run() {
+            super.run();
+
+            if(!enabled) return;
+
+            while(true) {
+                if(queue != null) {
+
+                    StatusBarNotification sbn;
+                    while ((sbn = queue.poll()) != null) {
+
+                        android.app.Notification notification = sbn.getNotification();
+                        if (notification == null) {
+                            continue;
+                        }
+
+                        String pack = sbn.getPackageName();
+
+                        String appName;
+                        try {
+                            appName = manager.getApplicationInfo(pack, 0).loadLabel(manager).toString();
+                        } catch (PackageManager.NameNotFoundException e) {
+                            appName = "null";
+                        }
+
+                        NotificationManager.NotificatedApp nApp = NotificationManager.getAppState(pack);
+                        if ((nApp != null && !nApp.enabled)) {
+                            continue;
+                        }
+
+                        if (nApp == null && !NotificationManager.default_app_state) {
+                            continue;
+                        }
+
+                        String f;
+                        if(nApp != null && nApp.format != null) f = nApp.format;
+                        else f = format;
+
+                        int textColor;
+                        if(nApp != null && nApp.color != null) textColor = Color.parseColor(nApp.color);
+                        else textColor = color;
+
+                        CharSequence s = Tuils.span(f, textColor);
+
+                        Bundle bundle = NotificationCompat.getExtras(notification);
+
+                        if(bundle != null) {
+                            Matcher m = formatPattern.matcher(s);
+                            String match;
+                            while(m.find()) {
+                                match = m.group(0);
+                                if (!match.startsWith(PKG) && !match.startsWith(APP) && !match.startsWith(NEWLINE) && !timePattern.matcher(match).matches()) {
+                                    String length = m.group(1);
+                                    String color = m.group(2);
+                                    String value = m.group(3);
+
+                                    if(value == null || value.length() == 0) value = m.group(4);
+
+                                    if(value != null) value = value.trim();
+                                    else continue;
+
+                                    if(value.length() == 0) continue;
+
+                                    if(value.equals("ttl")) value = "title";
+                                    else if(value.equals("txt")) value = "text";
+
+                                    String[] temp = value.split(":"), split;
+                                    if(value.endsWith(":")) {
+                                        split = new String[temp.length + 1];
+                                        System.arraycopy(temp, 0, split, 0, temp.length);
+                                        split[split.length - 1] = Tuils.EMPTYSTRING;
+                                    } else split = temp;
+
+//                                    because the last one is the default text, but only if there is more than one label
+                                    int stopAt = split.length;
+                                    if(stopAt > 1) stopAt--;
+
+                                    CharSequence text = null;
+                                    for(int j = 0; j < stopAt; j++) {
+                                        if(split[j].contains(LINES_LABEL)) {
+                                            CharSequence[] array = bundle.getCharSequenceArray(ANDROID_LABEL_PREFIX + split[j]);
+                                            if(array != null) {
+                                                for(CharSequence c : array) {
+                                                    if(text == null) text = c;
+                                                    else text = TextUtils.concat(text, Tuils.NEWLINE, c);
+                                                }
+                                            }
+                                        } else {
+                                            text = bundle.getCharSequence(ANDROID_LABEL_PREFIX + split[j]);
+                                        }
+
+                                        if(text != null && text.length() > 0) break;
+                                    }
+
+                                    if(text == null || text.length() == 0) {
+                                        text = split.length == 1 ? NULL_LABEL : split[split.length - 1];
+                                    }
+
+                                    String stringed = text.toString().trim();
+
+                                    try {
+                                        int l = Integer.parseInt(length);
+                                        stringed = stringed.substring(0,l);
+                                    } catch (Exception e) {}
+
+                                    try {
+                                        text = Tuils.span(stringed, Color.parseColor(color));
+                                    } catch (Exception e) {
+                                        text = stringed;
+                                    }
+
+                                    s = TextUtils.replace(s, new String[] {m.group(0)}, new CharSequence[] {text});
+                                }
+                            }
+                        }
+
+                        String text = s.toString();
+
+                        if(NotificationManager.match(pack, text)) continue;
+
+                        int found = isInPastNotifications(pack, text);
+//                        if(found == 0) {
+//                            Tuils.log("app " + pack, pastNotifications.get(pack).toString());
+//                        }
+
+                        if(found == 2) continue;
+
+//                        else
+                        Notification n = new Notification(System.currentTimeMillis(), text, pack, notification.contentIntent);
+
+                        if(found == 1) {
+                            List<Notification> ns = new ArrayList<>();
+                            ns.add(n);
+                            pastNotifications.put(pack, ns);
+                        } else if(found == 0) {
+                            pastNotifications.get(pack).add(n);
+                        }
+
+                        s = TextUtils.replace(s, new String[]{PKG, APP, NEWLINE}, new CharSequence[]{pack, appName, Tuils.NEWLINE});
+                        String st = s.toString();
+                        while (st.contains(NEWLINE)) {
+                            s = TextUtils.replace(s,
+                                    new String[]{NEWLINE},
+                                    new CharSequence[]{Tuils.NEWLINE});
+                            st = s.toString();
+                        }
+
+                        try {
+                            s = TimeManager.replace(s, timeColor);
+                        } catch (Exception e) {
+                            Tuils.log(e);
+                        }
+
+                        Tuils.sendOutput(NotificationService.this.getApplicationContext(), s, TerminalManager.CATEGORY_NOTIFICATION, click ? notification.contentIntent : null, longClick ? n : null);
+                    }
+                }
+
+                try {
+                    sleep(UPDATE_TIME);
+                } catch (InterruptedException e) {
+                    Tuils.log(e);
+                    return;
+                }
+            }
+        }
+    };
+
     @Override
     public void onCreate() {
         super.onCreate();
 
         NotificationManager.create(this);
+        try {
+            XMLPrefsManager.create(this);
+        } catch (Exception e) {
+            return;
+        }
 
         manager = getPackageManager();
-        format = NotificationManager.getFormat();
-        enabled = XMLPrefsManager.getBoolean(Notifications.show_notifications) ||
-                XMLPrefsManager.get(Notifications.show_notifications).equalsIgnoreCase("enabled");
-
-        if(NotificationManager.apps() == 0) {
-            NotificationManager.notificationsChangeFor(new ArrayList<>(Arrays.asList(
-                    new NotificatedApp("com.whatsapp", "#25D366", true),
-                    new NotificatedApp("com.google.android.apps.inbox", "#03A9F4", true),
-                    new NotificatedApp("com.paypal.android.p2pmobile", "#003087", true),
-                    new NotificatedApp("com.google.android.apps.plus", "#dd4b39", true),
-                    new NotificatedApp("com.facebook.katana", "#3b5998", true),
-                    new NotificatedApp("com.twitter.android", "#1da1f2", true),
-                    new NotificatedApp("com.android.vending", "#34a853", true)
-            )));
-        }
+        enabled = XMLPrefsManager.getBoolean(Notifications.show_notifications) || XMLPrefsManager.get(Notifications.show_notifications).equalsIgnoreCase("enabled");
+
+        pastNotifications = new HashMap<>();
+
+        format = XMLPrefsManager.get(Notifications.notification_format);
+        color = XMLPrefsManager.getColor(Notifications.default_notification_color);
+
+        click = XMLPrefsManager.getBoolean(Notifications.click_notification);
+        longClick = XMLPrefsManager.getBoolean(Notifications.long_click_notification);
+
+        maxOptionalDepth = XMLPrefsManager.getInt(Behavior.max_optional_depth);
 
         handler.post(new Runnable() {
             @Override
             public void run() {
-                SparseArray<Long> clone = ids.clone();
+                long now = System.currentTimeMillis();
 
-                long time = System.currentTimeMillis();
-                for(int c = 0; c < clone.size(); c++) {
-                    int key = clone.keyAt(c);
-                    long tm = clone.valueAt(c);
+                for (Map.Entry<String, List<Notification>> entry : pastNotifications.entrySet()) {
+                    List<Notification> notifications = entry.getValue();
 
-                    if(time - tm > UPDATE_TIME) ids.remove(key);
+                    Iterator<Notification> it = notifications.iterator();
+                    while (it.hasNext()) {
+                        if (now - it.next().time >= UPDATE_TIME) it.remove();
+                    }
                 }
 
                 handler.postDelayed(this, UPDATE_TIME);
             }
         });
+
+        queue = new ArrayBlockingQueue<>(5);
+        bgThread.start();
     }
 
     @Override
@@ -99,113 +290,70 @@ public class NotificationService extends NotificationListenerService {
     @Override
     public void onDestroy() {
         super.onDestroy();
-        handler.removeCallbacksAndMessages(null);
+        if(handler != null) handler.removeCallbacksAndMessages(null);
     }
 
-    String format;
-    int timeColor;
-    boolean enabled;
-
-    final Pattern patternPkg = Pattern.compile("%pkg", Pattern.CASE_INSENSITIVE | Pattern.LITERAL);
-    final Pattern patternText = Pattern.compile("%txt", Pattern.CASE_INSENSITIVE | Pattern.LITERAL);
-    final Pattern patternTitle = Pattern.compile("%ttl", Pattern.CASE_INSENSITIVE | Pattern.LITERAL);
-    final Pattern patternAppname = Pattern.compile("%app", Pattern.CASE_INSENSITIVE | Pattern.LITERAL);
-    final Pattern patternNewline = Pattern.compile("%n", Pattern.CASE_INSENSITIVE | Pattern.LITERAL);
-
-    PackageManager manager;
-
     @Override
     public void onNotificationPosted(StatusBarNotification sbn) {
-
         if(!enabled) return;
+        queue.offer(sbn);
+    }
 
-        for(int c = 0; c < ids.size(); c++) {
-            int key = ids.keyAt(c);
-            if(key == sbn.getId()) return;
-        }
-        ids.put(sbn.getId(), System.currentTimeMillis());
-
-        Notification notification = sbn.getNotification();
-        if (notification == null) {
-            return;
-        }
+//    0 = not found
+//    1 = the app wasnt found -> this is the first notification from this app
+//    2 = found
+    private int isInPastNotifications(String pkg, String text) {
+        List<Notification> notifications = pastNotifications.get(pkg);
+        if(notifications == null) return 1;
+        for(Notification n : notifications) if(n.text.equals(text)) return 2;
+        return 0;
+    }
 
-        String pack = sbn.getPackageName();
+    @Override
+    public void onNotificationRemoved(StatusBarNotification sbn) {}
 
-        String appName;
-        try {
-            appName = manager.getApplicationInfo(pack, 0).loadLabel(manager).toString();
-        } catch (PackageManager.NameNotFoundException e) {
-            appName = "null";
-        }
+    public static class Notification implements Parcelable {
+        public long time;
+        public String text, pkg;
+        public PendingIntent pendingIntent;
 
-        NotificatedApp nApp = NotificationManager.getAppState(pack);
-        if ((nApp != null && !nApp.enabled)) {
-            return;
+        public Notification(long time, String text, String pkg, PendingIntent pi) {
+            this.time = time;
+            this.text = text;
+            this.pkg = pkg;
+            this.pendingIntent = pi;
         }
 
-        if (nApp == null && !NotificationManager.default_app_state) {
-            return;
+        protected Notification(Parcel in) {
+            time = in.readLong();
+            text = in.readString();
+            pkg = in.readString();
+            pendingIntent = in.readParcelable(PendingIntent.class.getClassLoader());
         }
 
-        CharSequence textSequence = null, titleSequence = null;
-
-        Bundle bundle = NotificationCompat.getExtras(notification);
-        if(bundle != null) {
-            textSequence = bundle.getCharSequence(NotificationCompat.EXTRA_TEXT);
-            titleSequence = bundle.getCharSequence(NotificationCompat.EXTRA_TITLE);
-
-            if (textSequence == null) {
-                CharSequence[] charText = (CharSequence[]) bundle.get(NotificationCompat.EXTRA_TEXT_LINES);
-                if (charText != null && charText.length > 0) {
-                    textSequence = charText[charText.length - 1].toString();
-                }
+        public static final Creator<Notification> CREATOR = new Creator<Notification>() {
+            @Override
+            public Notification createFromParcel(Parcel in) {
+                return new Notification(in);
             }
-        } else {
-            textSequence = notification.tickerText;
-        }
 
-        String text = null, title = null;
-        if(textSequence != null) {
-            text = textSequence.toString();
-        }
-
-        if(titleSequence != null) {
-            title = titleSequence.toString();
-        }
-
-        if(title == null) title = "null";
-        if(text == null) text = "null";
-
-        if(NotificationManager.match(pack, text, title)) return;
+            @Override
+            public Notification[] newArray(int size) {
+                return new Notification[size];
+            }
+        };
 
-        int color;
-        try {
-            color = Color.parseColor(nApp.color);
-        } catch (Exception e) {
-            color = Color.parseColor(default_color);
+        @Override
+        public int describeContents() {
+            return 0;
         }
 
-        String finalText = format;
-        finalText = patternPkg.matcher(finalText).replaceAll(Matcher.quoteReplacement(pack));
-        finalText = patternAppname.matcher(finalText).replaceAll(Matcher.quoteReplacement(appName));
-        finalText = patternText.matcher(finalText).replaceAll(Matcher.quoteReplacement(text));
-        finalText = patternTitle.matcher(finalText).replaceAll(Matcher.quoteReplacement(title));
-        finalText = patternNewline.matcher(finalText).replaceAll(Matcher.quoteReplacement(Tuils.NEWLINE));
-
-        SpannableString spannableString = new SpannableString(finalText);
-        spannableString.setSpan(new ForegroundColorSpan(color), 0, finalText.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
-
-        CharSequence s;
-        try {
-            s = TimeManager.replace(spannableString, timeColor);
-        } catch (Exception e) {
-            return;
+        @Override
+        public void writeToParcel(Parcel dest, int flags) {
+            dest.writeLong(time);
+            dest.writeString(text);
+            dest.writeString(pkg);
+            dest.writeParcelable(pendingIntent, flags);
         }
-
-        Tuils.sendOutput(this, s, TerminalManager.CATEGORY_NOTIFICATION);
     }
-
-    @Override
-    public void onNotificationRemoved(StatusBarNotification sbn) {}
 }
\ No newline at end of file
diff --git a/app/src/main/java/ohi/andre/consolelauncher/managers/suggestions/SuggestionsManager.java b/app/src/main/java/ohi/andre/consolelauncher/managers/suggestions/SuggestionsManager.java
index 6729e7a..38b2450 100755
--- a/app/src/main/java/ohi/andre/consolelauncher/managers/suggestions/SuggestionsManager.java
+++ b/app/src/main/java/ohi/andre/consolelauncher/managers/suggestions/SuggestionsManager.java
@@ -17,11 +17,13 @@ import ohi.andre.consolelauncher.managers.AliasManager;
 import ohi.andre.consolelauncher.managers.AppsManager;
 import ohi.andre.consolelauncher.managers.ContactManager;
 import ohi.andre.consolelauncher.managers.FileManager;
+import ohi.andre.consolelauncher.managers.RssManager;
 import ohi.andre.consolelauncher.managers.music.Song;
 import ohi.andre.consolelauncher.managers.notifications.NotificationManager;
 import ohi.andre.consolelauncher.managers.xml.XMLPrefsManager;
 import ohi.andre.consolelauncher.managers.xml.options.Apps;
 import ohi.andre.consolelauncher.managers.xml.options.Notifications;
+import ohi.andre.consolelauncher.managers.xml.options.Rss;
 import ohi.andre.consolelauncher.managers.xml.options.Suggestions;
 import ohi.andre.consolelauncher.tuils.Compare;
 import ohi.andre.consolelauncher.tuils.SimpleMutableEntry;
@@ -44,7 +46,7 @@ public class SuggestionsManager {
 
     private boolean showAliasDefault, set = false, clickToLaunch, showAppsGpDefault;
 
-    public Suggestion[] getSuggestions(MainPack info, String before, String lastWord) {
+    public Suggestion[] getSuggestions(MainPack info, String beforeLastSpace , String lastWord) {
 
         if(!set) {
             showAliasDefault = XMLPrefsManager.getBoolean(Suggestions.suggest_alias_default);
@@ -55,14 +57,14 @@ public class SuggestionsManager {
 
         List<Suggestion> suggestionList = new ArrayList<>();
 
-        before = before.trim();
+        beforeLastSpace  = beforeLastSpace .trim();
         lastWord = lastWord.trim();
 
 //        lastword = 0
         if (lastWord.length() == 0) {
-//            lastword = 0 && before = 0
+//            lastword = 0 && beforeLastSpace  = 0
 
-            if (before.length() == 0) {
+            if (beforeLastSpace .length() == 0) {
                 AppsManager.LaunchInfo[] apps = info.appsManager.getSuggestedApps();
                 if (apps != null) {
                     for(int count = 0; count < apps.length; count++) {
@@ -72,22 +74,22 @@ public class SuggestionsManager {
 
                         float shift = count + 1;
                         float rate = 1f / shift;
-                        suggestionList.add(new Suggestion(before, apps[count].getString(), clickToLaunch, (int) Math.ceil(rate), Suggestion.TYPE_APP, apps[count]));
+                        suggestionList.add(new Suggestion(beforeLastSpace , apps[count].getString(), clickToLaunch, (int) Math.ceil(rate), Suggestion.TYPE_APP, apps[count]));
                     }
                 }
 
                 if(showAliasDefault) suggestAlias(info.aliasManager, suggestionList, lastWord);
-                if(showAppsGpDefault) suggestAppGroup(suggestionList, lastWord, before);
+                if(showAppsGpDefault) suggestAppGroup(suggestionList, lastWord, beforeLastSpace );
 
                 return suggestionList.toArray(new Suggestion[suggestionList.size()]);
             }
 
-//            lastword == 0 && before > 0
+//            lastword == 0 && beforeLastSpace  > 0
             else {
 //                check if this is a command
                 Command cmd = null;
                 try {
-                    cmd = CommandTuils.parse(before, info, true);
+                    cmd = CommandTuils.parse(beforeLastSpace , info, true);
                 } catch (Exception e) {}
 
                 if (cmd != null) {
@@ -105,17 +107,17 @@ public class SuggestionsManager {
 //                            (cmd.mArgs != null && cmd.mArgs.length > 0 && cmd.cmd instanceof ParamCommand && cmd.nArgs >= 1 && ((ParamCommand) cmd.cmd).argsForParam((String) cmd.mArgs[0]).length == cmd.nArgs
 //                                    && cmd.indexNotFound == ((ParamCommand) cmd.cmd).argsForParam((String) cmd.mArgs[0]).length)) {
 ////                        the last arg wasnt found
-//                        suggestArgs(info, cmd.cmd instanceof ParamCommand ? ((ParamCommand) cmd.cmd).argsForParam((String) cmd.mArgs[0])[cmd.nArgs - 1] : cmd.cmd.argType()[cmd.nArgs], suggestionList, lastWord, before);
+//                        suggestArgs(info, cmd.cmd instanceof ParamCommand ? ((ParamCommand) cmd.cmd).argsForParam((String) cmd.mArgs[0])[cmd.nArgs - 1] : cmd.cmd.argType()[cmd.nArgs], suggestionList, lastWord, beforeLastSpace );
 //                    }
 
                     if(cmd.cmd instanceof ParamCommand && (cmd.mArgs == null || cmd.mArgs.length == 0 || cmd.mArgs[0] instanceof String)) {
-                        suggestParams(info, suggestionList, (ParamCommand) cmd.cmd, before, null);
+                        suggestParams(info, suggestionList, (ParamCommand) cmd.cmd, beforeLastSpace , null);
                     }
-                    else suggestArgs(info, cmd.nextArg(), suggestionList, before);
+                    else suggestArgs(info, cmd.nextArg(), suggestionList, beforeLastSpace );
 
                 } else {
 
-                    String[] split = before.replaceAll("['\"]", Tuils.EMPTYSTRING).split(Tuils.SPACE);
+                    String[] split = beforeLastSpace .replaceAll("['\"]", Tuils.EMPTYSTRING).split(Tuils.SPACE);
                     boolean isShellCmd = false;
                     for(String s : split) {
                         if(needsFileSuggestion(s)) {
@@ -125,10 +127,10 @@ public class SuggestionsManager {
                     }
 
                     if(isShellCmd) {
-                        suggestFile(info, suggestionList, Tuils.EMPTYSTRING, before);
+                        suggestFile(info, suggestionList, Tuils.EMPTYSTRING, beforeLastSpace );
                     } else {
 //                        ==> app
-                        if(!suggestAppInsideGroup(suggestionList, Tuils.EMPTYSTRING, before, false)) suggestApp(info, suggestionList, before + Tuils.SPACE, Tuils.EMPTYSTRING);
+                        if(!suggestAppInsideGroup(suggestionList, Tuils.EMPTYSTRING, beforeLastSpace , false)) suggestApp(info, suggestionList, beforeLastSpace  + Tuils.SPACE, Tuils.EMPTYSTRING);
                     }
 
                 }
@@ -138,11 +140,11 @@ public class SuggestionsManager {
 //        lastWord > 0
         else {
 
-            if (before.length() > 0) {
-//                lastword > 0 && before > 0
+            if (beforeLastSpace .length() > 0) {
+//                lastword > 0 && beforeLastSpace  > 0
                 Command cmd = null;
                 try {
-                    cmd = CommandTuils.parse(before, info, true);
+                    cmd = CommandTuils.parse(beforeLastSpace , info, true);
                 } catch (Exception e) {}
 
                 if (cmd != null) {
@@ -150,18 +152,18 @@ public class SuggestionsManager {
                         suggestPermanentSuggestions(suggestionList, (PermanentSuggestionCommand) cmd.cmd);
                     }
 
-//                    if (cmd.cmd.maxArgs() == 1 && before.contains(Tuils.SPACE)) {
+//                    if (cmd.cmd.maxArgs() == 1 && beforeLastSpace .contains(Tuils.SPACE)) {
 //                        int index = cmd.cmd.getClass().getSimpleName().length() + 1;
 //
-//                        lastWord = before.substring(index) + lastWord;
+//                        lastWord = beforeLastSpace .substring(index) + lastWord;
 //                    }
 
                     if(cmd.cmd instanceof ParamCommand && (cmd.mArgs == null || cmd.mArgs.length == 0 || cmd.mArgs[0] instanceof String)) {
-                        suggestParams(info, suggestionList, (ParamCommand) cmd.cmd, before, lastWord);
-                    } else suggestArgs(info, cmd.nextArg(), suggestionList, lastWord, before);
+                        suggestParams(info, suggestionList, (ParamCommand) cmd.cmd, beforeLastSpace , lastWord);
+                    } else suggestArgs(info, cmd.nextArg(), suggestionList, lastWord, beforeLastSpace );
                 } else {
 
-                    String[] split = before.replaceAll("['\"]", Tuils.EMPTYSTRING).split(Tuils.SPACE);
+                    String[] split = beforeLastSpace .replaceAll("['\"]", Tuils.EMPTYSTRING).split(Tuils.SPACE);
                     boolean isShellCmd = false;
                     for(String s : split) {
                         if(needsFileSuggestion(s)) {
@@ -171,18 +173,18 @@ public class SuggestionsManager {
                     }
 
                     if(isShellCmd) {
-                        suggestFile(info, suggestionList, lastWord, before);
+                        suggestFile(info, suggestionList, lastWord, beforeLastSpace );
                     } else {
-                        if(!suggestAppInsideGroup(suggestionList, lastWord, before, false)) suggestApp(info, suggestionList, before + Tuils.SPACE + lastWord, Tuils.EMPTYSTRING);
+                        if(!suggestAppInsideGroup(suggestionList, lastWord, beforeLastSpace , false)) suggestApp(info, suggestionList, beforeLastSpace  + Tuils.SPACE + lastWord, Tuils.EMPTYSTRING);
                     }
                 }
 
             } else {
-//                lastword > 0 && before = 0
-                suggestCommand(info, suggestionList, lastWord, before);
+//                lastword > 0 && beforeLastSpace  = 0
+                suggestCommand(info, suggestionList, lastWord, beforeLastSpace );
                 suggestAlias(info.aliasManager, suggestionList, lastWord);
                 suggestApp(info, suggestionList, lastWord, Tuils.EMPTYSTRING);
-                suggestAppGroup(suggestionList, lastWord, before);
+                suggestAppGroup(suggestionList, lastWord, beforeLastSpace );
             }
         }
 
@@ -207,7 +209,7 @@ public class SuggestionsManager {
         else for(String s : aliasManager.getAliases()) if(s.startsWith(lastWord)) suggestions.add(new Suggestion(Tuils.EMPTYSTRING, s, clickToLaunch, NO_RATE, Suggestion.TYPE_ALIAS));
     }
 
-    private void suggestParams(MainPack pack, List<Suggestion> suggestions, ParamCommand cmd, String before, String lastWord) {
+    private void suggestParams(MainPack pack, List<Suggestion> suggestions, ParamCommand cmd, String beforeLastSpace , String lastWord) {
         String[] params = cmd.params();
         if (params == null) {
             return;
@@ -218,7 +220,7 @@ public class SuggestionsManager {
                 Param p = cmd.getParam(pack, s).getValue();
                 if(p == null) continue;
 
-                suggestions.add(new Suggestion(before, s, p.args().length == 0 && clickToLaunch, NO_RATE, 0));
+                suggestions.add(new Suggestion(beforeLastSpace , s, p.args().length == 0 && clickToLaunch, NO_RATE, 0));
             }
         }
         else {
@@ -227,108 +229,108 @@ public class SuggestionsManager {
                 if(p == null) continue;
 
                 if (s.startsWith(lastWord) || s.replace("-", Tuils.EMPTYSTRING).startsWith(lastWord)) {
-                    suggestions.add(new Suggestion(before, s, p.args().length == 0 && clickToLaunch, NO_RATE, 0));
+                    suggestions.add(new Suggestion(beforeLastSpace , s, p.args().length == 0 && clickToLaunch, NO_RATE, 0));
                 }
             }
         }
     }
 
-    private void suggestArgs(MainPack info, int type, List<Suggestion> suggestions, String prev, String before) {
+    private void suggestArgs(MainPack info, int type, List<Suggestion> suggestions, String afterLastSpace, String beforeLastSpace ) {
         switch (type) {
             case CommandAbstraction.FILE:
             case CommandAbstraction.FILE_LIST:
-                suggestFile(info, suggestions, prev, before);
+                suggestFile(info, suggestions, afterLastSpace, beforeLastSpace );
                 break;
             case CommandAbstraction.VISIBLE_PACKAGE:
-                suggestApp(info, suggestions, prev, before);
+                suggestApp(info, suggestions, afterLastSpace, beforeLastSpace );
                 break;
             case CommandAbstraction.COMMAND:
-                suggestCommand(info, suggestions, prev, before);
+                suggestCommand(info, suggestions, afterLastSpace, beforeLastSpace );
                 break;
             case CommandAbstraction.CONTACTNUMBER:
-                suggestContact(info, suggestions, prev, before);
+                suggestContact(info, suggestions, afterLastSpace, beforeLastSpace );
                 break;
             case CommandAbstraction.SONG:
-                suggestSong(info, suggestions, prev, before);
+                suggestSong(info, suggestions, afterLastSpace, beforeLastSpace );
                 break;
             case CommandAbstraction.BOOLEAN:
-                suggestBoolean(suggestions, before);
+                suggestBoolean(suggestions, beforeLastSpace );
                 break;
             case CommandAbstraction.HIDDEN_PACKAGE:
-                suggestHiddenApp(info, suggestions, prev, before);
+                suggestHiddenApp(info, suggestions, afterLastSpace, beforeLastSpace );
                 break;
             case CommandAbstraction.COLOR:
-                suggestColor(suggestions, prev, before);
+                suggestColor(suggestions, afterLastSpace, beforeLastSpace );
                 break;
             case CommandAbstraction.CONFIG_ENTRY:
-                suggestConfigEntry(suggestions, prev, before);
+                suggestConfigEntry(suggestions, afterLastSpace, beforeLastSpace );
                 break;
             case CommandAbstraction.CONFIG_FILE:
-                suggestConfigFile(suggestions, prev, before);
+                suggestConfigFile(suggestions, afterLastSpace, beforeLastSpace );
                 break;
             case CommandAbstraction.DEFAULT_APP:
-                suggestDefaultApp(info, suggestions, prev, before);
+                suggestDefaultApp(info, suggestions, afterLastSpace, beforeLastSpace );
                 break;
             case CommandAbstraction.ALL_PACKAGES:
-                suggestAllPackages(info, suggestions, prev, before);
+                suggestAllPackages(info, suggestions, afterLastSpace, beforeLastSpace );
                 break;
             case CommandAbstraction.APP_GROUP:
-                suggestAppGroup(suggestions, prev, before);
+                suggestAppGroup(suggestions, afterLastSpace, beforeLastSpace );
                 break;
             case CommandAbstraction.APP_INSIDE_GROUP:
-                suggestAppInsideGroup(suggestions, prev, before, true);
+                suggestAppInsideGroup(suggestions, afterLastSpace, beforeLastSpace , true);
                 break;
         }
     }
 
-    private void suggestArgs(MainPack info, int type, List<Suggestion> suggestions, String before) {
-        suggestArgs(info, type, suggestions, null, before);
+    private void suggestArgs(MainPack info, int type, List<Suggestion> suggestions, String beforeLastSpace ) {
+        suggestArgs(info, type, suggestions, null, beforeLastSpace );
     }
 
-    private void suggestBoolean(List<Suggestion> suggestions, String before) {
-        suggestions.add(new Suggestion(before, "true", clickToLaunch, NO_RATE, Suggestion.TYPE_BOOLEAN));
-        suggestions.add(new Suggestion(before, "false", clickToLaunch, NO_RATE, Suggestion.TYPE_BOOLEAN));
+    private void suggestBoolean(List<Suggestion> suggestions, String beforeLastSpace ) {
+        suggestions.add(new Suggestion(beforeLastSpace , "true", clickToLaunch, NO_RATE, Suggestion.TYPE_BOOLEAN));
+        suggestions.add(new Suggestion(beforeLastSpace , "false", clickToLaunch, NO_RATE, Suggestion.TYPE_BOOLEAN));
     }
 
-    private void suggestFile(MainPack info, List<Suggestion> suggestions, String prev, String before) {
-        if(prev == null || !prev.endsWith(File.separator)) {
-            suggestions.add(new Suggestion(before + Tuils.SPACE + (prev != null ? prev : Tuils.EMPTYSTRING), File.separator, false, MAX_RATE, Suggestion.TYPE_FILE));
+    private void suggestFile(MainPack info, List<Suggestion> suggestions, String afterLastSpace, String beforeLastSpace ) {
+        if(afterLastSpace == null || !afterLastSpace.endsWith(File.separator)) {
+            suggestions.add(new Suggestion(beforeLastSpace  + Tuils.SPACE + (afterLastSpace != null ? afterLastSpace : Tuils.EMPTYSTRING), File.separator, false, MAX_RATE, Suggestion.TYPE_FILE));
         }
 
-        if (prev == null || prev.length() == 0) {
-            suggestFilesInDir(suggestions, info.currentDirectory, before);
+        if (afterLastSpace == null || afterLastSpace.length() == 0) {
+            suggestFilesInDir(suggestions, info.currentDirectory, beforeLastSpace );
             return;
         }
 
-        if (!prev.contains(File.separator) && prev.length() > 0) {
-            suggestFilesInDir(suggestions, info.currentDirectory, prev, before);
-        } else if (prev.length() > 0) {
-            if (prev.endsWith(File.separator)) {
-                prev = prev.substring(0, prev.length() - 1);
-                before = before + Tuils.SPACE + prev + File.separator;
+        if (!afterLastSpace.contains(File.separator) && afterLastSpace.length() > 0) {
+            suggestFilesInDir(suggestions, info.currentDirectory, afterLastSpace, beforeLastSpace );
+        } else if (afterLastSpace.length() > 0) {
+            if (afterLastSpace.endsWith(File.separator)) {
+                afterLastSpace = afterLastSpace.substring(0, afterLastSpace.length() - 1);
+                beforeLastSpace  = beforeLastSpace  + Tuils.SPACE + afterLastSpace + File.separator;
 
-                FileManager.DirInfo dirInfo = FileManager.cd(info.currentDirectory, prev);
-                suggestFilesInDir(suggestions, dirInfo.file, before);
+                FileManager.DirInfo dirInfo = FileManager.cd(info.currentDirectory, afterLastSpace);
+                suggestFilesInDir(suggestions, dirInfo.file, beforeLastSpace );
             } else {
 //                contains / but doesn't end with it
-                FileManager.DirInfo dirInfo = FileManager.cd(info.currentDirectory, prev.substring(0,prev.lastIndexOf(File.separator)));
+                FileManager.DirInfo dirInfo = FileManager.cd(info.currentDirectory, afterLastSpace.substring(0,afterLastSpace.lastIndexOf(File.separator)));
 
-                int index = prev.lastIndexOf(File.separator);
-                String hold = prev.substring(0, index + 1);
-                prev = prev.substring(index + 1);
-                before = before + Tuils.SPACE + hold;
+                int index = afterLastSpace.lastIndexOf(File.separator);
+                String hold = afterLastSpace.substring(0, index + 1);
+                afterLastSpace = afterLastSpace.substring(index + 1);
+                beforeLastSpace  = beforeLastSpace  + Tuils.SPACE + hold;
 
-                suggestFilesInDir(suggestions, dirInfo.file, prev, before);
+                suggestFilesInDir(suggestions, dirInfo.file, afterLastSpace, beforeLastSpace );
             }
         }
     }
 
-    private void suggestFilesInDir(List<Suggestion> suggestions, File dir, String prev, String before) {
+    private void suggestFilesInDir(List<Suggestion> suggestions, File dir, String afterLastSpace, String beforeLastSpace ) {
         if (dir == null || !dir.isDirectory())
             return;
 
-        if (prev == null || prev.length() == 0) {
-            suggestFilesInDir(suggestions, dir, before);
+        if (afterLastSpace == null || afterLastSpace.length() == 0) {
+            suggestFilesInDir(suggestions, dir, beforeLastSpace );
             return;
         }
 
@@ -337,12 +339,12 @@ public class SuggestionsManager {
             return;
         }
 
-        for(SimpleMutableEntry<String, Integer> s : Compare.matchesWithRate(files, prev, false)) {
-            suggestions.add(new Suggestion(before, s.getKey(), false, s.getValue(), Suggestion.TYPE_FILE));
+        for(SimpleMutableEntry<String, Integer> s : Compare.matchesWithRate(files, afterLastSpace, false)) {
+            suggestions.add(new Suggestion(beforeLastSpace , s.getKey(), false, s.getValue(), Suggestion.TYPE_FILE));
         }
     }
 
-    private void suggestFilesInDir(List<Suggestion> suggestions, File dir, String before) {
+    private void suggestFilesInDir(List<Suggestion> suggestions, File dir, String beforeLastSpace ) {
         if (dir == null || !dir.isDirectory()) {
             return;
         }
@@ -354,57 +356,57 @@ public class SuggestionsManager {
             }
             Arrays.sort(files);
             for (String s : files) {
-                suggestions.add(new Suggestion(before, s, false, NO_RATE, Suggestion.TYPE_FILE));
+                suggestions.add(new Suggestion(beforeLastSpace , s, false, NO_RATE, Suggestion.TYPE_FILE));
             }
         } catch (NullPointerException e) {}
     }
 
-    private void suggestContact(MainPack info, List<Suggestion> suggestions, String prev, String before) {
+    private void suggestContact(MainPack info, List<Suggestion> suggestions, String afterLastSpace, String beforeLastSpace ) {
         List<ContactManager.Contact> contacts = info.contacts.getContacts();
         if(contacts == null) return;
 
-        if (prev == null || prev.length() == 0) {
-            for (ContactManager.Contact contact : contacts) suggestions.add(new Suggestion(before, contact.name, true, NO_RATE, Suggestion.TYPE_CONTACT, contact));
+        if (afterLastSpace == null || afterLastSpace.length() == 0) {
+            for (ContactManager.Contact contact : contacts) suggestions.add(new Suggestion(beforeLastSpace , contact.name, true, NO_RATE, Suggestion.TYPE_CONTACT, contact));
         }
         else {
             for(ContactManager.Contact contact : contacts) {
                 if(Thread.currentThread().isInterrupted()) return;
 
-                int rate = Compare.matches(contact.name, prev, true);
+                int rate = Compare.matches(contact.name, afterLastSpace, true);
                 if(rate != -1) {
-                    suggestions.add(new Suggestion(before, contact.name, true, rate, Suggestion.TYPE_CONTACT, contact));
+                    suggestions.add(new Suggestion(beforeLastSpace , contact.name, true, rate, Suggestion.TYPE_CONTACT, contact));
                 }
             }
         }
     }
 
-    private void suggestSong(MainPack info, List<Suggestion> suggestions, String prev, String before) {
+    private void suggestSong(MainPack info, List<Suggestion> suggestions, String afterLastSpace, String beforeLastSpace ) {
         if(info.player == null) return;
 
         List<Song> songs = info.player.getSongs();
         if(songs == null) return;
 
-        if (prev == null || prev.length() == 0) {
+        if (afterLastSpace == null || afterLastSpace.length() == 0) {
             for (Song s : songs) {
-                suggestions.add(new Suggestion(before, s.getTitle(), clickToLaunch, NO_RATE, Suggestion.TYPE_SONG));
+                suggestions.add(new Suggestion(beforeLastSpace , s.getTitle(), clickToLaunch, NO_RATE, Suggestion.TYPE_SONG));
             }
         }
         else {
-            List<SimpleMutableEntry<Compare.Stringable, Integer>> infos = Compare.matchesWithRate(songs, true, prev);
+            List<SimpleMutableEntry<Compare.Stringable, Integer>> infos = Compare.matchesWithRate(songs, true, afterLastSpace);
             for(SimpleMutableEntry<Compare.Stringable, Integer> i : infos) {
-                suggestions.add(new Suggestion(before, i.getKey().getString(), clickToLaunch, i.getValue(), Suggestion.TYPE_SONG));
+                suggestions.add(new Suggestion(beforeLastSpace , i.getKey().getString(), clickToLaunch, i.getValue(), Suggestion.TYPE_SONG));
             }
         }
     }
 
-    private void suggestCommand(MainPack info, List<Suggestion> suggestions, String prev, String before) {
-        if (prev == null || prev.length() == 0) {
-            suggestCommand(info, suggestions, before);
+    private void suggestCommand(MainPack info, List<Suggestion> suggestions, String afterLastSpace, String beforeLastSpace ) {
+        if (afterLastSpace == null || afterLastSpace.length() == 0) {
+            suggestCommand(info, suggestions, beforeLastSpace );
             return;
         }
 
-        if(prev.length() <= FIRST_INTERVAL) {
-            prev = prev.toLowerCase().trim();
+        if(afterLastSpace.length() <= FIRST_INTERVAL) {
+            afterLastSpace = afterLastSpace.toLowerCase().trim();
 
             String[] cmds = info.commandGroup.getCommandNames();
             if(cmds == null) return;
@@ -412,23 +414,23 @@ public class SuggestionsManager {
             for (String s : cmds) {
                 if(Thread.currentThread().isInterrupted()) return;
 
-                if(s.startsWith(prev)) {
+                if(s.startsWith(afterLastSpace)) {
                     CommandAbstraction cmd = info.commandGroup.getCommandByName(s);
                     int[] args = cmd.argType();
                     boolean exec = args == null || args.length == 0;
-                    suggestions.add(new Suggestion(before, s, exec && clickToLaunch, MAX_RATE, Suggestion.TYPE_COMMAND));
+                    suggestions.add(new Suggestion(beforeLastSpace , s, exec && clickToLaunch, MAX_RATE, Suggestion.TYPE_COMMAND));
                 }
             }
         }
     }
 
-    private void suggestColor(List<Suggestion> suggestions, String prev, String before) {
-        if(prev == null || prev.length() == 0 || (prev.length() == 1 && prev.charAt(0) != '#')) {
-            suggestions.add(new Suggestion(before, "#", false, MAX_RATE, Suggestion.TYPE_COLOR));
+    private void suggestColor(List<Suggestion> suggestions, String afterLastSpace, String beforeLastSpace ) {
+        if(afterLastSpace == null || afterLastSpace.length() == 0 || (afterLastSpace.length() == 1 && afterLastSpace.charAt(0) != '#')) {
+            suggestions.add(new Suggestion(beforeLastSpace , "#", false, MAX_RATE, Suggestion.TYPE_COLOR));
         }
     }
 
-    private void suggestCommand(MainPack info, List<Suggestion> suggestions, String before) {
+    private void suggestCommand(MainPack info, List<Suggestion> suggestions, String beforeLastSpace ) {
         String[] cmds = info.commandGroup.getCommandNames();
         if(cmds == null) return;
 
@@ -439,82 +441,82 @@ public class SuggestionsManager {
             if (cmd != null && cmd.priority() >= MIN_COMMAND_PRIORITY) {
                 int[] args = cmd.argType();
                 boolean exec = args == null || args.length == 0;
-                suggestions.add(new Suggestion(before, s, exec && clickToLaunch, cmd.priority(), Suggestion.TYPE_COMMAND));
+                suggestions.add(new Suggestion(beforeLastSpace , s, exec && clickToLaunch, cmd.priority(), Suggestion.TYPE_COMMAND));
             }
         }
     }
 
-    private void suggestApp(MainPack info, List<Suggestion> suggestions, String prev, String before) {
+    private void suggestApp(MainPack info, List<Suggestion> suggestions, String afterLastSpace, String beforeLastSpace) {
         List<AppsManager.LaunchInfo> apps = info.appsManager.shownApps();
         if(apps == null) return;
 
-        if (prev == null || prev.length() == 0) {
+        if (afterLastSpace == null || afterLastSpace.length() == 0) {
             for (AppsManager.LaunchInfo l : apps) {
-                suggestions.add(new Suggestion(before, l.publicLabel, clickToLaunch, NO_RATE, Suggestion.TYPE_APP, l));
+                suggestions.add(new Suggestion(beforeLastSpace , l.publicLabel, clickToLaunch, NO_RATE, Suggestion.TYPE_APP, l));
             }
         }
         else {
-            List<SimpleMutableEntry<Compare.Stringable, Integer>> infos = Compare.matchesWithRate(apps, true, prev);
+            List<SimpleMutableEntry<Compare.Stringable, Integer>> infos = Compare.matchesWithRate(apps, true, afterLastSpace);
             for(SimpleMutableEntry<Compare.Stringable, Integer> i : infos) {
-                suggestions.add(new Suggestion(before, i.getKey().getString(), clickToLaunch, i.getValue(), Suggestion.TYPE_APP, i.getKey()));
+                suggestions.add(new Suggestion(beforeLastSpace , i.getKey().getString(), clickToLaunch, i.getValue(), Suggestion.TYPE_APP, i.getKey()));
             }
         }
     }
 
-    private void suggestHiddenApp(MainPack info, List<Suggestion> suggestions, String prev, String before) {
+    private void suggestHiddenApp(MainPack info, List<Suggestion> suggestions, String afterLastSpace, String beforeLastSpace) {
         List<AppsManager.LaunchInfo> apps = info.appsManager.hiddenApps();
         if(apps == null) return;
 
-        if (prev == null || prev.length() == 0) {
+        if (afterLastSpace == null || afterLastSpace.length() == 0) {
             for (AppsManager.LaunchInfo a : apps) {
-                suggestions.add(new Suggestion(before, a.publicLabel, clickToLaunch, NO_RATE, Suggestion.TYPE_APP));
+                suggestions.add(new Suggestion(beforeLastSpace , a.publicLabel, false, NO_RATE, Suggestion.TYPE_APP));
             }
         }
         else {
-            List<SimpleMutableEntry<Compare.Stringable, Integer>> infos = Compare.matchesWithRate(apps, true, prev);
+            List<SimpleMutableEntry<Compare.Stringable, Integer>> infos = Compare.matchesWithRate(apps, true, afterLastSpace);
             for(SimpleMutableEntry<Compare.Stringable, Integer> i : infos) {
-                suggestions.add(new Suggestion(before, i.getKey().getString(), clickToLaunch, i.getValue(), Suggestion.TYPE_APP));
+                suggestions.add(new Suggestion(beforeLastSpace , i.getKey().getString(), false, i.getValue(), Suggestion.TYPE_APP));
             }
         }
     }
 
-    private void suggestAllPackages(MainPack info, List<Suggestion> suggestions, String prev, String before) {
+    private void suggestAllPackages(MainPack info, List<Suggestion> suggestions, String afterLastSpace, String beforeLastSpace ) {
         List<AppsManager.LaunchInfo> apps = new ArrayList<>(info.appsManager.shownApps());
         apps.addAll(info.appsManager.hiddenApps());
 
-        if (prev == null || prev.length() == 0) {
+        if (afterLastSpace == null || afterLastSpace.length() == 0) {
             for (AppsManager.LaunchInfo a : apps) {
-                suggestions.add(new Suggestion(before, a.publicLabel, clickToLaunch, NO_RATE, Suggestion.TYPE_APP, a));
+                suggestions.add(new Suggestion(beforeLastSpace , a.publicLabel, clickToLaunch, NO_RATE, Suggestion.TYPE_APP, a));
             }
         } else {
-            List<SimpleMutableEntry<Compare.Stringable, Integer>> infos = Compare.matchesWithRate(apps, true, prev);
+            List<SimpleMutableEntry<Compare.Stringable, Integer>> infos = Compare.matchesWithRate(apps, true, afterLastSpace);
             for(SimpleMutableEntry<Compare.Stringable, Integer> i : infos) {
-                suggestions.add(new Suggestion(before, i.getKey().getString(), clickToLaunch, i.getValue(), Suggestion.TYPE_APP, i.getKey()));
+                suggestions.add(new Suggestion(beforeLastSpace , i.getKey().getString(), clickToLaunch, i.getValue(), Suggestion.TYPE_APP, i.getKey()));
             }
         }
     }
 
-    private void suggestDefaultApp(MainPack info, List<Suggestion> suggestions, String prev, String before) {
-        suggestions.add(new Suggestion(before, "most_used", false, MAX_RATE, Suggestion.TYPE_PERMANENT));
-        suggestions.add(new Suggestion(before, "null", false, MAX_RATE, Suggestion.TYPE_PERMANENT));
+    private void suggestDefaultApp(MainPack info, List<Suggestion> suggestions, String afterLastSpace, String beforeLastSpace ) {
+        suggestions.add(new Suggestion(beforeLastSpace , "most_used", false, MAX_RATE, Suggestion.TYPE_PERMANENT));
+        suggestions.add(new Suggestion(beforeLastSpace , "null", false, MAX_RATE, Suggestion.TYPE_PERMANENT));
 
         List<AppsManager.LaunchInfo> apps = info.appsManager.shownApps();
         if(apps == null) return;
 
-        if (prev == null || prev.length() == 0) {
+        if (afterLastSpace == null || afterLastSpace.length() == 0) {
             for (AppsManager.LaunchInfo a : apps) {
-                suggestions.add(new Suggestion(before, a.publicLabel, clickToLaunch, NO_RATE, Suggestion.TYPE_APP, a));
+                suggestions.add(new Suggestion(beforeLastSpace , a.publicLabel, clickToLaunch, NO_RATE, Suggestion.TYPE_APP, a));
             }
         }
         else {
-            List<SimpleMutableEntry<Compare.Stringable, Integer>> infos = Compare.matchesWithRate(apps, true, prev);
+            List<SimpleMutableEntry<Compare.Stringable, Integer>> infos = Compare.matchesWithRate(apps, true, afterLastSpace);
             for(SimpleMutableEntry<Compare.Stringable, Integer> i : infos) {
-                suggestions.add(new Suggestion(before, i.getKey().getString(), clickToLaunch, i.getValue(), Suggestion.TYPE_APP, i.getKey()));
+                suggestions.add(new Suggestion(beforeLastSpace , i.getKey().getString(), clickToLaunch, i.getValue(), Suggestion.TYPE_APP, i.getKey()));
             }
         }
     }
 
-    private void suggestConfigEntry(List<Suggestion> suggestions, String prev, String before) {
+    private void suggestConfigEntry(List<Suggestion> suggestions, String afterLastSpace, String beforeLastSpace ) {
         if(xmlPrefsEntrys == null) {
             xmlPrefsEntrys = new ArrayList<>();
 
@@ -522,11 +524,12 @@ public class SuggestionsManager {
 
             Collections.addAll(xmlPrefsEntrys, Apps.values());
             Collections.addAll(xmlPrefsEntrys, Notifications.values());
+            Collections.addAll(xmlPrefsEntrys, Rss.values());
         }
 
-        if(prev == null || prev.length() == 0) {
+        if(afterLastSpace == null || afterLastSpace.length() == 0) {
             for(XMLPrefsManager.XMLPrefsSave s : xmlPrefsEntrys) {
-                Suggestion sg = new Suggestion(before, s.label(), false, NO_RATE, Suggestion.TYPE_COMMAND);
+                Suggestion sg = new Suggestion(beforeLastSpace , s.label(), false, NO_RATE, Suggestion.TYPE_COMMAND);
                 suggestions.add(sg);
             }
         }
@@ -535,86 +538,87 @@ public class SuggestionsManager {
                 if(Thread.currentThread().isInterrupted()) return;
 
                 String label = s.label();
-                int rate = Compare.matches(label, prev, true);
+                int rate = Compare.matches(label, afterLastSpace, true);
                 if(rate != -1) {
-                    suggestions.add(new Suggestion(before, label, false, rate, Suggestion.TYPE_COMMAND));
+                    suggestions.add(new Suggestion(beforeLastSpace , label, false, rate, Suggestion.TYPE_COMMAND));
                 }
             }
         }
     }
 
-    private void suggestConfigFile(List<Suggestion> suggestions, String prev, String before) {
+    private void suggestConfigFile(List<Suggestion> suggestions, String afterLastSpace, String beforeLastSpace ) {
         if(xmlPrefsFiles == null) {
             xmlPrefsFiles = new ArrayList<>();
             for(XMLPrefsManager.XMLPrefsRoot element : XMLPrefsManager.XMLPrefsRoot.values())
                 xmlPrefsFiles.add(element.path);
             xmlPrefsFiles.add(AppsManager.PATH);
             xmlPrefsFiles.add(NotificationManager.PATH);
+            xmlPrefsFiles.add(RssManager.PATH);
         }
 
-        if(prev == null || prev.length() == 0) {
+        if(afterLastSpace == null || afterLastSpace.length() == 0) {
             for(String s : xmlPrefsFiles) {
-                Suggestion sg = new Suggestion(before, s, false, NO_RATE, Suggestion.TYPE_FILE);
+                Suggestion sg = new Suggestion(beforeLastSpace , s, false, NO_RATE, Suggestion.TYPE_FILE);
                 suggestions.add(sg);
             }
-        } else if(prev.length() <= FIRST_INTERVAL) {
-            prev = prev.trim().toLowerCase();
+        } else if(afterLastSpace.length() <= FIRST_INTERVAL) {
+            afterLastSpace = afterLastSpace.trim().toLowerCase();
             for (String s : xmlPrefsFiles) {
                 if(Thread.currentThread().isInterrupted()) return;
 
-                if(s.startsWith(prev)) {
-                    suggestions.add(new Suggestion(before, s, false, MAX_RATE, Suggestion.TYPE_FILE));
+                if(s.startsWith(afterLastSpace)) {
+                    suggestions.add(new Suggestion(beforeLastSpace , s, false, MAX_RATE, Suggestion.TYPE_FILE));
                 }
             }
         }
     }
 
-    private void suggestAppGroup(List<Suggestion> suggestions, String prev, String before) {
+    private void suggestAppGroup(List<Suggestion> suggestions, String afterLastSpace, String beforeLastSpace ) {
         List<AppsManager.Group> groups = AppsManager.groups;
 
-        if(prev == null || prev.length() == 0) {
+        if(afterLastSpace == null || afterLastSpace.length() == 0) {
             for(AppsManager.Group g : groups) {
-                Suggestion sg = new Suggestion(before, g.getName(), false, NO_RATE, Suggestion.TYPE_APP, g);
+                Suggestion sg = new Suggestion(beforeLastSpace , g.getName(), false, NO_RATE, Suggestion.TYPE_APP, g);
                 suggestions.add(sg);
             }
         }
         else {
             for(AppsManager.Group g : groups) {
                 String label = g.getName();
-                int rate = Compare.matches(label, prev, true);
+                int rate = Compare.matches(label, afterLastSpace, true);
                 if(rate != -1) {
-                    suggestions.add(new Suggestion(before, label, false, rate, Suggestion.TYPE_APP, g));
+                    suggestions.add(new Suggestion(beforeLastSpace , label, false, rate, Suggestion.TYPE_APP, g));
                 }
             }
         }
     }
 
-    private boolean suggestAppInsideGroup(List<Suggestion> suggestions, String prev, String before, boolean keepGroupName) {
+    private boolean suggestAppInsideGroup(List<Suggestion> suggestions, String afterLastSpace, String beforeLastSpace , boolean keepGroupName) {
         int index = -1;
 
         String app = Tuils.EMPTYSTRING;
 
-        if(!before.contains(Tuils.SPACE)) {
-            index = Tuils.find(before, AppsManager.groups);
-            app = prev;
-            if(!keepGroupName) before = Tuils.EMPTYSTRING;
+        if(!beforeLastSpace .contains(Tuils.SPACE)) {
+            index = Tuils.find(beforeLastSpace , AppsManager.groups);
+            app = afterLastSpace;
+            if(!keepGroupName) beforeLastSpace  = Tuils.EMPTYSTRING;
         } else {
-            String[] split = before.split(Tuils.SPACE);
+            String[] split = beforeLastSpace .split(Tuils.SPACE);
             for(int count = 0; count < split.length; count++) {
                 index = Tuils.find(split[count], AppsManager.groups);
                 if(index != -1) {
 
-                    before = Tuils.EMPTYSTRING;
+                    beforeLastSpace  = Tuils.EMPTYSTRING;
                     for(int i = 0; (keepGroupName ? i <= count : i < count); i++) {
-                        before = before + split[i] + Tuils.SPACE;
+                        beforeLastSpace  = beforeLastSpace  + split[i] + Tuils.SPACE;
                     }
-                    before = before.trim();
+                    beforeLastSpace  = beforeLastSpace .trim();
 
                     count += 1;
                     for(; count < split.length; count++) {
                         app = app + split[count] + Tuils.SPACE;
                     }
-                    if(prev != null) app = app + Tuils.SPACE + prev;
+                    if(afterLastSpace != null) app = app + Tuils.SPACE + afterLastSpace;
                     app = app.trim();
 
                     break;
@@ -630,13 +634,13 @@ public class SuggestionsManager {
         if(apps != null && apps.size() > 0) {
             if (app == null || app.length() == 0) {
                 for (Compare.Stringable s : apps) {
-                    suggestions.add(new Suggestion(before, s.getString(), clickToLaunch, NO_RATE, Suggestion.TYPE_APP, s));
+                    suggestions.add(new Suggestion(beforeLastSpace , s.getString(), clickToLaunch, NO_RATE, Suggestion.TYPE_APP, s));
                 }
             }
             else {
                 List<SimpleMutableEntry<Compare.Stringable, Integer>> infos = Compare.matchesWithRate(apps, true, app);
                 for(SimpleMutableEntry<Compare.Stringable, Integer> i : infos) {
-                    suggestions.add(new Suggestion(before, i.getKey().getString(), clickToLaunch, i.getValue(), Suggestion.TYPE_APP, i.getKey()));
+                    suggestions.add(new Suggestion(beforeLastSpace , i.getKey().getString(), clickToLaunch, i.getValue(), Suggestion.TYPE_APP, i.getKey()));
                 }
             }
         }
@@ -665,12 +669,12 @@ public class SuggestionsManager {
 
         public Object object;
 
-        public Suggestion(String before, String text, boolean exec, int rate, int type) {
-            this(before, text, exec, rate, type, null);
+        public Suggestion(String beforeLastSpace , String text, boolean exec, int rate, int type) {
+            this(beforeLastSpace , text, exec, rate, type, null);
         }
 
-        public Suggestion(String before, String text, boolean exec, int rate, int type, Object tag) {
-            this.textBefore = before;
+        public Suggestion(String beforeLastSpace , String text, boolean exec, int rate, int type, Object tag) {
+            this.textBefore = beforeLastSpace ;
             this.text = text;
 
             this.exec = exec;
diff --git a/app/src/main/java/ohi/andre/consolelauncher/managers/xml/XMLPrefsManager.java b/app/src/main/java/ohi/andre/consolelauncher/managers/xml/XMLPrefsManager.java
index c493900..7dce317 100755
--- a/app/src/main/java/ohi/andre/consolelauncher/managers/xml/XMLPrefsManager.java
+++ b/app/src/main/java/ohi/andre/consolelauncher/managers/xml/XMLPrefsManager.java
@@ -14,6 +14,7 @@ import java.io.StringWriter;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
+import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
 import javax.xml.parsers.DocumentBuilder;
@@ -24,8 +25,12 @@ import javax.xml.transform.TransformerFactory;
 import javax.xml.transform.dom.DOMSource;
 import javax.xml.transform.stream.StreamResult;
 
-import ohi.andre.consolelauncher.R;
-import ohi.andre.consolelauncher.managers.xml.options.*;
+import ohi.andre.consolelauncher.managers.xml.options.Behavior;
+import ohi.andre.consolelauncher.managers.xml.options.Cmd;
+import ohi.andre.consolelauncher.managers.xml.options.Suggestions;
+import ohi.andre.consolelauncher.managers.xml.options.Theme;
+import ohi.andre.consolelauncher.managers.xml.options.Toolbar;
+import ohi.andre.consolelauncher.managers.xml.options.Ui;
 import ohi.andre.consolelauncher.tuils.Tuils;
 
 public class XMLPrefsManager {
@@ -44,8 +49,13 @@ public class XMLPrefsManager {
     }
 
     public interface XMLPrefsSave {
+
+        String APP = "app", INTEGER = "int", BOOLEAN = "boolean", TEXT = "text", COLOR = "color";
+
         String defaultValue();
         String label();
+        String type();
+        String info();
         XmlPrefsElement parent();
         boolean is(String s);
     }
@@ -55,13 +65,13 @@ public class XMLPrefsManager {
         THEME("theme.xml", Theme.values()) {
             @Override
             public String[] deleted() {
-                return new String[0];
+                return new String[] {"rss_color"};
             }
         },
         CMD("cmd.xml", Cmd.values()) {
             @Override
             public String[] deleted() {
-                return new String[] {"time_format"};
+                return new String[] {"time_format", "default_translatefrom", "default_translateto"};
             }
         },
         TOOLBAR("toolbar.xml", Toolbar.values()) {
@@ -73,13 +83,15 @@ public class XMLPrefsManager {
         UI("ui.xml", Ui.values()) {
             @Override
             public String[] deleted() {
-                return new String[] {"show_timestamp_before_cmd", "linux_like", "show_username_ssninfo", "show_ssninfo", "show_path_ssninfo", "show_devicename_ssninfo", "show_alias_suggestions", "transparent_bars"};
+                return new String[] {"status_line0_alignment", "status_line1_alignment", "status_line2_alignment", "status_line3_alignment", "status_line4_alignment", "status_line5_alignment",
+                        "font_size", "show_timestamp_before_cmd", "linux_like", "show_username_ssninfo", "show_ssninfo", "show_path_ssninfo", "show_devicename_ssninfo", "show_alias_suggestions",
+                        "transparent_bars"};
             }
         },
         BEHAVIOR("behavior.xml", Behavior.values()) {
             @Override
             public String[] deleted() {
-                return new String[] {"double_tap_closes", "donation_message"};
+                return new String[] {"double_tap_closes", "donation_message", "tui_notification_cmd_label", "autolower_firstchar", "long_click_vibrate", "long_click_vibrate_duration"};
             }
         },
         SUGGESTIONS("suggestions.xml", Suggestions.values()) {
@@ -109,7 +121,7 @@ public class XMLPrefsManager {
 
         @Override
         public void write(XMLPrefsSave save, String value) {
-            set(new File(Tuils.getFolder(), path), name(), save.label(), new String[] {VALUE_ATTRIBUTE}, new String[] {value});
+            set(new File(Tuils.getFolder(), path), save.label(), new String[] {VALUE_ATTRIBUTE}, new String[] {value});
         }
 
         public XMLPrefsList getValues() {
@@ -183,6 +195,8 @@ public class XMLPrefsManager {
 
     static boolean called = false;
     public static void create(Context context) throws Exception {
+        boolean timeFound = false;
+
         if(called) return;
         called = true;
 
@@ -197,9 +211,12 @@ public class XMLPrefsManager {
             Object[] o;
             try {
                 o = buildDocument(file, element.name());
+                if(o == null) {
+                    Tuils.sendXMLParseError(context, element.path);
+                    return;
+                }
             } catch (Exception e) {
-                Tuils.sendOutput(Color.RED, context, context.getString(R.string.output_xmlproblem1) + Tuils.SPACE + element.path + context.getString(R.string.output_xmlproblem2) +
-                        Tuils.NEWLINE + context.getString(R.string.output_errorlabel) + e.toString());
+                Tuils.sendXMLParseError(context, element.path, e);
                 continue;
             }
 
@@ -221,9 +238,137 @@ public class XMLPrefsManager {
 
             for(int count = 0; count < nodes.getLength(); count++) {
                 Node node = nodes.item(count);
-
                 String nn = node.getNodeName();
-                element.values.add(nn, node.getAttributes().getNamedItem(VALUE_ATTRIBUTE).getNodeValue());
+                String value = node.getAttributes().getNamedItem(VALUE_ATTRIBUTE).getNodeValue();
+
+//                remove this in a month?
+                if(!timeFound && nn.equals(Behavior.time_format.label()) && value.contains("%")) {
+                    timeFound = true;
+
+                    Pattern p = Pattern.compile("%(.{1})");
+                    Matcher m = p.matcher(value);
+                    while(m.find()) {
+                        char charc = m.group(1).charAt(0);
+
+                        String replaceWith = null;
+                        switch (charc) {
+                            case 'a':
+                                replaceWith = "EE";
+                                break;
+                            case 'A':
+                                replaceWith = "E";
+                                break;
+                            case 'b':
+                                replaceWith = "MM";
+                                break;
+                            case 'B':
+                                replaceWith = "M";
+                                break;
+                            case 'c':
+                                replaceWith = "EE MM dd HH:mm:ss yyyy";
+                                break;
+                            case 'C':
+                                break;
+                            case 'd':
+                                replaceWith = "dd";
+                                break;
+                            case 'D':
+                                replaceWith = "MM dd yyyy";
+                                break;
+                            case 'e':
+                                replaceWith = "dd";
+                                break;
+                            case 'F':
+                                replaceWith = "yyyy-MMM-dd";
+                                break;
+                            case 'g':
+                                break;
+                            case 'G':
+                                break;
+                            case 'h':
+                                replaceWith = "MMM";
+                                break;
+                            case 'H':
+                                replaceWith = "HH";
+                                break;
+                            case 'I':
+                                replaceWith = "hh";
+                                break;
+                            case 'j':
+                                replaceWith = "DDD";
+                                break;
+                            case 'k':
+                                replaceWith = "HH";
+                                break;
+                            case 'l':
+                                replaceWith = "hh";
+                                break;
+                            case 'm':
+                                replaceWith = "MM";
+                                break;
+                            case 'M':
+                                replaceWith = "mm";
+                                break;
+                            case 'n':
+                                break;
+                            case 'N':
+                                break;
+                            case 'p':
+                                replaceWith = "a";
+                                break;
+                            case 'P':
+                                break;
+                            case 'r':
+                                replaceWith = "KK:mm:ss a";
+                                break;
+                            case 'R':
+                                replaceWith = "HH:mm";
+                                break;
+                            case 's':
+                                break;
+                            case 'S':
+                                replaceWith = "s";
+                                break;
+                            case 't':
+                                break;
+                            case 'T':
+                                replaceWith = "HH:mm:ss";
+                                break;
+                            case 'u':
+                                replaceWith = "u";
+                                break;
+                            case 'U':
+                                replaceWith = "w";
+                                break;
+                            case 'V':
+                                break;
+                            case 'w':
+                                replaceWith = "u";
+                                break;
+                            case 'W':
+                                replaceWith = "w";
+                                break;
+                            case 'x':
+                                replaceWith = "MMM/dd/yyyy";
+                                break;
+                            case 'X':
+                                replaceWith = "HH:mm:ss";
+                                break;
+                            case 'y':
+                                replaceWith = "yy";
+                                break;
+                            case 'Y':
+                                replaceWith = "yyyy";
+                                break;
+                        }
+
+                        if(replaceWith != null) value = value.replaceAll(m.group(0), replaceWith);
+                    }
+
+                    ((Element) node).setAttribute(VALUE_ATTRIBUTE, value);
+                }
+
+                element.values.add(nn, value);
 
                 for(int en = 0; en < enums.size(); en++) {
                     if(enums.get(en).label().equals(nn)) {
@@ -296,12 +441,24 @@ public class XMLPrefsManager {
         return s;
     }
 
+//    rootName is needed in order to rebuild the file if it's corrupted
 //    [0] = document
 //    [1] = root
-    public static Object[] buildDocument(File file, String root) throws Exception {
-        Document d = builder.parse(file);
-        Element r = (Element) d.getElementsByTagName(root).item(0);
+    public static Object[] buildDocument(File file, String rootName) throws Exception {
+        Document d;
+        try {
+            d = builder.parse(file);
+        } catch (Exception e) {
+            Tuils.log(e);
 
+            int nOfBytes = Tuils.nOfBytes(file);
+            Tuils.log("nof", nOfBytes);
+            if(nOfBytes == 0 && rootName != null) {
+                XMLPrefsManager.resetFile(file, rootName);
+                d = builder.parse(file);
+            } else return null;
+        }
+        Element r = d.getDocumentElement();
         return new Object[] {d, r};
     }
 
@@ -322,15 +479,18 @@ public class XMLPrefsManager {
 
             stream.flush();
             stream.close();
-        } catch (Exception e) {}
+        } catch (Exception e) {
+            Tuils.log(e);
+        }
     }
 
 //    this will only add, it won't check if there's already one
-    public static String add(File file, String rootName, String elementName, String[] attributeNames, String[] attributeValues) {
+    public static String add(File file, String elementName, String[] attributeNames, String[] attributeValues) {
         try {
             Object[] o;
             try {
-                o = buildDocument(file, rootName);
+                o = buildDocument(file, null);
+                if(o == null) return Tuils.EMPTYSTRING;
             } catch (Exception e) {
                 Tuils.log(e);
                 return e.toString();
@@ -354,33 +514,42 @@ public class XMLPrefsManager {
         return null;
     }
 
-    public static String set(File file, String rootName, String elementName, String[] attributeNames, String[] attributeValues) {
-        return set(file, rootName, elementName, null, null, attributeNames, attributeValues, true);
+    public static String set(File file, String elementName, String[] attributeNames, String[] attributeValues) {
+        return set(file, elementName, null, null, attributeNames, attributeValues, true);
     }
 
-    public static String set(File file, String rootName, String elementName, String[] thatHasThose, String[] forValues, String[] attributeNames, String[] attributeValues, boolean addIfNotFound) {
+    public static String set(File file, String elementName, String[] thatHasThose, String[] forValues, String[] attributeNames, String[] attributeValues, boolean addIfNotFound) {
         String[][] values = new String[1][attributeValues.length];
         values[0] = attributeValues;
 
-        return setMany(file, rootName, new String[] {elementName}, thatHasThose, forValues, attributeNames, values, addIfNotFound);
+        return setMany(file, new String[] {elementName}, thatHasThose, forValues, attributeNames, values, addIfNotFound);
     }
 
-    public static String setMany(File file, String rootName, String elementNames[], String[] attributeNames, String[][] attributeValues) {
-        return setMany(file, rootName, elementNames, null, null, attributeNames, attributeValues, true);
+    public static String setMany(File file, String elementNames[], String[] attributeNames, String[][] attributeValues) {
+        return setMany(file, elementNames, null, null, attributeNames, attributeValues, true);
     }
 
-    public static String setMany(File file, String rootName, String elementNames[], String[] thatHasThose, String[] forValues, String[] attributeNames, String[][] attributeValues, boolean addIfNotFound) {
+    public static String setMany(File file, String elementNames[], String[] thatHasThose, String[] forValues, String[] attributeNames, String[][] attributeValues, boolean addIfNotFound) {
         try {
             Object[] o;
             try {
-                o = buildDocument(file, rootName);
+                o = buildDocument(file, null);
+                if(o == null) return Tuils.EMPTYSTRING;
             } catch (Exception e) {
+                Tuils.log(e);
                 return e.toString();
             }
 
             Document d = (Document) o[0];
             Element root = (Element) o[1];
 
+            if(d == null || root == null) {
+                Tuils.log("document is null or root is null");
+                return Tuils.EMPTYSTRING;
+            }
+
+            int nFound = 0;
+
             Main:
             for(int c = 0; c < elementNames.length; c++) {
                 NodeList nodes = root.getElementsByTagName(elementNames[c]);
@@ -391,57 +560,60 @@ public class XMLPrefsManager {
                     if(n.getNodeType() == Node.ELEMENT_NODE) {
                         Element e = (Element) n;
 
-                        if(checkAttributes(e, thatHasThose, forValues)) continue Nodes;
+                        if(!checkAttributes(e, thatHasThose, forValues)) {
+                            continue Nodes;
+                        }
+
+                        nFound++;
 
                         for(int a = 0; a < attributeNames.length; a++) {
                             e.setAttribute(attributeNames[a], attributeValues[c][a]);
                         }
 
                         elementNames[c] = null;
+
                         continue Main;
                     }
                 }
             }
 
-            boolean notFoundSomething = false;
+            if(nFound < elementNames.length) {
+                for (int count = 0; count < elementNames.length; count++) {
+                    if (elementNames[count] == null || elementNames[count].length() == 0) continue;
 
-//            not found
-            for(int count = 0; count < elementNames.length; count++) {
-                if(elementNames[count] == null || elementNames[count].length() == 0) continue;
+                    if (!addIfNotFound) continue;
 
-                notFoundSomething = true;
-
-                if(!addIfNotFound) continue;
-
-                Element element = d.createElement(elementNames[count]);
-                for(int c = 0; c < attributeNames.length; c++) {
-                    if(attributeValues[count][c] == null) continue;
-                    element.setAttribute(attributeNames[c], attributeValues[count][c]);
+                    Element element = d.createElement(elementNames[count]);
+                    for (int c = 0; c < attributeNames.length; c++) {
+                        if (attributeValues[count][c] == null) continue;
+                        element.setAttribute(attributeNames[c], attributeValues[count][c]);
+                    }
+                    root.appendChild(element);
                 }
-                root.appendChild(element);
             }
 
             writeTo(d, file);
 
-            if(notFoundSomething) return Tuils.EMPTYSTRING;
+            if(nFound == 0) return Tuils.EMPTYSTRING;
+            return null;
         } catch (Exception e) {
             Tuils.log(e);
             Tuils.toFile(e);
             return e.toString();
         }
-        return null;
     }
 
 //    return "" if node not found, null if all good
-    public static String removeNode(File file, String rootName, String nodeName) {
-        return removeNode(file, rootName, nodeName, null, null);
+    public static String removeNode(File file, String nodeName) {
+        return removeNode(file, nodeName, null, null);
     }
 
-    public static String removeNode(File file, String rootName, String nodeName, String[] thatHasThose, String[] forValues) {
+    public static String removeNode(File file, String nodeName, String[] thatHasThose, String[] forValues) {
         try {
             Object[] o;
             try {
-                o = buildDocument(file, rootName);
+                o = buildDocument(file, null);
+                if(o == null) return Tuils.EMPTYSTRING;
             } catch (Exception e) {
                 return e.toString();
             }
@@ -449,70 +621,71 @@ public class XMLPrefsManager {
             Document d = (Document) o[0];
             Element root = (Element) o[1];
 
-            NodeList nodeList = root.getElementsByTagName(nodeName);
-            if(nodeList == null || nodeList.getLength() == 0) return Tuils.EMPTYSTRING;
-
-            for(int c = 0; c < nodeList.getLength(); c++) {
-                Node n = nodeList.item(c);
+            Node n = findNode(root, nodeName, thatHasThose, forValues);
+            if(n == null) return Tuils.EMPTYSTRING;
 
-                if (n.getNodeType() == Node.ELEMENT_NODE && !checkAttributes((Element) n, thatHasThose, forValues))
-                    continue;
+            root.removeChild(n);
+            writeTo(d, file);
 
-                root.removeChild(n);
-                writeTo(d, file);
-                return null;
-            }
+            return null;
         } catch (Exception e) {
             return e.toString();
         }
+    }
 
-        return Tuils.EMPTYSTRING;
+    public static Node findNode(File file, String nodeName) {
+        return findNode(file, nodeName, null, null);
     }
 
-    public static Node findNode(File file, String rootName, String nodeName) {
+    public static Node findNode(File file, String nodeName, String[] thatHasThose, String[] forValues) {
         try {
             Object[] o;
             try {
-                o = buildDocument(file, rootName);
+                o = buildDocument(file, null);
+                if(o == null) return null;
             } catch (Exception e) {
                 return null;
             }
 
             Element root = (Element) o[1];
 
-            findNode(root, nodeName);
+            return findNode(root, nodeName, thatHasThose, forValues);
         } catch (Exception e) {
             return null;
         }
-
-        return null;
     }
 
     public static Node findNode(Element root, String nodeName) {
+        return findNode(root, nodeName, null, null);
+    }
+
+//    useful only if you're looking for a single node
+    public static Node findNode(Element root, String nodeName, String[] thatHasThose, String[] forValues) {
         NodeList nodes = root.getElementsByTagName(nodeName);
-        if(nodes.getLength() == 0) return null;
-        return nodes.item(0);
+        for(int j = 0; j < nodes.getLength(); j++) if(checkAttributes((Element) nodes.item(j), thatHasThose, forValues)) return nodes.item(j);
+        return null;
     }
 
-    public static String attrValue(File file, String rootName, String nodeName, String attrName) {
-        return attrValue(file, rootName, nodeName, null, null, attrName);
+    public static String attrValue(File file, String nodeName, String attrName) {
+        return attrValue(file, nodeName, null, null, attrName);
     }
 
-    public static String attrValue(File file, String rootName, String nodeName, String[] thatHasThose, String[] forValues, String attrName) {
-        String[] vs = attrValues(file, rootName, nodeName, thatHasThose, forValues, new String[] {attrName});
+    public static String attrValue(File file, String nodeName, String[] thatHasThose, String[] forValues, String attrName) {
+        String[] vs = attrValues(file, nodeName, thatHasThose, forValues, new String[] {attrName});
         if(vs != null && vs.length > 0) return vs[0];
         return null;
     }
 
-    public static String[] attrValues(File file, String rootName, String nodeName, String[] attrNames) {
-        return attrValues(file, rootName, nodeName, null, null, attrNames);
+    public static String[] attrValues(File file, String nodeName, String[] attrNames) {
+        return attrValues(file, nodeName, null, null, attrNames);
     }
 
-    public static String[] attrValues(File file, String rootName, String nodeName, String[] thatHasThose, String[] forValues, String[] attrNames) {
+    public static String[] attrValues(File file, String nodeName, String[] thatHasThose, String[] forValues, String[] attrNames) {
         try {
             Object[] o;
             try {
-                o = buildDocument(file, rootName);
+                o = buildDocument(file, null);
+                if(o == null) return null;
             } catch (Exception e) {
                 return null;
             }
@@ -539,7 +712,8 @@ public class XMLPrefsManager {
     private static boolean checkAttributes(Element e, String[] thatHasThose, String[] forValues) {
         if(thatHasThose != null && forValues != null && thatHasThose.length == forValues.length) {
             for(int a = 0; a < thatHasThose.length; a++) {
-                if(!e.hasAttribute(thatHasThose[a]) || !forValues[a].equals(e.getAttribute(thatHasThose[a]))) return false;
+                if(!e.hasAttribute(thatHasThose[a])) return false;
+                if(!forValues[a].equals(e.getAttribute(thatHasThose[a]))) return false;
             }
         }
         return true;
@@ -586,6 +760,7 @@ public class XMLPrefsManager {
 
     public static <T> T get(Class<T> c, XMLPrefsManager.XMLPrefsSave prefsSave) {
         try {
+            Tuils.log("list", prefsSave.parent().getValues().values().toString());
             return (T) transform(prefsSave.parent().getValues().get(prefsSave).value, c);
         } catch (Exception e) {
             Tuils.log(e);
@@ -616,6 +791,30 @@ public class XMLPrefsManager {
         }
     }
 
+    public static String getStringAttribute(Element e, String attribute) {
+        return e.hasAttribute(attribute) ? e.getAttribute(attribute) : null;
+    }
+
+    public static long getLongAttribute(Element e, String attribute) {
+        String value = getStringAttribute(e, attribute);
+        if(value == null) return -1;
+        return Long.parseLong(value);
+    }
+
+    public static boolean getBooleanAttribute(Element e, String attribute) {
+        return Boolean.parseBoolean(getStringAttribute(e, attribute));
+    }
+
+    public static class IdValue {
+        public String value;
+        public int id;
+
+        public IdValue(String value, int id) {
+            this.value = value;
+            this.id = id;
+        }
+    }
+
 //    private static HashMap<XMLPrefsSave, String> getOld(BufferedReader reader) {
 //        HashMap<XMLPrefsSave, String> map = new HashMap<>();
 //
diff --git a/app/src/main/java/ohi/andre/consolelauncher/managers/xml/options/Apps.java b/app/src/main/java/ohi/andre/consolelauncher/managers/xml/options/Apps.java
index d775371..5068a24 100644
--- a/app/src/main/java/ohi/andre/consolelauncher/managers/xml/options/Apps.java
+++ b/app/src/main/java/ohi/andre/consolelauncher/managers/xml/options/Apps.java
@@ -14,30 +14,55 @@ public enum Apps implements XMLPrefsManager.XMLPrefsSave {
         public String defaultValue() {
             return MOST_USED;
         }
+
+        @Override
+        public String info() {
+            return "The first default-suggested app";
+        }
     },
     default_app_n2 {
         @Override
         public String defaultValue() {
             return MOST_USED;
         }
+
+        @Override
+        public String info() {
+            return "The second default-suggested app";
+        }
     },
     default_app_n3 {
         @Override
         public String defaultValue() {
             return "com.android.vending";
         }
+
+        @Override
+        public String info() {
+            return "The third default-suggested app";
+        }
     },
     default_app_n4 {
         @Override
         public String defaultValue() {
             return NULL;
         }
+
+        @Override
+        public String info() {
+            return "The fourth default-suggested app";
+        }
     },
     default_app_n5 {
         @Override
         public String defaultValue() {
             return NULL;
         }
+
+        @Override
+        public String info() {
+            return "The fifth default-suggested app";
+        }
     };
 
     public static final String MOST_USED = "most_used";
@@ -57,4 +82,9 @@ public enum Apps implements XMLPrefsManager.XMLPrefsSave {
     public boolean is(String s) {
         return name().equals(s);
     }
+
+    @Override
+    public String type() {
+        return XMLPrefsManager.XMLPrefsSave.APP;
+    }
 }
diff --git a/app/src/main/java/ohi/andre/consolelauncher/managers/xml/options/Behavior.java b/app/src/main/java/ohi/andre/consolelauncher/managers/xml/options/Behavior.java
index ae2e396..a72ddfe 100644
--- a/app/src/main/java/ohi/andre/consolelauncher/managers/xml/options/Behavior.java
+++ b/app/src/main/java/ohi/andre/consolelauncher/managers/xml/options/Behavior.java
@@ -18,89 +18,255 @@ public enum Behavior implements XMLPrefsManager.XMLPrefsSave {
         public String defaultValue() {
             return "true";
         }
+
+        @Override
+        public String info() {
+            return "If true, t-ui will lock the screen on double tap";
+        }
+
+        @Override
+        public String type() {
+            return XMLPrefsManager.XMLPrefsSave.BOOLEAN;
+        }
     },
     double_tap_cmd {
         @Override
         public String defaultValue() {
             return "";
         }
+
+        @Override
+        public String info() {
+            return "The command that will run when you touch two times the screen quickly";
+        }
+
+        @Override
+        public String type() {
+            return XMLPrefsManager.XMLPrefsSave.TEXT;
+        }
     },
     random_play {
         @Override
         public String defaultValue() {
             return "true";
         }
+
+        @Override
+        public String info() {
+            return "If true, music player will play your tracks in random order";
+        }
+
+        @Override
+        public String type() {
+            return XMLPrefsManager.XMLPrefsSave.BOOLEAN;
+        }
     },
     songs_folder {
         @Override
         public String defaultValue() {
             return "";
         }
+
+        @Override
+        public String info() {
+            return "The folder that contains your music files";
+        }
+
+        @Override
+        public String type() {
+            return XMLPrefsManager.XMLPrefsSave.TEXT;
+        }
     },
     songs_from_mediastore {
         @Override
         public String defaultValue() {
             return "true";
         }
+
+        @Override
+        public String info() {
+            return "If true, t-ui will get tracks from the system mediastore";
+        }
+
+        @Override
+        public String type() {
+            return XMLPrefsManager.XMLPrefsSave.BOOLEAN;
+        }
     },
     tui_notification {
         @Override
         public String defaultValue() {
             return "false";
         }
+
+        @Override
+        public String info() {
+            return "If true, there will always be a notification in your status bar, telling you that t-ui is running";
+        }
+
+        @Override
+        public String type() {
+            return XMLPrefsManager.XMLPrefsSave.BOOLEAN;
+        }
     },
     auto_show_keyboard {
         @Override
         public String defaultValue() {
             return "true";
         }
+
+        @Override
+        public String info() {
+            return "If true, your keyboard will be shown everytime you go back to t-ui";
+        }
+
+        @Override
+        public String type() {
+            return XMLPrefsManager.XMLPrefsSave.BOOLEAN;
+        }
     },
     auto_scroll {
         @Override
         public String defaultValue() {
             return "true";
         }
+
+        @Override
+        public String info() {
+            return "If true, the terminal will be automatically scrolled down when the keyboard is open";
+        }
+
+        @Override
+        public String type() {
+            return XMLPrefsManager.XMLPrefsSave.BOOLEAN;
+        }
     },
     show_hints {
         @Override
         public String defaultValue() {
             return "true";
         }
+
+        @Override
+        public String info() {
+            return "If true, t-ui will tell you some useful hints sometime";
+        }
+
+        @Override
+        public String type() {
+            return XMLPrefsManager.XMLPrefsSave.BOOLEAN;
+        }
     },
     show_alias_content {
         @Override
         public String defaultValue() {
             return "false";
         }
+
+        @Override
+        public String info() {
+            return "If true, when you use an alias you'll also be able to know what command has been executed";
+        }
+
+        @Override
+        public String type() {
+            return XMLPrefsManager.XMLPrefsSave.BOOLEAN;
+        }
     },
     show_launch_history {
         @Override
         public String defaultValue() {
             return "true";
         }
+
+        @Override
+        public String info() {
+            return "If false, t-ui won't show the apps that you launch";
+        }
+
+        @Override
+        public String type() {
+            return XMLPrefsManager.XMLPrefsSave.BOOLEAN;
+        }
     },
     clear_after_cmds {
         @Override
         public String defaultValue() {
             return "-1";
         }
+
+        @Override
+        public String info() {
+            return "Auto-clear after n commands (if -1, this feature will be disabled)";
+        }
+
+        @Override
+        public String type() {
+            return XMLPrefsManager.XMLPrefsSave.INTEGER;
+        }
     },
     clear_after_seconds {
         @Override
         public String defaultValue() {
             return "-1";
         }
+
+        @Override
+        public String info() {
+            return "Auto-clear after n seconds (if -1, this feature will be disabled)";
+        }
+
+        @Override
+        public String type() {
+            return XMLPrefsManager.XMLPrefsSave.INTEGER;
+        }
     },
     max_lines {
         @Override
         public String defaultValue() {
             return "-1";
         }
+
+        @Override
+        public String info() {
+            return "Set maximum number of lines that will be shown in the terminal (if -1, this feature is be disabled)";
+        }
+
+        @Override
+        public String type() {
+            return XMLPrefsManager.XMLPrefsSave.INTEGER;
+        }
     },
     time_format {
         @Override
         public String defaultValue() {
-            return "%m/%d/%y %H.%M";
+            return "d MMM yyyy HH:mm:ss@HH:mm:ss";
+        }
+
+        @Override
+        public String info() {
+            return "Define the time format (see also Time Format)";
+        }
+
+        @Override
+        public String type() {
+            return XMLPrefsManager.XMLPrefsSave.TEXT;
+        }
+    },
+    time_format_separator {
+        @Override
+        public String defaultValue() {
+            return "@";
+        }
+
+        @Override
+        public String info() {
+            return "This is the separator between your different time formats (see also Multiple time formats)";
+        }
+
+        @Override
+        public String type() {
+            return XMLPrefsManager.XMLPrefsSave.TEXT;
         }
     },
     battery_medium {
@@ -108,77 +274,191 @@ public enum Behavior implements XMLPrefsManager.XMLPrefsSave {
         public String defaultValue() {
             return "50";
         }
+
+        @Override
+        public String info() {
+            return "The percentage below which the battery level will be considered \"medium\"";
+        }
+
+        @Override
+        public String type() {
+            return XMLPrefsManager.XMLPrefsSave.INTEGER;
+        }
     },
     battery_low {
         @Override
         public String defaultValue() {
             return "15";
         }
+
+        @Override
+        public String info() {
+            return "The percentage below which the battery level will be considered \"low\"";
+        }
+
+        @Override
+        public String type() {
+            return XMLPrefsManager.XMLPrefsSave.INTEGER;
+        }
     },
     device_format {
         @Override
         public String defaultValue() {
             return "%d: %u";
         }
+
+        @Override
+        public String info() {
+            return "Define the device format";
+        }
+
+        @Override
+        public String type() {
+            return XMLPrefsManager.XMLPrefsSave.TEXT;
+        }
     },
     ram_format {
         @Override
         public String defaultValue() {
             return "Available RAM: %avgb GB of %totgb GB (%av%%)";
         }
+
+        @Override
+        public String info() {
+            return "Define the RAM format";
+        }
+
+        @Override
+        public String type() {
+            return XMLPrefsManager.XMLPrefsSave.TEXT;
+        }
     },
     battery_format {
         @Override
         public String defaultValue() {
             return "%(Charging: /)%v%";
         }
+
+        @Override
+        public String info() {
+            return "Define the battery format";
+        }
+
+        @Override
+        public String type() {
+            return XMLPrefsManager.XMLPrefsSave.TEXT;
+        }
     },
     storage_format {
         @Override
         public String defaultValue() {
             return "Internal Storage: %iavgb GB / %itotgb GB (%iav%%)";
         }
+
+        @Override
+        public String info() {
+            return "Define the storage format";
+        }
+
+        @Override
+        public String type() {
+            return XMLPrefsManager.XMLPrefsSave.TEXT;
+        }
     },
     network_info_format {
         @Override
         public String defaultValue() {
             return "%(WiFi - %wn/%[Mobile Data: %d3/No Internet access])";
         }
+
+        @Override
+        public String info() {
+            return "Define the network format";
+        }
+
+        @Override
+        public String type() {
+            return XMLPrefsManager.XMLPrefsSave.TEXT;
+        }
     },
     input_format {
         @Override
         public String defaultValue() {
             return "[%t] %p %i";
         }
+
+        @Override
+        public String info() {
+            return "Define the input format ";
+        }
+
+        @Override
+        public String type() {
+            return XMLPrefsManager.XMLPrefsSave.TEXT;
+        }
     },
     output_format {
         @Override
         public String defaultValue() {
             return "%o";
         }
+
+        @Override
+        public String info() {
+            return "Define the output format ";
+        }
+
+        @Override
+        public String type() {
+            return XMLPrefsManager.XMLPrefsSave.TEXT;
+        }
     },
     session_info_format {
         @Override
         public String defaultValue() {
             return "%u@%d:%p";
         }
+
+        @Override
+        public String info() {
+            return "Define the session info format";
+        }
+
+        @Override
+        public String type() {
+            return XMLPrefsManager.XMLPrefsSave.TEXT;
+        }
     },
     enable_app_launch {
         @Override
         public String defaultValue() {
             return "true";
         }
+
+        @Override
+        public String info() {
+            return "If false, you won't be able to launch apps from t-ui, unless you use \"apps -frc\"";
+        }
+
+        @Override
+        public String type() {
+            return XMLPrefsManager.XMLPrefsSave.BOOLEAN;
+        }
     },
     app_launch_format {
         @Override
         public String defaultValue() {
             return "--> %a";
         }
-    },
-    time_format_separator {
+
         @Override
-        public String defaultValue() {
-            return "@";
+        public String info() {
+            return "Define app launch format ";
+        }
+
+        @Override
+        public String type() {
+            return XMLPrefsManager.XMLPrefsSave.TEXT;
         }
     },
     alias_param_marker {
@@ -186,24 +466,64 @@ public enum Behavior implements XMLPrefsManager.XMLPrefsSave {
         public String defaultValue() {
             return "%";
         }
+
+        @Override
+        public String info() {
+            return "Define the marker that will be replaced with a provided param";
+        }
+
+        @Override
+        public String type() {
+            return XMLPrefsManager.XMLPrefsSave.TEXT;
+        }
     },
     alias_param_separator {
         @Override
         public String defaultValue() {
             return ",";
         }
+
+        @Override
+        public String info() {
+            return "Define the separator between a group of params";
+        }
+
+        @Override
+        public String type() {
+            return XMLPrefsManager.XMLPrefsSave.TEXT;
+        }
     },
     multiple_cmd_separator {
         @Override
         public String defaultValue() {
             return ";";
         }
+
+        @Override
+        public String info() {
+            return "The separator between two or more commands in a single input";
+        }
+
+        @Override
+        public String type() {
+            return XMLPrefsManager.XMLPrefsSave.TEXT;
+        }
     },
     alias_content_format {
         @Override
         public String defaultValue() {
             return "%a --> [%v]";
         }
+
+        @Override
+        public String info() {
+            return "Define the format used to show your alias contents ";
+        }
+
+        @Override
+        public String type() {
+            return XMLPrefsManager.XMLPrefsSave.TEXT;
+        }
     },
     external_storage_path {
         @Override
@@ -216,48 +536,288 @@ public enum Behavior implements XMLPrefsManager.XMLPrefsSave {
 
             return Tuils.EMPTYSTRING;
         }
+
+        @Override
+        public String info() {
+            return "The path to your external storage (used to evaluate free/total space)";
+        }
+
+        @Override
+        public String type() {
+            return XMLPrefsManager.XMLPrefsSave.TEXT;
+        }
     },
     home_path {
         @Override
         public String defaultValue() {
             return Environment.getExternalStorageDirectory().getAbsolutePath();
         }
+
+        @Override
+        public String info() {
+            return "The path to your home directory";
+        }
+
+        @Override
+        public String type() {
+            return XMLPrefsManager.XMLPrefsSave.TEXT;
+        }
     },
     app_installed_format {
         @Override
         public String defaultValue() {
             return "App installed: %p";
         }
+
+        @Override
+        public String info() {
+            return "The format of the \"app installed\" message ";
+        }
+
+        @Override
+        public String type() {
+            return XMLPrefsManager.XMLPrefsSave.TEXT;
+        }
     },
     app_uninstalled_format {
         @Override
         public String defaultValue() {
             return "App uninstalled: %p";
         }
+
+        @Override
+        public String info() {
+            return "The format of the \"app uninstalled\" message ";
+        }
+
+        @Override
+        public String type() {
+            return XMLPrefsManager.XMLPrefsSave.TEXT;
+        }
     },
     enable_music {
         @Override
         public String defaultValue() {
             return "true";
         }
-    },
-    autolower_firstchar {
+
         @Override
-        public String defaultValue() {
-            return "true";
+        public String info() {
+            return "If false, t-ui won't try to load music from your device on startup";
+        }
+
+        @Override
+        public String type() {
+            return XMLPrefsManager.XMLPrefsSave.BOOLEAN;
         }
     },
-    max_optional_depth_network_info {
+    max_optional_depth {
         @Override
         public String defaultValue() {
             return "2";
         }
+
+        @Override
+        public String info() {
+            return "A value which is used to tell how deep t-ui can go in a nested optional value";
+        }
+
+        @Override
+        public String type() {
+            return XMLPrefsManager.XMLPrefsSave.INTEGER;
+        }
     },
     network_info_update_ms {
         @Override
         public String defaultValue() {
             return "3500";
         }
+
+        @Override
+        public String info() {
+            return "The time between two network info updates";
+        }
+
+        @Override
+        public String type() {
+            return XMLPrefsManager.XMLPrefsSave.INTEGER;
+        }
+    },
+    tui_notification_title {
+        @Override
+        public String defaultValue() {
+            return "T-UI";
+        }
+
+        @Override
+        public String info() {
+            return "The title of the T-UI notification";
+        }
+
+        @Override
+        public String type() {
+            return XMLPrefsManager.XMLPrefsSave.TEXT;
+        }
+    },
+    tui_notification_subtitle {
+        @Override
+        public String defaultValue() {
+            return "T-UI is running";
+        }
+
+        @Override
+        public String info() {
+            return "The subtitle of the T-UI notification";
+        }
+
+        @Override
+        public String type() {
+            return XMLPrefsManager.XMLPrefsSave.TEXT;
+        }
+    },
+    tui_notification_click_cmd {
+        @Override
+        public String defaultValue() {
+            return "";
+        }
+
+        @Override
+        public String info() {
+            return "The command ran when the T-UI notification is clicked";
+        }
+
+        @Override
+        public String type() {
+            return XMLPrefsManager.XMLPrefsSave.TEXT;
+        }
+    },
+    tui_notification_click_showhome {
+        @Override
+        public String defaultValue() {
+            return "true";
+        }
+
+        @Override
+        public String info() {
+            return "If false, the click on the T-UI notification won't bring you to your phone home";
+        }
+
+        @Override
+        public String type() {
+            return XMLPrefsManager.XMLPrefsSave.BOOLEAN;
+        }
+    },
+    tui_notification_lastcmds_size {
+        @Override
+        public String defaultValue() {
+            return "5";
+        }
+
+        @Override
+        public String info() {
+            return "The number of used commands that will appear inside the T-UI notification (<0 will disable the feature)";
+        }
+
+        @Override
+        public String type() {
+            return XMLPrefsManager.XMLPrefsSave.INTEGER;
+        }
+    },
+    tui_notification_lastcmds_updown {
+        @Override
+        public String defaultValue() {
+            return "true";
+        }
+
+        @Override
+        public String info() {
+            return "If true, the last used command will appear on top\n";
+        }
+
+        @Override
+        public String type() {
+            return XMLPrefsManager.XMLPrefsSave.BOOLEAN;
+        }
+    },
+    tui_notification_priority {
+        @Override
+        public String defaultValue() {
+            return "0";
+        }
+
+        @Override
+        public String info() {
+            return "The priority of the T-UI notification (-2 maximum priority, 2 minimum)";
+        }
+
+        @Override
+        public String type() {
+            return XMLPrefsManager.XMLPrefsSave.INTEGER;
+        }
+    },
+    long_click_vibration_duration {
+        @Override
+        public String defaultValue() {
+            return "100";
+        }
+
+        @Override
+        public String info() {
+            return "The duration (in milliseconds) of the vibration when you long click a notification or an RSS item (<0 will disable the feature)";
+        }
+
+        @Override
+        public String type() {
+            return XMLPrefsManager.XMLPrefsSave.INTEGER;
+        }
+    },
+    long_click_duration {
+        @Override
+        public String defaultValue() {
+            return "700";
+        }
+
+        @Override
+        public String info() {
+            return "The minimum duration of the long click on a notification or an RSS item";
+        }
+
+        @Override
+        public String type() {
+            return XMLPrefsManager.XMLPrefsSave.INTEGER;
+        }
+    },
+    click_commands {
+        @Override
+        public String defaultValue() {
+            return "true";
+        }
+
+        @Override
+        public String info() {
+            return "If true, you will be able to use a command again clicking on it";
+        }
+
+        @Override
+        public String type() {
+            return XMLPrefsManager.XMLPrefsSave.BOOLEAN;
+        }
+    },
+    long_click_commands {
+        @Override
+        public String defaultValue() {
+            return "true";
+        }
+
+        @Override
+        public String info() {
+            return "If true, you will be able to put a used command in the input field long-clicking it";
+        }
+
+        @Override
+        public String type() {
+            return XMLPrefsManager.XMLPrefsSave.BOOLEAN;
+        }
     };
 
     @Override
diff --git a/app/src/main/java/ohi/andre/consolelauncher/managers/xml/options/Cmd.java b/app/src/main/java/ohi/andre/consolelauncher/managers/xml/options/Cmd.java
index 6a75bb2..b5615bf 100644
--- a/app/src/main/java/ohi/andre/consolelauncher/managers/xml/options/Cmd.java
+++ b/app/src/main/java/ohi/andre/consolelauncher/managers/xml/options/Cmd.java
@@ -13,6 +13,16 @@ public enum Cmd implements XMLPrefsManager.XMLPrefsSave {
         public String defaultValue() {
             return "-gg";
         }
+
+        @Override
+        public String info() {
+            return "The param that will be used if you type \"search apples\" instead of \"search -param apples\"";
+        }
+
+        @Override
+        public String type() {
+            return XMLPrefsManager.XMLPrefsSave.TEXT;
+        }
     };
 
     @Override
diff --git a/app/src/main/java/ohi/andre/consolelauncher/managers/xml/options/Notifications.java b/app/src/main/java/ohi/andre/consolelauncher/managers/xml/options/Notifications.java
index ea3fd93..0a53ad0 100644
--- a/app/src/main/java/ohi/andre/consolelauncher/managers/xml/options/Notifications.java
+++ b/app/src/main/java/ohi/andre/consolelauncher/managers/xml/options/Notifications.java
@@ -14,23 +14,75 @@ public enum Notifications implements XMLPrefsManager.XMLPrefsSave {
         public String defaultValue() {
             return "false";
         }
+
+        @Override
+        public String info() {
+            return "If true, t-ui will show every incoming notification";
+        }
     },
     app_notification_enabled_default {
         @Override
         public String defaultValue() {
             return "true";
         }
+
+        @Override
+        public String info() {
+            return "If true, t-ui will show notifications from all apps, unless they are explicitly excluded. If false, t-ui won't show a notification from a specific app unless it was \texplicitly included";
+        }
     },
     default_notification_color {
         @Override
         public String defaultValue() {
             return "#00FF00";
         }
+
+        @Override
+        public String type() {
+            return XMLPrefsManager.XMLPrefsSave.COLOR;
+        }
+
+        @Override
+        public String info() {
+            return "The default color";
+        }
     },
     notification_format {
         @Override
         public String defaultValue() {
-            return "[%t] %pkg: %ttl --- %txt";
+            return "[%t] %pkg: %[100][teal]title --- %text";
+        }
+
+        @Override
+        public String type() {
+            return XMLPrefsManager.XMLPrefsSave.TEXT;
+        }
+
+        @Override
+        public String info() {
+            return "The default format";
+        }
+    },
+    click_notification {
+        @Override
+        public String defaultValue() {
+            return "true";
+        }
+
+        @Override
+        public String info() {
+            return "If true, T-UI will perform the operation associated with the original notification when you click it";
+        }
+    },
+    long_click_notification {
+        @Override
+        public String defaultValue() {
+            return "true";
+        }
+
+        @Override
+        public String info() {
+            return "If true, you will be able to perform some quick operations long-clicking a notification";
         }
     };
 
@@ -48,4 +100,9 @@ public enum Notifications implements XMLPrefsManager.XMLPrefsSave {
     public boolean is(String s) {
         return name().equals(s);
     }
+
+    @Override
+    public String type() {
+        return XMLPrefsManager.XMLPrefsSave.BOOLEAN;
+    }
 }
diff --git a/app/src/main/java/ohi/andre/consolelauncher/managers/xml/options/Rss.java b/app/src/main/java/ohi/andre/consolelauncher/managers/xml/options/Rss.java
index 894d1d0..7ed14ce 100644
--- a/app/src/main/java/ohi/andre/consolelauncher/managers/xml/options/Rss.java
+++ b/app/src/main/java/ohi/andre/consolelauncher/managers/xml/options/Rss.java
@@ -14,11 +14,31 @@ public enum Rss implements XMLPrefsManager.XMLPrefsSave {
         public String defaultValue() {
             return "#f44336";
         }
+
+        @Override
+        public String type() {
+            return XMLPrefsManager.XMLPrefsSave.COLOR;
+        }
+
+        @Override
+        public String info() {
+            return "The default color";
+        }
     },
     rss_default_format {
         @Override
         public String defaultValue() {
-            return "%[50]title --- %[100]description";
+            return "%[50][green]title ### %[100][teal]description (%pubDate)";
+        }
+
+        @Override
+        public String type() {
+            return XMLPrefsManager.XMLPrefsSave.TEXT;
+        }
+
+        @Override
+        public String info() {
+            return "The default format";
         }
     },
     include_rss_default {
@@ -26,19 +46,120 @@ public enum Rss implements XMLPrefsManager.XMLPrefsSave {
         public String defaultValue() {
             return "true";
         }
+
+        @Override
+        public String type() {
+            return XMLPrefsManager.XMLPrefsSave.COLOR;
+        }
+
+        @Override
+        public String info() {
+            return "If true, a filter will exclude an item if it matches. If false, a filter will include an item if it matches";
+        }
     },
     rss_hidden_tags {
         @Override
         public String defaultValue() {
             return "img";
         }
+
+        @Override
+        public String type() {
+            return XMLPrefsManager.XMLPrefsSave.TEXT;
+        }
+
+        @Override
+        public String info() {
+            return "A list of excluded tags (separated by comma)";
+        }
     },
     rss_time_format {
         @Override
         public String defaultValue() {
             return "%t0";
         }
-    };
+
+        @Override
+        public String type() {
+            return XMLPrefsManager.XMLPrefsSave.TEXT;
+        }
+
+        @Override
+        public String info() {
+            return "The time format used by RSS items";
+        }
+    },
+    show_rss_download {
+        @Override
+        public String defaultValue() {
+            return "true";
+        }
+
+        @Override
+        public String type() {
+            return XMLPrefsManager.XMLPrefsSave.COLOR;
+        }
+
+        @Override
+        public String info() {
+            return "If true, you will see a message when T-UI downloads a feed";
+        }
+    },
+    rss_download_format {
+        @Override
+        public String defaultValue() {
+            return "RSS: %id --- Downloaded %sb bytes";
+        }
+
+        @Override
+        public String type() {
+            return XMLPrefsManager.XMLPrefsSave.TEXT;
+        }
+
+        @Override
+        public String info() {
+            return "The message shown when an RSS feed is downloaded";
+        }
+    },
+    rss_download_message_color {
+        @Override
+        public String defaultValue() {
+            return "aqua";
+        }
+
+        @Override
+        public String type() {
+            return XMLPrefsManager.XMLPrefsSave.COLOR;
+        }
+
+        @Override
+        public String info() {
+            return "The color of the download message";
+        }
+    },
+    click_rss {
+        @Override
+        public String defaultValue() {
+            return "true";
+        }
+
+        @Override
+        public String type() {
+            return XMLPrefsManager.XMLPrefsSave.COLOR;
+        }
+
+        @Override
+        public String info() {
+            return "If true, you will be able to click on an RSS item to open the associated webpage";
+        }
+    },
+//    long_click_rss {
+//        @Override
+//        public String defaultValue() {
+//            return "true";
+//        }
+//    }
+    ;
 
     @Override
     public XMLPrefsManager.XmlPrefsElement parent() {
diff --git a/app/src/main/java/ohi/andre/consolelauncher/managers/xml/options/Suggestions.java b/app/src/main/java/ohi/andre/consolelauncher/managers/xml/options/Suggestions.java
index 62fff83..3097d59 100644
--- a/app/src/main/java/ohi/andre/consolelauncher/managers/xml/options/Suggestions.java
+++ b/app/src/main/java/ohi/andre/consolelauncher/managers/xml/options/Suggestions.java
@@ -13,120 +13,250 @@ public enum Suggestions implements XMLPrefsManager.XMLPrefsSave {
         public String defaultValue() {
             return "true";
         }
+
+        @Override
+        public String type() {
+            return XMLPrefsManager.XMLPrefsSave.BOOLEAN;
+        }
+
+        @Override
+        public String info() {
+            return "If false, suggestions won't be shown";
+        }
     },
     transparent_suggestions {
         @Override
         public String defaultValue() {
             return "false";
         }
+
+        @Override
+        public String type() {
+            return XMLPrefsManager.XMLPrefsSave.BOOLEAN;
+        }
+
+        @Override
+        public String info() {
+            return "If true, the background will be transparent";
+        }
     },
     default_text_color {
         @Override
         public String defaultValue() {
             return "#000000";
         }
+
+        @Override
+        public String info() {
+            return "The default text color";
+        }
     },
     default_bg_color {
         @Override
         public String defaultValue() {
             return "#ffffff";
         }
+
+        @Override
+        public String info() {
+            return "The default background color";
+        }
     },
     apps_text_color {
         @Override
         public String defaultValue() {
             return "";
         }
+
+        @Override
+        public String info() {
+            return "Apps suggestions text color";
+        }
     },
     apps_bg_color {
         @Override
         public String defaultValue() {
             return "#00897B";
         }
+
+        @Override
+        public String info() {
+            return "Apps suggestions background color";
+        }
     },
     alias_text_color {
         @Override
         public String defaultValue() {
             return "";
         }
+
+        @Override
+        public String info() {
+            return "Aliases suggestions text color";
+        }
     },
     alias_bg_color {
         @Override
         public String defaultValue() {
             return "#FF5722";
         }
+
+        @Override
+        public String info() {
+            return "Aliases suggestions background color";
+        }
     },
     cmd_text_color {
         @Override
         public String defaultValue() {
             return "";
         }
+
+        @Override
+        public String info() {
+            return "Commands suggestions text color";
+        }
     },
     cmd_bg_color {
         @Override
         public String defaultValue() {
             return "#76FF03";
         }
+
+        @Override
+        public String info() {
+            return "Commands suggestions background color";
+        }
     },
     song_text_color {
         @Override
         public String defaultValue() {
             return "";
         }
+
+        @Override
+        public String info() {
+            return "Songs suggestions text color";
+        }
     },
     song_bg_color {
         @Override
         public String defaultValue() {
             return "#EEFF41";
         }
+
+        @Override
+        public String info() {
+            return "Songs suggestions background color";
+        }
     },
     contact_text_color {
         @Override
         public String defaultValue() {
             return "";
         }
+
+        @Override
+        public String info() {
+            return "Contacts suggestions text color";
+        }
     },
     contact_bg_color {
         @Override
         public String defaultValue() {
             return "#64FFDA";
         }
+
+        @Override
+        public String info() {
+            return "Contacts suggestions background color";
+        }
     },
     file_text_color {
         @Override
         public String defaultValue() {
             return "";
         }
+
+        @Override
+        public String info() {
+            return "Files suggestions text color";
+        }
     },
     file_bg_color {
         @Override
         public String defaultValue() {
             return "#03A9F4";
         }
+
+        @Override
+        public String info() {
+            return "Files suggestions background color";
+        }
     },
     suggest_alias_default {
         @Override
         public String defaultValue() {
             return "true";
         }
+
+        @Override
+        public String type() {
+            return XMLPrefsManager.XMLPrefsSave.BOOLEAN;
+        }
+
+        @Override
+        public String info() {
+            return "If true, your alias will be shown when the input field is empty";
+        }
     },
     suggest_appgp_default {
         @Override
         public String defaultValue() {
             return "true";
         }
+
+        @Override
+        public String type() {
+            return XMLPrefsManager.XMLPrefsSave.BOOLEAN;
+        }
+
+        @Override
+        public String info() {
+            return "If true, your app groups will be shown when the input field is empty";
+        }
     },
     click_to_launch {
         @Override
         public String defaultValue() {
             return "true";
         }
+
+        @Override
+        public String type() {
+            return XMLPrefsManager.XMLPrefsSave.BOOLEAN;
+        }
+
+        @Override
+        public String info() {
+            return "If true, some suggestions will be executed as soon as you click them";
+        }
     },
     suggestions_size {
         @Override
         public String defaultValue() {
             return "12";
         }
+
+        @Override
+        public String type() {
+            return XMLPrefsManager.XMLPrefsSave.INTEGER;
+        }
+
+        @Override
+        public String info() {
+            return "The text size of the suggestions";
+        }
     };
 
     @Override
@@ -143,4 +273,9 @@ public enum Suggestions implements XMLPrefsManager.XMLPrefsSave {
     public boolean is(String s) {
         return name().equals(s);
     }
+
+    @Override
+    public String type() {
+        return XMLPrefsManager.XMLPrefsSave.COLOR;
+    }
 }
\ No newline at end of file
diff --git a/app/src/main/java/ohi/andre/consolelauncher/managers/xml/options/Theme.java b/app/src/main/java/ohi/andre/consolelauncher/managers/xml/options/Theme.java
index 31f138d..b05c430 100644
--- a/app/src/main/java/ohi/andre/consolelauncher/managers/xml/options/Theme.java
+++ b/app/src/main/java/ohi/andre/consolelauncher/managers/xml/options/Theme.java
@@ -13,131 +13,241 @@ public enum Theme implements XMLPrefsManager.XMLPrefsSave {
         public String defaultValue() {
             return "#ff00ff00";
         }
+
+        @Override
+        public String info() {
+            return "Input color";
+        }
     },
     output_color {
         @Override
         public String defaultValue() {
             return "#ffffffff";
         }
+
+        @Override
+        public String info() {
+            return "Output color";
+        }
     },
     bg_color {
         @Override
         public String defaultValue() {
             return "#ff000000";
         }
+
+        @Override
+        public String info() {
+            return "Background color";
+        }
     },
     device_color {
         @Override
         public String defaultValue() {
             return "#ffff9800";
         }
+
+        @Override
+        public String info() {
+            return "Device label color";
+        }
     },
     battery_color_high {
         @Override
         public String defaultValue() {
             return "#4CAF50";
         }
+
+        @Override
+        public String info() {
+            return "Battery label color when the battery level is high";
+        }
     },
     battery_color_medium {
         @Override
         public String defaultValue() {
             return "#FFEB3B";
         }
+
+        @Override
+        public String info() {
+            return "Battery label color when the battery level is medium";
+        }
     },
     battery_color_low {
         @Override
         public String defaultValue() {
             return "#FF5722";
         }
+
+        @Override
+        public String info() {
+            return "Battery label color when the battery level is low";
+        }
     },
     time_color {
         @Override
         public String defaultValue() {
             return "#03A9F4";
         }
+
+        @Override
+        public String info() {
+            return "Time label color";
+        }
     },
     storage_color {
         @Override
         public String defaultValue() {
             return "#9C27B0";
         }
+
+        @Override
+        public String info() {
+            return "Storage label color";
+        }
     },
     ram_color {
         @Override
         public String defaultValue() {
             return "#fff44336";
         }
+
+        @Override
+        public String info() {
+            return "RAM label color";
+        }
     },
     network_info_color {
         @Override
         public String defaultValue() {
             return "#FFCA28";
         }
+
+        @Override
+        public String info() {
+            return "";
+        }
     },
     toolbar_bg {
         @Override
         public String defaultValue() {
             return "#00000000";
         }
+
+        @Override
+        public String info() {
+            return "Toolbar background color";
+        }
     },
     toolbar_color {
         @Override
         public String defaultValue() {
             return "#ffff0000";
         }
+
+        @Override
+        public String info() {
+            return "Toolbar icons color";
+        }
     },
     enter_color {
         @Override
         public String defaultValue() {
             return "#ffffffff";
         }
+
+        @Override
+        public String info() {
+            return "Enter icon color";
+        }
+    },
+    cursor_color {
+        @Override
+        public String defaultValue() {
+            return "#ffffff";
+        }
+
+        @Override
+        public String info() {
+            return "";
+        }
     },
     overlay_color {
         @Override
         public String defaultValue() {
             return "#80000000";
         }
+
+        @Override
+        public String info() {
+            return "The overlay that overlaps to the background (only when system_wallpaper is true)";
+        }
     },
     alias_content_color {
         @Override
         public String defaultValue() {
             return "#1DE9B6";
         }
+
+        @Override
+        public String info() {
+            return "Alias content color";
+        }
     },
     statusbar_color {
         @Override
         public String defaultValue() {
             return "#000000";
         }
+
+        @Override
+        public String info() {
+            return "Status Bar color (5.0+)";
+        }
     },
     navigationbar_color {
         @Override
         public String defaultValue() {
             return "#000000";
         }
+
+        @Override
+        public String info() {
+            return "Navigation Bar color (5.0+)";
+        }
     },
     app_installed_color {
         @Override
         public String defaultValue() {
             return "#FF7043";
         }
+
+        @Override
+        public String info() {
+            return "App installed message color";
+        }
     },
     app_uninstalled_color {
         @Override
         public String defaultValue() {
             return "#FF7043";
         }
+
+        @Override
+        public String info() {
+            return "App uninstalled message color";
+        }
     },
     hint_color {
         @Override
         public String defaultValue() {
             return "#4CAF50";
         }
-    },
-    rss_color {
+
         @Override
-        public String defaultValue() {
-            return null;
+        public String info() {
+            return "Hint color";
         }
     },
     mark_color {
@@ -145,6 +255,11 @@ public enum Theme implements XMLPrefsManager.XMLPrefsSave {
         public String defaultValue() {
             return "#CDDC39";
         }
+
+        @Override
+        public String info() {
+            return "The background color that will be used as marker";
+        }
     };
 
     @Override
@@ -161,4 +276,9 @@ public enum Theme implements XMLPrefsManager.XMLPrefsSave {
     public boolean is(String s) {
         return name().equals(s);
     }
+
+    @Override
+    public String type() {
+        return XMLPrefsManager.XMLPrefsSave.COLOR;
+    }
 }
\ No newline at end of file
diff --git a/app/src/main/java/ohi/andre/consolelauncher/managers/xml/options/Toolbar.java b/app/src/main/java/ohi/andre/consolelauncher/managers/xml/options/Toolbar.java
index c5bc862..efc2ebd 100644
--- a/app/src/main/java/ohi/andre/consolelauncher/managers/xml/options/Toolbar.java
+++ b/app/src/main/java/ohi/andre/consolelauncher/managers/xml/options/Toolbar.java
@@ -13,6 +13,16 @@ public enum Toolbar implements XMLPrefsManager.XMLPrefsSave {
         public String defaultValue() {
             return "true";
         }
+
+        @Override
+        public String info() {
+            return "If false, the toolbar is hidden";
+        }
+
+        @Override
+        public String type() {
+            return XMLPrefsManager.XMLPrefsSave.BOOLEAN;
+        }
     };
 
     @Override
diff --git a/app/src/main/java/ohi/andre/consolelauncher/managers/xml/options/Ui.java b/app/src/main/java/ohi/andre/consolelauncher/managers/xml/options/Ui.java
index 18c78bd..a0fe32e 100644
--- a/app/src/main/java/ohi/andre/consolelauncher/managers/xml/options/Ui.java
+++ b/app/src/main/java/ohi/andre/consolelauncher/managers/xml/options/Ui.java
@@ -15,53 +15,143 @@ public enum Ui implements XMLPrefsManager.XMLPrefsSave {
         public String defaultValue() {
             return "true";
         }
+
+        @Override
+        public String type() {
+            return XMLPrefsManager.XMLPrefsSave.BOOLEAN;
+        }
+
+        @Override
+        public String info() {
+            return "Hide/show the enter button";
+        }
     },
     system_font {
         @Override
         public String defaultValue() {
             return "false";
         }
+
+        @Override
+        public String type() {
+            return XMLPrefsManager.XMLPrefsSave.BOOLEAN;
+        }
+
+        @Override
+        public String info() {
+            return "If false, the default t-ui font (\"Lucida Console\") will be used for all texts";
+        }
     },
     ram_size {
         @Override
         public String defaultValue() {
             return "13";
         }
+
+        @Override
+        public String type() {
+            return XMLPrefsManager.XMLPrefsSave.INTEGER;
+        }
+
+        @Override
+        public String info() {
+            return "The ram label font size";
+        }
     },
     battery_size {
         @Override
         public String defaultValue() {
             return "13";
         }
+
+        @Override
+        public String type() {
+            return XMLPrefsManager.XMLPrefsSave.INTEGER;
+        }
+
+        @Override
+        public String info() {
+            return "The battery label font size";
+        }
     },
     device_size {
         @Override
         public String defaultValue() {
             return "13";
         }
+
+        @Override
+        public String type() {
+            return XMLPrefsManager.XMLPrefsSave.INTEGER;
+        }
+
+        @Override
+        public String info() {
+            return "The device label font size";
+        }
     },
     time_size {
         @Override
         public String defaultValue() {
             return "13";
         }
+
+        @Override
+        public String type() {
+            return XMLPrefsManager.XMLPrefsSave.INTEGER;
+        }
+
+        @Override
+        public String info() {
+            return "The time label font size";
+        }
     },
     storage_size {
         @Override
         public String defaultValue() {
             return "13";
         }
+
+        @Override
+        public String type() {
+            return XMLPrefsManager.XMLPrefsSave.INTEGER;
+        }
+
+        @Override
+        public String info() {
+            return "The storage label font size";
+        }
     },
     network_size {
         @Override
         public String defaultValue() {
             return "13";
         }
+
+        @Override
+        public String type() {
+            return XMLPrefsManager.XMLPrefsSave.INTEGER;
+        }
+
+        @Override
+        public String info() {
+            return "The network label font size";
+        }
     },
     input_output_size {
         @Override
         public String defaultValue() {
-            return "13";
+            return "15";
+        }
+
+        @Override
+        public String type() {
+            return XMLPrefsManager.XMLPrefsSave.INTEGER;
+        }
+
+        @Override
+        public String info() {
+            return "The input/output font size";
         }
     },
     input_bottom {
@@ -69,204 +159,544 @@ public enum Ui implements XMLPrefsManager.XMLPrefsSave {
         public String defaultValue() {
             return "true";
         }
+
+        @Override
+        public String type() {
+            return XMLPrefsManager.XMLPrefsSave.BOOLEAN;
+        }
+
+        @Override
+        public String info() {
+            return "If false, the input field will be placed on top of the screen";
+        }
     },
     show_ram {
         @Override
         public String defaultValue() {
             return "true";
         }
+
+        @Override
+        public String type() {
+            return XMLPrefsManager.XMLPrefsSave.BOOLEAN;
+        }
+
+        @Override
+        public String info() {
+            return "If false, the RAM label will be hidden";
+        }
     },
     show_device_name {
         @Override
         public String defaultValue() {
             return "true";
         }
+
+        @Override
+        public String type() {
+            return XMLPrefsManager.XMLPrefsSave.BOOLEAN;
+        }
+
+        @Override
+        public String info() {
+            return "If false, the device label will be hidden";
+        }
     },
     show_battery {
         @Override
         public String defaultValue() {
             return "true";
         }
+
+        @Override
+        public String type() {
+            return XMLPrefsManager.XMLPrefsSave.BOOLEAN;
+        }
+
+        @Override
+        public String info() {
+            return "If false, the battery label will be hidden";
+        }
     },
     show_network_info {
         @Override
         public String defaultValue() {
             return "true";
         }
+
+        @Override
+        public String type() {
+            return XMLPrefsManager.XMLPrefsSave.BOOLEAN;
+        }
+
+        @Override
+        public String info() {
+            return "If false, the network info label will be hidden";
+        }
     },
     show_storage_info {
         @Override
         public String defaultValue() {
             return "true";
         }
+
+        @Override
+        public String type() {
+            return XMLPrefsManager.XMLPrefsSave.BOOLEAN;
+        }
+
+        @Override
+        public String info() {
+            return "If false, the time label will be hidden";
+        }
     },
     enable_battery_status {
         @Override
         public String defaultValue() {
             return "true";
         }
+
+        @Override
+        public String type() {
+            return XMLPrefsManager.XMLPrefsSave.BOOLEAN;
+        }
+
+        @Override
+        public String info() {
+            return "If true, battery color will change when your battery level reach different percentages battery_color high, battery_color_medium, battery_color_low. If false, only battery_color_high is used";
+        }
     },
     show_time {
         @Override
         public String defaultValue() {
             return "true";
         }
+
+        @Override
+        public String type() {
+            return XMLPrefsManager.XMLPrefsSave.BOOLEAN;
+        }
+
+        @Override
+        public String info() {
+            return "If false, the time label will be hidden";
+        }
     },
     username {
         @Override
         public String defaultValue() {
             return "user";
         }
+
+        @Override
+        public String type() {
+            return XMLPrefsManager.XMLPrefsSave.TEXT;
+        }
+
+        @Override
+        public String info() {
+            return "Your username";
+        }
     },
     deviceName {
         @Override
         public String defaultValue() {
             return Build.DEVICE;
         }
+
+        @Override
+        public String type() {
+            return XMLPrefsManager.XMLPrefsSave.TEXT;
+        }
+
+        @Override
+        public String info() {
+            return "Your device name";
+        }
     },
     system_wallpaper {
         @Override
         public String defaultValue() {
             return "false";
         }
+
+        @Override
+        public String type() {
+            return XMLPrefsManager.XMLPrefsSave.BOOLEAN;
+        }
+
+        @Override
+        public String info() {
+            return "If true, your system wallpaper will be used as background";
+        }
     },
     fullscreen {
         @Override
         public String defaultValue() {
             return "false";
         }
+
+        @Override
+        public String type() {
+            return XMLPrefsManager.XMLPrefsSave.BOOLEAN;
+        }
+
+        @Override
+        public String info() {
+            return "If true, t-ui will run in fullscreen mode";
+        }
     },
     device_index {
         @Override
         public String defaultValue() {
             return "0";
         }
+
+        @Override
+        public String type() {
+            return XMLPrefsManager.XMLPrefsSave.INTEGER;
+        }
+
+        @Override
+        public String info() {
+            return "This is used to order the labels on top of the screen";
+        }
     },
     ram_index {
         @Override
         public String defaultValue() {
             return "1";
         }
+
+        @Override
+        public String type() {
+            return XMLPrefsManager.XMLPrefsSave.INTEGER;
+        }
+
+        @Override
+        public String info() {
+            return "This is used to order the labels on top of the screen";
+        }
     },
     battery_index {
         @Override
         public String defaultValue() {
             return "2";
         }
+
+        @Override
+        public String type() {
+            return XMLPrefsManager.XMLPrefsSave.INTEGER;
+        }
+
+        @Override
+        public String info() {
+            return "This is used to order the labels on top of the screen";
+        }
     },
     time_index {
         @Override
         public String defaultValue() {
             return "3";
         }
+
+        @Override
+        public String type() {
+            return XMLPrefsManager.XMLPrefsSave.INTEGER;
+        }
+
+        @Override
+        public String info() {
+            return "This is used to order the labels on top of the screen";
+        }
     },
     storage_index {
         @Override
         public String defaultValue() {
             return "4";
         }
+
+        @Override
+        public String type() {
+            return XMLPrefsManager.XMLPrefsSave.INTEGER;
+        }
+
+        @Override
+        public String info() {
+            return "This is used to order the labels on top of the screen";
+        }
     },
     network_index {
         @Override
         public String defaultValue() {
             return "5";
         }
+
+        @Override
+        public String type() {
+            return XMLPrefsManager.XMLPrefsSave.INTEGER;
+        }
+
+        @Override
+        public String info() {
+            return "This is used to order the labels on top of the screen";
+        }
     },
-    status_line0_position {
+    status_line0_alignment {
         @Override
         public String defaultValue() {
             return "-1";
         }
+
+        @Override
+        public String type() {
+            return XMLPrefsManager.XMLPrefsSave.INTEGER;
+        }
+
+        @Override
+        public String info() {
+            return "The alignment of the first status line (<0 = left, =0 = center, >0 = right)";
+        }
     },
-    status_line1_position {
+    status_line1_alignment {
         @Override
         public String defaultValue() {
             return "-1";
         }
+
+        @Override
+        public String type() {
+            return XMLPrefsManager.XMLPrefsSave.INTEGER;
+        }
+
+        @Override
+        public String info() {
+            return "The alignment of the second status line (<0 = left, =0 = center, >0 = right)";
+        }
     },
-    status_line2_position {
+    status_line2_alignment {
         @Override
         public String defaultValue() {
             return "-1";
         }
+
+        @Override
+        public String type() {
+            return XMLPrefsManager.XMLPrefsSave.INTEGER;
+        }
+
+        @Override
+        public String info() {
+            return "The alignment of the third status line (<0 = left, =0 = center, >0 = right)";
+        }
     },
-    status_line3_position {
+    status_line3_alignment {
         @Override
         public String defaultValue() {
             return "-1";
         }
+
+        @Override
+        public String type() {
+            return XMLPrefsManager.XMLPrefsSave.INTEGER;
+        }
+
+        @Override
+        public String info() {
+            return "The alignment of the fourth status line (<0 = left, =0 = center, >0 = right)";
+        }
     },
-    status_line4_position {
+    status_line4_alignment {
         @Override
         public String defaultValue() {
             return "-1";
         }
+
+        @Override
+        public String type() {
+            return XMLPrefsManager.XMLPrefsSave.INTEGER;
+        }
+
+        @Override
+        public String info() {
+            return "The alignment of the fifth status line (<0 = left, =0 = center, >0 = right)";
+        }
     },
-    status_line5_position {
+    status_line5_alignment {
         @Override
         public String defaultValue() {
             return "-1";
         }
+
+        @Override
+        public String type() {
+            return XMLPrefsManager.XMLPrefsSave.INTEGER;
+        }
+
+        @Override
+        public String info() {
+            return "The alignment of the sixth status line (<0 = left, =0 = center, >0 = right)";
+        }
     },
     input_prefix {
         @Override
         public String defaultValue() {
             return "$";
         }
+
+        @Override
+        public String type() {
+            return XMLPrefsManager.XMLPrefsSave.TEXT;
+        }
+
+        @Override
+        public String info() {
+            return "The prefix placed before every input";
+        }
     },
     input_root_prefix {
         @Override
         public String defaultValue() {
             return "#";
         }
+
+        @Override
+        public String type() {
+            return XMLPrefsManager.XMLPrefsSave.TEXT;
+        }
+
+        @Override
+        public String info() {
+            return "The prefix placed before a root command (\"su ...\")";
+        }
     },
     left_margin_mm {
         @Override
         public String defaultValue() {
             return "0";
         }
+
+        @Override
+        public String type() {
+            return XMLPrefsManager.XMLPrefsSave.INTEGER;
+        }
+
+        @Override
+        public String info() {
+            return "The left margin (in millimeters)";
+        }
     },
     right_margin_mm {
         @Override
         public String defaultValue() {
             return "0";
         }
+
+        @Override
+        public String type() {
+            return XMLPrefsManager.XMLPrefsSave.INTEGER;
+        }
+
+        @Override
+        public String info() {
+            return "The right margin (in millimeters)";
+        }
     },
     top_margin_mm {
         @Override
         public String defaultValue() {
             return "0";
         }
+
+        @Override
+        public String type() {
+            return XMLPrefsManager.XMLPrefsSave.INTEGER;
+        }
+
+        @Override
+        public String info() {
+            return "The top margin (in millimeters)";
+        }
     },
     bottom_margin_mm {
         @Override
         public String defaultValue() {
             return "0";
         }
+
+        @Override
+        public String type() {
+            return XMLPrefsManager.XMLPrefsSave.INTEGER;
+        }
+
+        @Override
+        public String info() {
+            return "The bottom margin (in millimeters)";
+        }
     },
     ignore_bar_color {
         @Override
         public String defaultValue() {
             return "false";
         }
+
+        @Override
+        public String type() {
+            return XMLPrefsManager.XMLPrefsSave.BOOLEAN;
+        }
+
+        @Override
+        public String info() {
+            return "If true, statusbar_color and navigationbar_color will be ignored";
+        }
     },
     show_app_installed {
         @Override
         public String defaultValue() {
             return "true";
         }
+
+        @Override
+        public String type() {
+            return XMLPrefsManager.XMLPrefsSave.BOOLEAN;
+        }
+
+        @Override
+        public String info() {
+            return "If true, you will receive a message when you install an app";
+        }
     },
     show_app_uninstalled {
         @Override
         public String defaultValue() {
             return "true";
         }
+
+        @Override
+        public String type() {
+            return XMLPrefsManager.XMLPrefsSave.BOOLEAN;
+        }
+
+        @Override
+        public String info() {
+            return "If true, you will receive a message when you uninstall an app";
+        }
     },
     show_session_info {
         @Override
         public String defaultValue() {
             return "true";
         }
+
+        @Override
+        public String type() {
+            return XMLPrefsManager.XMLPrefsSave.BOOLEAN;
+        }
+
+        @Override
+        public String info() {
+            return "If true, when your input field is empty there will be a short line containing some information about the current session";
+        }
     };
 
     @Override
diff --git a/app/src/main/java/ohi/andre/consolelauncher/tuils/AllowEqualsSequence.java b/app/src/main/java/ohi/andre/consolelauncher/tuils/AllowEqualsSequence.java
index 34c551b..1757abf 100644
--- a/app/src/main/java/ohi/andre/consolelauncher/tuils/AllowEqualsSequence.java
+++ b/app/src/main/java/ohi/andre/consolelauncher/tuils/AllowEqualsSequence.java
@@ -31,7 +31,7 @@ public class AllowEqualsSequence {
             if(i != last) counter++;
 
             entry.key = counter;
-            last = counter;
+            last = i;
         }
     }
 
@@ -82,7 +82,7 @@ public class AllowEqualsSequence {
 
         @Override
         public String toString() {
-            return value + ": " + obj.toString();
+            return "key: " + key + ": " + obj.toString();
         }
     }
 }
diff --git a/app/src/main/java/ohi/andre/consolelauncher/tuils/InputOutputReceiver.java b/app/src/main/java/ohi/andre/consolelauncher/tuils/InputOutputReceiver.java
index 925cfdc..d3ca391 100644
--- a/app/src/main/java/ohi/andre/consolelauncher/tuils/InputOutputReceiver.java
+++ b/app/src/main/java/ohi/andre/consolelauncher/tuils/InputOutputReceiver.java
@@ -4,11 +4,13 @@ import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
 import android.os.Bundle;
-import android.support.v4.app.NotificationManagerCompat;
 import android.support.v4.app.RemoteInput;
+import android.text.SpannableStringBuilder;
+import android.text.Spanned;
 
 import ohi.andre.consolelauncher.managers.TerminalManager;
 import ohi.andre.consolelauncher.tuils.interfaces.CommandExecuter;
+import ohi.andre.consolelauncher.tuils.interfaces.Inputable;
 import ohi.andre.consolelauncher.tuils.interfaces.Outputable;
 
 /**
@@ -17,24 +19,35 @@ import ohi.andre.consolelauncher.tuils.interfaces.Outputable;
 
 public class InputOutputReceiver extends BroadcastReceiver {
 
+//    this class handles incoming intent to
+//    process input
+//    show custom output
+
     public static final int WAS_MUSIC_SERVICE = 10;
     public static final int WAS_KEEPER_SERVICE = 11;
 
     public static final String WAS_KEY = "was";
 
-    public static final String ACTION_CMD = "ohi.andre.consolelauncher.action_cmd";
     public static final String ACTION_OUTPUT = "ohi.andre.consolelauncher.action_output";
+//    this will set an input and click it
+    public static final String ACTION_CMD = "ohi.andre.consolelauncher.action_cmd";
+//    this will set an input and NOT click it
+    public static final String ACTION_INPUT = "ohi.andre.consolelauncher.action_input";
     public static final String TEXT = "ohi.andre.consolelauncher.text";
     public static final String TYPE = "ohi.andre.consolelauncher.type";
     public static final String COLOR = "ohi.andre.consolelauncher.color";
+    public static final String ACTION = "ohi.andre.consolelauncher.action";
+    public static final String LONG_ACTION = "ohi.andre.consolelauncher.longaction";
     public static final String SHOW_CONTENT = "ohi.andre.consolelauncher.show_content";
 
     CommandExecuter executer;
     Outputable outputable;
+    Inputable inputable;
 
-    public InputOutputReceiver(CommandExecuter executer, Outputable outputable) {
+    public InputOutputReceiver(CommandExecuter executer, Outputable outputable, Inputable inputable) {
         this.executer = executer;
         this.outputable = outputable;
+        this.inputable = inputable;
     }
 
     @Override
@@ -47,27 +60,42 @@ public class InputOutputReceiver extends BroadcastReceiver {
 
             if(intent.getAction().equals(ACTION_CMD)) {
                 executer.exec(text.toString(), intent.getBooleanExtra(SHOW_CONTENT, true));
-            } else {
+            } else if(intent.getAction().equals(ACTION_OUTPUT)) {
                 int color = intent.getIntExtra(COLOR, Integer.MAX_VALUE);
 
+                Object singleClickExtraObject, longClickExtraObject;
+
+                singleClickExtraObject = intent.getStringExtra(ACTION);
+                longClickExtraObject = intent.getStringExtra(LONG_ACTION);
+
+                if(singleClickExtraObject == null) singleClickExtraObject = intent.getParcelableExtra(ACTION);
+                if(longClickExtraObject == null) longClickExtraObject = intent.getParcelableExtra(LONG_ACTION);
+
+                if(singleClickExtraObject != null || longClickExtraObject != null) {
+                    text = new SpannableStringBuilder(text);
+                    ((SpannableStringBuilder) text).setSpan(new LongClickableSpan(singleClickExtraObject, longClickExtraObject), 0, text.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
+                }
+
                 if(color != Integer.MAX_VALUE) {
                     outputable.onOutput(color, text);
                 } else {
                     int type = intent.getIntExtra(TYPE, -1);
                     if(type != -1) outputable.onOutput(text, type);
-                    else outputable.onOutput(text, TerminalManager.CATEGORY_GENERAL);
+                    else outputable.onOutput(text, TerminalManager.CATEGORY_OUTPUT);
                 }
+            } else if(intent.getAction().equals(ACTION_INPUT)) {
+                inputable.in(text.toString());
             }
         } else {
             String cmd = remoteInput.getString(TEXT);
             executer.exec(cmd, true);
 
-            int was = intent.getIntExtra(WAS_KEY, 0);
-            if(was == WAS_KEEPER_SERVICE) {
-                NotificationManagerCompat.from(context).notify(KeeperService.ONGOING_NOTIFICATION_ID, KeeperService.buildNotification(context));
-            } else if(was == WAS_MUSIC_SERVICE) {
-//                do nothing
-            }
+//            int was = intent.getIntExtra(WAS_KEY, 0);
+//            if(was == WAS_KEEPER_SERVICE) {
+//                NotificationManagerCompat.from(context).notify(KeeperService.ONGOING_NOTIFICATION_ID, KeeperService.buildNotification(context));
+//            } else if(was == WAS_MUSIC_SERVICE) {
+////                do nothing
+//            }
         }
     }
 }
diff --git a/app/src/main/java/ohi/andre/consolelauncher/tuils/KeeperService.java b/app/src/main/java/ohi/andre/consolelauncher/tuils/KeeperService.java
deleted file mode 100755
index 94070c7..0000000
--- a/app/src/main/java/ohi/andre/consolelauncher/tuils/KeeperService.java
+++ /dev/null
@@ -1,72 +0,0 @@
-package ohi.andre.consolelauncher.tuils;
-
-import android.app.Notification;
-import android.app.PendingIntent;
-import android.app.Service;
-import android.content.Context;
-import android.content.Intent;
-import android.os.Build;
-import android.os.IBinder;
-import android.support.v4.app.NotificationCompat;
-import android.support.v4.app.RemoteInput;
-
-import ohi.andre.consolelauncher.LauncherActivity;
-import ohi.andre.consolelauncher.R;
-
-public class KeeperService extends Service {
-
-    public static final int ONGOING_NOTIFICATION_ID = 1001;
-
-    @Override
-    public IBinder onBind(Intent intent) {
-        return null;
-    }
-
-    @Override
-    public int onStartCommand(Intent intent, int flags, int startId) {
-        startForeground(ONGOING_NOTIFICATION_ID, buildNotification(getApplicationContext()));
-        return super.onStartCommand(intent, flags, startId);
-    }
-
-    @Override
-    public boolean onUnbind(Intent intent) {
-        return true;
-    }
-
-    public static Notification buildNotification(Context c) {
-        Intent resultIntent = new Intent(c, LauncherActivity.class);
-        PendingIntent resultPendingIntent = PendingIntent.getActivity(
-                c,
-                0,
-                resultIntent,
-                PendingIntent.FLAG_UPDATE_CURRENT
-        );
-
-        NotificationCompat.Builder builder = new NotificationCompat.Builder(c)
-                .setSmallIcon(R.mipmap.ic_launcher)
-                .setTicker(c.getString(R.string.start_notification))
-                .setWhen(System.currentTimeMillis())
-                .setContentTitle(c.getString(R.string.app_name))
-                .setContentText(c.getString(R.string.tui_running))
-                .setContentIntent(resultPendingIntent);
-
-        if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
-            String label = "cmd";
-            RemoteInput remoteInput = new RemoteInput.Builder(InputOutputReceiver.TEXT)
-                    .setLabel(label)
-                    .build();
-
-            Intent i = new Intent(InputOutputReceiver.ACTION_CMD);
-            i.putExtra(InputOutputReceiver.WAS_KEY, InputOutputReceiver.WAS_KEEPER_SERVICE);
-
-            NotificationCompat.Action action = new NotificationCompat.Action.Builder(R.mipmap.ic_launcher, label,
-                    PendingIntent.getBroadcast(c.getApplicationContext(), 40, i, PendingIntent.FLAG_UPDATE_CURRENT))
-                    .addRemoteInput(remoteInput)
-                    .build();
-
-            builder.addAction(action);
-        }
-
-        return builder.build();
-    }
-}
diff --git a/app/src/main/java/ohi/andre/consolelauncher/tuils/LongClickMovementMethod.java b/app/src/main/java/ohi/andre/consolelauncher/tuils/LongClickMovementMethod.java
new file mode 100644
index 0000000..0f5446b
--- /dev/null
+++ b/app/src/main/java/ohi/andre/consolelauncher/tuils/LongClickMovementMethod.java
@@ -0,0 +1,139 @@
+package ohi.andre.consolelauncher.tuils;
+
+import android.text.Layout;
+import android.text.Spannable;
+import android.text.method.LinkMovementMethod;
+import android.text.method.MovementMethod;
+import android.view.MotionEvent;
+import android.widget.TextView;
+
+/**
+ * Created by francescoandreuzzi on 17/11/2017.
+ */
+
+public class LongClickMovementMethod extends LinkMovementMethod {
+
+//    private Long lastClickTime = 0l;
+//    private int lastX = 0;
+//    private int lastY = 0;
+
+    private int longClickDuration, lastLine = -1;
+
+    private abstract class WasActivatedRunnable implements Runnable {
+
+        public boolean wasActivated = false;
+
+        @Override
+        public void run() {
+            wasActivated = true;
+        }
+    };
+
+    private WasActivatedRunnable runnable;
+
+    @Override
+    public boolean onTouchEvent(final TextView widget, Spannable buffer, MotionEvent event) {
+        int action = event.getAction();
+//        Tuils.log("action", action);
+
+        if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_DOWN || action == MotionEvent.ACTION_MOVE || action == MotionEvent.ACTION_CANCEL) {
+            int x = (int) event.getX();
+            int y = (int) event.getY();
+//            lastX = x;
+//            lastY = y;
+//            int deltaX = Math.abs(x-lastX);
+//            int deltaY = Math.abs(y-lastY);
+
+            x -= widget.getTotalPaddingLeft();
+            y -= widget.getTotalPaddingTop();
+
+            x += widget.getScrollX();
+            y += widget.getScrollY();
+
+            Layout layout = widget.getLayout();
+            final int line = layout.getLineForVertical(y);
+            int off = layout.getOffsetForHorizontal(line, x);
+
+            final LongClickableSpan[] link = buffer.getSpans(off, off, LongClickableSpan.class);
+
+//            Tuils.log("lastline", lastLine);
+//            Tuils.log("line", line);
+            if (action == MotionEvent.ACTION_UP) {
+//                Tuils.log("action up");
+
+//                    if (System.currentTimeMillis() - lastClickTime < longClickDuration) {
+//                        link[0].onClick(widget);
+//                    }
+//                    else if (deltaX < 10 && deltaY < 10) {
+//                        link[0].onLongClick(widget);
+//                    }
+
+                if(runnable != null) {
+//                        long click, do nothing
+                    if(runnable.wasActivated) {}
+//                        single click
+                    else {
+                        widget.removeCallbacks(runnable);
+                        if(link.length > 0) link[0].onClick(widget);
+                    }
+
+                    runnable = null;
+                }
+
+            } else if (action == MotionEvent.ACTION_DOWN) {
+
+//                Tuils.log("action down");
+
+//                    Selection.setSelection(buffer,
+//                            buffer.getSpanStart(link[0]),
+//                            buffer.getSpanEnd(link[0]));
+
+//                    lastClickTime = System.currentTimeMillis();
+
+                if(link.length > 0) {
+                    final LongClickableSpan span = link[0];
+                    runnable = new WasActivatedRunnable() {
+
+                        @Override
+                        public void run() {
+                            super.run();
+                            span.onLongClick(widget);
+                        }
+                    };
+                }
+
+                widget.postDelayed(runnable, longClickDuration);
+            } else {
+//                Tuils.log("action move or cancel");
+
+//                action_move
+                if(line != lastLine) {
+//                    Tuils.log("line != last line");
+                    widget.removeCallbacks(runnable);
+                }
+            }
+
+            lastLine = line;
+//            Tuils.log("updated kast line", lastLine);
+//            Tuils.log("#####");
+
+            return true;
+        }
+
+        return super.onTouchEvent(widget, buffer, event);
+    }
+
+    private static LongClickMovementMethod sInstance;
+    public static MovementMethod getInstance(int longClickDuration) {
+        if (sInstance == null) {
+            sInstance = new LongClickMovementMethod();
+            sInstance.longClickDuration = longClickDuration;
+        }
+
+        return sInstance;
+    }
+
+    public static MovementMethod getInstance() {
+        return getInstance(-1);
+    }
+}
\ No newline at end of file
diff --git a/app/src/main/java/ohi/andre/consolelauncher/tuils/LongClickableSpan.java b/app/src/main/java/ohi/andre/consolelauncher/tuils/LongClickableSpan.java
new file mode 100644
index 0000000..398db4c
--- /dev/null
+++ b/app/src/main/java/ohi/andre/consolelauncher/tuils/LongClickableSpan.java
@@ -0,0 +1,125 @@
+package ohi.andre.consolelauncher.tuils;
+
+import android.app.PendingIntent;
+import android.content.Context;
+import android.content.Intent;
+import android.os.Vibrator;
+import android.text.TextPaint;
+import android.text.style.ClickableSpan;
+import android.view.MenuItem;
+import android.view.View;
+import android.widget.PopupMenu;
+
+import ohi.andre.consolelauncher.R;
+import ohi.andre.consolelauncher.managers.notifications.NotificationManager;
+import ohi.andre.consolelauncher.managers.notifications.NotificationService;
+
+/**
+ * Created by francescoandreuzzi on 22/10/2017.
+ */
+
+public class LongClickableSpan extends ClickableSpan {
+
+    public static int longPressVibrateDuration = -1;
+
+    private Object clickO, longClickO;
+    private String longIntentKey;
+
+    public LongClickableSpan(Object clickAction, Object longClickAction) {
+        this.clickO = clickAction;
+        this.longClickO = longClickAction;
+        this.longIntentKey = null;
+    }
+
+    public LongClickableSpan(Object clickAction) {
+        this.clickO = clickAction;
+        this.longClickO = null;
+        this.longIntentKey = null;
+    }
+
+    public LongClickableSpan(Object clickAction, Object longClickAction, String longIntentKey) {
+        this.clickO = clickAction;
+        this.longClickO = longClickAction;
+        this.longIntentKey = longIntentKey;
+    }
+
+    public LongClickableSpan(Object clickAction, String longIntentKey) {
+        this.clickO = clickAction;
+        this.longClickO = null;
+        this.longIntentKey = longIntentKey;
+    }
+
+    public LongClickableSpan(String longIntentKey) {
+        this.clickO = null;
+        this.longClickO = null;
+        this.longIntentKey = longIntentKey;
+    }
+
+    @Override
+    public void updateDrawState(TextPaint ds) {}
+
+    @Override
+    public void onClick(View widget) {
+        execute(widget, clickO);
+    }
+
+    public void onLongClick(View widget) {
+        if(execute(widget, longClickO, longIntentKey) && longPressVibrateDuration > 0) ((Vibrator) widget.getContext().getApplicationContext().getSystemService(Context.VIBRATOR_SERVICE)).vibrate(longPressVibrateDuration);
+    }
+
+    private static boolean execute(View v, Object o) {
+        return execute(v, o, null);
+    }
+
+    private static boolean execute(View v, Object o, String intentKey) {
+        if(o == null) return false;
+
+        if(o instanceof String) {
+            Intent intent = new Intent(intentKey != null ? intentKey : InputOutputReceiver.ACTION_CMD);
+            intent.putExtra(InputOutputReceiver.SHOW_CONTENT, false);
+            intent.putExtra(InputOutputReceiver.TEXT, (String) o);
+            v.getContext().sendBroadcast(intent);
+        } else if(o instanceof PendingIntent) {
+            PendingIntent pi = (PendingIntent) o;
+
+            try {
+                pi.send();
+            } catch (PendingIntent.CanceledException e) {
+                Tuils.log(e);
+            }
+        } else if(o instanceof NotificationService.Notification) {
+            if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.HONEYCOMB) {
+                PopupMenu menu = new PopupMenu(v.getContext().getApplicationContext(), v);
+                menu.getMenuInflater().inflate(R.menu.notification_menu, menu.getMenu());
+
+                final NotificationService.Notification n = (NotificationService.Notification) o;
+
+                menu.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() {
+
+                    @Override
+                    public boolean onMenuItemClick(MenuItem item) {
+                        int id = item.getItemId();
+
+                        switch (id) {
+                            case R.id.exclude_app:
+                                NotificationManager.setState(n.pkg, false);
+                                break;
+                            case R.id.exclude_notification:
+                                NotificationManager.addFilter(n.text, -1);
+                                break;
+                            default:
+                                return false;
+                        }
+
+                        return true;
+                    }
+                });
+
+                menu.show();
+            }
+        }
+
+        return true;
+    }
+}
+
diff --git a/app/src/main/java/ohi/andre/consolelauncher/tuils/StoppableThread.java b/app/src/main/java/ohi/andre/consolelauncher/tuils/StoppableThread.java
index f98c1ec..a4bfd9b 100755
--- a/app/src/main/java/ohi/andre/consolelauncher/tuils/StoppableThread.java
+++ b/app/src/main/java/ohi/andre/consolelauncher/tuils/StoppableThread.java
@@ -1,7 +1,5 @@
 package ohi.andre.consolelauncher.tuils;
 
-import android.util.Log;
-
 /**
  * Created by francescoandreuzzi on 27/04/2017.
  */
@@ -9,6 +7,16 @@ import android.util.Log;
 public class StoppableThread extends Thread {
 
     private volatile boolean stopped = false;
+    public StoppableThread() {
+        Thread.setDefaultUncaughtExceptionHandler(new UncaughtExceptionHandler() {
+            @Override
+            public void uncaughtException(Thread t, Throwable e) {
+                Tuils.log(e);
+                Tuils.toFile(e);
+                System.exit(1);
+            }
+        });
+    }
 
     @Override
     public void interrupt() {
diff --git a/app/src/main/java/ohi/andre/consolelauncher/tuils/Tuils.java b/app/src/main/java/ohi/andre/consolelauncher/tuils/Tuils.java
index 4836734..dcbdf10 100755
--- a/app/src/main/java/ohi/andre/consolelauncher/tuils/Tuils.java
+++ b/app/src/main/java/ohi/andre/consolelauncher/tuils/Tuils.java
@@ -13,14 +13,19 @@ import android.content.Intent;
 import android.content.IntentFilter;
 import android.content.pm.PackageManager;
 import android.content.res.Resources;
+import android.graphics.Color;
+import android.graphics.PorterDuff;
 import android.graphics.Typeface;
+import android.graphics.drawable.Drawable;
 import android.net.Uri;
 import android.os.BatteryManager;
 import android.os.Build;
 import android.os.Environment;
+import android.os.Parcelable;
 import android.os.Process;
 import android.os.StatFs;
 import android.provider.Settings;
+import android.telephony.TelephonyManager;
 import android.text.SpannableString;
 import android.text.Spanned;
 import android.text.TextUtils;
@@ -33,6 +38,8 @@ import android.util.TypedValue;
 import android.view.View;
 import android.view.ViewGroup;
 import android.webkit.MimeTypeMap;
+import android.widget.EditText;
+import android.widget.TextView;
 
 import java.io.BufferedReader;
 import java.io.File;
@@ -44,10 +51,14 @@ import java.io.InputStreamReader;
 import java.io.OutputStream;
 import java.io.PrintStream;
 import java.io.PrintWriter;
+import java.io.Reader;
 import java.io.StringWriter;
 import java.lang.reflect.Array;
+import java.lang.reflect.Field;
 import java.math.BigDecimal;
 import java.math.RoundingMode;
+import java.net.HttpURLConnection;
+import java.net.URL;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Date;
@@ -58,6 +69,7 @@ import java.util.regex.Pattern;
 
 import dalvik.system.DexFile;
 import ohi.andre.consolelauncher.BuildConfig;
+import ohi.andre.consolelauncher.R;
 import ohi.andre.consolelauncher.managers.TerminalManager;
 import ohi.andre.consolelauncher.managers.music.MusicManager2;
 import ohi.andre.consolelauncher.managers.music.Song;
@@ -138,6 +150,8 @@ public class Tuils {
     }
 
     public static boolean arrayContains(int[] array, int value) {
+        if(array == null) return false;
+
         for(int i : array) {
             if(i == value) {
                 return true;
@@ -146,6 +160,55 @@ public class Tuils {
         return false;
     }
 
+    static final char CHAR_SPACE = ' ';
+    public static boolean equalsIgnoreSpaceAndCase(String s1, String s2) {
+        if (s1 == s2) {
+            return true;
+        }
+
+        int i1 = 0, i2 = 0;
+        while(true) {
+            if(i1 == s1.length() || i2 == s2.length()) break;
+
+            char c1 = Character.toLowerCase(s1.charAt(i1));
+            char c2 = Character.toLowerCase(s2.charAt(i2));
+
+            if(c1 != CHAR_SPACE) {
+                if(c2 != CHAR_SPACE) {
+                    if(c1 != c2) return false;
+                } else {
+//                    c1 is not space, c2 is space
+//                    i1 remains, i2 changes
+                    i2++;
+                    continue;
+                }
+            }
+
+//            c1 is space
+            if(c2 == CHAR_SPACE) {
+//                c1 is space, c2 is space
+                i1++;i2++;
+            } else {
+//                c1 is space, c2 is not space
+                i1++;
+                continue;
+            }
+        }
+
+        return true;
+    }
+
+    public static String readerToString(Reader initialReader) throws IOException {
+        char[] arr = new char[8 * 1024];
+        StringBuilder buffer = new StringBuilder();
+        int numCharsRead;
+        while ((numCharsRead = initialReader.read(arr, 0, arr.length)) != -1) {
+            buffer.append(arr, 0, numCharsRead);
+        }
+        initialReader.close();
+        return buffer.toString();
+    }
+
     public static void registerBatteryReceiver(Context context, OnBatteryUpdate listener) {
         try {
             IntentFilter iFilter = new IntentFilter(Intent.ACTION_BATTERY_CHANGED);
@@ -218,19 +281,24 @@ public class Tuils {
         return songs;
     }
 
-    public static void download(InputStream in, File file) throws Exception {
+    public static long download(InputStream in, File file) throws Exception {
         OutputStream out = new FileOutputStream(file, false);
 
         byte data[] = new byte[1024];
 
+        long bytes = 0;
+
         int count;
         while ((count = in.read(data)) != -1) {
             out.write(data, 0, count);
+            bytes += count;
         }
 
         out.flush();
         out.close();
         in.close();
+
+        return bytes;
     }
 
     public static void write(File file, String separator, String... ss) throws Exception {
@@ -384,7 +452,9 @@ public class Tuils {
     public static SpannableString span(Context context, String text, int color, int size) {
         SpannableString spannableString = new SpannableString(text);
         if(size != Integer.MAX_VALUE && context != null) spannableString.setSpan(new AbsoluteSizeSpan(convertSpToPixels(size, context)), 0, text.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
-        if(color != Integer.MAX_VALUE) spannableString.setSpan(new ForegroundColorSpan(color), 0, text.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
+        if(color != Integer.MAX_VALUE) {
+            spannableString.setSpan(new ForegroundColorSpan(color), 0, text.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
+        }
         return spannableString;
     }
 
@@ -484,7 +554,7 @@ public class Tuils {
     }
 
     public static void sendOutput(int color, Context context, CharSequence s) {
-        sendOutput(color, context, s, TerminalManager.CATEGORY_GENERAL);
+        sendOutput(color, context, s, TerminalManager.CATEGORY_OUTPUT);
     }
 
     public static void sendOutput(Context context, CharSequence s, int type) {
@@ -499,6 +569,47 @@ public class Tuils {
         context.sendBroadcast(intent);
     }
 
+    public static void sendOutput(Context context, CharSequence s, int type, Object action) {
+        sendOutput(Integer.MAX_VALUE, context, s, type, action);
+    }
+
+    public static void sendOutput(int color, Context context, CharSequence s, int type, Object action) {
+        Intent intent = new Intent(InputOutputReceiver.ACTION_OUTPUT);
+        intent.putExtra(InputOutputReceiver.TEXT, s);
+        intent.putExtra(InputOutputReceiver.COLOR, color);
+        intent.putExtra(InputOutputReceiver.TYPE, type);
+
+        if(action instanceof String) intent.putExtra(InputOutputReceiver.ACTION, (String) action);
+        else if(action instanceof Parcelable) intent.putExtra(InputOutputReceiver.ACTION, (Parcelable) action);
+
+        context.sendBroadcast(intent);
+    }
+
+    public static void sendOutput(Context context, CharSequence s, int type, Object action, Object longAction) {
+        sendOutput(Integer.MAX_VALUE, context, s, type, action, longAction);
+    }
+
+    public static void sendOutput(int color, Context context, CharSequence s, int type, Object action, Object longAction) {
+        Intent intent = new Intent(InputOutputReceiver.ACTION_OUTPUT);
+        intent.putExtra(InputOutputReceiver.TEXT, s);
+        intent.putExtra(InputOutputReceiver.COLOR, color);
+        intent.putExtra(InputOutputReceiver.TYPE, type);
+
+        if(action instanceof String) intent.putExtra(InputOutputReceiver.ACTION, (String) action);
+        else if(action instanceof Parcelable) intent.putExtra(InputOutputReceiver.ACTION, (Parcelable) action);
+
+        if(longAction instanceof String) intent.putExtra(InputOutputReceiver.LONG_ACTION, (String) longAction);
+        else if(longAction instanceof Parcelable) intent.putExtra(InputOutputReceiver.LONG_ACTION, (Parcelable) longAction);
+
+        context.sendBroadcast(intent);
+    }
+
+    public static void sendInput(Context context, String text) {
+        Intent intent = new Intent(InputOutputReceiver.ACTION_INPUT);
+        intent.putExtra(InputOutputReceiver.TEXT, text);
+        context.sendBroadcast(intent);
+    }
+
     public static final int TERA = 0;
     public static final int GIGA = 1;
     public static final int MEGA = 2;
@@ -563,6 +674,8 @@ public class Tuils {
     }
 
     private static String getNicePath(String filePath) {
+        if(filePath == null) return "null";
+
         String home = XMLPrefsManager.get(File.class, Behavior.home_path).getAbsolutePath();
 
         if(filePath.equals(home)) {
@@ -704,11 +817,30 @@ public class Tuils {
 
         if(o instanceof Throwable) {
             Log.e("andre", "", (Throwable) o);
+        } else if(o instanceof Object[]){
+            Log.e("andre", Arrays.toString((Object[]) o));
         } else {
             Log.e("andre", String.valueOf(o));
         }
     }
 
+    public static void log(Object o, Object o2) {
+        if(o instanceof Object[] && o2 instanceof Object[]){
+            Log.e("andre", Arrays.toString((Object[]) o) + " -- " + Arrays.toString((Object[]) o2));
+        } else {
+            Log.e("andre", String.valueOf(o) + " -- " + String.valueOf(o2));
+        }
+    }
+
+    public static boolean hasInternetAccess() {
+        try {
+            HttpURLConnection urlc = (HttpURLConnection) (new URL("http://clients3.google.com/generate_204").openConnection());
+            return (urlc.getResponseCode() == 204 && urlc.getContentLength() == 0);
+        } catch (IOException e) {
+            return false;
+        }
+    }
+
     public static <T> T getDefaultValue(Class<T> clazz) {
         return (T) Array.get(Array.newInstance(clazz, 1), 0);
     }
@@ -807,7 +939,7 @@ public class Tuils {
         return true;
     }
 
-//    return -1 if only digit
+//    return 0 if only digit
     public static char firstNonDigit(String s) {
         if(s == null) {
             return 0;
@@ -994,4 +1126,75 @@ public class Tuils {
     public static String removeSpaces(String string) {
         return string.replaceAll(SPACE_REGEXP, EMPTYSTRING);
     }
+
+    public static String getNetworkType(Context context) {
+        TelephonyManager mTelephonyManager = (TelephonyManager)
+                context.getSystemService(Context.TELEPHONY_SERVICE);
+        int networkType = mTelephonyManager.getNetworkType();
+        switch (networkType) {
+            case TelephonyManager.NETWORK_TYPE_GPRS:
+            case TelephonyManager.NETWORK_TYPE_EDGE:
+            case TelephonyManager.NETWORK_TYPE_CDMA:
+            case TelephonyManager.NETWORK_TYPE_1xRTT:
+            case TelephonyManager.NETWORK_TYPE_IDEN:
+                return "2g";
+            case TelephonyManager.NETWORK_TYPE_UMTS:
+            case TelephonyManager.NETWORK_TYPE_EVDO_0:
+            case TelephonyManager.NETWORK_TYPE_EVDO_A:
+            case TelephonyManager.NETWORK_TYPE_HSDPA:
+            case TelephonyManager.NETWORK_TYPE_HSUPA:
+            case TelephonyManager.NETWORK_TYPE_HSPA:
+            case TelephonyManager.NETWORK_TYPE_EVDO_B:
+            case TelephonyManager.NETWORK_TYPE_EHRPD:
+            case TelephonyManager.NETWORK_TYPE_HSPAP:
+                return "3g";
+            case TelephonyManager.NETWORK_TYPE_LTE:
+                return "4g";
+            default:
+                return "unknown";
+        }
+    }
+
+    public static void setCursorDrawableColor(EditText editText, int color) {
+        try {
+            Field fCursorDrawableRes = TextView.class.getDeclaredField("mCursorDrawableRes");
+            fCursorDrawableRes.setAccessible(true);
+            int mCursorDrawableRes = fCursorDrawableRes.getInt(editText);
+            Field fEditor = TextView.class.getDeclaredField("mEditor");
+            fEditor.setAccessible(true);
+            Object editor = fEditor.get(editText);
+            Class<?> clazz = editor.getClass();
+            Field fCursorDrawable = clazz.getDeclaredField("mCursorDrawable");
+            fCursorDrawable.setAccessible(true);
+            Drawable[] drawables = new Drawable[2];
+            drawables[0] = editText.getContext().getResources().getDrawable(mCursorDrawableRes);
+            drawables[1] = editText.getContext().getResources().getDrawable(mCursorDrawableRes);
+            drawables[0].setColorFilter(color, PorterDuff.Mode.SRC_IN);
+            drawables[1].setColorFilter(color, PorterDuff.Mode.SRC_IN);
+            fCursorDrawable.set(editor, drawables);
+        } catch (Throwable ignored) {}
+    }
+
+    public static int nOfBytes(File file) {
+        int count = 0;
+        try {
+            FileInputStream in = new FileInputStream(file);
+
+            while(in.read() != -1) count++;
+
+            return count;
+        } catch (IOException e) {
+            Tuils.log(e);
+            return count;
+        }
+    }
+
+    public static void sendXMLParseError(Context context, String PATH, Exception e) {
+        Tuils.sendOutput(Color.RED, context, context.getString(R.string.output_xmlproblem1) + Tuils.SPACE + PATH + context.getString(R.string.output_xmlproblem2) +
+                Tuils.NEWLINE + context.getString(R.string.output_errorlabel) + e.toString());
+    }
+
+    public static void sendXMLParseError(Context context, String PATH) {
+        Tuils.sendOutput(Color.RED, context, context.getString(R.string.output_xmlproblem1) + Tuils.SPACE + PATH + context.getString(R.string.output_xmlproblem2));
+    }
 }
diff --git a/app/src/main/java/ohi/andre/consolelauncher/tuils/html_escape/Html4EscapeSymbolsInitializer.java b/app/src/main/java/ohi/andre/consolelauncher/tuils/html_escape/Html4EscapeSymbolsInitializer.java
new file mode 100755
index 0000000..d4f774a
--- /dev/null
+++ b/app/src/main/java/ohi/andre/consolelauncher/tuils/html_escape/Html4EscapeSymbolsInitializer.java
@@ -0,0 +1,356 @@
+/*
+ * =============================================================================
+ * 
+ *   Copyright (c) 2014-2017, The UNBESCAPE team (http://www.unbescape.org)
+ * 
+ *   Licensed under the Apache License, Version 2.0 (the "License");
+ *   you may not use this file except in compliance with the License.
+ *   You may obtain a copy of the License at
+ * 
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ *   Unless required by applicable law or agreed to in writing, software
+ *   distributed under the License is distributed on an "AS IS" BASIS,
+ *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *   See the License for the specific language governing permissions and
+ *   limitations under the License.
+ * 
+ * =============================================================================
+ */
+package ohi.andre.consolelauncher.tuils.html_escape;
+
+import java.util.Arrays;
+
+/**
+ * <p>
+ *   This class initializes the {@link org.unbescape.html.HtmlEscapeSymbols#HTML4_SYMBOLS} structure.
+ * </p>
+ * 
+ * @author Daniel Fern&aacute;ndez
+ * 
+ * @since 1.0.0
+ *
+ */
+final class Html4EscapeSymbolsInitializer {
+
+
+    static HtmlEscapeSymbols initializeHtml4() {
+
+        final HtmlEscapeSymbols.References html4References = new HtmlEscapeSymbols.References();
+
+        /*
+         * -----------------------------------------------------------------
+         *   HTML4 NAMED CHARACTER REFERENCES (CHARACTER ENTITY REFERENCES)
+         *   See: http://www.w3.org/TR/html4/sgml/entities.html
+         * -----------------------------------------------------------------
+         */
+
+        /* HTML NCRs FOR MARKUP-SIGNIFICANT CHARACTERS */
+        // (Note HTML 4 does not include &apos; as a valid NCR)
+        html4References.addReference('"', "&quot;");
+        html4References.addReference('&', "&amp;");
+        html4References.addReference('<', "&lt;");
+        html4References.addReference('>', "&gt;");
+        /* HTML NCRs FOR ISO-8859-1 CHARACTERS */
+        html4References.addReference('\u00A0', "&nbsp;");
+        html4References.addReference('\u00A1', "&iexcl;");
+        html4References.addReference('\u00A2', "&cent;");
+        html4References.addReference('\u00A3', "&pound;");
+        html4References.addReference('\u00A4', "&curren;");
+        html4References.addReference('\u00A5', "&yen;");
+        html4References.addReference('\u00A6', "&brvbar;");
+        html4References.addReference('\u00A7', "&sect;");
+        html4References.addReference('\u00A8', "&uml;");
+        html4References.addReference('\u00A9', "&copy;");
+        html4References.addReference('\u00AA', "&ordf;");
+        html4References.addReference('\u00AB', "&laquo;");
+        html4References.addReference('\u00AC', "&not;");
+        html4References.addReference('\u00AD', "&shy;");
+        html4References.addReference('\u00AE', "&reg;");
+        html4References.addReference('\u00AF', "&macr;");
+        html4References.addReference('\u00B0', "&deg;");
+        html4References.addReference('\u00B1', "&plusmn;");
+        html4References.addReference('\u00B2', "&sup2;");
+        html4References.addReference('\u00B3', "&sup3;");
+        html4References.addReference('\u00B4', "&acute;");
+        html4References.addReference('\u00B5', "&micro;");
+        html4References.addReference('\u00B6', "&para;");
+        html4References.addReference('\u00B7', "&middot;");
+        html4References.addReference('\u00B8', "&cedil;");
+        html4References.addReference('\u00B9', "&sup1;");
+        html4References.addReference('\u00BA', "&ordm;");
+        html4References.addReference('\u00BB', "&raquo;");
+        html4References.addReference('\u00BC', "&frac14;");
+        html4References.addReference('\u00BD', "&frac12;");
+        html4References.addReference('\u00BE', "&frac34;");
+        html4References.addReference('\u00BF', "&iquest;");
+        html4References.addReference('\u00C0', "&Agrave;");
+        html4References.addReference('\u00C1', "&Aacute;");
+        html4References.addReference('\u00C2', "&Acirc;");
+        html4References.addReference('\u00C3', "&Atilde;");
+        html4References.addReference('\u00C4', "&Auml;");
+        html4References.addReference('\u00C5', "&Aring;");
+        html4References.addReference('\u00C6', "&AElig;");
+        html4References.addReference('\u00C7', "&Ccedil;");
+        html4References.addReference('\u00C8', "&Egrave;");
+        html4References.addReference('\u00C9', "&Eacute;");
+        html4References.addReference('\u00CA', "&Ecirc;");
+        html4References.addReference('\u00CB', "&Euml;");
+        html4References.addReference('\u00CC', "&Igrave;");
+        html4References.addReference('\u00CD', "&Iacute;");
+        html4References.addReference('\u00CE', "&Icirc;");
+        html4References.addReference('\u00CF', "&Iuml;");
+        html4References.addReference('\u00D0', "&ETH;");
+        html4References.addReference('\u00D1', "&Ntilde;");
+        html4References.addReference('\u00D2', "&Ograve;");
+        html4References.addReference('\u00D3', "&Oacute;");
+        html4References.addReference('\u00D4', "&Ocirc;");
+        html4References.addReference('\u00D5', "&Otilde;");
+        html4References.addReference('\u00D6', "&Ouml;");
+        html4References.addReference('\u00D7', "&times;");
+        html4References.addReference('\u00D8', "&Oslash;");
+        html4References.addReference('\u00D9', "&Ugrave;");
+        html4References.addReference('\u00DA', "&Uacute;");
+        html4References.addReference('\u00DB', "&Ucirc;");
+        html4References.addReference('\u00DC', "&Uuml;");
+        html4References.addReference('\u00DD', "&Yacute;");
+        html4References.addReference('\u00DE', "&THORN;");
+        html4References.addReference('\u00DF', "&szlig;");
+        html4References.addReference('\u00E0', "&agrave;");
+        html4References.addReference('\u00E1', "&aacute;");
+        html4References.addReference('\u00E2', "&acirc;");
+        html4References.addReference('\u00E3', "&atilde;");
+        html4References.addReference('\u00E4', "&auml;");
+        html4References.addReference('\u00E5', "&aring;");
+        html4References.addReference('\u00E6', "&aelig;");
+        html4References.addReference('\u00E7', "&ccedil;");
+        html4References.addReference('\u00E8', "&egrave;");
+        html4References.addReference('\u00E9', "&eacute;");
+        html4References.addReference('\u00EA', "&ecirc;");
+        html4References.addReference('\u00EB', "&euml;");
+        html4References.addReference('\u00EC', "&igrave;");
+        html4References.addReference('\u00ED', "&iacute;");
+        html4References.addReference('\u00EE', "&icirc;");
+        html4References.addReference('\u00EF', "&iuml;");
+        html4References.addReference('\u00F0', "&eth;");
+        html4References.addReference('\u00F1', "&ntilde;");
+        html4References.addReference('\u00F2', "&ograve;");
+        html4References.addReference('\u00F3', "&oacute;");
+        html4References.addReference('\u00F4', "&ocirc;");
+        html4References.addReference('\u00F5', "&otilde;");
+        html4References.addReference('\u00F6', "&ouml;");
+        html4References.addReference('\u00F7', "&divide;");
+        html4References.addReference('\u00F8', "&oslash;");
+        html4References.addReference('\u00F9', "&ugrave;");
+        html4References.addReference('\u00FA', "&uacute;");
+        html4References.addReference('\u00FB', "&ucirc;");
+        html4References.addReference('\u00FC', "&uuml;");
+        html4References.addReference('\u00FD', "&yacute;");
+        html4References.addReference('\u00FE', "&thorn;");
+        html4References.addReference('\u00FF', "&yuml;");
+        /* HTML NCRs FOR SYMBOLS, MATHEMATICAL SYMBOLS AND GREEK LETTERS */
+        /* - Greek */
+        html4References.addReference('\u0192', "&fnof;");
+        html4References.addReference('\u0391', "&Alpha;");
+        html4References.addReference('\u0392', "&Beta;");
+        html4References.addReference('\u0393', "&Gamma;");
+        html4References.addReference('\u0394', "&Delta;");
+        html4References.addReference('\u0395', "&Epsilon;");
+        html4References.addReference('\u0396', "&Zeta;");
+        html4References.addReference('\u0397', "&Eta;");
+        html4References.addReference('\u0398', "&Theta;");
+        html4References.addReference('\u0399', "&Iota;");
+        html4References.addReference('\u039A', "&Kappa;");
+        html4References.addReference('\u039B', "&Lambda;");
+        html4References.addReference('\u039C', "&Mu;");
+        html4References.addReference('\u039D', "&Nu;");
+        html4References.addReference('\u039E', "&Xi;");
+        html4References.addReference('\u039F', "&Omicron;");
+        html4References.addReference('\u03A0', "&Pi;");
+        html4References.addReference('\u03A1', "&Rho;");
+        html4References.addReference('\u03A3', "&Sigma;");
+        html4References.addReference('\u03A4', "&Tau;");
+        html4References.addReference('\u03A5', "&Upsilon;");
+        html4References.addReference('\u03A6', "&Phi;");
+        html4References.addReference('\u03A7', "&Chi;");
+        html4References.addReference('\u03A8', "&Psi;");
+        html4References.addReference('\u03A9', "&Omega;");
+        html4References.addReference('\u03B1', "&alpha;");
+        html4References.addReference('\u03B2', "&beta;");
+        html4References.addReference('\u03B3', "&gamma;");
+        html4References.addReference('\u03B4', "&delta;");
+        html4References.addReference('\u03B5', "&epsilon;");
+        html4References.addReference('\u03B6', "&zeta;");
+        html4References.addReference('\u03B7', "&eta;");
+        html4References.addReference('\u03B8', "&theta;");
+        html4References.addReference('\u03B9', "&iota;");
+        html4References.addReference('\u03BA', "&kappa;");
+        html4References.addReference('\u03BB', "&lambda;");
+        html4References.addReference('\u03BC', "&mu;");
+        html4References.addReference('\u03BD', "&nu;");
+        html4References.addReference('\u03BE', "&xi;");
+        html4References.addReference('\u03BF', "&omicron;");
+        html4References.addReference('\u03C0', "&pi;");
+        html4References.addReference('\u03C1', "&rho;");
+        html4References.addReference('\u03C2', "&sigmaf;");
+        html4References.addReference('\u03C3', "&sigma;");
+        html4References.addReference('\u03C4', "&tau;");
+        html4References.addReference('\u03C5', "&upsilon;");
+        html4References.addReference('\u03C6', "&phi;");
+        html4References.addReference('\u03C7', "&chi;");
+        html4References.addReference('\u03C8', "&psi;");
+        html4References.addReference('\u03C9', "&omega;");
+        html4References.addReference('\u03D1', "&thetasym;");
+        html4References.addReference('\u03D2', "&upsih;");
+        html4References.addReference('\u03D6', "&piv;");
+        /* - General punctuation */
+        html4References.addReference('\u2022', "&bull;");
+        html4References.addReference('\u2026', "&hellip;");
+        html4References.addReference('\u2032', "&prime;");
+        html4References.addReference('\u2033', "&Prime;");
+        html4References.addReference('\u203E', "&oline;");
+        html4References.addReference('\u2044', "&frasl;");
+        /* - Letter-like symbols */
+        html4References.addReference('\u2118', "&weierp;");
+        html4References.addReference('\u2111', "&image;");
+        html4References.addReference('\u211C', "&real;");
+        html4References.addReference('\u2122', "&trade;");
+        html4References.addReference('\u2135', "&alefsym;");
+        /* - Arrows */
+        html4References.addReference('\u2190', "&larr;");
+        html4References.addReference('\u2191', "&uarr;");
+        html4References.addReference('\u2192', "&rarr;");
+        html4References.addReference('\u2193', "&darr;");
+        html4References.addReference('\u2194', "&harr;");
+        html4References.addReference('\u21B5', "&crarr;");
+        html4References.addReference('\u21D0', "&lArr;");
+        html4References.addReference('\u21D1', "&uArr;");
+        html4References.addReference('\u21D2', "&rArr;");
+        html4References.addReference('\u21D3', "&dArr;");
+        html4References.addReference('\u21D4', "&hArr;");
+        /* - Mathematical operators */
+        html4References.addReference('\u2200', "&forall;");
+        html4References.addReference('\u2202', "&part;");
+        html4References.addReference('\u2203', "&exist;");
+        html4References.addReference('\u2205', "&empty;");
+        html4References.addReference('\u2207', "&nabla;");
+        html4References.addReference('\u2208', "&isin;");
+        html4References.addReference('\u2209', "&notin;");
+        html4References.addReference('\u220B', "&ni;");
+        html4References.addReference('\u220F', "&prod;");
+        html4References.addReference('\u2211', "&sum;");
+        html4References.addReference('\u2212', "&minus;");
+        html4References.addReference('\u2217', "&lowast;");
+        html4References.addReference('\u221A', "&radic;");
+        html4References.addReference('\u221D', "&prop;");
+        html4References.addReference('\u221E', "&infin;");
+        html4References.addReference('\u2220', "&ang;");
+        html4References.addReference('\u2227', "&and;");
+        html4References.addReference('\u2228', "&or;");
+        html4References.addReference('\u2229', "&cap;");
+        html4References.addReference('\u222A', "&cup;");
+        html4References.addReference('\u222B', "&int;");
+        html4References.addReference('\u2234', "&there4;");
+        html4References.addReference('\u223C', "&sim;");
+        html4References.addReference('\u2245', "&cong;");
+        html4References.addReference('\u2248', "&asymp;");
+        html4References.addReference('\u2260', "&ne;");
+        html4References.addReference('\u2261', "&equiv;");
+        html4References.addReference('\u2264', "&le;");
+        html4References.addReference('\u2265', "&ge;");
+        html4References.addReference('\u2282', "&sub;");
+        html4References.addReference('\u2283', "&sup;");
+        html4References.addReference('\u2284', "&nsub;");
+        html4References.addReference('\u2286', "&sube;");
+        html4References.addReference('\u2287', "&supe;");
+        html4References.addReference('\u2295', "&oplus;");
+        html4References.addReference('\u2297', "&otimes;");
+        html4References.addReference('\u22A5', "&perp;");
+        html4References.addReference('\u22C5', "&sdot;");
+        /* - Miscellaneous technical */
+        html4References.addReference('\u2308', "&lceil;");
+        html4References.addReference('\u2309', "&rceil;");
+        html4References.addReference('\u230A', "&lfloor;");
+        html4References.addReference('\u230B', "&rfloor;");
+        html4References.addReference('\u2329', "&lang;");
+        html4References.addReference('\u232A', "&rang;");
+        /* - Geometric shapes */
+        html4References.addReference('\u25CA', "&loz;");
+        html4References.addReference('\u2660', "&spades;");
+        html4References.addReference('\u2663', "&clubs;");
+        html4References.addReference('\u2665', "&hearts;");
+        html4References.addReference('\u2666', "&diams;");
+        /* HTML NCRs FOR INTERNATIONALIZATION CHARACTERS */
+        /* - Latin Extended-A */
+        html4References.addReference('\u0152', "&OElig;");
+        html4References.addReference('\u0153', "&oelig;");
+        html4References.addReference('\u0160', "&Scaron;");
+        html4References.addReference('\u0161', "&scaron;");
+        html4References.addReference('\u0178', "&Yuml;");
+        /* - Spacing modifier letters */
+        html4References.addReference('\u02C6', "&circ;");
+        html4References.addReference('\u02DC', "&tilde;");
+        /* - General punctuation */
+        html4References.addReference('\u2002', "&ensp;");
+        html4References.addReference('\u2003', "&emsp;");
+        html4References.addReference('\u2009', "&thinsp;");
+        html4References.addReference('\u200C', "&zwnj;");
+        html4References.addReference('\u200D', "&zwj;");
+        html4References.addReference('\u200E', "&lrm;");
+        html4References.addReference('\u200F', "&rlm;");
+        html4References.addReference('\u2013', "&ndash;");
+        html4References.addReference('\u2014', "&mdash;");
+        html4References.addReference('\u2018', "&lsquo;");
+        html4References.addReference('\u2019', "&rsquo;");
+        html4References.addReference('\u201A', "&sbquo;");
+        html4References.addReference('\u201C', "&ldquo;");
+        html4References.addReference('\u201D', "&rdquo;");
+        html4References.addReference('\u201E', "&bdquo;");
+        html4References.addReference('\u2020', "&dagger;");
+        html4References.addReference('\u2021', "&Dagger;");
+        html4References.addReference('\u2030', "&permil;");
+        html4References.addReference('\u2039', "&lsaquo;");
+        html4References.addReference('\u203A', "&rsaquo;");
+        html4References.addReference('\u20AC', "&euro;");
+
+
+        /*
+         * Initialization of escape levels.
+         * Defined levels :
+         *
+         *    - Level 0 : Only markup-significant characters except the apostrophe (')
+         *    - Level 1 : Only markup-significant characters (including the apostrophe)
+         *    - Level 2 : Markup-significant characters plus all non-ASCII
+         *    - Level 3 : All non-alphanumeric characters
+         *    - Level 4 : All characters
+         */
+        final byte[] escapeLevels = new byte[0x7f + 2];
+        Arrays.fill(escapeLevels, (byte)3);
+        for (char c = 'A'; c <= 'Z'; c++) {
+            escapeLevels[c] = 4;
+        }
+        for (char c = 'a'; c <= 'z'; c++) {
+            escapeLevels[c] = 4;
+        }
+        for (char c = '0'; c <= '9'; c++) {
+            escapeLevels[c] = 4;
+        }
+        escapeLevels['\''] = 1;
+        escapeLevels['"'] = 0;
+        escapeLevels['<'] = 0;
+        escapeLevels['>'] = 0;
+        escapeLevels['&'] = 0;
+        escapeLevels[0x7f + 1] = 2;
+
+
+        return new HtmlEscapeSymbols(html4References, escapeLevels);
+
+    }
+
+
+    private Html4EscapeSymbolsInitializer() {
+        super();
+    }
+
+}
+
diff --git a/app/src/main/java/ohi/andre/consolelauncher/tuils/html_escape/Html5EscapeSymbolsInitializer.java b/app/src/main/java/ohi/andre/consolelauncher/tuils/html_escape/Html5EscapeSymbolsInitializer.java
new file mode 100755
index 0000000..b4cbf22
--- /dev/null
+++ b/app/src/main/java/ohi/andre/consolelauncher/tuils/html_escape/Html5EscapeSymbolsInitializer.java
@@ -0,0 +1,2320 @@
+/*
+ * =============================================================================
+ * 
+ *   Copyright (c) 2014-2017, The UNBESCAPE team (http://www.unbescape.org)
+ * 
+ *   Licensed under the Apache License, Version 2.0 (the "License");
+ *   you may not use this file except in compliance with the License.
+ *   You may obtain a copy of the License at
+ * 
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ *   Unless required by applicable law or agreed to in writing, software
+ *   distributed under the License is distributed on an "AS IS" BASIS,
+ *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *   See the License for the specific language governing permissions and
+ *   limitations under the License.
+ * 
+ * =============================================================================
+ */
+package ohi.andre.consolelauncher.tuils.html_escape;
+
+import java.util.Arrays;
+
+/**
+ * <p>
+ *   This class initializes the {@link org.unbescape.html.HtmlEscapeSymbols#HTML5_SYMBOLS} structure.
+ * </p>
+ *
+ * @author Daniel Fern&aacute;ndez
+ * 
+ * @since 1.0.0
+ *
+ */
+final class Html5EscapeSymbolsInitializer {
+
+
+    static HtmlEscapeSymbols initializeHtml5() {
+
+        final HtmlEscapeSymbols.References html5References = new HtmlEscapeSymbols.References();
+
+        /*
+         * --------------------------------------------------------------------------------------------------
+         *   HTML5 NAMED CHARACTER REFERENCES
+         *   See: http://www.w3.org/TR/html5/syntax.html#named-character-references  [HTML5]
+         *        http://www.w3.org/TR/html51/syntax.html#named-character-references [HTML 5.1]
+         * --------------------------------------------------------------------------------------------------
+         */
+        html5References.addReference(     9, "&Tab;");
+        html5References.addReference(    10, "&NewLine;");
+        html5References.addReference(    33, "&excl;");
+        html5References.addReference(    34, "&quot;");
+        html5References.addReference(    34, "&quot");
+        html5References.addReference(    34, "&QUOT");
+        html5References.addReference(    34, "&QUOT;");
+        html5References.addReference(    35, "&num;");
+        html5References.addReference(    36, "&dollar;");
+        html5References.addReference(    37, "&percnt;");
+        html5References.addReference(    38, "&amp;");
+        html5References.addReference(    38, "&amp");
+        html5References.addReference(    38, "&AMP");
+        html5References.addReference(    38, "&AMP;");
+        html5References.addReference(    39, "&apos;");
+        html5References.addReference(    40, "&lpar;");
+        html5References.addReference(    41, "&rpar;");
+        html5References.addReference(    42, "&ast;");
+        html5References.addReference(    42, "&midast;");
+        html5References.addReference(    43, "&plus;");
+        html5References.addReference(    44, "&comma;");
+        html5References.addReference(    46, "&period;");
+        html5References.addReference(    47, "&sol;");
+        html5References.addReference(    58, "&colon;");
+        html5References.addReference(    59, "&semi;");
+        html5References.addReference(    60, "&lt;");
+        html5References.addReference(    60, "&lt");
+        html5References.addReference(    60, "&LT");
+        html5References.addReference(    60, "&LT;");
+        html5References.addReference(    60,  8402, "&nvlt;");
+        html5References.addReference(    61, "&equals;");
+        html5References.addReference(    61,  8421, "&bne;");
+        html5References.addReference(    62, "&gt;");
+        html5References.addReference(    62, "&gt");
+        html5References.addReference(    62, "&GT");
+        html5References.addReference(    62, "&GT;");
+        html5References.addReference(    62,  8402, "&nvgt;");
+        html5References.addReference(    63, "&quest;");
+        html5References.addReference(    64, "&commat;");
+        html5References.addReference(    91, "&lbrack;");
+        html5References.addReference(    91, "&lsqb;");
+        html5References.addReference(    92, "&bsol;");
+        html5References.addReference(    93, "&rbrack;");
+        html5References.addReference(    93, "&rsqb;");
+        html5References.addReference(    94, "&Hat;");
+        html5References.addReference(    95, "&lowbar;");
+        html5References.addReference(    95, "&UnderBar;");
+        html5References.addReference(    96, "&grave;");
+        html5References.addReference(    96, "&DiacriticalGrave;");
+        html5References.addReference(   102,   106, "&fjlig;");
+        html5References.addReference(   123, "&lbrace;");
+        html5References.addReference(   123, "&lcub;");
+        html5References.addReference(   124, "&verbar;");
+        html5References.addReference(   124, "&vert;");
+        html5References.addReference(   124, "&VerticalLine;");
+        html5References.addReference(   125, "&rbrace;");
+        html5References.addReference(   125, "&rcub;");
+        html5References.addReference(   160, "&nbsp;");
+        html5References.addReference(   160, "&nbsp");
+        html5References.addReference(   160, "&NonBreakingSpace;");
+        html5References.addReference(   161, "&iexcl;");
+        html5References.addReference(   161, "&iexcl");
+        html5References.addReference(   162, "&cent;");
+        html5References.addReference(   162, "&cent");
+        html5References.addReference(   163, "&pound;");
+        html5References.addReference(   163, "&pound");
+        html5References.addReference(   164, "&curren;");
+        html5References.addReference(   164, "&curren");
+        html5References.addReference(   165, "&yen;");
+        html5References.addReference(   165, "&yen");
+        html5References.addReference(   166, "&brvbar;");
+        html5References.addReference(   166, "&brvbar");
+        html5References.addReference(   167, "&sect;");
+        html5References.addReference(   167, "&sect");
+        html5References.addReference(   168, "&uml;");
+        html5References.addReference(   168, "&die;");
+        html5References.addReference(   168, "&uml");
+        html5References.addReference(   168, "&Dot;");
+        html5References.addReference(   168, "&DoubleDot;");
+        html5References.addReference(   169, "&copy;");
+        html5References.addReference(   169, "&copy");
+        html5References.addReference(   169, "&COPY");
+        html5References.addReference(   169, "&COPY;");
+        html5References.addReference(   170, "&ordf;");
+        html5References.addReference(   170, "&ordf");
+        html5References.addReference(   171, "&laquo;");
+        html5References.addReference(   171, "&laquo");
+        html5References.addReference(   172, "&not;");
+        html5References.addReference(   172, "&not");
+        html5References.addReference(   173, "&shy;");
+        html5References.addReference(   173, "&shy");
+        html5References.addReference(   174, "&reg;");
+        html5References.addReference(   174, "&circledR;");
+        html5References.addReference(   174, "&reg");
+        html5References.addReference(   174, "&REG");
+        html5References.addReference(   174, "&REG;");
+        html5References.addReference(   175, "&macr;");
+        html5References.addReference(   175, "&macr");
+        html5References.addReference(   175, "&strns;");
+        html5References.addReference(   176, "&deg;");
+        html5References.addReference(   176, "&deg");
+        html5References.addReference(   177, "&plusmn;");
+        html5References.addReference(   177, "&plusmn");
+        html5References.addReference(   177, "&pm;");
+        html5References.addReference(   177, "&PlusMinus;");
+        html5References.addReference(   178, "&sup2;");
+        html5References.addReference(   178, "&sup2");
+        html5References.addReference(   179, "&sup3;");
+        html5References.addReference(   179, "&sup3");
+        html5References.addReference(   180, "&acute;");
+        html5References.addReference(   180, "&acute");
+        html5References.addReference(   180, "&DiacriticalAcute;");
+        html5References.addReference(   181, "&micro;");
+        html5References.addReference(   181, "&micro");
+        html5References.addReference(   182, "&para;");
+        html5References.addReference(   182, "&para");
+        html5References.addReference(   183, "&middot;");
+        html5References.addReference(   183, "&centerdot;");
+        html5References.addReference(   183, "&middot");
+        html5References.addReference(   183, "&CenterDot;");
+        html5References.addReference(   184, "&cedil;");
+        html5References.addReference(   184, "&cedil");
+        html5References.addReference(   184, "&Cedilla;");
+        html5References.addReference(   185, "&sup1;");
+        html5References.addReference(   185, "&sup1");
+        html5References.addReference(   186, "&ordm;");
+        html5References.addReference(   186, "&ordm");
+        html5References.addReference(   187, "&raquo;");
+        html5References.addReference(   187, "&raquo");
+        html5References.addReference(   188, "&frac14;");
+        html5References.addReference(   188, "&frac14");
+        html5References.addReference(   189, "&frac12;");
+        html5References.addReference(   189, "&frac12");
+        html5References.addReference(   189, "&half;");
+        html5References.addReference(   190, "&frac34;");
+        html5References.addReference(   190, "&frac34");
+        html5References.addReference(   191, "&iquest;");
+        html5References.addReference(   191, "&iquest");
+        html5References.addReference(   192, "&Agrave;");
+        html5References.addReference(   192, "&Agrave");
+        html5References.addReference(   193, "&Aacute;");
+        html5References.addReference(   193, "&Aacute");
+        html5References.addReference(   194, "&Acirc;");
+        html5References.addReference(   194, "&Acirc");
+        html5References.addReference(   195, "&Atilde;");
+        html5References.addReference(   195, "&Atilde");
+        html5References.addReference(   196, "&Auml;");
+        html5References.addReference(   196, "&Auml");
+        html5References.addReference(   197, "&Aring;");
+        html5References.addReference(   197, "&angst;");
+        html5References.addReference(   197, "&Aring");
+        html5References.addReference(   198, "&AElig;");
+        html5References.addReference(   198, "&AElig");
+        html5References.addReference(   199, "&Ccedil;");
+        html5References.addReference(   199, "&Ccedil");
+        html5References.addReference(   200, "&Egrave;");
+        html5References.addReference(   200, "&Egrave");
+        html5References.addReference(   201, "&Eacute;");
+        html5References.addReference(   201, "&Eacute");
+        html5References.addReference(   202, "&Ecirc;");
+        html5References.addReference(   202, "&Ecirc");
+        html5References.addReference(   203, "&Euml;");
+        html5References.addReference(   203, "&Euml");
+        html5References.addReference(   204, "&Igrave;");
+        html5References.addReference(   204, "&Igrave");
+        html5References.addReference(   205, "&Iacute;");
+        html5References.addReference(   205, "&Iacute");
+        html5References.addReference(   206, "&Icirc;");
+        html5References.addReference(   206, "&Icirc");
+        html5References.addReference(   207, "&Iuml;");
+        html5References.addReference(   207, "&Iuml");
+        html5References.addReference(   208, "&ETH;");
+        html5References.addReference(   208, "&ETH");
+        html5References.addReference(   209, "&Ntilde;");
+        html5References.addReference(   209, "&Ntilde");
+        html5References.addReference(   210, "&Ograve;");
+        html5References.addReference(   210, "&Ograve");
+        html5References.addReference(   211, "&Oacute;");
+        html5References.addReference(   211, "&Oacute");
+        html5References.addReference(   212, "&Ocirc;");
+        html5References.addReference(   212, "&Ocirc");
+        html5References.addReference(   213, "&Otilde;");
+        html5References.addReference(   213, "&Otilde");
+        html5References.addReference(   214, "&Ouml;");
+        html5References.addReference(   214, "&Ouml");
+        html5References.addReference(   215, "&times;");
+        html5References.addReference(   215, "&times");
+        html5References.addReference(   216, "&Oslash;");
+        html5References.addReference(   216, "&Oslash");
+        html5References.addReference(   217, "&Ugrave;");
+        html5References.addReference(   217, "&Ugrave");
+        html5References.addReference(   218, "&Uacute;");
+        html5References.addReference(   218, "&Uacute");
+        html5References.addReference(   219, "&Ucirc;");
+        html5References.addReference(   219, "&Ucirc");
+        html5References.addReference(   220, "&Uuml;");
+        html5References.addReference(   220, "&Uuml");
+        html5References.addReference(   221, "&Yacute;");
+        html5References.addReference(   221, "&Yacute");
+        html5References.addReference(   222, "&THORN;");
+        html5References.addReference(   222, "&THORN");
+        html5References.addReference(   223, "&szlig;");
+        html5References.addReference(   223, "&szlig");
+        html5References.addReference(   224, "&agrave;");
+        html5References.addReference(   224, "&agrave");
+        html5References.addReference(   225, "&aacute;");
+        html5References.addReference(   225, "&aacute");
+        html5References.addReference(   226, "&acirc;");
+        html5References.addReference(   226, "&acirc");
+        html5References.addReference(   227, "&atilde;");
+        html5References.addReference(   227, "&atilde");
+        html5References.addReference(   228, "&auml;");
+        html5References.addReference(   228, "&auml");
+        html5References.addReference(   229, "&aring;");
+        html5References.addReference(   229, "&aring");
+        html5References.addReference(   230, "&aelig;");
+        html5References.addReference(   230, "&aelig");
+        html5References.addReference(   231, "&ccedil;");
+        html5References.addReference(   231, "&ccedil");
+        html5References.addReference(   232, "&egrave;");
+        html5References.addReference(   232, "&egrave");
+        html5References.addReference(   233, "&eacute;");
+        html5References.addReference(   233, "&eacute");
+        html5References.addReference(   234, "&ecirc;");
+        html5References.addReference(   234, "&ecirc");
+        html5References.addReference(   235, "&euml;");
+        html5References.addReference(   235, "&euml");
+        html5References.addReference(   236, "&igrave;");
+        html5References.addReference(   236, "&igrave");
+        html5References.addReference(   237, "&iacute;");
+        html5References.addReference(   237, "&iacute");
+        html5References.addReference(   238, "&icirc;");
+        html5References.addReference(   238, "&icirc");
+        html5References.addReference(   239, "&iuml;");
+        html5References.addReference(   239, "&iuml");
+        html5References.addReference(   240, "&eth;");
+        html5References.addReference(   240, "&eth");
+        html5References.addReference(   241, "&ntilde;");
+        html5References.addReference(   241, "&ntilde");
+        html5References.addReference(   242, "&ograve;");
+        html5References.addReference(   242, "&ograve");
+        html5References.addReference(   243, "&oacute;");
+        html5References.addReference(   243, "&oacute");
+        html5References.addReference(   244, "&ocirc;");
+        html5References.addReference(   244, "&ocirc");
+        html5References.addReference(   245, "&otilde;");
+        html5References.addReference(   245, "&otilde");
+        html5References.addReference(   246, "&ouml;");
+        html5References.addReference(   246, "&ouml");
+        html5References.addReference(   247, "&divide;");
+        html5References.addReference(   247, "&div;");
+        html5References.addReference(   247, "&divide");
+        html5References.addReference(   248, "&oslash;");
+        html5References.addReference(   248, "&oslash");
+        html5References.addReference(   249, "&ugrave;");
+        html5References.addReference(   249, "&ugrave");
+        html5References.addReference(   250, "&uacute;");
+        html5References.addReference(   250, "&uacute");
+        html5References.addReference(   251, "&ucirc;");
+        html5References.addReference(   251, "&ucirc");
+        html5References.addReference(   252, "&uuml;");
+        html5References.addReference(   252, "&uuml");
+        html5References.addReference(   253, "&yacute;");
+        html5References.addReference(   253, "&yacute");
+        html5References.addReference(   254, "&thorn;");
+        html5References.addReference(   254, "&thorn");
+        html5References.addReference(   255, "&yuml;");
+        html5References.addReference(   255, "&yuml");
+        html5References.addReference(   256, "&Amacr;");
+        html5References.addReference(   257, "&amacr;");
+        html5References.addReference(   258, "&Abreve;");
+        html5References.addReference(   259, "&abreve;");
+        html5References.addReference(   260, "&Aogon;");
+        html5References.addReference(   261, "&aogon;");
+        html5References.addReference(   262, "&Cacute;");
+        html5References.addReference(   263, "&cacute;");
+        html5References.addReference(   264, "&Ccirc;");
+        html5References.addReference(   265, "&ccirc;");
+        html5References.addReference(   266, "&Cdot;");
+        html5References.addReference(   267, "&cdot;");
+        html5References.addReference(   268, "&Ccaron;");
+        html5References.addReference(   269, "&ccaron;");
+        html5References.addReference(   270, "&Dcaron;");
+        html5References.addReference(   271, "&dcaron;");
+        html5References.addReference(   272, "&Dstrok;");
+        html5References.addReference(   273, "&dstrok;");
+        html5References.addReference(   274, "&Emacr;");
+        html5References.addReference(   275, "&emacr;");
+        html5References.addReference(   278, "&Edot;");
+        html5References.addReference(   279, "&edot;");
+        html5References.addReference(   280, "&Eogon;");
+        html5References.addReference(   281, "&eogon;");
+        html5References.addReference(   282, "&Ecaron;");
+        html5References.addReference(   283, "&ecaron;");
+        html5References.addReference(   284, "&Gcirc;");
+        html5References.addReference(   285, "&gcirc;");
+        html5References.addReference(   286, "&Gbreve;");
+        html5References.addReference(   287, "&gbreve;");
+        html5References.addReference(   288, "&Gdot;");
+        html5References.addReference(   289, "&gdot;");
+        html5References.addReference(   290, "&Gcedil;");
+        html5References.addReference(   292, "&Hcirc;");
+        html5References.addReference(   293, "&hcirc;");
+        html5References.addReference(   294, "&Hstrok;");
+        html5References.addReference(   295, "&hstrok;");
+        html5References.addReference(   296, "&Itilde;");
+        html5References.addReference(   297, "&itilde;");
+        html5References.addReference(   298, "&Imacr;");
+        html5References.addReference(   299, "&imacr;");
+        html5References.addReference(   302, "&Iogon;");
+        html5References.addReference(   303, "&iogon;");
+        html5References.addReference(   304, "&Idot;");
+        html5References.addReference(   305, "&imath;");
+        html5References.addReference(   305, "&inodot;");
+        html5References.addReference(   306, "&IJlig;");
+        html5References.addReference(   307, "&ijlig;");
+        html5References.addReference(   308, "&Jcirc;");
+        html5References.addReference(   309, "&jcirc;");
+        html5References.addReference(   310, "&Kcedil;");
+        html5References.addReference(   311, "&kcedil;");
+        html5References.addReference(   312, "&kgreen;");
+        html5References.addReference(   313, "&Lacute;");
+        html5References.addReference(   314, "&lacute;");
+        html5References.addReference(   315, "&Lcedil;");
+        html5References.addReference(   316, "&lcedil;");
+        html5References.addReference(   317, "&Lcaron;");
+        html5References.addReference(   318, "&lcaron;");
+        html5References.addReference(   319, "&Lmidot;");
+        html5References.addReference(   320, "&lmidot;");
+        html5References.addReference(   321, "&Lstrok;");
+        html5References.addReference(   322, "&lstrok;");
+        html5References.addReference(   323, "&Nacute;");
+        html5References.addReference(   324, "&nacute;");
+        html5References.addReference(   325, "&Ncedil;");
+        html5References.addReference(   326, "&ncedil;");
+        html5References.addReference(   327, "&Ncaron;");
+        html5References.addReference(   328, "&ncaron;");
+        html5References.addReference(   329, "&napos;");
+        html5References.addReference(   330, "&ENG;");
+        html5References.addReference(   331, "&eng;");
+        html5References.addReference(   332, "&Omacr;");
+        html5References.addReference(   333, "&omacr;");
+        html5References.addReference(   336, "&Odblac;");
+        html5References.addReference(   337, "&odblac;");
+        html5References.addReference(   338, "&OElig;");
+        html5References.addReference(   339, "&oelig;");
+        html5References.addReference(   340, "&Racute;");
+        html5References.addReference(   341, "&racute;");
+        html5References.addReference(   342, "&Rcedil;");
+        html5References.addReference(   343, "&rcedil;");
+        html5References.addReference(   344, "&Rcaron;");
+        html5References.addReference(   345, "&rcaron;");
+        html5References.addReference(   346, "&Sacute;");
+        html5References.addReference(   347, "&sacute;");
+        html5References.addReference(   348, "&Scirc;");
+        html5References.addReference(   349, "&scirc;");
+        html5References.addReference(   350, "&Scedil;");
+        html5References.addReference(   351, "&scedil;");
+        html5References.addReference(   352, "&Scaron;");
+        html5References.addReference(   353, "&scaron;");
+        html5References.addReference(   354, "&Tcedil;");
+        html5References.addReference(   355, "&tcedil;");
+        html5References.addReference(   356, "&Tcaron;");
+        html5References.addReference(   357, "&tcaron;");
+        html5References.addReference(   358, "&Tstrok;");
+        html5References.addReference(   359, "&tstrok;");
+        html5References.addReference(   360, "&Utilde;");
+        html5References.addReference(   361, "&utilde;");
+        html5References.addReference(   362, "&Umacr;");
+        html5References.addReference(   363, "&umacr;");
+        html5References.addReference(   364, "&Ubreve;");
+        html5References.addReference(   365, "&ubreve;");
+        html5References.addReference(   366, "&Uring;");
+        html5References.addReference(   367, "&uring;");
+        html5References.addReference(   368, "&Udblac;");
+        html5References.addReference(   369, "&udblac;");
+        html5References.addReference(   370, "&Uogon;");
+        html5References.addReference(   371, "&uogon;");
+        html5References.addReference(   372, "&Wcirc;");
+        html5References.addReference(   373, "&wcirc;");
+        html5References.addReference(   374, "&Ycirc;");
+        html5References.addReference(   375, "&ycirc;");
+        html5References.addReference(   376, "&Yuml;");
+        html5References.addReference(   377, "&Zacute;");
+        html5References.addReference(   378, "&zacute;");
+        html5References.addReference(   379, "&Zdot;");
+        html5References.addReference(   380, "&zdot;");
+        html5References.addReference(   381, "&Zcaron;");
+        html5References.addReference(   382, "&zcaron;");
+        html5References.addReference(   402, "&fnof;");
+        html5References.addReference(   437, "&imped;");
+        html5References.addReference(   501, "&gacute;");
+        html5References.addReference(   567, "&jmath;");
+        html5References.addReference(   710, "&circ;");
+        html5References.addReference(   711, "&caron;");
+        html5References.addReference(   711, "&Hacek;");
+        html5References.addReference(   728, "&breve;");
+        html5References.addReference(   728, "&Breve;");
+        html5References.addReference(   729, "&dot;");
+        html5References.addReference(   729, "&DiacriticalDot;");
+        html5References.addReference(   730, "&ring;");
+        html5References.addReference(   731, "&ogon;");
+        html5References.addReference(   732, "&tilde;");
+        html5References.addReference(   732, "&DiacriticalTilde;");
+        html5References.addReference(   733, "&dblac;");
+        html5References.addReference(   733, "&DiacriticalDoubleAcute;");
+        html5References.addReference(   785, "&DownBreve;");
+        html5References.addReference(   913, "&Alpha;");
+        html5References.addReference(   914, "&Beta;");
+        html5References.addReference(   915, "&Gamma;");
+        html5References.addReference(   916, "&Delta;");
+        html5References.addReference(   917, "&Epsilon;");
+        html5References.addReference(   918, "&Zeta;");
+        html5References.addReference(   919, "&Eta;");
+        html5References.addReference(   920, "&Theta;");
+        html5References.addReference(   921, "&Iota;");
+        html5References.addReference(   922, "&Kappa;");
+        html5References.addReference(   923, "&Lambda;");
+        html5References.addReference(   924, "&Mu;");
+        html5References.addReference(   925, "&Nu;");
+        html5References.addReference(   926, "&Xi;");
+        html5References.addReference(   927, "&Omicron;");
+        html5References.addReference(   928, "&Pi;");
+        html5References.addReference(   929, "&Rho;");
+        html5References.addReference(   931, "&Sigma;");
+        html5References.addReference(   932, "&Tau;");
+        html5References.addReference(   933, "&Upsilon;");
+        html5References.addReference(   934, "&Phi;");
+        html5References.addReference(   935, "&Chi;");
+        html5References.addReference(   936, "&Psi;");
+        html5References.addReference(   937, "&Omega;");
+        html5References.addReference(   937, "&ohm;");
+        html5References.addReference(   945, "&alpha;");
+        html5References.addReference(   946, "&beta;");
+        html5References.addReference(   947, "&gamma;");
+        html5References.addReference(   948, "&delta;");
+        html5References.addReference(   949, "&epsilon;");
+        html5References.addReference(   949, "&epsi;");
+        html5References.addReference(   950, "&zeta;");
+        html5References.addReference(   951, "&eta;");
+        html5References.addReference(   952, "&theta;");
+        html5References.addReference(   953, "&iota;");
+        html5References.addReference(   954, "&kappa;");
+        html5References.addReference(   955, "&lambda;");
+        html5References.addReference(   956, "&mu;");
+        html5References.addReference(   957, "&nu;");
+        html5References.addReference(   958, "&xi;");
+        html5References.addReference(   959, "&omicron;");
+        html5References.addReference(   960, "&pi;");
+        html5References.addReference(   961, "&rho;");
+        html5References.addReference(   962, "&sigmaf;");
+        html5References.addReference(   962, "&sigmav;");
+        html5References.addReference(   962, "&varsigma;");
+        html5References.addReference(   963, "&sigma;");
+        html5References.addReference(   964, "&tau;");
+        html5References.addReference(   965, "&upsilon;");
+        html5References.addReference(   965, "&upsi;");
+        html5References.addReference(   966, "&phi;");
+        html5References.addReference(   967, "&chi;");
+        html5References.addReference(   968, "&psi;");
+        html5References.addReference(   969, "&omega;");
+        html5References.addReference(   977, "&thetasym;");
+        html5References.addReference(   977, "&thetav;");
+        html5References.addReference(   977, "&vartheta;");
+        html5References.addReference(   978, "&upsih;");
+        html5References.addReference(   978, "&Upsi;");
+        html5References.addReference(   981, "&phiv;");
+        html5References.addReference(   981, "&straightphi;");
+        html5References.addReference(   981, "&varphi;");
+        html5References.addReference(   982, "&piv;");
+        html5References.addReference(   982, "&varpi;");
+        html5References.addReference(   988, "&Gammad;");
+        html5References.addReference(   989, "&digamma;");
+        html5References.addReference(   989, "&gammad;");
+        html5References.addReference(  1008, "&kappav;");
+        html5References.addReference(  1008, "&varkappa;");
+        html5References.addReference(  1009, "&rhov;");
+        html5References.addReference(  1009, "&varrho;");
+        html5References.addReference(  1013, "&epsiv;");
+        html5References.addReference(  1013, "&straightepsilon;");
+        html5References.addReference(  1013, "&varepsilon;");
+        html5References.addReference(  1014, "&backepsilon;");
+        html5References.addReference(  1014, "&bepsi;");
+        html5References.addReference(  1025, "&IOcy;");
+        html5References.addReference(  1026, "&DJcy;");
+        html5References.addReference(  1027, "&GJcy;");
+        html5References.addReference(  1028, "&Jukcy;");
+        html5References.addReference(  1029, "&DScy;");
+        html5References.addReference(  1030, "&Iukcy;");
+        html5References.addReference(  1031, "&YIcy;");
+        html5References.addReference(  1032, "&Jsercy;");
+        html5References.addReference(  1033, "&LJcy;");
+        html5References.addReference(  1034, "&NJcy;");
+        html5References.addReference(  1035, "&TSHcy;");
+        html5References.addReference(  1036, "&KJcy;");
+        html5References.addReference(  1038, "&Ubrcy;");
+        html5References.addReference(  1039, "&DZcy;");
+        html5References.addReference(  1040, "&Acy;");
+        html5References.addReference(  1041, "&Bcy;");
+        html5References.addReference(  1042, "&Vcy;");
+        html5References.addReference(  1043, "&Gcy;");
+        html5References.addReference(  1044, "&Dcy;");
+        html5References.addReference(  1045, "&IEcy;");
+        html5References.addReference(  1046, "&ZHcy;");
+        html5References.addReference(  1047, "&Zcy;");
+        html5References.addReference(  1048, "&Icy;");
+        html5References.addReference(  1049, "&Jcy;");
+        html5References.addReference(  1050, "&Kcy;");
+        html5References.addReference(  1051, "&Lcy;");
+        html5References.addReference(  1052, "&Mcy;");
+        html5References.addReference(  1053, "&Ncy;");
+        html5References.addReference(  1054, "&Ocy;");
+        html5References.addReference(  1055, "&Pcy;");
+        html5References.addReference(  1056, "&Rcy;");
+        html5References.addReference(  1057, "&Scy;");
+        html5References.addReference(  1058, "&Tcy;");
+        html5References.addReference(  1059, "&Ucy;");
+        html5References.addReference(  1060, "&Fcy;");
+        html5References.addReference(  1061, "&KHcy;");
+        html5References.addReference(  1062, "&TScy;");
+        html5References.addReference(  1063, "&CHcy;");
+        html5References.addReference(  1064, "&SHcy;");
+        html5References.addReference(  1065, "&SHCHcy;");
+        html5References.addReference(  1066, "&HARDcy;");
+        html5References.addReference(  1067, "&Ycy;");
+        html5References.addReference(  1068, "&SOFTcy;");
+        html5References.addReference(  1069, "&Ecy;");
+        html5References.addReference(  1070, "&YUcy;");
+        html5References.addReference(  1071, "&YAcy;");
+        html5References.addReference(  1072, "&acy;");
+        html5References.addReference(  1073, "&bcy;");
+        html5References.addReference(  1074, "&vcy;");
+        html5References.addReference(  1075, "&gcy;");
+        html5References.addReference(  1076, "&dcy;");
+        html5References.addReference(  1077, "&iecy;");
+        html5References.addReference(  1078, "&zhcy;");
+        html5References.addReference(  1079, "&zcy;");
+        html5References.addReference(  1080, "&icy;");
+        html5References.addReference(  1081, "&jcy;");
+        html5References.addReference(  1082, "&kcy;");
+        html5References.addReference(  1083, "&lcy;");
+        html5References.addReference(  1084, "&mcy;");
+        html5References.addReference(  1085, "&ncy;");
+        html5References.addReference(  1086, "&ocy;");
+        html5References.addReference(  1087, "&pcy;");
+        html5References.addReference(  1088, "&rcy;");
+        html5References.addReference(  1089, "&scy;");
+        html5References.addReference(  1090, "&tcy;");
+        html5References.addReference(  1091, "&ucy;");
+        html5References.addReference(  1092, "&fcy;");
+        html5References.addReference(  1093, "&khcy;");
+        html5References.addReference(  1094, "&tscy;");
+        html5References.addReference(  1095, "&chcy;");
+        html5References.addReference(  1096, "&shcy;");
+        html5References.addReference(  1097, "&shchcy;");
+        html5References.addReference(  1098, "&hardcy;");
+        html5References.addReference(  1099, "&ycy;");
+        html5References.addReference(  1100, "&softcy;");
+        html5References.addReference(  1101, "&ecy;");
+        html5References.addReference(  1102, "&yucy;");
+        html5References.addReference(  1103, "&yacy;");
+        html5References.addReference(  1105, "&iocy;");
+        html5References.addReference(  1106, "&djcy;");
+        html5References.addReference(  1107, "&gjcy;");
+        html5References.addReference(  1108, "&jukcy;");
+        html5References.addReference(  1109, "&dscy;");
+        html5References.addReference(  1110, "&iukcy;");
+        html5References.addReference(  1111, "&yicy;");
+        html5References.addReference(  1112, "&jsercy;");
+        html5References.addReference(  1113, "&ljcy;");
+        html5References.addReference(  1114, "&njcy;");
+        html5References.addReference(  1115, "&tshcy;");
+        html5References.addReference(  1116, "&kjcy;");
+        html5References.addReference(  1118, "&ubrcy;");
+        html5References.addReference(  1119, "&dzcy;");
+        html5References.addReference(  8194, "&ensp;");
+        html5References.addReference(  8195, "&emsp;");
+        html5References.addReference(  8196, "&emsp13;");
+        html5References.addReference(  8197, "&emsp14;");
+        html5References.addReference(  8199, "&numsp;");
+        html5References.addReference(  8200, "&puncsp;");
+        html5References.addReference(  8201, "&thinsp;");
+        html5References.addReference(  8201, "&ThinSpace;");
+        html5References.addReference(  8202, "&hairsp;");
+        html5References.addReference(  8202, "&VeryThinSpace;");
+        html5References.addReference(  8203, "&NegativeMediumSpace;");
+        html5References.addReference(  8203, "&NegativeThickSpace;");
+        html5References.addReference(  8203, "&NegativeThinSpace;");
+        html5References.addReference(  8203, "&NegativeVeryThinSpace;");
+        html5References.addReference(  8203, "&ZeroWidthSpace;");
+        html5References.addReference(  8204, "&zwnj;");
+        html5References.addReference(  8205, "&zwj;");
+        html5References.addReference(  8206, "&lrm;");
+        html5References.addReference(  8207, "&rlm;");
+        html5References.addReference(  8208, "&dash;");
+        html5References.addReference(  8208, "&hyphen;");
+        html5References.addReference(  8211, "&ndash;");
+        html5References.addReference(  8212, "&mdash;");
+        html5References.addReference(  8213, "&horbar;");
+        html5References.addReference(  8214, "&Verbar;");
+        html5References.addReference(  8214, "&Vert;");
+        html5References.addReference(  8216, "&lsquo;");
+        html5References.addReference(  8216, "&OpenCurlyQuote;");
+        html5References.addReference(  8217, "&rsquo;");
+        html5References.addReference(  8217, "&rsquor;");
+        html5References.addReference(  8217, "&CloseCurlyQuote;");
+        html5References.addReference(  8218, "&sbquo;");
+        html5References.addReference(  8218, "&lsquor;");
+        html5References.addReference(  8220, "&ldquo;");
+        html5References.addReference(  8220, "&OpenCurlyDoubleQuote;");
+        html5References.addReference(  8221, "&rdquo;");
+        html5References.addReference(  8221, "&rdquor;");
+        html5References.addReference(  8221, "&CloseCurlyDoubleQuote;");
+        html5References.addReference(  8222, "&bdquo;");
+        html5References.addReference(  8222, "&ldquor;");
+        html5References.addReference(  8224, "&dagger;");
+        html5References.addReference(  8225, "&Dagger;");
+        html5References.addReference(  8225, "&ddagger;");
+        html5References.addReference(  8226, "&bull;");
+        html5References.addReference(  8226, "&bullet;");
+        html5References.addReference(  8229, "&nldr;");
+        html5References.addReference(  8230, "&hellip;");
+        html5References.addReference(  8230, "&mldr;");
+        html5References.addReference(  8240, "&permil;");
+        html5References.addReference(  8241, "&pertenk;");
+        html5References.addReference(  8242, "&prime;");
+        html5References.addReference(  8243, "&Prime;");
+        html5References.addReference(  8244, "&tprime;");
+        html5References.addReference(  8245, "&backprime;");
+        html5References.addReference(  8245, "&bprime;");
+        html5References.addReference(  8249, "&lsaquo;");
+        html5References.addReference(  8250, "&rsaquo;");
+        html5References.addReference(  8254, "&oline;");
+        html5References.addReference(  8254, "&OverBar;");
+        html5References.addReference(  8257, "&caret;");
+        html5References.addReference(  8259, "&hybull;");
+        html5References.addReference(  8260, "&frasl;");
+        html5References.addReference(  8271, "&bsemi;");
+        html5References.addReference(  8279, "&qprime;");
+        html5References.addReference(  8287, "&MediumSpace;");
+        html5References.addReference(  8287,  8202, "&ThickSpace;");
+        html5References.addReference(  8288, "&NoBreak;");
+        html5References.addReference(  8289, "&af;");
+        html5References.addReference(  8289, "&ApplyFunction;");
+        html5References.addReference(  8290, "&it;");
+        html5References.addReference(  8290, "&InvisibleTimes;");
+        html5References.addReference(  8291, "&ic;");
+        html5References.addReference(  8291, "&InvisibleComma;");
+        html5References.addReference(  8364, "&euro;");
+        html5References.addReference(  8411, "&tdot;");
+        html5References.addReference(  8411, "&TripleDot;");
+        html5References.addReference(  8412, "&DotDot;");
+        html5References.addReference(  8450, "&complexes;");
+        html5References.addReference(  8450, "&Copf;");
+        html5References.addReference(  8453, "&incare;");
+        html5References.addReference(  8458, "&gscr;");
+        html5References.addReference(  8459, "&hamilt;");
+        html5References.addReference(  8459, "&HilbertSpace;");
+        html5References.addReference(  8459, "&Hscr;");
+        html5References.addReference(  8460, "&Hfr;");
+        html5References.addReference(  8460, "&Poincareplane;");
+        html5References.addReference(  8461, "&quaternions;");
+        html5References.addReference(  8461, "&Hopf;");
+        html5References.addReference(  8462, "&planckh;");
+        html5References.addReference(  8463, "&hbar;");
+        html5References.addReference(  8463, "&hslash;");
+        html5References.addReference(  8463, "&planck;");
+        html5References.addReference(  8463, "&plankv;");
+        html5References.addReference(  8464, "&imagline;");
+        html5References.addReference(  8464, "&Iscr;");
+        html5References.addReference(  8465, "&image;");
+        html5References.addReference(  8465, "&imagpart;");
+        html5References.addReference(  8465, "&Ifr;");
+        html5References.addReference(  8465, "&Im;");
+        html5References.addReference(  8466, "&lagran;");
+        html5References.addReference(  8466, "&Laplacetrf;");
+        html5References.addReference(  8466, "&Lscr;");
+        html5References.addReference(  8467, "&ell;");
+        html5References.addReference(  8469, "&naturals;");
+        html5References.addReference(  8469, "&Nopf;");
+        html5References.addReference(  8470, "&numero;");
+        html5References.addReference(  8471, "&copysr;");
+        html5References.addReference(  8472, "&weierp;");
+        html5References.addReference(  8472, "&wp;");
+        html5References.addReference(  8473, "&primes;");
+        html5References.addReference(  8473, "&Popf;");
+        html5References.addReference(  8474, "&rationals;");
+        html5References.addReference(  8474, "&Qopf;");
+        html5References.addReference(  8475, "&realine;");
+        html5References.addReference(  8475, "&Rscr;");
+        html5References.addReference(  8476, "&real;");
+        html5References.addReference(  8476, "&realpart;");
+        html5References.addReference(  8476, "&Re;");
+        html5References.addReference(  8476, "&Rfr;");
+        html5References.addReference(  8477, "&reals;");
+        html5References.addReference(  8477, "&Ropf;");
+        html5References.addReference(  8478, "&rx;");
+        html5References.addReference(  8482, "&trade;");
+        html5References.addReference(  8482, "&TRADE;");
+        html5References.addReference(  8484, "&integers;");
+        html5References.addReference(  8484, "&Zopf;");
+        html5References.addReference(  8487, "&mho;");
+        html5References.addReference(  8488, "&zeetrf;");
+        html5References.addReference(  8488, "&Zfr;");
+        html5References.addReference(  8489, "&iiota;");
+        html5References.addReference(  8492, "&bernou;");
+        html5References.addReference(  8492, "&Bernoullis;");
+        html5References.addReference(  8492, "&Bscr;");
+        html5References.addReference(  8493, "&Cayleys;");
+        html5References.addReference(  8493, "&Cfr;");
+        html5References.addReference(  8495, "&escr;");
+        html5References.addReference(  8496, "&expectation;");
+        html5References.addReference(  8496, "&Escr;");
+        html5References.addReference(  8497, "&Fouriertrf;");
+        html5References.addReference(  8497, "&Fscr;");
+        html5References.addReference(  8499, "&phmmat;");
+        html5References.addReference(  8499, "&Mellintrf;");
+        html5References.addReference(  8499, "&Mscr;");
+        html5References.addReference(  8500, "&order;");
+        html5References.addReference(  8500, "&orderof;");
+        html5References.addReference(  8500, "&oscr;");
+        html5References.addReference(  8501, "&alefsym;");
+        html5References.addReference(  8501, "&aleph;");
+        html5References.addReference(  8502, "&beth;");
+        html5References.addReference(  8503, "&gimel;");
+        html5References.addReference(  8504, "&daleth;");
+        html5References.addReference(  8517, "&CapitalDifferentialD;");
+        html5References.addReference(  8517, "&DD;");
+        html5References.addReference(  8518, "&dd;");
+        html5References.addReference(  8518, "&DifferentialD;");
+        html5References.addReference(  8519, "&ee;");
+        html5References.addReference(  8519, "&exponentiale;");
+        html5References.addReference(  8519, "&ExponentialE;");
+        html5References.addReference(  8520, "&ii;");
+        html5References.addReference(  8520, "&ImaginaryI;");
+        html5References.addReference(  8531, "&frac13;");
+        html5References.addReference(  8532, "&frac23;");
+        html5References.addReference(  8533, "&frac15;");
+        html5References.addReference(  8534, "&frac25;");
+        html5References.addReference(  8535, "&frac35;");
+        html5References.addReference(  8536, "&frac45;");
+        html5References.addReference(  8537, "&frac16;");
+        html5References.addReference(  8538, "&frac56;");
+        html5References.addReference(  8539, "&frac18;");
+        html5References.addReference(  8540, "&frac38;");
+        html5References.addReference(  8541, "&frac58;");
+        html5References.addReference(  8542, "&frac78;");
+        html5References.addReference(  8592, "&larr;");
+        html5References.addReference(  8592, "&leftarrow;");
+        html5References.addReference(  8592, "&slarr;");
+        html5References.addReference(  8592, "&LeftArrow;");
+        html5References.addReference(  8592, "&ShortLeftArrow;");
+        html5References.addReference(  8593, "&uarr;");
+        html5References.addReference(  8593, "&uparrow;");
+        html5References.addReference(  8593, "&ShortUpArrow;");
+        html5References.addReference(  8593, "&UpArrow;");
+        html5References.addReference(  8594, "&rarr;");
+        html5References.addReference(  8594, "&rightarrow;");
+        html5References.addReference(  8594, "&srarr;");
+        html5References.addReference(  8594, "&RightArrow;");
+        html5References.addReference(  8594, "&ShortRightArrow;");
+        html5References.addReference(  8595, "&darr;");
+        html5References.addReference(  8595, "&downarrow;");
+        html5References.addReference(  8595, "&DownArrow;");
+        html5References.addReference(  8595, "&ShortDownArrow;");
+        html5References.addReference(  8596, "&harr;");
+        html5References.addReference(  8596, "&leftrightarrow;");
+        html5References.addReference(  8596, "&LeftRightArrow;");
+        html5References.addReference(  8597, "&updownarrow;");
+        html5References.addReference(  8597, "&varr;");
+        html5References.addReference(  8597, "&UpDownArrow;");
+        html5References.addReference(  8598, "&nwarr;");
+        html5References.addReference(  8598, "&nwarrow;");
+        html5References.addReference(  8598, "&UpperLeftArrow;");
+        html5References.addReference(  8599, "&nearr;");
+        html5References.addReference(  8599, "&nearrow;");
+        html5References.addReference(  8599, "&UpperRightArrow;");
+        html5References.addReference(  8600, "&searr;");
+        html5References.addReference(  8600, "&searrow;");
+        html5References.addReference(  8600, "&LowerRightArrow;");
+        html5References.addReference(  8601, "&swarr;");
+        html5References.addReference(  8601, "&swarrow;");
+        html5References.addReference(  8601, "&LowerLeftArrow;");
+        html5References.addReference(  8602, "&nlarr;");
+        html5References.addReference(  8602, "&nleftarrow;");
+        html5References.addReference(  8603, "&nrarr;");
+        html5References.addReference(  8603, "&nrightarrow;");
+        html5References.addReference(  8605, "&rarrw;");
+        html5References.addReference(  8605, "&rightsquigarrow;");
+        html5References.addReference(  8605,   824, "&nrarrw;");
+        html5References.addReference(  8606, "&twoheadleftarrow;");
+        html5References.addReference(  8606, "&Larr;");
+        html5References.addReference(  8607, "&Uarr;");
+        html5References.addReference(  8608, "&twoheadrightarrow;");
+        html5References.addReference(  8608, "&Rarr;");
+        html5References.addReference(  8609, "&Darr;");
+        html5References.addReference(  8610, "&larrtl;");
+        html5References.addReference(  8610, "&leftarrowtail;");
+        html5References.addReference(  8611, "&rarrtl;");
+        html5References.addReference(  8611, "&rightarrowtail;");
+        html5References.addReference(  8612, "&mapstoleft;");
+        html5References.addReference(  8612, "&LeftTeeArrow;");
+        html5References.addReference(  8613, "&mapstoup;");
+        html5References.addReference(  8613, "&UpTeeArrow;");
+        html5References.addReference(  8614, "&map;");
+        html5References.addReference(  8614, "&mapsto;");
+        html5References.addReference(  8614, "&RightTeeArrow;");
+        html5References.addReference(  8615, "&mapstodown;");
+        html5References.addReference(  8615, "&DownTeeArrow;");
+        html5References.addReference(  8617, "&hookleftarrow;");
+        html5References.addReference(  8617, "&larrhk;");
+        html5References.addReference(  8618, "&hookrightarrow;");
+        html5References.addReference(  8618, "&rarrhk;");
+        html5References.addReference(  8619, "&larrlp;");
+        html5References.addReference(  8619, "&looparrowleft;");
+        html5References.addReference(  8620, "&looparrowright;");
+        html5References.addReference(  8620, "&rarrlp;");
+        html5References.addReference(  8621, "&harrw;");
+        html5References.addReference(  8621, "&leftrightsquigarrow;");
+        html5References.addReference(  8622, "&nharr;");
+        html5References.addReference(  8622, "&nleftrightarrow;");
+        html5References.addReference(  8624, "&lsh;");
+        html5References.addReference(  8624, "&Lsh;");
+        html5References.addReference(  8625, "&rsh;");
+        html5References.addReference(  8625, "&Rsh;");
+        html5References.addReference(  8626, "&ldsh;");
+        html5References.addReference(  8627, "&rdsh;");
+        html5References.addReference(  8629, "&crarr;");
+        html5References.addReference(  8630, "&cularr;");
+        html5References.addReference(  8630, "&curvearrowleft;");
+        html5References.addReference(  8631, "&curarr;");
+        html5References.addReference(  8631, "&curvearrowright;");
+        html5References.addReference(  8634, "&circlearrowleft;");
+        html5References.addReference(  8634, "&olarr;");
+        html5References.addReference(  8635, "&circlearrowright;");
+        html5References.addReference(  8635, "&orarr;");
+        html5References.addReference(  8636, "&leftharpoonup;");
+        html5References.addReference(  8636, "&lharu;");
+        html5References.addReference(  8636, "&LeftVector;");
+        html5References.addReference(  8637, "&leftharpoondown;");
+        html5References.addReference(  8637, "&lhard;");
+        html5References.addReference(  8637, "&DownLeftVector;");
+        html5References.addReference(  8638, "&uharr;");
+        html5References.addReference(  8638, "&upharpoonright;");
+        html5References.addReference(  8638, "&RightUpVector;");
+        html5References.addReference(  8639, "&uharl;");
+        html5References.addReference(  8639, "&upharpoonleft;");
+        html5References.addReference(  8639, "&LeftUpVector;");
+        html5References.addReference(  8640, "&rharu;");
+        html5References.addReference(  8640, "&rightharpoonup;");
+        html5References.addReference(  8640, "&RightVector;");
+        html5References.addReference(  8641, "&rhard;");
+        html5References.addReference(  8641, "&rightharpoondown;");
+        html5References.addReference(  8641, "&DownRightVector;");
+        html5References.addReference(  8642, "&dharr;");
+        html5References.addReference(  8642, "&downharpoonright;");
+        html5References.addReference(  8642, "&RightDownVector;");
+        html5References.addReference(  8643, "&dharl;");
+        html5References.addReference(  8643, "&downharpoonleft;");
+        html5References.addReference(  8643, "&LeftDownVector;");
+        html5References.addReference(  8644, "&rightleftarrows;");
+        html5References.addReference(  8644, "&rlarr;");
+        html5References.addReference(  8644, "&RightArrowLeftArrow;");
+        html5References.addReference(  8645, "&udarr;");
+        html5References.addReference(  8645, "&UpArrowDownArrow;");
+        html5References.addReference(  8646, "&leftrightarrows;");
+        html5References.addReference(  8646, "&lrarr;");
+        html5References.addReference(  8646, "&LeftArrowRightArrow;");
+        html5References.addReference(  8647, "&leftleftarrows;");
+        html5References.addReference(  8647, "&llarr;");
+        html5References.addReference(  8648, "&upuparrows;");
+        html5References.addReference(  8648, "&uuarr;");
+        html5References.addReference(  8649, "&rightrightarrows;");
+        html5References.addReference(  8649, "&rrarr;");
+        html5References.addReference(  8650, "&ddarr;");
+        html5References.addReference(  8650, "&downdownarrows;");
+        html5References.addReference(  8651, "&leftrightharpoons;");
+        html5References.addReference(  8651, "&lrhar;");
+        html5References.addReference(  8651, "&ReverseEquilibrium;");
+        html5References.addReference(  8652, "&rightleftharpoons;");
+        html5References.addReference(  8652, "&rlhar;");
+        html5References.addReference(  8652, "&Equilibrium;");
+        html5References.addReference(  8653, "&nLeftarrow;");
+        html5References.addReference(  8653, "&nlArr;");
+        html5References.addReference(  8654, "&nLeftrightarrow;");
+        html5References.addReference(  8654, "&nhArr;");
+        html5References.addReference(  8655, "&nRightarrow;");
+        html5References.addReference(  8655, "&nrArr;");
+        html5References.addReference(  8656, "&lArr;");
+        html5References.addReference(  8656, "&DoubleLeftArrow;");
+        html5References.addReference(  8656, "&Leftarrow;");
+        html5References.addReference(  8657, "&uArr;");
+        html5References.addReference(  8657, "&DoubleUpArrow;");
+        html5References.addReference(  8657, "&Uparrow;");
+        html5References.addReference(  8658, "&rArr;");
+        html5References.addReference(  8658, "&DoubleRightArrow;");
+        html5References.addReference(  8658, "&Implies;");
+        html5References.addReference(  8658, "&Rightarrow;");
+        html5References.addReference(  8659, "&dArr;");
+        html5References.addReference(  8659, "&DoubleDownArrow;");
+        html5References.addReference(  8659, "&Downarrow;");
+        html5References.addReference(  8660, "&hArr;");
+        html5References.addReference(  8660, "&iff;");
+        html5References.addReference(  8660, "&DoubleLeftRightArrow;");
+        html5References.addReference(  8660, "&Leftrightarrow;");
+        html5References.addReference(  8661, "&vArr;");
+        html5References.addReference(  8661, "&DoubleUpDownArrow;");
+        html5References.addReference(  8661, "&Updownarrow;");
+        html5References.addReference(  8662, "&nwArr;");
+        html5References.addReference(  8663, "&neArr;");
+        html5References.addReference(  8664, "&seArr;");
+        html5References.addReference(  8665, "&swArr;");
+        html5References.addReference(  8666, "&lAarr;");
+        html5References.addReference(  8666, "&Lleftarrow;");
+        html5References.addReference(  8667, "&rAarr;");
+        html5References.addReference(  8667, "&Rrightarrow;");
+        html5References.addReference(  8669, "&zigrarr;");
+        html5References.addReference(  8676, "&larrb;");
+        html5References.addReference(  8676, "&LeftArrowBar;");
+        html5References.addReference(  8677, "&rarrb;");
+        html5References.addReference(  8677, "&RightArrowBar;");
+        html5References.addReference(  8693, "&duarr;");
+        html5References.addReference(  8693, "&DownArrowUpArrow;");
+        html5References.addReference(  8701, "&loarr;");
+        html5References.addReference(  8702, "&roarr;");
+        html5References.addReference(  8703, "&hoarr;");
+        html5References.addReference(  8704, "&forall;");
+        html5References.addReference(  8704, "&ForAll;");
+        html5References.addReference(  8705, "&comp;");
+        html5References.addReference(  8705, "&complement;");
+        html5References.addReference(  8706, "&part;");
+        html5References.addReference(  8706, "&PartialD;");
+        html5References.addReference(  8706,   824, "&npart;");
+        html5References.addReference(  8707, "&exist;");
+        html5References.addReference(  8707, "&Exists;");
+        html5References.addReference(  8708, "&nexist;");
+        html5References.addReference(  8708, "&nexists;");
+        html5References.addReference(  8708, "&NotExists;");
+        html5References.addReference(  8709, "&empty;");
+        html5References.addReference(  8709, "&emptyset;");
+        html5References.addReference(  8709, "&emptyv;");
+        html5References.addReference(  8709, "&varnothing;");
+        html5References.addReference(  8711, "&nabla;");
+        html5References.addReference(  8711, "&Del;");
+        html5References.addReference(  8712, "&isin;");
+        html5References.addReference(  8712, "&in;");
+        html5References.addReference(  8712, "&isinv;");
+        html5References.addReference(  8712, "&Element;");
+        html5References.addReference(  8713, "&notin;");
+        html5References.addReference(  8713, "&notinva;");
+        html5References.addReference(  8713, "&NotElement;");
+        html5References.addReference(  8715, "&ni;");
+        html5References.addReference(  8715, "&niv;");
+        html5References.addReference(  8715, "&ReverseElement;");
+        html5References.addReference(  8715, "&SuchThat;");
+        html5References.addReference(  8716, "&notni;");
+        html5References.addReference(  8716, "&notniva;");
+        html5References.addReference(  8716, "&NotReverseElement;");
+        html5References.addReference(  8719, "&prod;");
+        html5References.addReference(  8719, "&Product;");
+        html5References.addReference(  8720, "&coprod;");
+        html5References.addReference(  8720, "&Coproduct;");
+        html5References.addReference(  8721, "&sum;");
+        html5References.addReference(  8721, "&Sum;");
+        html5References.addReference(  8722, "&minus;");
+        html5References.addReference(  8723, "&mnplus;");
+        html5References.addReference(  8723, "&mp;");
+        html5References.addReference(  8723, "&MinusPlus;");
+        html5References.addReference(  8724, "&dotplus;");
+        html5References.addReference(  8724, "&plusdo;");
+        html5References.addReference(  8726, "&setminus;");
+        html5References.addReference(  8726, "&setmn;");
+        html5References.addReference(  8726, "&smallsetminus;");
+        html5References.addReference(  8726, "&ssetmn;");
+        html5References.addReference(  8726, "&Backslash;");
+        html5References.addReference(  8727, "&lowast;");
+        html5References.addReference(  8728, "&compfn;");
+        html5References.addReference(  8728, "&SmallCircle;");
+        html5References.addReference(  8730, "&radic;");
+        html5References.addReference(  8730, "&Sqrt;");
+        html5References.addReference(  8733, "&prop;");
+        html5References.addReference(  8733, "&propto;");
+        html5References.addReference(  8733, "&varpropto;");
+        html5References.addReference(  8733, "&vprop;");
+        html5References.addReference(  8733, "&Proportional;");
+        html5References.addReference(  8734, "&infin;");
+        html5References.addReference(  8735, "&angrt;");
+        html5References.addReference(  8736, "&ang;");
+        html5References.addReference(  8736, "&angle;");
+        html5References.addReference(  8736,  8402, "&nang;");
+        html5References.addReference(  8737, "&angmsd;");
+        html5References.addReference(  8737, "&measuredangle;");
+        html5References.addReference(  8738, "&angsph;");
+        html5References.addReference(  8739, "&mid;");
+        html5References.addReference(  8739, "&shortmid;");
+        html5References.addReference(  8739, "&smid;");
+        html5References.addReference(  8739, "&VerticalBar;");
+        html5References.addReference(  8740, "&nmid;");
+        html5References.addReference(  8740, "&nshortmid;");
+        html5References.addReference(  8740, "&nsmid;");
+        html5References.addReference(  8740, "&NotVerticalBar;");
+        html5References.addReference(  8741, "&par;");
+        html5References.addReference(  8741, "&parallel;");
+        html5References.addReference(  8741, "&shortparallel;");
+        html5References.addReference(  8741, "&spar;");
+        html5References.addReference(  8741, "&DoubleVerticalBar;");
+        html5References.addReference(  8742, "&npar;");
+        html5References.addReference(  8742, "&nparallel;");
+        html5References.addReference(  8742, "&nshortparallel;");
+        html5References.addReference(  8742, "&nspar;");
+        html5References.addReference(  8742, "&NotDoubleVerticalBar;");
+        html5References.addReference(  8743, "&and;");
+        html5References.addReference(  8743, "&wedge;");
+        html5References.addReference(  8744, "&or;");
+        html5References.addReference(  8744, "&vee;");
+        html5References.addReference(  8745, "&cap;");
+        html5References.addReference(  8745, 65024, "&caps;");
+        html5References.addReference(  8746, "&cup;");
+        html5References.addReference(  8746, 65024, "&cups;");
+        html5References.addReference(  8747, "&int;");
+        html5References.addReference(  8747, "&Integral;");
+        html5References.addReference(  8748, "&Int;");
+        html5References.addReference(  8749, "&iiint;");
+        html5References.addReference(  8749, "&tint;");
+        html5References.addReference(  8750, "&conint;");
+        html5References.addReference(  8750, "&oint;");
+        html5References.addReference(  8750, "&ContourIntegral;");
+        html5References.addReference(  8751, "&Conint;");
+        html5References.addReference(  8751, "&DoubleContourIntegral;");
+        html5References.addReference(  8752, "&Cconint;");
+        html5References.addReference(  8753, "&cwint;");
+        html5References.addReference(  8754, "&cwconint;");
+        html5References.addReference(  8754, "&ClockwiseContourIntegral;");
+        html5References.addReference(  8755, "&awconint;");
+        html5References.addReference(  8755, "&CounterClockwiseContourIntegral;");
+        html5References.addReference(  8756, "&there4;");
+        html5References.addReference(  8756, "&therefore;");
+        html5References.addReference(  8756, "&Therefore;");
+        html5References.addReference(  8757, "&becaus;");
+        html5References.addReference(  8757, "&because;");
+        html5References.addReference(  8757, "&Because;");
+        html5References.addReference(  8758, "&ratio;");
+        html5References.addReference(  8759, "&Colon;");
+        html5References.addReference(  8759, "&Proportion;");
+        html5References.addReference(  8760, "&dotminus;");
+        html5References.addReference(  8760, "&minusd;");
+        html5References.addReference(  8762, "&mDDot;");
+        html5References.addReference(  8763, "&homtht;");
+        html5References.addReference(  8764, "&sim;");
+        html5References.addReference(  8764, "&thicksim;");
+        html5References.addReference(  8764, "&thksim;");
+        html5References.addReference(  8764, "&Tilde;");
+        html5References.addReference(  8764,  8402, "&nvsim;");
+        html5References.addReference(  8765, "&backsim;");
+        html5References.addReference(  8765, "&bsim;");
+        html5References.addReference(  8765,   817, "&race;");
+        html5References.addReference(  8766, "&ac;");
+        html5References.addReference(  8766, "&mstpos;");
+        html5References.addReference(  8766,   819, "&acE;");
+        html5References.addReference(  8767, "&acd;");
+        html5References.addReference(  8768, "&wr;");
+        html5References.addReference(  8768, "&wreath;");
+        html5References.addReference(  8768, "&VerticalTilde;");
+        html5References.addReference(  8769, "&nsim;");
+        html5References.addReference(  8769, "&NotTilde;");
+        html5References.addReference(  8770, "&eqsim;");
+        html5References.addReference(  8770, "&esim;");
+        html5References.addReference(  8770, "&EqualTilde;");
+        html5References.addReference(  8770,   824, "&nesim;");
+        html5References.addReference(  8770,   824, "&NotEqualTilde;");
+        html5References.addReference(  8771, "&sime;");
+        html5References.addReference(  8771, "&simeq;");
+        html5References.addReference(  8771, "&TildeEqual;");
+        html5References.addReference(  8772, "&nsime;");
+        html5References.addReference(  8772, "&nsimeq;");
+        html5References.addReference(  8772, "&NotTildeEqual;");
+        html5References.addReference(  8773, "&cong;");
+        html5References.addReference(  8773, "&TildeFullEqual;");
+        html5References.addReference(  8774, "&simne;");
+        html5References.addReference(  8775, "&ncong;");
+        html5References.addReference(  8775, "&NotTildeFullEqual;");
+        html5References.addReference(  8776, "&asymp;");
+        html5References.addReference(  8776, "&ap;");
+        html5References.addReference(  8776, "&approx;");
+        html5References.addReference(  8776, "&thickapprox;");
+        html5References.addReference(  8776, "&thkap;");
+        html5References.addReference(  8776, "&TildeTilde;");
+        html5References.addReference(  8777, "&nap;");
+        html5References.addReference(  8777, "&napprox;");
+        html5References.addReference(  8777, "&NotTildeTilde;");
+        html5References.addReference(  8778, "&ape;");
+        html5References.addReference(  8778, "&approxeq;");
+        html5References.addReference(  8779, "&apid;");
+        html5References.addReference(  8779,   824, "&napid;");
+        html5References.addReference(  8780, "&backcong;");
+        html5References.addReference(  8780, "&bcong;");
+        html5References.addReference(  8781, "&asympeq;");
+        html5References.addReference(  8781, "&CupCap;");
+        html5References.addReference(  8781,  8402, "&nvap;");
+        html5References.addReference(  8782, "&bump;");
+        html5References.addReference(  8782, "&Bumpeq;");
+        html5References.addReference(  8782, "&HumpDownHump;");
+        html5References.addReference(  8782,   824, "&nbump;");
+        html5References.addReference(  8782,   824, "&NotHumpDownHump;");
+        html5References.addReference(  8783, "&bumpe;");
+        html5References.addReference(  8783, "&bumpeq;");
+        html5References.addReference(  8783, "&HumpEqual;");
+        html5References.addReference(  8783,   824, "&nbumpe;");
+        html5References.addReference(  8783,   824, "&NotHumpEqual;");
+        html5References.addReference(  8784, "&doteq;");
+        html5References.addReference(  8784, "&esdot;");
+        html5References.addReference(  8784, "&DotEqual;");
+        html5References.addReference(  8784,   824, "&nedot;");
+        html5References.addReference(  8785, "&doteqdot;");
+        html5References.addReference(  8785, "&eDot;");
+        html5References.addReference(  8786, "&efDot;");
+        html5References.addReference(  8786, "&fallingdotseq;");
+        html5References.addReference(  8787, "&erDot;");
+        html5References.addReference(  8787, "&risingdotseq;");
+        html5References.addReference(  8788, "&colone;");
+        html5References.addReference(  8788, "&coloneq;");
+        html5References.addReference(  8788, "&Assign;");
+        html5References.addReference(  8789, "&ecolon;");
+        html5References.addReference(  8789, "&eqcolon;");
+        html5References.addReference(  8790, "&ecir;");
+        html5References.addReference(  8790, "&eqcirc;");
+        html5References.addReference(  8791, "&circeq;");
+        html5References.addReference(  8791, "&cire;");
+        html5References.addReference(  8793, "&wedgeq;");
+        html5References.addReference(  8794, "&veeeq;");
+        html5References.addReference(  8796, "&triangleq;");
+        html5References.addReference(  8796, "&trie;");
+        html5References.addReference(  8799, "&equest;");
+        html5References.addReference(  8799, "&questeq;");
+        html5References.addReference(  8800, "&ne;");
+        html5References.addReference(  8800, "&NotEqual;");
+        html5References.addReference(  8801, "&equiv;");
+        html5References.addReference(  8801, "&Congruent;");
+        html5References.addReference(  8801,  8421, "&bnequiv;");
+        html5References.addReference(  8802, "&nequiv;");
+        html5References.addReference(  8802, "&NotCongruent;");
+        html5References.addReference(  8804, "&le;");
+        html5References.addReference(  8804, "&leq;");
+        html5References.addReference(  8804,  8402, "&nvle;");
+        html5References.addReference(  8805, "&ge;");
+        html5References.addReference(  8805, "&geq;");
+        html5References.addReference(  8805, "&GreaterEqual;");
+        html5References.addReference(  8805,  8402, "&nvge;");
+        html5References.addReference(  8806, "&lE;");
+        html5References.addReference(  8806, "&leqq;");
+        html5References.addReference(  8806, "&LessFullEqual;");
+        html5References.addReference(  8806,   824, "&nlE;");
+        html5References.addReference(  8806,   824, "&nleqq;");
+        html5References.addReference(  8807, "&gE;");
+        html5References.addReference(  8807, "&geqq;");
+        html5References.addReference(  8807, "&GreaterFullEqual;");
+        html5References.addReference(  8807,   824, "&ngE;");
+        html5References.addReference(  8807,   824, "&ngeqq;");
+        html5References.addReference(  8807,   824, "&NotGreaterFullEqual;");
+        html5References.addReference(  8808, "&lnE;");
+        html5References.addReference(  8808, "&lneqq;");
+        html5References.addReference(  8808, 65024, "&lvertneqq;");
+        html5References.addReference(  8808, 65024, "&lvnE;");
+        html5References.addReference(  8809, "&gnE;");
+        html5References.addReference(  8809, "&gneqq;");
+        html5References.addReference(  8809, 65024, "&gvertneqq;");
+        html5References.addReference(  8809, 65024, "&gvnE;");
+        html5References.addReference(  8810, "&ll;");
+        html5References.addReference(  8810, "&Lt;");
+        html5References.addReference(  8810, "&NestedLessLess;");
+        html5References.addReference(  8810,   824, "&nLtv;");
+        html5References.addReference(  8810,   824, "&NotLessLess;");
+        html5References.addReference(  8810,  8402, "&nLt;");
+        html5References.addReference(  8811, "&gg;");
+        html5References.addReference(  8811, "&Gt;");
+        html5References.addReference(  8811, "&NestedGreaterGreater;");
+        html5References.addReference(  8811,   824, "&nGtv;");
+        html5References.addReference(  8811,   824, "&NotGreaterGreater;");
+        html5References.addReference(  8811,  8402, "&nGt;");
+        html5References.addReference(  8812, "&between;");
+        html5References.addReference(  8812, "&twixt;");
+        html5References.addReference(  8813, "&NotCupCap;");
+        html5References.addReference(  8814, "&nless;");
+        html5References.addReference(  8814, "&nlt;");
+        html5References.addReference(  8814, "&NotLess;");
+        html5References.addReference(  8815, "&ngt;");
+        html5References.addReference(  8815, "&ngtr;");
+        html5References.addReference(  8815, "&NotGreater;");
+        html5References.addReference(  8816, "&nle;");
+        html5References.addReference(  8816, "&nleq;");
+        html5References.addReference(  8816, "&NotLessEqual;");
+        html5References.addReference(  8817, "&nge;");
+        html5References.addReference(  8817, "&ngeq;");
+        html5References.addReference(  8817, "&NotGreaterEqual;");
+        html5References.addReference(  8818, "&lesssim;");
+        html5References.addReference(  8818, "&lsim;");
+        html5References.addReference(  8818, "&LessTilde;");
+        html5References.addReference(  8819, "&gsim;");
+        html5References.addReference(  8819, "&gtrsim;");
+        html5References.addReference(  8819, "&GreaterTilde;");
+        html5References.addReference(  8820, "&nlsim;");
+        html5References.addReference(  8820, "&NotLessTilde;");
+        html5References.addReference(  8821, "&ngsim;");
+        html5References.addReference(  8821, "&NotGreaterTilde;");
+        html5References.addReference(  8822, "&lessgtr;");
+        html5References.addReference(  8822, "&lg;");
+        html5References.addReference(  8822, "&LessGreater;");
+        html5References.addReference(  8823, "&gl;");
+        html5References.addReference(  8823, "&gtrless;");
+        html5References.addReference(  8823, "&GreaterLess;");
+        html5References.addReference(  8824, "&ntlg;");
+        html5References.addReference(  8824, "&NotLessGreater;");
+        html5References.addReference(  8825, "&ntgl;");
+        html5References.addReference(  8825, "&NotGreaterLess;");
+        html5References.addReference(  8826, "&pr;");
+        html5References.addReference(  8826, "&prec;");
+        html5References.addReference(  8826, "&Precedes;");
+        html5References.addReference(  8827, "&sc;");
+        html5References.addReference(  8827, "&succ;");
+        html5References.addReference(  8827, "&Succeeds;");
+        html5References.addReference(  8828, "&prcue;");
+        html5References.addReference(  8828, "&preccurlyeq;");
+        html5References.addReference(  8828, "&PrecedesSlantEqual;");
+        html5References.addReference(  8829, "&sccue;");
+        html5References.addReference(  8829, "&succcurlyeq;");
+        html5References.addReference(  8829, "&SucceedsSlantEqual;");
+        html5References.addReference(  8830, "&precsim;");
+        html5References.addReference(  8830, "&prsim;");
+        html5References.addReference(  8830, "&PrecedesTilde;");
+        html5References.addReference(  8831, "&scsim;");
+        html5References.addReference(  8831, "&succsim;");
+        html5References.addReference(  8831, "&SucceedsTilde;");
+        html5References.addReference(  8831,   824, "&NotSucceedsTilde;");
+        html5References.addReference(  8832, "&npr;");
+        html5References.addReference(  8832, "&nprec;");
+        html5References.addReference(  8832, "&NotPrecedes;");
+        html5References.addReference(  8833, "&nsc;");
+        html5References.addReference(  8833, "&nsucc;");
+        html5References.addReference(  8833, "&NotSucceeds;");
+        html5References.addReference(  8834, "&sub;");
+        html5References.addReference(  8834, "&subset;");
+        html5References.addReference(  8834,  8402, "&nsubset;");
+        html5References.addReference(  8834,  8402, "&vnsub;");
+        html5References.addReference(  8834,  8402, "&NotSubset;");
+        html5References.addReference(  8835, "&sup;");
+        html5References.addReference(  8835, "&supset;");
+        html5References.addReference(  8835, "&Superset;");
+        html5References.addReference(  8835,  8402, "&nsupset;");
+        html5References.addReference(  8835,  8402, "&vnsup;");
+        html5References.addReference(  8835,  8402, "&NotSuperset;");
+        html5References.addReference(  8836, "&nsub;");
+        html5References.addReference(  8837, "&nsup;");
+        html5References.addReference(  8838, "&sube;");
+        html5References.addReference(  8838, "&subseteq;");
+        html5References.addReference(  8838, "&SubsetEqual;");
+        html5References.addReference(  8839, "&supe;");
+        html5References.addReference(  8839, "&supseteq;");
+        html5References.addReference(  8839, "&SupersetEqual;");
+        html5References.addReference(  8840, "&nsube;");
+        html5References.addReference(  8840, "&nsubseteq;");
+        html5References.addReference(  8840, "&NotSubsetEqual;");
+        html5References.addReference(  8841, "&nsupe;");
+        html5References.addReference(  8841, "&nsupseteq;");
+        html5References.addReference(  8841, "&NotSupersetEqual;");
+        html5References.addReference(  8842, "&subne;");
+        html5References.addReference(  8842, "&subsetneq;");
+        html5References.addReference(  8842, 65024, "&varsubsetneq;");
+        html5References.addReference(  8842, 65024, "&vsubne;");
+        html5References.addReference(  8843, "&supne;");
+        html5References.addReference(  8843, "&supsetneq;");
+        html5References.addReference(  8843, 65024, "&varsupsetneq;");
+        html5References.addReference(  8843, 65024, "&vsupne;");
+        html5References.addReference(  8845, "&cupdot;");
+        html5References.addReference(  8846, "&uplus;");
+        html5References.addReference(  8846, "&UnionPlus;");
+        html5References.addReference(  8847, "&sqsub;");
+        html5References.addReference(  8847, "&sqsubset;");
+        html5References.addReference(  8847, "&SquareSubset;");
+        html5References.addReference(  8847,   824, "&NotSquareSubset;");
+        html5References.addReference(  8848, "&sqsup;");
+        html5References.addReference(  8848, "&sqsupset;");
+        html5References.addReference(  8848, "&SquareSuperset;");
+        html5References.addReference(  8848,   824, "&NotSquareSuperset;");
+        html5References.addReference(  8849, "&sqsube;");
+        html5References.addReference(  8849, "&sqsubseteq;");
+        html5References.addReference(  8849, "&SquareSubsetEqual;");
+        html5References.addReference(  8850, "&sqsupe;");
+        html5References.addReference(  8850, "&sqsupseteq;");
+        html5References.addReference(  8850, "&SquareSupersetEqual;");
+        html5References.addReference(  8851, "&sqcap;");
+        html5References.addReference(  8851, "&SquareIntersection;");
+        html5References.addReference(  8851, 65024, "&sqcaps;");
+        html5References.addReference(  8852, "&sqcup;");
+        html5References.addReference(  8852, "&SquareUnion;");
+        html5References.addReference(  8852, 65024, "&sqcups;");
+        html5References.addReference(  8853, "&oplus;");
+        html5References.addReference(  8853, "&CirclePlus;");
+        html5References.addReference(  8854, "&ominus;");
+        html5References.addReference(  8854, "&CircleMinus;");
+        html5References.addReference(  8855, "&otimes;");
+        html5References.addReference(  8855, "&CircleTimes;");
+        html5References.addReference(  8856, "&osol;");
+        html5References.addReference(  8857, "&odot;");
+        html5References.addReference(  8857, "&CircleDot;");
+        html5References.addReference(  8858, "&circledcirc;");
+        html5References.addReference(  8858, "&ocir;");
+        html5References.addReference(  8859, "&circledast;");
+        html5References.addReference(  8859, "&oast;");
+        html5References.addReference(  8861, "&circleddash;");
+        html5References.addReference(  8861, "&odash;");
+        html5References.addReference(  8862, "&boxplus;");
+        html5References.addReference(  8862, "&plusb;");
+        html5References.addReference(  8863, "&boxminus;");
+        html5References.addReference(  8863, "&minusb;");
+        html5References.addReference(  8864, "&boxtimes;");
+        html5References.addReference(  8864, "&timesb;");
+        html5References.addReference(  8865, "&dotsquare;");
+        html5References.addReference(  8865, "&sdotb;");
+        html5References.addReference(  8866, "&vdash;");
+        html5References.addReference(  8866, "&RightTee;");
+        html5References.addReference(  8867, "&dashv;");
+        html5References.addReference(  8867, "&LeftTee;");
+        html5References.addReference(  8868, "&top;");
+        html5References.addReference(  8868, "&DownTee;");
+        html5References.addReference(  8869, "&perp;");
+        html5References.addReference(  8869, "&bot;");
+        html5References.addReference(  8869, "&bottom;");
+        html5References.addReference(  8869, "&UpTee;");
+        html5References.addReference(  8871, "&models;");
+        html5References.addReference(  8872, "&vDash;");
+        html5References.addReference(  8872, "&DoubleRightTee;");
+        html5References.addReference(  8873, "&Vdash;");
+        html5References.addReference(  8874, "&Vvdash;");
+        html5References.addReference(  8875, "&VDash;");
+        html5References.addReference(  8876, "&nvdash;");
+        html5References.addReference(  8877, "&nvDash;");
+        html5References.addReference(  8878, "&nVdash;");
+        html5References.addReference(  8879, "&nVDash;");
+        html5References.addReference(  8880, "&prurel;");
+        html5References.addReference(  8882, "&vartriangleleft;");
+        html5References.addReference(  8882, "&vltri;");
+        html5References.addReference(  8882, "&LeftTriangle;");
+        html5References.addReference(  8883, "&vartriangleright;");
+        html5References.addReference(  8883, "&vrtri;");
+        html5References.addReference(  8883, "&RightTriangle;");
+        html5References.addReference(  8884, "&ltrie;");
+        html5References.addReference(  8884, "&trianglelefteq;");
+        html5References.addReference(  8884, "&LeftTriangleEqual;");
+        html5References.addReference(  8884,  8402, "&nvltrie;");
+        html5References.addReference(  8885, "&rtrie;");
+        html5References.addReference(  8885, "&trianglerighteq;");
+        html5References.addReference(  8885, "&RightTriangleEqual;");
+        html5References.addReference(  8885,  8402, "&nvrtrie;");
+        html5References.addReference(  8886, "&origof;");
+        html5References.addReference(  8887, "&imof;");
+        html5References.addReference(  8888, "&multimap;");
+        html5References.addReference(  8888, "&mumap;");
+        html5References.addReference(  8889, "&hercon;");
+        html5References.addReference(  8890, "&intcal;");
+        html5References.addReference(  8890, "&intercal;");
+        html5References.addReference(  8891, "&veebar;");
+        html5References.addReference(  8893, "&barvee;");
+        html5References.addReference(  8894, "&angrtvb;");
+        html5References.addReference(  8895, "&lrtri;");
+        html5References.addReference(  8896, "&bigwedge;");
+        html5References.addReference(  8896, "&xwedge;");
+        html5References.addReference(  8896, "&Wedge;");
+        html5References.addReference(  8897, "&bigvee;");
+        html5References.addReference(  8897, "&xvee;");
+        html5References.addReference(  8897, "&Vee;");
+        html5References.addReference(  8898, "&bigcap;");
+        html5References.addReference(  8898, "&xcap;");
+        html5References.addReference(  8898, "&Intersection;");
+        html5References.addReference(  8899, "&bigcup;");
+        html5References.addReference(  8899, "&xcup;");
+        html5References.addReference(  8899, "&Union;");
+        html5References.addReference(  8900, "&diam;");
+        html5References.addReference(  8900, "&diamond;");
+        html5References.addReference(  8900, "&Diamond;");
+        html5References.addReference(  8901, "&sdot;");
+        html5References.addReference(  8902, "&sstarf;");
+        html5References.addReference(  8902, "&Star;");
+        html5References.addReference(  8903, "&divideontimes;");
+        html5References.addReference(  8903, "&divonx;");
+        html5References.addReference(  8904, "&bowtie;");
+        html5References.addReference(  8905, "&ltimes;");
+        html5References.addReference(  8906, "&rtimes;");
+        html5References.addReference(  8907, "&leftthreetimes;");
+        html5References.addReference(  8907, "&lthree;");
+        html5References.addReference(  8908, "&rightthreetimes;");
+        html5References.addReference(  8908, "&rthree;");
+        html5References.addReference(  8909, "&backsimeq;");
+        html5References.addReference(  8909, "&bsime;");
+        html5References.addReference(  8910, "&curlyvee;");
+        html5References.addReference(  8910, "&cuvee;");
+        html5References.addReference(  8911, "&curlywedge;");
+        html5References.addReference(  8911, "&cuwed;");
+        html5References.addReference(  8912, "&Sub;");
+        html5References.addReference(  8912, "&Subset;");
+        html5References.addReference(  8913, "&Sup;");
+        html5References.addReference(  8913, "&Supset;");
+        html5References.addReference(  8914, "&Cap;");
+        html5References.addReference(  8915, "&Cup;");
+        html5References.addReference(  8916, "&fork;");
+        html5References.addReference(  8916, "&pitchfork;");
+        html5References.addReference(  8917, "&epar;");
+        html5References.addReference(  8918, "&lessdot;");
+        html5References.addReference(  8918, "&ltdot;");
+        html5References.addReference(  8919, "&gtdot;");
+        html5References.addReference(  8919, "&gtrdot;");
+        html5References.addReference(  8920, "&Ll;");
+        html5References.addReference(  8920,   824, "&nLl;");
+        html5References.addReference(  8921, "&ggg;");
+        html5References.addReference(  8921, "&Gg;");
+        html5References.addReference(  8921,   824, "&nGg;");
+        html5References.addReference(  8922, "&leg;");
+        html5References.addReference(  8922, "&lesseqgtr;");
+        html5References.addReference(  8922, "&LessEqualGreater;");
+        html5References.addReference(  8922, 65024, "&lesg;");
+        html5References.addReference(  8923, "&gel;");
+        html5References.addReference(  8923, "&gtreqless;");
+        html5References.addReference(  8923, "&GreaterEqualLess;");
+        html5References.addReference(  8923, 65024, "&gesl;");
+        html5References.addReference(  8926, "&cuepr;");
+        html5References.addReference(  8926, "&curlyeqprec;");
+        html5References.addReference(  8927, "&cuesc;");
+        html5References.addReference(  8927, "&curlyeqsucc;");
+        html5References.addReference(  8928, "&nprcue;");
+        html5References.addReference(  8928, "&NotPrecedesSlantEqual;");
+        html5References.addReference(  8929, "&nsccue;");
+        html5References.addReference(  8929, "&NotSucceedsSlantEqual;");
+        html5References.addReference(  8930, "&nsqsube;");
+        html5References.addReference(  8930, "&NotSquareSubsetEqual;");
+        html5References.addReference(  8931, "&nsqsupe;");
+        html5References.addReference(  8931, "&NotSquareSupersetEqual;");
+        html5References.addReference(  8934, "&lnsim;");
+        html5References.addReference(  8935, "&gnsim;");
+        html5References.addReference(  8936, "&precnsim;");
+        html5References.addReference(  8936, "&prnsim;");
+        html5References.addReference(  8937, "&scnsim;");
+        html5References.addReference(  8937, "&succnsim;");
+        html5References.addReference(  8938, "&nltri;");
+        html5References.addReference(  8938, "&ntriangleleft;");
+        html5References.addReference(  8938, "&NotLeftTriangle;");
+        html5References.addReference(  8939, "&nrtri;");
+        html5References.addReference(  8939, "&ntriangleright;");
+        html5References.addReference(  8939, "&NotRightTriangle;");
+        html5References.addReference(  8940, "&nltrie;");
+        html5References.addReference(  8940, "&ntrianglelefteq;");
+        html5References.addReference(  8940, "&NotLeftTriangleEqual;");
+        html5References.addReference(  8941, "&nrtrie;");
+        html5References.addReference(  8941, "&ntrianglerighteq;");
+        html5References.addReference(  8941, "&NotRightTriangleEqual;");
+        html5References.addReference(  8942, "&vellip;");
+        html5References.addReference(  8943, "&ctdot;");
+        html5References.addReference(  8944, "&utdot;");
+        html5References.addReference(  8945, "&dtdot;");
+        html5References.addReference(  8946, "&disin;");
+        html5References.addReference(  8947, "&isinsv;");
+        html5References.addReference(  8948, "&isins;");
+        html5References.addReference(  8949, "&isindot;");
+        html5References.addReference(  8949,   824, "&notindot;");
+        html5References.addReference(  8950, "&notinvc;");
+        html5References.addReference(  8951, "&notinvb;");
+        html5References.addReference(  8953, "&isinE;");
+        html5References.addReference(  8953,   824, "&notinE;");
+        html5References.addReference(  8954, "&nisd;");
+        html5References.addReference(  8955, "&xnis;");
+        html5References.addReference(  8956, "&nis;");
+        html5References.addReference(  8957, "&notnivc;");
+        html5References.addReference(  8958, "&notnivb;");
+        html5References.addReference(  8965, "&barwed;");
+        html5References.addReference(  8965, "&barwedge;");
+        html5References.addReference(  8966, "&doublebarwedge;");
+        html5References.addReference(  8966, "&Barwed;");
+        html5References.addReference(  8968, "&lceil;");
+        html5References.addReference(  8968, "&LeftCeiling;");
+        html5References.addReference(  8969, "&rceil;");
+        html5References.addReference(  8969, "&RightCeiling;");
+        html5References.addReference(  8970, "&lfloor;");
+        html5References.addReference(  8970, "&LeftFloor;");
+        html5References.addReference(  8971, "&rfloor;");
+        html5References.addReference(  8971, "&RightFloor;");
+        html5References.addReference(  8972, "&drcrop;");
+        html5References.addReference(  8973, "&dlcrop;");
+        html5References.addReference(  8974, "&urcrop;");
+        html5References.addReference(  8975, "&ulcrop;");
+        html5References.addReference(  8976, "&bnot;");
+        html5References.addReference(  8978, "&profline;");
+        html5References.addReference(  8979, "&profsurf;");
+        html5References.addReference(  8981, "&telrec;");
+        html5References.addReference(  8982, "&target;");
+        html5References.addReference(  8988, "&ulcorn;");
+        html5References.addReference(  8988, "&ulcorner;");
+        html5References.addReference(  8989, "&urcorn;");
+        html5References.addReference(  8989, "&urcorner;");
+        html5References.addReference(  8990, "&dlcorn;");
+        html5References.addReference(  8990, "&llcorner;");
+        html5References.addReference(  8991, "&drcorn;");
+        html5References.addReference(  8991, "&lrcorner;");
+        html5References.addReference(  8994, "&frown;");
+        html5References.addReference(  8994, "&sfrown;");
+        html5References.addReference(  8995, "&smile;");
+        html5References.addReference(  8995, "&ssmile;");
+        html5References.addReference(  9005, "&cylcty;");
+        html5References.addReference(  9006, "&profalar;");
+        html5References.addReference(  9014, "&topbot;");
+        html5References.addReference(  9021, "&ovbar;");
+        html5References.addReference(  9023, "&solbar;");
+        html5References.addReference(  9084, "&angzarr;");
+        html5References.addReference(  9136, "&lmoust;");
+        html5References.addReference(  9136, "&lmoustache;");
+        html5References.addReference(  9137, "&rmoust;");
+        html5References.addReference(  9137, "&rmoustache;");
+        html5References.addReference(  9140, "&tbrk;");
+        html5References.addReference(  9140, "&OverBracket;");
+        html5References.addReference(  9141, "&bbrk;");
+        html5References.addReference(  9141, "&UnderBracket;");
+        html5References.addReference(  9142, "&bbrktbrk;");
+        html5References.addReference(  9180, "&OverParenthesis;");
+        html5References.addReference(  9181, "&UnderParenthesis;");
+        html5References.addReference(  9182, "&OverBrace;");
+        html5References.addReference(  9183, "&UnderBrace;");
+        html5References.addReference(  9186, "&trpezium;");
+        html5References.addReference(  9191, "&elinters;");
+        html5References.addReference(  9251, "&blank;");
+        html5References.addReference(  9416, "&circledS;");
+        html5References.addReference(  9416, "&oS;");
+        html5References.addReference(  9472, "&boxh;");
+        html5References.addReference(  9472, "&HorizontalLine;");
+        html5References.addReference(  9474, "&boxv;");
+        html5References.addReference(  9484, "&boxdr;");
+        html5References.addReference(  9488, "&boxdl;");
+        html5References.addReference(  9492, "&boxur;");
+        html5References.addReference(  9496, "&boxul;");
+        html5References.addReference(  9500, "&boxvr;");
+        html5References.addReference(  9508, "&boxvl;");
+        html5References.addReference(  9516, "&boxhd;");
+        html5References.addReference(  9524, "&boxhu;");
+        html5References.addReference(  9532, "&boxvh;");
+        html5References.addReference(  9552, "&boxH;");
+        html5References.addReference(  9553, "&boxV;");
+        html5References.addReference(  9554, "&boxdR;");
+        html5References.addReference(  9555, "&boxDr;");
+        html5References.addReference(  9556, "&boxDR;");
+        html5References.addReference(  9557, "&boxdL;");
+        html5References.addReference(  9558, "&boxDl;");
+        html5References.addReference(  9559, "&boxDL;");
+        html5References.addReference(  9560, "&boxuR;");
+        html5References.addReference(  9561, "&boxUr;");
+        html5References.addReference(  9562, "&boxUR;");
+        html5References.addReference(  9563, "&boxuL;");
+        html5References.addReference(  9564, "&boxUl;");
+        html5References.addReference(  9565, "&boxUL;");
+        html5References.addReference(  9566, "&boxvR;");
+        html5References.addReference(  9567, "&boxVr;");
+        html5References.addReference(  9568, "&boxVR;");
+        html5References.addReference(  9569, "&boxvL;");
+        html5References.addReference(  9570, "&boxVl;");
+        html5References.addReference(  9571, "&boxVL;");
+        html5References.addReference(  9572, "&boxHd;");
+        html5References.addReference(  9573, "&boxhD;");
+        html5References.addReference(  9574, "&boxHD;");
+        html5References.addReference(  9575, "&boxHu;");
+        html5References.addReference(  9576, "&boxhU;");
+        html5References.addReference(  9577, "&boxHU;");
+        html5References.addReference(  9578, "&boxvH;");
+        html5References.addReference(  9579, "&boxVh;");
+        html5References.addReference(  9580, "&boxVH;");
+        html5References.addReference(  9600, "&uhblk;");
+        html5References.addReference(  9604, "&lhblk;");
+        html5References.addReference(  9608, "&block;");
+        html5References.addReference(  9617, "&blk14;");
+        html5References.addReference(  9618, "&blk12;");
+        html5References.addReference(  9619, "&blk34;");
+        html5References.addReference(  9633, "&squ;");
+        html5References.addReference(  9633, "&square;");
+        html5References.addReference(  9633, "&Square;");
+        html5References.addReference(  9642, "&blacksquare;");
+        html5References.addReference(  9642, "&squarf;");
+        html5References.addReference(  9642, "&squf;");
+        html5References.addReference(  9642, "&FilledVerySmallSquare;");
+        html5References.addReference(  9643, "&EmptyVerySmallSquare;");
+        html5References.addReference(  9645, "&rect;");
+        html5References.addReference(  9646, "&marker;");
+        html5References.addReference(  9649, "&fltns;");
+        html5References.addReference(  9651, "&bigtriangleup;");
+        html5References.addReference(  9651, "&xutri;");
+        html5References.addReference(  9652, "&blacktriangle;");
+        html5References.addReference(  9652, "&utrif;");
+        html5References.addReference(  9653, "&triangle;");
+        html5References.addReference(  9653, "&utri;");
+        html5References.addReference(  9656, "&blacktriangleright;");
+        html5References.addReference(  9656, "&rtrif;");
+        html5References.addReference(  9657, "&rtri;");
+        html5References.addReference(  9657, "&triangleright;");
+        html5References.addReference(  9661, "&bigtriangledown;");
+        html5References.addReference(  9661, "&xdtri;");
+        html5References.addReference(  9662, "&blacktriangledown;");
+        html5References.addReference(  9662, "&dtrif;");
+        html5References.addReference(  9663, "&dtri;");
+        html5References.addReference(  9663, "&triangledown;");
+        html5References.addReference(  9666, "&blacktriangleleft;");
+        html5References.addReference(  9666, "&ltrif;");
+        html5References.addReference(  9667, "&ltri;");
+        html5References.addReference(  9667, "&triangleleft;");
+        html5References.addReference(  9674, "&loz;");
+        html5References.addReference(  9674, "&lozenge;");
+        html5References.addReference(  9675, "&cir;");
+        html5References.addReference(  9708, "&tridot;");
+        html5References.addReference(  9711, "&bigcirc;");
+        html5References.addReference(  9711, "&xcirc;");
+        html5References.addReference(  9720, "&ultri;");
+        html5References.addReference(  9721, "&urtri;");
+        html5References.addReference(  9722, "&lltri;");
+        html5References.addReference(  9723, "&EmptySmallSquare;");
+        html5References.addReference(  9724, "&FilledSmallSquare;");
+        html5References.addReference(  9733, "&bigstar;");
+        html5References.addReference(  9733, "&starf;");
+        html5References.addReference(  9734, "&star;");
+        html5References.addReference(  9742, "&phone;");
+        html5References.addReference(  9792, "&female;");
+        html5References.addReference(  9794, "&male;");
+        html5References.addReference(  9824, "&spades;");
+        html5References.addReference(  9824, "&spadesuit;");
+        html5References.addReference(  9827, "&clubs;");
+        html5References.addReference(  9827, "&clubsuit;");
+        html5References.addReference(  9829, "&hearts;");
+        html5References.addReference(  9829, "&heartsuit;");
+        html5References.addReference(  9830, "&diams;");
+        html5References.addReference(  9830, "&diamondsuit;");
+        html5References.addReference(  9834, "&sung;");
+        html5References.addReference(  9837, "&flat;");
+        html5References.addReference(  9838, "&natur;");
+        html5References.addReference(  9838, "&natural;");
+        html5References.addReference(  9839, "&sharp;");
+        html5References.addReference( 10003, "&check;");
+        html5References.addReference( 10003, "&checkmark;");
+        html5References.addReference( 10007, "&cross;");
+        html5References.addReference( 10016, "&malt;");
+        html5References.addReference( 10016, "&maltese;");
+        html5References.addReference( 10038, "&sext;");
+        html5References.addReference( 10072, "&VerticalSeparator;");
+        html5References.addReference( 10098, "&lbbrk;");
+        html5References.addReference( 10099, "&rbbrk;");
+        html5References.addReference( 10184, "&bsolhsub;");
+        html5References.addReference( 10185, "&suphsol;");
+        html5References.addReference( 10214, "&lobrk;");
+        html5References.addReference( 10214, "&LeftDoubleBracket;");
+        html5References.addReference( 10215, "&robrk;");
+        html5References.addReference( 10215, "&RightDoubleBracket;");
+        html5References.addReference( 10216, "&lang;");
+        html5References.addReference( 10216, "&langle;");
+        html5References.addReference( 10216, "&LeftAngleBracket;");
+        html5References.addReference( 10217, "&rang;");
+        html5References.addReference( 10217, "&rangle;");
+        html5References.addReference( 10217, "&RightAngleBracket;");
+        html5References.addReference( 10218, "&Lang;");
+        html5References.addReference( 10219, "&Rang;");
+        html5References.addReference( 10220, "&loang;");
+        html5References.addReference( 10221, "&roang;");
+        html5References.addReference( 10229, "&longleftarrow;");
+        html5References.addReference( 10229, "&xlarr;");
+        html5References.addReference( 10229, "&LongLeftArrow;");
+        html5References.addReference( 10230, "&longrightarrow;");
+        html5References.addReference( 10230, "&xrarr;");
+        html5References.addReference( 10230, "&LongRightArrow;");
+        html5References.addReference( 10231, "&longleftrightarrow;");
+        html5References.addReference( 10231, "&xharr;");
+        html5References.addReference( 10231, "&LongLeftRightArrow;");
+        html5References.addReference( 10232, "&xlArr;");
+        html5References.addReference( 10232, "&DoubleLongLeftArrow;");
+        html5References.addReference( 10232, "&Longleftarrow;");
+        html5References.addReference( 10233, "&xrArr;");
+        html5References.addReference( 10233, "&DoubleLongRightArrow;");
+        html5References.addReference( 10233, "&Longrightarrow;");
+        html5References.addReference( 10234, "&xhArr;");
+        html5References.addReference( 10234, "&DoubleLongLeftRightArrow;");
+        html5References.addReference( 10234, "&Longleftrightarrow;");
+        html5References.addReference( 10236, "&longmapsto;");
+        html5References.addReference( 10236, "&xmap;");
+        html5References.addReference( 10239, "&dzigrarr;");
+        html5References.addReference( 10498, "&nvlArr;");
+        html5References.addReference( 10499, "&nvrArr;");
+        html5References.addReference( 10500, "&nvHarr;");
+        html5References.addReference( 10501, "&Map;");
+        html5References.addReference( 10508, "&lbarr;");
+        html5References.addReference( 10509, "&bkarow;");
+        html5References.addReference( 10509, "&rbarr;");
+        html5References.addReference( 10510, "&lBarr;");
+        html5References.addReference( 10511, "&dbkarow;");
+        html5References.addReference( 10511, "&rBarr;");
+        html5References.addReference( 10512, "&drbkarow;");
+        html5References.addReference( 10512, "&RBarr;");
+        html5References.addReference( 10513, "&DDotrahd;");
+        html5References.addReference( 10514, "&UpArrowBar;");
+        html5References.addReference( 10515, "&DownArrowBar;");
+        html5References.addReference( 10518, "&Rarrtl;");
+        html5References.addReference( 10521, "&latail;");
+        html5References.addReference( 10522, "&ratail;");
+        html5References.addReference( 10523, "&lAtail;");
+        html5References.addReference( 10524, "&rAtail;");
+        html5References.addReference( 10525, "&larrfs;");
+        html5References.addReference( 10526, "&rarrfs;");
+        html5References.addReference( 10527, "&larrbfs;");
+        html5References.addReference( 10528, "&rarrbfs;");
+        html5References.addReference( 10531, "&nwarhk;");
+        html5References.addReference( 10532, "&nearhk;");
+        html5References.addReference( 10533, "&hksearow;");
+        html5References.addReference( 10533, "&searhk;");
+        html5References.addReference( 10534, "&hkswarow;");
+        html5References.addReference( 10534, "&swarhk;");
+        html5References.addReference( 10535, "&nwnear;");
+        html5References.addReference( 10536, "&nesear;");
+        html5References.addReference( 10536, "&toea;");
+        html5References.addReference( 10537, "&seswar;");
+        html5References.addReference( 10537, "&tosa;");
+        html5References.addReference( 10538, "&swnwar;");
+        html5References.addReference( 10547, "&rarrc;");
+        html5References.addReference( 10547,   824, "&nrarrc;");
+        html5References.addReference( 10549, "&cudarrr;");
+        html5References.addReference( 10550, "&ldca;");
+        html5References.addReference( 10551, "&rdca;");
+        html5References.addReference( 10552, "&cudarrl;");
+        html5References.addReference( 10553, "&larrpl;");
+        html5References.addReference( 10556, "&curarrm;");
+        html5References.addReference( 10557, "&cularrp;");
+        html5References.addReference( 10565, "&rarrpl;");
+        html5References.addReference( 10568, "&harrcir;");
+        html5References.addReference( 10569, "&Uarrocir;");
+        html5References.addReference( 10570, "&lurdshar;");
+        html5References.addReference( 10571, "&ldrushar;");
+        html5References.addReference( 10574, "&LeftRightVector;");
+        html5References.addReference( 10575, "&RightUpDownVector;");
+        html5References.addReference( 10576, "&DownLeftRightVector;");
+        html5References.addReference( 10577, "&LeftUpDownVector;");
+        html5References.addReference( 10578, "&LeftVectorBar;");
+        html5References.addReference( 10579, "&RightVectorBar;");
+        html5References.addReference( 10580, "&RightUpVectorBar;");
+        html5References.addReference( 10581, "&RightDownVectorBar;");
+        html5References.addReference( 10582, "&DownLeftVectorBar;");
+        html5References.addReference( 10583, "&DownRightVectorBar;");
+        html5References.addReference( 10584, "&LeftUpVectorBar;");
+        html5References.addReference( 10585, "&LeftDownVectorBar;");
+        html5References.addReference( 10586, "&LeftTeeVector;");
+        html5References.addReference( 10587, "&RightTeeVector;");
+        html5References.addReference( 10588, "&RightUpTeeVector;");
+        html5References.addReference( 10589, "&RightDownTeeVector;");
+        html5References.addReference( 10590, "&DownLeftTeeVector;");
+        html5References.addReference( 10591, "&DownRightTeeVector;");
+        html5References.addReference( 10592, "&LeftUpTeeVector;");
+        html5References.addReference( 10593, "&LeftDownTeeVector;");
+        html5References.addReference( 10594, "&lHar;");
+        html5References.addReference( 10595, "&uHar;");
+        html5References.addReference( 10596, "&rHar;");
+        html5References.addReference( 10597, "&dHar;");
+        html5References.addReference( 10598, "&luruhar;");
+        html5References.addReference( 10599, "&ldrdhar;");
+        html5References.addReference( 10600, "&ruluhar;");
+        html5References.addReference( 10601, "&rdldhar;");
+        html5References.addReference( 10602, "&lharul;");
+        html5References.addReference( 10603, "&llhard;");
+        html5References.addReference( 10604, "&rharul;");
+        html5References.addReference( 10605, "&lrhard;");
+        html5References.addReference( 10606, "&udhar;");
+        html5References.addReference( 10606, "&UpEquilibrium;");
+        html5References.addReference( 10607, "&duhar;");
+        html5References.addReference( 10607, "&ReverseUpEquilibrium;");
+        html5References.addReference( 10608, "&RoundImplies;");
+        html5References.addReference( 10609, "&erarr;");
+        html5References.addReference( 10610, "&simrarr;");
+        html5References.addReference( 10611, "&larrsim;");
+        html5References.addReference( 10612, "&rarrsim;");
+        html5References.addReference( 10613, "&rarrap;");
+        html5References.addReference( 10614, "&ltlarr;");
+        html5References.addReference( 10616, "&gtrarr;");
+        html5References.addReference( 10617, "&subrarr;");
+        html5References.addReference( 10619, "&suplarr;");
+        html5References.addReference( 10620, "&lfisht;");
+        html5References.addReference( 10621, "&rfisht;");
+        html5References.addReference( 10622, "&ufisht;");
+        html5References.addReference( 10623, "&dfisht;");
+        html5References.addReference( 10629, "&lopar;");
+        html5References.addReference( 10630, "&ropar;");
+        html5References.addReference( 10635, "&lbrke;");
+        html5References.addReference( 10636, "&rbrke;");
+        html5References.addReference( 10637, "&lbrkslu;");
+        html5References.addReference( 10638, "&rbrksld;");
+        html5References.addReference( 10639, "&lbrksld;");
+        html5References.addReference( 10640, "&rbrkslu;");
+        html5References.addReference( 10641, "&langd;");
+        html5References.addReference( 10642, "&rangd;");
+        html5References.addReference( 10643, "&lparlt;");
+        html5References.addReference( 10644, "&rpargt;");
+        html5References.addReference( 10645, "&gtlPar;");
+        html5References.addReference( 10646, "&ltrPar;");
+        html5References.addReference( 10650, "&vzigzag;");
+        html5References.addReference( 10652, "&vangrt;");
+        html5References.addReference( 10653, "&angrtvbd;");
+        html5References.addReference( 10660, "&ange;");
+        html5References.addReference( 10661, "&range;");
+        html5References.addReference( 10662, "&dwangle;");
+        html5References.addReference( 10663, "&uwangle;");
+        html5References.addReference( 10664, "&angmsdaa;");
+        html5References.addReference( 10665, "&angmsdab;");
+        html5References.addReference( 10666, "&angmsdac;");
+        html5References.addReference( 10667, "&angmsdad;");
+        html5References.addReference( 10668, "&angmsdae;");
+        html5References.addReference( 10669, "&angmsdaf;");
+        html5References.addReference( 10670, "&angmsdag;");
+        html5References.addReference( 10671, "&angmsdah;");
+        html5References.addReference( 10672, "&bemptyv;");
+        html5References.addReference( 10673, "&demptyv;");
+        html5References.addReference( 10674, "&cemptyv;");
+        html5References.addReference( 10675, "&raemptyv;");
+        html5References.addReference( 10676, "&laemptyv;");
+        html5References.addReference( 10677, "&ohbar;");
+        html5References.addReference( 10678, "&omid;");
+        html5References.addReference( 10679, "&opar;");
+        html5References.addReference( 10681, "&operp;");
+        html5References.addReference( 10683, "&olcross;");
+        html5References.addReference( 10684, "&odsold;");
+        html5References.addReference( 10686, "&olcir;");
+        html5References.addReference( 10687, "&ofcir;");
+        html5References.addReference( 10688, "&olt;");
+        html5References.addReference( 10689, "&ogt;");
+        html5References.addReference( 10690, "&cirscir;");
+        html5References.addReference( 10691, "&cirE;");
+        html5References.addReference( 10692, "&solb;");
+        html5References.addReference( 10693, "&bsolb;");
+        html5References.addReference( 10697, "&boxbox;");
+        html5References.addReference( 10701, "&trisb;");
+        html5References.addReference( 10702, "&rtriltri;");
+        html5References.addReference( 10703, "&LeftTriangleBar;");
+        html5References.addReference( 10703,   824, "&NotLeftTriangleBar;");
+        html5References.addReference( 10704, "&RightTriangleBar;");
+        html5References.addReference( 10704,   824, "&NotRightTriangleBar;");
+        html5References.addReference( 10716, "&iinfin;");
+        html5References.addReference( 10717, "&infintie;");
+        html5References.addReference( 10718, "&nvinfin;");
+        html5References.addReference( 10723, "&eparsl;");
+        html5References.addReference( 10724, "&smeparsl;");
+        html5References.addReference( 10725, "&eqvparsl;");
+        html5References.addReference( 10731, "&blacklozenge;");
+        html5References.addReference( 10731, "&lozf;");
+        html5References.addReference( 10740, "&RuleDelayed;");
+        html5References.addReference( 10742, "&dsol;");
+        html5References.addReference( 10752, "&bigodot;");
+        html5References.addReference( 10752, "&xodot;");
+        html5References.addReference( 10753, "&bigoplus;");
+        html5References.addReference( 10753, "&xoplus;");
+        html5References.addReference( 10754, "&bigotimes;");
+        html5References.addReference( 10754, "&xotime;");
+        html5References.addReference( 10756, "&biguplus;");
+        html5References.addReference( 10756, "&xuplus;");
+        html5References.addReference( 10758, "&bigsqcup;");
+        html5References.addReference( 10758, "&xsqcup;");
+        html5References.addReference( 10764, "&iiiint;");
+        html5References.addReference( 10764, "&qint;");
+        html5References.addReference( 10765, "&fpartint;");
+        html5References.addReference( 10768, "&cirfnint;");
+        html5References.addReference( 10769, "&awint;");
+        html5References.addReference( 10770, "&rppolint;");
+        html5References.addReference( 10771, "&scpolint;");
+        html5References.addReference( 10772, "&npolint;");
+        html5References.addReference( 10773, "&pointint;");
+        html5References.addReference( 10774, "&quatint;");
+        html5References.addReference( 10775, "&intlarhk;");
+        html5References.addReference( 10786, "&pluscir;");
+        html5References.addReference( 10787, "&plusacir;");
+        html5References.addReference( 10788, "&simplus;");
+        html5References.addReference( 10789, "&plusdu;");
+        html5References.addReference( 10790, "&plussim;");
+        html5References.addReference( 10791, "&plustwo;");
+        html5References.addReference( 10793, "&mcomma;");
+        html5References.addReference( 10794, "&minusdu;");
+        html5References.addReference( 10797, "&loplus;");
+        html5References.addReference( 10798, "&roplus;");
+        html5References.addReference( 10799, "&Cross;");
+        html5References.addReference( 10800, "&timesd;");
+        html5References.addReference( 10801, "&timesbar;");
+        html5References.addReference( 10803, "&smashp;");
+        html5References.addReference( 10804, "&lotimes;");
+        html5References.addReference( 10805, "&rotimes;");
+        html5References.addReference( 10806, "&otimesas;");
+        html5References.addReference( 10807, "&Otimes;");
+        html5References.addReference( 10808, "&odiv;");
+        html5References.addReference( 10809, "&triplus;");
+        html5References.addReference( 10810, "&triminus;");
+        html5References.addReference( 10811, "&tritime;");
+        html5References.addReference( 10812, "&intprod;");
+        html5References.addReference( 10812, "&iprod;");
+        html5References.addReference( 10815, "&amalg;");
+        html5References.addReference( 10816, "&capdot;");
+        html5References.addReference( 10818, "&ncup;");
+        html5References.addReference( 10819, "&ncap;");
+        html5References.addReference( 10820, "&capand;");
+        html5References.addReference( 10821, "&cupor;");
+        html5References.addReference( 10822, "&cupcap;");
+        html5References.addReference( 10823, "&capcup;");
+        html5References.addReference( 10824, "&cupbrcap;");
+        html5References.addReference( 10825, "&capbrcup;");
+        html5References.addReference( 10826, "&cupcup;");
+        html5References.addReference( 10827, "&capcap;");
+        html5References.addReference( 10828, "&ccups;");
+        html5References.addReference( 10829, "&ccaps;");
+        html5References.addReference( 10832, "&ccupssm;");
+        html5References.addReference( 10835, "&And;");
+        html5References.addReference( 10836, "&Or;");
+        html5References.addReference( 10837, "&andand;");
+        html5References.addReference( 10838, "&oror;");
+        html5References.addReference( 10839, "&orslope;");
+        html5References.addReference( 10840, "&andslope;");
+        html5References.addReference( 10842, "&andv;");
+        html5References.addReference( 10843, "&orv;");
+        html5References.addReference( 10844, "&andd;");
+        html5References.addReference( 10845, "&ord;");
+        html5References.addReference( 10847, "&wedbar;");
+        html5References.addReference( 10854, "&sdote;");
+        html5References.addReference( 10858, "&simdot;");
+        html5References.addReference( 10861, "&congdot;");
+        html5References.addReference( 10861,   824, "&ncongdot;");
+        html5References.addReference( 10862, "&easter;");
+        html5References.addReference( 10863, "&apacir;");
+        html5References.addReference( 10864, "&apE;");
+        html5References.addReference( 10864,   824, "&napE;");
+        html5References.addReference( 10865, "&eplus;");
+        html5References.addReference( 10866, "&pluse;");
+        html5References.addReference( 10867, "&Esim;");
+        html5References.addReference( 10868, "&Colone;");
+        html5References.addReference( 10869, "&Equal;");
+        html5References.addReference( 10871, "&ddotseq;");
+        html5References.addReference( 10871, "&eDDot;");
+        html5References.addReference( 10872, "&equivDD;");
+        html5References.addReference( 10873, "&ltcir;");
+        html5References.addReference( 10874, "&gtcir;");
+        html5References.addReference( 10875, "&ltquest;");
+        html5References.addReference( 10876, "&gtquest;");
+        html5References.addReference( 10877, "&leqslant;");
+        html5References.addReference( 10877, "&les;");
+        html5References.addReference( 10877, "&LessSlantEqual;");
+        html5References.addReference( 10877,   824, "&nleqslant;");
+        html5References.addReference( 10877,   824, "&nles;");
+        html5References.addReference( 10877,   824, "&NotLessSlantEqual;");
+        html5References.addReference( 10878, "&geqslant;");
+        html5References.addReference( 10878, "&ges;");
+        html5References.addReference( 10878, "&GreaterSlantEqual;");
+        html5References.addReference( 10878,   824, "&ngeqslant;");
+        html5References.addReference( 10878,   824, "&nges;");
+        html5References.addReference( 10878,   824, "&NotGreaterSlantEqual;");
+        html5References.addReference( 10879, "&lesdot;");
+        html5References.addReference( 10880, "&gesdot;");
+        html5References.addReference( 10881, "&lesdoto;");
+        html5References.addReference( 10882, "&gesdoto;");
+        html5References.addReference( 10883, "&lesdotor;");
+        html5References.addReference( 10884, "&gesdotol;");
+        html5References.addReference( 10885, "&lap;");
+        html5References.addReference( 10885, "&lessapprox;");
+        html5References.addReference( 10886, "&gap;");
+        html5References.addReference( 10886, "&gtrapprox;");
+        html5References.addReference( 10887, "&lne;");
+        html5References.addReference( 10887, "&lneq;");
+        html5References.addReference( 10888, "&gne;");
+        html5References.addReference( 10888, "&gneq;");
+        html5References.addReference( 10889, "&lnap;");
+        html5References.addReference( 10889, "&lnapprox;");
+        html5References.addReference( 10890, "&gnap;");
+        html5References.addReference( 10890, "&gnapprox;");
+        html5References.addReference( 10891, "&lEg;");
+        html5References.addReference( 10891, "&lesseqqgtr;");
+        html5References.addReference( 10892, "&gEl;");
+        html5References.addReference( 10892, "&gtreqqless;");
+        html5References.addReference( 10893, "&lsime;");
+        html5References.addReference( 10894, "&gsime;");
+        html5References.addReference( 10895, "&lsimg;");
+        html5References.addReference( 10896, "&gsiml;");
+        html5References.addReference( 10897, "&lgE;");
+        html5References.addReference( 10898, "&glE;");
+        html5References.addReference( 10899, "&lesges;");
+        html5References.addReference( 10900, "&gesles;");
+        html5References.addReference( 10901, "&els;");
+        html5References.addReference( 10901, "&eqslantless;");
+        html5References.addReference( 10902, "&egs;");
+        html5References.addReference( 10902, "&eqslantgtr;");
+        html5References.addReference( 10903, "&elsdot;");
+        html5References.addReference( 10904, "&egsdot;");
+        html5References.addReference( 10905, "&el;");
+        html5References.addReference( 10906, "&eg;");
+        html5References.addReference( 10909, "&siml;");
+        html5References.addReference( 10910, "&simg;");
+        html5References.addReference( 10911, "&simlE;");
+        html5References.addReference( 10912, "&simgE;");
+        html5References.addReference( 10913, "&LessLess;");
+        html5References.addReference( 10913,   824, "&NotNestedLessLess;");
+        html5References.addReference( 10914, "&GreaterGreater;");
+        html5References.addReference( 10914,   824, "&NotNestedGreaterGreater;");
+        html5References.addReference( 10916, "&glj;");
+        html5References.addReference( 10917, "&gla;");
+        html5References.addReference( 10918, "&ltcc;");
+        html5References.addReference( 10919, "&gtcc;");
+        html5References.addReference( 10920, "&lescc;");
+        html5References.addReference( 10921, "&gescc;");
+        html5References.addReference( 10922, "&smt;");
+        html5References.addReference( 10923, "&lat;");
+        html5References.addReference( 10924, "&smte;");
+        html5References.addReference( 10924, 65024, "&smtes;");
+        html5References.addReference( 10925, "&late;");
+        html5References.addReference( 10925, 65024, "&lates;");
+        html5References.addReference( 10926, "&bumpE;");
+        html5References.addReference( 10927, "&pre;");
+        html5References.addReference( 10927, "&preceq;");
+        html5References.addReference( 10927, "&PrecedesEqual;");
+        html5References.addReference( 10927,   824, "&npre;");
+        html5References.addReference( 10927,   824, "&npreceq;");
+        html5References.addReference( 10927,   824, "&NotPrecedesEqual;");
+        html5References.addReference( 10928, "&sce;");
+        html5References.addReference( 10928, "&succeq;");
+        html5References.addReference( 10928, "&SucceedsEqual;");
+        html5References.addReference( 10928,   824, "&nsce;");
+        html5References.addReference( 10928,   824, "&nsucceq;");
+        html5References.addReference( 10928,   824, "&NotSucceedsEqual;");
+        html5References.addReference( 10931, "&prE;");
+        html5References.addReference( 10932, "&scE;");
+        html5References.addReference( 10933, "&precneqq;");
+        html5References.addReference( 10933, "&prnE;");
+        html5References.addReference( 10934, "&scnE;");
+        html5References.addReference( 10934, "&succneqq;");
+        html5References.addReference( 10935, "&prap;");
+        html5References.addReference( 10935, "&precapprox;");
+        html5References.addReference( 10936, "&scap;");
+        html5References.addReference( 10936, "&succapprox;");
+        html5References.addReference( 10937, "&precnapprox;");
+        html5References.addReference( 10937, "&prnap;");
+        html5References.addReference( 10938, "&scnap;");
+        html5References.addReference( 10938, "&succnapprox;");
+        html5References.addReference( 10939, "&Pr;");
+        html5References.addReference( 10940, "&Sc;");
+        html5References.addReference( 10941, "&subdot;");
+        html5References.addReference( 10942, "&supdot;");
+        html5References.addReference( 10943, "&subplus;");
+        html5References.addReference( 10944, "&supplus;");
+        html5References.addReference( 10945, "&submult;");
+        html5References.addReference( 10946, "&supmult;");
+        html5References.addReference( 10947, "&subedot;");
+        html5References.addReference( 10948, "&supedot;");
+        html5References.addReference( 10949, "&subE;");
+        html5References.addReference( 10949, "&subseteqq;");
+        html5References.addReference( 10949,   824, "&nsubE;");
+        html5References.addReference( 10949,   824, "&nsubseteqq;");
+        html5References.addReference( 10950, "&supE;");
+        html5References.addReference( 10950, "&supseteqq;");
+        html5References.addReference( 10950,   824, "&nsupE;");
+        html5References.addReference( 10950,   824, "&nsupseteqq;");
+        html5References.addReference( 10951, "&subsim;");
+        html5References.addReference( 10952, "&supsim;");
+        html5References.addReference( 10955, "&subnE;");
+        html5References.addReference( 10955, "&subsetneqq;");
+        html5References.addReference( 10955, 65024, "&varsubsetneqq;");
+        html5References.addReference( 10955, 65024, "&vsubnE;");
+        html5References.addReference( 10956, "&supnE;");
+        html5References.addReference( 10956, "&supsetneqq;");
+        html5References.addReference( 10956, 65024, "&varsupsetneqq;");
+        html5References.addReference( 10956, 65024, "&vsupnE;");
+        html5References.addReference( 10959, "&csub;");
+        html5References.addReference( 10960, "&csup;");
+        html5References.addReference( 10961, "&csube;");
+        html5References.addReference( 10962, "&csupe;");
+        html5References.addReference( 10963, "&subsup;");
+        html5References.addReference( 10964, "&supsub;");
+        html5References.addReference( 10965, "&subsub;");
+        html5References.addReference( 10966, "&supsup;");
+        html5References.addReference( 10967, "&suphsub;");
+        html5References.addReference( 10968, "&supdsub;");
+        html5References.addReference( 10969, "&forkv;");
+        html5References.addReference( 10970, "&topfork;");
+        html5References.addReference( 10971, "&mlcp;");
+        html5References.addReference( 10980, "&Dashv;");
+        html5References.addReference( 10980, "&DoubleLeftTee;");
+        html5References.addReference( 10982, "&Vdashl;");
+        html5References.addReference( 10983, "&Barv;");
+        html5References.addReference( 10984, "&vBar;");
+        html5References.addReference( 10985, "&vBarv;");
+        html5References.addReference( 10987, "&Vbar;");
+        html5References.addReference( 10988, "&Not;");
+        html5References.addReference( 10989, "&bNot;");
+        html5References.addReference( 10990, "&rnmid;");
+        html5References.addReference( 10991, "&cirmid;");
+        html5References.addReference( 10992, "&midcir;");
+        html5References.addReference( 10993, "&topcir;");
+        html5References.addReference( 10994, "&nhpar;");
+        html5References.addReference( 10995, "&parsim;");
+        html5References.addReference( 11005, "&parsl;");
+        html5References.addReference( 11005,  8421, "&nparsl;");
+        html5References.addReference( 64256, "&fflig;");
+        html5References.addReference( 64257, "&filig;");
+        html5References.addReference( 64258, "&fllig;");
+        html5References.addReference( 64259, "&ffilig;");
+        html5References.addReference( 64260, "&ffllig;");
+        html5References.addReference(119964, "&Ascr;");
+        html5References.addReference(119966, "&Cscr;");
+        html5References.addReference(119967, "&Dscr;");
+        html5References.addReference(119970, "&Gscr;");
+        html5References.addReference(119973, "&Jscr;");
+        html5References.addReference(119974, "&Kscr;");
+        html5References.addReference(119977, "&Nscr;");
+        html5References.addReference(119978, "&Oscr;");
+        html5References.addReference(119979, "&Pscr;");
+        html5References.addReference(119980, "&Qscr;");
+        html5References.addReference(119982, "&Sscr;");
+        html5References.addReference(119983, "&Tscr;");
+        html5References.addReference(119984, "&Uscr;");
+        html5References.addReference(119985, "&Vscr;");
+        html5References.addReference(119986, "&Wscr;");
+        html5References.addReference(119987, "&Xscr;");
+        html5References.addReference(119988, "&Yscr;");
+        html5References.addReference(119989, "&Zscr;");
+        html5References.addReference(119990, "&ascr;");
+        html5References.addReference(119991, "&bscr;");
+        html5References.addReference(119992, "&cscr;");
+        html5References.addReference(119993, "&dscr;");
+        html5References.addReference(119995, "&fscr;");
+        html5References.addReference(119997, "&hscr;");
+        html5References.addReference(119998, "&iscr;");
+        html5References.addReference(119999, "&jscr;");
+        html5References.addReference(120000, "&kscr;");
+        html5References.addReference(120001, "&lscr;");
+        html5References.addReference(120002, "&mscr;");
+        html5References.addReference(120003, "&nscr;");
+        html5References.addReference(120005, "&pscr;");
+        html5References.addReference(120006, "&qscr;");
+        html5References.addReference(120007, "&rscr;");
+        html5References.addReference(120008, "&sscr;");
+        html5References.addReference(120009, "&tscr;");
+        html5References.addReference(120010, "&uscr;");
+        html5References.addReference(120011, "&vscr;");
+        html5References.addReference(120012, "&wscr;");
+        html5References.addReference(120013, "&xscr;");
+        html5References.addReference(120014, "&yscr;");
+        html5References.addReference(120015, "&zscr;");
+        html5References.addReference(120068, "&Afr;");
+        html5References.addReference(120069, "&Bfr;");
+        html5References.addReference(120071, "&Dfr;");
+        html5References.addReference(120072, "&Efr;");
+        html5References.addReference(120073, "&Ffr;");
+        html5References.addReference(120074, "&Gfr;");
+        html5References.addReference(120077, "&Jfr;");
+        html5References.addReference(120078, "&Kfr;");
+        html5References.addReference(120079, "&Lfr;");
+        html5References.addReference(120080, "&Mfr;");
+        html5References.addReference(120081, "&Nfr;");
+        html5References.addReference(120082, "&Ofr;");
+        html5References.addReference(120083, "&Pfr;");
+        html5References.addReference(120084, "&Qfr;");
+        html5References.addReference(120086, "&Sfr;");
+        html5References.addReference(120087, "&Tfr;");
+        html5References.addReference(120088, "&Ufr;");
+        html5References.addReference(120089, "&Vfr;");
+        html5References.addReference(120090, "&Wfr;");
+        html5References.addReference(120091, "&Xfr;");
+        html5References.addReference(120092, "&Yfr;");
+        html5References.addReference(120094, "&afr;");
+        html5References.addReference(120095, "&bfr;");
+        html5References.addReference(120096, "&cfr;");
+        html5References.addReference(120097, "&dfr;");
+        html5References.addReference(120098, "&efr;");
+        html5References.addReference(120099, "&ffr;");
+        html5References.addReference(120100, "&gfr;");
+        html5References.addReference(120101, "&hfr;");
+        html5References.addReference(120102, "&ifr;");
+        html5References.addReference(120103, "&jfr;");
+        html5References.addReference(120104, "&kfr;");
+        html5References.addReference(120105, "&lfr;");
+        html5References.addReference(120106, "&mfr;");
+        html5References.addReference(120107, "&nfr;");
+        html5References.addReference(120108, "&ofr;");
+        html5References.addReference(120109, "&pfr;");
+        html5References.addReference(120110, "&qfr;");
+        html5References.addReference(120111, "&rfr;");
+        html5References.addReference(120112, "&sfr;");
+        html5References.addReference(120113, "&tfr;");
+        html5References.addReference(120114, "&ufr;");
+        html5References.addReference(120115, "&vfr;");
+        html5References.addReference(120116, "&wfr;");
+        html5References.addReference(120117, "&xfr;");
+        html5References.addReference(120118, "&yfr;");
+        html5References.addReference(120119, "&zfr;");
+        html5References.addReference(120120, "&Aopf;");
+        html5References.addReference(120121, "&Bopf;");
+        html5References.addReference(120123, "&Dopf;");
+        html5References.addReference(120124, "&Eopf;");
+        html5References.addReference(120125, "&Fopf;");
+        html5References.addReference(120126, "&Gopf;");
+        html5References.addReference(120128, "&Iopf;");
+        html5References.addReference(120129, "&Jopf;");
+        html5References.addReference(120130, "&Kopf;");
+        html5References.addReference(120131, "&Lopf;");
+        html5References.addReference(120132, "&Mopf;");
+        html5References.addReference(120134, "&Oopf;");
+        html5References.addReference(120138, "&Sopf;");
+        html5References.addReference(120139, "&Topf;");
+        html5References.addReference(120140, "&Uopf;");
+        html5References.addReference(120141, "&Vopf;");
+        html5References.addReference(120142, "&Wopf;");
+        html5References.addReference(120143, "&Xopf;");
+        html5References.addReference(120144, "&Yopf;");
+        html5References.addReference(120146, "&aopf;");
+        html5References.addReference(120147, "&bopf;");
+        html5References.addReference(120148, "&copf;");
+        html5References.addReference(120149, "&dopf;");
+        html5References.addReference(120150, "&eopf;");
+        html5References.addReference(120151, "&fopf;");
+        html5References.addReference(120152, "&gopf;");
+        html5References.addReference(120153, "&hopf;");
+        html5References.addReference(120154, "&iopf;");
+        html5References.addReference(120155, "&jopf;");
+        html5References.addReference(120156, "&kopf;");
+        html5References.addReference(120157, "&lopf;");
+        html5References.addReference(120158, "&mopf;");
+        html5References.addReference(120159, "&nopf;");
+        html5References.addReference(120160, "&oopf;");
+        html5References.addReference(120161, "&popf;");
+        html5References.addReference(120162, "&qopf;");
+        html5References.addReference(120163, "&ropf;");
+        html5References.addReference(120164, "&sopf;");
+        html5References.addReference(120165, "&topf;");
+        html5References.addReference(120166, "&uopf;");
+        html5References.addReference(120167, "&vopf;");
+        html5References.addReference(120168, "&wopf;");
+        html5References.addReference(120169, "&xopf;");
+        html5References.addReference(120170, "&yopf;");
+        html5References.addReference(120171, "&zopf;");
+
+        /*
+         * Initialization of escape levels.
+         * Defined levels :
+         *
+         *    - Level 0 : Only markup-significant characters except the apostrophe (')
+         *    - Level 1 : Only markup-significant characters (including the apostrophe)
+         *    - Level 2 : Markup-significant characters plus all non-ASCII
+         *    - Level 3 : All non-alphanumeric characters
+         *    - Level 4 : All characters
+         */
+        final byte[] escapeLevels = new byte[0x7f + 2];
+        Arrays.fill(escapeLevels, (byte)3);
+        for (char c = 'A'; c <= 'Z'; c++) {
+            escapeLevels[c] = 4;
+        }
+        for (char c = 'a'; c <= 'z'; c++) {
+            escapeLevels[c] = 4;
+        }
+        for (char c = '0'; c <= '9'; c++) {
+            escapeLevels[c] = 4;
+        }
+        escapeLevels['\''] = 1;
+        escapeLevels['"'] = 0;
+        escapeLevels['<'] = 0;
+        escapeLevels['>'] = 0;
+        escapeLevels['&'] = 0;
+        escapeLevels[0x7f + 1] = 2;
+
+
+        return new HtmlEscapeSymbols(html5References, escapeLevels);
+
+    }
+
+
+
+    private Html5EscapeSymbolsInitializer() {
+        super();
+    }
+
+}
+
diff --git a/app/src/main/java/ohi/andre/consolelauncher/tuils/html_escape/HtmlEscape.java b/app/src/main/java/ohi/andre/consolelauncher/tuils/html_escape/HtmlEscape.java
new file mode 100755
index 0000000..7d1cd8c
--- /dev/null
+++ b/app/src/main/java/ohi/andre/consolelauncher/tuils/html_escape/HtmlEscape.java
@@ -0,0 +1,1283 @@
+/*
+ * =============================================================================
+ * 
+ *   Copyright (c) 2014-2017, The UNBESCAPE team (http://www.unbescape.org)
+ * 
+ *   Licensed under the Apache License, Version 2.0 (the "License");
+ *   you may not use this file except in compliance with the License.
+ *   You may obtain a copy of the License at
+ * 
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ *   Unless required by applicable law or agreed to in writing, software
+ *   distributed under the License is distributed on an "AS IS" BASIS,
+ *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *   See the License for the specific language governing permissions and
+ *   limitations under the License.
+ * 
+ * =============================================================================
+ */
+package ohi.andre.consolelauncher.tuils.html_escape;
+
+import java.io.IOException;
+import java.io.Reader;
+import java.io.Writer;
+
+/**
+ * <p>
+ *   Utility class for performing HTML escape/unescape operations.
+ * </p>
+ *
+ * <strong><u>Configuration of escape/unescape operations</u></strong>
+ *
+ * <p>
+ *   <strong>Escape</strong> operations can be (optionally) configured by means of:
+ * </p>
+ * <ul>
+ *   <li><em>Level</em>, which defines how deep the escape operation must be (what
+ *       chars are to be considered eligible for escaping, depending on the specific
+ *       needs of the scenario). Its values are defined by the {@link org.unbescape.html.HtmlEscapeLevel}
+ *       enum.</li>
+ *   <li><em>Type</em>, which defines whether escaping should be performed by means of NCRs
+ *       (Named Character References), by means of decimal/hexadecimal numerical references,
+ *       using the HTML5 or the HTML 4 NCR set, etc. Its values are defined by the
+ *       {@link org.unbescape.html.HtmlEscapeType} enum.</li>
+ * </ul>
+ * <p>
+ *   <strong>Unescape</strong> operations need no configuration parameters. Unescape operations
+ *   will always perform <em>complete</em> unescape of NCRs (whole HTML5 set supported), decimal
+ *   and hexadecimal references.
+ * </p>
+ *
+ * <strong><u>Features</u></strong>
+ *
+ * <p>
+ *   Specific features of the HTML escape/unescape operations performed by means of this class:
+ * </p>
+ * <ul>
+ *   <li>Whole HTML5 NCR (Named Character Reference) set supported, if required:
+ *       <tt>&amp;rsqb;</tt>,<tt>&amp;NewLine;</tt>, etc. (HTML 4 set available too).</li>
+ *   <li>Mixed named and numerical (decimal or hexa) character references supported.</li>
+ *   <li>Ability to default to numerical (decimal or hexa) references when an applicable NCR does not exist
+ *       (depending on the selected operation <em>level</em>).</li>
+ *   <li>Support for the whole Unicode character set: <tt>&#92;u0000</tt> to <tt>&#92;u10FFFF</tt>, including
+ *       characters not representable by only one <tt>char</tt> in Java (<tt>&gt;&#92;uFFFF</tt>).</li>
+ *   <li>Support for unescape of double-char NCRs in HTML5: <tt>'&amp;fjlig;'</tt> &rarr; <tt>'fj'</tt>.</li>
+ *   <li>Support for a set of HTML5 unescape <em>tweaks</em> included in the HTML5 specification:
+ *       <ul>
+ *         <li>Unescape of numerical character references not ending in semi-colon
+ *             (e.g. <tt>'&amp;#x23ac'</tt>).</li>
+ *         <li>Unescape of specific NCRs not ending in semi-colon (e.g. <tt>'&amp;aacute'</tt>).</li>
+ *         <li>Unescape of specific numerical character references wrongly specified by their Windows-1252
+ *             codepage code instead of the Unicode one (e.g. <tt>'&amp;#x80;'</tt> for '&euro;'
+ *             (<tt>'&amp;euro;'</tt>) instead of <tt>'&amp;#x20ac;'</tt>).</li>
+ *       </ul>
+ *   </li>
+ * </ul>
+ *
+ * <strong><u>Input/Output</u></strong>
+ *
+ * <p>
+ *   There are four different input/output modes that can be used in escape/unescape operations:
+ * </p>
+ * <ul>
+ *   <li><em><tt>String</tt> input, <tt>String</tt> output</em>: Input is specified as a <tt>String</tt> object
+ *       and output is returned as another. In order to improve memory performance, all escape and unescape
+ *       operations <u>will return the exact same input object as output if no escape/unescape modifications
+ *       are required</u>.</li>
+ *   <li><em><tt>String</tt> input, <tt>java.io.Writer</tt> output</em>: Input will be read from a String
+ *       and output will be written into the specified <tt>java.io.Writer</tt>.</li>
+ *   <li><em><tt>java.io.Reader</tt> input, <tt>java.io.Writer</tt> output</em>: Input will be read from a Reader
+ *       and output will be written into the specified <tt>java.io.Writer</tt>.</li>
+ *   <li><em><tt>char[]</tt> input, <tt>java.io.Writer</tt> output</em>: Input will be read from a char array
+ *       (<tt>char[]</tt>) and output will be written into the specified <tt>java.io.Writer</tt>.
+ *       Two <tt>int</tt> arguments called <tt>offset</tt> and <tt>len</tt> will be
+ *       used for specifying the part of the <tt>char[]</tt> that should be escaped/unescaped. These methods
+ *       should be called with <tt>offset = 0</tt> and <tt>len = text.length</tt> in order to process
+ *       the whole <tt>char[]</tt>.</li>
+ * </ul>
+ *
+ * <strong><u>Glossary</u></strong>
+ *
+ * <dl>
+ *   <dt>NCR</dt>
+ *     <dd>Named Character Reference or <em>Character Entity Reference</em>: textual
+ *         representation of an Unicode codepoint: <tt>&amp;aacute;</tt></dd>
+ *   <dt>DCR</dt>
+ *     <dd>Decimal Character Reference: base-10 numerical representation of an Unicode codepoint:
+ *         <tt>&amp;#225;</tt></dd>
+ *   <dt>HCR</dt>
+ *     <dd>Hexadecimal Character Reference: hexadecimal numerical representation of an Unicode codepoint:
+ *         <tt>&amp;#xE1;</tt></dd>
+ *   <dt>Unicode Codepoint</dt>
+ *     <dd>Each of the <tt>int</tt> values conforming the Unicode code space.
+ *         Normally corresponding to a Java <tt>char</tt> primitive value (codepoint &lt;= <tt>&#92;uFFFF</tt>),
+ *         but might be two <tt>char</tt>s for codepoints <tt>&#92;u10000</tt> to <tt>&#92;u10FFFF</tt> if the
+ *         first <tt>char</tt> is a high surrogate (<tt>&#92;uD800</tt> to <tt>&#92;uDBFF</tt>) and the
+ *         second is a low surrogate (<tt>&#92;uDC00</tt> to <tt>&#92;uDFFF</tt>).</dd>
+ * </dl>
+ *
+ * <strong><u>References</u></strong>
+ *
+ * <p>
+ *   The following references apply:
+ * </p>
+ * <ul>
+ *   <li><a href="http://www.w3.org/International/questions/qa-escapes" target="_blank">Using character escapes in
+ *       markup and CSS</a> [w3.org]</li>
+ *   <li><a href="http://www.w3.org/TR/html4/sgml/entities.html" target="_blank">Named Character References (or
+ *       <em>Character entity references</em>) in HTML 4</a> [w3.org]</li>
+ *   <li><a href="http://www.w3.org/TR/html5/syntax.html#named-character-references" target="_blank">Named Character
+ *       References (or <em>Character entity references</em>) in HTML5</a> [w3.org]</li>
+ *   <li><a href="http://www.w3.org/TR/html51/syntax.html#named-character-references" target="_blank">Named Character
+ *       References (or <em>Character entity references</em>) in HTML 5.1</a> [w3.org]</li>
+ *   <li><a href="http://www.w3.org/TR/html5/syntax.html#consume-a-character-reference" target="_blank">How to consume a
+ *       character reference (HTML5 specification)</a> [w3.org]</li>
+ *   <li><a href="https://www.owasp.org/index.php/XSS_(Cross_Site_Scripting)_Prevention_Cheat_Sheet"
+ *       target="_blank">OWASP XSS (Cross Site Scripting) Prevention Cheat Sheet</a> [owasp.org]</li>
+ *   <li><a href="http://www.oracle.com/technetwork/articles/javase/supplementary-142654.html"
+ *       target="_blank">Supplementary characters in the Java Platform</a> [oracle.com]</li>
+ * </ul>
+ *
+ *
+ * @author Daniel Fern&aacute;ndez
+ * 
+ * @since 1.0.0
+ *
+ */
+public final class HtmlEscape {
+
+
+
+
+    /**
+     * <p>
+     *   Perform an HTML5 level 2 (result is ASCII) <strong>escape</strong> operation on a <tt>String</tt> input.
+     * </p>
+     * <p>
+     *   <em>Level 2</em> means this method will escape:
+     * </p>
+     * <ul>
+     *   <li>The five markup-significant characters: <tt>&lt;</tt>, <tt>&gt;</tt>, <tt>&amp;</tt>,
+     *       <tt>&quot;</tt> and <tt>&#39;</tt></li>
+     *   <li>All non ASCII characters.</li>
+     * </ul>
+     * <p>
+     *   This escape will be performed by replacing those chars by the corresponding HTML5 Named Character References
+     *   (e.g. <tt>'&amp;acute;'</tt>) when such NCR exists for the replaced character, and replacing by a decimal
+     *   character reference (e.g. <tt>'&amp;#8345;'</tt>) when there there is no NCR for the replaced character.
+     * </p>
+     * <p>
+     *   This method calls {@link #escapeHtml(String, HtmlEscapeType, HtmlEscapeLevel)} with the following
+     *   preconfigured values:
+     * </p>
+     * <ul>
+     *   <li><tt>type</tt>:
+     *       {@link org.unbescape.html.HtmlEscapeType#HTML5_NAMED_REFERENCES_DEFAULT_TO_DECIMAL}</li>
+     *   <li><tt>level</tt>:
+     *       {@link org.unbescape.html.HtmlEscapeLevel#LEVEL_2_ALL_NON_ASCII_PLUS_MARKUP_SIGNIFICANT}</li>
+     * </ul>
+     * <p>
+     *   This method is <strong>thread-safe</strong>.
+     * </p>
+     *
+     * @param text the <tt>String</tt> to be escaped.
+     * @return The escaped result <tt>String</tt>. As a memory-performance improvement, will return the exact
+     *         same object as the <tt>text</tt> input argument if no escaping modifications were required (and
+     *         no additional <tt>String</tt> objects will be created during processing). Will
+     *         return <tt>null</tt> if input is <tt>null</tt>.
+     */
+    public static String escapeHtml5(final String text) {
+        return escapeHtml(text, HtmlEscapeType.HTML5_NAMED_REFERENCES_DEFAULT_TO_DECIMAL,
+                HtmlEscapeLevel.LEVEL_2_ALL_NON_ASCII_PLUS_MARKUP_SIGNIFICANT);
+    }
+
+
+    /**
+     * <p>
+     *   Perform an HTML5 level 1 (XML-style) <strong>escape</strong> operation on a <tt>String</tt> input.
+     * </p>
+     * <p>
+     *   <em>Level 1</em> means this method will only escape the five markup-significant characters:
+     *   <tt>&lt;</tt>, <tt>&gt;</tt>, <tt>&amp;</tt>, <tt>&quot;</tt> and <tt>&#39;</tt>. It is called
+     *   <em>XML-style</em> in order to link it with JSP's <tt>escapeXml</tt> attribute in JSTL's
+     *   <tt>&lt;c:out ... /&gt;</tt> tags.
+     * </p>
+     * <p>
+     *  Note this method may <strong>not</strong> produce the same results as {@link #escapeHtml4Xml(String)} because
+     *  it will escape the apostrophe as <tt>&amp;apos;</tt>, whereas in HTML 4 such NCR does not exist
+     *  (the decimal numeric reference <tt>&amp;#39;</tt> is used instead).
+     * </p>
+     * <p>
+     *   This method calls {@link #escapeHtml(String, HtmlEscapeType, HtmlEscapeLevel)} with the following
+     *   preconfigured values:
+     * </p>
+     * <ul>
+     *   <li><tt>type</tt>:
+     *       {@link org.unbescape.html.HtmlEscapeType#HTML5_NAMED_REFERENCES_DEFAULT_TO_DECIMAL}</li>
+     *   <li><tt>level</tt>:
+     *       {@link org.unbescape.html.HtmlEscapeLevel#LEVEL_1_ONLY_MARKUP_SIGNIFICANT}</li>
+     * </ul>
+     * <p>
+     *   This method is <strong>thread-safe</strong>.
+     * </p>
+     *
+     * @param text the <tt>String</tt> to be escaped.
+     * @return The escaped result <tt>String</tt>. As a memory-performance improvement, will return the exact
+     *         same object as the <tt>text</tt> input argument if no escaping modifications were required (and
+     *         no additional <tt>String</tt> objects will be created during processing). Will
+     *         return <tt>null</tt> if input is <tt>null</tt>.
+     */
+    public static String escapeHtml5Xml(final String text) {
+        return escapeHtml(text, HtmlEscapeType.HTML5_NAMED_REFERENCES_DEFAULT_TO_DECIMAL,
+                HtmlEscapeLevel.LEVEL_1_ONLY_MARKUP_SIGNIFICANT);
+    }
+
+
+    /**
+     * <p>
+     *   Perform an HTML 4 level 2 (result is ASCII) <strong>escape</strong> operation on a <tt>String</tt> input.
+     * </p>
+     * <p>
+     *   <em>Level 2</em> means this method will escape:
+     * </p>
+     * <ul>
+     *   <li>The five markup-significant characters: <tt>&lt;</tt>, <tt>&gt;</tt>, <tt>&amp;</tt>,
+     *       <tt>&quot;</tt> and <tt>&#39;</tt></li>
+     *   <li>All non ASCII characters.</li>
+     * </ul>
+     * <p>
+     *   This escape will be performed by replacing those chars by the corresponding HTML 4 Named Character References
+     *   (e.g. <tt>'&amp;acute;'</tt>) when such NCR exists for the replaced character, and replacing by a decimal
+     *   character reference (e.g. <tt>'&amp;#8345;'</tt>) when there there is no NCR for the replaced character.
+     * </p>
+     * <p>
+     *   This method calls {@link #escapeHtml(String, HtmlEscapeType, HtmlEscapeLevel)} with the following
+     *   preconfigured values:
+     * </p>
+     * <ul>
+     *   <li><tt>type</tt>:
+     *       {@link org.unbescape.html.HtmlEscapeType#HTML4_NAMED_REFERENCES_DEFAULT_TO_DECIMAL}</li>
+     *   <li><tt>level</tt>:
+     *       {@link org.unbescape.html.HtmlEscapeLevel#LEVEL_2_ALL_NON_ASCII_PLUS_MARKUP_SIGNIFICANT}</li>
+     * </ul>
+     * <p>
+     *   This method is <strong>thread-safe</strong>.
+     * </p>
+     *
+     * @param text the <tt>String</tt> to be escaped.
+     * @return The escaped result <tt>String</tt>. As a memory-performance improvement, will return the exact
+     *         same object as the <tt>text</tt> input argument if no escaping modifications were required (and
+     *         no additional <tt>String</tt> objects will be created during processing). Will
+     *         return <tt>null</tt> if input is <tt>null</tt>.
+     */
+    public static String escapeHtml4(final String text) {
+        return escapeHtml(text, HtmlEscapeType.HTML4_NAMED_REFERENCES_DEFAULT_TO_DECIMAL,
+                HtmlEscapeLevel.LEVEL_2_ALL_NON_ASCII_PLUS_MARKUP_SIGNIFICANT);
+    }
+
+
+    /**
+     * <p>
+     *   Perform an HTML 4 level 1 (XML-style) <strong>escape</strong> operation on a <tt>String</tt> input.
+     * </p>
+     * <p>
+     *   <em>Level 1</em> means this method will only escape the five markup-significant characters:
+     *   <tt>&lt;</tt>, <tt>&gt;</tt>, <tt>&amp;</tt>, <tt>&quot;</tt> and <tt>&#39;</tt>. It is called
+     *   <em>XML-style</em> in order to link it with JSP's <tt>escapeXml</tt> attribute in JSTL's
+     *   <tt>&lt;c:out ... /&gt;</tt> tags.
+     * </p>
+     * <p>
+     *  Note this method may <strong>not</strong> produce the same results as {@link #escapeHtml5Xml(String)} because
+     *  it will escape the apostrophe as <tt>&amp;#39;</tt>, whereas in HTML5 there is a specific NCR for
+     *  such character (<tt>&amp;apos;</tt>).
+     * </p>
+     * <p>
+     *   This method calls {@link #escapeHtml(String, HtmlEscapeType, HtmlEscapeLevel)} with the following
+     *   preconfigured values:
+     * </p>
+     * <ul>
+     *   <li><tt>type</tt>:
+     *       {@link org.unbescape.html.HtmlEscapeType#HTML4_NAMED_REFERENCES_DEFAULT_TO_DECIMAL}</li>
+     *   <li><tt>level</tt>:
+     *       {@link org.unbescape.html.HtmlEscapeLevel#LEVEL_1_ONLY_MARKUP_SIGNIFICANT}</li>
+     * </ul>
+     * <p>
+     *   This method is <strong>thread-safe</strong>.
+     * </p>
+     *
+     * @param text the <tt>String</tt> to be escaped.
+     * @return The escaped result <tt>String</tt>. As a memory-performance improvement, will return the exact
+     *         same object as the <tt>text</tt> input argument if no escaping modifications were required (and
+     *         no additional <tt>String</tt> objects will be created during processing). Will
+     *         return <tt>null</tt> if input is <tt>null</tt>.
+     */
+    public static String escapeHtml4Xml(final String text) {
+        return escapeHtml(text, HtmlEscapeType.HTML4_NAMED_REFERENCES_DEFAULT_TO_DECIMAL,
+                HtmlEscapeLevel.LEVEL_1_ONLY_MARKUP_SIGNIFICANT);
+    }
+
+
+    /**
+     * <p>
+     *   Perform a (configurable) HTML <strong>escape</strong> operation on a <tt>String</tt> input.
+     * </p>
+     * <p>
+     *   This method will perform an escape operation according to the specified
+     *   {@link org.unbescape.html.HtmlEscapeType} and {@link org.unbescape.html.HtmlEscapeLevel}
+     *   argument values.
+     * </p>
+     * <p>
+     *   All other <tt>String</tt>-based <tt>escapeHtml*(...)</tt> methods call this one with preconfigured
+     *   <tt>type</tt> and <tt>level</tt> values.
+     * </p>
+     * <p>
+     *   This method is <strong>thread-safe</strong>.
+     * </p>
+     *
+     * @param text the <tt>String</tt> to be escaped.
+     * @param type the type of escape operation to be performed, see {@link org.unbescape.html.HtmlEscapeType}.
+     * @param level the escape level to be applied, see {@link org.unbescape.html.HtmlEscapeLevel}.
+     * @return The escaped result <tt>String</tt>. As a memory-performance improvement, will return the exact
+     *         same object as the <tt>text</tt> input argument if no escaping modifications were required (and
+     *         no additional <tt>String</tt> objects will be created during processing). Will
+     *         return <tt>null</tt> if input is <tt>null</tt>.
+     */
+    public static String escapeHtml(final String text, final HtmlEscapeType type, final HtmlEscapeLevel level) {
+
+        if (type == null) {
+            throw new IllegalArgumentException("The 'type' argument cannot be null");
+        }
+
+        if (level == null) {
+            throw new IllegalArgumentException("The 'level' argument cannot be null");
+        }
+
+        return HtmlEscapeUtil.escape(text, type, level);
+
+    }
+
+
+
+
+
+
+
+    /**
+     * <p>
+     *   Perform an HTML5 level 2 (result is ASCII) <strong>escape</strong> operation on a <tt>String</tt> input,
+     *   writing results to a <tt>Writer</tt>.
+     * </p>
+     * <p>
+     *   <em>Level 2</em> means this method will escape:
+     * </p>
+     * <ul>
+     *   <li>The five markup-significant characters: <tt>&lt;</tt>, <tt>&gt;</tt>, <tt>&amp;</tt>,
+     *       <tt>&quot;</tt> and <tt>&#39;</tt></li>
+     *   <li>All non ASCII characters.</li>
+     * </ul>
+     * <p>
+     *   This escape will be performed by replacing those chars by the corresponding HTML5 Named Character References
+     *   (e.g. <tt>'&amp;acute;'</tt>) when such NCR exists for the replaced character, and replacing by a decimal
+     *   character reference (e.g. <tt>'&amp;#8345;'</tt>) when there there is no NCR for the replaced character.
+     * </p>
+     * <p>
+     *   This method calls {@link #escapeHtml(String, Writer, HtmlEscapeType, HtmlEscapeLevel)} with the following
+     *   preconfigured values:
+     * </p>
+     * <ul>
+     *   <li><tt>type</tt>:
+     *       {@link org.unbescape.html.HtmlEscapeType#HTML5_NAMED_REFERENCES_DEFAULT_TO_DECIMAL}</li>
+     *   <li><tt>level</tt>:
+     *       {@link org.unbescape.html.HtmlEscapeLevel#LEVEL_2_ALL_NON_ASCII_PLUS_MARKUP_SIGNIFICANT}</li>
+     * </ul>
+     * <p>
+     *   This method is <strong>thread-safe</strong>.
+     * </p>
+     *
+     * @param text the <tt>String</tt> to be escaped.
+     * @param writer the <tt>java.io.Writer</tt> to which the escaped result will be written. Nothing will
+     *               be written at all to this writer if input is <tt>null</tt>.
+     * @throws IOException if an input/output exception occurs
+     *
+     * @since 1.1.2
+     */
+    public static void escapeHtml5(final String text, final Writer writer)
+            throws IOException {
+        escapeHtml(text, writer, HtmlEscapeType.HTML5_NAMED_REFERENCES_DEFAULT_TO_DECIMAL,
+                HtmlEscapeLevel.LEVEL_2_ALL_NON_ASCII_PLUS_MARKUP_SIGNIFICANT);
+    }
+
+
+    /**
+     * <p>
+     *   Perform an HTML5 level 1 (XML-style) <strong>escape</strong> operation on a <tt>String</tt> input,
+     *   writing results to a <tt>Writer</tt>.
+     * </p>
+     * <p>
+     *   <em>Level 1</em> means this method will only escape the five markup-significant characters:
+     *   <tt>&lt;</tt>, <tt>&gt;</tt>, <tt>&amp;</tt>, <tt>&quot;</tt> and <tt>&#39;</tt>. It is called
+     *   <em>XML-style</em> in order to link it with JSP's <tt>escapeXml</tt> attribute in JSTL's
+     *   <tt>&lt;c:out ... /&gt;</tt> tags.
+     * </p>
+     * <p>
+     *  Note this method may <strong>not</strong> produce the same results as {@link #escapeHtml4Xml(String, Writer)} because
+     *  it will escape the apostrophe as <tt>&amp;apos;</tt>, whereas in HTML 4 such NCR does not exist
+     *  (the decimal numeric reference <tt>&amp;#39;</tt> is used instead).
+     * </p>
+     * <p>
+     *   This method calls {@link #escapeHtml(String, Writer, HtmlEscapeType, HtmlEscapeLevel)} with the following
+     *   preconfigured values:
+     * </p>
+     * <ul>
+     *   <li><tt>type</tt>:
+     *       {@link org.unbescape.html.HtmlEscapeType#HTML5_NAMED_REFERENCES_DEFAULT_TO_DECIMAL}</li>
+     *   <li><tt>level</tt>:
+     *       {@link org.unbescape.html.HtmlEscapeLevel#LEVEL_1_ONLY_MARKUP_SIGNIFICANT}</li>
+     * </ul>
+     * <p>
+     *   This method is <strong>thread-safe</strong>.
+     * </p>
+     *
+     * @param text the <tt>String</tt> to be escaped.
+     * @param writer the <tt>java.io.Writer</tt> to which the escaped result will be written. Nothing will
+     *               be written at all to this writer if input is <tt>null</tt>.
+     * @throws IOException if an input/output exception occurs
+     *
+     * @since 1.1.2
+     */
+    public static void escapeHtml5Xml(final String text, final Writer writer)
+            throws IOException {
+        escapeHtml(text, writer, HtmlEscapeType.HTML5_NAMED_REFERENCES_DEFAULT_TO_DECIMAL,
+                HtmlEscapeLevel.LEVEL_1_ONLY_MARKUP_SIGNIFICANT);
+    }
+
+
+    /**
+     * <p>
+     *   Perform an HTML 4 level 2 (result is ASCII) <strong>escape</strong> operation on a <tt>String</tt> input,
+     *   writing results to a <tt>Writer</tt>.
+     * </p>
+     * <p>
+     *   <em>Level 2</em> means this method will escape:
+     * </p>
+     * <ul>
+     *   <li>The five markup-significant characters: <tt>&lt;</tt>, <tt>&gt;</tt>, <tt>&amp;</tt>,
+     *       <tt>&quot;</tt> and <tt>&#39;</tt></li>
+     *   <li>All non ASCII characters.</li>
+     * </ul>
+     * <p>
+     *   This escape will be performed by replacing those chars by the corresponding HTML 4 Named Character References
+     *   (e.g. <tt>'&amp;acute;'</tt>) when such NCR exists for the replaced character, and replacing by a decimal
+     *   character reference (e.g. <tt>'&amp;#8345;'</tt>) when there there is no NCR for the replaced character.
+     * </p>
+     * <p>
+     *   This method calls {@link #escapeHtml(String, Writer, HtmlEscapeType, HtmlEscapeLevel)} with the following
+     *   preconfigured values:
+     * </p>
+     * <ul>
+     *   <li><tt>type</tt>:
+     *       {@link org.unbescape.html.HtmlEscapeType#HTML4_NAMED_REFERENCES_DEFAULT_TO_DECIMAL}</li>
+     *   <li><tt>level</tt>:
+     *       {@link org.unbescape.html.HtmlEscapeLevel#LEVEL_2_ALL_NON_ASCII_PLUS_MARKUP_SIGNIFICANT}</li>
+     * </ul>
+     * <p>
+     *   This method is <strong>thread-safe</strong>.
+     * </p>
+     *
+     * @param text the <tt>String</tt> to be escaped.
+     * @param writer the <tt>java.io.Writer</tt> to which the escaped result will be written. Nothing will
+     *               be written at all to this writer if input is <tt>null</tt>.
+     * @throws IOException if an input/output exception occurs
+     *
+     * @since 1.1.2
+     */
+    public static void escapeHtml4(final String text, final Writer writer)
+            throws IOException {
+        escapeHtml(text, writer, HtmlEscapeType.HTML4_NAMED_REFERENCES_DEFAULT_TO_DECIMAL,
+                HtmlEscapeLevel.LEVEL_2_ALL_NON_ASCII_PLUS_MARKUP_SIGNIFICANT);
+    }
+
+
+    /**
+     * <p>
+     *   Perform an HTML 4 level 1 (XML-style) <strong>escape</strong> operation on a <tt>String</tt> input,
+     *   writing results to a <tt>Writer</tt>.
+     * </p>
+     * <p>
+     *   <em>Level 1</em> means this method will only escape the five markup-significant characters:
+     *   <tt>&lt;</tt>, <tt>&gt;</tt>, <tt>&amp;</tt>, <tt>&quot;</tt> and <tt>&#39;</tt>. It is called
+     *   <em>XML-style</em> in order to link it with JSP's <tt>escapeXml</tt> attribute in JSTL's
+     *   <tt>&lt;c:out ... /&gt;</tt> tags.
+     * </p>
+     * <p>
+     *  Note this method may <strong>not</strong> produce the same results as {@link #escapeHtml5Xml(String, Writer)} because
+     *  it will escape the apostrophe as <tt>&amp;#39;</tt>, whereas in HTML5 there is a specific NCR for
+     *  such character (<tt>&amp;apos;</tt>).
+     * </p>
+     * <p>
+     *   This method calls {@link #escapeHtml(String, Writer, HtmlEscapeType, HtmlEscapeLevel)} with the following
+     *   preconfigured values:
+     * </p>
+     * <ul>
+     *   <li><tt>type</tt>:
+     *       {@link org.unbescape.html.HtmlEscapeType#HTML4_NAMED_REFERENCES_DEFAULT_TO_DECIMAL}</li>
+     *   <li><tt>level</tt>:
+     *       {@link org.unbescape.html.HtmlEscapeLevel#LEVEL_1_ONLY_MARKUP_SIGNIFICANT}</li>
+     * </ul>
+     * <p>
+     *   This method is <strong>thread-safe</strong>.
+     * </p>
+     *
+     * @param text the <tt>String</tt> to be escaped.
+     * @param writer the <tt>java.io.Writer</tt> to which the escaped result will be written. Nothing will
+     *               be written at all to this writer if input is <tt>null</tt>.
+     * @throws IOException if an input/output exception occurs
+     *
+     * @since 1.1.2
+     */
+    public static void escapeHtml4Xml(final String text, final Writer writer)
+            throws IOException {
+        escapeHtml(text, writer, HtmlEscapeType.HTML4_NAMED_REFERENCES_DEFAULT_TO_DECIMAL,
+                HtmlEscapeLevel.LEVEL_1_ONLY_MARKUP_SIGNIFICANT);
+    }
+
+
+    /**
+     * <p>
+     *   Perform a (configurable) HTML <strong>escape</strong> operation on a <tt>String</tt> input, writing
+     *   results to a <tt>Writer</tt>.
+     * </p>
+     * <p>
+     *   This method will perform an escape operation according to the specified
+     *   {@link org.unbescape.html.HtmlEscapeType} and {@link org.unbescape.html.HtmlEscapeLevel}
+     *   argument values.
+     * </p>
+     * <p>
+     *   All other <tt>String</tt>/<tt>Writer</tt>-based <tt>escapeHtml*(...)</tt> methods call this one with preconfigured
+     *   <tt>type</tt> and <tt>level</tt> values.
+     * </p>
+     * <p>
+     *   This method is <strong>thread-safe</strong>.
+     * </p>
+     *
+     * @param text the <tt>String</tt> to be escaped.
+     * @param writer the <tt>java.io.Writer</tt> to which the escaped result will be written. Nothing will
+     *               be written at all to this writer if input is <tt>null</tt>.
+     * @param type the type of escape operation to be performed, see {@link org.unbescape.html.HtmlEscapeType}.
+     * @param level the escape level to be applied, see {@link org.unbescape.html.HtmlEscapeLevel}.
+     * @throws IOException if an input/output exception occurs
+     *
+     * @since 1.1.2
+     */
+    public static void escapeHtml(final String text, final Writer writer, final HtmlEscapeType type, final HtmlEscapeLevel level)
+            throws IOException {
+
+        if (writer == null) {
+            throw new IllegalArgumentException("Argument 'writer' cannot be null");
+        }
+
+        if (type == null) {
+            throw new IllegalArgumentException("The 'type' argument cannot be null");
+        }
+
+        if (level == null) {
+            throw new IllegalArgumentException("The 'level' argument cannot be null");
+        }
+
+        HtmlEscapeUtil.escape(new InternalStringReader(text), writer, type, level);
+
+    }
+
+
+
+
+
+
+
+    /**
+     * <p>
+     *   Perform an HTML5 level 2 (result is ASCII) <strong>escape</strong> operation on a <tt>Reader</tt> input,
+     *   writing results to a <tt>Writer</tt>.
+     * </p>
+     * <p>
+     *   <em>Level 2</em> means this method will escape:
+     * </p>
+     * <ul>
+     *   <li>The five markup-significant characters: <tt>&lt;</tt>, <tt>&gt;</tt>, <tt>&amp;</tt>,
+     *       <tt>&quot;</tt> and <tt>&#39;</tt></li>
+     *   <li>All non ASCII characters.</li>
+     * </ul>
+     * <p>
+     *   This escape will be performed by replacing those chars by the corresponding HTML5 Named Character References
+     *   (e.g. <tt>'&amp;acute;'</tt>) when such NCR exists for the replaced character, and replacing by a decimal
+     *   character reference (e.g. <tt>'&amp;#8345;'</tt>) when there there is no NCR for the replaced character.
+     * </p>
+     * <p>
+     *   This method calls {@link #escapeHtml(Reader, Writer, HtmlEscapeType, HtmlEscapeLevel)} with the following
+     *   preconfigured values:
+     * </p>
+     * <ul>
+     *   <li><tt>type</tt>:
+     *       {@link org.unbescape.html.HtmlEscapeType#HTML5_NAMED_REFERENCES_DEFAULT_TO_DECIMAL}</li>
+     *   <li><tt>level</tt>:
+     *       {@link org.unbescape.html.HtmlEscapeLevel#LEVEL_2_ALL_NON_ASCII_PLUS_MARKUP_SIGNIFICANT}</li>
+     * </ul>
+     * <p>
+     *   This method is <strong>thread-safe</strong>.
+     * </p>
+     *
+     * @param reader the <tt>Reader</tt> reading the text to be escaped.
+     * @param writer the <tt>java.io.Writer</tt> to which the escaped result will be written. Nothing will
+     *               be written at all to this writer if input is <tt>null</tt>.
+     * @throws IOException if an input/output exception occurs
+     *
+     * @since 1.1.2
+     */
+    public static void escapeHtml5(final Reader reader, final Writer writer)
+            throws IOException {
+        escapeHtml(reader, writer, HtmlEscapeType.HTML5_NAMED_REFERENCES_DEFAULT_TO_DECIMAL,
+                HtmlEscapeLevel.LEVEL_2_ALL_NON_ASCII_PLUS_MARKUP_SIGNIFICANT);
+    }
+
+
+    /**
+     * <p>
+     *   Perform an HTML5 level 1 (XML-style) <strong>escape</strong> operation on a <tt>Reader</tt> input,
+     *   writing results to a <tt>Writer</tt>.
+     * </p>
+     * <p>
+     *   <em>Level 1</em> means this method will only escape the five markup-significant characters:
+     *   <tt>&lt;</tt>, <tt>&gt;</tt>, <tt>&amp;</tt>, <tt>&quot;</tt> and <tt>&#39;</tt>. It is called
+     *   <em>XML-style</em> in order to link it with JSP's <tt>escapeXml</tt> attribute in JSTL's
+     *   <tt>&lt;c:out ... /&gt;</tt> tags.
+     * </p>
+     * <p>
+     *  Note this method may <strong>not</strong> produce the same results as {@link #escapeHtml4Xml(Reader, Writer)} because
+     *  it will escape the apostrophe as <tt>&amp;apos;</tt>, whereas in HTML 4 such NCR does not exist
+     *  (the decimal numeric reference <tt>&amp;#39;</tt> is used instead).
+     * </p>
+     * <p>
+     *   This method calls {@link #escapeHtml(Reader, Writer, HtmlEscapeType, HtmlEscapeLevel)} with the following
+     *   preconfigured values:
+     * </p>
+     * <ul>
+     *   <li><tt>type</tt>:
+     *       {@link org.unbescape.html.HtmlEscapeType#HTML5_NAMED_REFERENCES_DEFAULT_TO_DECIMAL}</li>
+     *   <li><tt>level</tt>:
+     *       {@link org.unbescape.html.HtmlEscapeLevel#LEVEL_1_ONLY_MARKUP_SIGNIFICANT}</li>
+     * </ul>
+     * <p>
+     *   This method is <strong>thread-safe</strong>.
+     * </p>
+     *
+     * @param reader the <tt>Reader</tt> reading the text to be escaped.
+     * @param writer the <tt>java.io.Writer</tt> to which the escaped result will be written. Nothing will
+     *               be written at all to this writer if input is <tt>null</tt>.
+     * @throws IOException if an input/output exception occurs
+     *
+     * @since 1.1.2
+     */
+    public static void escapeHtml5Xml(final Reader reader, final Writer writer)
+            throws IOException {
+        escapeHtml(reader, writer, HtmlEscapeType.HTML5_NAMED_REFERENCES_DEFAULT_TO_DECIMAL,
+                HtmlEscapeLevel.LEVEL_1_ONLY_MARKUP_SIGNIFICANT);
+    }
+
+
+    /**
+     * <p>
+     *   Perform an HTML 4 level 2 (result is ASCII) <strong>escape</strong> operation on a <tt>Reader</tt> input,
+     *   writing results to a <tt>Writer</tt>.
+     * </p>
+     * <p>
+     *   <em>Level 2</em> means this method will escape:
+     * </p>
+     * <ul>
+     *   <li>The five markup-significant characters: <tt>&lt;</tt>, <tt>&gt;</tt>, <tt>&amp;</tt>,
+     *       <tt>&quot;</tt> and <tt>&#39;</tt></li>
+     *   <li>All non ASCII characters.</li>
+     * </ul>
+     * <p>
+     *   This escape will be performed by replacing those chars by the corresponding HTML 4 Named Character References
+     *   (e.g. <tt>'&amp;acute;'</tt>) when such NCR exists for the replaced character, and replacing by a decimal
+     *   character reference (e.g. <tt>'&amp;#8345;'</tt>) when there there is no NCR for the replaced character.
+     * </p>
+     * <p>
+     *   This method calls {@link #escapeHtml(Reader, Writer, HtmlEscapeType, HtmlEscapeLevel)} with the following
+     *   preconfigured values:
+     * </p>
+     * <ul>
+     *   <li><tt>type</tt>:
+     *       {@link org.unbescape.html.HtmlEscapeType#HTML4_NAMED_REFERENCES_DEFAULT_TO_DECIMAL}</li>
+     *   <li><tt>level</tt>:
+     *       {@link org.unbescape.html.HtmlEscapeLevel#LEVEL_2_ALL_NON_ASCII_PLUS_MARKUP_SIGNIFICANT}</li>
+     * </ul>
+     * <p>
+     *   This method is <strong>thread-safe</strong>.
+     * </p>
+     *
+     * @param reader the <tt>Reader</tt> reading the text to be escaped.
+     * @param writer the <tt>java.io.Writer</tt> to which the escaped result will be written. Nothing will
+     *               be written at all to this writer if input is <tt>null</tt>.
+     * @throws IOException if an input/output exception occurs
+     *
+     * @since 1.1.2
+     */
+    public static void escapeHtml4(final Reader reader, final Writer writer)
+            throws IOException {
+        escapeHtml(reader, writer, HtmlEscapeType.HTML4_NAMED_REFERENCES_DEFAULT_TO_DECIMAL,
+                HtmlEscapeLevel.LEVEL_2_ALL_NON_ASCII_PLUS_MARKUP_SIGNIFICANT);
+    }
+
+
+    /**
+     * <p>
+     *   Perform an HTML 4 level 1 (XML-style) <strong>escape</strong> operation on a <tt>Reader</tt> input,
+     *   writing results to a <tt>Writer</tt>.
+     * </p>
+     * <p>
+     *   <em>Level 1</em> means this method will only escape the five markup-significant characters:
+     *   <tt>&lt;</tt>, <tt>&gt;</tt>, <tt>&amp;</tt>, <tt>&quot;</tt> and <tt>&#39;</tt>. It is called
+     *   <em>XML-style</em> in order to link it with JSP's <tt>escapeXml</tt> attribute in JSTL's
+     *   <tt>&lt;c:out ... /&gt;</tt> tags.
+     * </p>
+     * <p>
+     *  Note this method may <strong>not</strong> produce the same results as {@link #escapeHtml5Xml(Reader, Writer)} because
+     *  it will escape the apostrophe as <tt>&amp;#39;</tt>, whereas in HTML5 there is a specific NCR for
+     *  such character (<tt>&amp;apos;</tt>).
+     * </p>
+     * <p>
+     *   This method calls {@link #escapeHtml(Reader, Writer, HtmlEscapeType, HtmlEscapeLevel)} with the following
+     *   preconfigured values:
+     * </p>
+     * <ul>
+     *   <li><tt>type</tt>:
+     *       {@link org.unbescape.html.HtmlEscapeType#HTML4_NAMED_REFERENCES_DEFAULT_TO_DECIMAL}</li>
+     *   <li><tt>level</tt>:
+     *       {@link org.unbescape.html.HtmlEscapeLevel#LEVEL_1_ONLY_MARKUP_SIGNIFICANT}</li>
+     * </ul>
+     * <p>
+     *   This method is <strong>thread-safe</strong>.
+     * </p>
+     *
+     * @param reader the <tt>Reader</tt> reading the text to be escaped.
+     * @param writer the <tt>java.io.Writer</tt> to which the escaped result will be written. Nothing will
+     *               be written at all to this writer if input is <tt>null</tt>.
+     * @throws IOException if an input/output exception occurs
+     *
+     * @since 1.1.2
+     */
+    public static void escapeHtml4Xml(final Reader reader, final Writer writer)
+            throws IOException {
+        escapeHtml(reader, writer, HtmlEscapeType.HTML4_NAMED_REFERENCES_DEFAULT_TO_DECIMAL,
+                HtmlEscapeLevel.LEVEL_1_ONLY_MARKUP_SIGNIFICANT);
+    }
+
+
+    /**
+     * <p>
+     *   Perform a (configurable) HTML <strong>escape</strong> operation on a <tt>Reader</tt> input, writing
+     *   results to a <tt>Writer</tt>.
+     * </p>
+     * <p>
+     *   This method will perform an escape operation according to the specified
+     *   {@link org.unbescape.html.HtmlEscapeType} and {@link org.unbescape.html.HtmlEscapeLevel}
+     *   argument values.
+     * </p>
+     * <p>
+     *   All other <tt>Reader</tt>/<tt>Writer</tt>-based <tt>escapeHtml*(...)</tt> methods call this one with preconfigured
+     *   <tt>type</tt> and <tt>level</tt> values.
+     * </p>
+     * <p>
+     *   This method is <strong>thread-safe</strong>.
+     * </p>
+     *
+     * @param reader the <tt>Reader</tt> reading the text to be escaped.
+     * @param writer the <tt>java.io.Writer</tt> to which the escaped result will be written. Nothing will
+     *               be written at all to this writer if input is <tt>null</tt>.
+     * @param type the type of escape operation to be performed, see {@link org.unbescape.html.HtmlEscapeType}.
+     * @param level the escape level to be applied, see {@link org.unbescape.html.HtmlEscapeLevel}.
+     * @throws IOException if an input/output exception occurs
+     *
+     * @since 1.1.2
+     */
+    public static void escapeHtml(final Reader reader, final Writer writer, final HtmlEscapeType type, final HtmlEscapeLevel level)
+            throws IOException {
+
+        if (writer == null) {
+            throw new IllegalArgumentException("Argument 'writer' cannot be null");
+        }
+
+        if (type == null) {
+            throw new IllegalArgumentException("The 'type' argument cannot be null");
+        }
+
+        if (level == null) {
+            throw new IllegalArgumentException("The 'level' argument cannot be null");
+        }
+
+        HtmlEscapeUtil.escape(reader, writer, type, level);
+
+    }
+
+
+
+
+
+
+
+    /**
+     * <p>
+     *   Perform an HTML5 level 2 (result is ASCII) <strong>escape</strong> operation on a <tt>char[]</tt> input.
+     * </p>
+     * <p>
+     *   <em>Level 2</em> means this method will escape:
+     * </p>
+     * <ul>
+     *   <li>The five markup-significant characters: <tt>&lt;</tt>, <tt>&gt;</tt>, <tt>&amp;</tt>,
+     *       <tt>&quot;</tt> and <tt>&#39;</tt></li>
+     *   <li>All non ASCII characters.</li>
+     * </ul>
+     * <p>
+     *   This escape will be performed by replacing those chars by the corresponding HTML5 Named Character References
+     *   (e.g. <tt>'&amp;acute;'</tt>) when such NCR exists for the replaced character, and replacing by a decimal
+     *   character reference (e.g. <tt>'&amp;#8345;'</tt>) when there there is no NCR for the replaced character.
+     * </p>
+     * <p>
+     *   This method calls {@link #escapeHtml(char[], int, int, Writer, HtmlEscapeType, HtmlEscapeLevel)}
+     *   with the following preconfigured values:
+     * </p>
+     * <ul>
+     *   <li><tt>type</tt>:
+     *       {@link org.unbescape.html.HtmlEscapeType#HTML5_NAMED_REFERENCES_DEFAULT_TO_DECIMAL}</li>
+     *   <li><tt>level</tt>:
+     *       {@link org.unbescape.html.HtmlEscapeLevel#LEVEL_2_ALL_NON_ASCII_PLUS_MARKUP_SIGNIFICANT}</li>
+     * </ul>
+     * <p>
+     *   This method is <strong>thread-safe</strong>.
+     * </p>
+     *
+     * @param text the <tt>char[]</tt> to be escaped.
+     * @param offset the position in <tt>text</tt> at which the escape operation should start.
+     * @param len the number of characters in <tt>text</tt> that should be escaped.
+     * @param writer the <tt>java.io.Writer</tt> to which the escaped result will be written. Nothing will
+     *               be written at all to this writer if input is <tt>null</tt>.
+     * @throws IOException if an input/output exception occurs
+     */
+    public static void escapeHtml5(final char[] text, final int offset, final int len, final Writer writer)
+                                   throws IOException {
+        escapeHtml(text, offset, len, writer, HtmlEscapeType.HTML5_NAMED_REFERENCES_DEFAULT_TO_DECIMAL,
+                HtmlEscapeLevel.LEVEL_2_ALL_NON_ASCII_PLUS_MARKUP_SIGNIFICANT);
+    }
+
+
+    /**
+     * <p>
+     *   Perform an HTML5 level 1 (XML-style) <strong>escape</strong> operation on a <tt>char[]</tt> input.
+     * </p>
+     * <p>
+     *   <em>Level 1</em> means this method will only escape the five markup-significant characters:
+     *   <tt>&lt;</tt>, <tt>&gt;</tt>, <tt>&amp;</tt>, <tt>&quot;</tt> and <tt>&#39;</tt>. It is called
+     *   <em>XML-style</em> in order to link it with JSP's <tt>escapeXml</tt> attribute in JSTL's
+     *   <tt>&lt;c:out ... /&gt;</tt> tags.
+     * </p>
+     * <p>
+     *  Note this method may <strong>not</strong> produce the same results as
+     *  {@link #escapeHtml4Xml(char[], int, int, Writer)} because
+     *  it will escape the apostrophe as <tt>&amp;apos;</tt>, whereas in HTML 4 such NCR does not exist
+     *  (the decimal numeric reference <tt>&amp;#39;</tt> is used instead).
+     * </p>
+     * <p>
+     *   This method calls {@link #escapeHtml(char[], int, int, Writer, HtmlEscapeType, HtmlEscapeLevel)}
+     *   with the following preconfigured values:
+     * </p>
+     * <ul>
+     *   <li><tt>type</tt>:
+     *       {@link org.unbescape.html.HtmlEscapeType#HTML5_NAMED_REFERENCES_DEFAULT_TO_DECIMAL}</li>
+     *   <li><tt>level</tt>:
+     *       {@link org.unbescape.html.HtmlEscapeLevel#LEVEL_1_ONLY_MARKUP_SIGNIFICANT}</li>
+     * </ul>
+     * <p>
+     *   This method is <strong>thread-safe</strong>.
+     * </p>
+     *
+     * @param text the <tt>char[]</tt> to be escaped.
+     * @param offset the position in <tt>text</tt> at which the escape operation should start.
+     * @param len the number of characters in <tt>text</tt> that should be escaped.
+     * @param writer the <tt>java.io.Writer</tt> to which the escaped result will be written. Nothing will
+     *               be written at all to this writer if input is <tt>null</tt>.
+     * @throws IOException if an input/output exception occurs
+     */
+    public static void escapeHtml5Xml(final char[] text, final int offset, final int len, final Writer writer)
+                                      throws IOException {
+        escapeHtml(text, offset, len, writer, HtmlEscapeType.HTML5_NAMED_REFERENCES_DEFAULT_TO_DECIMAL,
+                HtmlEscapeLevel.LEVEL_1_ONLY_MARKUP_SIGNIFICANT);
+    }
+
+
+    /**
+     * <p>
+     *   Perform an HTML 4 level 2 (result is ASCII) <strong>escape</strong> operation on a <tt>char[]</tt> input.
+     * </p>
+     * <p>
+     *   <em>Level 2</em> means this method will escape:
+     * </p>
+     * <ul>
+     *   <li>The five markup-significant characters: <tt>&lt;</tt>, <tt>&gt;</tt>, <tt>&amp;</tt>,
+     *       <tt>&quot;</tt> and <tt>&#39;</tt></li>
+     *   <li>All non ASCII characters.</li>
+     * </ul>
+     * <p>
+     *   This escape will be performed by replacing those chars by the corresponding HTML 4 Named Character References
+     *   (e.g. <tt>'&amp;acute;'</tt>) when such NCR exists for the replaced character, and replacing by a decimal
+     *   character reference (e.g. <tt>'&amp;#8345;'</tt>) when there there is no NCR for the replaced character.
+     * </p>
+     * <p>
+     *   This method calls {@link #escapeHtml(char[], int, int, Writer, HtmlEscapeType, HtmlEscapeLevel)}
+     *   with the following preconfigured values:
+     * </p>
+     * <ul>
+     *   <li><tt>type</tt>:
+     *       {@link org.unbescape.html.HtmlEscapeType#HTML4_NAMED_REFERENCES_DEFAULT_TO_DECIMAL}</li>
+     *   <li><tt>level</tt>:
+     *       {@link org.unbescape.html.HtmlEscapeLevel#LEVEL_2_ALL_NON_ASCII_PLUS_MARKUP_SIGNIFICANT}</li>
+     * </ul>
+     * <p>
+     *   This method is <strong>thread-safe</strong>.
+     * </p>
+     *
+     * @param text the <tt>char[]</tt> to be escaped.
+     * @param offset the position in <tt>text</tt> at which the escape operation should start.
+     * @param len the number of characters in <tt>text</tt> that should be escaped.
+     * @param writer the <tt>java.io.Writer</tt> to which the escaped result will be written. Nothing will
+     *               be written at all to this writer if input is <tt>null</tt>.
+     * @throws IOException if an input/output exception occurs
+     */
+    public static void escapeHtml4(final char[] text, final int offset, final int len, final Writer writer)
+                                   throws IOException {
+        escapeHtml(text, offset, len, writer, HtmlEscapeType.HTML4_NAMED_REFERENCES_DEFAULT_TO_DECIMAL,
+                HtmlEscapeLevel.LEVEL_2_ALL_NON_ASCII_PLUS_MARKUP_SIGNIFICANT);
+    }
+
+
+    /**
+     * <p>
+     *   Perform an HTML 4 level 1 (XML-style) <strong>escape</strong> operation on a <tt>char[]</tt> input.
+     * </p>
+     * <p>
+     *   <em>Level 1</em> means this method will only escape the five markup-significant characters:
+     *   <tt>&lt;</tt>, <tt>&gt;</tt>, <tt>&amp;</tt>, <tt>&quot;</tt> and <tt>&#39;</tt>. It is called
+     *   <em>XML-style</em> in order to link it with JSP's <tt>escapeXml</tt> attribute in JSTL's
+     *   <tt>&lt;c:out ... /&gt;</tt> tags.
+     * </p>
+     * <p>
+     *  Note this method may <strong>not</strong> produce the same results as
+     *  {@link #escapeHtml5Xml(char[], int, int, Writer)}  because it will escape the apostrophe as
+     *  <tt>&amp;#39;</tt>, whereas in HTML5 there is a specific NCR for such character (<tt>&amp;apos;</tt>).
+     * </p>
+     * <p>
+     *   This method calls {@link #escapeHtml(char[], int, int, Writer, HtmlEscapeType, HtmlEscapeLevel)}
+     *   with the following preconfigured values:
+     * </p>
+     * <ul>
+     *   <li><tt>type</tt>:
+     *       {@link org.unbescape.html.HtmlEscapeType#HTML4_NAMED_REFERENCES_DEFAULT_TO_DECIMAL}</li>
+     *   <li><tt>level</tt>:
+     *       {@link org.unbescape.html.HtmlEscapeLevel#LEVEL_1_ONLY_MARKUP_SIGNIFICANT}</li>
+     * </ul>
+     * <p>
+     *   This method is <strong>thread-safe</strong>.
+     * </p>
+     *
+     * @param text the <tt>char[]</tt> to be escaped.
+     * @param offset the position in <tt>text</tt> at which the escape operation should start.
+     * @param len the number of characters in <tt>text</tt> that should be escaped.
+     * @param writer the <tt>java.io.Writer</tt> to which the escaped result will be written. Nothing will
+     *               be written at all to this writer if input is <tt>null</tt>.
+     * @throws IOException if an input/output exception occurs
+     */
+    public static void escapeHtml4Xml(final char[] text, final int offset, final int len, final Writer writer)
+                                      throws IOException {
+        escapeHtml(text, offset, len, writer, HtmlEscapeType.HTML4_NAMED_REFERENCES_DEFAULT_TO_DECIMAL,
+                HtmlEscapeLevel.LEVEL_1_ONLY_MARKUP_SIGNIFICANT);
+    }
+
+
+    /**
+     * <p>
+     *   Perform a (configurable) HTML <strong>escape</strong> operation on a <tt>char[]</tt> input.
+     * </p>
+     * <p>
+     *   This method will perform an escape operation according to the specified
+     *   {@link org.unbescape.html.HtmlEscapeType} and {@link org.unbescape.html.HtmlEscapeLevel}
+     *   argument values.
+     * </p>
+     * <p>
+     *   All other <tt>char[]</tt>-based <tt>escapeHtml*(...)</tt> methods call this one with preconfigured
+     *   <tt>type</tt> and <tt>level</tt> values.
+     * </p>
+     * <p>
+     *   This method is <strong>thread-safe</strong>.
+     * </p>
+     *
+     * @param text the <tt>char[]</tt> to be escaped.
+     * @param offset the position in <tt>text</tt> at which the escape operation should start.
+     * @param len the number of characters in <tt>text</tt> that should be escaped.
+     * @param writer the <tt>java.io.Writer</tt> to which the escaped result will be written. Nothing will
+     *               be written at all to this writer if input is <tt>null</tt>.
+     * @param type the type of escape operation to be performed, see {@link org.unbescape.html.HtmlEscapeType}.
+     * @param level the escape level to be applied, see {@link org.unbescape.html.HtmlEscapeLevel}.
+     * @throws IOException if an input/output exception occurs
+     */
+    public static void escapeHtml(final char[] text, final int offset, final int len, final Writer writer,
+                                  final HtmlEscapeType type, final HtmlEscapeLevel level)
+                                  throws IOException {
+
+        if (writer == null) {
+            throw new IllegalArgumentException("Argument 'writer' cannot be null");
+        }
+
+        if (type == null) {
+            throw new IllegalArgumentException("The 'type' argument cannot be null");
+        }
+
+        if (level == null) {
+            throw new IllegalArgumentException("The 'level' argument cannot be null");
+        }
+
+        final int textLen = (text == null? 0 : text.length);
+
+        if (offset < 0 || offset > textLen) {
+            throw new IllegalArgumentException(
+                    "Invalid (offset, len). offset=" + offset + ", len=" + len + ", text.length=" + textLen);
+        }
+
+        if (len < 0 || (offset + len) > textLen) {
+            throw new IllegalArgumentException(
+                    "Invalid (offset, len). offset=" + offset + ", len=" + len + ", text.length=" + textLen);
+        }
+
+        HtmlEscapeUtil.escape(text, offset, len, writer, type, level);
+
+    }
+
+
+
+
+
+
+    /**
+     * <p>
+     *   Perform an HTML <strong>unescape</strong> operation on a <tt>String</tt> input.
+     * </p>
+     * <p>
+     *   No additional configuration arguments are required. Unescape operations
+     *   will always perform <em>complete</em> unescape of NCRs (whole HTML5 set supported), decimal
+     *   and hexadecimal references.
+     * </p>
+     * <p>
+     *   This method is <strong>thread-safe</strong>.
+     * </p>
+     *
+     * @param text the <tt>String</tt> to be unescaped.
+     * @return The unescaped result <tt>String</tt>. As a memory-performance improvement, will return the exact
+     *         same object as the <tt>text</tt> input argument if no unescaping modifications were required (and
+     *         no additional <tt>String</tt> objects will be created during processing). Will
+     *         return <tt>null</tt> if input is <tt>null</tt>.
+     */
+    public static String unescapeHtml(final String text) {
+        if (text == null) {
+            return null;
+        }
+        if (text.indexOf('&') < 0) {
+            // Fail fast, avoid more complex (and less JIT-table) method to execute if not needed
+            return text;
+        }
+        return HtmlEscapeUtil.unescape(text);
+    }
+
+
+
+    /**
+     * <p>
+     *   Perform an HTML <strong>unescape</strong> operation on a <tt>String</tt> input, writing results to
+     *   a <tt>Writer</tt>.
+     * </p>
+     * <p>
+     *   No additional configuration arguments are required. Unescape operations
+     *   will always perform <em>complete</em> unescape of NCRs (whole HTML5 set supported), decimal
+     *   and hexadecimal references.
+     * </p>
+     * <p>
+     *   This method is <strong>thread-safe</strong>.
+     * </p>
+     *
+     * @param text the <tt>String</tt> to be unescaped.
+     * @param writer the <tt>java.io.Writer</tt> to which the unescaped result will be written. Nothing will
+     *               be written at all to this writer if input is <tt>null</tt>.
+     * @throws IOException if an input/output exception occurs
+     *
+     * @since 1.1.2
+     */
+    public static void unescapeHtml(final String text, final Writer writer)
+            throws IOException {
+
+        if (writer == null) {
+            throw new IllegalArgumentException("Argument 'writer' cannot be null");
+        }
+        if (text == null) {
+            return;
+        }
+        if (text.indexOf('&') < 0) {
+            // Fail fast, avoid more complex (and less JIT-table) method to execute if not needed
+            writer.write(text);
+            return;
+        }
+
+        HtmlEscapeUtil.unescape(new InternalStringReader(text), writer);
+
+    }
+
+
+
+    /**
+     * <p>
+     *   Perform an HTML <strong>unescape</strong> operation on a <tt>Reader</tt> input, writing results to
+     *   a <tt>Writer</tt>.
+     * </p>
+     * <p>
+     *   No additional configuration arguments are required. Unescape operations
+     *   will always perform <em>complete</em> unescape of NCRs (whole HTML5 set supported), decimal
+     *   and hexadecimal references.
+     * </p>
+     * <p>
+     *   This method is <strong>thread-safe</strong>.
+     * </p>
+     *
+     * @param reader the <tt>Reader</tt> reading the text to be unescaped.
+     * @param writer the <tt>java.io.Writer</tt> to which the unescaped result will be written. Nothing will
+     *               be written at all to this writer if input is <tt>null</tt>.
+     * @throws IOException if an input/output exception occurs
+     *
+     * @since 1.1.2
+     */
+    public static void unescapeHtml(final Reader reader, final Writer writer)
+            throws IOException {
+
+        if (writer == null) {
+            throw new IllegalArgumentException("Argument 'writer' cannot be null");
+        }
+
+        HtmlEscapeUtil.unescape(reader, writer);
+
+    }
+
+
+
+    /**
+     * <p>
+     *   Perform an HTML <strong>unescape</strong> operation on a <tt>char[]</tt> input.
+     * </p>
+     * <p>
+     *   No additional configuration arguments are required. Unescape operations
+     *   will always perform <em>complete</em> unescape of NCRs (whole HTML5 set supported), decimal
+     *   and hexadecimal references.
+     * </p>
+     * <p>
+     *   This method is <strong>thread-safe</strong>.
+     * </p>
+     *
+     * @param text the <tt>char[]</tt> to be unescaped.
+     * @param offset the position in <tt>text</tt> at which the unescape operation should start.
+     * @param len the number of characters in <tt>text</tt> that should be unescaped.
+     * @param writer the <tt>java.io.Writer</tt> to which the unescaped result will be written. Nothing will
+     *               be written at all to this writer if input is <tt>null</tt>.
+     * @throws IOException if an input/output exception occurs
+     */
+    public static void unescapeHtml(final char[] text, final int offset, final int len, final Writer writer)
+                                    throws IOException{
+
+        if (writer == null) {
+            throw new IllegalArgumentException("Argument 'writer' cannot be null");
+        }
+
+        final int textLen = (text == null? 0 : text.length);
+
+        if (offset < 0 || offset > textLen) {
+            throw new IllegalArgumentException(
+                    "Invalid (offset, len). offset=" + offset + ", len=" + len + ", text.length=" + textLen);
+        }
+
+        if (len < 0 || (offset + len) > textLen) {
+            throw new IllegalArgumentException(
+                    "Invalid (offset, len). offset=" + offset + ", len=" + len + ", text.length=" + textLen);
+        }
+
+        HtmlEscapeUtil.unescape(text, offset, len, writer);
+
+    }
+
+
+
+
+    private HtmlEscape() {
+        super();
+    }
+
+
+
+    /*
+     * This is basically a very simplified, thread-unsafe version of StringReader that should
+     * perform better than the original StringReader by removing all synchronization structures.
+     *
+     * Note the only implemented methods are those that we know are really used from within the
+     * stream-based escape/unescape operations.
+     */
+    private static final class InternalStringReader extends Reader {
+
+        private String str;
+        private int length;
+        private int next = 0;
+
+        public InternalStringReader(final String s) {
+            super();
+            this.str = s;
+            this.length = s.length();
+        }
+
+        @Override
+        public int read() throws IOException {
+            if (this.next >= length) {
+                return -1;
+            }
+            return this.str.charAt(this.next++);
+        }
+
+        @Override
+        public int read(final char[] cbuf, final int off, final int len) throws IOException {
+            if ((off < 0) || (off > cbuf.length) || (len < 0) ||
+                    ((off + len) > cbuf.length) || ((off + len) < 0)) {
+                throw new IndexOutOfBoundsException();
+            } else if (len == 0) {
+                return 0;
+            }
+            if (this.next >= this.length) {
+                return -1;
+            }
+            int n = Math.min(this.length - this.next, len);
+            this.str.getChars(this.next, this.next + n, cbuf, off);
+            this.next += n;
+            return n;
+        }
+
+        @Override
+        public void close() throws IOException {
+            this.str = null; // Just set the reference to null, help the GC
+        }
+
+    }
+
+
+}
+
diff --git a/app/src/main/java/ohi/andre/consolelauncher/tuils/html_escape/HtmlEscapeLevel.java b/app/src/main/java/ohi/andre/consolelauncher/tuils/html_escape/HtmlEscapeLevel.java
new file mode 100755
index 0000000..33a70e3
--- /dev/null
+++ b/app/src/main/java/ohi/andre/consolelauncher/tuils/html_escape/HtmlEscapeLevel.java
@@ -0,0 +1,138 @@
+/*
+ * =============================================================================
+ * 
+ *   Copyright (c) 2014-2017, The UNBESCAPE team (http://www.unbescape.org)
+ * 
+ *   Licensed under the Apache License, Version 2.0 (the "License");
+ *   you may not use this file except in compliance with the License.
+ *   You may obtain a copy of the License at
+ * 
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ *   Unless required by applicable law or agreed to in writing, software
+ *   distributed under the License is distributed on an "AS IS" BASIS,
+ *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *   See the License for the specific language governing permissions and
+ *   limitations under the License.
+ * 
+ * =============================================================================
+ */
+package ohi.andre.consolelauncher.tuils.html_escape;
+
+/**
+ * <p>
+ *   Levels defined for HTML escape/unescape operations:
+ * </p>
+ *
+ * <ul>
+ *     <li><strong>Level 0</strong>: Escape only markup-significant characters, excluding the apostrophe. Therefore
+ *         <tt>&lt;</tt>, <tt>&gt;</tt>, <tt>&amp;</tt> and <tt>&quot;</tt> will be escaped. This level can be
+ *         used for escaping texts and also tag attributes that are always surrounded by double quotes, whenever the
+ *         apostrophe (<tt>&#39;</tt>) is considered a <em>safe</em> character and the user prefers it not to be
+ *         escaped for legibility reasons (e.g. might denote literals in expression languages like OGNL).
+ *         Note the result of a level-0 escape operation might still contain non-ASCII characters if they existed
+ *         in input, and therefore you will still need to correctly manage your input/output character
+ *         encoding settings.</li>
+ *     <li><strong>Level 1</strong>: Escape only markup-significant characters (including the apostrophe). Therefore
+ *         <tt>&lt;</tt>, <tt>&gt;</tt>, <tt>&amp;</tt>, <tt>&quot;</tt> and <tt>&#39;</tt> will be escaped.
+ *         This level is sometimes called <em>XML escape</em> or <strong><em>XML-style escape</em></strong>, though it
+ *         is not exactly equivalent to XML due to some HTML specificities. It is equivalent to the JSP escape
+ *         configured by the <tt>escapeXml</tt> attribute in JSTL's <tt>&lt;c:out ... /&gt;</tt> tags, and safe
+ *         for use in texts and also tag attributes that are always quoted &mdash;be it with single (apostrophe) or
+ *         double quotes. Note the result of a level-1 escape operation might still contain non-ASCII characters if they
+ *         existed in input, and therefore you will still need to correctly manage your input/output character
+ *         encoding settings.</li>
+ *     <li><strong>Level 2</strong>: Escape all markup-significant characters (as defined in level 1), plus all
+ *         non-ASCII characters. The result of a level-2 escape operation is therefore always ASCII-only text, and
+ *         safer to use in complex scenarios with mixed input/output character encodings. This level can be used
+ *         for escaping texts and also tag attributes that are always quoted &mdash;be it with single (apostrophe) or
+ *         double quotes.</li>
+ *     <li><strong>Level 3</strong>: Escape all non-alphanumeric characters, this is, all but those in the
+ *         <tt>A</tt>-<tt>Z</tt>, <tt>a</tt>-<tt>z</tt> and <tt>0</tt>-<tt>9</tt> ranges. This level
+ *         can be safely used for escaping texts and also tag attributes, even when these tag attributes are
+ *         unquoted.</li>
+ *     <li><strong>Level 4</strong>: Escape all characters, even alphanumeric ones.</li>
+ * </ul>
+ *
+ * <p>
+ *   For further information, see the <em>Glossary</em> and the <em>References</em> sections at the
+ *   documentation for the {@link org.unbescape.html.HtmlEscape} class.
+ * </p>
+ *
+ * @author Daniel Fern&aacute;ndez
+ * 
+ * @since 1.0.0
+ *
+ */
+public enum HtmlEscapeLevel {
+
+    /**
+     * Level 0 escape: escape only markup-significant characters, excluding the apostrophe:
+     * <tt>&lt;</tt>, <tt>&gt;</tt>, <tt>&amp;</tt> and <tt>&quot;</tt>
+     */
+    LEVEL_0_ONLY_MARKUP_SIGNIFICANT_EXCEPT_APOS(0),
+
+    /**
+     * Level 1 escape (<em>XML-style</em>): escape only markup-significant characters (including the apostrophe):
+     * <tt>&lt;</tt>, <tt>&gt;</tt>, <tt>&amp;</tt>, <tt>&quot;</tt> and <tt>&#39;</tt>
+     */
+    LEVEL_1_ONLY_MARKUP_SIGNIFICANT(1),
+
+    /**
+     * Level 2 escape: escape markup-significant characters plus all non-ASCII characters (result will always be ASCII).
+     */
+    LEVEL_2_ALL_NON_ASCII_PLUS_MARKUP_SIGNIFICANT(2),
+
+    /**
+     * Level 3 escape: escape all non-alphanumeric characteres (escape all but those in the
+     * <tt>A</tt>-<tt>Z</tt>, <tt>a</tt>-<tt>z</tt> and <tt>0</tt>-<tt>9</tt> ranges).
+     */
+    LEVEL_3_ALL_NON_ALPHANUMERIC(3),
+
+    /**
+     * Level 4 escape: escape all characters, including alphanumeric.
+     */
+    LEVEL_4_ALL_CHARACTERS(4);
+
+
+
+
+    private final int escapeLevel;
+
+
+    /**
+     * <p>
+     *   Utility method for obtaining an enum value from its corresponding <tt>int</tt> level value.
+     * </p>
+     *
+     * @param level the level
+     * @return the escape level enum constant, or <tt>IllegalArgumentException</tt> if level does not exist.
+     */
+    public static HtmlEscapeLevel forLevel(final int level) {
+        switch (level) {
+            case 0: return LEVEL_0_ONLY_MARKUP_SIGNIFICANT_EXCEPT_APOS;
+            case 1: return LEVEL_1_ONLY_MARKUP_SIGNIFICANT;
+            case 2: return LEVEL_2_ALL_NON_ASCII_PLUS_MARKUP_SIGNIFICANT;
+            case 3: return LEVEL_3_ALL_NON_ALPHANUMERIC;
+            case 4: return LEVEL_4_ALL_CHARACTERS;
+            default:
+                throw new IllegalArgumentException("No escape level enum constant defined for level: " + level);
+        }
+    }
+
+
+    HtmlEscapeLevel(final int escapeLevel) {
+        this.escapeLevel = escapeLevel;
+    }
+
+    /**
+     * Return the <tt>int</tt> escape level.
+     *
+     * @return the escape level.
+     */
+    public int getEscapeLevel() {
+        return this.escapeLevel;
+    }
+
+}
+
diff --git a/app/src/main/java/ohi/andre/consolelauncher/tuils/html_escape/HtmlEscapeSymbols.java b/app/src/main/java/ohi/andre/consolelauncher/tuils/html_escape/HtmlEscapeSymbols.java
new file mode 100755
index 0000000..9152bef
--- /dev/null
+++ b/app/src/main/java/ohi/andre/consolelauncher/tuils/html_escape/HtmlEscapeSymbols.java
@@ -0,0 +1,573 @@
+/*
+ * =============================================================================
+ * 
+ *   Copyright (c) 2014-2017, The UNBESCAPE team (http://www.unbescape.org)
+ * 
+ *   Licensed under the Apache License, Version 2.0 (the "License");
+ *   you may not use this file except in compliance with the License.
+ *   You may obtain a copy of the License at
+ * 
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ *   Unless required by applicable law or agreed to in writing, software
+ *   distributed under the License is distributed on an "AS IS" BASIS,
+ *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *   See the License for the specific language governing permissions and
+ *   limitations under the License.
+ * 
+ * =============================================================================
+ */
+package ohi.andre.consolelauncher.tuils.html_escape;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * <p>
+ *   Instances of this class group all the complex data structures needed to support full escape and unescape
+ *   operations for HTML.
+ * </p>
+ * <p>
+ *   Most of the fields in objects of this class are package-accessible, as the class itself is, in order to allow
+ *   them (the fields) to be directly accessed from the classes doing the real escape/unescape (basically,
+ *   the {@link HtmlEscapeUtil} class.
+ * </p>
+ * 
+ * @author Daniel Fern&aacute;ndez
+ * 
+ * @since 1.0.0
+ *
+ */
+final class HtmlEscapeSymbols {
+
+
+    /*
+     * GLOSSARY
+     * ------------------------
+     *
+     *   NCR
+     *      Named Character Reference or Character Entity Reference: textual
+     *      representation of an Unicode codepoint: &aacute;
+     *
+     *   DCR
+     *      Decimal Character Reference: base-10 numerical representation of an Unicode codepoint: &#225;
+     *
+     *   HCR
+     *      Hexadecimal Character Reference: hexadecimal numerical representation of an Unicode codepoint: &#xE1;
+     *
+     *   Unicode Codepoint
+     *      Each of the int values conforming the Unicode code space.
+     *      Normally corresponding to a Java char primitive value (codepoint <= \uFFFF),
+     *      but might be two chars for codepoints \u10000 to \u10FFFF if the first char is a high
+     *      surrogate (\uD800 to \uDBFF) and the second is a low surrogate (\uDC00 to \uDFFF).
+     *      See: http://www.oracle.com/technetwork/articles/javase/supplementary-142654.html
+     *
+     */
+
+
+
+
+    /*
+     * Length of the array used for holding the 'base' NCRS indexed by the codepoints themselves. This size
+     * (0x2fff - 12287) is considered enough to hold most of the NCRS that should be needed (HTML4 has 252
+     * NCRs with a maximum codepoint of 0x2666 - HTML5 has 2125 NCRs with a maximum codepoint of 120171, but
+     * only 138 scarcely used NCRs live above codepoint 0x2fff so an overflow map should be enough for
+     * those 138 cases).
+     */
+    static final int NCRS_BY_CODEPOINT_LEN = 0x2fff;
+
+    /*
+     * This array will contain the NCRs for the first NCRS_BY_CODEPOINT_LEN (0x2fff) codepoints, indexed by
+     * the codepoints themselves so that they (even in the form of mere char's) can be used for array random access.
+     * - Values are short in order to index values at the SORTED_NCRS array. This avoids the need for this
+     *   array to hold String pointers, which would be 4 bytes in size each (compared to shorts, which are 2 bytes).
+     * - Chars themselves or int codepoints can (will, in fact) be used as indexes.
+     * - Given values are short, the maximum amount of total references this class can handle is 0x7fff = 32767
+     *   (which is safe, because HTML5 has 2125).
+     * - All XML and HTML4 NCRs will fit in this array. In the case of HTML5 NCRs, only 138 of the 2125 will
+     *   not fit here (NCRs assigned to codepoints > 0x2fff), and an overflow map will be provided for them.
+     * - Approximate size will be 16 (header) + 12287 * 2 = 24590 bytes.
+     */
+    final short[] NCRS_BY_CODEPOINT = new short[NCRS_BY_CODEPOINT_LEN];
+
+    /*
+     * This map will work as an overflow of the NCRS_BY_CODEPOINT array, so that the codepoint-to-NCR relation is
+     * stored here (with hash-based access) for codepoints >= NCRS_BY_CODEPOINT_LEN (0x2fff).
+     * - The use of a Map here still allows for reasonabily fast access for those rare cases in which codepoints above
+     *   0x2fff are used.
+     * - In the real world, this map will contain the 138 values needed by HTML5 for codepoints >= 0x2fff.
+     * - Approximate max size will be (being a complex object like a Map, it's a rough approximation):
+     *   16 (header) + 138 * (16 (entry header) + 16*2 (key, value headers) + 4 (key) + 2 (value)) = 7468 bytes
+     */
+    final Map<Integer,Short> NCRS_BY_CODEPOINT_OVERFLOW;// No need to instantiate it until we know it's needed
+
+    /*
+     * Maximum char value inside the ASCII plane
+     */
+    static final char MAX_ASCII_CHAR = 0x7f;
+
+    /*
+     * This array will hold the 'escape level' assigned to each ASCII character (codepoint), 0x0 to 0x7f and also
+     * a level for the rest of non-ASCII characters.
+     * - These levels are used to configure how (and if) escape operations should ignore ASCII or non-ASCII
+     *   characters, or escape them somehow if required.
+     * - Each HtmlEscapeSymbols structure will define a different set of levels for ASCII chars, according to their needs.
+     * - Position 0x7f + 1 represents all the non-ASCII characters. The specified value will determine whether
+     *   all non-ASCII characters have to be escaped or not.
+     */
+    final byte[] ESCAPE_LEVELS = new byte[MAX_ASCII_CHAR + 2];
+
+    /*
+     * This array will contain all the NCRs, alphabetically ordered.
+     * - Positions in this array will correspond to positions in the SORTED_CODEPOINTS array, so that one array
+     *   (this one) holds the NCRs while the other one holds the codepoint(s) such NCRs refer to.
+     * - Gives the opportunity to store all NCRs in alphabetical order and therefore be able to perform
+     *   binary search operations in order to quickly find NCRs (and translate to codepoints) when unescaping.
+     * - Note this array will contain:
+     *     * All NCRs referenced from NCRS_BY_CODEPOINT
+     *     * NCRs whose codepoint is >= 0x2fff and therefore live in NCRS_BY_CODEPOINT_OVERFLOW
+     *     * NCRs which are not referenced in any of the above because they are a shortcut for (and completely
+     *       equivalent to) a sequence of two codepoints. These NCRs will only be unescaped, but never escaped.
+     * - Max size in real world, when populated for HTML5: 2125 NCRs * 4 bytes/objref -> 8500 bytes, plus the texts.
+     */
+    final char[][] SORTED_NCRS;
+
+    /*
+     * This array contains all the codepoints corresponding to the NCRs stored in SORTED_NCRS. This array is ordered
+     * so that each index in SORTED_NCRS can also be used to retrieve the corresponding CODEPOINT when used on this array.
+     * - Values in this array can be positive (= single codepoint) or negative (= double codepoint, will need further
+     *   resolution by means of the DOUBLE_CODEPOINTS array)
+     * - Max size in real world, when populated for HTML5: 2125 NCRs * 4 bytes/objref -> 8500 bytes.
+     */
+    final int[] SORTED_CODEPOINTS;
+
+
+    /*
+     * This array stores the sequences of two codepoints that are escaped as a single NCR. The indexes of this array are
+     * referenced as negative numbers at the SORTED_CODEPOINTS array, and the values are int[2], containing the
+     * sequence of codepoints. HTML4 has no NCRs like this, HTML5 has 93.
+     * - Note this array is only used in UNESCAPE operations. Double-codepoint NCR escape is not performed because
+     *   the resulting characters are exactly equivalent to the escape of the two codepoints separately.
+     * - Max size in real world, when populated for HTML5 (rough approximate): 93 * (4 (ref) + 16 + 2 * 4) = 2604 bytes
+     */
+    final int[][] DOUBLE_CODEPOINTS;
+
+
+    /*
+     * This constant will be used at the NCRS_BY_CODEPOINT array to specify there is no NCR associated with a
+     * codepoint.
+     */
+    static final short NO_NCR = (short) 0;
+
+
+
+
+    /*
+     * Constants holding the definition of all the HtmlEscapeSymbols for HTML4 and HTML5, to be used in escape and
+     * unescape operations.
+     */
+    static final HtmlEscapeSymbols HTML4_SYMBOLS;
+    static final HtmlEscapeSymbols HTML5_SYMBOLS;
+
+
+
+
+    static {
+
+        HTML4_SYMBOLS = Html4EscapeSymbolsInitializer.initializeHtml4();
+        HTML5_SYMBOLS = Html5EscapeSymbolsInitializer.initializeHtml5();
+
+    }
+
+
+
+
+
+    /*
+     * Create a new HtmlEscapeSymbols structure. This will initialize all the structures needed to cover the
+     * specified references and escape levels, including sorted arrays, overflow maps, etc.
+     */
+    HtmlEscapeSymbols(final References references, final byte[] escapeLevels) {
+
+        super();
+
+        // Initialize ASCII escape levels: just copy the array
+        System.arraycopy(escapeLevels, 0, ESCAPE_LEVELS, 0, (0x7f + 2));
+
+
+        // Initialize some auxiliary structures
+        final List<char[]> ncrs = new ArrayList<char[]>(references.references.size() + 5);
+        final List<Integer> codepoints = new ArrayList<Integer>(references.references.size() + 5);
+        final List<int[]> doubleCodepoints = new ArrayList<int[]>(100);
+        final Map<Integer,Short> ncrsByCodepointOverflow = new HashMap<Integer, Short>(20);
+
+        // For each reference, initialize its corresponding codepoint -> ncr and ncr -> codepoint structures
+        for (final Reference reference : references.references) {
+
+            final char[] referenceNcr = reference.ncr;
+            final int[] referenceCodepoints = reference.codepoints;
+
+            ncrs.add(referenceNcr);
+
+            if (referenceCodepoints.length == 1) {
+                // Only one codepoint (might be > 1 chars, though), this is the normal case
+
+                final int referenceCodepoint = referenceCodepoints[0];
+                codepoints.add(Integer.valueOf(referenceCodepoint));
+
+            } else if (referenceCodepoints.length == 2) {
+                // Two codepoints, therefore this NCR will translate when unescaping into a two-codepoint
+                // (probably two-char, too) sequence. We will use a negative codepoint value to signal this.
+
+                doubleCodepoints.add(referenceCodepoints);
+                // Will need to subtract one from its index when unescaping (codepoint = -1 -> position 0)
+                codepoints.add(Integer.valueOf((-1) * doubleCodepoints.size()));
+
+            } else {
+
+                throw new RuntimeException(
+                        "Unsupported codepoints #: " + referenceCodepoints.length + " for " + new String(referenceNcr));
+
+            }
+
+        }
+
+        // We hadn't touched this array before. First thing to do is initialize it, as it will have a huge
+        // amount of "empty" (i.e. non-assigned) values.
+        Arrays.fill(NCRS_BY_CODEPOINT, NO_NCR);
+
+
+        // We can initialize now these arrays that will hold the NCR-to-codepoint correspondence, but we cannot copy
+        // them directly from our auxiliary structures because we need to order the NCRs alphabetically first.
+
+        SORTED_NCRS = new char[ncrs.size()][];
+        SORTED_CODEPOINTS = new int[codepoints.size()];
+
+        final List<char[]> ncrsOrdered = new ArrayList<char[]>(ncrs);
+        Collections.sort(ncrsOrdered, new Comparator<char[]>() {
+            public int compare(final char[] o1, final char[] o2) {
+                return HtmlEscapeSymbols.compare(o1, o2, 0, o2.length);
+            }
+        });
+
+        for (short i = 0; i < SORTED_NCRS.length; i++) {
+
+            final char[] ncr = ncrsOrdered.get(i);
+            SORTED_NCRS[i] = ncr;
+
+            for (short j = 0; j  < SORTED_NCRS.length; j++) {
+
+                if (Arrays.equals(ncr,ncrs.get(j))) {
+
+                    final int cp = codepoints.get(j);
+                    SORTED_CODEPOINTS[i] = cp;
+
+                    if (cp > 0) {
+                        // Not negative (i.e. not double-codepoint)
+                        if (cp < NCRS_BY_CODEPOINT_LEN) {
+                            // Not overflown
+                            if (NCRS_BY_CODEPOINT[cp] == NO_NCR) {
+                                // Only the first NCR for each codepoint will be used for escaping.
+                                NCRS_BY_CODEPOINT[cp] = i;
+                            } else {
+                                final int positionOfCurrent = positionInList(ncrs, SORTED_NCRS[NCRS_BY_CODEPOINT[cp]]);
+                                final int positionOfNew = positionInList(ncrs, ncr);
+                                if (positionOfNew < positionOfCurrent) {
+                                    // The order in which NCRs were originally specified in the references argument
+                                    // marks which NCR should be used for escaping (the first one), if several NCRs
+                                    // have the same codepoint.
+                                    NCRS_BY_CODEPOINT[cp] = i;
+                                }
+                            }
+                        } else {
+                            // Codepoint should be overflown
+                            ncrsByCodepointOverflow.put(Integer.valueOf(cp), Short.valueOf(i));
+                        }
+                    }
+
+                    break;
+
+                }
+
+            }
+
+        }
+
+
+        // Only create the overflow map if it is really needed.
+        if (ncrsByCodepointOverflow.size() > 0) {
+            NCRS_BY_CODEPOINT_OVERFLOW = ncrsByCodepointOverflow;
+        } else {
+            NCRS_BY_CODEPOINT_OVERFLOW = null;
+        }
+
+
+        // Finally, the double-codepoints structure can be initialized, if really needed.
+        if (doubleCodepoints.size() > 0) {
+            DOUBLE_CODEPOINTS = new int[doubleCodepoints.size()][];
+            for (int i = 0; i < DOUBLE_CODEPOINTS.length; i++) {
+                DOUBLE_CODEPOINTS[i] = doubleCodepoints.get(i);
+            }
+        } else {
+            DOUBLE_CODEPOINTS = null;
+        }
+
+    }
+
+
+    /*
+     * Utility method, used for determining which of the different NCRs for the same
+     * codepoint (when there are many) was specified first, because that is the one
+     * we should be using for escaping.
+     * (Note all of the NCRs will be available for unescaping, obviously)
+     */
+    private static int positionInList(final List<char[]> list, final char[] element) {
+        int i = 0;
+        for (final char[] e : list) {
+            if (Arrays.equals(e, element)) {
+                return i;
+            }
+            i++;
+        }
+        return -1;
+    }
+
+
+
+
+    /*
+     * These two methods (two versions: for String and for char[]) compare each of the candidate
+     * text fragments with an NCR coming from the SORTED_NCRs array, during binary search operations.
+     *
+     * Note these methods not only perform a normal comparison (returning -1, 0 or 1), but will also
+     * return a negative number < -10 when a partial match is possible, this is, when the specified text
+     * fragment contains a complete NCR at its first chars but contains more chars afterwards. This is
+     * useful for matching HTML5 NCRs which do not end in ; (like '&aacute'), which will come in bigger fragments
+     * because the unescape method will have no way of differentiating the chars after the NCR from chars that
+     * could be in fact part of the NCR. Also note that, in the case of a partial match, (-1) * (returnValue + 10)
+     * will specify the number of matched chars.
+     *
+     * Note we will willingly alter order so that ';' goes always first (even before no-char). This will allow
+     * proper functioning of the partial-matching mechanism for NCRs that can appear both with and without
+     * a ';' suffix.
+     */
+
+    private static int compare(final char[] ncr, final String text, final int start, final int end) {
+        final int textLen = end - start;
+        final int maxCommon = Math.min(ncr.length, textLen);
+        int i;
+        // char 0 is discarded, will be & in both cases
+        for (i = 1; i < maxCommon; i++) {
+            final char tc = text.charAt(start + i);
+            if (ncr[i] < tc) {
+                if (tc == ';') {
+                    return 1;
+                }
+                return -1;
+            } else if (ncr[i] > tc) {
+                if (ncr[i] == ';') {
+                    return -1;
+                }
+                return 1;
+            }
+        }
+        if (ncr.length > i) {
+            if (ncr[i] == ';') {
+                return -1;
+            }
+            return 1;
+        }
+        if (textLen > i) {
+            if (text.charAt(start + i) == ';') {
+                return 1;
+            }
+            // We have a partial match. Can be an NCR not finishing in a semicolon
+            return - ((textLen - i) + 10);
+        }
+        return 0;
+    }
+
+    private static int compare(final char[] ncr, final char[] text, final int start, final int end) {
+        final int textLen = end - start;
+        final int maxCommon = Math.min(ncr.length, textLen);
+        int i;
+        // char 0 is discarded, will be & in both cases
+        for (i = 1; i < maxCommon; i++) {
+            final char tc = text[start + i];
+            if (ncr[i] < tc) {
+                if (tc == ';') {
+                    return 1;
+                }
+                return -1;
+            } else if (ncr[i] > tc) {
+                if (ncr[i] == ';') {
+                    return -1;
+                }
+                return 1;
+            }
+        }
+        if (ncr.length > i) {
+            if (ncr[i] == ';') {
+                return -1;
+            }
+            return 1;
+        }
+        if (textLen > i) {
+            if (text[start + i] == ';') {
+                return 1;
+            }
+            // We have a partial match. Can be an NCR not finishing in a semicolon
+            return - ((textLen - i) + 10);
+        }
+        return 0;
+    }
+
+
+
+    /*
+     * These two methods (two versions: for String and for char[]) are used during unescape at the
+     * {@link HtmlEscapeUtil} class in order to quickly find the NCR corresponding to a preselected fragment
+     * of text (if there is such NCR).
+     *
+     * Note this operation supports partial matching (based on the above 'compare(...)' methods). That way,
+     * if an exact match is not found but a partial match exists, the partial match will be returned.
+     */
+
+    static int binarySearch(final char[][] values,
+                            final String text, final int start, final int end) {
+
+        int low = 0;
+        int high = values.length - 1;
+
+        int partialIndex = Integer.MIN_VALUE;
+        int partialValue = Integer.MIN_VALUE;
+
+        while (low <= high) {
+
+            final int mid = (low + high) >>> 1;
+            final char[] midVal = values[mid];
+
+            final int cmp = compare(midVal, text, start, end);
+
+            if (cmp == -1) {
+                low = mid + 1;
+            } else if (cmp == 1) {
+                high = mid - 1;
+            } else if (cmp < -10) {
+                // Partial match
+                low = mid + 1;
+                if (partialIndex == Integer.MIN_VALUE || partialValue < cmp) {
+                    partialIndex = mid;
+                    partialValue = cmp; // partial will always be negative, and -10. We look for the smallest partial
+                }
+            } else {
+                // Found!!
+                return mid;
+            }
+
+        }
+
+        if (partialIndex != Integer.MIN_VALUE) {
+            // We have a partial result. We return the closest result index as negative + (-10)
+            return (-1) * (partialIndex + 10);
+        }
+
+        return Integer.MIN_VALUE; // Not found!
+
+    }
+
+    static int binarySearch(final char[][] values,
+                            final char[] text, final int start, final int end) {
+
+        int low = 0;
+        int high = values.length - 1;
+
+        int partialIndex = Integer.MIN_VALUE;
+        int partialValue = Integer.MIN_VALUE;
+
+        while (low <= high) {
+
+            final int mid = (low + high) >>> 1;
+            final char[] midVal = values[mid];
+
+            final int cmp = compare(midVal, text, start, end);
+
+            if (cmp == -1) {
+                low = mid + 1;
+            } else if (cmp == 1) {
+                high = mid - 1;
+            } else if (cmp < -10) {
+                // Partial match
+                low = mid + 1;
+                if (partialIndex == Integer.MIN_VALUE || partialValue < cmp) {
+                    partialIndex = mid;
+                    partialValue = cmp; // partial will always be negative, and -10. We look for the smallest partial
+                }
+            } else {
+                // Found!!
+                return mid;
+            }
+
+        }
+
+        if (partialIndex != Integer.MIN_VALUE) {
+            // We have a partial result. We return the closest result index as negative + (-10)
+            return (-1) * (partialIndex + 10);
+        }
+
+        return Integer.MIN_VALUE; // Not found!
+
+    }
+
+
+
+
+
+
+    /*
+     * Inner utility classes that model the named character references to be included in an initialized
+     * instance of the HtmlEscapeSymbols class.
+     */
+
+
+    static final class References {
+
+        private final List<Reference> references = new ArrayList<Reference>(200);
+
+        References() {
+            super();
+        }
+
+        void addReference(final int codepoint, final String ncr) {
+            this.references.add(new Reference(ncr, new int[]{codepoint}));
+        }
+
+        void addReference(final int codepoint0, final int codepoint1, final String ncr) {
+            this.references.add(new Reference(ncr, new int[] { codepoint0, codepoint1 }));
+        }
+
+    }
+
+
+    private static final class Reference {
+
+        private final char[] ncr;
+        private final int[] codepoints;
+
+        private Reference(final String ncr, final int[] codepoints) {
+            super();
+            this.ncr = ncr.toCharArray();
+            this.codepoints = codepoints;
+        }
+
+    }
+
+
+
+}
+
diff --git a/app/src/main/java/ohi/andre/consolelauncher/tuils/html_escape/HtmlEscapeType.java b/app/src/main/java/ohi/andre/consolelauncher/tuils/html_escape/HtmlEscapeType.java
new file mode 100755
index 0000000..fe2affb
--- /dev/null
+++ b/app/src/main/java/ohi/andre/consolelauncher/tuils/html_escape/HtmlEscapeType.java
@@ -0,0 +1,119 @@
+/*
+ * =============================================================================
+ * 
+ *   Copyright (c) 2014-2017, The UNBESCAPE team (http://www.unbescape.org)
+ * 
+ *   Licensed under the Apache License, Version 2.0 (the "License");
+ *   you may not use this file except in compliance with the License.
+ *   You may obtain a copy of the License at
+ * 
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ *   Unless required by applicable law or agreed to in writing, software
+ *   distributed under the License is distributed on an "AS IS" BASIS,
+ *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *   See the License for the specific language governing permissions and
+ *   limitations under the License.
+ * 
+ * =============================================================================
+ */
+package ohi.andre.consolelauncher.tuils.html_escape;
+
+/**
+ * <p>
+ *   Types of escape operations to be performed on HTML text:
+ * </p>
+ *
+ * <ul>
+ *     <li><tt><strong>HTML4_NAMED_REFERENCES_DEFAULT_TO_DECIMAL</strong></tt>: Replace escaped characters
+ *         with HTML 4 <em>Named Character References</em> (<em>Character Entity References</em>) whenever
+ *         possible (depending on the specified {@link org.unbescape.html.HtmlEscapeLevel}), and default to
+ *         using <em>Decimal Character References</em> for escaped characters that do not have an associated
+ *         NCR.</li>
+ *     <li><tt><strong>HTML4_NAMED_REFERENCES_DEFAULT_TO_HEXA</strong></tt>: Replace escaped characters
+ *         with HTML 4 <em>Named Character References</em> (<em>Character Entity References</em>) whenever
+ *         possible (depending on the specified {@link org.unbescape.html.HtmlEscapeLevel}), and default to
+ *         using <em>Hexadecimal Character References</em> for escaped characters that do not have an associated
+ *         NCR.</li>
+ *     <li><tt><strong>HTML5_NAMED_REFERENCES_DEFAULT_TO_DECIMAL</strong></tt>: Replace escaped characters
+ *         with HTML5 <em>Named Character References</em> whenever
+ *         possible (depending on the specified {@link org.unbescape.html.HtmlEscapeLevel}), and default to
+ *         using <em>Decimal Character References</em> for escaped characters that do not have an associated
+ *         NCR.</li>
+ *     <li><tt><strong>HTML5_NAMED_REFERENCES_DEFAULT_TO_HEXA</strong></tt>: Replace escaped characters
+ *         with HTML5 <em>Named Character References</em> whenever
+ *         possible (depending on the specified {@link org.unbescape.html.HtmlEscapeLevel}), and default to
+ *         using <em>Hexadecimal Character References</em> for escaped characters that do not have an associated
+ *         NCR.</li>
+ *     <li><tt><strong>DECIMAL_REFERENCES</strong></tt>: Replace escaped characters with
+ *         <em>Decimal Character References</em> (will never use NCRs).</li>
+ *     <li><tt><strong>HEXADECIMAL_REFERENCES</strong></tt>: Replace escaped characters with
+ *         <em>Hexadecimal Character References</em> (will never use NCRs).</li>
+ * </ul>
+ *
+ * <p>
+ *   For further information, see the <em>Glossary</em> and the <em>References</em> sections at the
+ *   documentation for the {@link org.unbescape.html.HtmlEscape} class.
+ * </p>
+ *
+ * @author Daniel Fern&aacute;ndez
+ *
+ * @since 1.0.0
+ *
+ */
+public enum HtmlEscapeType {
+
+    /**
+     * Use HTML 4 NCRs if possible, default to Decimal Character References.
+     */
+    HTML4_NAMED_REFERENCES_DEFAULT_TO_DECIMAL(true, false, false),
+
+    /**
+     * Use HTML 4 NCRs if possible, default to Hexadecimal Character References.
+     */
+    HTML4_NAMED_REFERENCES_DEFAULT_TO_HEXA(true, true, false),
+
+    /**
+     * Use HTML5 NCRs if possible, default to Decimal Character References.
+     */
+    HTML5_NAMED_REFERENCES_DEFAULT_TO_DECIMAL(true, false, true),
+
+    /**
+     * Use HTML5 NCRs if possible, default to Hexadecimal Character References.
+     */
+    HTML5_NAMED_REFERENCES_DEFAULT_TO_HEXA(true, true, true),
+
+    /**
+     * Always use Decimal Character References (no NCRs will be used).
+     */
+    DECIMAL_REFERENCES(false, false, false),
+
+    /**
+     * Always use Hexadecimal Character References (no NCRs will be used).
+     */
+    HEXADECIMAL_REFERENCES(false, true, false);
+
+
+    private final boolean useNCRs;
+    private final boolean useHexa;
+    private final boolean useHtml5;
+
+    HtmlEscapeType(final boolean useNCRs, final boolean useHexa, final boolean useHtml5) {
+        this.useNCRs = useNCRs;
+        this.useHexa = useHexa;
+        this.useHtml5 = useHtml5;
+    }
+
+    boolean getUseNCRs() {
+        return this.useNCRs;
+    }
+
+    boolean getUseHexa() {
+        return this.useHexa;
+    }
+
+    boolean getUseHtml5() {
+        return this.useHtml5;
+    }
+}
+
diff --git a/app/src/main/java/ohi/andre/consolelauncher/tuils/html_escape/HtmlEscapeUtil.java b/app/src/main/java/ohi/andre/consolelauncher/tuils/html_escape/HtmlEscapeUtil.java
new file mode 100755
index 0000000..1c3caf4
--- /dev/null
+++ b/app/src/main/java/ohi/andre/consolelauncher/tuils/html_escape/HtmlEscapeUtil.java
@@ -0,0 +1,1368 @@
+/*
+ * =============================================================================
+ * 
+ *   Copyright (c) 2014-2017, The UNBESCAPE team (http://www.unbescape.org)
+ * 
+ *   Licensed under the Apache License, Version 2.0 (the "License");
+ *   you may not use this file except in compliance with the License.
+ *   You may obtain a copy of the License at
+ * 
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ *   Unless required by applicable law or agreed to in writing, software
+ *   distributed under the License is distributed on an "AS IS" BASIS,
+ *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *   See the License for the specific language governing permissions and
+ *   limitations under the License.
+ * 
+ * =============================================================================
+ */
+package ohi.andre.consolelauncher.tuils.html_escape;
+
+import java.io.IOException;
+import java.io.Reader;
+import java.io.Writer;
+
+/**
+ * <p>
+ *   Internal class in charge of performing the real escape/unescape operations.
+ * </p>
+ *
+ * @author Daniel Fern&aacute;ndez
+ * 
+ * @since 1.0.0
+ *
+ */
+final class HtmlEscapeUtil {
+
+
+    
+    /*
+     * GLOSSARY
+     * ------------------------
+     *
+     *   NCR
+     *      Named Character Reference or Character Entity Reference: textual
+     *      representation of an Unicode codepoint: &aacute;
+     *
+     *   DCR
+     *      Decimal Character Reference: base-10 numerical representation of an Unicode codepoint: &#225;
+     *
+     *   HCR
+     *      Hexadecimal Character Reference: hexadecimal numerical representation of an Unicode codepoint: &#xE1;
+     *
+     *   Unicode Codepoint
+     *      Each of the int values conforming the Unicode code space.
+     *      Normally corresponding to a Java char primitive value (codepoint <= \uFFFF),
+     *      but might be two chars for codepoints \u10000 to \u10FFFF if the first char is a high
+     *      surrogate (\uD800 to \uDBFF) and the second is a low surrogate (\uDC00 to \uDFFF).
+     *      See: http://www.oracle.com/technetwork/articles/javase/supplementary-142654.html
+     *
+     */
+
+
+
+
+    /*
+     * Prefixes and suffix defined for use in decimal/hexa escape and unescape.
+     */
+    private static final char REFERENCE_PREFIX = '&';
+    private static final char REFERENCE_NUMERIC_PREFIX2 = '#';
+    private static final char REFERENCE_HEXA_PREFIX3_UPPER = 'X';
+    private static final char REFERENCE_HEXA_PREFIX3_LOWER = 'x';
+    private static final char[] REFERENCE_DECIMAL_PREFIX = "&#".toCharArray();
+    private static final char[] REFERENCE_HEXA_PREFIX = "&#x".toCharArray();
+    private static final char REFERENCE_SUFFIX = ';';
+
+    /*
+     * Small utility char arrays for hexadecimal conversion
+     */
+    private static char[] HEXA_CHARS_UPPER = "0123456789ABCDEF".toCharArray();
+    private static char[] HEXA_CHARS_LOWER = "0123456789abcdef".toCharArray();
+
+
+
+
+    private HtmlEscapeUtil() {
+        super();
+    }
+
+
+
+
+
+    /*
+     * Perform an escape operation, based on String, according to the specified level and type.
+     */
+    static String escape(final String text, final HtmlEscapeType escapeType, final HtmlEscapeLevel escapeLevel) {
+
+        if (text == null) {
+            return null;
+        }
+
+        final int level = escapeLevel.getEscapeLevel();
+        final boolean useHtml5 = escapeType.getUseHtml5();
+        final boolean useNCRs = escapeType.getUseNCRs();
+        final boolean useHexa = escapeType.getUseHexa();
+
+        final HtmlEscapeSymbols symbols =
+                (useHtml5? HtmlEscapeSymbols.HTML5_SYMBOLS : HtmlEscapeSymbols.HTML4_SYMBOLS);
+
+        StringBuilder strBuilder = null;
+
+        final int offset = 0;
+        final int max = text.length();
+
+        int readOffset = offset;
+
+        for (int i = offset; i < max; i++) {
+
+            final char c = text.charAt(i);
+
+
+            /*
+             * Shortcut: most characters will be ASCII/Alphanumeric, and we won't need to do anything at
+             * all for them
+             */
+            if (c <= HtmlEscapeSymbols.MAX_ASCII_CHAR && level < symbols.ESCAPE_LEVELS[c]) {
+                continue;
+            }
+
+
+            /*
+             * Shortcut: we might not want to escape non-ASCII chars at all either.
+             */
+            if (c > HtmlEscapeSymbols.MAX_ASCII_CHAR
+                    && level < symbols.ESCAPE_LEVELS[HtmlEscapeSymbols.MAX_ASCII_CHAR + 1]) {
+                continue;
+            }
+
+
+            /*
+             * Compute the codepoint. This will be used instead of the char for the rest of the process.
+             */
+            final int codepoint = Character.codePointAt(text, i);
+
+
+            /*
+             * At this point we know for sure we will need some kind of escape, so we
+             * can increase the offset and initialize the string builder if needed, along with
+             * copying to it all the contents pending up to this point.
+             */
+
+            if (strBuilder == null) {
+                strBuilder = new StringBuilder(max + 20);
+            }
+
+            if (i - readOffset > 0) {
+                strBuilder.append(text, readOffset, i);
+            }
+
+            if (Character.charCount(codepoint) > 1) {
+                // This is to compensate that we are actually escaping two char[] positions with a single codepoint.
+                i++;
+            }
+
+            readOffset = i + 1;
+
+
+            /*
+             * -----------------------------------------------------------------------------------------
+             *
+             * Perform the real escape, attending the different combinations of NCR, DCR and HCR needs.
+             *
+             * -----------------------------------------------------------------------------------------
+             */
+
+            if (useNCRs) {
+                // We will try to use an NCR
+
+                if (codepoint < symbols.NCRS_BY_CODEPOINT_LEN) {
+                    // codepoint < 0x2fff - all HTML4, most HTML5
+
+                    final short ncrIndex = symbols.NCRS_BY_CODEPOINT[codepoint];
+                    if (ncrIndex != symbols.NO_NCR) {
+                        // There is an NCR for this codepoint!
+                        strBuilder.append(symbols.SORTED_NCRS[ncrIndex]);
+                        continue;
+                    } // else, just let it exit the block and let decimal/hexa escape do its job
+
+                } else if (symbols.NCRS_BY_CODEPOINT_OVERFLOW != null) {
+                    // codepoint >= 0x2fff. NCR, if exists, will live at the overflow map (if there is one).
+
+                    final Short ncrIndex = symbols.NCRS_BY_CODEPOINT_OVERFLOW.get(Integer.valueOf(codepoint));
+                    if (ncrIndex != null) {
+                        strBuilder.append(symbols.SORTED_NCRS[ncrIndex.shortValue()]);
+                        continue;
+                    } // else, just let it exit the block and let decimal/hexa escape do its job
+
+                }
+
+            }
+
+            /*
+             * No NCR-escape was possible (or allowed), so we need decimal/hexa escape.
+             */
+
+            if (useHexa) {
+                strBuilder.append(REFERENCE_HEXA_PREFIX);
+                strBuilder.append(Integer.toHexString(codepoint));
+            } else {
+                strBuilder.append(REFERENCE_DECIMAL_PREFIX);
+                strBuilder.append(String.valueOf(codepoint));
+            }
+            strBuilder.append(REFERENCE_SUFFIX);
+
+        }
+
+
+        /*
+         * -----------------------------------------------------------------------------------------------
+         * Final cleaning: return the original String object if no escape was actually needed. Otherwise
+         *                 append the remaining unescaped text to the string builder and return.
+         * -----------------------------------------------------------------------------------------------
+         */
+
+        if (strBuilder == null) {
+            return text;
+        }
+
+        if (max - readOffset > 0) {
+            strBuilder.append(text, readOffset, max);
+        }
+
+        return strBuilder.toString();
+
+    }
+
+
+
+
+
+    /*
+     * Perform an escape operation, based on a Reader, according to the specified level and type and writing the
+     * result to a Writer.
+     *
+     * Note this reader is going to be read char-by-char, so some kind of buffering might be appropriate if this
+     * is an inconvenience for the specific Reader implementation.
+     */
+    static void escape(
+            final Reader reader, final Writer writer, final HtmlEscapeType escapeType, final HtmlEscapeLevel escapeLevel)
+            throws IOException {
+
+        if (reader == null) {
+            return;
+        }
+
+        final int level = escapeLevel.getEscapeLevel();
+        final boolean useHtml5 = escapeType.getUseHtml5();
+        final boolean useNCRs = escapeType.getUseNCRs();
+        final boolean useHexa = escapeType.getUseHexa();
+
+        final HtmlEscapeSymbols symbols =
+                (useHtml5? HtmlEscapeSymbols.HTML5_SYMBOLS : HtmlEscapeSymbols.HTML4_SYMBOLS);
+
+        int c1, c2; // c1: current char, c2: next char
+
+        c2 = reader.read();
+
+        while (c2 >= 0) {
+
+            c1 = c2;
+            c2 = reader.read();
+
+
+            /*
+             * Shortcut: most characters will be ASCII/Alphanumeric, and we won't need to do anything at
+             * all for them
+             */
+            if (c1 <= HtmlEscapeSymbols.MAX_ASCII_CHAR && level < symbols.ESCAPE_LEVELS[c1]) {
+                writer.write(c1);
+                continue;
+            }
+
+
+            /*
+             * Shortcut: we might not want to escape non-ASCII chars at all either.
+             */
+            if (c1 > HtmlEscapeSymbols.MAX_ASCII_CHAR
+                    && level < symbols.ESCAPE_LEVELS[HtmlEscapeSymbols.MAX_ASCII_CHAR + 1]) {
+                writer.write(c1);
+                continue;
+            }
+
+
+            /*
+             * Compute the codepoint. This will be used instead of the char for the rest of the process.
+             */
+            final int codepoint = codePointAt((char)c1, (char)c2);
+
+
+            /*
+             * We know we need to escape, so from here on we will only work with the codepoint -- we can advance
+             * the chars.
+             */
+
+            if (Character.charCount(codepoint) > 1) {
+                // This is to compensate that we are actually reading two char positions with a single codepoint.
+                c1 = c2;
+                c2 = reader.read();
+            }
+
+
+            /*
+             * -----------------------------------------------------------------------------------------
+             *
+             * Perform the real escape, attending the different combinations of NCR, DCR and HCR needs.
+             *
+             * -----------------------------------------------------------------------------------------
+             */
+
+            if (useNCRs) {
+                // We will try to use an NCR
+
+                if (codepoint < symbols.NCRS_BY_CODEPOINT_LEN) {
+                    // codepoint < 0x2fff - all HTML4, most HTML5
+
+                    final short ncrIndex = symbols.NCRS_BY_CODEPOINT[codepoint];
+                    if (ncrIndex != symbols.NO_NCR) {
+                        // There is an NCR for this codepoint!
+                        writer.write(symbols.SORTED_NCRS[ncrIndex]);
+                        continue;
+                    } // else, just let it exit the block and let decimal/hexa escape do its job
+
+                } else if (symbols.NCRS_BY_CODEPOINT_OVERFLOW != null) {
+                    // codepoint >= 0x2fff. NCR, if exists, will live at the overflow map (if there is one).
+
+                    final Short ncrIndex = symbols.NCRS_BY_CODEPOINT_OVERFLOW.get(Integer.valueOf(codepoint));
+                    if (ncrIndex != null) {
+                        writer.write(symbols.SORTED_NCRS[ncrIndex.shortValue()]);
+                        continue;
+                    } // else, just let it exit the block and let decimal/hexa escape do its job
+
+                }
+
+            }
+
+            /*
+             * No NCR-escape was possible (or allowed), so we need decimal/hexa escape.
+             */
+
+            if (useHexa) {
+                writer.write(REFERENCE_HEXA_PREFIX);
+                writer.write(Integer.toHexString(codepoint));
+            } else {
+                writer.write(REFERENCE_DECIMAL_PREFIX);
+                writer.write(String.valueOf(codepoint));
+            }
+            writer.write(REFERENCE_SUFFIX);
+
+        }
+
+    }
+
+
+
+
+
+    /*
+     * Perform an escape operation, based on char[], according to the specified level and type.
+     */
+    static void escape(final char[] text, final int offset, final int len, final Writer writer,
+                       final HtmlEscapeType escapeType, final HtmlEscapeLevel escapeLevel)
+                       throws IOException {
+
+        if (text == null || text.length == 0) {
+            return;
+        }
+
+        final int level = escapeLevel.getEscapeLevel();
+        final boolean useHtml5 = escapeType.getUseHtml5();
+        final boolean useNCRs = escapeType.getUseNCRs();
+        final boolean useHexa = escapeType.getUseHexa();
+
+        final HtmlEscapeSymbols symbols =
+                (useHtml5? HtmlEscapeSymbols.HTML5_SYMBOLS : HtmlEscapeSymbols.HTML4_SYMBOLS);
+
+        final int max = (offset + len);
+
+        int readOffset = offset;
+
+        for (int i = offset; i < max; i++) {
+
+            final char c = text[i];
+
+
+            /*
+             * Shortcut: most characters will be ASCII/Alphanumeric, and we won't need to do anything at
+             * all for them
+             */
+            if (c <= symbols.MAX_ASCII_CHAR && level < symbols.ESCAPE_LEVELS[c]) {
+                continue;
+            }
+
+
+            /*
+             * Shortcut: we might not want to escape non-ASCII chars at all either.
+             */
+            if (c > symbols.MAX_ASCII_CHAR && level < symbols.ESCAPE_LEVELS[symbols.MAX_ASCII_CHAR + 1]) {
+                continue;
+            }
+
+
+            /*
+             * Compute the codepoint. This will be used instead of the char for the rest of the process.
+             */
+            final int codepoint = Character.codePointAt(text, i);
+
+
+            /*
+             * At this point we know for sure we will need some kind of escape, so we
+             * can write all the contents pending up to this point.
+             */
+
+            if (i - readOffset > 0) {
+                writer.write(text, readOffset, (i - readOffset));
+            }
+
+            if (Character.charCount(codepoint) > 1) {
+                // This is to compensate that we are actually escaping two char[] positions with a single codepoint.
+                i++;
+            }
+
+            readOffset = i + 1;
+
+
+            /*
+             * -----------------------------------------------------------------------------------------
+             *
+             * Perform the real escape, attending the different combinations of NCR, DCR and HCR needs.
+             *
+             * -----------------------------------------------------------------------------------------
+             */
+
+            if (useNCRs) {
+                // We will try to use an NCR
+
+                if (codepoint < symbols.NCRS_BY_CODEPOINT_LEN) {
+                    // codepoint < 0x2fff - all HTML4, most HTML5
+
+                    final short ncrIndex = symbols.NCRS_BY_CODEPOINT[codepoint];
+                    if (ncrIndex != symbols.NO_NCR) {
+                        // There is an NCR for this codepoint!
+                        writer.write(symbols.SORTED_NCRS[ncrIndex]);
+                        continue;
+                    } // else, just let it exit the block and let decimal/hexa escape do its job
+
+                } else if (symbols.NCRS_BY_CODEPOINT_OVERFLOW != null) {
+                    // codepoint >= 0x2fff. NCR, if exists, will live at the overflow map (if there is one).
+
+                    final Short ncrIndex = symbols.NCRS_BY_CODEPOINT_OVERFLOW.get(Integer.valueOf(codepoint));
+                    if (ncrIndex != null) {
+                        writer.write(symbols.SORTED_NCRS[ncrIndex.shortValue()]);
+                        continue;
+                    } // else, just let it exit the block and let decimal/hexa escape do its job
+
+                }
+
+            }
+
+            /*
+             * No NCR-escape was possible (or allowed), so we need decimal/hexa escape.
+             */
+
+            if (useHexa) {
+                writer.write(REFERENCE_HEXA_PREFIX);
+                writer.write(Integer.toHexString(codepoint));
+            } else {
+                writer.write(REFERENCE_DECIMAL_PREFIX);
+                writer.write(String.valueOf(codepoint));
+            }
+            writer.write(REFERENCE_SUFFIX);
+
+        }
+
+
+        /*
+         * -----------------------------------------------------------------------------------------------
+         * Final cleaning: append the remaining unescaped text to the writer and return.
+         * -----------------------------------------------------------------------------------------------
+         */
+
+        if (max - readOffset > 0) {
+            writer.write(text, readOffset, (max - readOffset));
+        }
+
+    }
+
+
+
+
+
+
+    /*
+     * This translation is needed during unescape to support ill-formed escape codes for Windows 1252 codes
+     * instead of the correct unicode ones (for example, &#x80; for the euro symbol instead of &#x20aC;). This is
+     * something browsers do support, and included in the HTML5 spec for consuming character references.
+     * See http://www.w3.org/TR/html5/syntax.html#consume-a-character-reference
+     */
+    static int translateIllFormedCodepoint(final int codepoint) {
+        switch (codepoint) {
+            case 0x00: return 0xFFFD;
+            case 0x80: return 0x20AC;
+            case 0x82: return 0x201A;
+            case 0x83: return 0x0192;
+            case 0x84: return 0x201E;
+            case 0x85: return 0x2026;
+            case 0x86: return 0x2020;
+            case 0x87: return 0x2021;
+            case 0x88: return 0x02C6;
+            case 0x89: return 0x2030;
+            case 0x8A: return 0x0160;
+            case 0x8B: return 0x2039;
+            case 0x8C: return 0x0152;
+            case 0x8E: return 0x017D;
+            case 0x91: return 0x2018;
+            case 0x92: return 0x2019;
+            case 0x93: return 0x201C;
+            case 0x94: return 0x201D;
+            case 0x95: return 0x2022;
+            case 0x96: return 0x2013;
+            case 0x97: return 0x2014;
+            case 0x98: return 0x02DC;
+            case 0x99: return 0x2122;
+            case 0x9A: return 0x0161;
+            case 0x9B: return 0x203A;
+            case 0x9C: return 0x0153;
+            case 0x9E: return 0x017E;
+            case 0x9F: return 0x0178;
+            default: break;
+        }
+        if (codepoint >= 0xD800 && codepoint <= 0xDFFF) {
+            return 0xFFFD;
+        } else if (codepoint > 0x10FFFF) {
+            return 0xFFFD;
+        } else {
+          return codepoint;
+        }
+    }
+
+
+    /*
+     * This methods (the two versions) are used instead of Integer.parseInt(str,radix) in order to avoid the need
+     * to create substrings of the text being unescaped to feed such method.
+     * -  No need to check all chars are within the radix limits - reference parsing code will already have done so.
+     */
+
+    static int parseIntFromReference(final String text, final int start, final int end, final int radix) {
+        int result = 0;
+        for (int i = start; i < end; i++) {
+            final char c = text.charAt(i);
+            int n = -1;
+            for (int j = 0; j < HEXA_CHARS_UPPER.length; j++) {
+                if (c == HEXA_CHARS_UPPER[j] || c == HEXA_CHARS_LOWER[j]) {
+                    n = j;
+                    break;
+                }
+            }
+            result *= radix;
+            if (result < 0) {
+                return 0xFFFD;
+            }
+            result += n;
+            if (result < 0) {
+                return 0xFFFD;
+            }
+        }
+        return result;
+    }
+
+    static int parseIntFromReference(final char[] text, final int start, final int end, final int radix) {
+        int result = 0;
+        for (int i = start; i < end; i++) {
+            final char c = text[i];
+            int n = -1;
+            for (int j = 0; j < HEXA_CHARS_UPPER.length; j++) {
+                if (c == HEXA_CHARS_UPPER[j] || c == HEXA_CHARS_LOWER[j]) {
+                    n = j;
+                    break;
+                }
+            }
+            result *= radix;
+            if (result < 0) {
+                return 0xFFFD;
+            }
+            result += n;
+            if (result < 0) {
+                return 0xFFFD;
+            }
+        }
+        return result;
+    }
+
+
+
+
+
+
+
+
+
+    /*
+     * Perform an unescape operation based on String. Unescape operations are always based on the HTML5 symbol set.
+     * Unescape operations will be performed in the most similar way possible to the process a browser follows for
+     * showing HTML5 escaped code. See: http://www.w3.org/TR/html5/syntax.html#consume-a-character-reference
+     */
+    static String unescape(final String text) {
+
+        if (text == null) {
+            return null;
+        }
+
+        // Unescape will always cover the full HTML5 spectrum.
+        final HtmlEscapeSymbols symbols = HtmlEscapeSymbols.HTML5_SYMBOLS;
+        StringBuilder strBuilder = null;
+
+        final int offset = 0;
+        final int max = text.length();
+
+        int readOffset = offset;
+        int referenceOffset = offset;
+
+        for (int i = offset; i < max; i++) {
+
+            final char c = text.charAt(i);
+
+            /*
+             * Check the need for an unescape operation at this point
+             */
+
+            if (c != REFERENCE_PREFIX || (i + 1) >= max) {
+                continue;
+            }
+
+            int codepoint = 0;
+
+            if (c == REFERENCE_PREFIX) {
+
+                final char c1 = text.charAt(i + 1);
+
+                if (c1 == '\u0020' || // SPACE
+                    c1 == '\n' ||     // LF
+                    c1 == '\u0009' || // TAB
+                    c1 == '\u000C' || // FF
+                    c1 == '\u003C' || // LES-THAN SIGN
+                    c1 == '\u0026') { // AMPERSAND
+                    // Not a character references. No characters are consumed, and nothing is returned.
+                    continue;
+
+                } else if (c1 == REFERENCE_NUMERIC_PREFIX2) {
+
+                    if (i + 2 >= max) {
+                        // No reference possible
+                        continue;
+                    }
+
+                    final char c2 = text.charAt(i + 2);
+
+                    if ((c2 == REFERENCE_HEXA_PREFIX3_LOWER || c2 == REFERENCE_HEXA_PREFIX3_UPPER) && (i + 3) < max) {
+                        // This is a hexadecimal reference
+
+                        int f = i + 3;
+                        while (f < max) {
+                            final char cf = text.charAt(f);
+                            if (!((cf >= '0' && cf <= '9') || (cf >= 'A' && cf <= 'F') || (cf >= 'a' && cf <= 'f'))) {
+                                break;
+                            }
+                            f++;
+                        }
+
+                        if ((f - (i + 3)) <= 0) {
+                            // We weren't able to consume any hexa chars
+                            continue;
+                        }
+
+                        codepoint = parseIntFromReference(text, i + 3, f, 16);
+                        referenceOffset = f - 1;
+
+                        if ((f < max) && text.charAt(f) == REFERENCE_SUFFIX) {
+                            referenceOffset++;
+                        }
+
+                        codepoint = translateIllFormedCodepoint(codepoint);
+
+                        // Don't continue here, just let the unescape code below do its job
+
+                    } else if (c2 >= '0' && c2 <= '9') {
+                        // This is a decimal reference
+
+                        int f = i + 2;
+                        while (f < max) {
+                            final char cf = text.charAt(f);
+                            if (!(cf >= '0' && cf <= '9')) {
+                                break;
+                            }
+                            f++;
+                        }
+
+                        if ((f - (i + 2)) <= 0) {
+                            // We weren't able to consume any decimal chars
+                            continue;
+                        }
+
+                        codepoint = parseIntFromReference(text, i + 2, f, 10);
+                        referenceOffset = f - 1;
+
+                        if ((f < max) && text.charAt(f) == REFERENCE_SUFFIX) {
+                            referenceOffset++;
+                        }
+
+                        codepoint = translateIllFormedCodepoint(codepoint);
+
+                        // Don't continue here, just let the unescape code below do its job
+
+                    } else {
+                        // This is not a valid reference, just discard
+                        continue;
+                    }
+
+
+                } else {
+
+                    // This is a named reference, must be comprised only of ALPHABETIC chars
+
+                    int f = i + 1;
+                    while (f < max) {
+                        final char cf = text.charAt(f);
+                        if (!((cf >= 'a' && cf <= 'z') || (cf >= 'A' && cf <= 'Z') || (cf >= '0' && cf <= '9'))) {
+                            break;
+                        }
+                        f++;
+                    }
+
+                    if ((f - (i + 1)) <= 0) {
+                        // We weren't able to consume any alphanumeric
+                        continue;
+                    }
+
+                    if ((f < max) && text.charAt(f) == REFERENCE_SUFFIX) {
+                        f++;
+                    }
+
+                    final int ncrPosition = HtmlEscapeSymbols.binarySearch(symbols.SORTED_NCRS, text, i, f);
+                    if (ncrPosition >= 0) {
+                        codepoint = symbols.SORTED_CODEPOINTS[ncrPosition];
+                    } else if (ncrPosition == Integer.MIN_VALUE) {
+                        // Not found! Just ignore our efforts to find a match.
+                        continue;
+                    } else if (ncrPosition < -10) {
+                        // Found but partial!
+                        final int partialIndex = (-1) * (ncrPosition + 10);
+                        final char[] partialMatch = symbols.SORTED_NCRS[partialIndex];
+                        codepoint = symbols.SORTED_CODEPOINTS[partialIndex];
+                        f -= ((f - i) - partialMatch.length); // un-consume the chars remaining from the partial match
+                    } else {
+                        // Should never happen!
+                        throw new RuntimeException("Invalid unescape codepoint after search: " + ncrPosition);
+                    }
+
+                    referenceOffset = f - 1;
+
+                }
+
+            }
+
+
+            /*
+             * At this point we know for sure we will need some kind of unescape, so we
+             * can increase the offset and initialize the string builder if needed, along with
+             * copying to it all the contents pending up to this point.
+             */
+
+            if (strBuilder == null) {
+                strBuilder = new StringBuilder(max + 5);
+            }
+
+            if (i - readOffset > 0) {
+                strBuilder.append(text, readOffset, i);
+            }
+
+            i = referenceOffset;
+            readOffset = i + 1;
+
+            /*
+             * --------------------------
+             *
+             * Perform the real unescape
+             *
+             * --------------------------
+             */
+
+            if (codepoint > '\uFFFF') {
+                strBuilder.append(Character.toChars(codepoint));
+            } else if (codepoint < 0) {
+                // This is a double-codepoint unescape operation
+                final int[] codepoints = symbols.DOUBLE_CODEPOINTS[((-1) * codepoint) - 1];
+                if (codepoints[0] > '\uFFFF') {
+                    strBuilder.append(Character.toChars(codepoints[0]));
+                } else {
+                    strBuilder.append((char) codepoints[0]);
+                }
+                if (codepoints[1] > '\uFFFF') {
+                    strBuilder.append(Character.toChars(codepoints[1]));
+                } else {
+                    strBuilder.append((char) codepoints[1]);
+                }
+            } else {
+                strBuilder.append((char)codepoint);
+            }
+
+        }
+
+
+        /*
+         * -----------------------------------------------------------------------------------------------
+         * Final cleaning: return the original String object if no unescape was actually needed. Otherwise
+         *                 append the remaining escaped text to the string builder and return.
+         * -----------------------------------------------------------------------------------------------
+         */
+
+        if (strBuilder == null) {
+            return text;
+        }
+
+        if (max - readOffset > 0) {
+            strBuilder.append(text, readOffset, max);
+        }
+
+        return strBuilder.toString();
+
+    }
+
+
+
+
+
+
+    /*
+     * Perform an unescape operation based on a Reader, writing the results to a Writer. Unescape operations are
+     * always based on the HTML5 symbol set. Unescape operations will be performed in the most similar way
+     * possible to the process a browser follows for showing HTML5 escaped code.
+     * See: http://www.w3.org/TR/html5/syntax.html#consume-a-character-reference
+     *
+     * Note this reader is going to be read char-by-char, so some kind of buffering might be appropriate if this
+     * is an inconvenience for the specific Reader implementation.
+     */
+    static void unescape(final Reader reader, final Writer writer) throws IOException {
+
+        if (reader == null) {
+            return;
+        }
+
+        // Unescape will always cover the full HTML5 spectrum.
+        final HtmlEscapeSymbols symbols = HtmlEscapeSymbols.HTML5_SYMBOLS;
+
+        char[] escapes = new char[10];
+        int escapei = 0;
+
+        int c1, c2, ce; // c1: current char, c2: next char, ce: current escaped char
+
+        c2 = reader.read();
+
+        while (c2 >= 0) {
+
+            c1 = c2;
+            c2 = reader.read();
+
+            escapei = 0;
+
+            /*
+             * Check the need for an unescape operation at this point
+             */
+
+            if (c1 != REFERENCE_PREFIX || c2 < 0) {
+                writer.write(c1);
+                continue;
+            }
+
+            int codepoint = 0;
+
+            if (c1 == REFERENCE_PREFIX) {
+
+                if (c2 == '\u0020' || // SPACE
+                        c2 == '\n' ||     // LF
+                        c2 == '\u0009' || // TAB
+                        c2 == '\u000C' || // FF
+                        c2 == '\u003C' || // LES-THAN SIGN
+                        c2 == '\u0026') { // AMPERSAND
+                    // Not a character references. No characters are consumed, and nothing is returned.
+                    writer.write(c1);
+                    continue;
+
+                } else if (c2 == REFERENCE_NUMERIC_PREFIX2) {
+
+                    final int c3 = reader.read();
+
+                    if (c3 < 0) {
+                        // No reference possible
+                        writer.write(c1);
+                        writer.write(c2);
+                        c1 = c2;
+                        c2 = c3;
+                        continue;
+                    }
+
+                    if ((c3 == REFERENCE_HEXA_PREFIX3_LOWER || c3 == REFERENCE_HEXA_PREFIX3_UPPER)) {
+                        // This is a hexadecimal reference
+
+                        ce = reader.read();
+                        while (ce >= 0) {
+                            if (!((ce >= '0' && ce <= '9') || (ce >= 'A' && ce <= 'F') || (ce >= 'a' && ce <= 'f'))) {
+                                break;
+                            }
+                            if (escapei == escapes.length) {
+                                // too many escape chars for our array: grow it!
+                                final char[] newEscapes = new char[escapes.length + 4];
+                                System.arraycopy(escapes, 0, newEscapes, 0, escapes.length);
+                                escapes = newEscapes;
+                            }
+                            escapes[escapei] = (char) ce;
+                            ce = reader.read();
+                            escapei++;
+                        }
+
+                        if (escapei == 0) {
+                            // We weren't able to consume any hexa chars
+                            writer.write(c1);
+                            writer.write(c2);
+                            writer.write(c3);
+                            c1 = c3;
+                            c2 = ce;
+                            continue;
+                        }
+
+                        c1 = escapes[escapei - 1];
+                        c2 = ce;
+
+                        codepoint = parseIntFromReference(escapes, 0, escapei, 16);
+
+                        if (c2 == REFERENCE_SUFFIX) {
+                            // If the reference ends in a ';', just consume it
+                            c1 = c2;
+                            c2 = reader.read();
+                        }
+
+                        codepoint = translateIllFormedCodepoint(codepoint);
+
+                        escapei = 0;
+
+                        // Don't continue here, just let the unescape code below do its job
+
+                    } else if (c3 >= '0' && c3 <= '9') {
+                        // This is a decimal reference
+
+                        ce = c3;
+                        while (ce >= 0) {
+                            if (!(ce >= '0' && ce <= '9')) {
+                                break;
+                            }
+                            if (escapei == escapes.length) {
+                                // too many escape chars for our array: grow it!
+                                final char[] newEscapes = new char[escapes.length + 4];
+                                System.arraycopy(escapes, 0, newEscapes, 0, escapes.length);
+                                escapes = newEscapes;
+                            }
+                            escapes[escapei] = (char) ce;
+                            ce = reader.read();
+                            escapei++;
+                        }
+
+                        if (escapei == 0) {
+                            // We weren't able to consume any decimal chars
+                            writer.write(c1);
+                            writer.write(c2);
+                            c1 = c2;
+                            c2 = c3;
+                            continue;
+                        }
+
+                        c1 = escapes[escapei - 1];
+                        c2 = ce;
+
+                        codepoint = parseIntFromReference(escapes, 0, escapei, 10);
+
+                        if (c2 == REFERENCE_SUFFIX) {
+                            // If the reference ends in a ';', just consume it
+                            c1 = c2;
+                            c2 = reader.read();
+                        }
+
+                        codepoint = translateIllFormedCodepoint(codepoint);
+
+                        escapei = 0;
+
+                        // Don't continue here, just let the unescape code below do its job
+
+                    } else {
+                        // This is not a valid reference, just discard
+                        writer.write(c1);
+                        writer.write(c2);
+                        c1 = c2;
+                        c2 = c3;
+                        continue;
+                    }
+
+
+                } else {
+
+                    // This is a named reference, must be comprised only of ALPHABETIC chars
+
+                    ce = c2;
+                    while (ce >= 0) {
+                        if (!((ce >= '0' && ce <= '9') || (ce >= 'A' && ce <= 'Z') || (ce >= 'a' && ce <= 'z'))) {
+                            break;
+                        }
+                        if (escapei == escapes.length) {
+                            // too many escape chars for our array: grow it!
+                            final char[] newEscapes = new char[escapes.length + 4];
+                            System.arraycopy(escapes, 0, newEscapes, 0, escapes.length);
+                            escapes = newEscapes;
+                        }
+                        escapes[escapei] = (char) ce;
+                        ce = reader.read();
+                        escapei++;
+                    }
+
+                    if (escapei == 0) {
+                        // We weren't able to consume any decimal chars
+                        writer.write(c1);
+                        continue;
+                    }
+
+                    if (escapei + 2 >= escapes.length) {
+                        // the entire escape sequence does not fit: grow it!
+                        final char[] newEscapes = new char[escapes.length + 4];
+                        System.arraycopy(escapes, 0, newEscapes, 0, escapes.length);
+                        escapes = newEscapes;
+                    }
+
+                    System.arraycopy(escapes, 0, escapes, 1, escapei);
+                    escapes[0] = (char) c1;
+                    escapei++;
+
+                    if (ce == REFERENCE_SUFFIX) {
+                        // If the reference ends in a ';', just consume it
+                        escapes[escapei++] = (char) ce;
+                        ce = reader.read();
+                    }
+
+                    c1 = escapes[escapei - 1];
+                    c2 = ce;
+
+                    final int ncrPosition = HtmlEscapeSymbols.binarySearch(symbols.SORTED_NCRS, escapes, 0, escapei);
+                    if (ncrPosition >= 0) {
+                        codepoint = symbols.SORTED_CODEPOINTS[ncrPosition];
+                        escapei = 0;
+                    } else if (ncrPosition == Integer.MIN_VALUE) {
+                        // Not found! Just ignore our efforts to find a match.
+                        writer.write(escapes, 0, escapei);
+                        continue;
+                    } else if (ncrPosition < -10) {
+                        // Found but partial!
+                        final int partialIndex = (-1) * (ncrPosition + 10);
+                        final char[] partialMatch = symbols.SORTED_NCRS[partialIndex];
+                        codepoint = symbols.SORTED_CODEPOINTS[partialIndex];
+                        System.arraycopy(escapes, partialMatch.length, escapes, 0, (escapei - partialMatch.length));
+                        escapei -= partialMatch.length; // so that we know we have to output the rest of 'escapes'
+                    } else {
+                        // Should never happen!
+                        throw new RuntimeException("Invalid unescape codepoint after search: " + ncrPosition);
+                    }
+
+                }
+
+            }
+
+            /*
+             * --------------------------
+             *
+             * Perform the real unescape
+             *
+             * --------------------------
+             */
+
+            if (codepoint > '\uFFFF') {
+                writer.write(Character.toChars(codepoint));
+            } else if (codepoint < 0) {
+                // This is a double-codepoint unescape operation
+                final int[] codepoints = symbols.DOUBLE_CODEPOINTS[((-1) * codepoint) - 1];
+                if (codepoints[0] > '\uFFFF') {
+                    writer.write(Character.toChars(codepoints[0]));
+                } else {
+                    writer.write((char) codepoints[0]);
+                }
+                if (codepoints[1] > '\uFFFF') {
+                    writer.write(Character.toChars(codepoints[1]));
+                } else {
+                    writer.write((char) codepoints[1]);
+                }
+            } else {
+                writer.write((char)codepoint);
+            }
+
+            /*
+             * ----------------------------------------
+             * Cleanup, in case we had a partial match
+             * ----------------------------------------
+             */
+
+            if (escapei > 0) {
+                writer.write(escapes, 0, escapei);
+                escapei = 0;
+            }
+
+
+        }
+
+    }
+
+
+
+
+
+
+    /*
+     * Perform an unescape operation based on char[]. Unescape operations are always based on the HTML5 symbol set.
+     * Unescape operations will be performed in the most similar way possible to the process a browser follows for
+     * showing HTML5 escaped code. See: http://www.w3.org/TR/html5/syntax.html#consume-a-character-reference
+     */
+    static void unescape(final char[] text, final int offset, final int len, final Writer writer)
+                         throws IOException {
+
+        if (text == null) {
+            return;
+        }
+
+        final HtmlEscapeSymbols symbols = HtmlEscapeSymbols.HTML5_SYMBOLS;
+
+        final int max = (offset + len);
+
+        int readOffset = offset;
+        int referenceOffset = offset;
+
+        for (int i = offset; i < max; i++) {
+
+            final char c = text[i];
+
+            /*
+             * Check the need for an unescape operation at this point
+             */
+
+            if (c != REFERENCE_PREFIX || (i + 1) >= max) {
+                continue;
+            }
+
+            int codepoint = 0;
+
+            if (c == REFERENCE_PREFIX) {
+
+                final char c1 = text[i + 1];
+
+                if (c1 == '\u0020' || // SPACE
+                        c1 == '\n' ||     // LF
+                        c1 == '\u0009' || // TAB
+                        c1 == '\u000C' || // FF
+                        c1 == '\u003C' || // LES-THAN SIGN
+                        c1 == '\u0026') { // AMPERSAND
+                    // Not a character references. No characters are consumed, and nothing is returned.
+                    continue;
+
+                } else if (c1 == REFERENCE_NUMERIC_PREFIX2) {
+
+                    if (i + 2 >= max) {
+                        // No reference possible
+                        continue;
+                    }
+
+                    final char c2 = text[i + 2];
+
+                    if ((c2 == REFERENCE_HEXA_PREFIX3_LOWER || c2 == REFERENCE_HEXA_PREFIX3_UPPER) && (i + 3) < max) {
+                        // This is a hexadecimal reference
+
+                        int f = i + 3;
+                        while (f < max) {
+                            final char cf = text[f];
+                            if (!((cf >= '0' && cf <= '9') || (cf >= 'A' && cf <= 'F') || (cf >= 'a' && cf <= 'f'))) {
+                                break;
+                            }
+                            f++;
+                        }
+
+                        if ((f - (i + 3)) <= 0) {
+                            // We weren't able to consume any hexa chars
+                            continue;
+                        }
+
+                        codepoint = parseIntFromReference(text, i + 3, f, 16);
+                        referenceOffset = f - 1;
+
+                        if ((f < max) && text[f] == REFERENCE_SUFFIX) {
+                            referenceOffset++;
+                        }
+
+                        codepoint = translateIllFormedCodepoint(codepoint);
+
+                        // Don't continue here, just let the unescape code below do its job
+
+                    } else if (c2 >= '0' && c2 <= '9') {
+                        // This is a decimal reference
+
+                        int f = i + 2;
+                        while (f < max) {
+                            final char cf = text[f];
+                            if (!(cf >= '0' && cf <= '9')) {
+                                break;
+                            }
+                            f++;
+                        }
+
+                        if ((f - (i + 2)) <= 0) {
+                            // We weren't able to consume any decimal chars
+                            continue;
+                        }
+
+                        codepoint = parseIntFromReference(text, i + 2, f, 10);
+                        referenceOffset = f - 1;
+
+                        if ((f < max) && text[f] == REFERENCE_SUFFIX) {
+                            referenceOffset++;
+                        }
+
+                        codepoint = translateIllFormedCodepoint(codepoint);
+
+                        // Don't continue here, just let the unescape code below do its job
+
+                    } else {
+                        // This is not a valid reference, just discard
+                        continue;
+                    }
+
+
+                } else {
+
+                    // This is a named reference, must be comprised only of ALPHABETIC chars
+
+                    int f = i + 1;
+                    while (f < max) {
+                        final char cf = text[f];
+                        if (!((cf >= 'a' && cf <= 'z') || (cf >= 'A' && cf <= 'Z') || (cf >= '0' && cf <= '9'))) {
+                            break;
+                        }
+                        f++;
+                    }
+
+                    if ((f - (i + 1)) <= 0) {
+                        // We weren't able to consume any alphanumeric
+                        continue;
+                    }
+
+                    if ((f < max) && text[f] == REFERENCE_SUFFIX) {
+                        f++;
+                    }
+
+                    final int ncrPosition = HtmlEscapeSymbols.binarySearch(symbols.SORTED_NCRS, text, i, f);
+                    if (ncrPosition >= 0) {
+                        codepoint = symbols.SORTED_CODEPOINTS[ncrPosition];
+                    } else if (ncrPosition == Integer.MIN_VALUE) {
+                        // Not found! Just ignore our efforts to find a match.
+                        continue;
+                    } else if (ncrPosition < -10) {
+                        // Found but partial!
+                        final int partialIndex = (-1) * (ncrPosition + 10);
+                        final char[] partialMatch = symbols.SORTED_NCRS[partialIndex];
+                        codepoint = symbols.SORTED_CODEPOINTS[partialIndex];
+                        f -= ((f - i) - partialMatch.length); // un-consume the chars remaining from the partial match
+                    } else {
+                        // Should never happen!
+                        throw new RuntimeException("Invalid unescape codepoint after search: " + ncrPosition);
+                    }
+
+                    referenceOffset = f - 1;
+
+                }
+
+            }
+
+
+            /*
+             * At this point we know for sure we will need some kind of unescape, so we
+             * write all the contents pending up to this point.
+             */
+
+            if (i - readOffset > 0) {
+                writer.write(text, readOffset, (i - readOffset));
+            }
+
+            i = referenceOffset;
+            readOffset = i + 1;
+
+            /*
+             * --------------------------
+             *
+             * Perform the real unescape
+             *
+             * --------------------------
+             */
+
+            if (codepoint > '\uFFFF') {
+                writer.write(Character.toChars(codepoint));
+            } else if (codepoint < 0) {
+                // This is a double-codepoint unescape operation
+                final int[] codepoints = symbols.DOUBLE_CODEPOINTS[((-1) * codepoint) - 1];
+                if (codepoints[0] > '\uFFFF') {
+                    writer.write(Character.toChars(codepoints[0]));
+                } else {
+                    writer.write((char) codepoints[0]);
+                }
+                if (codepoints[1] > '\uFFFF') {
+                    writer.write(Character.toChars(codepoints[1]));
+                } else {
+                    writer.write((char) codepoints[1]);
+                }
+            } else {
+                writer.write((char) codepoint);
+            }
+
+        }
+
+
+        /*
+         * -----------------------------------------------------------------------------------------------
+         * Final cleaning: writer the remaining escaped text and return.
+         * -----------------------------------------------------------------------------------------------
+         */
+
+        if (max - readOffset > 0) {
+            writer.write(text, readOffset, (max - readOffset));
+        }
+
+    }
+
+
+
+
+    private static int codePointAt(final char c1, final char c2) {
+        if (Character.isHighSurrogate(c1)) {
+            if (c2 >= 0) {
+                if (Character.isLowSurrogate(c2)) {
+                    return Character.toCodePoint(c1, c2);
+                }
+            }
+        }
+        return c1;
+    }
+
+
+
+}
+
diff --git a/app/src/main/java/ohi/andre/consolelauncher/tuils/interfaces/CommandExecuter.java b/app/src/main/java/ohi/andre/consolelauncher/tuils/interfaces/CommandExecuter.java
index d9a82bb..f6a0c80 100755
--- a/app/src/main/java/ohi/andre/consolelauncher/tuils/interfaces/CommandExecuter.java
+++ b/app/src/main/java/ohi/andre/consolelauncher/tuils/interfaces/CommandExecuter.java
@@ -5,7 +5,8 @@ package ohi.andre.consolelauncher.tuils.interfaces;
  */
 public interface CommandExecuter {
 
-    String exec(String aliasValue, String aliasName);
-    String exec(String input);
-    String exec(String input, boolean needWriteInput);
+    void exec(String aliasValue, String aliasName);
+    void exec(String input);
+    void exec(String input, boolean needWriteInput);
+    void exec(String input, Object obj);
 }
diff --git a/app/src/main/res/menu/notification_menu.xml b/app/src/main/res/menu/notification_menu.xml
new file mode 100644
index 0000000..62cd80c
--- /dev/null
+++ b/app/src/main/res/menu/notification_menu.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<menu xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:id="@+id/exclude_app" android:title="@string/exclude_app"/>
+    <item android:id="@+id/exclude_notification" android:title="@string/exclude_notification"/>
+</menu>
\ No newline at end of file
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 2241b0b..4467be3 100755
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -6,18 +6,22 @@
     <string name="location_off">Turn on GPS or network location</string>
     <string name="share_label">Share</string>
     <string name="output_about">Francesco Andreuzzi (Italy)\n\t-> Programmer
-        \n\nLuke Winward (USA)\n\t-> Idea and design
-        \n\nAlexander King (Australia)\n\t-> t-ui theme website and db management</string>
+        \n\nLuke Winward (USA)\n\t-> Idea and design</string>
     <string name="output_refresh">Refresh: apps, alias, music, contacts, rss feeds</string>
     <string name="output_rate">Thank you!</string>
     <string name="start_notification">T-UI started</string>
     <string name="tui_running">T-UI is running</string>
     <string name="anr">t-ui is having some issues. Please send to the developer your file crash.txt in the "t-ui" folder</string>
     <string name="admin_permission">Lock the screen on double tap</string>
+    <string name="translation_not_found">Translation not found</string>
+
+    <!-- notifications menu -->
+    <string name="exclude_notification">Exclude this notification</string>
+    <string name="exclude_app">Exclude app</string>
+    <string name="notification_service_not_running">The notification service is\'t running</string>
 
     <!-- regex -->
-    <string name="regex_not_found">Couldn\'t find a Regex with this ID</string>
-    <string name="regex_exists">An other Regex is already using this ID</string>
+    <string name="invalid_regex">Invalid regex:</string>
 
     <!-- theme -->
     <string name="theme_not_found">Theme not found</string>
@@ -57,6 +61,7 @@
     <string name="hint_config">Are you having doubts about any config option? Use the cmd \"$ config -tutorial\" and look for that option inside the table</string>
     <string name="hint_alias">Did you know that t-ui supports aliases? It also supports parameterized aliases.\nFor more info, use the cmd \"$ alias -tutorial\"</string>
     <string name="hint_musicdisable">Do you want to make t-ui lighter? Use the cmd \"$ config -set enable_music false\" to disable the music player and save resources</string>
+    <string name="hint_excludenotification">Did you know? You can exclude an unwanted notification long-clicking on it</string>
 
     <string name="hint_disable">You can disable this messages with the cmd \"$ config -set show_hints false\"</string>
 
@@ -91,7 +96,11 @@
     <string name="rss_not_found">Invalid ID: no RSS feed found</string>
     <string name="id_already">This ID has already been used</string>
     <string name="id_notfound">Invalid ID</string>
-
+    <string name="rss_never_checked">This RSS feed hasn\'t been checked yet</string>
+    <string name="rss_invalid_timeformat">The time format couldn\'t be parsed</string>
+    <string name="rss_invalid_date">Invalid publication date tag:</string>
+    <string name="rss_invalid_entry_tag">Invalid entry tag:</string>
+    <string name="rss_invalid_empty">Invalid RSS: the file is empty:</string>
 
     <!-- alias -->
     <string name="output_aliasnotfound">Alias not found:</string>
@@ -189,9 +198,10 @@
     </string>
     <string name="help_config">-set [option] [value] -> set the value of an option
         \n-append [option] [value] -> append the given string to the value of the selected option
-        \n-file [file] -> open a config file
+        \n-file [file] -> open a config file (behavior.xml, ui.xml, theme.xml, ...)
         \n-get [option] -> get the value of an option
         \n-reset [option] -> reset the value of an option
+        \n-info [option] -> request info about the given option
         \n-apply [file] -> move a file to the t-ui directory
         \n-tutorial -> open the tutorial page
     </string>
@@ -268,12 +278,15 @@
         \n$ beep</string>
     <string name="help_notifications">-inc [appName] -> include an application
         \n-exc [appName] -> exclude an application
-        \n-clr [color] [appName] -> set the color to be used for the application
+        \n-color [color] [appName] -> set the color to be used for the application
+        \n-format [ID] [appName] -> apply the format with the given ID to the corresponding application
+        \n-add_filter [ID] [filter] -> create a new filter with the given ID
+        \n-add_format [ID] [format] -> create a new format with the given ID
+        \n-rm_filter [ID] -> delete the filter having the given ID
+        \n-rm_format [ID] -> delete the format having the given ID
+        \n-access -> show the system settings page dedicated to the Notification Access
         \n-file -> open notifications.xml
-        \n-title_filter [ID] [regex] -> set a filter over notifications title with a given ID
-        \n-text_filter [ID] [regex] -> set a filter over notifications text with a given ID
-        \n-apply_filter [ID] [appName] -> apply a filter (or a group of filters) to a single application
-        \n-access -> show the system settings page dedicated to the Notification Access</string>
+        \n-tutorial -> show the tutorial page</string>
     <string name="help_location">Show your current location</string>
     <string name="help_cntcts">-ls -> list your contacts
         \n-l [contactName] -> show details about a contact
@@ -286,18 +299,22 @@
         \n-ls -> list your RSS feeds
         \n-l [ID] -> show the whole content of the corresponding RSS feed
         \n-show [ID] [boolean] -> toggle the [show] property of the given saved RSS feed
-        \n-time [ID] [update_time_in_seconds] -> set the update time of the corresponding RSS feed
+        \n-update_time [ID] [update_time_in_seconds] -> set the update time of the corresponding RSS feed
         \n-format [ID] [format] -> set the format of the corresponding RSS feed ([format] can be both a string or the ID of an existing format)
         \n-color [ID] [color] -> set the base color of the corresponding RSS feed
         \n-wifi_only [ID] [boolean] -> if [boolean] is true, the corresponding feed will be updated only if your device is connected to a WiFi network
         \n-last_check [ID] -> show the last time t-ui checked this RSS feed
-        \n-frc [ID] -> update the corresponding RSS feed and eventually show new updates
+        \n-entry_tag [ID] -> set the base tag for every single entry (default: \"item\")
+        \n-date_tag [ID] [tag] -> set the tag which holds info about the publication date (default: \"pubDate\")
+        \n-add_command [ID] [IDs (comma separated)] [regex] [cmd] -> create a new regex command that will be applied on the RSS feeds corresponding to IDs
+        \n-rm_command [ID] -> rm the corresponding regex command
+        \n-frc [ID] -> update the corresponding RSS feed
         \n-info [ID] -> show info about the corresponding RSS feed settings
         \n-include_if_matches [ID] [regex] -> if the given regex matches on an RSS feed item, it will be shown ([regex] can be both a string or the ID of a regex saved inside regex.xml)
         \n-exclude_if_matches [ID] [regex] -> if the given regex matches on an RSS feed item, it won\'t be shown ([regex] can be both a string or the ID of a regex saved inside regex.xml)
         \n-add_format [ID] [format] -> create a new format that you will be able to use for more than one RSS feed
         \n-rm_format [ID] [format] -> remove an existing format
-        \n-file -> open the file RSS.xml</string>
+        \n-file -> open the file rss.xml</string>
 
     <!-- linux -->
     <string name="help_ctrlc">Interrupt the current shell process and create a new one</string>
diff --git a/build.gradle b/build.gradle
index 5bbec01..8682043 100644
--- a/build.gradle
+++ b/build.gradle
@@ -17,6 +17,7 @@ task clean(type: Delete) {
 
 allprojects {
     repositories {
+        jcenter()
         maven { url "https://jitpack.io" }
     }
 }
-- 
GitLab