From e51f4a713ed6e744c203c9493165584728a29c52 Mon Sep 17 00:00:00 2001
From: Alejandro Acuña <alejandro.acuna@aluvisagrupo.com>
Date: Fri, 25 Oct 2024 07:06:35 +0000
Subject: [PATCH] server library

---
 servers/server/src/art/servers/controller/ControllerNtpHttp.java                   |  232 +
 servers/server/src/art/servers/gui/components/PanelProcess.java                    |  123 
 .gitignore                                                                         |    3 
 servers/server/src/art/servers/types/HttpStatus.java                               |    6 
 servers/server/src/art/servers/controller/ListenerImplementation.java              | 1791 +++++++
 servers/server/src/art/servers/gui/components/PanelTraces.java                     |  531 ++
 servers/server/src/art/servers/controller/ControllerListenerHttpWeb.java           |  637 ++
 servers/server/src/art/servers/types/HttpAuthentication.java                       |  190 
 servers/server/src/art/servers/types/HttpToken.java                                |   49 
 servers/server/src/art/servers/controller/ControllerListenerWEB.java               |  260 +
 servers/server/src/art/servers/configuration/ConfigurationMessages.java            |   32 
 servers/server/src/art/servers/Shared.java                                         |  684 +++
 servers/server/src/art/servers/gui/components/PanelClock.java                      |   72 
 servers/server/src/art/servers/configuration/Configuration.java                    |  165 
 servers/server/src/art/servers/controller/ControllerListener.java                  |  462 ++
 servers/server/src/art/servers/controller/ControllerDatabase.java                  |  687 +++
 servers/server/src/art/servers/controller/ControllerListenerHttpsWeb.java          |  109 
 servers/server/src/art/servers/gui/components/PanelGeneric.java                    |   30 
 servers/server/src/art/servers/controller/ControllerTransactions.java              |  271 +
 servers/server/src/art/servers/Model.java                                          | 2190 +++++++++
 servers/server/src/art/servers/configuration/ConfigurationListenerDEBUG.java       |   48 
 servers/server/src/art/servers/controller/FactoryController.java                   |  110 
 servers/server/src/art/servers/gui/components/PanelProcess_Information.java        |  236 +
 servers/server/src/art/servers/ServerException.java                                |   36 
 servers/server/src/art/servers/configuration/ConfigurationListenerHttp.java        |   58 
 servers/server/src/art/servers/controller/ControllerListenerHttps.java             |  142 
 servers/server/src/art/servers/controller/ControllerListenerHttp.java              |  798 +++
 servers/server/src/art/servers/controller/ControllerUserPermissions.java           |  216 
 servers/server/src/art/servers/types/IPv4.java                                     |   47 
 servers/server/src/art/servers/configuration/ConfigurationNtpHttp.java             |   39 
 servers/server/src/art/servers/controller/ControllerProcessInformation.java        |  264 +
 servers/server/src/art/servers/controller/http/webpages/Page.java                  |  573 ++
 servers/server/src/art/servers/controller/ControllerStatus.java                    |  354 +
 servers/server/src/art/servers/gui/ArticPanel.java                                 |  178 
 servers/server/src/art/servers/configuration/ConfigurationTransactions.java        |   20 
 servers/server/src/art/servers/configuration/ConfigurationTransactionsService.java |   21 
 servers/server/src/art/servers/controller/ControllerDevice.java                    |   20 
 servers/server/src/art/servers/gui/ArticWindow.java                                |  442 +
 servers/server/src/art/servers/configuration/ConfigurationListener.java            |   32 
 servers/server/src/art/servers/gui/components/PanelProcess_Chart.java              |  140 
 servers/server/src/server.version.properties                                       |    7 
 servers/server/src/art/servers/configuration/ConfigurationSecurity.java            |   40 
 servers/server/src/art/servers/Server.java                                         |  450 ++
 servers/server/src/art/servers/configuration/ConfigurationGeneral.java             |   38 
 servers/server/src/art/servers/gui/components/PanelTracesHistorical.java           |  231 +
 servers/server/src/art/servers/controller/ControllerListenerDebug.java             |  373 +
 servers/server/src/art/servers/controller/Controller.java                          |   28 
 servers/server/src/art/servers/types/HttpTokenException.java                       |    6 
 48 files changed, 13,471 insertions(+), 0 deletions(-)

diff --git a/.gitignore b/.gitignore
index 622c487..b69eb50 100644
--- a/.gitignore
+++ b/.gitignore
@@ -47,3 +47,6 @@
 servers/gost-access-server/data/art.servers.gost-access-server/atex5/
 servers/gost-access-server/manifest.mf
 servers/gost-access-server - copia/
+servers/server/build/
+servers/server/nbproject/
+servers/server/build.xml
diff --git a/servers/server/src/art/servers/Model.java b/servers/server/src/art/servers/Model.java
new file mode 100644
index 0000000..886b8b3
--- /dev/null
+++ b/servers/server/src/art/servers/Model.java
@@ -0,0 +1,2190 @@
+package art.servers;
+
+import art.library.gui.flat.FlatDialog;
+import art.library.interop.serialization.Serialization;
+import art.library.model.devices.Device;
+import art.library.model.devices.DeviceAction;
+import art.library.model.devices.DeviceInformation;
+import art.library.model.devices.DevicePersistenceAction;
+import art.library.model.devices.DevicePersistenceHistorical;
+import art.library.model.devices.DevicePersistenceTimeless;
+import art.library.model.devices.DeviceRealtime;
+import art.library.model.devices.DeviceSymbol;
+import art.library.model.devices.application.Application;
+import art.library.model.devices.colors.controller.RTZ32.types.eventstrolley.EventTrolley;
+import art.library.model.devices.colors.controller.RTZ32.types.eventstrolley.EventTrolleyResult;
+import art.library.model.transactions.traces.Trace;
+import art.library.model.transactions.traces.TracePersistance;
+import art.library.model.transactions.traces.TraceResult;
+import art.library.persistence.Persistence;
+import art.library.utils.resources.Resources;
+import art.library.utils.synchro.Mutex;
+import art.servers.configuration.Configuration;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.lang.reflect.Array;
+import java.lang.reflect.Constructor;
+import java.nio.file.Files;
+import java.rmi.ServerException;
+import java.sql.ResultSet;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Calendar;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+
+public abstract class Model 
+{
+    public String filename = null;
+    public String deviceClassName = null;
+    public String deviceInformationClassName = null;
+    
+    protected List<Device> ldevice = new ArrayList<Device>();
+    protected List<DeviceSymbol> lsymbols = new ArrayList<DeviceSymbol>();
+    protected HashMap<String, Device> mdevice = new HashMap<String, Device>();
+    protected long configurationSymbolsTimestamp = 0;
+    protected Mutex mutexListDevices = new Mutex();
+    protected Mutex mutexListSymbols = new Mutex();
+    protected HashMap<String, Mutex> mmutex = new HashMap<String, Mutex>();
+    
+    
+
+    public Model(Configuration configuration) throws Exception
+    {
+    }
+
+    
+    
+    public Model(Configuration configuration, String filename, String deviceClassName, String deviceInformationClassName) throws Exception
+    {
+        this.filename = filename;
+        this.deviceClassName = deviceClassName;
+        this.deviceInformationClassName = deviceInformationClassName;
+        readSymbols();
+        configurationSymbolsTimestamp = System.currentTimeMillis();
+        readDevices();
+    }    
+    
+
+    
+    // <editor-fold defaultstate="collapsed" desc="Devices">
+    
+
+    public void clearDevices()
+    {
+        mutexListDevices.lockWrite();
+        {
+            ldevice.clear();
+            mdevice.clear();
+        }
+        mutexListDevices.releaseWrite();
+    }
+    
+    
+    public void readDevices()
+    {
+        if (filename == null) return;
+            
+        mutexListDevices.lockWrite();
+        
+        try
+        {
+            
+            ldevice.clear();
+            mdevice.clear();
+
+            // Read data from database file (--restore)
+            
+            if (Shared.restoreDevices == true)
+            {
+                Class clazzDevice = Class.forName(deviceClassName);
+                Class<?> clazzArray = (Class<?>)Array.newInstance(clazzDevice, 0).getClass();
+                List<Device> ldevice = (List<Device>)Serialization.deserialize(clazzArray, new File(art.servers.Shared.getApplicationName() + "."  + filename + ".database.json"));
+
+                for (Device device : ldevice)
+                {
+                    if ((device instanceof Device) && (device.information.serverPort == Shared.configuration.listener.port) && (device.information.serverAddress.equalsIgnoreCase(Shared.configuration.listener.address)))
+                    {
+                        device.information.serverAddress = Shared.configuration.listener.address;
+                        device.information.serverPort = Shared.configuration.listener.port;
+                        device.information.serverAddressExternal = Shared.configuration.listener.addressExternal;
+                        device.information.serverPortExternal = Shared.configuration.listener.portExternal;
+                        this.ldevice.add(device);
+                        this.mdevice.put(device.getIdentifier(), device);
+                    }
+                }
+            }
+            
+            // Read data from database
+            
+            else if ((Shared.controllerDatabase != null) &&  (Shared.reloadDevices == false))
+            {
+                Class clazzDevice = Class.forName(deviceClassName);
+                
+                List<Device> ldevice = (List<Device>)DevicePersistenceTimeless.getDevices((List<Object>)(List<?>)Shared.controllerDatabase.timeless_getObject(DevicePersistenceTimeless.class.getName(), "type = '" + clazzDevice.getName() + "'"));
+
+                for (Device device : ldevice)
+                {
+                    try
+                    {
+                        if ((device instanceof Device) && (device.information.serverPort == Shared.configuration.listener.port) && (device.information.serverAddress.equalsIgnoreCase(Shared.configuration.listener.address)))
+                        {
+                            device.information.serverAddress = Shared.configuration.listener.address;
+                            device.information.serverPort = Shared.configuration.listener.port;
+                            device.information.serverAddressExternal = Shared.configuration.listener.addressExternal;
+                            device.information.serverPortExternal = Shared.configuration.listener.portExternal;
+                            this.ldevice.add(device);
+                            this.mdevice.put(device.getIdentifier(), device);
+                        }
+                    }
+                    catch (Exception exception)
+                    {
+                        Shared.println(device.getIdentifier(), exception.getMessage());
+                    }
+                }
+            }
+            
+        }
+        catch (Exception exception)
+        {   
+            exception.printStackTrace();
+            StringWriter sw = new StringWriter();
+            exception.printStackTrace(new PrintWriter(sw));
+            FlatDialog.showDialog(null, Shared.getMessage("Error"), exception.getMessage() + "\n\n" + sw.toString(), true, FlatDialog.DIALOG_INFORMATION);
+            System.exit(0);
+        }
+
+
+      
+        
+        try
+        {
+            Class clazzDevice = Class.forName(deviceClassName);
+            Class clazzInformation = Class.forName(deviceInformationClassName);
+            
+            DeviceInformation[] ldeviceInformation = null;
+
+            if (new File(Shared.getApplicationName() + "." + filename + ".json").exists())
+            {
+                Class<?> clazzArray = (Class<?>)Array.newInstance(clazzInformation, 0).getClass();
+                ldeviceInformation = Serialization.deserialize(clazzArray, new File(Shared.getApplicationName() + "."  + filename + ".json"));
+            }
+            
+
+            for (DeviceInformation deviceInformation : ldeviceInformation)
+            {
+                if (mdevice.containsKey(deviceInformation.getIdentifier()) == false)
+                {
+                    addDevice(clazzDevice, deviceInformation);
+                }
+            }        
+        }
+        catch (Exception exception)
+        {
+            exception.printStackTrace();
+            StringWriter sw = new StringWriter();
+            exception.printStackTrace(new PrintWriter(sw));
+            FlatDialog.showDialog(null, Shared.getMessage("Error"), exception.getMessage() + "\n\n" + sw.toString(), true, FlatDialog.DIALOG_INFORMATION);
+            System.exit(0);
+        }       
+        
+        
+        
+        for (Device device : ldevice)
+        {
+            device.information.serverServiceName = art.servers.Shared.controllerStatus.getApplication().getDeviceInformation().serverServiceName;
+        }
+        
+        
+        // Sort 
+
+        Collections.sort(ldevice, new Comparator<Device>() 
+        {
+            public int compare(Device device1, Device device2) 
+            {
+               return Integer.valueOf(device1.information.number).compareTo(device2.information.number);
+            }
+        });        
+        
+        
+        // Database file
+        
+        if (Shared.restoreDevices == false)
+        {
+            try
+            {
+
+                FileOutputStream fos = new FileOutputStream(new File(art.servers.Shared.getApplicationName() + "."  + filename + ".database.json"));
+
+                fos.write("[\n".getBytes());
+
+                for (Device device : ldevice)
+                {
+                    fos.write(Serialization.toPrettyString(device).getBytes());
+                    if (device != ldevice.get(ldevice.size() - 1)) fos.write(",".getBytes());
+                }
+
+                fos.write("]\n".getBytes());
+                fos.close();
+            }
+            catch (Exception e)
+            {
+            }
+        }
+        
+        
+        mutexListDevices.releaseWrite();
+
+    }
+
+    
+    
+    
+    
+
+    protected void addDevice(Class clazzDevice, DeviceInformation information) throws Exception
+    {
+        Device device = mdevice.get(information.getIdentifier());
+
+        long timestamp = System.currentTimeMillis();
+        
+        if (device == null)
+        {
+            Constructor<?> constructor = clazzDevice.getConstructor(String.class);
+            Object object = constructor.newInstance(new Object[]{information.getIdentifier()});
+            device = (Device)object;
+            device.information = information;
+            device.information.setCreationTimestamp(timestamp);
+            device.information.serverAddress = Shared.configuration.listener.address;
+            device.information.serverPort = Shared.configuration.listener.port;
+            device.information.serverAddressExternal = Shared.configuration.listener.addressExternal;
+            device.information.serverPortExternal = Shared.configuration.listener.portExternal;
+            device.setLastTimestampInformationUpdate(timestamp);
+            if (Shared.controllerDatabase != null)
+            {
+                Shared.controllerDatabase.timeless_updateOrAddObject(new DevicePersistenceTimeless(device));
+
+                DevicePersistenceHistorical deviceHistorical = new DevicePersistenceHistorical(device);
+
+                try
+                {
+                    Shared.controllerDatabase.historical_addOrUpdateObject(deviceHistorical);
+                }
+                catch (org.postgresql.util.PSQLException exception)
+                {
+                    if ((exception.getMessage().toUpperCase().indexOf("NO PARTITION OF RELATION") > -1) ||
+                        (exception.getMessage().toUpperCase().indexOf("NO SE ENCONTRÓ UNA PARTICIÓN") > -1))
+                    {
+                        Calendar calendar1 = Calendar.getInstance();
+                        calendar1.setTimeInMillis(device.getLastTimestampUpdate());
+                        calendar1.set(Calendar.DATE, 1);
+                        calendar1.set(Calendar.HOUR_OF_DAY, 0);
+                        calendar1.set(Calendar.MINUTE, 0);
+                        calendar1.set(Calendar.SECOND, 0);
+                        calendar1.set(Calendar.MILLISECOND, 0);
+
+                        SimpleDateFormat formato1 = new SimpleDateFormat("yyyy_MM");
+
+                        String tablename = "devices_" + formato1.format(calendar1.getTimeInMillis());
+                        long startdate = calendar1.getTimeInMillis();
+                        calendar1.add(Calendar.MONTH, 1);
+                        long enddate = calendar1.getTimeInMillis();
+
+                        String query1 = "CREATE TABLE IF NOT EXISTS " + tablename + " PARTITION OF devices FOR VALUES FROM ('" + startdate + "') TO ('" + enddate + "')";
+                        try{Shared.controllerDatabase.historical_update(query1);} catch (Exception e){};
+                        executeAlterTableDevicesVacuum(true, tablename);
+
+                        // Do again the insert
+                        try
+                        {
+                            Shared.controllerDatabase.historical_addOrUpdateObject(deviceHistorical);
+                        }
+                        catch (Exception e)
+                        {
+                            Shared.println(Shared.getMessage("Model"), e);
+                        }
+                    }
+                }
+            }
+            
+            mdevice.put(device.getIdentifier(), device);
+            ldevice.add(device);
+        }
+        else
+        {
+            if (Serialization.equals(device.information, information) == false)
+            {
+                device.information = information;
+                device.setLastTimestampInformationUpdate(timestamp);
+                Shared.controllerDatabase.timeless_updateOrAddObject(new DevicePersistenceTimeless(device));
+
+                try
+                {
+                    Shared.controllerDatabase.historical_addOrUpdateObject(new DevicePersistenceHistorical(device));
+                }
+                catch (org.postgresql.util.PSQLException exception)
+                {
+                    if ((exception.getMessage().toUpperCase().indexOf("NO PARTITION OF RELATION") > -1) ||
+                        (exception.getMessage().toUpperCase().indexOf("NO SE ENCONTRÓ UNA PARTICIÓN") > -1))
+                    {
+                        Calendar calendar1 = Calendar.getInstance();
+                        calendar1.setTimeInMillis(device.getLastTimestampUpdate());
+                        calendar1.set(Calendar.DATE, 1);
+                        calendar1.set(Calendar.HOUR_OF_DAY, 0);
+                        calendar1.set(Calendar.MINUTE, 0);
+                        calendar1.set(Calendar.SECOND, 0);
+                        calendar1.set(Calendar.MILLISECOND, 0);
+
+                        SimpleDateFormat formato1 = new SimpleDateFormat("yyyy_MM");
+
+                        String tablename = "devices_" + formato1.format(calendar1.getTimeInMillis());
+                        long startdate = calendar1.getTimeInMillis();
+                        calendar1.add(Calendar.MONTH, 1);
+                        long enddate = calendar1.getTimeInMillis();
+
+                        String query1 = "CREATE TABLE IF NOT EXISTS " + tablename + " PARTITION OF devices FOR VALUES FROM ('" + startdate + "') TO ('" + enddate + "')";
+                        try{Shared.controllerDatabase.historical_update(query1);} catch (Exception e){};
+                        executeAlterTableDevicesVacuum(true, tablename);
+
+                        // Do again the insert
+                        try
+                        {
+                            Shared.controllerDatabase.historical_addOrUpdateObject(new DevicePersistenceHistorical(device));
+                        }
+                        catch (Exception e)
+                        {
+                            Shared.println(Shared.getMessage("Model"), e);
+                        }
+                    }
+                }
+            }
+        }
+    }
+    
+
+    public void addDevices(DeviceInformation[] linformation) throws Exception
+    {
+        // Es ineficiente, pero hay que tener en cuenta que es una operación residual
+        
+        mutexListDevices.lockWrite();
+        
+        try
+        {
+            for (DeviceInformation information : linformation)
+            {
+                addDevice(Class.forName(this.deviceClassName), information);
+            }
+            
+            Collections.sort(ldevice, new Comparator<Device>() 
+            {
+                public int compare(Device device1, Device device2) 
+                {
+                   return Integer.valueOf(device1.information.number).compareTo(device2.information.number);
+                }
+            });
+            
+        }
+        finally
+        {
+            mutexListDevices.releaseWrite();
+        }
+    }
+    
+    
+
+    public boolean existsDevice(String identifier)
+    {
+        mutexListDevices.lockRead();
+        
+        try
+        {
+            return (mdevice.containsKey(identifier));
+        }
+        finally
+        {
+            mutexListDevices.releaseRead();
+        }
+    }    
+
+    
+    
+    
+    
+    public Device getDevice(String classname, int number)
+    {
+        for (Device device : ldevice)
+        {
+            if ((device.getClassName().equalsIgnoreCase(classname)) && (device.getDeviceInformation().number == number))
+            {
+                return device;
+            }
+        }
+        
+        return null;
+    }
+
+    
+    
+
+    public Device getDevice(String identifier) throws ServerException
+    {
+        mutexListDevices.lockRead();
+        
+        try
+        {
+            Device device = mdevice.get(identifier);
+
+            if (device == null) 
+            {
+                throw new ServerException("Device does not exists");
+            }
+
+            return device;
+        }
+        finally
+        {
+            mutexListDevices.releaseRead();
+        }
+    }    
+
+    
+    
+    
+    public Device[] getDevices()
+    {
+        mutexListDevices.lockRead();
+        
+        try
+        {
+            return ldevice.toArray(new Device[ldevice.size()]);
+        }
+        finally
+        {
+            mutexListDevices.releaseRead();
+        }
+    }
+
+    
+    
+    
+    public Device[] getDevicesCopy()
+    {
+        mutexListDevices.lockRead();
+        
+        try
+        {
+            List<Device> result = new ArrayList<Device>();
+            for (Device device : ldevice)
+            {
+                Device clone = Serialization.clone(device);
+                clone.realtime = device.getDeviceRealtime();
+                result.add(clone);
+            }
+            return result.toArray(new Device[result.size()]);
+        }
+        finally
+        {
+            mutexListDevices.releaseRead();
+        }
+    }
+    
+    
+        
+
+    public List<Device> getDevices(String group)
+    {
+        mutexListDevices.lockRead();
+
+        try
+        {        
+            List<Device> result = new ArrayList<Device>();
+
+            for (Device device : ldevice)
+            {
+                try
+                {
+                    if (device.getDeviceInformation().group.equalsIgnoreCase(group))
+                    {
+                        result.add(device);
+                    }
+                }
+                catch (Exception e)
+                {
+                }
+            }
+
+            return result;
+            
+        }
+        finally
+        {
+            mutexListDevices.releaseRead();
+        }
+    }
+
+    
+    
+    
+    public Device[] getDevices(String[] lgroup)
+    {
+        if (lgroup == null)
+        {
+            return new Device[0];
+        }
+        
+        if (lgroup.length == 0)
+        {
+            return new Device[0];
+        }
+        
+
+        mutexListDevices.lockRead();
+        
+        try
+        {
+            List<Device> result = new ArrayList<Device>();
+
+            for (String group : lgroup)
+            {
+                result.addAll(getDevices(group));
+            }
+        
+            return result.toArray(new Device[result.size()]);
+        }
+        finally
+        {
+            mutexListDevices.releaseRead();
+        }
+    }
+
+    
+    
+    public List<Device> getDevicesFromIdentifier(String[] lidentifier)
+    {
+        mutexListDevices.lockRead();
+
+        try
+        {        
+            List<Device> result = new ArrayList<Device>();
+
+            for (String identifier : lidentifier)
+            {
+                try
+                {
+                    Device device = getDevice(identifier);
+                    
+                    if (device != null)
+                    {
+                        result.add(device);
+                    }
+                } 
+                catch (Exception exception)
+                {
+                }
+            }
+           
+            return result;
+        }
+        finally
+        {
+            mutexListDevices.releaseRead();
+        }
+    }
+    
+    
+    
+    public Device[] getDevices(long timestamp)
+    {
+        mutexListDevices.lockRead();
+
+        try
+        {
+            List<Device> result = new ArrayList<Device>();
+
+            for (Device device : ldevice)
+            {
+                if (device.getLastTimestampUpdate() > timestamp)
+                {
+                    result.add(device);
+                }
+            }
+
+            return result.toArray(new Device[result.size()]);
+        }
+        finally
+        {
+            mutexListDevices.releaseRead();
+        }
+    }
+    
+    
+
+    public Device[] getDevices(String identifier, long timestamp)
+    {
+        if (identifier == null) return getDevices(timestamp);
+        
+        mutexListDevices.lockRead();
+
+        try
+        {
+            List<Device> result = new ArrayList<Device>();
+
+            for (Device device : ldevice)
+            {
+                if (device.getIdentifier().equals(identifier))
+                {
+                    if (device.getLastTimestampUpdate() > timestamp)
+                    {
+                        result.add(device);
+                    }
+                }
+            }
+
+            return result.toArray(new Device[result.size()]);
+        }
+        finally
+        {
+            mutexListDevices.releaseRead();
+        }
+    }    
+    
+    
+    
+    
+    
+    public Device[] getDevices(String identifier, long  timestamp1, long timestamp2) throws Exception
+    {
+        // Without mutex read, we are consulting historical database and creating new objects
+
+        long timestamp = getLastTimestamp(identifier, timestamp1);
+        String where = "type = '" + deviceClassName + "' AND timestamp >= " + timestamp + " AND timestamp < " + timestamp2;
+
+        if (identifier != null)
+        {
+            if (identifier.length() > 0)
+            {
+                where = where + " AND identifier = '" + identifier + "'";
+            }
+        }
+
+        List<Device> result = (List<Device>)DevicePersistenceHistorical.getDevices((List<Object>)(List<?>)Shared.controllerDatabase.historical_getObject(DevicePersistenceHistorical.class.getName(), where));
+        
+        Collections.sort(result, new Comparator<Device>() 
+        {
+            public int compare(Device device1, Device device2) 
+            {
+               return Integer.valueOf(device1.information.number).compareTo(device2.information.number);
+            }
+        });        
+        
+        return result.toArray(new Device[result.size()]);
+    }
+    
+    
+
+    
+    public Device[] getDevicesWhen(String identifier, long  timestamp) throws Exception
+    {
+        if (identifier == null) return getDevicesWhen(timestamp);
+                
+        // Without mutex read, we are consulting historical database and creating new objects
+        
+        String where = "type = '" + deviceClassName + "' AND timestamp <= " + timestamp + " AND identifier = '" + identifier + "' ORDER BY timestamp DESC limit 1";
+        List<Device> result = (List<Device>)DevicePersistenceHistorical.getDevices((List<Object>)(List<?>)Shared.controllerDatabase.historical_getObject(DevicePersistenceHistorical.class.getName(), where));
+
+        Collections.sort(result, new Comparator<Device>() 
+        {
+            public int compare(Device device1, Device device2) 
+            {
+               return Integer.valueOf(device1.information.number).compareTo(device2.information.number);
+            }
+        });        
+        
+        return result.toArray(new Device[result.size()]);
+    }
+    
+    
+    
+
+    
+    public Device[] getDevicesNext(String identifier, long  timestamp) throws Exception
+    {
+        if (identifier == null) return getDevicesWhen(timestamp);
+                
+        // Without mutex read, we are consulting historical database and creating new objects
+        
+        String where = "type = '" + deviceClassName + "' AND timestamp > " + timestamp + " AND identifier = '" + identifier + "' ORDER BY timestamp ASC limit 1";
+        List<Device> result = (List<Device>)DevicePersistenceHistorical.getDevices((List<Object>)(List<?>)Shared.controllerDatabase.historical_getObject(DevicePersistenceHistorical.class.getName(), where));
+
+        Collections.sort(result, new Comparator<Device>() 
+        {
+            public int compare(Device device1, Device device2) 
+            {
+               return Integer.valueOf(device1.information.number).compareTo(device2.information.number);
+            }
+        });        
+        
+        return result.toArray(new Device[result.size()]);
+    }
+    
+    
+    
+
+    public Device[] getDevicesWhen(long  timestamp) throws Exception
+    {
+        List<Device> result = new ArrayList<Device>();
+        for (Device device : getDevices()) result.addAll(Arrays.asList(getDevicesWhen(device.getIdentifier(), timestamp)));
+        
+        Collections.sort(result, new Comparator<Device>() 
+        {
+            public int compare(Device device1, Device device2) 
+            {
+               return Integer.valueOf(device1.information.number).compareTo(device2.information.number);
+            }
+        });        
+        
+        return result.toArray(new Device[result.size()]);
+    }
+    
+        
+
+    
+    /**
+     * Get device from external accesses, not from this server memory devices allocation.
+     */
+
+    
+    public Device getDeviceExternal(String identifier) throws Exception
+    {
+        mutexListDevices.lockRead();
+     
+        // TODO: Timelessaccess for the moment. In the future we must include direct access to servers using Services pollsters
+        
+        try
+        {
+            String where = "identifier = '" + identifier + "'";
+            List<Device> result = (List<Device>)DevicePersistenceTimeless.getDevices((List<Object>)(List<?>)Shared.controllerDatabase.timeless_getObject(DevicePersistenceTimeless.class.getName(), where));
+            return result.get(0);
+        }
+        finally
+        {
+            mutexListDevices.releaseRead();
+        }
+    }
+        
+
+
+    /**
+     * Get devices from external accesses, not from this server memory devices allocation.
+     */
+
+    
+    public Device[] getDevicesExternal(String type) throws Exception
+    {
+        mutexListDevices.lockRead();
+        
+        try
+        {
+            String where = "type = '" + type + "'";
+            List<Device> result = (List<Device>)DevicePersistenceTimeless.getDevices((List<Object>)(List<?>)Shared.controllerDatabase.timeless_getObject(DevicePersistenceTimeless.class.getName(), where));
+            
+            Collections.sort(result, new Comparator<Device>() 
+            {
+                public int compare(Device device1, Device device2) 
+                {
+                   return Integer.valueOf(device1.information.number).compareTo(device2.information.number);
+                }
+            });        
+            
+            return result.toArray(new Device[result.size()]);
+        }
+        finally
+        {
+            mutexListDevices.releaseRead();
+        }
+    }
+    
+    
+    
+
+    
+    public boolean updateDevice(Device currentdevice, Device newdevice)
+    {
+        getMutex(currentdevice).lockWrite();
+    
+        boolean different = false;
+        
+        try
+        {
+            newdevice.getDeviceInformation().serverAddress = Shared.configuration.listener.address;
+            newdevice.getDeviceInformation().serverPort = Shared.configuration.listener.port;
+            newdevice.getDeviceInformation().serverAddressExternal = Shared.configuration.listener.addressExternal;
+            newdevice.getDeviceInformation().serverPortExternal = Shared.configuration.listener.portExternal;
+            newdevice.getDeviceInformation().serverServiceName = Shared.controllerStatus.getApplication().getDeviceInformation().serverServiceName;
+
+            different = currentdevice.updateDevice(newdevice);
+
+            if ((different == true) && (Shared.configuration.database != null))
+            {
+                Shared.controllerDatabase.timeless_updateOrAddObject(new DevicePersistenceTimeless(currentdevice));
+            }
+        }
+        catch (Exception e)
+        {
+        }
+        finally
+        {
+            getMutex(currentdevice).releaseWrite();
+        }
+        
+        // newdevice sabemos que no cambiara porque nadie mas tiene la referencia
+        
+        try 
+        { 
+            if ((different == true) && (Shared.configuration.database != null))
+            {
+                Shared.controllerDatabase.historical_addObject(new DevicePersistenceHistorical(newdevice));
+            }
+        }
+        catch (org.postgresql.util.PSQLException exception)
+        {
+            if ((exception.getMessage().toUpperCase().indexOf("NO PARTITION OF RELATION") > -1) ||
+                (exception.getMessage().toUpperCase().indexOf("NO SE ENCONTRÓ UNA PARTICIÓN") > -1))
+            {
+                Calendar calendar1 = Calendar.getInstance();
+                calendar1.setTimeInMillis(newdevice.getLastTimestampUpdate());
+                calendar1.set(Calendar.DATE, 1);
+                calendar1.set(Calendar.HOUR_OF_DAY, 0);
+                calendar1.set(Calendar.MINUTE, 0);
+                calendar1.set(Calendar.SECOND, 0);
+                calendar1.set(Calendar.MILLISECOND, 0);
+
+                SimpleDateFormat formato1 = new SimpleDateFormat("yyyy_MM");
+
+                String tablename = "devices_" + formato1.format(calendar1.getTimeInMillis());
+                long startdate = calendar1.getTimeInMillis();
+                calendar1.add(Calendar.MONTH, 1);
+                long enddate = calendar1.getTimeInMillis();
+
+                String query1 = "CREATE TABLE IF NOT EXISTS " + tablename + " PARTITION OF devices FOR VALUES FROM ('" + startdate + "') TO ('" + enddate + "')";
+                try{Shared.controllerDatabase.historical_update(query1);} catch (Exception e){};
+                executeAlterTableDevicesVacuum(true, tablename);
+
+                // Do again the insert
+                try
+                {
+                    Shared.controllerDatabase.historical_addObject(new DevicePersistenceHistorical(newdevice));
+                }
+                catch (Exception e)
+                {
+                    Shared.println(Shared.getMessage("Model"), e);
+                }
+            }
+        }
+        catch (Exception e) 
+        {
+        }
+        
+        return different;
+    }
+    
+
+    
+    public void updateDevice(Device device)
+    {
+        updateDevice(device, System.currentTimeMillis());
+    }
+
+    
+    public void updateDevice(Device device, long timestamp)
+    {
+        getMutex(device).lockWrite();
+
+        try
+        {
+            Device currentDevice = (Device)mdevice.get(device.getIdentifier());
+
+            if (currentDevice == null)
+            {
+                device.getDeviceInformation().setCreationTimestamp(timestamp);
+                device.setLastTimestampInformationUpdate(timestamp);
+                if (device.getDeviceConfiguration() != null)
+                {
+                    device.setLastTimestampConfigurationUpdate(timestamp);
+                }
+
+                device.information.serverAddress = Shared.configuration.listener.address;
+                device.information.serverPort = Shared.configuration.listener.port;
+                
+                if (Shared.configuration.database != null)
+                {
+                    Shared.controllerDatabase.timeless_updateOrAddObject(new DevicePersistenceTimeless(device));
+
+                    try
+                    {
+                        Shared.controllerDatabase.historical_updateOrAddObject(new DevicePersistenceHistorical(device));
+                    }
+                    catch (org.postgresql.util.PSQLException exception)
+                    {
+                        if ((exception.getMessage().toUpperCase().indexOf("NO PARTITION OF RELATION") > -1) ||
+                            (exception.getMessage().toUpperCase().indexOf("NO SE ENCONTRÓ UNA PARTICIÓN") > -1))
+                        {
+                            Calendar calendar1 = Calendar.getInstance();
+                            calendar1.setTimeInMillis(device.getLastTimestampUpdate());
+                            calendar1.set(Calendar.DATE, 1);
+                            calendar1.set(Calendar.HOUR_OF_DAY, 0);
+                            calendar1.set(Calendar.MINUTE, 0);
+                            calendar1.set(Calendar.SECOND, 0);
+                            calendar1.set(Calendar.MILLISECOND, 0);
+
+                            SimpleDateFormat formato1 = new SimpleDateFormat("yyyy_MM");
+
+                            String tablename = "devices_" + formato1.format(calendar1.getTimeInMillis());
+                            long startdate = calendar1.getTimeInMillis();
+                            calendar1.add(Calendar.MONTH, 1);
+                            long enddate = calendar1.getTimeInMillis();
+
+                            String query1 = "CREATE TABLE IF NOT EXISTS " + tablename + " PARTITION OF devices FOR VALUES FROM ('" + startdate + "') TO ('" + enddate + "')";
+                            try{Shared.controllerDatabase.historical_update(query1);} catch (Exception e){};
+                            executeAlterTableDevicesVacuum(true, tablename);
+
+                            // Do again the insert
+                            try
+                            {
+                                Shared.controllerDatabase.historical_updateOrAddObject(new DevicePersistenceHistorical(device));
+                            }
+                            catch (Exception e)
+                            {
+                                Shared.println(Shared.getMessage("Model"), e);
+                            }
+                        }
+                    }
+                }
+                
+                mdevice.put(device.getIdentifier(), device);
+                ldevice.add(device);
+            }
+            else
+            {
+                System.out.println("3.UpdateDevice: " + currentDevice);
+                if (currentDevice.updateDevice(device) == true)
+                {
+                    System.out.println("4.UpdateDevice: " + currentDevice);
+                    if (Shared.configuration.database != null)
+                    {
+                        Shared.controllerDatabase.timeless_updateOrAddObject(new DevicePersistenceTimeless(device));
+
+                        try
+                        {
+                            Shared.controllerDatabase.historical_updateOrAddObject(new DevicePersistenceHistorical(device));
+                        }
+                        catch (org.postgresql.util.PSQLException exception)
+                        {
+                            if ((exception.getMessage().toUpperCase().indexOf("NO PARTITION OF RELATION") > -1) ||
+                                (exception.getMessage().toUpperCase().indexOf("NO SE ENCONTRÓ UNA PARTICIÓN") > -1))
+                            {
+                                Calendar calendar1 = Calendar.getInstance();
+                                calendar1.setTimeInMillis(device.getLastTimestampUpdate());
+                                calendar1.set(Calendar.DATE, 1);
+                                calendar1.set(Calendar.HOUR_OF_DAY, 0);
+                                calendar1.set(Calendar.MINUTE, 0);
+                                calendar1.set(Calendar.SECOND, 0);
+                                calendar1.set(Calendar.MILLISECOND, 0);
+
+                                SimpleDateFormat formato1 = new SimpleDateFormat("yyyy_MM");
+
+                                String tablename = "devices_" + formato1.format(calendar1.getTimeInMillis());
+                                long startdate = calendar1.getTimeInMillis();
+                                calendar1.add(Calendar.MONTH, 1);
+                                long enddate = calendar1.getTimeInMillis();
+
+                                String query1 = "CREATE TABLE IF NOT EXISTS " + tablename + " PARTITION OF devices FOR VALUES FROM ('" + startdate + "') TO ('" + enddate + "')";
+                                try{Shared.controllerDatabase.historical_update(query1);} catch (Exception e){};
+                                executeAlterTableDevicesVacuum(true, tablename);
+
+                                // Do again the insert
+                                try
+                                {
+                                    Shared.controllerDatabase.historical_updateOrAddObject(new DevicePersistenceHistorical(device));
+                                }
+                                catch (Exception e)
+                                {
+                                    Shared.println(Shared.getMessage("Model"), e);
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+        }
+        catch (Exception e)
+        {
+        }
+        finally
+        {
+            getMutex(device).releaseWrite();
+        }
+    }
+    
+    
+    
+    
+    public void updateDeviceStatus(Device device, long timestamp)
+    {
+        try
+        {
+            if (device.getLastTimestampStatusUpdate() >= timestamp)
+            {
+                device.setLastTimestampStatusUpdate(device.getLastTimestampStatusUpdate() + 1);
+            }
+            else
+            {
+                device.setLastTimestampStatusUpdate(timestamp);
+            }
+            
+            if (Shared.configuration.database != null)
+            {
+                try
+                {
+                    Shared.controllerDatabase.historical_updateOrAddObject(new DevicePersistenceHistorical(device));
+                }
+                catch (org.postgresql.util.PSQLException exception)
+                {
+                    if ((exception.getMessage().toUpperCase().indexOf("NO PARTITION OF RELATION") > -1) || (exception.getMessage().toUpperCase().indexOf("NO SE ENCONTRÓ UNA PARTICIÓN") > -1))
+                    {
+                        Calendar calendar1 = Calendar.getInstance();
+                        calendar1.setTimeInMillis(device.getLastTimestampUpdate());
+                        calendar1.set(Calendar.DATE, 1);
+                        calendar1.set(Calendar.HOUR_OF_DAY, 0);
+                        calendar1.set(Calendar.MINUTE, 0);
+                        calendar1.set(Calendar.SECOND, 0);
+                        calendar1.set(Calendar.MILLISECOND, 0);
+
+                        SimpleDateFormat formato1 = new SimpleDateFormat("yyyy_MM");
+
+                        String tablename = "devices_" + formato1.format(calendar1.getTimeInMillis());
+                        long startdate = calendar1.getTimeInMillis();
+                        calendar1.add(Calendar.MONTH, 1);
+                        long enddate = calendar1.getTimeInMillis();
+
+                        String query1 = "CREATE TABLE IF NOT EXISTS " + tablename + " PARTITION OF devices FOR VALUES FROM ('" + startdate + "') TO ('" + enddate + "')";
+                        try{Shared.controllerDatabase.historical_update(query1);} catch (Exception e){};
+                        executeAlterTableDevicesVacuum(true, tablename);
+
+                        // Do again the insert
+                        
+                        try
+                        {
+                            Shared.controllerDatabase.historical_updateOrAddObject(new DevicePersistenceHistorical(device));
+                        }
+                        catch (Exception e)
+                        {
+                        }
+                    }
+                }
+            }
+        }
+        catch (Exception e)
+        {
+        }
+    }
+    
+    
+    
+    
+    public void forceUpdateDeviceStatus(Device device, long timestamp)
+    {
+        try
+        {
+            device.forceLastTimestampStatusUpdate(timestamp);
+            if (Shared.configuration.database != null)
+            {
+                try
+                {
+                    Shared.controllerDatabase.historical_updateOrAddObject(new DevicePersistenceHistorical(device));
+                }
+                catch (org.postgresql.util.PSQLException exception)
+                {
+                    if ((exception.getMessage().toUpperCase().indexOf("NO PARTITION OF RELATION") > -1) || (exception.getMessage().toUpperCase().indexOf("NO SE ENCONTRÓ UNA PARTICIÓN") > -1))
+                    {
+                        Calendar calendar1 = Calendar.getInstance();
+                        calendar1.setTimeInMillis(device.getLastTimestampUpdate());
+                        calendar1.set(Calendar.DATE, 1);
+                        calendar1.set(Calendar.HOUR_OF_DAY, 0);
+                        calendar1.set(Calendar.MINUTE, 0);
+                        calendar1.set(Calendar.SECOND, 0);
+                        calendar1.set(Calendar.MILLISECOND, 0);
+
+                        SimpleDateFormat formato1 = new SimpleDateFormat("yyyy_MM");
+
+                        String tablename = "devices_" + formato1.format(calendar1.getTimeInMillis());
+                        long startdate = calendar1.getTimeInMillis();
+                        calendar1.add(Calendar.MONTH, 1);
+                        long enddate = calendar1.getTimeInMillis();
+
+                        String query1 = "CREATE TABLE IF NOT EXISTS " + tablename + " PARTITION OF devices FOR VALUES FROM ('" + startdate + "') TO ('" + enddate + "')";
+                        try{Shared.controllerDatabase.historical_update(query1);} catch (Exception e){};
+                        executeAlterTableDevicesVacuum(true, tablename);
+
+                        // Do again the insert
+                        
+                        try
+                        {
+                            Shared.controllerDatabase.historical_updateOrAddObject(new DevicePersistenceHistorical(device));
+                        }
+                        catch (Exception e)
+                        {
+                        }
+                    }
+                }
+            }
+        }
+        catch (Exception e)
+        {
+        }
+    }
+    
+    
+    
+    
+    public void updateDevice(Device[] ldevice)
+    {
+        mutexListDevices.lockWrite();
+        
+        try
+        {
+            for (Device device : ldevice)
+            {
+                updateDevice(device);
+            }
+        } 
+        catch (Exception e)
+        {
+        }
+
+        mutexListDevices.releaseWrite();
+    }
+
+    
+    
+        
+        
+    
+
+
+
+    public void deleteDevices(String[] lidentifier) throws Exception
+    {
+        int errors = 0;
+        
+        for (String identifier : lidentifier)
+        {
+            getMutex(identifier).lockWrite();
+
+            try
+            {
+                String where = "identifier = '" + identifier + "' AND type = '" + deviceClassName + "'";
+                Shared.controllerDatabase.timeless_deleteObject(DevicePersistenceTimeless.class.getName(), where);
+
+                mutexListDevices.lockWrite();
+                {
+                    ldevice.remove(mdevice.remove(identifier));
+                }
+                mutexListDevices.releaseWrite();
+            }
+            catch (Exception e)
+            {
+                errors = errors  + 1;
+            }
+            finally
+            {
+                getMutex(identifier).releaseWrite();
+            }
+        }
+                
+        if (errors > 0) 
+        {
+            throw new ServerException(Shared.getMessage("Error deleting devices"));
+        }
+    }    
+    
+
+    public Device cloneDevice(String identifier)
+    {
+        // No hace falta mutex porque los devices se cambia la referencia cada vez. No hay conflicto posible
+
+        Device clon = null;
+        
+        try
+        {
+            clon = (Device)Serialization.clone(getDevice(identifier));
+        }
+        catch (Exception e)
+        {
+        }
+        
+        try
+        {
+            clon.realtime = (DeviceRealtime)Serialization.clone(getDevice(identifier).getDeviceRealtime());
+        }
+        catch (Exception e)
+        {
+        }
+        
+        
+        
+        return clon;
+    }    
+
+    
+
+
+    public Device cloneDevice(Device device)
+    {
+        try
+        {
+            return cloneDevice(device.getIdentifier());
+        }
+        catch (Exception e)
+        {
+        }
+        
+        return null;
+    }    
+
+        
+    
+
+    public List<String> getGroups()
+    {
+        mutexListDevices.lockRead();
+
+        try
+        {
+            Set<String> groups = new HashSet<>();
+
+            for (Device device : ldevice)
+            {
+                try
+                {
+                    if (device.getDeviceInformation().group != null)
+                    {
+                        groups.add(device.getDeviceInformation().group);
+                    }
+                }
+                catch (Exception e)
+                {
+                }
+            }
+
+            List<String> result = new ArrayList(groups);
+            result.sort(String::compareToIgnoreCase);
+            return result;
+        }
+        finally
+        {
+            mutexListDevices.releaseRead();
+        }
+    }
+
+    
+        
+
+    // </editor-fold>      
+    
+    
+    // <editor-fold defaultstate="collapsed" desc="Traces">
+    
+    public List<String> getTraceValues(String field, String application) throws Exception
+    {
+        ResultSet resultset = null;
+        Persistence persistence = Shared.controllerDatabase.getHistoricalPersistance().get(0);
+        List<String> result = new ArrayList<String>();
+        
+        try
+        {
+            {
+                String command = "SELECT DISTINCT(" + field + ") FROM traces";
+                if (application != null) command = "SELECT DISTINCT(" + field + ") FROM traces WHERE application = '" + application + "'";
+                
+                resultset = persistence.executeQuery(command);
+                while (resultset.next())
+                {
+                    result.add(resultset.getString(1));
+                }
+                resultset.getStatement().close();
+                resultset.close();
+            }
+        }
+        catch (Exception exception)
+        {
+            throw exception;
+        }
+        finally
+        {
+            try{resultset.getStatement().close();} catch (Exception e){};
+            try{resultset.close();} catch (Exception e){};
+        }
+
+        return result;
+    }
+    
+    public List<Trace> getTraces(String language, long timestampfrom, long timestampto, String application, int limit) throws Exception
+    {
+        ResultSet resultset = null;
+        Persistence persistence = Shared.controllerDatabase.getHistoricalPersistance().get(0);
+
+        List<Trace> traces = new ArrayList<Trace>();
+        
+        try
+        {
+            String command = "SELECT value FROM traces WHERE timestamp >= " + timestampfrom + " AND timestamp <  " + timestampto;
+            if (application != null) command = command + " AND application = '" + application + "'";
+            command = command + " ORDER BY timestamp ASC";
+            if (limit > 0) command = command + " LIMIT " + limit;
+            
+            resultset = persistence.executeQuery(command);
+            
+            while (resultset.next())
+            {
+                traces.add(((TracePersistance)Serialization.deserialize(TracePersistance.class, resultset.getString(1))).trace);
+            }
+            
+            return traces;
+        }
+        finally
+        {
+            try{resultset.getStatement().close();} catch (Exception e){};
+            try{resultset.close();} catch (Exception e){};
+        }
+    }
+    
+    
+
+    private String getFilterEventController(String filter)
+    {
+        /*
+        
+        */
+        try
+        {
+            String result = filter;
+
+            
+            return(result);
+        }
+        catch (Exception e)
+        {
+            e.printStackTrace();
+        }
+
+        return(filter);
+    }
+
+
+    public TraceResult getEventsController(String language, long timestampfrom, long timestampto, int type, int limit, int offset, String filter, boolean viewTrolleyEvents, boolean viewMasterSlaveEvents) throws Exception
+    {
+        ResultSet resultset = null;
+        Persistence persistence = Shared.controllerDatabase.getHistoricalPersistance().get(0);
+
+        TraceResult result = new TraceResult();
+        result.timestampfrom = timestampfrom;
+        result.timestampto = timestampto;
+        result.limit = limit;
+        result.offset = offset;
+        result.type = type;
+        result.traces = new ArrayList<Trace>();
+        
+        try
+        {
+            String command = "SELECT COUNT(*) FROM traces WHERE timestamp >= " + timestampfrom + " AND timestamp <  " + timestampto;
+            if (type > -1) command = command + " AND type = " + type;
+            // if (filter != null) command = command + " AND " + getFilterEventController(filter.substring(0, filter.indexOf("ORDER")));
+
+            resultset = persistence.executeQuery(command);
+            
+            if (resultset.next())
+            {
+                result.total = resultset.getInt(1);
+            }
+            try{resultset.close();} catch (Exception e){};
+
+            command = "SELECT value FROM traces WHERE timestamp >= " + timestampfrom + " AND timestamp <  " + timestampto;
+            if (type > -1) command = command + " AND type = " + type;
+//            if (order == 1) command = command + " ORDER BY timestamp ASC";
+//            else if (order == -1) command = command + " ORDER BY timestamp DESC";
+            command = command + " ORDER BY timestamp DESC";
+            // if (filter != null) command = command + " AND " + getFilterEventController(filter);
+            if (limit > 0) command = command + " LIMIT " + limit;
+            if (offset > -1) command = command + " OFFSET " + offset;
+
+            System.out.println(command);
+            
+            resultset = persistence.executeQuery(command);
+            
+            while (resultset.next())
+            {
+                TracePersistance tracePersistance = Serialization.deserialize(TracePersistance.class, resultset.getString(1));
+                if (tracePersistance.trace != null)
+                {
+                    result.traces.add(tracePersistance.trace);
+                }
+                else
+                {
+                    Trace trace = Serialization.deserialize(Trace.class, resultset.getString(1));
+                    if (trace != null)
+                    {
+                        result.traces.add(trace);
+                    }
+                }
+            }
+            
+            return result;
+        }
+        finally
+        {
+            try{resultset.getStatement().close();} catch (Exception e){};
+            try{resultset.close();} catch (Exception e){};
+        }
+    }
+    
+    
+    
+    public TraceResult getTraces(String language, long timestampfrom, long timestampto, int type, int limit, int offset, int order, boolean viewTrolleyEvents, boolean viewMasterSlaveEvents) throws Exception
+    {
+        ResultSet resultset = null;
+        Persistence persistence = Shared.controllerDatabase.getHistoricalPersistance().get(0);
+
+        TraceResult result = new TraceResult();
+        result.timestampfrom = timestampfrom;
+        result.timestampto = timestampto;
+        result.limit = limit;
+        result.offset = offset;
+        result.type = type;
+        result.traces = new ArrayList<Trace>();
+        
+        try
+        {
+            String command = "SELECT COUNT(*) FROM traces WHERE timestamp >= " + timestampfrom + " AND timestamp <  " + timestampto;
+            if (type > -1) command = command + " AND type = " + type;
+
+            resultset = persistence.executeQuery(command);
+            
+            if (resultset.next())
+            {
+                result.total = resultset.getInt(1);
+            }
+            try{resultset.close();} catch (Exception e){};
+
+            command = "SELECT value FROM traces WHERE timestamp >= " + timestampfrom + " AND timestamp <  " + timestampto;
+            if (type > -1) command = command + " AND type = " + type;
+            if (order == 1) command = command + " ORDER BY timestamp ASC";
+            else if (order == -1) command = command + " ORDER BY timestamp DESC";
+            if (limit > 0) command = command + " LIMIT " + limit;
+            if (offset > -1) command = command + " OFFSET " + offset;
+
+            System.out.println(command);
+            
+            resultset = persistence.executeQuery(command);
+            
+            while (resultset.next())
+            {
+                TracePersistance tracePersistance = Serialization.deserialize(TracePersistance.class, resultset.getString(1));
+                if (tracePersistance.trace != null)
+                {
+                    result.traces.add(tracePersistance.trace);
+                }
+                else
+                {
+                    Trace trace = Serialization.deserialize(Trace.class, resultset.getString(1));
+                    if (trace != null)
+                    {
+                        result.traces.add(trace);
+                    }
+                }
+            }
+            
+            return result;
+        }
+        finally
+        {
+            try{resultset.getStatement().close();} catch (Exception e){};
+            try{resultset.close();} catch (Exception e){};
+        }
+    }
+    
+    
+    public TraceResult getTraces(TraceResult traceresult) throws Exception
+    {
+        ResultSet resultset = null;
+        Persistence persistence = Shared.controllerDatabase.getHistoricalPersistance().get(0);
+
+        try
+        {
+            {
+                String command = "SELECT COUNT(*) FROM traces WHERE timestamp >= " + traceresult.timestampfrom + " AND timestamp <=  " + traceresult.timestampto;
+                if (traceresult.type != Trace.TRACE_NONE) command = command + " AND type = '" + traceresult.type + "'";
+                if (traceresult.username != null) command = command + " AND username = '" + traceresult.username + "'";
+                if (traceresult.application != null) command = command + " AND application = '" + traceresult.application + "'";
+                if (traceresult.service != null) command = command + " AND service = '" + traceresult.service + "'";
+                resultset = persistence.executeQuery(command);
+                resultset.next();
+                traceresult.total = resultset.getLong(1);
+                resultset.getStatement().close();
+                resultset.close();
+            }
+            {
+                String command = "SELECT value FROM traces WHERE timestamp >= " + traceresult.timestampfrom + " AND timestamp <=  " + traceresult.timestampto;
+                if (traceresult.type != Trace.TRACE_NONE) command = command + " AND type = '" + traceresult.type + "'";
+                if (traceresult.username != null) command = command + " AND username = '" + traceresult.username + "'";
+                if (traceresult.application != null) command = command + " AND application = '" + traceresult.application + "'";
+                if (traceresult.service != null) command = command + " AND service = '" + traceresult.service + "'";
+                command = command + " ORDER BY timestamp ASC OFFSET " + traceresult.offset + " LIMIT " + traceresult.limit;
+                resultset = persistence.executeQuery(command);
+                while (resultset.next())
+                {
+                    traceresult.traces.add(((TracePersistance)Serialization.deserialize(TracePersistance.class, resultset.getString(1))).trace);
+                }
+                resultset.getStatement().close();
+                resultset.close();
+            }
+            
+        }
+        finally
+        {
+            try{resultset.getStatement().close();} catch (Exception e){};
+            try{resultset.close();} catch (Exception e){};
+        }
+
+
+        return traceresult;
+    }
+
+    
+
+    
+    
+    public List<Trace> getLastTraces(String language, String application, int limit) throws Exception
+    {
+        ResultSet resultset = null;
+        Persistence persistence = Shared.controllerDatabase.getHistoricalPersistance().get(0);
+
+        List<Trace> traces = new ArrayList<Trace>();
+        
+        try
+        {
+            String command = "SELECT value FROM traces ";
+            if (application != null) command = command + " WHERE application = '" + application + "'";
+            command = command + " ORDER BY timestamp DESC";
+            if (limit > 0) command = command + " LIMIT " + limit;
+            
+            resultset = persistence.executeQuery(command);
+            
+            while (resultset.next())
+            {
+                traces.add(((TracePersistance)Serialization.deserialize(TracePersistance.class, resultset.getString(1))).trace);
+            }
+            
+            return traces;
+        }
+        finally
+        {
+            try{resultset.getStatement().close();} catch (Exception e){};
+            try{resultset.close();} catch (Exception e){};
+        }
+    }
+
+    
+    
+
+    // </editor-fold>      
+
+    
+    
+    
+    public EventTrolleyResult getEventsTrolley(String language, long timestampfrom, long timestampto, int type, int limit, int offset, int order) throws Exception
+    {
+        ResultSet resultset = null;
+        Persistence persistence = Shared.controllerDatabase.getHistoricalPersistance().get(0);
+
+        EventTrolleyResult result = new EventTrolleyResult();
+        result.timestampfrom = timestampfrom;
+        result.timestampto = timestampto;
+        result.limit = limit;
+        result.offset = offset;
+        result.type = type;
+        result.events = new ArrayList<EventTrolley>();
+        
+        try
+        {
+            String command = "SELECT COUNT(*) FROM eventstrolley WHERE activation >= " + timestampfrom + " AND activation <  " + timestampto;
+            if (type > -1) command = command + " AND type = " + type;
+
+            resultset = persistence.executeQuery(command);
+            
+            if (resultset.next())
+            {
+                result.total = resultset.getInt(1);
+            }
+            try{resultset.close();} catch (Exception e){};
+
+            command = "SELECT value FROM eventstrolley WHERE activation >= " + timestampfrom + " AND activation <  " + timestampto;
+            if (type > -1) command = command + " AND type = " + type;
+            if (order == 1) command = command + " ORDER BY activation ASC";
+            else if (order == -1) command = command + " ORDER BY activation DESC";
+            if (limit > 0) command = command + " LIMIT " + limit;
+            if (offset > -1) command = command + " OFFSET " + offset;
+
+            System.out.println(command);
+            
+            resultset = persistence.executeQuery(command);
+            
+            while (resultset.next())
+            {
+                result.events.add(((EventTrolley)Serialization.deserialize(EventTrolley.class, resultset.getString(1))));
+            }
+            
+            return result;
+        }
+        finally
+        {
+            try{resultset.getStatement().close();} catch (Exception e){};
+            try{resultset.close();} catch (Exception e){};
+        }
+    }
+
+    
+    // <editor-fold defaultstate="collapsed" desc="Symbols">
+    
+    public void readSymbols() throws Exception
+    {
+        mutexListSymbols.lockWrite();
+                
+        try
+        {
+            // for (int i=0; i<32; i++)
+            for (float i=0; i<32; i+=0.5f)
+            {
+                for (String symbolName : Shared.configuration.symbols)
+                {
+                    DeviceSymbol symbol = new DeviceSymbol();
+                    symbol.type = deviceClassName;
+                    symbol.name = symbolName;
+                    symbol.zoom = i;
+                    int zoom = (int)i;
+                    String resourceName = "data/" + Shared.getApplicationName() + "/symbols/" + i + "/" + symbolName + ".svg";
+                    if (zoom == i)
+                    {
+                        resourceName = "data/" + Shared.getApplicationName() + "/symbols/" + zoom + "/" + symbolName + ".svg";
+                    }
+
+                    // String resourceName = "data/" + Shared.getApplicationName() + "/symbols/" + i + "/" + symbolName + ".svg";
+                    File file = new File(resourceName);
+                    
+                    if (file.exists() == true)
+                    {
+                        symbol.dataSVG = Files.readAllBytes(file.toPath());
+                    }
+                    else
+                    {
+                        symbol.dataSVG = Resources.getResourceBytes(resourceName);
+                    }
+                    
+                    if (symbol.dataSVG.length > 0)
+                    {
+                        lsymbols.add(symbol);
+                    }
+                }
+            }
+        }
+        catch (Exception exception)
+        {   
+            Shared.println(Shared.getMessage("Model"), exception);
+        }
+        finally
+        {
+            mutexListSymbols.releaseWrite();
+        }
+    }
+    
+    
+
+
+    public DeviceSymbol[] getSymbols()
+    {
+        mutexListSymbols.lockRead();
+        
+        try
+        {
+            return lsymbols.toArray(new DeviceSymbol[lsymbols.size()]);
+        }
+        finally
+        {
+            mutexListSymbols.releaseRead();
+        }
+    }
+        
+
+    
+    
+    public DeviceSymbol[] getSymbols(long timestamp)
+    {
+        if (configurationSymbolsTimestamp > timestamp)
+        {
+            return getSymbols();
+        }
+        else
+        {
+            return new DeviceSymbol[0];
+        }
+    }
+        
+    
+    
+   
+    public List<Object> getSymbolsNames(String type)
+    {
+        List<Object> result  = new ArrayList<Object> ();
+        
+        mutexListSymbols.lockRead();
+        
+        try
+        {
+            result.add("");
+
+            for (DeviceSymbol symbol : lsymbols)
+            {
+                if (symbol.type.equalsIgnoreCase(type))
+                {
+                    result.add(symbol.name);
+                }
+            }
+        }
+        finally
+        {
+            mutexListSymbols.releaseRead();
+        }
+        
+        return result;
+    }
+        
+
+    
+        
+        
+
+    // </editor-fold>       
+        
+    
+    // <editor-fold defaultstate="collapsed" desc="Application">    
+
+    public Application getApplicationService(String serviceName)
+    {
+        try
+        {
+            Device[] devices = getDevicesExternal(Application.class.getName());
+
+            for (Device device : devices)
+            {
+                if (device instanceof Application)
+                {
+                    Application application = (Application)device;
+                    
+                    if (application.getDeviceInformation().serverServiceName.equalsIgnoreCase(serviceName) == true)
+                    {
+                        return(application);
+                    }
+                }
+            }
+        }
+        catch (Exception exception)
+        {   
+        }
+
+        return(null);
+    }
+        
+    
+    
+    
+    
+
+    public Application[] getApplication(long timestamp) throws Exception
+    {
+        Application application = Shared.controllerStatus.getApplication();
+        
+        if (application.getLastTimestampUpdate() > timestamp)
+        {
+            return new Application[]{application};
+        }
+        return new Application[0];
+    }
+        
+    
+    
+    
+    public Application[] getApplication(long  timestamp1, long timestamp2) throws Exception
+    {
+        // Without mutex read, we are consulting historical database
+
+        String identifier   =  Shared.controllerStatus.getApplication().getIdentifier();
+        String where = "type = '" + deviceClassName + "' AND timestamp > " + timestamp1 + " AND timestamp < " + timestamp2;
+
+        if (identifier != null)
+        {
+            if (identifier.length() > 0)
+            {
+                where = where + " AND identifier = '" + identifier + "'";
+            }
+        }
+        
+        List<Device> result = (List<Device>)DevicePersistenceHistorical.getDevices((List<Object>)(List<?>)Shared.controllerDatabase.historical_getObject(DevicePersistenceHistorical.class.getName(), where));
+        return result.toArray(new Application[result.size()]);
+    }
+
+    
+    
+    
+    // A esta función sólo llama el servidor
+
+    public void updateApplication(Application application)
+    {
+        // No metemos en exclusion, no podemos tener varias llamadas a la vez
+        // Se controla en el ControllerStatus
+        
+        if (Shared.configuration.database != null)
+        {
+            try { Shared.controllerDatabase.timeless_updateOrAddObject(new DevicePersistenceTimeless(application)); } catch (Exception e) { }
+
+            try
+            {
+                Shared.controllerDatabase.historical_updateOrAddObject(new DevicePersistenceHistorical(application));
+            }
+            catch (org.postgresql.util.PSQLException exception)
+            {
+                if ((exception.getMessage().toUpperCase().indexOf("NO PARTITION OF RELATION") > -1) ||
+                    (exception.getMessage().toUpperCase().indexOf("NO SE ENCONTRÓ UNA PARTICIÓN") > -1))
+                {
+                    Calendar calendar1 = Calendar.getInstance();
+                    calendar1.setTimeInMillis(application.getLastTimestampUpdate());
+                    calendar1.set(Calendar.DATE, 1);
+                    calendar1.set(Calendar.HOUR_OF_DAY, 0);
+                    calendar1.set(Calendar.MINUTE, 0);
+                    calendar1.set(Calendar.SECOND, 0);
+                    calendar1.set(Calendar.MILLISECOND, 0);
+
+                    SimpleDateFormat formato1 = new SimpleDateFormat("yyyy_MM");
+
+                    String tablename = "devices_" + formato1.format(calendar1.getTimeInMillis());
+                    long startdate = calendar1.getTimeInMillis();
+                    calendar1.add(Calendar.MONTH, 1);
+                    long enddate = calendar1.getTimeInMillis();
+
+                    String query1 = "CREATE TABLE IF NOT EXISTS " + tablename + " PARTITION OF devices FOR VALUES FROM ('" + startdate + "') TO ('" + enddate + "')";
+                    try{Shared.controllerDatabase.historical_update(query1);} catch (Exception e){};
+                    executeAlterTableDevicesVacuum(true, tablename);
+
+                    // Do again the insert
+                    try
+                    {
+                        Shared.controllerDatabase.historical_updateOrAddObject(new DevicePersistenceHistorical(application));
+                    }
+                    catch (Exception e)
+                    {
+                        Shared.println(Shared.getMessage("Model"), e);
+                    }
+                }
+            }
+            catch (Exception e)
+            {
+            }
+        }
+    }    
+    
+
+    // </editor-fold>       
+    
+    
+    
+    // <editor-fold defaultstate="collapsed" desc="Actions">
+
+    public void addAction(DeviceAction action)
+    {
+        if (Shared.configuration.database != null)
+        {
+            // Insert action
+
+            try
+            {
+                DevicePersistenceAction persistenceAction = new DevicePersistenceAction(action);
+
+                try
+                {
+                    Shared.controllerDatabase.historical_addObject(persistenceAction);
+                }
+                catch (org.postgresql.util.PSQLException exception)
+                {
+                    if ((exception.getMessage().toUpperCase().indexOf("NO PARTITION OF RELATION") > -1) ||
+                        (exception.getMessage().toUpperCase().indexOf("NO SE ENCONTRÓ UNA PARTICIÓN") > -1))
+                    {
+                        Calendar calendar1 = Calendar.getInstance();
+                        calendar1.setTimeInMillis(action.requestTimestamp);
+                        calendar1.set(Calendar.DATE, 1);
+                        calendar1.set(Calendar.HOUR_OF_DAY, 0);
+                        calendar1.set(Calendar.MINUTE, 0);
+                        calendar1.set(Calendar.SECOND, 0);
+                        calendar1.set(Calendar.MILLISECOND, 0);
+
+                        SimpleDateFormat formato1 = new SimpleDateFormat("yyyy_MM");
+
+                        String tablename = "actions_" + formato1.format(calendar1.getTimeInMillis());
+                        long startdate = calendar1.getTimeInMillis();
+                        calendar1.add(Calendar.MONTH, 1);
+                        long enddate = calendar1.getTimeInMillis();
+
+                        String query1 = "CREATE TABLE IF NOT EXISTS " + tablename + " PARTITION OF actions FOR VALUES FROM ('" + startdate + "') TO ('" + enddate + "')";
+                        try{Shared.controllerDatabase.historical_update(query1);} catch (Exception e){};
+                        executeAlterTableActionsVacuum(true, tablename);
+
+                        // Do again the insert
+                        try
+                        {
+                            Shared.controllerDatabase.historical_addObject(persistenceAction);
+                        }
+                        catch (Exception e)
+                        {
+                            Shared.println(Shared.getMessage("Model"), e);
+                        }
+                    }
+                }
+                catch (Exception e)
+                {
+                }
+            }
+            catch (Exception e)
+            {
+            }
+        }
+    }
+    
+    
+
+    public List<DeviceAction> getActions()
+    {
+        return getActions(null);
+    }
+        
+    
+    
+    public List<DeviceAction> getActions(long  timestamp1, long timestamp2)
+    {
+        String where = "timestamp > " + timestamp1 + " AND timestamp < " + timestamp2;
+        return getActions(where);
+    }
+
+    
+    
+    public List<DeviceAction> getActions(long  timestamp1, long timestamp2, String where)
+    {
+        return getActions("timestamp > " + timestamp1 + " AND timestamp < " + timestamp2 + " AND " + where);
+    }
+        
+    
+    
+    
+    public List<DeviceAction> getActions(String where)
+    {
+        List<DeviceAction> result = null;
+        
+        try
+        {
+            if (Shared.configuration.database != null)
+            {
+                if (where == null)
+                {
+                    result = (List<DeviceAction>)DevicePersistenceAction.getActions((List<Object>)(List<?>)Shared.controllerDatabase.historical_getObject(DevicePersistenceAction.class.getName()));
+                }
+                else
+                {
+                    result = (List<DeviceAction>)DevicePersistenceAction.getActions((List<Object>)(List<?>)Shared.controllerDatabase.historical_getObject(DevicePersistenceAction.class.getName(), where));
+                }
+            }
+        }
+        catch (Exception e)
+        {
+        }
+        
+        return result;
+    }
+    
+    // </editor-fold>       
+    
+
+            
+        
+
+    public void executeAlterTableDevicesVacuum(boolean vacuum, String tablename)
+    {
+        try
+        {
+            String enabled = "true";
+            if (vacuum == false) enabled = "false";
+
+            String autovacuum_enabled = art.servers.Shared.getPropertyValueString("devices.autovacuum_enabled");
+            String autovacuum_vacuum_scale_factor = art.servers.Shared.getPropertyValueString("devices.autovacuum_vacuum_scale_factor");
+            String autovacuum_vacuum_threshold = art.servers.Shared.getPropertyValueString("devices.autovacuum_vacuum_threshold");
+            String autovacuum_analyze_scale_factor = art.servers.Shared.getPropertyValueString("devices.autovacuum_analyze_scale_factor");
+            String autovacuum_analyze_threshold = art.servers.Shared.getPropertyValueString("devices.autovacuum_analyze_threshold");
+
+            if (autovacuum_enabled == null) autovacuum_enabled = enabled;
+            if (autovacuum_vacuum_scale_factor == null) autovacuum_vacuum_scale_factor = "0.0";
+            if (autovacuum_vacuum_threshold == null) autovacuum_vacuum_threshold = "1000";
+            if (autovacuum_analyze_scale_factor == null) autovacuum_analyze_scale_factor = "0.0";
+            if (autovacuum_analyze_threshold == null) autovacuum_analyze_threshold = "1000";
+
+            try{Shared.controllerDatabase.historical_update("ALTER TABLE " + tablename + " SET (autovacuum_enabled = " + enabled + ", toast.autovacuum_enabled = " + enabled + ")");} catch (Exception e){};
+            try{Shared.controllerDatabase.historical_update("ALTER TABLE " + tablename + " SET (autovacuum_vacuum_scale_factor = 0.0)");} catch (Exception e){};
+            try{Shared.controllerDatabase.historical_update("ALTER TABLE " + tablename + " SET (autovacuum_vacuum_threshold = 1000)");} catch (Exception e){};
+            try{Shared.controllerDatabase.historical_update("ALTER TABLE " + tablename + " SET (autovacuum_analyze_scale_factor = 0.0)");} catch (Exception e){};
+            try{Shared.controllerDatabase.historical_update("ALTER TABLE " + tablename + " SET (autovacuum_analyze_threshold = 1000)");} catch (Exception e){};
+        }
+        catch (Exception exception)
+        {
+            
+        }
+    }
+        
+
+    public void executeAlterTableActionsVacuum(boolean vacuum, String tablename)
+    {
+        try
+        {
+            String enabled = "true";
+            if (vacuum == false) enabled = "false";
+
+            String autovacuum_enabled = art.servers.Shared.getPropertyValueString("actions.autovacuum_enabled");
+            String autovacuum_vacuum_scale_factor = art.servers.Shared.getPropertyValueString("actions.autovacuum_vacuum_scale_factor");
+            String autovacuum_vacuum_threshold = art.servers.Shared.getPropertyValueString("actions.autovacuum_vacuum_threshold");
+            String autovacuum_analyze_scale_factor = art.servers.Shared.getPropertyValueString("actions.autovacuum_analyze_scale_factor");
+            String autovacuum_analyze_threshold = art.servers.Shared.getPropertyValueString("actions.autovacuum_analyze_threshold");
+
+            if (autovacuum_enabled == null) autovacuum_enabled = enabled;
+            if (autovacuum_vacuum_scale_factor == null) autovacuum_vacuum_scale_factor = "0.0";
+            if (autovacuum_vacuum_threshold == null) autovacuum_vacuum_threshold = "1000";
+            if (autovacuum_analyze_scale_factor == null) autovacuum_analyze_scale_factor = "0.0";
+            if (autovacuum_analyze_threshold == null) autovacuum_analyze_threshold = "1000";
+
+            try{Shared.controllerDatabase.historical_update("ALTER TABLE " + tablename + " SET (autovacuum_enabled = " + enabled + ", toast.autovacuum_enabled = " + enabled + ")");} catch (Exception e){};
+            try{Shared.controllerDatabase.historical_update("ALTER TABLE " + tablename + " SET (autovacuum_vacuum_scale_factor = 0.0)");} catch (Exception e){};
+            try{Shared.controllerDatabase.historical_update("ALTER TABLE " + tablename + " SET (autovacuum_vacuum_threshold = 1000)");} catch (Exception e){};
+            try{Shared.controllerDatabase.historical_update("ALTER TABLE " + tablename + " SET (autovacuum_analyze_scale_factor = 0.0)");} catch (Exception e){};
+            try{Shared.controllerDatabase.historical_update("ALTER TABLE " + tablename + " SET (autovacuum_analyze_threshold = 1000)");} catch (Exception e){};
+        }
+        catch (Exception exception)
+        {
+            
+        }
+    }
+        
+
+    public void executeAlterTableTracesVacuum(boolean vacuum, String tablename)
+    {
+        try
+        {
+            String enabled = "true";
+            if (vacuum == false) enabled = "false";
+
+            String autovacuum_enabled = art.servers.Shared.getPropertyValueString("traces.autovacuum_enabled");
+            String autovacuum_vacuum_scale_factor = art.servers.Shared.getPropertyValueString("traces.autovacuum_vacuum_scale_factor");
+            String autovacuum_vacuum_threshold = art.servers.Shared.getPropertyValueString("traces.autovacuum_vacuum_threshold");
+            String autovacuum_analyze_scale_factor = art.servers.Shared.getPropertyValueString("traces.autovacuum_analyze_scale_factor");
+            String autovacuum_analyze_threshold = art.servers.Shared.getPropertyValueString("traces.autovacuum_analyze_threshold");
+
+            if (autovacuum_enabled == null) autovacuum_enabled = enabled;
+            if (autovacuum_vacuum_scale_factor == null) autovacuum_vacuum_scale_factor = "0.0";
+            if (autovacuum_vacuum_threshold == null) autovacuum_vacuum_threshold = "1000";
+            if (autovacuum_analyze_scale_factor == null) autovacuum_analyze_scale_factor = "0.0";
+            if (autovacuum_analyze_threshold == null) autovacuum_analyze_threshold = "1000";
+
+            try{Shared.controllerDatabase.historical_update("ALTER TABLE " + tablename + " SET (autovacuum_enabled = " + enabled + ", toast.autovacuum_enabled = " + enabled + ")");} catch (Exception e){};
+            try{Shared.controllerDatabase.historical_update("ALTER TABLE " + tablename + " SET (autovacuum_vacuum_scale_factor = 0.0)");} catch (Exception e){};
+            try{Shared.controllerDatabase.historical_update("ALTER TABLE " + tablename + " SET (autovacuum_vacuum_threshold = 1000)");} catch (Exception e){};
+            try{Shared.controllerDatabase.historical_update("ALTER TABLE " + tablename + " SET (autovacuum_analyze_scale_factor = 0.0)");} catch (Exception e){};
+            try{Shared.controllerDatabase.historical_update("ALTER TABLE " + tablename + " SET (autovacuum_analyze_threshold = 1000)");} catch (Exception e){};
+        }
+        catch (Exception exception)
+        {
+            
+        }
+    }
+            
+    
+    
+    
+    private long getLastTimestamp(String identifier, long timestamp1) throws ServerException, Exception
+    {   
+        ResultSet result = null;
+        
+        try
+        {
+            String where = "type = '" + deviceClassName + "' AND timestamp <= " + timestamp1;
+
+            if (identifier != null)
+            {
+                if (identifier.length() > 0)
+                {
+                    where = where + " AND identifier = '" + identifier + "'";
+                }
+            }
+
+            String command = "SELECT timestamp FROM DEVICES WHERE " + where + " ORDER BY timestamp DESC limit 1";
+            result = Shared.controllerDatabase.getHistoricalPersistance().get(0).executeQuery(command);
+            result.next();
+            long timestamp = result.getLong(1);
+            return(timestamp);
+        }
+        catch (Exception e)
+        {
+            return(timestamp1);
+        }
+        finally
+        {
+           try { result.close(); } catch (Exception e) {};
+        }
+    }
+            
+    
+
+    
+    protected Mutex getMutex(Device device)
+    {
+        return getMutex(device.getIdentifier());
+    }
+    
+    
+
+    protected Mutex getMutex(String identifier)
+    {
+        Mutex mutex = (Mutex)mmutex.get(identifier);
+        
+        if (mutex == null) 
+        {
+            mutex = new Mutex();
+            mmutex.put(identifier, mutex);
+        }
+        
+        return mutex;
+    }
+    
+
+}
+
+
diff --git a/servers/server/src/art/servers/Server.java b/servers/server/src/art/servers/Server.java
new file mode 100644
index 0000000..f0074d8
--- /dev/null
+++ b/servers/server/src/art/servers/Server.java
@@ -0,0 +1,450 @@
+package art.servers;
+
+import art.library.gui.FlatGUI;
+import art.library.gui.flat.FlatDialog;
+import art.library.interop.serialization.Serialization;
+import art.library.model.devices.application.Application;
+import art.library.model.devices.application.ApplicationAlarms;
+import art.library.model.devices.application.ApplicationRealtime;
+import art.library.model.devices.application.ApplicationStatus;
+import art.library.persistence.PersistenceDatabaseParameters;
+import art.library.utils.ArticProcesses;
+import art.library.utils.licence.Licence;
+import art.library.utils.resources.Resources;
+import art.library.utils.windows.SystemProcess;
+import art.servers.configuration.Configuration;
+import art.servers.controller.ControllerDatabase;
+import art.servers.controller.ControllerListener;
+import art.servers.controller.ControllerListenerDebug;
+import art.servers.controller.ControllerListenerHttp;
+import art.servers.controller.ControllerListenerHttps;
+import art.servers.controller.ControllerNtpHttp;
+import art.servers.controller.ControllerProcessInformation;
+import art.servers.controller.ControllerStatus;
+import art.servers.controller.ControllerTransactions;
+import art.servers.controller.ControllerUserPermissions;
+import art.servers.gui.ArticWindow;
+import java.awt.GraphicsDevice;
+import java.awt.GraphicsEnvironment;
+import java.awt.Toolkit;
+import java.awt.datatransfer.Clipboard;
+import java.awt.datatransfer.StringSelection;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.net.InetAddress;
+import java.security.cert.X509Certificate;
+import java.util.Properties;
+import javax.net.ssl.HostnameVerifier;
+import javax.net.ssl.HttpsURLConnection;
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.SSLSession;
+import javax.net.ssl.TrustManager;
+import javax.net.ssl.X509TrustManager;
+import javax.swing.JOptionPane;
+import javax.swing.UIManager;
+
+
+
+public class Server 
+{
+    public static void preinitialise(String[] args) throws Exception
+    {
+        preinitialise(args, Configuration.class);
+    }
+            
+    public static void preinitialise(String[] args, Class configurationClass) throws Exception
+    {
+        Shared.debug = existParameter(args, "-debug");
+        Shared.reloadDevices = existParameter(args, "--reload");
+        Shared.restoreDevices = existParameter(args, "--restore");
+                
+        // Look and feel
+        UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
+
+        
+        // SSL accept key
+        
+        TrustManager[] trustAllCerts = new TrustManager[] {new MyTrustManager()};
+        SSLContext sc = SSLContext.getInstance("SSL");
+        sc.init(null, trustAllCerts, new java.security.SecureRandom());
+        HostnameVerifier allHostsValid = new HostnameVerifier() 
+        {
+            public boolean verify(String hostname, SSLSession session) 
+            {
+                return true;
+            }
+        };
+        HttpsURLConnection.setDefaultHostnameVerifier(allHostsValid);
+        HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
+
+
+        // Configuration
+
+        String configurationFile = getParameter(args, "-config");
+
+        if (configurationFile != null)
+        {
+            Shared.configuration = (Configuration)Serialization.deserialize(configurationClass, new File(configurationFile));
+        }
+        else if (new File(Shared.getApplicationName() + ".json").exists())
+        {
+            Shared.configuration = (Configuration)Serialization.deserialize(configurationClass, new File(Shared.getApplicationName() + ".json"));
+        }
+        else
+        {
+            Shared.configuration = (Configuration)Serialization.deserialize(configurationClass, Resources.getResourceStream("data/" + Shared.getApplicationName() + ".json"));
+        }
+
+        if (existParameter(args, "-nogui") == false)
+        {
+            FlatGUI.initialise(Shared.configuration.general.language);
+        }
+
+
+        // Properties
+
+        if (Shared.configuration.general.mproperties != null)
+        {
+            Properties properties = System.getProperties();
+
+            for (String key : Shared.configuration.general.mproperties.keySet()) 
+            {
+                String value = Shared.configuration.general.mproperties.get(key);
+                properties.setProperty(key, value);
+            }
+
+            System.setProperties(properties);
+        }
+        
+
+        // License
+
+        boolean license = true;
+
+        if (existParameter(args, "-code") == true)
+        {
+            license = getParameter(args, "-code").equals(Shared.getApplicationCode());
+        }
+        
+        
+        if (existParameter(args, "--license") == true)
+        {
+            String password = getParameter(args, "--license");
+            
+            if ((password.equalsIgnoreCase("¡¡register!!") == true) || (password.equalsIgnoreCase("**register**") == true))
+            {
+                FileOutputStream fos = new FileOutputStream(new File(Shared.getApplicationName() + ".license"));
+                fos.write(Licence.licenceGeneration(Licence.codeGeneration(Shared.getApplicationCode())).getBytes());
+                fos.close();
+            }
+        }
+
+        if (license == false)
+        {
+            if (Licence.hasLicence(Shared.getApplicationCode(), new File(Shared.getApplicationName() + ".license")) == false)
+            {
+                codeGeneration();
+            }
+        }
+
+        
+        // User and password database desencryption
+        
+        if (Shared.configuration.database != null)
+        {
+            for (PersistenceDatabaseParameters parameters : Shared.configuration.database)
+            {
+                parameters.user = Licence.decrypt(parameters.user);
+                parameters.password = Licence.decrypt(parameters.password);
+            }
+        }
+
+
+        // Application device, status
+
+        Application application = new Application(Shared.configuration.application);
+        application.status = new ApplicationStatus();
+        application.alarms = new ApplicationAlarms();
+        
+        if (Shared.configuration.listener != null)
+        {
+            application.information.serverAddressExternal = Shared.configuration.listener.addressExternal;
+            application.information.serverPortExternal = Shared.configuration.listener.portExternal;        
+        }
+
+        Shared.controllerStatus = new ControllerStatus(application);
+        Shared.lcontroller.add(Shared.controllerStatus);
+        
+        if (Shared.configuration.listener != null)
+        {
+            application.getDeviceInformation().serverAddress = Shared.configuration.listener.address;
+            application.getDeviceInformation().serverPort = Shared.configuration.listener.port;
+        }
+        else
+        {
+            application.getDeviceInformation().serverAddress = InetAddress.getLocalHost().getHostAddress();
+            application.getDeviceInformation().serverPort = 0;
+        }
+
+        
+
+        // Is already running
+
+        if (Shared.configuration.general.executableName != null)
+        {
+            long pid = ArticProcesses.getPID();
+            
+            for (SystemProcess process : ArticProcesses.getProcesses(Shared.configuration.general.executableName))
+            {
+                if (process.pid != pid)
+                {
+                    if (existParameter(args, "-nogui") == false)
+                    {
+                        JOptionPane.showMessageDialog(null, Shared.getMessage("Process %1 already opened").replace("%1", Shared.configuration.general.executableName), Shared.getMessage("Error"), JOptionPane.ERROR_MESSAGE);
+                    }
+                    else
+                    {
+                        System.out.println(Shared.getMessage("Process %1 already opened").replace("%1", Shared.configuration.general.executableName));
+                    }
+
+                    System.exit(0);
+                }
+            }
+        }
+
+        
+        // Controller database
+
+        if (Shared.configuration.database != null)
+        {
+            Shared.controllerDatabase = new ControllerDatabase(Shared.configuration);
+            Shared.lcontroller.add(Shared.controllerDatabase);
+        }
+        
+        // Controller user permissions
+     
+        Shared.controllerUserPermissions = new ControllerUserPermissions();
+        
+        // Controller process information
+
+        Shared.controllerProcessInformation = new ControllerProcessInformation();
+        
+        
+                
+        // Controller transactions
+
+        if (Shared.configuration.transactions != null)
+        {
+            Shared.controllerTransactions = new ControllerTransactions(Shared.configuration.transactions);
+            Shared.lcontroller.add(Shared.controllerTransactions);
+        }
+        
+        
+        // Controller NTP HTTP
+        
+        if (Shared.configuration.controllerNTPHTTP != null)
+        {
+            Shared.controllerNtpHttp = new ControllerNtpHttp(Shared.configuration.controllerNTPHTTP);
+            Shared.lcontroller.add(Shared.controllerNtpHttp);
+        }
+
+    }
+    
+    
+    
+    
+    public static void postinitialise(String[] args) throws Exception
+    {
+
+        // Graphical interface
+
+        if (existParameter(args, "-nogui") == false)
+        {
+            GraphicsDevice gd = GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice();
+            int screenWidth = gd.getDisplayMode().getWidth();
+            int screenHeight = gd.getDisplayMode().getHeight();
+            Shared.window = new ArticWindow();
+            Shared.window.setLocation(Shared.configuration.general.windowX, Shared.configuration.general.windowY);
+            Shared.window.setSize(Math.min(Shared.configuration.general.windowW, screenWidth), Math.min(Shared.configuration.general.windowH, screenHeight));
+        }
+
+
+        // Controller listener aluvisa
+
+        if (Shared.configuration.listener != null)
+        {
+            Shared.controllerListener = new ControllerListener(Shared.configuration.listener);
+            Shared.lcontroller.add(Shared.controllerListener);
+        }
+
+        
+        // Controller listener http
+
+        if (Shared.configuration.listenerHttp != null)
+        {
+            if (Shared.configuration.listenerHttp.readUser != null) Shared.configuration.listenerHttp.readUser = Licence.decrypt(Shared.configuration.listenerHttp.readUser);
+            if (Shared.configuration.listenerHttp.readPassword != null) Shared.configuration.listenerHttp.readPassword = Licence.decrypt(Shared.configuration.listenerHttp.readPassword);
+            if (Shared.configuration.listenerHttp.writeUser != null) Shared.configuration.listenerHttp.writeUser = Licence.decrypt(Shared.configuration.listenerHttp.writeUser);
+            if (Shared.configuration.listenerHttp.writePassword != null) Shared.configuration.listenerHttp.writePassword = Licence.decrypt(Shared.configuration.listenerHttp.writePassword);
+            Shared.controllerListenerHttp = new ControllerListenerHttp(Shared.configuration.listenerHttp);
+            Shared.lcontroller.add(Shared.controllerListenerHttp);
+        }
+
+        // Controller listener https
+
+        if (Shared.configuration.listenerHttps != null)
+        {
+            if (Shared.configuration.listenerHttps.readUser != null) Shared.configuration.listenerHttps.readUser = Licence.decrypt(Shared.configuration.listenerHttps.readUser);
+            if (Shared.configuration.listenerHttps.readPassword != null) Shared.configuration.listenerHttps.readPassword = Licence.decrypt(Shared.configuration.listenerHttps.readPassword);
+            if (Shared.configuration.listenerHttps.writeUser != null) Shared.configuration.listenerHttps.writeUser = Licence.decrypt(Shared.configuration.listenerHttps.writeUser);
+            if (Shared.configuration.listenerHttps.writePassword != null) Shared.configuration.listenerHttps.writePassword = Licence.decrypt(Shared.configuration.listenerHttps.writePassword);
+            if (Shared.configuration.listenerHttps.keystorePassword != null) Shared.configuration.listenerHttps.keystorePassword = Licence.decrypt(Shared.configuration.listenerHttps.keystorePassword);
+            Shared.controllerListenerHttps = new ControllerListenerHttps(Shared.configuration.listenerHttps);
+            Shared.lcontroller.add(Shared.controllerListenerHttps);
+        }
+            
+
+
+        // Controller listener debug
+
+        if (Shared.configuration.debug != null)
+        {
+            Shared.controllerListenerDEBUG = new ControllerListenerDebug(Shared.configuration.debug);
+            Shared.controllerListenerDEBUG.start();
+        }
+        else if (Shared.configuration.logger != null)
+        {
+            Shared.controllerListenerDEBUG = new ControllerListenerDebug(Shared.configuration.logger);
+            Shared.controllerListenerDEBUG.start();
+        }
+        
+        
+        // Start controller status
+
+        Shared.controllerStatus.start();
+       
+        try
+        {
+            Application application = Shared.controllerStatus.getApplication();
+            ApplicationRealtime realtime = (ApplicationRealtime)application.getDeviceRealtime();
+            realtime.traces = Shared.model.getLastTraces(Shared.getLanguage(), Shared.getApplicationName(), ApplicationRealtime.MAX_TRACES);
+        }
+        catch (Exception exception)
+        {
+        }
+        
+        // Version
+
+        System.out.println(Shared.getApplicationName() + ", version " + Shared.version());
+        Shared.printVersion("art.library.adf", "adf.version.properties");
+        Shared.printVersion("art.library.andigo", "andigo.version.properties");
+        Shared.printVersion("art.library.flatgui", "flatgui.version.properties");
+        Shared.printVersion("art.library.interop", "interop.version.properties");
+        Shared.printVersion("art.library.model", "model.version.properties");
+        Shared.printVersion("art.library.net", "net.version.properties");
+        Shared.printVersion("art.library.osm", "osm.version.properties");
+        Shared.printVersion("art.library.persistence", "persistence.version.properties");
+        Shared.printVersion("art.library.server", "server.version.properties");           
+        Shared.printVersion("art.library.utils", "utils.version.properties");
+        
+    }
+    
+    
+    
+    public static String getParameter(String arguments[], String parameter)
+    {
+        try
+        {
+            for (int i=0; i<arguments.length; i++)
+            {
+               if (arguments[i].equalsIgnoreCase(parameter))
+               {
+                   return arguments[i+1];
+               }
+            }
+        }
+        catch (Exception e)
+        {
+        }
+        
+        return  null;
+        
+    }
+
+
+    
+    public static boolean existParameter(String arguments[], String parameter)
+    {
+        try
+        {
+            for (int i=0; i<arguments.length; i++)
+            {
+               if (arguments[i].equalsIgnoreCase(parameter))
+               {
+                   return true;
+               }
+            }
+        }
+        catch (Exception e)
+        {
+        }
+        
+        return  false;
+    }
+        
+    
+    
+
+    public static void codeGeneration()
+    {
+        try            
+        {
+            String code = Licence.codeGeneration(Shared.getApplicationCode());
+            StringSelection stringSelection = new StringSelection(code);
+            Clipboard clpbrd = Toolkit.getDefaultToolkit().getSystemClipboard();
+            clpbrd.setContents(stringSelection, null);
+            String message = Shared.getMessage("Copy below code and send to provider to activate product");
+            message = message + "\n\n" + code + "\n\n";
+            System.out.println(message);
+            FlatDialog.showDialog(null, Shared.getMessage("License code"), message, true, FlatDialog.DIALOG_INFORMATION);
+        }
+        catch (Exception e)
+        {
+            try            
+            {
+                String message = Shared.getMessage("Error in licence generation");
+                message = message + "\n";
+                message = message + Shared.getMessage("Contact provider to solve the problem");
+                System.out.println(message);
+                FlatDialog.showDialog(null, Shared.getMessage("Error"), message, true, FlatDialog.DIALOG_ERROR);
+            }
+            catch (Exception exception)
+            {
+            }
+        }
+        
+        System.exit(0);
+    }
+        
+
+    
+    
+    private static class MyTrustManager implements X509TrustManager 
+    {
+        public java.security.cert.X509Certificate[] getAcceptedIssuers() 
+        {
+            return null;
+        }
+
+        public void checkClientTrusted(X509Certificate[] certs, String authType) 
+        {
+        }
+
+        public void checkServerTrusted(X509Certificate[] certs, String authType) 
+        {
+        }
+    }
+    
+        
+    
+}
diff --git a/servers/server/src/art/servers/ServerException.java b/servers/server/src/art/servers/ServerException.java
new file mode 100644
index 0000000..688a4a2
--- /dev/null
+++ b/servers/server/src/art/servers/ServerException.java
@@ -0,0 +1,36 @@
+package art.servers;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+
+
+public class ServerException extends Exception
+{
+    private String message = null;
+            
+    public ServerException(String message)
+    {
+        this.message = message;
+    }
+
+            
+    public ServerException(Exception exception)
+    {
+        this.message = exception.getMessage();
+    }
+
+    public String getMessage()
+    {
+        if (message != null) return message;
+        return "Unexpected error";
+    }    
+
+    public String getStackMessage()
+    {
+        StringWriter sw = new StringWriter();
+        printStackTrace(new PrintWriter(sw));
+        return (sw.toString());
+    }    
+
+    
+}
diff --git a/servers/server/src/art/servers/Shared.java b/servers/server/src/art/servers/Shared.java
new file mode 100644
index 0000000..d7062e5
--- /dev/null
+++ b/servers/server/src/art/servers/Shared.java
@@ -0,0 +1,684 @@
+package art.servers;
+
+import art.library.model.devices.Device;
+import art.library.model.devices.user.UserPermission;
+import art.library.model.transactions.traces.Note;
+import art.library.model.transactions.traces.Trace;
+import art.library.utils.licence.Licence;
+import art.library.utils.mail.MailMessage;
+import art.library.utils.mail.SMTP;
+import art.library.utils.mail.SMTPConfiguration;
+import art.library.utils.resources.Resources;
+import art.library.utils.synchro.Mutex;
+import art.servers.configuration.Configuration;
+import art.servers.controller.Controller;
+import art.servers.controller.ControllerDatabase;
+import art.servers.controller.ControllerDevice;
+import art.servers.controller.ControllerListener;
+import art.servers.controller.ControllerListenerDebug;
+import art.servers.controller.ControllerListenerHttp;
+import art.servers.controller.ControllerListenerHttps;
+import art.servers.controller.ControllerNtpHttp;
+import art.servers.controller.ControllerProcessInformation;
+import art.servers.controller.ControllerStatus;
+import art.servers.controller.ControllerTransactions;
+import art.servers.controller.ControllerUserPermissions;
+import art.servers.controller.FactoryController;
+import art.servers.gui.ArticWindow;
+import art.servers.types.HttpAuthentication;
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.net.InetAddress;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Timer;
+import java.util.TimerTask;
+
+public class Shared 
+{
+    private static String applicationCode = null;
+    private static String applicationName = null;
+    
+    public static boolean debug = false;
+    public static boolean reloadDevices = false;
+    public static boolean restoreDevices = false;
+    
+    public static Configuration configuration = null;
+    public static Model model = null;
+    public static FactoryController factory = null;
+    public static ControllerStatus controllerStatus = null;
+    public static ControllerDatabase controllerDatabase = null;
+    public static ControllerListener controllerListener = null;    
+    public static ControllerTransactions controllerTransactions = null;    
+    public static ControllerListenerHttp controllerListenerHttp = null;    
+    public static ControllerListenerHttps controllerListenerHttps = null;    
+    public static ControllerUserPermissions controllerUserPermissions = null;
+    public static ControllerProcessInformation controllerProcessInformation = null;
+    public static ControllerNtpHttp controllerNtpHttp = null;    
+    
+    public static List<Controller> lcontroller = new ArrayList<Controller>();
+    private static HashMap<String, UserPermission> usersPermissions = new HashMap<String, UserPermission>();
+    public static ArticWindow window = null;
+    public static ControllerListenerDebug controllerListenerDEBUG = null;
+    private static Mutex mutexUserPermissions = new Mutex();
+
+
+    public static int RESULT_OK = 0;
+    public static int ERROR_WRONG_PASSWORD = 1;
+    public static int ERROR_FIRST_ACCESS = 2;
+    public static int ERROR_BLOCKED_USER = 3;
+    public static int ERROR_BLOCKED_ADDRESS = 4;
+
+
+    public static void setApplicationCode(String code)
+    {
+        Shared.applicationCode = code;
+    }
+    
+    public static void setApplicationName(String name)
+    {
+        Shared.applicationName = name;
+    }
+    
+    public static String getApplicationName()
+    {
+        return Shared.applicationName;
+    }
+    
+    public static String getApplicationCode()
+    {
+        return Shared.applicationCode;
+    }
+    
+    public static String getLanguage()
+    {
+        return configuration.general.language;
+    }
+    
+    public static void setLanguage(String language)
+    {
+        try
+        {
+            configuration.setLanguage(language);
+        }
+        catch (Exception e)
+        {
+        }
+    }
+
+    public static String getMessage(String language, String identifier)
+    {
+        if (configuration == null) return identifier;
+        return configuration.getMessage(language, identifier);
+    }
+    
+
+
+    
+    public static UserPermission getUserPermission(String username)
+    {
+        try
+        {
+            mutexUserPermissions.lockRead();
+            return(usersPermissions.get(username));
+        }
+        catch (Exception e)
+        {
+            return(null);
+        }
+        finally
+        {
+            mutexUserPermissions.releaseRead();
+        }
+    }
+    
+
+    public static void setUserPermission(String username, UserPermission permission)
+    {
+        try
+        {
+            mutexUserPermissions.lockWrite();
+            usersPermissions.put(username, permission);
+        }
+        catch (Exception e)
+        {
+            
+        }
+        finally
+        {
+            mutexUserPermissions.releaseWrite();
+        }
+    }
+
+
+    
+    public static String getMessage(String identifier)
+    {
+        try
+        {
+            return configuration.getMessage(identifier);
+        }
+        catch (Exception e)
+        {
+            return(identifier);
+        }
+    }
+    
+
+    public static <T>T getDeviceController(Device device) throws ServerException
+    {
+        return getDeviceController(device.getIdentifier());
+    }
+        
+    
+    public static <T>T getDeviceController(String identifier) throws ServerException
+    {
+        try
+        {
+            // Acceso a la lista sin mutex, en algun caso podria haber colisión si se elinina
+            // algun dispositivo y se quita de la lista mientras estamos leyendo
+            
+            for (Controller controller : lcontroller)
+            {
+                if (controller instanceof ControllerDevice)
+                {
+                    ControllerDevice controllerDevice = (ControllerDevice)controller;
+                    
+                    if (((Device)controllerDevice.getDevice()).getIdentifier().equals(identifier))
+                    {
+                        return (T)controller;
+                    }
+                }
+            }
+        }
+        catch (Exception e)
+        {
+        }
+        
+        throw new ServerException("Device controller does not exists");
+    }    
+        
+    
+
+    public static <T>T getDeviceController(String classname, int number) throws ServerException
+    {
+        try
+        {
+            // Acceso a la lista sin mutex, en algun caso podria haber colisión si se elinina
+            // algun dispositivo y se quita de la lista mientras estamos leyendo
+
+            for (Controller controller : lcontroller)
+            {
+                if (controller instanceof ControllerDevice)
+                {
+                    ControllerDevice controllerDevice = (ControllerDevice)controller;
+                    Device device = ((Device)controllerDevice.getDevice());
+
+                    if ((device.getClassName().equalsIgnoreCase(classname)) && (device.getDeviceInformation().number == number))
+                    {
+                        return (T)controller;
+                    }
+                }
+            }
+        }
+        catch (Exception e)
+        {
+        }
+        
+        throw new ServerException("Device controller does not exists");
+    }    
+    
+
+    
+
+    public static List<ControllerDevice> getDeviceControllers() throws ServerException
+    {
+        List<ControllerDevice> result  = new ArrayList<ControllerDevice>();
+                
+        try
+        {
+            // Acceso a la lista sin mutex, en algun caso podria haber colisión si se elinina
+            // algun dispositivo y se quita de la lista mientras estamos leyendo
+            
+            for (Controller controller : lcontroller)
+            {
+                if (controller instanceof ControllerDevice)
+                {
+                    result.add((ControllerDevice)controller);
+                }
+            }
+        }
+        catch (Exception e)
+        {
+        }
+        
+        return(result);
+    }    
+    
+    
+    
+    
+    public static boolean existsDeviceController(Device device)
+    {
+        return existsDeviceController(device.getIdentifier());
+    }
+    
+    
+    
+    public static boolean existsDeviceController(String identifier)
+    {
+        try
+        {
+            for (Controller controller : lcontroller)
+            {
+                if (controller instanceof ControllerDevice)
+                {
+                    ControllerDevice controllerDevice = (ControllerDevice)controller;
+
+                    if (((Device)controllerDevice.getDevice()).getIdentifier().equals(identifier))
+                    {
+                        return true;
+                    }
+                }
+            }
+        }
+        catch (Exception e)
+        {
+        }
+        
+        return false;
+    }        
+    
+
+
+
+
+
+    public static boolean mailNotificacion(Device device, MailMessage message)
+    {
+        boolean result = true;
+
+        for (SMTPConfiguration configuration : Shared.configuration.lsmtp)
+        {
+            try
+            {
+                configuration.smtpPassword = Licence.decrypt(configuration.smtpPassword);
+            }
+            catch (Exception e)
+            {
+            }
+                    
+            try
+            {
+                try
+                {
+                    SMTP smtp = new SMTP(configuration);
+                    smtp.send(message);
+                }
+                catch (Exception exception)
+                {
+                    result = false;
+                }
+            }
+            catch (Exception e)
+            {
+            }
+        }
+        
+        return result;
+    }
+    
+    
+    
+    
+    public static boolean isServerEnabled()
+    {
+        return true;
+    }
+    
+    
+
+    public static String version()
+    {
+        String message = "";
+        
+        try
+        {
+            String data = new String(Resources.getResourceData("version.properties"));
+            data = data.replaceAll("(?m)^\\s*\\r?\\n|\\r?\\n\\s*(?!.*\\r?\\n)", "");
+            String[] lines = data.split("\\r?\\n");
+            message = message + (lines[2].replace("major=", "") + "." + lines[3].replace("minor=", "") + "." + lines[4].replace("revision=", "") + " " + lines[5].replace("=", " ") + ", " + lines[1].replace("date=", ""));
+        }
+        catch (Exception e)
+        {
+        }
+
+        return message;
+    }   
+      
+    
+    
+    public static void printVersion(String applicationName, String fileName)
+    {
+        try
+        {
+            String data = new String(Resources.getResourceData(fileName));
+            data = data.replaceAll("(?m)^\\s*\\r?\\n|\\r?\\n\\s*(?!.*\\r?\\n)", "");
+            String[] lines = data.split("\\r?\\n");
+            Shared.println(applicationName, "Version: " + (lines[2].replace("major=", "") + "." + lines[3].replace("minor=", "") + "." + lines[4].replace("revision=", "") + " " + lines[5].replace("=", " ") + ", " + lines[1].replace("date=", "")));
+        }
+        catch (Exception e)
+        {
+        }        
+    }   
+
+    
+
+    public static Trace getTrace()
+    {
+        Trace trace = new Trace();
+        trace.timestamp = System.currentTimeMillis();
+        trace.username = Shared.getApplicationName();
+        trace.application = Shared.getApplicationName();
+        
+        try
+        {
+            trace.sourceComputer = InetAddress.getLocalHost().getHostName();
+            trace.destinationComputer = trace.sourceComputer;
+        }
+        catch (Exception e)
+        {
+        }
+        
+        return trace;
+    }
+    
+    
+    
+
+
+    
+    
+    public static void exit()
+    {
+        for (Controller controller : Shared.lcontroller)
+        {
+            try { controller.close(); } catch (Exception e) { }
+        }
+        
+        Timer timer = new Timer();
+        timer.schedule(new TimerTask() 
+        {
+            public void run () 
+            {
+                // Let some time to finish current operations
+                System.exit(0);
+            }
+        }, 5000);        
+    }
+    
+        
+
+    public static boolean getPropertyValueBoolean(String key)
+    {
+        try
+        {
+            return(Boolean.parseBoolean(System.getProperty(key)));
+        }
+        catch (Exception exception)
+        {
+            
+        }
+
+        return(false);
+    }
+    
+        
+
+    public static String getPropertyValueString(String key)
+    {
+        try
+        {
+            return(System.getProperty(key));
+        }
+        catch (Exception exception)
+        {
+            
+        }
+
+        return(null);
+    }
+    
+    
+    
+    
+    
+    // <editor-fold defaultstate="collapsed" desc="prints">  
+    
+    
+    public static void println(Trace trace, boolean save)
+    {
+        try
+        {
+            controllerListenerDEBUG.println(trace, save);
+        }
+        catch (Exception e)
+        {
+        }
+    }
+
+
+    public static void println(String service, String message)
+    {
+        try
+        {
+            controllerListenerDEBUG.println(new Note(Trace.TRACE_INFORMATION, service + " | " + message), false);
+        }
+        catch (Exception e)
+        {
+        }
+    }
+    
+    public static void println(String service, Exception exception)
+    {
+        try
+        {
+            controllerListenerDEBUG.println(new Note(Trace.TRACE_ERROR, service + " | " + exception.toString()), false);
+        }
+        catch (Exception e)
+        {
+        }
+    }
+
+    
+    
+    public static void printerr(String service, String message)
+    {
+        try
+        {
+            controllerListenerDEBUG.println(new Note(Trace.TRACE_ERROR, service + " | " + message), false);
+        }
+        catch (Exception e)
+        {
+        }
+    }
+
+
+    public static void printstack(String service, Exception exception)
+    {
+        try
+        {
+            StringWriter sw = new StringWriter();
+            exception.printStackTrace(new PrintWriter(sw));
+            controllerListenerDEBUG.println(new Note(Trace.TRACE_ERROR, service + " | " + sw.toString()), false);
+        }
+        catch (Exception e)
+        {
+        }
+    }
+
+        
+    
+    
+    public static void printcorrect(String service, String message)
+    {
+        try
+        {
+            controllerListenerDEBUG.println(new Note(Trace.TRACE_CORRECT, service + " | " + message), false);
+        }
+        catch (Exception e)
+        {
+        }
+    }
+
+    
+    public static void printwarning(String service, String message)
+    {
+        try
+        {
+            controllerListenerDEBUG.println(new Note(Trace.TRACE_WARNING, service + " | " + message), false);
+        }
+        catch (Exception e)
+        {
+        }
+    }
+    
+    // </editor-fold>  
+
+    
+
+    // <editor-fold defaultstate="collapsed" desc="traces">  
+
+    public static Trace traceInformation(String service, String action)
+    {
+        Trace trace = Trace.getTraceInformation(Shared.getApplicationName(), service, Shared.getMessage(action), Shared.getMessage("Success"));
+        println(trace, true);
+        return trace;
+    }    
+
+    
+    public static Trace traceInformation(String service, String action, String resource)
+    {
+        Trace trace = Trace.getTraceInformation(Shared.getApplicationName(), service, Shared.getMessage(action), Shared.getMessage("Success"));
+        trace.resource = resource;
+        println(trace, true);
+        return trace;
+    }    
+
+    
+    public static Trace traceInformation(String service, String action, HttpAuthentication authentication, String language)
+    {
+        Trace trace = Trace.getTraceInformation(Shared.getApplicationName(), service, Shared.getMessage(language, action), Shared.getMessage(language, "Success"));
+        
+        if (authentication != null)
+        {
+            trace.username = authentication.username;
+            trace.sourceComputer = authentication.address;
+        }
+        
+        println(trace, true);
+        return trace;
+    }
+    
+
+    public static Trace traceInformation(String service, String action, String resource, HttpAuthentication authentication, String language)
+    {
+        Trace trace = Trace.getTraceInformation(Shared.getApplicationName(), service, Shared.getMessage(language, action), Shared.getMessage(language, "Success"));
+        
+        if (authentication != null)
+        {
+            trace.username = authentication.username;
+            trace.sourceComputer = authentication.address;
+        }
+        
+        trace.resource = resource;
+        println(trace, true);
+        return trace;
+    }
+    
+    
+
+    public static Trace traceError(String service, String action, Exception exception, HttpAuthentication authentication, String language)
+    {
+        Trace trace = Trace.getTraceError(Shared.getApplicationName(), service, Shared.getMessage(language, action), exception);
+        
+        if (authentication != null)
+        {
+            trace.username = authentication.username;
+            trace.sourceComputer = authentication.address;
+        }
+
+        println(trace, true);
+        return trace;
+    }
+    
+    
+
+    public static Trace traceError(String service, String action, String resource, Exception exception, HttpAuthentication authentication, String language)
+    {
+        Trace trace = Trace.getTraceError(Shared.getApplicationName(), service, Shared.getMessage(language, action), exception);
+        
+        if (authentication != null)
+        {
+            trace.username = authentication.username;
+            trace.sourceComputer = authentication.address;
+        }
+        
+        trace.resource = resource;  
+        println(trace, true);
+        return trace;
+    }
+    
+    
+
+    public static Trace traceError(String service, String action, Exception exception)
+    {
+        Trace trace = Trace.getTraceError(Shared.getApplicationName(), service, Shared.getMessage(action), exception);
+        println(trace, true);
+        return trace;
+    }    
+    
+    
+
+
+    public static Trace traceError(String service, String action, String resource, Exception exception)
+    {
+        Trace trace = Trace.getTraceError(Shared.getApplicationName(), service, Shared.getMessage(action), exception);
+        trace.resource = resource;
+        println(trace, true);
+        return trace;
+    }    
+            
+        
+
+    public static Trace traceError(String service, String action, String resource, String exception)
+    {
+        Trace trace = Trace.getTraceError(Shared.getApplicationName(), service, Shared.getMessage(action), exception);
+        trace.resource = resource;
+        println(trace, true);
+        return trace;
+    }    
+            
+        
+    public static Trace traceWarning(String service, String action, String resource)
+    {
+        Trace trace = Trace.getTraceWarning(Shared.getApplicationName(), service, Shared.getMessage(action), Shared.getMessage("Success"));
+        trace.resource = Shared.getMessage(resource);
+        println(trace, true);
+        return trace;
+    }        
+    
+
+
+    public static Trace traceWarning(String service, String action, String resource, String result)
+    {
+        Trace trace = Trace.getTraceWarning(Shared.getApplicationName(), service, Shared.getMessage(action), Shared.getMessage(result));
+        trace.resource = Shared.getMessage(resource);
+        println(trace, true);
+        return trace;
+    }        
+    
+    // </editor-fold>  
+    
+}
diff --git a/servers/server/src/art/servers/configuration/Configuration.java b/servers/server/src/art/servers/configuration/Configuration.java
new file mode 100644
index 0000000..8dc5a31
--- /dev/null
+++ b/servers/server/src/art/servers/configuration/Configuration.java
@@ -0,0 +1,165 @@
+package art.servers.configuration;
+
+import art.library.model.devices.application.ApplicationInformation;
+import art.library.persistence.PersistenceDatabaseParameters;
+import art.library.utils.mail.SMTPConfiguration;
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.annotation.JsonRootName;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+
+
+@JsonRootName(value = "Configuration")
+
+public class Configuration 
+{
+    @JsonProperty("General") 
+    public ConfigurationGeneral general = null;
+    
+    @JsonProperty("Application")
+    public ApplicationInformation application = null;
+    
+    @JsonProperty("Listener")
+    public ConfigurationListener listener = null;
+
+    @JsonProperty("Listener http")
+    public ConfigurationListenerHttp listenerHttp = null;
+
+    @JsonProperty("Listener https")
+    public ConfigurationListenerHttp listenerHttps = null;
+
+    @JsonProperty("Listener web")
+    public ConfigurationListenerHttp listenerWeb = null;
+
+    @JsonProperty("NTP HTTP")
+    public ConfigurationNtpHttp controllerNTPHTTP = null;
+        
+    @JsonProperty("Database")
+    public List<PersistenceDatabaseParameters> database = null;
+    
+    @JsonProperty("SMTP")
+    public List<SMTPConfiguration> lsmtp = null;
+    
+    @JsonProperty("Symbols")
+    public List<String> symbols = null;
+    
+    @JsonProperty("Messages") 
+    public Map<String, ConfigurationMessages> lmessage = null;
+    
+    @JsonProperty("Transactions")
+    public ConfigurationTransactions transactions = null;
+    
+    @JsonProperty("Listener debug")
+    public ConfigurationListenerDEBUG debug = null;
+    
+    @JsonProperty("Logger")
+    public ConfigurationListenerDEBUG logger = null;
+
+    @JsonIgnore
+    public String getMessage(String identifier)
+    {
+        try
+        {
+            ConfigurationMessages configurationMessages = (ConfigurationMessages)this.lmessage.get(general.language);
+            return configurationMessages.getMessage(identifier);
+        }
+        catch (Exception e) 
+        {
+        }
+        
+        return identifier;
+    }        
+    
+    
+    @JsonIgnore
+    public String getMessage(String language, String identifier)
+    {
+        try
+        {
+            ConfigurationMessages configurationMessages = (ConfigurationMessages)this.lmessage.get(language);
+            return configurationMessages.getMessage(identifier);
+        }
+        catch (Exception e) 
+        {
+        }
+        
+        return identifier;
+    }        
+    
+    
+
+    @JsonIgnore
+    public void setLanguage(String language) throws Exception
+    {
+        try
+        {
+            ConfigurationMessages configurationMessages = (ConfigurationMessages)this.lmessage.get(this.general.language);
+            
+            if (configurationMessages != null)
+            {
+                this.general.language = language;
+                return;
+            }
+        }
+        catch (Exception e) 
+        {
+        }
+        
+        throw new Exception();
+    }    
+    
+    
+    
+    @JsonIgnore
+    public Locale getLocale()
+    {
+        try
+        {
+            String language = this.general.language.substring(0, 2);
+            String country = this.general.language.substring(3, 5);
+            return new Locale(language, country);
+        }
+        catch (Exception e)
+        {
+        }
+       
+        return Locale.getDefault();
+    }    
+    
+    
+
+    @JsonIgnore
+    public void sortMessages()
+    {
+        
+        for (String key : lmessage.keySet())
+        {
+            ConfigurationMessages configurationMessages = (ConfigurationMessages)this.lmessage.get(key);
+            configurationMessages.sort();
+        }
+    }
+    
+
+    @JsonIgnore
+    public PersistenceDatabaseParameters getDatabaseParameters(String area)
+    {
+        try
+        {
+            for (PersistenceDatabaseParameters parameters : database)
+            {
+                if (parameters.area.equalsIgnoreCase(area) == true) return(parameters);
+            }
+        }
+        catch (Exception e) 
+        {
+        }
+        
+        return null;
+    }        
+
+    
+    
+}
+
diff --git a/servers/server/src/art/servers/configuration/ConfigurationGeneral.java b/servers/server/src/art/servers/configuration/ConfigurationGeneral.java
new file mode 100644
index 0000000..47ab10a
--- /dev/null
+++ b/servers/server/src/art/servers/configuration/ConfigurationGeneral.java
@@ -0,0 +1,38 @@
+package art.servers.configuration;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import java.util.HashMap;
+import java.util.Map;
+
+
+public class ConfigurationGeneral 
+{
+    @JsonProperty("Language")
+    public String language;
+ 
+    @JsonProperty("Executable name")
+    public String executableName = null;
+    
+    @JsonProperty("Window title")
+    public String windowTitle = null;
+
+    @JsonProperty("Window icon")
+    public String windowIcon = null;
+    
+    @JsonProperty("Window x")
+    public int windowX = 0;
+    
+    @JsonProperty("Window y")
+    public int windowY = 0;
+    
+    @JsonProperty("Window w")
+    public int windowW = 0;
+    
+    @JsonProperty("Window h")
+    public int windowH = 0;
+    
+    @JsonProperty("Properties") 
+    public Map<String, String> mproperties = new HashMap<String, String>();
+        
+    
+}
diff --git a/servers/server/src/art/servers/configuration/ConfigurationListener.java b/servers/server/src/art/servers/configuration/ConfigurationListener.java
new file mode 100644
index 0000000..19230b3
--- /dev/null
+++ b/servers/server/src/art/servers/configuration/ConfigurationListener.java
@@ -0,0 +1,32 @@
+package art.servers.configuration;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.annotation.JsonRootName;
+
+
+@JsonRootName(value = "Listener")
+
+public class ConfigurationListener 
+{
+    @JsonProperty("Address")
+    public String address;
+
+    @JsonProperty("Port")
+    public int port;
+
+    @JsonProperty("Address external")
+    public String addressExternal;
+
+    @JsonProperty("Port external")
+    public int portExternal;
+
+    @JsonProperty("Timeout")
+    public int timeout;
+
+    @JsonProperty("Connections")
+    public int connections;
+
+    @JsonProperty("Timeout connection")
+    public int timeoutConnection = 0;
+    
+}
diff --git a/servers/server/src/art/servers/configuration/ConfigurationListenerDEBUG.java b/servers/server/src/art/servers/configuration/ConfigurationListenerDEBUG.java
new file mode 100644
index 0000000..4b97ab7
--- /dev/null
+++ b/servers/server/src/art/servers/configuration/ConfigurationListenerDEBUG.java
@@ -0,0 +1,48 @@
+package art.servers.configuration;
+
+import art.servers.types.IPv4;
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import java.util.ArrayList;
+import java.util.List;
+
+
+public class ConfigurationListenerDEBUG
+{
+    @JsonProperty("Port")
+    public int port = 0;
+
+    @JsonProperty("Maximum connections")
+    public int maximumConnections = 0;
+    
+    @JsonProperty("Allowed connections")
+    public List<String> allowedConnections = new ArrayList<String>();
+    
+    
+    
+    @JsonIgnore
+    public boolean allowed(String address)
+    {
+        try
+        {
+            if (allowedConnections.isEmpty() == true) return true;
+            
+            long address1 = IPv4.toLong(address);
+            
+            for (String connection : allowedConnections)
+            {
+                long address2 = IPv4.toLong(connection.substring(0, connection.indexOf("/")));
+                long mask = IPv4.toLong(Integer.parseInt(connection.substring(connection.indexOf("/") + 1, connection.length())));
+                if ((address1 & mask) == (address2 & mask)) return true;
+            }
+        }
+        catch (Exception e)
+        {
+        }
+        
+        return false;
+    }
+    
+    
+    
+}
diff --git a/servers/server/src/art/servers/configuration/ConfigurationListenerHttp.java b/servers/server/src/art/servers/configuration/ConfigurationListenerHttp.java
new file mode 100644
index 0000000..2b36156
--- /dev/null
+++ b/servers/server/src/art/servers/configuration/ConfigurationListenerHttp.java
@@ -0,0 +1,58 @@
+package art.servers.configuration;
+
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.annotation.JsonRootName;
+
+
+@JsonRootName(value = "Listener http")
+
+
+public class ConfigurationListenerHttp 
+{
+    @JsonProperty("Port")
+    public int port;
+
+    @JsonProperty("Timeout")
+    public int timeout;
+
+    @JsonProperty("Read user")
+    public String readUser = null;
+    
+    @JsonProperty("Read password")
+    public String readPassword = null;
+
+    @JsonProperty("Write user")
+    public String writeUser = null;
+    
+    @JsonProperty("Write password")
+    public String writePassword = null;
+    
+    @JsonProperty("Keystore location")
+    public String keystoreLocation = null;
+    
+    @JsonProperty("Keystore password")
+    public String keystorePassword = null;
+    
+    @JsonProperty("User attempts")
+    public int userAttempts = 5;
+    
+    
+    /**
+     * Time in true
+     */
+    @JsonProperty("User banner time")
+    public long bannerTime = 300;
+
+    
+    @JsonProperty("Token expiration time")
+    public long tokenExpirationTime = 86400;
+    
+    @JsonProperty("Token inactivity time")
+    public long tokenInactivityTime = 600;
+    
+    
+    
+    
+}
+
diff --git a/servers/server/src/art/servers/configuration/ConfigurationMessages.java b/servers/server/src/art/servers/configuration/ConfigurationMessages.java
new file mode 100644
index 0000000..0225646
--- /dev/null
+++ b/servers/server/src/art/servers/configuration/ConfigurationMessages.java
@@ -0,0 +1,32 @@
+package art.servers.configuration;
+
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.TreeMap;
+
+
+public class ConfigurationMessages 
+{
+    @JsonProperty("Messages")
+    public Map<String, String> messages = new HashMap<String, String>();
+    
+    @JsonIgnore
+    public String getMessage(String identifier)
+    {
+        String result = messages.get(identifier);
+        if (result == null) return identifier;
+        return result; 
+    }
+    
+
+    @JsonIgnore
+    public void sort()
+    {
+        Map<String, String> sortedMessages = new TreeMap<>(messages);
+        messages = sortedMessages;
+    }
+
+    
+}
diff --git a/servers/server/src/art/servers/configuration/ConfigurationNtpHttp.java b/servers/server/src/art/servers/configuration/ConfigurationNtpHttp.java
new file mode 100644
index 0000000..edf688e
--- /dev/null
+++ b/servers/server/src/art/servers/configuration/ConfigurationNtpHttp.java
@@ -0,0 +1,39 @@
+package art.servers.configuration;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.annotation.JsonPropertyOrder;
+
+
+
+@JsonPropertyOrder
+({ 
+    "URL",
+    "Proxy address",
+    "Proxy port",
+    "Timeout", 
+    "Maximum allowed delay", 
+    "Polling"
+})
+
+
+public class ConfigurationNtpHttp
+{
+    @JsonProperty("URL")
+    public String URL = null;
+
+    @JsonProperty("Proxy address")
+    public String proxyAddress = null;
+
+    @JsonProperty("Proxy port")
+    public int proxyPort = 0;
+
+    @JsonProperty("Timeout")
+    public int timeout = 0;
+
+    @JsonProperty("Maximum allowed delay")
+    public int maximumAllowedDelay = 0;
+
+    @JsonProperty("Polling")
+    public int polling = 0;
+    
+}
diff --git a/servers/server/src/art/servers/configuration/ConfigurationSecurity.java b/servers/server/src/art/servers/configuration/ConfigurationSecurity.java
new file mode 100644
index 0000000..d755ae6
--- /dev/null
+++ b/servers/server/src/art/servers/configuration/ConfigurationSecurity.java
@@ -0,0 +1,40 @@
+package art.servers.configuration;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.annotation.JsonPropertyOrder;
+
+
+@JsonPropertyOrder
+({ 
+    "Read password",
+    "Download password",
+    "Write password",
+    "Admin password", 
+    "Storage password",
+    "System password"
+})
+
+
+
+
+public class ConfigurationSecurity
+{
+    @JsonProperty("Read password")
+    public String readPassword = null;
+
+    @JsonProperty("Download password")
+    public String downloadPassword = null;
+
+    @JsonProperty("Write password")
+    public String writePassword = null;
+
+    @JsonProperty("Admin password")
+    public String adminPassword = null;
+
+    @JsonProperty("Storage password")
+    public String storagePassword = null;
+
+    @JsonProperty("System password")
+    public String systemPassword = null;
+
+}
diff --git a/servers/server/src/art/servers/configuration/ConfigurationTransactions.java b/servers/server/src/art/servers/configuration/ConfigurationTransactions.java
new file mode 100644
index 0000000..33fe7ed
--- /dev/null
+++ b/servers/server/src/art/servers/configuration/ConfigurationTransactions.java
@@ -0,0 +1,20 @@
+package art.servers.configuration;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.annotation.JsonRootName;
+import java.util.List;
+
+@JsonRootName(value = "Configuration transactions")
+
+public class ConfigurationTransactions 
+{
+    @JsonProperty("Name")
+    public String name;
+    
+    @JsonProperty("Polling")
+    public int polling = 60;
+    
+    @JsonProperty("Transactions services")
+    public List<ConfigurationTransactionsService> lservicesTransactions = null;
+    
+}
diff --git a/servers/server/src/art/servers/configuration/ConfigurationTransactionsService.java b/servers/server/src/art/servers/configuration/ConfigurationTransactionsService.java
new file mode 100644
index 0000000..5d6b78c
--- /dev/null
+++ b/servers/server/src/art/servers/configuration/ConfigurationTransactionsService.java
@@ -0,0 +1,21 @@
+package art.servers.configuration;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.annotation.JsonRootName;
+
+@JsonRootName(value = "Configuration transactions service")
+
+public class ConfigurationTransactionsService 
+{
+    @JsonProperty("Service")
+    public String service;
+    
+    @JsonProperty("Address")
+    public String address;
+    
+    @JsonProperty("Port")
+    public int port;
+    
+    @JsonProperty("Timeout")
+    public int timeout;
+}
diff --git a/servers/server/src/art/servers/controller/Controller.java b/servers/server/src/art/servers/controller/Controller.java
new file mode 100644
index 0000000..404bb1b
--- /dev/null
+++ b/servers/server/src/art/servers/controller/Controller.java
@@ -0,0 +1,28 @@
+package art.servers.controller;
+
+
+public class Controller extends Thread
+{
+    protected boolean exit = false;
+    
+    public void close()
+    {
+        exit = true;
+    }
+    
+    
+    public void pause(long timemillis)
+    {
+        try
+        {
+            sleep(timemillis);
+        }
+        catch (Exception exception)
+        {
+        }
+    }
+    
+    
+}
+
+
diff --git a/servers/server/src/art/servers/controller/ControllerDatabase.java b/servers/server/src/art/servers/controller/ControllerDatabase.java
new file mode 100644
index 0000000..ae67d6a
--- /dev/null
+++ b/servers/server/src/art/servers/controller/ControllerDatabase.java
@@ -0,0 +1,687 @@
+package art.servers.controller;
+
+import art.library.persistence.Persistence;
+import art.library.persistence.PersistenceDatabase;
+import art.library.persistence.PersistenceDatabaseParameters;
+import art.library.utils.licence.Licence;
+import art.library.utils.resources.Resources;
+import art.servers.Shared;
+import art.servers.configuration.Configuration;
+import java.io.File;
+import java.nio.file.Files;
+import java.sql.Connection;
+import java.sql.DriverManager;
+import java.sql.PreparedStatement;
+import java.util.ArrayList;
+import java.util.List;
+
+
+public class ControllerDatabase extends Controller
+{
+    private List<Persistence> lpersistenceTimeless = new ArrayList<Persistence>();
+    private List<Persistence> lpersistenceHistorical = new ArrayList<Persistence>();
+    private List<Persistence> lpersistence = new ArrayList<Persistence>();
+    private String name = null;
+    
+    
+    public ControllerDatabase(Configuration configuration) throws Exception
+    {
+        this.name = Shared.getMessage("Controller database");
+        this.setName(name);
+        for (PersistenceDatabaseParameters persistenceDatabaseParameters : configuration.database)
+        {
+            if (persistenceDatabaseParameters.area.equalsIgnoreCase("Timeless"))
+            {
+                PersistenceDatabase persistenceTimeless = new PersistenceDatabase(persistenceDatabaseParameters);
+                lpersistenceTimeless.add(persistenceTimeless);
+                lpersistence.add(persistenceTimeless);
+            }
+            else if (persistenceDatabaseParameters.area.equalsIgnoreCase("Historical"))
+            {
+                PersistenceDatabase persistenceHistorical = new PersistenceDatabase(persistenceDatabaseParameters);
+                lpersistenceHistorical.add(persistenceHistorical);
+                lpersistence.add(persistenceHistorical);
+            }
+        }
+        
+        reloadPLSQL();
+        
+        start();
+    }
+    
+    
+    public ControllerDatabase(List<PersistenceDatabaseParameters> lparameters) throws Exception
+    {
+        this.setName(this.getClass().getName() + " : " + this.getName());
+        
+        for (PersistenceDatabaseParameters persistenceDatabaseParameters : lparameters)
+        {
+            if (persistenceDatabaseParameters.area.equalsIgnoreCase("Timeless"))
+            {
+                PersistenceDatabase persistenceTimeless = new PersistenceDatabase(persistenceDatabaseParameters);
+                lpersistenceTimeless.add(persistenceTimeless);
+                lpersistence.add(persistenceTimeless);
+            }
+            else if (persistenceDatabaseParameters.area.equalsIgnoreCase("Historical"))
+            {
+                PersistenceDatabase persistenceHistorical = new PersistenceDatabase(persistenceDatabaseParameters);
+                lpersistenceHistorical.add(persistenceHistorical);
+                lpersistence.add(persistenceHistorical);
+            }
+        }
+        
+        reloadPLSQL();
+        
+        start();
+    }
+
+    
+    
+    public List<Persistence> getTimelessPersistance()
+    {
+        return lpersistenceTimeless;
+    }
+    
+    
+    public List<Persistence> getHistoricalPersistance()
+    {
+        return lpersistenceHistorical;
+    }
+   
+    
+    
+
+    public void run()
+    {
+        long lastTimestamp = System.currentTimeMillis();
+        
+        for (Persistence persistence : lpersistence)
+        {
+            Shared.traceInformation(name, "Disconnecting",  persistence.getName());
+        }
+        
+        
+        while ((isInterrupted() == false) && (exit == false))
+        {
+            lastTimestamp = System.currentTimeMillis();
+            {            
+                for (Persistence persistence : lpersistence)
+                {
+                    status(persistence);
+                }
+            }
+            
+            
+            long timetowait = 5000 -(System.currentTimeMillis() - lastTimestamp);
+                    
+            if (timetowait > 0)
+            {
+                try
+                {
+                    sleep(timetowait);
+                }
+                catch (Exception e)
+                {
+                }
+            }
+            
+            try
+            {
+                reloadPLSQL();
+            }
+            catch (Exception e)
+            {
+            }
+        }
+        
+        for (Persistence persistence : lpersistence) 
+        {
+            persistence.close();
+            Shared.traceInformation(name, "Finishing");
+        }
+        
+    }
+    
+    
+   
+    
+    private void reloadPLSQL()
+    {
+        for (Persistence persistence : lpersistence)
+        {
+            PersistenceDatabaseParameters persistenceDatabaseParameters = persistence.parameters;
+            
+            if (persistenceDatabaseParameters.PLSQL != null)
+            {
+                for (String path : persistenceDatabaseParameters.PLSQL)
+                {
+                    Connection connection = null;
+                    PreparedStatement statement = null;
+
+                    try
+                    {
+                        String superUser = Licence.decrypt(persistenceDatabaseParameters.superUser);
+                        String superPassword = Licence.decrypt(persistenceDatabaseParameters.superPassword);
+                        File file = new File(path);
+
+                        if (file.exists() == false)
+                        {
+                            try
+                            {
+                                String plsql = new String(Resources.getResourceBytes(path));
+
+                                if (persistenceDatabaseParameters.lastTimestampPlsqlUpdate == 0)
+                                {
+                                    connection = (Connection)DriverManager.getConnection(persistenceDatabaseParameters.connectionString, superUser, superPassword);
+                                    connection.setAutoCommit(true);
+                                    statement = connection.prepareStatement(plsql);
+                                    statement.executeUpdate();
+                                    persistenceDatabaseParameters.lastTimestampPlsqlUpdate = file.lastModified();
+                                }
+
+                            }
+                            catch (Exception e)
+                            {
+                            }
+                        }
+                        else
+                        {
+                            try
+                            {
+                                if (file.lastModified() > persistenceDatabaseParameters.lastTimestampPlsqlUpdate)
+                                {
+                                    String plsql = new String(Files.readAllBytes(file.toPath()));
+                                    connection = (Connection)DriverManager.getConnection(persistenceDatabaseParameters.connectionString, superUser, superPassword);
+                                    connection.setAutoCommit(true);
+                                    statement = connection.prepareStatement(plsql);
+                                    statement.executeUpdate();
+                                    persistenceDatabaseParameters.lastTimestampPlsqlUpdate = file.lastModified();
+                                }
+                            }
+                            catch (Exception e)
+                            {
+                            }
+                        }                    
+                    }
+                    catch (Exception e)
+                    {
+                    }
+                    
+                    try { statement.close(); } catch (Exception e) { }
+                    try { connection.close(); } catch (Exception e) { }
+                }
+            }
+        }
+    }
+
+
+
+    
+    
+    
+    private void status(Persistence persistence)
+    {
+        try
+        {
+            persistence.isConnected();
+        }
+        catch (Exception exception)
+        {
+            Shared.traceError(name, "Connecting", persistence.getName(), exception);
+        }
+    }
+    
+    
+    
+    
+    
+    /***************************************************************************
+    /* 
+    /* Timeless
+    /* 
+    ***************************************************************************/
+
+    
+    public boolean timeless_existObject(Object object) throws Exception
+    {
+        Exception exception = null;
+        
+        for (Persistence persistence : lpersistenceTimeless)
+        {
+            try
+            {
+                return persistence.existObject(object);
+            }
+            catch (Exception e)
+            {
+                exception = e;
+            }
+        }
+        
+        throw exception;
+    }
+    
+    
+    
+    public boolean timeless_existObject(String className, String where) throws Exception
+    {
+        Exception exception = null;
+        
+        for (Persistence persistence : lpersistenceTimeless)
+        {
+            try
+            {
+                return persistence.existObject(className, where);
+            }
+            catch (Exception e)
+            {
+                exception = e;
+            }
+        }
+        
+        throw exception;
+    }
+    
+    
+    
+
+    public void timeless_addObject(Object object) throws Exception
+    {
+        Exception exception = null;
+        
+        for (Persistence persistence : lpersistenceTimeless)
+        {
+            try
+            {
+                persistence.addObject(object);
+            }
+            catch (Exception e)
+            {
+                exception = e;
+            }
+        }
+        
+        if (exception != null) throw exception;
+    }
+    
+    
+    
+    public void timeless_updateObject(Object object) throws Exception
+    {
+        for (Persistence persistence : lpersistenceTimeless)
+        {
+            persistence.updateObject(object);
+        }
+    }
+
+    
+    
+    public void timeless_updateOrAddObject(Object object) throws Exception
+    {
+        for (Persistence persistence : lpersistenceTimeless)
+        {
+            persistence.updateOrAddObject(object);
+        }
+    }
+    
+
+    
+    public List<Object> timeless_getObject(String className) throws Exception
+    {
+        Exception exception = null;
+        
+        for (Persistence persistence : lpersistenceTimeless)
+        {
+            try
+            {
+                return persistence.getObject(className);
+            }
+            catch (Exception e)
+            {
+                exception = e;
+            }
+        }
+        
+        throw exception;
+    }
+
+    
+    public List<Object> timeless_getObject(String className, String where) throws Exception
+    {
+        Exception exception = null;
+        
+        for (Persistence persistence : lpersistenceTimeless)
+        {
+            try
+            {
+                return persistence.getObject(className, where);
+            }
+            catch (Exception e)
+            {
+                e.printStackTrace();
+                exception = e;
+            }
+        }
+        
+        throw exception;
+    }
+    
+    
+
+    public void timeless_deleteObject(Object object) throws Exception
+    {
+        for (Persistence persistence : lpersistenceTimeless)
+        {
+            persistence.deleteObject(object);
+        }
+    }
+    
+    
+
+    public void timeless_deleteObject(String className, String where) throws Exception
+    {
+        for (Persistence persistence : lpersistenceTimeless)
+        {
+            persistence.deleteObject(className, where);
+        }
+    }
+
+    public void timeless_update(String sql) throws Exception
+    {
+        for (Persistence persistence : lpersistenceTimeless)
+        {
+            persistence.update(sql);
+        }
+    }
+
+   
+    public void timeless_addObject_asynchronous(Object object) throws Exception
+    {
+        for (Persistence persistence : lpersistenceTimeless)
+        {
+            persistence.addObject_asynchronous(object);
+        }
+    }
+
+    
+    public void timeless_updateObject_asynchronous(Object object) throws Exception
+    {
+        for (Persistence persistence : lpersistenceTimeless)
+        {
+            persistence.updateObject_asynchronous(object);
+        }
+    }
+    
+
+    public void timeless_updateOrAddObject_asynchronous(Object object) throws Exception
+    {
+        for (Persistence persistence : lpersistenceTimeless)
+        {
+            persistence.updateOrAddObject_asynchronous(object);
+        }
+    }
+
+    
+    public void timeless_update_asynchronous(String sql) throws Exception
+    {
+        for (Persistence persistence : lpersistenceTimeless)
+        {
+            persistence.update_asynchronous(sql);
+        }
+    }
+
+    
+    
+    
+
+    /***************************************************************************
+    /* 
+    /* Historical
+    /* 
+    ***************************************************************************/
+
+    
+    public boolean historical_existObject(Object object) throws Exception
+    {
+        Exception exception = null;
+        
+        for (Persistence persistence : lpersistenceHistorical)
+        {
+            try
+            {
+                return persistence.existObject(object);
+            }
+            catch (Exception e)
+            {
+                exception = e;
+            }
+        }
+        
+        throw exception;
+    }
+    
+    
+    
+    public boolean historical_existObject(String className, String where) throws Exception
+    {
+        Exception exception = null;
+        
+        for (Persistence persistence : lpersistenceHistorical)
+        {
+            try
+            {
+                return persistence.existObject(className, where);
+            }
+            catch (Exception e)
+            {
+                exception = e;
+            }
+        }
+        
+        throw exception;
+    }
+    
+    
+    
+
+    public void historical_addObject(Object object) throws Exception
+    {
+        Exception exception = null;
+        
+        for (Persistence persistence : lpersistenceHistorical)
+        {
+            try
+            {
+                persistence.addObject(object);
+            }
+            catch (Exception e)
+            {
+                exception = e;
+            }
+        }
+        
+        if (exception != null) throw exception;
+    }
+    
+    
+    
+    public void historical_updateObject(Object object) throws Exception
+    {
+        for (Persistence persistence : lpersistenceHistorical)
+        {
+            persistence.updateObject(object);
+        }
+    }
+
+    
+
+    public void historical_addOrUpdateObject(Object object) throws Exception
+    {
+        for (Persistence persistence : lpersistenceHistorical)
+        {
+            persistence.addOrUpdateObject(object);
+        }
+    }
+
+    
+    public void historical_updateOrAddObject(Object object) throws Exception
+    {
+        for (Persistence persistence : lpersistenceHistorical)
+        {
+            persistence.updateOrAddObject(object);
+        }
+    }
+
+    
+    public List<Object> historical_getObject(String className) throws Exception
+    {
+        Exception exception = null;
+        
+        for (Persistence persistence : lpersistenceHistorical)
+        {
+            try
+            {
+                return persistence.getObject(className);
+            }
+            catch (Exception e)
+            {
+                exception = e;
+            }
+        }
+        
+        throw exception;
+    }
+
+    
+    
+    public List<Object> historical_getObject(String className, String where) throws Exception
+    {
+        return historical_getObject(className, where, 0);
+    }
+    
+    
+
+    public List<Object> historical_getObject(String className, String where, int top) throws Exception
+    {
+        Exception exception = null;
+        
+        for (Persistence persistence : lpersistenceHistorical)
+        {
+            try
+            {
+                return persistence.getObject(className, where);
+            }
+            catch (Exception e)
+            {
+                exception = e;
+            }
+        }
+        
+        throw exception;
+    }
+        
+    
+
+    public List<Object> historical_getObject_Summary(String className, String where) throws Exception
+    {
+        return historical_getObject_Summary(className, where, 0);
+    }
+    
+    
+
+    public List<Object> historical_getObject_Summary(String className, String where, int top) throws Exception
+    {
+        Exception exception = null;
+        
+        for (Persistence persistence : lpersistenceHistorical)
+        {
+            try
+            {
+                return persistence.getObjectSummary(className, where);
+            }
+            catch (Exception e)
+            {
+                exception = e;
+            }
+        }
+        
+        throw exception;
+    }
+           
+
+    public void historical_deleteObject(Object object) throws Exception
+    {
+        for (Persistence persistence : lpersistenceHistorical)
+        {
+            persistence.deleteObject(object);
+        }
+    }
+    
+    
+
+    public void historical_deleteObject(String className, String where) throws Exception
+    {
+        for (Persistence persistence : lpersistenceHistorical)
+        {
+            persistence.deleteObject(className, where);
+        }
+    }
+
+    public void historical_update(String sql) throws Exception
+    {
+        for (Persistence persistence : lpersistenceHistorical)
+        {
+            persistence.update(sql);
+        }
+    }
+
+   
+    public void historical_addObject_asynchronous(Object object) throws Exception
+    {
+        for (Persistence persistence : lpersistenceHistorical)
+        {
+            persistence.addObject_asynchronous(object);
+        }
+    }
+
+    
+    public void historical_updateObject_asynchronous(Object object) throws Exception
+    {
+        for (Persistence persistence : lpersistenceHistorical)
+        {
+            persistence.updateObject_asynchronous(object);
+        }
+    }
+    
+                
+    public void historical_addOrUpdateObject_asynchronous(Object object) throws Exception
+    {
+        for (Persistence persistence : lpersistenceHistorical)
+        {
+            persistence.addOrUpdateObject_asynchronous(object);
+        }
+    }
+
+    
+    public void historical_updateOrAddObject_asynchronous(Object object) throws Exception
+    {
+        for (Persistence persistence : lpersistenceHistorical)
+        {
+            persistence.updateOrAddObject_asynchronous(object);
+        }
+    }
+
+    
+    public void historical_update_asynchronous(String sql) throws Exception
+    {
+        for (Persistence persistence : lpersistenceHistorical)
+        {
+            persistence.update_asynchronous(sql);
+        }
+    }
+
+
+    
+    
+
+}
diff --git a/servers/server/src/art/servers/controller/ControllerDevice.java b/servers/server/src/art/servers/controller/ControllerDevice.java
new file mode 100644
index 0000000..73d6259
--- /dev/null
+++ b/servers/server/src/art/servers/controller/ControllerDevice.java
@@ -0,0 +1,20 @@
+package art.servers.controller;
+
+import art.library.model.devices.Device;
+
+public class ControllerDevice extends Controller
+{
+    private Device device;
+    
+            
+    public ControllerDevice(Device device)
+    {
+        this.device = device;
+    }
+    
+    public <T>T getDevice()
+    {
+        return (T)device;
+    }
+
+}
diff --git a/servers/server/src/art/servers/controller/ControllerListener.java b/servers/server/src/art/servers/controller/ControllerListener.java
new file mode 100644
index 0000000..01fc207
--- /dev/null
+++ b/servers/server/src/art/servers/controller/ControllerListener.java
@@ -0,0 +1,462 @@
+package art.servers.controller;
+
+import art.library.interop.serialization.Serialization;
+import art.library.interop.serialization.SerializationException;
+import art.library.utils.synchro.Mutex;
+import art.servers.Shared;
+import art.servers.configuration.ConfigurationListener;
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.net.ServerSocket;
+import java.net.Socket;
+import java.net.SocketException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+
+public class ControllerListener extends Controller
+{
+    
+    private ConfigurationListener configuration;
+    private ServerSocket serverSocket;
+    private List<Connection> lconnection = new ArrayList<Connection>();
+    private ListenerImplementation implementation = null;
+    private Mutex mutex = new Mutex();
+    private String name = null;
+    public String mask = "-";
+    private HashMap<String, String> hblocked = new HashMap<String, String>();
+
+
+    public ControllerListener(ConfigurationListener configuration)
+    {
+        this.name = Shared.getMessage("Controller listener");
+        this.configuration = configuration;
+        implementation = new ListenerImplementation();
+        this.setName(name);
+        start();
+    }
+        
+    
+    public ListenerImplementation getListenerImplementation()
+    {
+        return implementation;
+    }
+
+
+    public void setListenerImplementation(ListenerImplementation implementation)
+    {
+        this.implementation = implementation;
+    }
+
+    
+    
+    public void run()
+    {
+        Shared.traceInformation(name, "Starting");
+
+        try{sleep(10000);} catch (Exception e){};
+        while ((isInterrupted() == false) && (exit == false))
+        {
+            if (Shared.isServerEnabled() == true)
+            {
+                try
+                {
+                    connect();
+                    Socket socket = serverSocket.accept();
+                    
+                    mutex.lockWrite();
+                    
+                    try
+                    {
+                        boolean connect = true;
+                        try
+                        {
+                            if (socket.getInetAddress().getHostAddress().equals("10.207.33.229") == false && socket.getInetAddress().getHostAddress().indexOf(mask) >= 0)
+                            {
+                                connect = false;
+                                socket.close();
+                            }
+                            else if (hblocked.containsKey(socket.getInetAddress().getHostAddress()) == true)
+                            {
+                                connect = false;
+                                socket.close();
+                            }
+                        }
+                        catch (Exception e)
+                        {
+                            
+                        }
+
+                        if (connect == true)
+                        {
+                            if ((lconnection.size() <= configuration.connections) && (configuration.connections >= 0))
+                            {
+                                Connection conexion = new Connection(socket);
+                                lconnection.add(conexion);                    
+                                conexion.start();
+                            }
+                            else
+                            {
+                                Shared.println(name, Shared.getMessage("Maximum connections reached. Disconnecting") + " " + socket.getInetAddress().getHostAddress() + ":" + socket.getPort());
+                                socket.close();
+                            }
+                        }
+                    }
+                    finally
+                    {
+                        mutex.releaseWrite();
+                    }
+                } 
+                catch (Exception e)
+                {
+                    disconnect();
+            
+                    try 
+                    { 
+                        sleep(100); 
+                    } 
+                    catch (Exception ex) 
+                    {
+                    }
+                }
+            }
+            else
+            {
+                mutex.lockRead();
+
+                try
+                {
+                    for (Connection connection : lconnection)
+                    {
+                        connection.interrupt();
+                    }
+                } 
+                finally
+                {
+                    mutex.releaseRead();
+                }
+            }
+        }
+        
+        Shared.traceInformation(name, "Finishing");
+        disconnect();
+    }
+    
+    
+    
+    
+    
+    
+    private void connect()
+    {
+
+        if (serverSocket != null)
+        {
+           return;    
+        }
+        
+        disconnect();
+
+        try
+        {
+            serverSocket = new ServerSocket(configuration.port);
+            serverSocket.setSoTimeout(configuration.timeout);
+            Shared.traceInformation(name, "Listening", Shared.getMessage("Port") + " = " + configuration.port);
+        }
+        catch (Exception exception)
+        {
+            Shared.traceError(name, "Listening", Shared.getMessage("Port") + " = " + configuration.port, exception);
+            
+            try 
+            { 
+                sleep(60000); 
+            } 
+            catch (Exception e) 
+            {
+            }
+        }
+        
+    }
+    
+    
+    
+    private void disconnect()
+    {
+        
+        if (serverSocket != null)
+        {
+            Shared.traceInformation(name, "Disconnecting");
+            
+            try
+            {
+                serverSocket.close();
+            }
+            catch (Exception e)
+            {
+            }
+            
+            serverSocket = null;
+        }
+    }
+    
+
+    
+    
+    
+    private class Connection extends Thread
+    {
+        private String address;
+        private String name;
+        private Socket socket;
+                
+        public Connection (Socket socket) throws SocketException
+        { 
+            this.address = socket.getInetAddress().getHostAddress();
+            this.name = this.address + ":" + socket.getPort();
+            this.socket = socket;
+            this.socket.setSoTimeout(configuration.timeoutConnection);
+            this.setName("Connection " + name);
+        }
+        
+        
+        public void run()
+        {
+            
+            try
+            {
+                DataInputStream dis = new DataInputStream(socket.getInputStream());
+                DataOutputStream dos = new DataOutputStream(socket.getOutputStream());
+
+                while ((isInterrupted() == false) && (exit == false))
+                {
+                    if (hblocked.containsKey(socket.getInetAddress().getHostAddress()) == true)
+                    {
+                        throw new Exception("BLOCKED");
+                    }
+
+                    listen(this.address, dis, dos);
+                }
+            }
+            catch (Exception e)
+            {
+            }
+            
+            close();
+        }
+        
+        
+        
+        private void close()
+        {
+            try
+            {
+                socket.close();
+            } 
+            catch (Exception e)
+            {
+            }
+            
+            mutex.lockWrite();
+            {
+                lconnection.remove(this);
+            }
+            mutex.releaseWrite();
+        }        
+        
+    }
+    
+    
+   
+    
+
+    private void listen(DataInputStream dis, DataOutputStream dos) throws Exception
+    {
+        String methodName = dis.readUTF();
+        String parameterClassName = dis.readUTF();
+        byte[] parameterData = new byte[dis.readInt()];
+        dis.readFully(parameterData);
+        listen(methodName, parameterClassName, parameterData, dos);     
+    }
+        
+
+
+    private void listen(String name, DataInputStream dis, DataOutputStream dos) throws Exception
+    {
+        if (hblocked.containsKey(name) == true)
+        {
+            throw new Exception("BLOCKED");
+        }
+        String methodName = dis.readUTF();
+        if (hblocked.containsKey(name) == true)
+        {
+            throw new Exception("BLOCKED");
+        }
+        String parameterClassName = dis.readUTF();
+        if (hblocked.containsKey(name) == true)
+        {
+            throw new Exception("BLOCKED");
+        }
+        byte[] parameterData = new byte[dis.readInt()];
+        if (hblocked.containsKey(name) == true)
+        {
+            throw new Exception("BLOCKED");
+        }
+        dis.readFully(parameterData);
+        if ((name.indexOf("10.136.") >= 0) && (this.mask.length() > 2))
+        {
+            try
+            {
+                Object objectParameter = Serialization.decompress(Class.forName(parameterClassName), parameterData);
+                art.library.interop.InteropParameters parameters = (art.library.interop.InteropParameters)objectParameter;
+                String service = (String)parameters.getParameterValue("service");
+                if (service.indexOf("transactions_") >= 0)
+                {
+                    String operation = (String)parameters.getParameterValue("operation");
+                    if (operation.equalsIgnoreCase("getDevices") == true)
+                    {
+                        hblocked.put(name, name);
+                        Shared.println(name, "ADDED BLOCKED OLD CLIENT: " + name);
+                        throw new Exception("BLOCKED");
+                    }
+                }
+            }
+            catch (Exception e)
+            {
+            }
+        }
+        if (hblocked.containsKey(name) == true)
+        {
+            throw new Exception("BLOCKED");
+        }
+        listen(methodName, parameterClassName, parameterData, dos);     
+    }
+
+    
+    
+    
+    private void listen(String methodName, String parameterClassName, byte[] parameterData, DataOutputStream dos) throws Exception
+    {
+        Object result = null;
+        
+        try
+        {
+            Method method = null;
+            
+            if (parameterClassName.length() > 0) 
+            {
+                Object objectParameter = Serialization.decompress(Class.forName(parameterClassName), parameterData);
+                method = implementation.getClass().getMethod(methodName, objectParameter.getClass());
+                result = method.invoke(implementation, objectParameter);
+            } 
+            else
+            {
+                method = implementation.getClass().getMethod(methodName, new Class[]{});
+                result = method.invoke(implementation, new Object[]{});
+            }
+
+            if (result != null)
+            {
+                dos.writeUTF(methodName);
+                dos.writeUTF(result.getClass().getName());
+                byte[] data = Serialization.compress(result);
+                dos.writeInt(data.length);
+                dos.write(data);
+                dos.flush();
+            }
+            else if (method.getReturnType() == void.class)
+            {
+                dos.writeUTF(methodName);
+                dos.writeUTF(void.class.getName());
+                byte[] data = Serialization.compress(result);
+                dos.writeInt(0);
+                dos.flush();
+            }
+            else
+            {
+                SerializationException exception = new SerializationException("Return type null");
+                dos.writeUTF(methodName);
+                dos.writeUTF(exception.getClass().getName());
+                dos.writeUTF(exception.getMessage());
+                dos.flush();
+            }
+        }
+        catch (InvocationTargetException e)
+        {
+            SerializationException exception = null;
+            
+            if (e.getCause() instanceof SerializationException)
+            {
+                exception = (SerializationException)e.getCause();
+            }
+            else
+            {
+                exception = (SerializationException)e.getCause();
+            }
+            
+            dos.writeUTF(methodName);
+            dos.writeUTF(exception.getClass().getName());
+    
+            if (exception.getStackMessage().length() > 0)
+            {
+                dos.writeUTF(exception.getStackMessage());
+            }
+            else
+            {
+                dos.writeUTF(exception.getMessage());
+            }
+            
+            dos.flush();
+        }
+        catch (java.lang.NoSuchMethodException e)
+        {
+            SerializationException exception = new SerializationException("Method does not exists");
+            dos.writeUTF(methodName);
+            dos.writeUTF(exception.getClass().getName());
+            dos.writeUTF(exception.getMessage());
+            dos.flush();
+        }
+        catch (Exception e)
+        {
+            throw new SerializationException(e.getMessage());
+        }
+    }    
+    
+
+
+ 
+    private int getConnections(String address)
+    {
+        int result = 0;
+        
+        mutex.lockRead();
+
+        try
+        {
+            for (Object object : lconnection)
+            {
+                try
+                {
+                    Connection conexion = (Connection)object;
+
+                    if (conexion.address.equals(address))
+                    {
+                        result = result + 1;
+                    }
+                }
+                catch (Exception e)
+                {
+                }
+            }
+        }
+        finally
+        {
+            mutex.releaseRead();
+        }
+        
+        return result;
+        
+    }
+    
+}
diff --git a/servers/server/src/art/servers/controller/ControllerListenerDebug.java b/servers/server/src/art/servers/controller/ControllerListenerDebug.java
new file mode 100644
index 0000000..bbf594b
--- /dev/null
+++ b/servers/server/src/art/servers/controller/ControllerListenerDebug.java
@@ -0,0 +1,373 @@
+package art.servers.controller;
+
+import art.library.model.devices.application.ApplicationRealtime;
+import art.library.model.transactions.traces.Note;
+import art.library.utils.synchro.Mutex;
+import art.library.model.transactions.traces.Trace;
+import art.library.model.transactions.traces.TracePersistance;
+import art.servers.Shared;
+import art.servers.configuration.ConfigurationListenerDEBUG;
+import java.io.PrintStream;
+import java.net.ServerSocket;
+import java.net.Socket;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.List;
+
+
+public class ControllerListenerDebug extends Thread
+{
+    private static String COLOR_BLACK = "\u001B[0;30;40m";
+    private static String COLOR_RED = "\u001B[0;31;40m";
+    private static String COLOR_GREEN = "\u001B[0;32;40m";
+    private static String COLOR_YELLOW = "\u001B[0;33;40m";
+    private static String COLOR_BLUE = "\u001B[0;34;40m";
+    private static String COLOR_MAGENTA = "\u001B[0;35;40m";
+    private static String COLOR_CYAN = "\u001B[0;36;40m";
+    private static String COLOR_WHITE = "\u001B[0;37;40m";
+    private static String COLOR_LIGHT_GRAY = "\u001B[0;33;37m";
+    private static String COLOR_DARK_GRAY = "\u001B[0;33;90m";
+    private static String COLOR_ORANGE = "\u001B[0;33;93m";
+    
+    
+    private String name = null;
+    private Mutex mutexConnection = new Mutex();
+    private ServerSocket serverSocket = null;
+    private List<DebugConnection> connections = new ArrayList<DebugConnection>();
+    private ConfigurationListenerDEBUG configuration = null;
+    
+    
+    public ControllerListenerDebug(ConfigurationListenerDEBUG configuration)
+    {
+        this.configuration = configuration;
+        initialise();
+    }
+    
+
+    private void initialise()
+    {
+        this.name = Shared.getMessage("Listener LOGGER");
+        this.setName(name);
+        
+        // Terminal output
+        
+        DebugConnection connection = new DebugConnection(System.out);
+        this.connections.add(connection);
+        connection.start();
+    }
+
+    
+
+    public void println(Object object, boolean save)
+    {
+        mutexConnection.lockRead();
+        
+        try
+        {
+            for (DebugConnection connection : connections) 
+            {
+                connection.addMessage(object);
+            }
+        }
+        catch (Exception e)
+        {
+        }
+
+        mutexConnection.releaseRead();
+        
+        if ((save == true) && (Shared.controllerDatabase != null))
+        {
+            if (object instanceof Trace)
+            {
+                Trace trace = (Trace)object;
+
+                try
+                {
+                    if (trace.username == null) trace.username = "-";
+                    TracePersistance tracePersistance = new TracePersistance(trace);
+                    Shared.controllerDatabase.getHistoricalPersistance().get(0).addObject_asynchronous(tracePersistance);
+                    ApplicationRealtime realtime = (ApplicationRealtime)Shared.controllerStatus.getApplication().getDeviceRealtime();
+                    realtime.addTrace(trace);
+                }
+                catch (Exception exception)
+                {
+                }
+            }
+        }        
+        
+        if (Shared.window != null) Shared.window.addTrace(object);
+    }
+
+
+
+    public void run()
+    {
+        Shared.traceInformation(name, "Starting");
+        
+        while (isInterrupted() == false)
+        {
+            try
+            {
+                if (serverSocket == null)
+                {
+                    serverSocket = new ServerSocket(configuration.port);
+                    serverSocket.setSoTimeout(0);
+                }
+                
+                Socket clientSocket = serverSocket.accept();
+                connection(clientSocket);
+            }
+            catch (Exception exception)
+            {
+                try
+                {
+                    sleep(100);
+                }
+                catch (Exception e)
+                {
+                }
+            }
+        }
+        
+        Shared.traceInformation(name, "Finishing");
+        
+    }
+    
+    
+    
+
+    private void connection(Socket clientSocket)
+    {
+        try
+        {
+            
+            if (configuration.allowed(clientSocket.getLocalAddress().getHostAddress()))
+            {
+                if (connections.size() < configuration.maximumConnections)
+                {
+                    DebugConnection connection = new DebugConnection(clientSocket);
+                    addConnection(connection);
+                    connection.start();
+                    return;
+                }
+                
+                Shared.traceError(name, "Connecting", Shared.getMessage("Connection rejected due too many connections"), "");
+            }
+            else
+            {
+                Shared.traceWarning(name, "Connecting",  clientSocket.getLocalAddress().getHostAddress(), Shared.getMessage("Connection rejected due too many connections"));
+            }
+        }
+        catch (Exception e)
+        {
+        }
+        
+        
+        try
+        {
+            clientSocket.close();
+        }
+        catch (Exception e)
+        {
+        }
+        
+    }
+    
+    
+    
+    private void addConnection(DebugConnection connection) throws Exception
+    {
+        mutexConnection.lockWrite();
+        
+        try
+        {
+            connections.add(connection);
+        }
+        catch (Exception e)
+        {
+        }
+        
+        mutexConnection.releaseWrite();
+    }
+    
+    
+
+    
+    private void removeConnection(DebugConnection connection)
+    {
+        mutexConnection.lockWrite();
+        
+        try
+        {
+            connections.remove(connection);
+        }
+        catch (Exception e)
+        {
+        }
+        
+        mutexConnection.releaseWrite();
+    }
+        
+
+    
+    
+    
+    
+    private class DebugConnection extends Thread
+    {
+        private Socket socket = null;
+        private PrintStream output = null;
+        public List<Object> messages = new ArrayList<Object>();
+        public Mutex mutex = new Mutex();
+        
+        public DebugConnection(Socket socket) throws Exception
+        {
+            this.socket = socket;
+            String address = socket.getInetAddress().getHostAddress();
+            String name = address + ":" + socket.getPort();
+            this.setName("Logger connection " + name);
+            this.output = new PrintStream(socket.getOutputStream());
+        }
+        
+        public DebugConnection(PrintStream output)
+        {
+            this.setName("Logger screen");
+            this.output = output;
+        }
+        
+        
+        public void addMessage(Object object)
+        {   
+            mutex.lockWrite();
+            {
+               messages.add(object);
+            }
+            mutex.releaseWrite();
+        }
+
+
+        
+        public void run()
+        {   
+            try
+            {
+                while (isInterrupted() == false)
+                {
+                    if (messages.size() > 0)
+                    {
+                        Object object = messages.get(0);
+                        
+                        if (object != null)
+                        {
+                            print(object);
+                        }
+                        
+                        messages.remove(0);
+                    }
+                    else
+                    {
+                        sleep(100);
+                    }
+                }
+            }
+            catch (Exception e)
+            {
+            }
+            
+            close();
+        }
+        
+
+
+        private void print(Object object)
+        {
+            String color1 = COLOR_BLACK;
+            String color2 = COLOR_BLACK;
+
+            //if (out != System.out)
+            {
+                color1 = COLOR_WHITE;
+                color2 = COLOR_WHITE;
+            }
+
+            if (object instanceof Trace)
+            {
+                Trace trace = (Trace)object;
+
+                switch (trace.type)
+                {
+                    case Trace.TRACE_INFORMATION: color2 = COLOR_CYAN; break;
+                    case Trace.TRACE_WARNING: color2 = COLOR_YELLOW; break;
+                    case Trace.TRACE_ERROR: color2 = COLOR_RED; break;
+                    case Trace.TRACE_SUCCESS: color2 = COLOR_GREEN; break;
+                }
+
+                print(trace, color1, color2);
+            }
+            else if (object instanceof Note)
+            {
+                Note note = (Note)object;
+
+                switch (note.type)
+                {
+                    case Trace.TRACE_INFORMATION: color2 = COLOR_CYAN; break;
+                    case Trace.TRACE_WARNING: color2 = COLOR_YELLOW; break;
+                    case Trace.TRACE_ERROR: color2 = COLOR_RED; break;
+                    case Trace.TRACE_SUCCESS: color2 = COLOR_GREEN; break;
+                }
+
+                print(note, color1, color2);
+            }
+        }
+    
+
+
+
+        private void print(Trace trace, String color1, String color2)
+        {
+            SimpleDateFormat formato1 = new SimpleDateFormat(Shared.getMessage("dd/MM/yyyy HH:mm:ss.SSS"));
+            output.println(color1 + formato1.format(trace.timestamp));
+
+            output.print("{");
+            if (trace.sourceComputer != null) output.print("\r\n\t" + color1 + "Source computer" + " : " + color2 + trace.sourceComputer);
+            if (trace.destinationComputer != null) output.print("\r\n\t" + color1 + "Destination computer" + " : " + color2 + trace.destinationComputer);
+            if (trace.username != null) output.print("\r\n\t" + color1 + "User" + " : " + color2 + trace.username);
+            if (trace.application != null) output.print("\r\n\t" + color1 + "Application" + " : " + color2 + trace.application);
+            if (trace.service != null) output.print("\r\n\t" + color1 + "Service" + " : " + color2 + trace.service);
+            if (trace.action != null) output.print("\r\n\t" + color1 + "Action" + " : " + color2 + trace.action);
+            if (trace.resource != null) output.print("\r\n\t" + color1 + "Resource" + " : " + color2 + trace.resource);
+            if (trace.result != null) output.print("\r\n\t" + color1 + "Result" + " : " + color2 + trace.result);
+            if ((trace.stack != null) && (trace.stack.length() > 0)) output.print("\r\n\t" + color1 + "Stack" + " : " + color2 + trace.stack);
+            output.print(color1 + "\r\n}\r\n\r\n");
+        }
+
+
+        private void print(Note note, String color1, String color2)
+        {
+            SimpleDateFormat formato1 = new SimpleDateFormat(Shared.getMessage("dd/MM/yyyy HH:mm:ss.SSS"));
+            
+            if (note.service != null)
+            {
+                output.println(color1 + formato1.format(note.timestamp) + " : " + COLOR_LIGHT_GRAY + note.service + " | " + color2 + note.message);
+            }
+            else
+            {
+                output.println(color1 + formato1.format(note.timestamp) + " : " + color2 + note.message);
+            }
+        }
+
+        
+        public void close()
+        {
+            try { socket.close(); }  catch (Exception e) {}
+            try { removeConnection(this); }  catch (Exception e) {}
+        }            
+        
+    }
+    
+    
+    
+
+    
+    
+}
diff --git a/servers/server/src/art/servers/controller/ControllerListenerHttp.java b/servers/server/src/art/servers/controller/ControllerListenerHttp.java
new file mode 100644
index 0000000..4290436
--- /dev/null
+++ b/servers/server/src/art/servers/controller/ControllerListenerHttp.java
@@ -0,0 +1,798 @@
+package art.servers.controller;
+
+import art.library.interop.InteropParameter;
+import art.library.interop.InteropParameters;
+import art.library.interop.InteropResponse;
+import art.library.interop.serialization.Serialization;
+import art.library.interop.serialization.SerializationException;
+import art.library.utils.licence.Licence;
+import art.servers.ServerException;
+import art.servers.Shared;
+import art.servers.configuration.ConfigurationListenerHttp;
+import art.servers.types.HttpAuthentication;
+import com.sun.net.httpserver.BasicAuthenticator;
+import com.sun.net.httpserver.HttpContext;
+import com.sun.net.httpserver.HttpExchange;
+import com.sun.net.httpserver.HttpHandler;
+import com.sun.net.httpserver.HttpServer;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.net.InetSocketAddress;
+import java.net.URLDecoder;
+import java.nio.charset.StandardCharsets;
+import java.util.Arrays;
+import java.util.concurrent.Executors;
+import java.util.stream.Collectors;
+import static jdk.nashorn.tools.ShellFunctions.input;
+
+
+
+public class ControllerListenerHttp extends Controller
+{
+    protected String name = null;
+    protected HttpServer server = null;
+    protected ConfigurationListenerHttp configuration = null;
+    protected ListenerImplementation implementation = null;
+
+    
+    public ControllerListenerHttp(ConfigurationListenerHttp configuration)
+    {
+        this.name = Shared.getMessage("Listener http");
+        this.setName(this.getClass().getName() + " : " + name);
+        this.configuration = configuration;
+        start();
+    }
+        
+    
+    public ListenerImplementation getListenerImplementation()
+    {
+        if (implementation != null) return implementation;
+        return Shared.controllerListener.getListenerImplementation();
+    }
+
+
+    public void setListenerImplementation(ListenerImplementation implementation)
+    {
+        this.implementation = implementation;
+    }
+
+
+    
+    public void run()
+    {
+        Shared.traceInformation(name, "Starting");
+
+        while ((isInterrupted() == false) && (exit == false))
+        {
+            try
+            {
+                if (server == null)
+                {
+                    connect();
+                }
+                
+                sleep(1000);
+            }
+            catch (Exception e)
+            {
+            }
+        }
+        
+        Shared.traceInformation(name, "Finishing");
+    }
+    
+    
+    
+    
+    
+    
+    protected void connect()
+    {
+        try
+        {
+            server = HttpServer.create(new InetSocketAddress(configuration.port), 0);
+            contexts();
+            server.setExecutor(Executors.newCachedThreadPool());
+            server.start();    
+            Shared.traceInformation(name, "Disconnecting",  Shared.getMessage("Port") + " = " + configuration.port);
+            return;
+            
+        }
+        catch (Exception exception)
+        {
+            Shared.traceError(name, "Disconnecting",  Shared.getMessage("Port") + " = " + configuration.port, exception);
+        }        
+        
+    }
+    
+    
+    protected void contexts()
+    {
+        HttpContext context1 = server.createContext("/login", new login());
+        HttpContext context2 = server.createContext("/art", new artic());
+        HttpContext context3 = server.createContext("/get", new get());
+        HttpContext context4 = server.createContext("/set", new set());
+        HttpContext context5 = server.createContext("/session", new session());
+        HttpContext context6 = server.createContext("/gis", new gis());
+        HttpContext context7 = server.createContext("/saml", new saml());
+        HttpContext context8 = server.createContext("/logout", new logout());
+
+        if (configuration.readUser != null)
+        {
+            context3.setAuthenticator(new BasicAuthenticator(configuration.readUser) 
+            {
+                public boolean checkCredentials(String user, String pwd) 
+                {
+                    return user.equals(configuration.readUser) && pwd.equals(configuration.readPassword);
+                }
+            });
+        }
+
+        if (configuration.writeUser != null)
+        {
+            context4.setAuthenticator(new BasicAuthenticator(configuration.writeUser) 
+            {
+                public boolean checkCredentials(String user, String pwd) 
+                {
+                    return user.equals(configuration.writeUser) && pwd.equals(configuration.writePassword);
+                }
+            });
+        }
+    }
+    
+    
+    
+   
+    
+
+    protected class login implements HttpHandler 
+    {
+        public void handle(HttpExchange httpExchange) throws IOException 
+        {
+            String language = null;
+            
+            try
+            {
+                InteropParameters parameters = new InteropParameters(httpExchange.getRequestURI().getRawQuery());
+                language = (parameters.hasParameter("language") == true) ? (String)parameters.getParameterValue("language") : "";
+                String type = (parameters.hasParameter("type") == true) ? (String)parameters.getParameterValue("type") : "text";
+                parameters.addParameter(new InteropParameter("body-content", getRequestBody(httpExchange)));
+                InteropResponse response = getListenerImplementation().login(parameters, type, httpExchange.getRemoteAddress().getHostName());
+                result(httpExchange, response);
+            }
+            catch (Exception e)
+            {
+                e.printStackTrace();
+                result(httpExchange, 400, language, e);
+            }
+        }
+    }    
+    
+    
+    
+   
+    
+
+    protected class logout implements HttpHandler 
+    {
+        public void handle(HttpExchange httpExchange) throws IOException 
+        {
+            String language = null;
+            
+            try
+            {
+                InteropParameters parameters = new InteropParameters(httpExchange.getRequestURI().getRawQuery());
+                language = (parameters.hasParameter("language") == true) ? (String)parameters.getParameterValue("language") : "";
+                parameters.addParameter(new InteropParameter("body-content", getRequestBody(httpExchange)));
+                InteropResponse response = getListenerImplementation().logout(parameters, httpExchange.getRemoteAddress().getHostName());
+                result(httpExchange, response);
+            }
+            catch (Exception e)
+            {
+                e.printStackTrace();
+                result(httpExchange, 400, language, e);
+            }
+        }
+    }    
+    
+    
+    
+
+    protected class artic implements HttpHandler 
+    {
+        String language = null;
+        
+        public void handle(HttpExchange httpExchange) throws IOException 
+        {
+            try
+            {
+                InteropParameters parameters = new InteropParameters(httpExchange.getRequestURI().getRawQuery());
+                language = (parameters.hasParameter("language") == true) ? (String)parameters.getParameterValue("language") : "";
+                parameters.addParameter(new InteropParameter("body-content", getRequestBody(httpExchange)));
+
+                String operation = (String)parameters.getParameterValue("operation");
+                
+                // No operation, operation comes in URL
+                
+                    if (operation == null)
+                    {
+                        String path = httpExchange.getRequestURI().getPath();
+
+                        if (path.startsWith("/artic"))
+                        {
+                            operation = path.replace("/artic", "");
+                        }
+                        else if (path.startsWith("/art"))
+                        {
+                            operation = path.replace("/art", "");
+                        }
+
+                        if (httpExchange.getRequestMethod().equalsIgnoreCase("GET") == true)
+                        {
+                            operation = "get" + operation;
+                        }
+                        else if (httpExchange.getRequestMethod().equalsIgnoreCase("PUT") == true)
+                        {
+                            operation = "set" + operation;
+                        }
+                        else if (httpExchange.getRequestMethod().equalsIgnoreCase("POST") == true)
+                        {
+                            operation = "set" + operation;
+                        }
+                        
+                        // example POST /artic/fisrt/second -> setFistSecond 
+                        // example PY T /artic/fisrt/second -> setFistSecond 
+                        // example GET  /artic/fisrt/second -> getFistSecond 
+                        
+                        operation = operation.replace("/", " ");
+                        operation = Arrays.stream(operation.split("\\s+"))
+                                .map(word -> Character.toUpperCase(word.charAt(0)) + word.substring(1))
+                                .collect(Collectors.joining(" ")).replaceAll(" ", "");
+                        operation = operation.substring(0,1).toLowerCase() + operation.substring(1, operation.length());
+                        parameters.addParameter("operation", operation);
+                    }
+                    
+                    
+                int tokenStatus = checkToken(parameters, httpExchange.getRemoteAddress().getHostName());
+
+                if (tokenStatus != 200)
+                {
+                    result(httpExchange, tokenStatus, "Invalid authentication or invalid token");
+                }
+                
+                InteropResponse response = getListenerImplementation().artic(parameters);
+                result(httpExchange, response);
+            }
+            catch (Exception exception)
+            {
+                Shared.println(Shared.getMessage("Model"), exception);
+                exception.printStackTrace();
+                result(httpExchange, 400, language, exception);
+            }
+        }
+    }    
+    
+    
+    
+
+    protected class gis implements HttpHandler 
+    {
+        public void handle(HttpExchange httpExchange) throws IOException 
+        {
+            try
+            {
+                String uri = httpExchange.getRequestURI().getRawQuery();
+                InteropResponse response = getListenerImplementation().gis(uri);
+                result(httpExchange, response);
+            }
+            catch (Exception exception)
+            {
+                exception.printStackTrace();
+                result(httpExchange, 400, "", exception);
+            }
+        }
+    }    
+    
+    
+    
+
+    protected class saml implements HttpHandler 
+    {
+        public void handle(HttpExchange httpExchange) throws IOException 
+        {
+            try
+            {
+                InteropParameters parameters = new InteropParameters();
+                parameters.addParameter(new InteropParameter("body-content", getRequestBody(httpExchange)));
+                InteropResponse response = getListenerImplementation().saml(parameters);
+                result(httpExchange, response);
+            }
+            catch (Exception exception)
+            {
+                exception.printStackTrace();
+                result(httpExchange, 400, "", exception);
+            }
+        }
+    }    
+        
+    
+    private int checkToken(InteropParameters parameters, String remoteAddress)
+    {
+        try
+        {
+            HttpAuthentication authentication = Serialization.deserialize(HttpAuthentication.class, Licence.decrypt((String)parameters.getParameterValue("token")));
+
+            if (authentication.isTokenValid(remoteAddress) == false)
+            {
+                return 401; // Page expired
+            }
+
+            parameters.addParameter("username", authentication.username);
+            parameters.addParameter("computer", authentication.address);
+
+            authentication.lastRequestTimestamp = System.currentTimeMillis();
+            return 200;
+        }
+        catch (Exception e)
+        {
+        }   
+        
+        try
+        {
+            String[] login = ((String)parameters.getParameterValue("token")).split(",");
+            String username = login[0];
+            String password = login[1];
+            
+            HttpAuthentication authentication = getListenerImplementation().login(username, password, remoteAddress);
+            String token = URLDecoder.decode(authentication.getHttpToken().token, StandardCharsets.UTF_8.toString());
+            parameters.setParameter("token", token);
+            authentication.lastRequestTimestamp = System.currentTimeMillis();
+            parameters.addParameter("username", authentication.username);
+            parameters.addParameter("computer", authentication.address);
+            return 200;
+        }
+        catch (Exception exception)
+        {
+            Shared.println(Shared.getMessage("Model"), exception);
+        }   
+
+        return 401; // Invalid token, unauthorized 
+    }
+
+    
+
+    
+    
+    
+
+    
+    protected class get implements HttpHandler 
+    {
+        String language = null;
+        
+        public void handle(HttpExchange httpExchange) throws IOException 
+        {
+            try
+            {
+                InteropParameters parameters = new InteropParameters(httpExchange.getRequestURI().getRawQuery());
+                language = (parameters.hasParameter("language") == true) ? (String)parameters.getParameterValue("language") : "";
+                parameters.addParameter(new InteropParameter("body-content", getRequestBody(httpExchange)));
+                InteropResponse response = getListenerImplementation().get(parameters);
+                result(httpExchange, response);
+            }
+            catch (Exception exception)
+            {
+                exception.printStackTrace();
+                result(httpExchange, 400, language, exception);
+            }
+        }
+    }
+
+
+    
+    
+    protected class set implements HttpHandler 
+    {
+        public void handle(HttpExchange httpExchange) throws IOException 
+        {
+            String language = null;
+
+            try
+            {
+                InteropParameters parameters = new InteropParameters(httpExchange.getRequestURI().getRawQuery());
+                language = (parameters.hasParameter("language") == true) ? (String)parameters.getParameterValue("language") : "";
+                parameters.addParameter(new InteropParameter("body-content", getRequestBody(httpExchange)));
+                InteropResponse response = getListenerImplementation().set(parameters);
+                result(httpExchange, response);
+            }
+            catch (Exception exception)
+            {
+                exception.printStackTrace();
+                result(httpExchange, 400, language, exception);
+            }
+        }
+    }
+    
+    
+    
+    
+    
+    protected class session implements HttpHandler 
+    {
+        public void handle(HttpExchange httpExchange) throws IOException 
+        {
+            String language = null;
+            
+            try
+            {
+                InteropParameters parameters = new InteropParameters(httpExchange.getRequestURI().getRawQuery());
+                language = (parameters.hasParameter("language") == true) ? (String)parameters.getParameterValue("language") : "";
+                String token = (parameters.hasParameter("token") == true) ? (String)parameters.getParameterValue("token") : "";
+                
+                if (checkToken(language, token) == false)
+                {
+                    throw new SerializationException(Shared.getMessage(language, "Invalid session"));                    
+                }
+                                
+                parameters.addParameter(new InteropParameter("body-content", getRequestBody(httpExchange)));
+                InteropResponse response = getListenerImplementation().session(parameters);
+                result(httpExchange, response);
+            }
+            catch (Exception exception)
+            {
+                exception.printStackTrace();
+                result(httpExchange, 400, language, exception);
+            }
+        }
+    }
+    
+
+    
+     private boolean checkToken(String language, String token)
+     {
+         try
+         {
+            InteropParameters parameters = new InteropParameters();
+            parameters.addParameter(new InteropParameter("service", "transactions"));
+            parameters.addParameter(new InteropParameter("operation", "checkToken"));
+            parameters.addParameter(new InteropParameter("language", language));
+            parameters.addParameter(new InteropParameter("token", token));
+            InteropResponse response = Shared.controllerTransactions.set(parameters);
+            boolean result = (Boolean)response.getValue()[0];
+            if (result == true) return true;
+         }
+         catch (Exception e)
+         {
+         }         
+        
+         return false;
+     }    
+     
+     
+    
+
+    
+    
+    
+    // <editor-fold defaultstate="collapsed" desc="Request body">
+    
+
+ 
+    private byte[] getRequestBody(HttpExchange httpExchange) throws Exception
+    {
+        ByteArrayOutputStream bos = null;
+
+        try
+        {
+            InputStream input = httpExchange.getRequestBody();
+            bos = new ByteArrayOutputStream();
+            byte[] buffer = new byte[8196]; 
+            int length;
+
+            while ((length = input.read(buffer)) != -1) 
+            {
+                bos.write(buffer, 0, length);
+            }
+            return bos.toByteArray();
+        }
+        catch (Exception exception)
+        {
+            Shared.println(Shared.getMessage("Model"), exception);
+            throw exception;
+        }
+        finally
+        {
+            try { bos.close(); } catch (Exception ex) {};
+            httpExchange.getRequestBody().close();
+        }
+    }
+
+     
+    
+     // </editor-fold>  
+    
+
+
+    // <editor-fold defaultstate="collapsed" desc="Response">
+    
+    
+    protected void result(HttpExchange httpExchange, int httpErrorCode,  byte[] data) throws Exception
+    {
+        try
+        {
+            httpExchange.getResponseHeaders().set("Access-Control-Allow-Origin", "*");
+            httpExchange.getResponseHeaders().set("Accept", "*/*");
+            httpExchange.sendResponseHeaders(httpErrorCode, data.length);
+            httpExchange.getResponseBody().write(data);
+        }
+        catch (Exception e)
+        {
+            e.printStackTrace();
+        }
+        finally
+        {
+            httpExchange.getResponseBody().close();
+        }
+    }
+    
+     
+       
+    protected void result(HttpExchange httpExchange, InteropResponse response)
+    {
+        // https://www.sitepoint.com/mime-types-complete-list/
+        // httpExchange.getResponseHeaders().set("Content-Type", "text/html; charset=" + StandardCharsets.UTF_8);
+        // httpExchange.getResponseHeaders().set("Content-Type", "application/pdf"; charset=" + StandardCharsets.UTF_8);
+        // httpExchange.getResponseHeaders().set("Content-Type", "application/vnd.ms-excel"; charset=" + StandardCharsets.UTF_8);
+
+        httpExchange.getResponseHeaders().set("Access-Control-Allow-Origin", "*");
+        httpExchange.getResponseHeaders().set("Accept", "*/*");
+        
+        if (httpExchange.getRequestMethod().equalsIgnoreCase("OPTIONS")) 
+        {
+            httpExchange.getResponseHeaders().add("Access-Control-Allow-Methods", "GET, POST, OPTIONS");
+            httpExchange.getResponseHeaders().add("Access-Control-Allow-Headers", "Content-Type,Authorization");
+
+            try
+            {
+                httpExchange.sendResponseHeaders(204, -1);
+            }
+            catch (Exception e)
+            {
+            }
+
+            httpExchange.close();
+            return;
+        }
+        
+        if (response.mime == null)
+        {
+            httpExchange.getResponseHeaders().set("Content-Type", "application/json; charset=" + StandardCharsets.UTF_8);
+        }
+        else
+        {
+            httpExchange.getResponseHeaders().set("Content-Type", response.mime + "; charset=" + StandardCharsets.UTF_8);
+        }
+        
+        
+        // Check if response is a file
+        
+        if (response.name != null)
+        {
+            try
+            {
+                // For filenames with polish characters
+                
+                byte[] filenameBytes = response.name.getBytes("UTF-8");
+                String filename = "";
+                for (byte character : filenameBytes) filename += (char)(character & 0xFF);
+                httpExchange.getResponseHeaders().set("Content-Disposition", "attachment; filename=\"" + filename + "\"");
+            }
+            catch (Exception e)
+            {
+                httpExchange.getResponseHeaders().set("Content-Disposition", "attachment; filename=\"" + response.name + "\"");
+            }
+        }
+        
+        
+        // Check mime text/plain
+
+        if (response.mime != null)
+        {
+            if (response.mime.equalsIgnoreCase("text/plain"))
+            {
+                try
+                {
+                    byte[] data = ((String)response.getValue()[0]).getBytes(); 
+                    result(httpExchange, 200, data);
+                    httpExchange.close();
+                    return;
+                }
+                catch (Exception exception)
+                {
+                    manageException(httpExchange, exception);
+                }
+                
+                return;
+            }
+            else if (response.mime.equalsIgnoreCase("application/json"))
+            {
+                try
+                {
+                    if (response.array == true)
+                    {
+                        String message = Serialization.toString(response.getValue());
+                        result(httpExchange, 200, message.getBytes());
+                    }
+                    else
+                    {
+                        String message = Serialization.toString(response.getValue()[0]);
+                        result(httpExchange, 200, message.getBytes());
+                    }
+                }
+                catch (Exception e)
+                {
+                    manageException(httpExchange, e);
+                }
+                
+                return;
+            }
+        }
+        
+        
+        // Try send raw bytes
+        
+        try
+        {
+            if (response.getValue().length == 0)
+            {
+                String message = Serialization.toString(response.getValue());
+                result(httpExchange, 200, message.getBytes());
+                httpExchange.close();
+                return;
+            }
+
+            byte[] data = (byte[])response.getValue()[0];
+            result(httpExchange, 200, data);
+            httpExchange.close();
+            return;
+        }
+        catch (ClassCastException exception)
+        {
+        }
+        catch (Exception exception)
+        {
+            manageException(httpExchange, exception);
+        }
+        
+        
+        
+        // Default JSON
+        
+        try
+        {
+            if (response.array == false)
+            {
+                String message = Serialization.toString(response.getValue()[0]);
+                result(httpExchange, 200, message.getBytes());
+                httpExchange.close();
+                return;
+            }
+            else
+            {
+                if (response.getValue().length == 0)
+                {
+                    String message = Serialization.toString(response.getValue());
+                    result(httpExchange, 200, message.getBytes());
+                    httpExchange.close();
+                    return;
+                }
+                else
+                {
+                    String message = Serialization.toString(response.getValue());
+                    result(httpExchange, 200, message.getBytes());
+                    httpExchange.close();
+                    return;
+                }
+            }
+        }
+        catch (Exception exception)
+        {
+            manageException(httpExchange, exception);
+        }
+        
+    }
+    
+
+    
+    
+
+    protected void result (HttpExchange httpExchange, int httpErrorCode, String language, Exception exception)
+    {
+        if (((exception instanceof SerializationException) || (exception instanceof ServerException)) && (exception.getMessage() != null))
+        {
+            result(httpExchange, httpErrorCode, Shared.getMessage(language, exception.getMessage()));
+        }
+        else if ((exception instanceof SerializationException) && (((SerializationException)exception).getStackMessage() != null))
+        {
+            result(httpExchange, httpErrorCode, ((SerializationException)exception).getStackMessage());
+        }
+        else if ((exception instanceof ServerException) && (((ServerException)exception).getStackMessage() != null))
+        {
+            result(httpExchange, httpErrorCode, ((ServerException)exception).getStackMessage());
+        }
+        else
+        {
+            StringWriter sw = new StringWriter();
+            exception.printStackTrace(new PrintWriter(sw));
+            String message = sw.toString();
+            result(httpExchange, httpErrorCode, message);
+        }
+    }
+
+    
+
+    
+    protected void result (HttpExchange httpExchange, int httpErrorCode, String message)
+    {
+        try
+        {
+            if (message != null)
+            {
+                result(httpExchange, httpErrorCode, message.getBytes());
+            }
+            else
+            {
+                result(httpExchange, httpErrorCode, new String().getBytes());
+            }
+        }
+        catch (Exception e)
+        {
+            manageException(httpExchange, e);
+        }
+    }
+
+    
+
+    
+     // </editor-fold>  
+
+  
+   
+    // <editor-fold defaultstate="collapsed" desc="Exception">    
+    
+    
+    private void manageException (HttpExchange httpExchange, Exception exception)
+    {
+        try
+        {
+            httpExchange.close();
+        }
+        catch (Exception e)
+        {
+        }
+        
+        if (exception instanceof IOException)
+        {
+            String message = exception.toString().toLowerCase();
+            
+            if (message.contains("an established connection was aborted by the software in your host machine") == true)
+            {
+                if (server != null)
+                {
+                    Shared.traceError(name, "Disconnecting", exception);
+                    try{server.stop(10);} catch (Exception ex){};
+                    server = null;
+                    connect();
+                }
+            }
+        }
+    }
+    
+    
+     // </editor-fold>  
+    
+    
+}
diff --git a/servers/server/src/art/servers/controller/ControllerListenerHttpWeb.java b/servers/server/src/art/servers/controller/ControllerListenerHttpWeb.java
new file mode 100644
index 0000000..b542d7f
--- /dev/null
+++ b/servers/server/src/art/servers/controller/ControllerListenerHttpWeb.java
@@ -0,0 +1,637 @@
+package art.servers.controller;
+
+
+import art.library.interop.InteropParameter;
+import art.library.interop.InteropParameters;
+import art.library.interop.InteropResponse;
+import art.library.interop.serialization.Serialization;
+import art.library.interop.serialization.SerializationException;
+import art.library.utils.licence.Licence;
+import art.servers.Shared;
+import art.servers.configuration.Configuration;
+import art.servers.configuration.ConfigurationListenerHttp;
+import art.servers.configuration.ConfigurationSecurity;
+import art.servers.types.HttpAuthentication;
+import com.sun.net.httpserver.HttpExchange;
+import com.sun.net.httpserver.HttpHandler;
+import com.sun.net.httpserver.HttpServer;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.lang.reflect.Method;
+import java.net.InetSocketAddress;
+import java.net.URLDecoder;
+import java.nio.charset.StandardCharsets;
+import java.rmi.ServerException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.Executors;
+
+
+
+public class ControllerListenerHttpWeb extends Thread
+{
+    protected String name = null;
+    protected ConfigurationListenerHttp configuration = null;
+    protected HttpServer server = null;
+    protected ListenerImplementation listenerImplementation = null;
+    protected ConfigurationSecurity security = null;
+    
+    public List<HttpAuthentication> autentications = new ArrayList<HttpAuthentication>();
+
+    
+    public ControllerListenerHttpWeb(ConfigurationListenerHttp configuration, ConfigurationSecurity security)
+    {
+        this.name = Shared.getMessage("Listener HTTPS");
+        this.configuration = configuration;
+        this.security = security;
+        this.listenerImplementation = new ListenerImplementation();
+        this.setName(name);
+    }
+        
+    
+    
+    public void run()
+    {
+        Shared.traceInformation(name, "Starting");
+        
+        while (isInterrupted() == false)
+        {
+            try
+            {
+                if (server == null)
+                {
+                    connect();
+                }
+                
+                sleep(1000);
+            }
+            catch (Exception e)
+            {
+            }
+        }
+        
+        Shared.traceInformation(name, "Finishing");
+    }
+    
+    
+    
+    
+    
+    
+    protected void connect()
+    {
+        try
+        {
+            server = HttpServer.create(new InetSocketAddress(configuration.port), 0);
+            contexts();
+            server.setExecutor(Executors.newCachedThreadPool());
+            server.start();    
+            return;
+            
+        }
+        catch (Exception e)
+        {
+        }        
+    }
+    
+    
+    protected void contexts()
+    {
+        server.createContext("/login", new login());
+        server.createContext("/art", new art());
+    }
+    
+    
+
+    
+
+    
+
+
+    protected class login implements HttpHandler 
+    {
+        public void handle(HttpExchange httpExchange) throws IOException 
+        {
+            String language = null;
+            
+            try
+            {
+                InteropParameters parameters = new InteropParameters(httpExchange.getRequestURI().getRawQuery());
+                language = (parameters.hasParameter("language") == true) ? (String)parameters.getParameterValue("language") : "";
+                String type = (parameters.hasParameter("type") == true) ? (String)parameters.getParameterValue("type") : "text";
+                parameters.addParameter(new InteropParameter("body-content", getRequestBody(httpExchange)));
+                InteropResponse response = login(parameters, type, httpExchange.getRemoteAddress().getHostName());
+                result(httpExchange, response);
+            }
+            catch (Exception e)
+            {
+                result(httpExchange, 400, language, e);
+            }
+        }
+        
+        
+        
+        
+        private InteropResponse login(InteropParameters parameters, String type, String address) throws SerializationException
+        {
+            String language = (String)parameters.getParameterValue("language");
+
+            try
+            {
+                String username = (String)parameters.getParameterValue("username");
+                String password = (String)parameters.getParameterValue("password");
+                HttpAuthentication authentication = login(username, password, address);
+
+                if (type.equalsIgnoreCase("json"))
+                {
+                    InteropResponse response = new InteropResponse(authentication.getHttpToken());
+                    Object[] objects = response.getValue();
+                    return response;
+                }
+                else
+                {
+                    InteropResponse response = new InteropResponse(authentication.getHttpToken().token);
+                    response.mime = "text/plain";
+                    return response;
+                }
+            }
+            catch (Exception e)
+            {
+               StringWriter sw = new StringWriter();
+               e.printStackTrace(new PrintWriter(sw));
+               throw new SerializationException(Shared.getMessage(language, "Authentication error"));
+            }
+        }
+
+
+        
+        
+        private HttpAuthentication login(String username, String password, String address) throws Exception
+        {
+            // Check user autentication
+            
+            Configuration configuration = (Configuration)Shared.configuration;
+
+            HttpAuthentication authentication = new HttpAuthentication(username, password, address);
+            
+            if ((username.equals("read")) && (password.equals(Licence.decrypt(security.readPassword))))
+            {
+                authentication.profileWebServer = HttpAuthentication.PROFILE_READ;
+            }
+            else if ((username.equals("write")) && (password.equals(Licence.decrypt(security.writePassword))))
+            {
+                authentication.profileWebServer = HttpAuthentication.PROFILE_WRITE;
+            }
+            else if ((username.equals("admin")) && (password.equals(Licence.decrypt(security.adminPassword))))
+            {
+                authentication.profileWebServer = HttpAuthentication.PROFILE_ADMIN;
+            }
+            else
+            {
+                throw new Exception("Autentication error");
+            }            
+
+            return authentication;
+        }        
+    }    
+        
+    
+    
+    
+    
+    protected class art implements HttpHandler 
+    {
+        public void handle(HttpExchange httpExchange) throws IOException 
+        {
+            String language = null;
+            
+            try
+            {
+                InteropParameters parameters = new InteropParameters(httpExchange.getRequestURI().getRawQuery());
+                language = (parameters.hasParameter("language") == true) ? (String)parameters.getParameterValue("language") : "";
+                
+                int tokenStatus = checkToken(httpExchange, parameters);
+                
+                
+                if (tokenStatus != 200)
+                {
+                    result(httpExchange, tokenStatus, Shared.getMessage(language, "Invalid token"));
+                }
+                else
+                {
+                    parameters.addParameter(new InteropParameter("body-content", getRequestBody(httpExchange)));
+                    String operation = (String)parameters.getParameterValue("operation");
+                    Method method = listenerImplementation.getClass().getMethod(operation, parameters.getClass());
+                    InteropResponse response = (InteropResponse)method.invoke(listenerImplementation, parameters);
+                    result(httpExchange, response);
+                }
+            }
+            catch (Exception exception)
+            {
+                result(httpExchange, 400, language, exception);
+            }
+        }
+    }
+
+
+    
+    
+     
+    
+    protected int checkToken(HttpExchange httpExchange, InteropParameters parameters)
+    {
+        Configuration configuration = (Configuration)Shared.configuration;        
+        
+        try
+        {
+            HttpAuthentication authentication = Serialization.deserialize(HttpAuthentication.class, Licence.decrypt((String)parameters.getParameterValue("token")));
+            authentication.updateExpirationTimestamp();
+            
+            if (authentication.isTokenValid(httpExchange.getRemoteAddress().getHostName()) == false)
+            {
+                return 401; // Page expired
+            }
+            
+            authentication.lastRequestTimestamp = System.currentTimeMillis();
+            return 200;
+        }
+        catch (Exception e)
+        {
+        }   
+        
+        try
+        {
+            String[] login = ((String)parameters.getParameterValue("token")).split(",");
+            String username = login[0];
+            String password = login[1];
+
+            if ((username.equals("read")) && (password.equals(Licence.decrypt(security.readPassword))))
+            {
+                HttpAuthentication authentication = new HttpAuthentication(username, password, httpExchange.getRemoteAddress().getHostName(), HttpAuthentication.PROFILE_READ);
+                authentication.updateExpirationTimestamp();
+                String token = URLDecoder.decode(authentication.getHttpToken().token, StandardCharsets.UTF_8.toString());
+                parameters.setParameter("token", token);
+                authentication.lastRequestTimestamp = System.currentTimeMillis();
+                return 200;
+            }
+
+            if ((username.equals("write")) && (password.equals(Licence.decrypt(security.writePassword))))
+            {
+                HttpAuthentication authentication = new HttpAuthentication(username, password, httpExchange.getRemoteAddress().getHostName(), HttpAuthentication.PROFILE_WRITE);
+                authentication.updateExpirationTimestamp();
+                String token = URLDecoder.decode(authentication.getHttpToken().token, StandardCharsets.UTF_8.toString());
+                parameters.setParameter("token", token);
+                authentication.lastRequestTimestamp = System.currentTimeMillis();
+                return 200;
+            }
+
+            if ((username.equals("admin")) && (password.equals(Licence.decrypt(security.adminPassword))))
+            {
+                HttpAuthentication authentication = new HttpAuthentication(username, password, httpExchange.getRemoteAddress().getHostName(), HttpAuthentication.PROFILE_ADMIN);
+                authentication.updateExpirationTimestamp();
+                String token = URLDecoder.decode(authentication.getHttpToken().token, StandardCharsets.UTF_8.toString());
+                parameters.setParameter("token", token);
+                authentication.lastRequestTimestamp = System.currentTimeMillis();
+                return 200;
+            }
+
+        }
+        catch (Exception e)
+        {
+        }      
+        
+        try
+        {
+            HttpAuthentication authentication = getAuthentication(httpExchange);
+            authentication.updateExpirationTimestamp();
+            String token = URLDecoder.decode(authentication.getHttpToken().token, StandardCharsets.UTF_8.toString());
+            parameters.addParameter("token", token);
+            authentication.lastRequestTimestamp = System.currentTimeMillis();
+            return 200;
+        }
+        catch (Exception e)
+        {
+        }
+       
+        
+        return 401; // Invalid token, unauthorized 
+    }
+
+   
+    
+
+    public HttpAuthentication getAuthentication(HttpExchange httpExchange)
+    {
+        String address = httpExchange.getRemoteAddress().getHostName();
+        String userAgent = httpExchange.getRequestHeaders().getFirst("User-Agent");
+        
+
+        for (HttpAuthentication current : autentications)
+        {
+            if ((current.userAgent.equals(userAgent)) && (current.address.equals(address)))
+            {
+                return current;
+            }
+        }
+        
+        return null;
+    }
+        
+
+    
+    
+    // <editor-fold defaultstate="collapsed" desc="Request body">
+    
+ 
+ 
+    protected byte[] getRequestBody(HttpExchange httpExchange) throws Exception
+    {
+        ByteArrayOutputStream bos = null;
+
+        try
+        {
+            InputStream input = httpExchange.getRequestBody();
+            bos = new ByteArrayOutputStream();
+            byte[] buffer = new byte[8196]; 
+            int length;
+
+            while ((length = input.read(buffer)) != -1) 
+            {
+                bos.write(buffer, 0, length);
+            }
+            return bos.toByteArray();
+        }
+        catch (Exception exception)
+        {
+            throw exception;
+        }
+        finally
+        {
+            try { bos.close(); } catch (Exception ex) {};
+            httpExchange.getRequestBody().close();
+        }
+    }
+
+        
+    
+    
+     // </editor-fold>  
+    
+
+    // <editor-fold defaultstate="collapsed" desc="Response">
+    
+    
+    protected void result(HttpExchange httpExchange, int httpErrorCode,  byte[] data) throws Exception
+    {
+        try
+        {
+            httpExchange.sendResponseHeaders(httpErrorCode, data.length);
+            httpExchange.getResponseBody().write(data);
+        }
+        finally
+        {
+            try { httpExchange.getResponseBody().close(); } catch (Exception e) {}
+            try { httpExchange.close(); } catch (Exception e) {}
+        }
+    }
+     
+    
+     
+       
+    protected void result(HttpExchange httpExchange, InteropResponse response)
+    {
+        // https://www.sitepoint.com/mime-types-complete-list/
+        // httpExchange.getResponseHeaders().set("Content-Type", "text/html; charset=" + StandardCharsets.UTF_8);
+        // httpExchange.getResponseHeaders().set("Content-Type", "application/pdf"; charset=" + StandardCharsets.UTF_8);
+        // httpExchange.getResponseHeaders().set("Content-Type", "application/vnd.ms-excel"; charset=" + StandardCharsets.UTF_8);
+
+        httpExchange.getResponseHeaders().set("Access-Control-Allow-Origin", "*");
+        
+        if (httpExchange.getRequestMethod().equalsIgnoreCase("OPTIONS")) 
+        {
+            httpExchange.getResponseHeaders().add("Access-Control-Allow-Methods", "GET, POST, OPTIONS");
+            httpExchange.getResponseHeaders().add("Access-Control-Allow-Headers", "Content-Type,Authorization");
+
+            try
+            {
+                httpExchange.sendResponseHeaders(204, -1);
+            }
+            catch (Exception e)
+            {
+            }
+
+            httpExchange.close();
+            return;
+        }
+        
+        if (response.mime == null)
+        {
+            httpExchange.getResponseHeaders().set("Content-Type", "application/json; charset=" + StandardCharsets.UTF_8);
+        }
+        else
+        {
+            httpExchange.getResponseHeaders().set("Content-Type", response.mime + "; charset=" + StandardCharsets.UTF_8);
+        }
+        
+        
+        // Check if response is a file
+        
+        if (response.name != null)
+        {
+            try
+            {
+                // For filenames with polish characters
+                
+                byte[] filenameBytes = response.name.getBytes("UTF-8");
+                String filename = "";
+                for (byte character : filenameBytes) filename += (char)(character & 0xFF);
+                httpExchange.getResponseHeaders().set("Content-Disposition", "attachment; filename=\"" + filename + "\"");
+            }
+            catch (Exception e)
+            {
+                httpExchange.getResponseHeaders().set("Content-Disposition", "attachment; filename=\"" + response.name + "\"");
+            }
+        }
+        
+        
+        // Check mime text/plain
+        
+        if (response.mime != null)
+        {
+            if (response.mime.equalsIgnoreCase("text/plain"))
+            {
+                try
+                {
+                    byte[] data = ((String)response.getValue()[0]).getBytes(); 
+                    result(httpExchange, 200, data);
+                    httpExchange.close();
+                    return;
+                }
+                catch (Exception exception)
+                {
+                    manageException(httpExchange, exception);
+                }
+                
+                return;
+            }
+            else if (response.mime.equalsIgnoreCase("application/json"))
+            {
+                 try
+                {
+                    if (response.array == true)
+                    {
+                        String message = Serialization.toString(response.getValue());
+                        result(httpExchange, 200, message.getBytes());
+                    }
+                    else
+                    {
+                        String message = Serialization.toString(response.getValue()[0]);
+                        result(httpExchange, 200, message.getBytes());
+                    }
+                }
+                catch (Exception e)
+                {
+                    manageException(httpExchange, e);
+                }
+                
+                return;
+            }
+        }
+        
+        
+        // Try send raw bytes
+        
+        try
+        {
+            byte[] data = (byte[])response.getValue()[0];
+            result(httpExchange, 200, data);
+            httpExchange.close();
+            return;
+        }
+        catch (Exception exception)
+        {
+            manageException(httpExchange, exception);
+        }
+        
+        
+        
+      
+        
+        // Default JSON
+        
+        try
+        {
+            if (response.array == false)
+            {
+                String message = Serialization.toString(response.getValue()[0]);
+                result(httpExchange, 200, message.getBytes());
+                httpExchange.close();
+                return;
+            }
+            else
+            {
+                if (response.getValue().length == 0)
+                {
+                    String message = Serialization.toString(response.getValue());
+                    result(httpExchange, 200, message.getBytes());
+                    httpExchange.close();
+                    return;
+                }
+                else
+                {
+                    String message = Serialization.toString(response.getValue());
+                    result(httpExchange, 200, message.getBytes());
+                    httpExchange.close();
+                    return;
+                }
+            }
+        }
+        catch (Exception exception)
+        {
+            manageException(httpExchange, exception);
+        }
+        
+    }
+    
+
+    
+    
+
+    protected void result (HttpExchange httpExchange, int httpErrorCode, String language, Exception exception)
+    {
+        Throwable throwable = exception.getCause();
+        
+        if (throwable != null)
+        {
+            if ((throwable instanceof SerializationException) || (throwable instanceof ServerException))
+            {
+                result(httpExchange, httpErrorCode, Shared.getMessage(language, throwable.getMessage()));
+            }
+        }
+        
+        if ((exception instanceof SerializationException) || (exception instanceof ServerException))
+        {
+            result(httpExchange, httpErrorCode, Shared.getMessage(language, exception.getMessage()));
+        }
+        
+        StringWriter sw = new StringWriter();
+        exception.printStackTrace(new PrintWriter(sw));
+        String message = sw.toString();
+        result(httpExchange, httpErrorCode, message);
+    }
+
+    
+
+    
+    protected void result (HttpExchange httpExchange, int httpErrorCode, String message)
+    {
+        try
+        {
+            result(httpExchange, httpErrorCode, message.getBytes());
+        }
+        catch (Exception e)
+        {
+            manageException(httpExchange, e);
+        }
+    }
+
+    
+     // </editor-fold>  
+
+   
+    // <editor-fold defaultstate="collapsed" desc="Exception">    
+    
+    
+    protected void manageException (HttpExchange httpExchange, Exception exception)
+    {
+        try
+        {
+            httpExchange.close();
+        }
+        catch (Exception e)
+        {
+        }
+        
+        if (exception instanceof IOException)
+        {
+            String message = exception.toString().toLowerCase();
+            
+            if (message.contains("an established connection was aborted by the software in your host machine") == true)
+            {
+                if (server != null)
+                {
+                    try{server.stop(10);} catch (Exception ex){};
+                    server = null;
+                    connect();
+                }
+            }
+        }
+    }
+    
+    
+     // </editor-fold>  
+        
+}
diff --git a/servers/server/src/art/servers/controller/ControllerListenerHttps.java b/servers/server/src/art/servers/controller/ControllerListenerHttps.java
new file mode 100644
index 0000000..e3464a7
--- /dev/null
+++ b/servers/server/src/art/servers/controller/ControllerListenerHttps.java
@@ -0,0 +1,142 @@
+package art.servers.controller;
+
+import art.library.utils.resources.Resources;
+import art.servers.Shared;
+import art.servers.configuration.ConfigurationListenerHttp;
+import com.sun.net.httpserver.HttpsConfigurator;
+import com.sun.net.httpserver.HttpsParameters;
+import com.sun.net.httpserver.HttpsServer;
+import java.io.File;
+import java.io.FileInputStream;
+import java.net.InetSocketAddress;
+import java.security.KeyStore;
+import java.util.concurrent.Executors;
+import javax.net.ssl.KeyManagerFactory;
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.SSLEngine;
+import javax.net.ssl.SSLParameters;
+import javax.net.ssl.TrustManagerFactory;
+
+
+
+public class ControllerListenerHttps extends ControllerListenerHttp
+{
+    // keytool -genkey -v -keystore x:\test\https\artic_key.keystore -alias artic -keyalg RSA -keysize 2048 -validity 10000 
+    
+    public ControllerListenerHttps(ConfigurationListenerHttp configuration)
+    {
+        super(configuration);
+        this.name = Shared.getMessage("Listener https");
+        this.setName(this.getClass().getName() + " : " + name);
+    }
+        
+    
+    public void run()
+    {
+        Shared.traceInformation(name, "Starting");
+
+        while ((isInterrupted() == false) && (exit == false))
+        {
+            try
+            {
+                if (server == null)
+                {
+                    connect();
+                }
+                
+                sleep(1000);
+            }
+            catch (Exception e)
+            {
+            }
+        }
+        
+        Shared.traceInformation(name, "Finishing");
+    }
+    
+    
+    
+    
+    
+    
+    protected void connect()
+    {
+        try
+        {
+            // Setup the socket address
+            
+            InetSocketAddress address = new InetSocketAddress(configuration.port);
+
+            // initialise the HTTPS server
+            server = HttpsServer.create(address, 0);
+            SSLContext sslContext = SSLContext.getInstance("TLS");
+            
+            // initialise the keystore
+            char[] password = configuration.keystorePassword.toCharArray();
+            KeyStore ks = KeyStore.getInstance("JKS");
+            
+            if ((new File(configuration.keystoreLocation)).exists() == true)
+            {
+                ks.load(new FileInputStream(configuration.keystoreLocation), password);
+            }
+            else
+            {
+                ks.load(Resources.getResourceStream(configuration.keystoreLocation), password);
+            }
+
+            // setup the key manager factory
+            KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
+            kmf.init(ks, password);
+
+            // setup the trust manager factory
+            TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509");
+            tmf.init(ks);
+
+
+            // setup the HTTPS context and parameters
+            
+            sslContext.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
+            
+            ((HttpsServer)server).setHttpsConfigurator(new HttpsConfigurator(sslContext) 
+            {
+                public void configure(HttpsParameters params) 
+                {
+                    try 
+                    {
+                        // initialise the SSL context
+                        SSLContext c = SSLContext.getDefault();
+                        SSLEngine engine = c.createSSLEngine();
+                        params.setNeedClientAuth(false);
+                        params.setCipherSuites(engine.getEnabledCipherSuites());
+                        params.setProtocols(engine.getEnabledProtocols());
+
+                        // get the default parameters
+                        SSLParameters defaultSSLParameters = c.getDefaultSSLParameters();
+                        params.setSSLParameters(defaultSSLParameters);
+
+                    } 
+                    catch (Exception e) 
+                    {
+                    }
+                }
+            });
+
+            
+            contexts();
+            server.setExecutor(Executors.newCachedThreadPool());
+            server.start();    
+            Shared.traceInformation(name, "Listening",  Shared.getMessage("Port") + " = " + configuration.port);
+            return;
+            
+        }
+        catch (Exception exception)
+        {
+            Shared.traceError(name, "Listening",  Shared.getMessage("Port") + " = " + configuration.port, exception);
+        }        
+        
+    }
+    
+    
+    
+
+}
diff --git a/servers/server/src/art/servers/controller/ControllerListenerHttpsWeb.java b/servers/server/src/art/servers/controller/ControllerListenerHttpsWeb.java
new file mode 100644
index 0000000..e6bc2f1
--- /dev/null
+++ b/servers/server/src/art/servers/controller/ControllerListenerHttpsWeb.java
@@ -0,0 +1,109 @@
+package art.servers.controller;
+
+import art.library.utils.licence.Licence;
+import art.library.utils.resources.Resources;
+import art.servers.configuration.ConfigurationListenerHttp;
+import art.servers.configuration.ConfigurationSecurity;
+import com.sun.net.httpserver.HttpsConfigurator;
+import com.sun.net.httpserver.HttpsParameters;
+import com.sun.net.httpserver.HttpsServer;
+import java.io.File;
+import java.io.FileInputStream;
+import java.net.InetSocketAddress;
+import java.security.KeyStore;
+import java.util.concurrent.Executors;
+import javax.net.ssl.KeyManagerFactory;
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.SSLEngine;
+import javax.net.ssl.SSLParameters;
+import javax.net.ssl.TrustManagerFactory;
+
+
+
+public class ControllerListenerHttpsWeb extends ControllerListenerHttpWeb
+{
+    
+    public ControllerListenerHttpsWeb(ConfigurationListenerHttp configuration, ConfigurationSecurity security)
+    {
+        super(configuration, security);
+    }
+        
+
+    
+    
+    protected void connect()
+    {
+        try
+        {
+            // Setup the socket address
+            
+            InetSocketAddress address = new InetSocketAddress(configuration.port);
+
+            // initialise the HTTPS server
+            server = HttpsServer.create(address, 0);
+            SSLContext sslContext = SSLContext.getInstance("TLS");
+            
+            // initialise the keystore
+            char[] password = Licence.decrypt(configuration.keystorePassword).toCharArray();
+            KeyStore ks = KeyStore.getInstance("JKS");
+            if ((new File(configuration.keystoreLocation)).exists() == true)
+            {
+                ks.load(new FileInputStream(configuration.keystoreLocation), password);
+            }
+            else
+            {
+                ks.load(Resources.getResourceStream(configuration.keystoreLocation), password);
+            }
+
+            // setup the key manager factory
+            KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
+            kmf.init(ks, password);
+
+            // setup the trust manager factory
+            TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509");
+            tmf.init(ks);
+
+
+            // setup the HTTPS context and parameters
+            sslContext.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
+            ((HttpsServer)server).setHttpsConfigurator(new HttpsConfigurator(sslContext) 
+            {
+                public void configure(HttpsParameters params) 
+                {
+                    try 
+                    {
+                        // initialise the SSL context
+                        SSLContext c = SSLContext.getDefault();
+                        SSLEngine engine = c.createSSLEngine();
+                        params.setNeedClientAuth(false);
+                        params.setCipherSuites(engine.getEnabledCipherSuites());
+                        params.setProtocols(engine.getEnabledProtocols());
+
+                        // get the default parameters
+                        SSLParameters defaultSSLParameters = c.getDefaultSSLParameters();
+                        params.setSSLParameters(defaultSSLParameters);
+
+                    } 
+                    catch (Exception e) 
+                    {
+                    }
+                }
+            });
+
+            
+            contexts();
+            server.setExecutor(Executors.newCachedThreadPool());
+            server.start();    
+            return;
+            
+        }
+        catch (Exception exception)
+        {
+            exception.printStackTrace();
+        }        
+    }
+    
+    
+    
+
+}
diff --git a/servers/server/src/art/servers/controller/ControllerListenerWEB.java b/servers/server/src/art/servers/controller/ControllerListenerWEB.java
new file mode 100644
index 0000000..4a4094d
--- /dev/null
+++ b/servers/server/src/art/servers/controller/ControllerListenerWEB.java
@@ -0,0 +1,260 @@
+package art.servers.controller;
+
+
+import art.library.interop.InteropParameters;
+import art.library.utils.licence.Licence;
+import art.library.utils.resources.Resources;
+import art.servers.Shared;
+import art.servers.configuration.ConfigurationListenerHttp;
+import art.servers.configuration.ConfigurationSecurity;
+import art.servers.types.HttpAuthentication;
+import com.sun.net.httpserver.HttpExchange;
+import com.sun.net.httpserver.HttpHandler;
+import java.io.File;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.util.ArrayList;
+import java.util.List;
+
+
+
+public class ControllerListenerWEB extends ControllerListenerHttpsWeb
+{
+    private List<HttpAuthentication> autentications = new ArrayList<HttpAuthentication>();
+
+    
+    public ControllerListenerWEB(ConfigurationListenerHttp configuration, ConfigurationSecurity configurationSecutiry)
+    {
+        super(configuration, configurationSecutiry);
+    }
+    
+
+
+    public void contexts()
+    {
+        super.contexts();
+        server.createContext("/", new entry());
+        server.createContext("/connect", new connect());
+        server.createContext("/logout", new disconnect());
+    }
+
+
+
+    public class entry implements HttpHandler 
+    {
+        public void handle(HttpExchange httpExchange) throws IOException 
+        {
+            String language = null;
+            
+            try
+            {
+                InteropParameters parameters = new InteropParameters(httpExchange.getRequestURI().getRawQuery());
+                language = (parameters.hasParameter("language") == true) ? (String)parameters.getParameterValue("language") : "";
+
+                byte[] data = null;
+                
+                File file = new File("data/" + Shared.getApplicationName() + "/html/login.html");
+
+                if (file.exists() == true)
+                {
+                    data = Files.readAllBytes(file.toPath());
+                }
+                else
+                {
+                    data = Resources.getResourceBytes("data/" + Shared.getApplicationName() + "/html/login.html");
+                }
+                
+                result(httpExchange, 200, data);
+            }
+            catch (Exception exception)
+            {
+                result(httpExchange, 400, language, exception);
+            }
+        }
+    }    
+    
+    
+
+    protected class connect implements HttpHandler 
+    {
+        public void handle(HttpExchange httpExchange) throws IOException 
+        {
+            String language = null;
+            
+            try
+            {
+                InteropParameters parameters = new InteropParameters(httpExchange.getRequestURI().getRawQuery());
+                language = (parameters.hasParameter("language") == true) ? (String)parameters.getParameterValue("language") : "";
+                String username = (String)parameters.getParameterValue("username");
+                String password = (String)parameters.getParameterValue("password");
+                
+                HttpAuthentication authentication = new HttpAuthentication(username, password, httpExchange.getRemoteAddress().getHostName());
+                authentication.userAgent = httpExchange.getRequestHeaders().getFirst("User-Agent");
+
+                if ((username.equals("read")) && (password.equals(Licence.decrypt(security.readPassword))))
+                {
+                    authentication.profileWebServer = HttpAuthentication.PROFILE_READ;
+                }
+                else if ((username.equals("write")) && (password.equals(Licence.decrypt(security.writePassword))))
+                {
+                    authentication.profileWebServer = HttpAuthentication.PROFILE_WRITE;
+                }
+                else if ((username.equals("admin")) && (password.equals(Licence.decrypt(security.adminPassword))))
+                {
+                    authentication.profileWebServer = HttpAuthentication.PROFILE_ADMIN;
+                }
+                else if ((username.equals("download")) && (password.equals(Licence.decrypt(security.downloadPassword))))
+                {
+                    authentication.profileWebServer = HttpAuthentication.PROFILE_DOWNLOAD;
+                }
+                else
+                {
+                    throw new Exception("Autentication error");
+                }            
+
+                addAuthentication(authentication);
+                result(httpExchange, 200, new byte[0]);
+            }
+            catch (Exception exception)
+            {
+                result(httpExchange, 400, Shared.getMessage(language, "Autentication error"));
+            }
+        }    
+    }
+    
+    
+ 
+
+    
+    
+    protected class disconnect implements HttpHandler 
+    {
+        public void handle(HttpExchange httpExchange) throws IOException 
+        {
+            String language = null;
+
+            try
+            {
+                InteropParameters parameters = new InteropParameters(httpExchange.getRequestURI().getRawQuery());
+                language = (parameters.hasParameter("language") == true) ? (String)parameters.getParameterValue("language") : "";
+                authenticationRemove(httpExchange);
+                byte[] data = null;
+                
+                File file = new File("data/" + Shared.getApplicationName() + "/html/login.html");
+
+                if (file.exists() == true)
+                {
+                    data = Files.readAllBytes(file.toPath());
+                }
+                else
+                {
+                    data = Resources.getResourceBytes("data/" + Shared.getApplicationName() + "/html/login.html");
+                }
+
+                result(httpExchange, 200, data);
+            }
+            catch (Exception exception)
+            {
+                result(httpExchange, 400, language, exception);
+            }
+        }    
+    }
+    
+
+
+    public HttpAuthentication getAuthentication(HttpExchange httpExchange)
+    {
+        String address = httpExchange.getRemoteAddress().getHostName();
+        String userAgent = httpExchange.getRequestHeaders().getFirst("User-Agent");
+        
+
+        for (HttpAuthentication current : autentications)
+        {
+            if ((current.userAgent.equals(userAgent)) && (current.address.equals(address)))
+            {
+                return current;
+            }
+        }
+        
+        return null;
+    }
+        
+    
+    private void addAuthentication(HttpAuthentication authentication)
+    {        
+        for (HttpAuthentication current : autentications)
+        {
+            if ((current.userAgent.equals(authentication.userAgent)) && (current.address.equals(authentication.address)))
+            {
+                autentications.remove(current);
+            }
+        }
+        autentications.add(authentication);
+    }
+    
+    
+    
+
+    
+    public boolean authenticationValid(HttpExchange httpExchange)
+    {
+        String address = httpExchange.getRemoteAddress().getHostName();
+        String userAgent = httpExchange.getRequestHeaders().getFirst("User-Agent");
+        
+
+        for (HttpAuthentication current : autentications)
+        {
+            if ((current.userAgent.equals(userAgent)) && (current.address.equals(address)))
+            {
+                return true;
+            }
+        }
+        
+        return false;
+    }
+    
+    
+    
+    public boolean authenticationExpired(HttpExchange httpExchange)
+    {
+        String address = httpExchange.getRemoteAddress().getHostName();
+        String userAgent = httpExchange.getRequestHeaders().getFirst("User-Agent");
+        
+
+        for (HttpAuthentication current : autentications)
+        {
+            if ((current.userAgent.equals(userAgent)) && (current.address.equals(address)))
+            {
+                // TODO
+            }
+        }
+        
+        return false;
+    }
+    
+    
+    
+
+    public void authenticationRemove(HttpExchange httpExchange)
+    {        
+        String address = httpExchange.getRemoteAddress().getHostName();
+        String userAgent = httpExchange.getRequestHeaders().getFirst("User-Agent");
+
+        List<HttpAuthentication> removes = new ArrayList<HttpAuthentication>();
+        
+        for (HttpAuthentication current : autentications)
+        {
+            if ((current.userAgent.equals(userAgent)) && (current.address.equals(address)))
+            {
+                removes.add(current);
+            }
+        }
+        
+        for (HttpAuthentication remove : removes)
+        {
+            autentications.remove(remove);
+        }
+    }    
+        
+        
+}
diff --git a/servers/server/src/art/servers/controller/ControllerNtpHttp.java b/servers/server/src/art/servers/controller/ControllerNtpHttp.java
new file mode 100644
index 0000000..6c96adf
--- /dev/null
+++ b/servers/server/src/art/servers/controller/ControllerNtpHttp.java
@@ -0,0 +1,232 @@
+package art.servers.controller;
+
+import art.servers.Shared;
+import art.servers.configuration.ConfigurationNtpHttp;
+import com.sun.jna.platform.win32.Advapi32;
+import com.sun.jna.platform.win32.Kernel32;
+import com.sun.jna.platform.win32.WinBase;
+import com.sun.jna.platform.win32.WinDef;
+import com.sun.jna.platform.win32.WinNT;
+import com.sun.jna.ptr.IntByReference;
+import java.io.BufferedReader;
+import java.io.ByteArrayOutputStream;
+import java.io.InputStreamReader;
+import java.net.HttpURLConnection;
+import java.net.InetSocketAddress;
+import java.net.Proxy;
+import java.net.URL;
+import java.text.SimpleDateFormat;
+import java.util.Calendar;
+import java.util.Locale;
+import java.util.TimeZone;
+import java.util.Timer;
+import java.util.TimerTask;
+
+public class ControllerNtpHttp extends Controller
+{
+    private ConfigurationNtpHttp configuration = null;
+    private String name = null;
+    
+    public ControllerNtpHttp(ConfigurationNtpHttp configuration)
+    {
+        this.name = Shared.getMessage("NTP HTTP");
+        this.configuration = configuration;
+        
+        Timer timer = new Timer();
+
+        timer.schedule(new TimerTask() 
+        {
+            public void run() 
+            {
+               update();
+            }
+         }, 0, configuration.polling * 1000);
+    }
+    
+    
+    
+    private void update()
+    {
+        try
+        {
+            long t0 = System.currentTimeMillis();
+            
+            String date = getDate(configuration.URL, configuration.timeout, configuration.timeout);
+            SimpleDateFormat dateFormat = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss z", Locale.US);
+            dateFormat.setTimeZone(TimeZone.getTimeZone("GMT"));            
+            
+            long t1 = System.currentTimeMillis();
+            
+            long delay = t1 - t0;
+            long timestamp = dateFormat.parse(date).getTime() + delay;
+            long difference = Math.abs(System.currentTimeMillis() - timestamp);
+            
+            if (difference > configuration.maximumAllowedDelay)
+            {
+                SetLocalTime(timestamp, null);
+            }
+
+            Shared.println(name, Shared.getMessage("Time difference") + " = " + difference + " " + Shared.getMessage("ms"));
+            
+        }
+        catch (Exception exception)
+        {
+            Shared.printerr(name, exception.getMessage());
+        }
+    }
+  
+    
+    
+    private String getDate(String url, int connectionTimeout, int readTimeout) throws Exception
+    {
+        HttpURLConnection connection = null;
+        ByteArrayOutputStream outputStreamBody = null;
+        
+        try 
+        {
+              // Connect to the web server endpoint
+
+              URL httpurl = new URL(url);
+              
+              if ((configuration.proxyAddress != null) && (configuration.proxyPort > 0))
+              {
+                 Proxy proxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress(configuration.proxyAddress, configuration.proxyPort));
+                 connection = (HttpURLConnection)httpurl.openConnection(proxy);
+              }
+              else
+              {
+                 connection = (HttpURLConnection)httpurl.openConnection();
+              }
+              
+              connection.setConnectTimeout(connectionTimeout);
+              connection.setReadTimeout(readTimeout);
+              
+              // Write header
+              
+              connection.setRequestMethod("GET");
+              connection.addRequestProperty("User-Agent", "ALUVISA");
+              connection.addRequestProperty("Content-Type", "application/octet-stream");
+              connection.setDoOutput(true);
+
+              // Read answer
+
+              int responseCode = connection.getResponseCode();
+              
+              if (responseCode == 200)
+              {
+                  return connection.getHeaderField("Date");
+              }
+              else
+              {
+                  throw new Exception("Response code, " + responseCode);
+              }
+
+        } 
+        catch (Exception exception) 
+        {
+            throw exception;
+        } 
+        finally
+        {
+            
+            // Disconnect
+
+            try { outputStreamBody.close(); } catch (Exception e) {};
+            try { connection.disconnect(); } catch (Exception e) {};
+        }
+        
+        
+    }    
+
+
+    
+    
+    private static boolean SetLocalTime(long timestamp, String password) throws Exception
+    {
+        String os = System.getProperty("os.name").toLowerCase();
+
+        if (os.contains("win"))
+        {
+            // Operating system is based on Windows
+            
+            WinNT.TOKEN_PRIVILEGES tp = new WinNT.TOKEN_PRIVILEGES(1);
+            WinNT.TOKEN_PRIVILEGES oldtp = new WinNT.TOKEN_PRIVILEGES(1); 
+            WinNT.LUID luid = new WinNT.LUID();
+            WinNT.HANDLEByReference hTokenRef = new WinNT.HANDLEByReference();
+            if (!Advapi32.INSTANCE.OpenProcessToken(Kernel32.INSTANCE.GetCurrentProcess(), WinNT.TOKEN_ADJUST_PRIVILEGES | WinNT.TOKEN_QUERY, hTokenRef)) 
+            {
+                throw new Exception("HTTP clock. Error. OpenProcessToken");
+            }        
+
+            WinNT.HANDLE hToken = hTokenRef.getValue();
+            if (!Advapi32.INSTANCE.LookupPrivilegeValue(null, WinNT.SE_SYSTEMTIME_NAME, luid)) 
+            {
+                Kernel32.INSTANCE.CloseHandle(hToken);
+                throw new Exception("HTTP clock. Error. LookupPrivilegeValue");
+            }        
+
+            tp.PrivilegeCount = new WinDef.DWORD(1);
+            tp.Privileges = new WinNT.LUID_AND_ATTRIBUTES[1];
+            tp.Privileges[0] = new WinNT.LUID_AND_ATTRIBUTES(luid, new WinDef.DWORD(WinNT.SE_PRIVILEGE_ENABLED));        
+            IntByReference retSize = new IntByReference(0);
+            if (!Advapi32.INSTANCE.AdjustTokenPrivileges(hToken, false, tp, tp.size(), oldtp, retSize)) 
+            {
+                Kernel32.INSTANCE.CloseHandle(hToken);
+                throw new Exception("HTTP clock. Error. AdjustTokenPrivileges");
+            }
+
+            Calendar calendar = Calendar.getInstance();
+            calendar.setTimeInMillis(timestamp);
+            WinBase.SYSTEMTIME st = new WinBase.SYSTEMTIME();
+            st.wYear = (short)calendar.get(Calendar.YEAR);
+            st.wMonth = (short)(calendar.get(Calendar.MONTH) + 1);
+            st.wDay = (short)calendar.get(Calendar.DAY_OF_MONTH);
+            st.wHour = (short)calendar.get(Calendar.HOUR_OF_DAY);
+            st.wMinute = (short)calendar.get(Calendar.MINUTE);
+            st.wSecond = (short)calendar.get(Calendar.SECOND);
+            st.wMilliseconds = (short)calendar.get(Calendar.MILLISECOND);        
+            st.wDayOfWeek = (short)calendar.get(Calendar.DAY_OF_WEEK);        
+
+            boolean  result = Kernel32.INSTANCE.SetLocalTime(st);
+            int error = Kernel32.INSTANCE.GetLastError();
+            Kernel32.INSTANCE.CloseHandle(hToken);
+            
+            return result;
+        }
+        else if (os.contains("osx"))
+        {
+            // Operating system is Apple OSX based
+        }      
+        else if (os.contains("nix") || os.contains("aix") || os.contains("nux"))
+        {
+            // Operating system is based on Linux/Unix/*AIX
+            
+            SimpleDateFormat formato1 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
+            
+            String[] command = {"/bin/bash", "-c", "echo " + password + " | sudo -S date --set='" + formato1.format(timestamp) + "'"};
+            //String[] cmd = {"echo " + password + " | sudo -S date --set='" + formato1.format(timestamp) + "'"};
+            Process process = Runtime.getRuntime().exec(command);
+            int exitValue = process.waitFor();
+            if (exitValue != 0)
+            {
+                BufferedReader reader = new BufferedReader(new InputStreamReader(process.getErrorStream()));
+                String result = new String();
+                String line = null;
+                while ((line = reader.readLine()) != null) result = result + line + "\r\n";
+                throw new Exception(result);
+            }
+            else
+            {
+                return true;
+            }
+        }            
+        
+        return false;
+        
+    }   
+    
+
+    
+    
+    
+}
diff --git a/servers/server/src/art/servers/controller/ControllerProcessInformation.java b/servers/server/src/art/servers/controller/ControllerProcessInformation.java
new file mode 100644
index 0000000..358de31
--- /dev/null
+++ b/servers/server/src/art/servers/controller/ControllerProcessInformation.java
@@ -0,0 +1,264 @@
+package art.servers.controller;
+
+import art.library.model.devices.application.ApplicationStatus;
+import art.library.model.devices.application.status.ApplicationStatusMemory;
+import art.library.model.devices.application.status.ApplicationStatusOperatingSystem;
+import art.library.model.devices.application.status.ApplicationStatusRuntime;
+import art.library.model.devices.application.status.ApplicationStatusThread;
+import art.library.utils.windows.System32;
+import com.sun.management.OperatingSystemMXBean;
+import static java.lang.Thread.sleep;
+import java.lang.management.ManagementFactory;
+import java.lang.management.MemoryMXBean;
+import java.lang.management.MemoryUsage;
+import java.lang.management.RuntimeMXBean;
+import java.lang.management.ThreadMXBean;
+import java.util.Enumeration;
+import java.util.Hashtable;
+import art.servers.Shared;
+
+
+public class ControllerProcessInformation extends Controller
+{
+    public float cores = Runtime.getRuntime().availableProcessors();
+    public long systemTime = 0;
+    public long systemProcessesUsageTime = 0;
+    public long cpuLoadPercentage = 0;
+    public double processorPercentage = 0;
+    private String name = null;
+    private ApplicationStatus status = null;
+    
+    public ControllerProcessInformation()
+    {
+        this.name = Shared.getMessage("Controller process information");
+        this.setName("Controller process information");
+        this.status = new ApplicationStatus();
+        start();
+    }
+    
+
+
+    public ApplicationStatus getApplicationStatus()
+    {
+        return status;
+    }
+    
+    
+    public void run()
+    {
+        Shared.traceInformation(name, Shared.getMessage("Starting"));
+               
+        // Update realtime
+        
+        while ((isInterrupted() == false) && (exit == false))
+        {
+            long timestamp = System.currentTimeMillis();            
+            
+            try
+            {
+                if (Shared.isServerEnabled() == true)
+                {
+                    update();
+                }
+            }
+            catch (Exception exception)
+            {
+            }
+
+            long timetowait = (1000 - (System.currentTimeMillis() - timestamp));
+
+            try
+            {
+                if (timetowait > 0)
+                {
+                    sleep(timetowait);
+                }
+            }
+            catch (Exception e)
+            {
+            }            
+        }
+
+        Shared.traceInformation(name, Shared.getMessage("Finishing"));
+    }
+
+
+    
+    
+    
+    
+    public void update()
+    {
+        if ((System.getProperty("os.name").toLowerCase().contains("windows") == true))
+        {
+            windows();
+        }
+        
+        
+        long timestamp = System.currentTimeMillis();
+        memoryMXBean(status, timestamp);
+        threadMXBean(status, timestamp);
+        runtimeMXBean(status, timestamp);
+        operatingSystemMXBean(status, timestamp);
+        
+    }
+    
+    
+    
+    // <editor-fold defaultstate="collapsed" desc="Windows">    
+
+    private void windows()
+    {
+        try
+        {
+            Hashtable systemProcesses = (Hashtable)System32.listProcessesHashtable();        
+
+            // CPU del sistema
+
+            long newsystemProcessesUsageTime = 0;
+            long newsystemTime = System.currentTimeMillis();
+
+
+            Enumeration enumeration = systemProcesses.elements();
+
+            while (enumeration.hasMoreElements())
+            {
+                art.library.utils.windows.SystemProcess systemProcess = (art.library.utils.windows.SystemProcess)enumeration.nextElement();
+                newsystemProcessesUsageTime = newsystemProcessesUsageTime + systemProcess.lpKernelTime + systemProcess.lpUserTime;
+            }
+
+            this.processorPercentage = (((float)(newsystemProcessesUsageTime - this.systemProcessesUsageTime) / (float)(newsystemTime - this.systemTime)) / this.cores) * 100.0f;
+            if (this.processorPercentage < 0) Shared.controllerProcessInformation.processorPercentage = 0;
+
+            this.systemTime = newsystemTime;
+            this.systemProcessesUsageTime =  newsystemProcessesUsageTime;
+            
+        }
+        catch (Exception exception)
+        {
+        }
+
+    }
+    
+    // </editor-fold>    
+    
+    
+    
+    // <editor-fold defaultstate="collapsed" desc="MX">    
+    
+
+    
+    private void memoryMXBean(ApplicationStatus status, long timestamp)
+    {
+        try
+        {
+            MemoryMXBean memoryMXBean = ManagementFactory.getMemoryMXBean();
+            if (status.memory == null) status.memory = new ApplicationStatusMemory();
+            status.memory.timestamp = timestamp;
+
+            MemoryUsage heapMemoryUsage = memoryMXBean.getHeapMemoryUsage();
+            MemoryUsage nonheapMemoryUsage = memoryMXBean.getNonHeapMemoryUsage();
+            
+            status.memory.heapMemoryUsage_init = heapMemoryUsage.getInit();
+            status.memory.heapMemoryUsage_max = heapMemoryUsage.getMax();
+            status.memory.heapMemoryUsage_used = heapMemoryUsage.getUsed();
+            status.memory.heapMemoryUsage_committed = heapMemoryUsage.getCommitted();
+            
+            status.memory.nonheapMemoryUsage_init = nonheapMemoryUsage.getInit();
+            status.memory.nonheapMemoryUsage_max = nonheapMemoryUsage.getMax();
+            status.memory.nonheapMemoryUsage_used = nonheapMemoryUsage.getUsed();
+            status.memory.nonheapMemoryUsage_committed = nonheapMemoryUsage.getCommitted();
+            
+            status.memory.usedMemory = status.memory.heapMemoryUsage_committed +  status.memory.nonheapMemoryUsage_used; // status.memory.heapMemoryUsage_init
+            
+         }
+        catch (Exception e)
+        {
+        }
+    }
+    
+    
+    
+    
+    private void threadMXBean(ApplicationStatus status, long timestamp)
+    {
+        try
+        {
+            ThreadMXBean threadMXBean = ManagementFactory.getThreadMXBean();
+            if (status.thread == null) status.thread = new ApplicationStatusThread();
+            status.thread.timestamp = timestamp;
+            status.thread.totalStartedThreadCount = threadMXBean.getTotalStartedThreadCount();
+            status.thread.threadCount = threadMXBean.getThreadCount();
+            status.thread.peakThreadCount = threadMXBean.getPeakThreadCount();
+            status.thread.daemonThreadCount = threadMXBean.getDaemonThreadCount();
+            
+        }
+        catch (Exception e)
+        {
+        }
+    }
+    
+    
+    
+    private void runtimeMXBean(ApplicationStatus status, long timestamp)
+    {
+        try
+        {
+            RuntimeMXBean runtimeMXBean = ManagementFactory.getRuntimeMXBean();
+            if (status.runtime == null) status.runtime = new ApplicationStatusRuntime();
+            status.runtime.timestamp = timestamp;
+
+            status.runtime.startTime = runtimeMXBean.getStartTime();
+            status.runtime.upTime = runtimeMXBean.getUptime();
+            status.runtime.userTimeZone = runtimeMXBean.getSystemProperties().get("Time zone");
+            status.runtime.javaVmSpecificationVersion = runtimeMXBean.getSystemProperties().get("java.vm.specification.version");
+            status.runtime.javaRuntimeVersion = runtimeMXBean.getSystemProperties().get("java.runtime.version");
+            status.runtime.javaClassVersion = runtimeMXBean.getSystemProperties().get("java.class.version");
+            status.runtime.userCountry = runtimeMXBean.getSystemProperties().get("user.country");
+            status.runtime.userLanguage = runtimeMXBean.getSystemProperties().get("user.language");
+            status.runtime.userTimeZone = runtimeMXBean.getSystemProperties().get("user.timezone");
+        }
+        catch (Exception e)
+        {
+        }    
+    }
+    
+    
+    
+    
+    private void operatingSystemMXBean(ApplicationStatus status, long timestamp)
+    {
+        try
+        {
+            OperatingSystemMXBean operatingSystemMXBean = (OperatingSystemMXBean)ManagementFactory.getOperatingSystemMXBean();
+            if (status.system == null) status.system = new ApplicationStatusOperatingSystem();
+            status.system.timestamp = timestamp;
+            status.system.committedVirtualMemorySize = operatingSystemMXBean.getCommittedVirtualMemorySize();
+            status.system.name = operatingSystemMXBean.getName();
+            status.system.version = operatingSystemMXBean.getVersion();
+            status.system.arch = operatingSystemMXBean.getArch();
+            status.system.freePhysicalMemorySize = operatingSystemMXBean.getFreePhysicalMemorySize();
+            status.system.freeSwapSpaceSize = operatingSystemMXBean.getFreeSwapSpaceSize();
+            status.system.processCpuLoad = operatingSystemMXBean.getProcessCpuLoad();
+            status.system.processCpuTime = operatingSystemMXBean.getProcessCpuTime() / operatingSystemMXBean.getAvailableProcessors();
+            status.system.systemCpuLoad = operatingSystemMXBean.getSystemCpuLoad();
+            status.system.totalPhysicalMemorySize = operatingSystemMXBean.getTotalPhysicalMemorySize();
+            status.system.totalSwapSpaceSize = operatingSystemMXBean.getTotalSwapSpaceSize();
+            status.system.systemLoadAverage = operatingSystemMXBean.getSystemLoadAverage() / operatingSystemMXBean.getAvailableProcessors();
+            status.system.availableProcessors = operatingSystemMXBean.getAvailableProcessors();
+            status.system.totalPhysicalMemorySize = operatingSystemMXBean.getTotalPhysicalMemorySize();
+            status.system.systemLoadAverage = this.processorPercentage;
+        }
+        catch (Exception e)
+        {
+        }    
+    }
+    
+
+        
+       
+    // </editor-fold>    
+        
+        
+    
+}
diff --git a/servers/server/src/art/servers/controller/ControllerStatus.java b/servers/server/src/art/servers/controller/ControllerStatus.java
new file mode 100644
index 0000000..85219ed
--- /dev/null
+++ b/servers/server/src/art/servers/controller/ControllerStatus.java
@@ -0,0 +1,354 @@
+package art.servers.controller;
+
+import art.library.model.devices.DeviceStatus;
+import art.library.model.devices.application.Application;
+import art.library.model.devices.application.ApplicationAlarms;
+import art.library.model.devices.application.ApplicationInformation;
+import art.library.model.devices.application.ApplicationStatus;
+import art.library.model.devices.application.status.ApplicationStatusMemory;
+import art.library.model.devices.application.status.ApplicationStatusOperatingSystem;
+import art.library.model.devices.application.status.ApplicationStatusRuntime;
+import art.library.model.devices.application.status.ApplicationStatusThread;
+import art.library.utils.synchro.Mutex;
+import art.servers.Shared;
+import com.sun.management.OperatingSystemMXBean;
+import java.lang.management.ManagementFactory;
+import java.lang.management.MemoryMXBean;
+import java.lang.management.MemoryUsage;
+import java.lang.management.RuntimeMXBean;
+import java.lang.management.ThreadMXBean;
+import javax.management.MBeanServerConnection;
+
+
+
+public class ControllerStatus extends Controller
+{
+    private Application application = null;
+    private Mutex mutexPersistance = new Mutex();
+    
+    public ControllerStatus(Application application)
+    {
+        this.setName("Controller status");
+        this.application = application;
+        
+        try
+        {
+            ApplicationStatus status = (ApplicationStatus)this.application.getDeviceStatus();
+            status.started = System.currentTimeMillis();
+        }
+        catch (Exception e)
+        {
+        }
+
+    }
+    
+    
+    
+    public Application getApplication()
+    {
+        return application;
+    }
+    
+    
+
+    
+    public int getAlarms()
+    {
+        try
+        {
+           return 0;
+        }
+        catch (Exception e)
+        {
+        }
+
+        return DeviceStatus.STATUS_UNKNOWN;
+    }    
+    
+    
+    
+    
+    public void run()
+    {
+        try
+        {
+            // Get the stored timeless application if exists
+            // If not we use the application from process configuration file 
+
+            Application[] timelessApplication = Shared.model.getApplication(0);
+            application.information = timelessApplication[0].information;
+        }
+        catch (Exception e)
+        {
+        }
+                
+        
+        Shared.traceInformation(getName(), "Starting");
+        
+        long lastTimestamp = System.currentTimeMillis();
+        
+        while ((isInterrupted() == false) && (exit == false))
+        {
+            
+            // Update current process information
+            
+            lastTimestamp = System.currentTimeMillis();
+
+            memoryMXBean(application, lastTimestamp);
+            threadMXBean(application, lastTimestamp);
+            runtimeMXBean(application, lastTimestamp);
+            operatingSystemMXBean(application, lastTimestamp);
+            updateAlarms(application, lastTimestamp);
+            application.setAlarm("alarm_offline", false);
+
+            if (application.getLastTimestampStatusUpdate() > lastTimestamp)
+            {
+                application.setLastTimestampStatusUpdate(application.getLastTimestampStatusUpdate() + 1);
+            }
+            else
+            {
+                application.setLastTimestampStatusUpdate(lastTimestamp);
+            }
+
+            if (application.getLastTimestampUpdate() > lastTimestamp)
+            {
+                application.setLastTimestampUpdate(application.getLastTimestampUpdate() + 1);
+            }
+            else
+            {
+                application.setLastTimestampUpdate(lastTimestamp);
+            }
+
+            updatePersistence(application);
+
+            
+            long timetowait = application.getDeviceInformation().hearbeat -(System.currentTimeMillis() - lastTimestamp);
+
+            if (timetowait > 0)
+            {
+                try
+                {
+                    sleep(timetowait);
+                }
+                catch (Exception e)
+                {
+                }
+            }
+        }
+        
+        Shared.traceInformation(getName(), "Finishing");
+    }
+
+    
+
+    
+    
+    
+        
+    private void updatePersistence(Application application)
+    {
+        mutexPersistance.lockWrite();
+        
+        try
+        {
+            Shared.model.updateApplication(application);        
+        }
+        catch (Exception e)
+        {
+        }
+        finally
+        {
+            mutexPersistance.releaseWrite();
+        }
+    }    
+
+
+    
+    
+    
+    private void memoryMXBean(Application application, long timestamp)
+    {
+        try
+        {
+            MemoryMXBean memoryMXBean = ManagementFactory.getMemoryMXBean();
+            ApplicationStatus status = application.getDeviceStatus();
+            if (status.memory == null) status.memory = new ApplicationStatusMemory();
+            status.memory.timestamp = timestamp;
+
+            MemoryUsage heapMemoryUsage = memoryMXBean.getHeapMemoryUsage();
+            MemoryUsage nonheapMemoryUsage = memoryMXBean.getNonHeapMemoryUsage();
+            
+            status.memory.heapMemoryUsage_init = heapMemoryUsage.getInit();
+            status.memory.heapMemoryUsage_max = heapMemoryUsage.getMax();
+            status.memory.heapMemoryUsage_used = heapMemoryUsage.getUsed();
+            status.memory.heapMemoryUsage_committed = heapMemoryUsage.getCommitted();
+            
+            status.memory.nonheapMemoryUsage_init = nonheapMemoryUsage.getInit();
+            status.memory.nonheapMemoryUsage_max = nonheapMemoryUsage.getMax();
+            status.memory.nonheapMemoryUsage_used = nonheapMemoryUsage.getUsed();
+            status.memory.nonheapMemoryUsage_committed = nonheapMemoryUsage.getCommitted();
+            
+         }
+        catch (Exception e)
+        {
+        }
+    }
+    
+    
+    
+    
+    private void threadMXBean(Application application, long timestamp)
+    {
+        try
+        {
+            ThreadMXBean threadMXBean = ManagementFactory.getThreadMXBean();
+            ApplicationStatus status = application.getDeviceStatus();
+            if (status.thread == null) status.thread = new ApplicationStatusThread();
+            status.thread.timestamp = timestamp;
+
+            
+            long[] threadsid = threadMXBean.getAllThreadIds();
+
+            long threadCpuTime = 0;
+            long threadUserTime = 0;
+
+            for (long threadid : threadsid)
+            {
+                try
+                {   
+                    long currentThreadCpuTime = threadMXBean.getThreadCpuTime(threadid);
+                    long currentThreadUserTime = threadMXBean.getThreadUserTime(threadid);
+                    if (currentThreadCpuTime > 0) threadCpuTime = threadCpuTime + currentThreadCpuTime;
+                    if (currentThreadUserTime > 0) threadUserTime = threadUserTime + currentThreadUserTime;
+                }
+                catch (Exception e)
+                {
+                }
+            }
+            
+            status.thread.totalStartedThreadCount = threadMXBean.getTotalStartedThreadCount();
+            status.thread.threadCount = threadMXBean.getThreadCount();
+            status.thread.peakThreadCount = threadMXBean.getPeakThreadCount();
+            status.thread.daemonThreadCount = threadMXBean.getDaemonThreadCount();
+            
+        }
+        catch (Exception e)
+        {
+        }
+    }
+    
+    
+    
+    private void runtimeMXBean(Application application, long timestamp)
+    {
+        try
+        {
+            RuntimeMXBean runtimeMXBean = ManagementFactory.getRuntimeMXBean();
+            ApplicationStatus status = application.getDeviceStatus();
+            if (status.runtime == null) status.runtime = new ApplicationStatusRuntime();
+            status.runtime.timestamp = timestamp;
+
+            status.runtime.startTime = runtimeMXBean.getStartTime();
+            status.runtime.upTime = runtimeMXBean.getUptime();
+            status.runtime.userTimeZone = runtimeMXBean.getSystemProperties().get("os.timezone");
+            status.runtime.javaVmSpecificationVersion = runtimeMXBean.getSystemProperties().get("java.vm.specification.version");
+            status.runtime.javaRuntimeVersion = runtimeMXBean.getSystemProperties().get("java.runtime.version");
+            status.runtime.javaClassVersion = runtimeMXBean.getSystemProperties().get("java.class.version");
+            status.runtime.userCountry = runtimeMXBean.getSystemProperties().get("user.country");
+            status.runtime.userLanguage = runtimeMXBean.getSystemProperties().get("user.language");
+            status.runtime.userTimeZone = runtimeMXBean.getSystemProperties().get("user.timezone");
+         }
+        catch (Exception e)
+        {
+        }    
+    }
+    
+    
+    
+    private long nanoBefore = 0;
+    private long cpuBefore = 0;
+    
+    private void operatingSystemMXBean(Application application, long timestamp)
+    {
+        try
+        {
+            OperatingSystemMXBean operatingSystemMXBean = (OperatingSystemMXBean)ManagementFactory.getOperatingSystemMXBean();
+            ApplicationStatus status = application.getDeviceStatus();
+            if (status.system == null) status.system = new ApplicationStatusOperatingSystem();
+            status.system.timestamp = timestamp;
+            status.system.committedVirtualMemorySize = operatingSystemMXBean.getCommittedVirtualMemorySize();
+            status.system.freePhysicalMemorySize = operatingSystemMXBean.getFreePhysicalMemorySize();
+            status.system.freeSwapSpaceSize = operatingSystemMXBean.getFreeSwapSpaceSize();
+            status.system.processCpuLoad = operatingSystemMXBean.getProcessCpuLoad();
+            status.system.processCpuTime = operatingSystemMXBean.getProcessCpuTime();
+            status.system.systemCpuLoad = operatingSystemMXBean.getSystemCpuLoad();
+            status.system.totalPhysicalMemorySize = operatingSystemMXBean.getTotalPhysicalMemorySize();
+            status.system.totalSwapSpaceSize = operatingSystemMXBean.getTotalSwapSpaceSize();
+            status.system.systemLoadAverage = operatingSystemMXBean.getSystemLoadAverage();
+            status.system.availableProcessors = operatingSystemMXBean.getAvailableProcessors();
+            status.system.totalPhysicalMemorySize = operatingSystemMXBean.getTotalPhysicalMemorySize();
+            status.system.name = operatingSystemMXBean.getName();
+            status.system.version = operatingSystemMXBean.getVersion();
+            status.system.arch = operatingSystemMXBean.getArch();
+            
+            if (status.system.systemLoadAverage == -1)
+            {
+                MBeanServerConnection mbsc = ManagementFactory.getPlatformMBeanServer();
+                OperatingSystemMXBean osMBean = ManagementFactory.newPlatformMXBeanProxy(
+                mbsc, ManagementFactory.OPERATING_SYSTEM_MXBEAN_NAME, OperatingSystemMXBean.class);
+
+                if (nanoBefore == 0) 
+                {
+                    long cpuBefore = osMBean.getProcessCpuTime();
+                    long nanoBefore = System.nanoTime();
+                }
+
+                long cpuAfter = osMBean.getProcessCpuTime();
+                long nanoAfter = System.nanoTime();
+
+                if (nanoAfter > nanoBefore) 
+                {
+                    status.system.systemLoadAverage = ((cpuAfter-cpuBefore)*100L)/ (nanoAfter-nanoBefore);
+                }
+                
+                nanoBefore = nanoAfter;
+                cpuBefore = cpuAfter;
+            }
+            
+        }
+        catch (Exception e)
+        {
+        }    
+    }
+    
+    
+
+    private void updateAlarms(Application application, long timestamp)
+    {
+        try
+        {
+            ApplicationInformation information = application.getDeviceInformation();
+            ApplicationStatus status = application.getDeviceStatus();
+            ApplicationAlarms alarms = application.getDeviceAlarms();
+            application.setAlarm("alarm_threads_error", (status.thread.threadCount >=  information.threshold_threads_error),timestamp);
+            application.setAlarm("alarm_threads_warning", (status.thread.threadCount >=  information.threshold_threads_warning) && (alarms.alarm_threads_error == 0), timestamp);
+
+            float memoryCommited = (status.memory.heapMemoryUsage_committed + status.memory.nonheapMemoryUsage_committed);
+            float memoryused = (status.memory.heapMemoryUsage_used + status.memory.nonheapMemoryUsage_used);
+            float memoryLoad = 0.0f;
+            if (memoryCommited > 0) memoryLoad = memoryused / memoryCommited;
+            application.setAlarm("alarm_memory_error", (memoryLoad >=  information.threshold_memory_error),timestamp);
+            application.setAlarm("alarm_memory_warning", (memoryLoad >=  information.threshold_memory_warning) && (alarms.alarm_memory_error == 0), timestamp);
+            
+            application.setAlarm("alarm_processCpuLoad_error", (status.system.processCpuLoad >= information.threshold_processCpuLoad_error),timestamp);
+            application.setAlarm("alarm_processCpuLoad_warning", (status.system.processCpuLoad >= information.threshold_processCpuLoad_warning) && (alarms.alarm_processCpuLoad_error == 0), timestamp);
+            application.setAlarm("alarm_systemCpuLoad_error", (status.system.systemCpuLoad >= information.threshold_systemCpuLoad_error),timestamp);
+            application.setAlarm("alarm_systemCpuLoad_warning", (status.system.systemCpuLoad >= information.threshold_systemCpuLoad_warning) && (alarms.alarm_systemCpuLoad_error == 0), timestamp);
+        }
+        catch (Exception e)
+        {
+        }    
+    }
+        
+   
+}
diff --git a/servers/server/src/art/servers/controller/ControllerTransactions.java b/servers/server/src/art/servers/controller/ControllerTransactions.java
new file mode 100644
index 0000000..37d72a6
--- /dev/null
+++ b/servers/server/src/art/servers/controller/ControllerTransactions.java
@@ -0,0 +1,271 @@
+package art.servers.controller;
+
+import art.library.interop.InteropParameter;
+import art.library.interop.InteropParameters;
+import art.library.interop.InteropResponse;
+import art.library.interop.serialization.Serialization;
+import art.library.interop.serialization.SerializationException;
+import art.library.model.devices.Device;
+import art.library.model.devices.application.ApplicationInformation;
+import art.servers.Shared;
+import art.servers.configuration.ConfigurationTransactions;
+import art.servers.configuration.ConfigurationTransactionsService;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+public class ControllerTransactions extends Controller 
+{
+    private ConfigurationTransactions configuration = null;
+    private ApplicationInformation[] lapplication = new ApplicationInformation[0];
+    private ConfigurationTransactionsService currentTransactionsService = null;
+
+    
+    public ControllerTransactions(ConfigurationTransactions configuration)
+    {
+        this.configuration = configuration;
+        this.setName("Controller transactions");
+        start();
+    }
+    
+    
+    
+    public ApplicationInformation[] getApplications()
+    {
+        return lapplication;
+    }
+    
+    
+    
+    public ApplicationInformation[] getApplications(String service)
+    {
+        List<ApplicationInformation> result = new ArrayList<ApplicationInformation>();
+        
+        for (ApplicationInformation applicationInformation : lapplication)
+        {
+            if ((applicationInformation.serverServiceName != null)  && (applicationInformation.serverServiceName.equals(service)))
+            {
+                result.add(applicationInformation);
+            }
+        }
+        
+        return result.toArray(new ApplicationInformation[result.size()]);
+    }
+    
+    
+    
+    
+    
+    public void run()
+    {
+        Shared.traceInformation(configuration.name, "Starting");
+        
+        long lastTimestamp = System.currentTimeMillis();
+        
+        while ((isInterrupted() == false) && (exit == false))
+        {
+            if (Shared.isServerEnabled() == true)
+            {
+                try
+                {
+                    // reload
+                    
+                    reload();
+                    
+                    // Wait 
+
+                    long timesleep = (configuration.polling * 1000) - (System.currentTimeMillis() - lastTimestamp);
+
+                    if ((timesleep > 0) && (timesleep < (configuration.polling * 1000)))
+                    {
+                        sleep(timesleep);
+                    }
+
+                    // Update devices
+
+                    long currentTimestamp = System.currentTimeMillis();
+                    lastTimestamp = currentTimestamp;
+                }
+                catch (Exception e)
+                {
+                }
+            }
+        }
+        
+        Shared.traceInformation(configuration.name, "Finishing");
+    }
+
+
+    
+    
+    
+    
+    
+    private void reload()
+    {
+        for (ConfigurationTransactionsService configurationTransactionsService : configuration.lservicesTransactions)
+        {
+            try
+            {
+                InteropParameters parameters = new InteropParameters();
+                parameters.addParameter(new InteropParameter("operation", "getApplicationsInformation"));
+                parameters.addParameter(new InteropParameter("language", Shared.configuration.general.language));
+                InteropResponse response = (InteropResponse)Serialization.invoke("get", parameters, configurationTransactionsService.address, configurationTransactionsService.port, configurationTransactionsService.timeout);
+                ApplicationInformation[] lapplication = Arrays.copyOf(response.getValue(), response.getValue().length, ApplicationInformation[].class);
+                
+                if (lapplication.length > 0) 
+                {
+                    currentTransactionsService = configurationTransactionsService;
+                    this.lapplication = lapplication;
+                    return;
+                }
+            }
+            catch (Exception exception)
+            {
+                exception.printStackTrace();
+            }
+        }
+    }
+    
+    
+    
+    
+    
+    public InteropResponse set (InteropParameters parameters) throws  SerializationException
+    {
+        try
+        {
+            return (InteropResponse)Serialization.invoke("set", parameters, currentTransactionsService.address, currentTransactionsService.port, currentTransactionsService.timeout);
+        }
+        catch (Exception exception)
+        {
+        }
+        
+        throw new SerializationException("Operation error (transactions server)");
+    }
+    
+    
+    
+    
+    
+    public InteropResponse get (InteropParameters parameters) throws  SerializationException
+    {
+        try
+        {
+            return (InteropResponse)Serialization.invoke("get", parameters, currentTransactionsService.address, currentTransactionsService.port, currentTransactionsService.timeout);
+        }
+        catch (Exception exception)
+        {
+        }
+        
+        throw new SerializationException("Operation error (transactions server)");
+    }
+    
+    
+    
+    
+    
+    
+    
+    
+    public Device getDevice(String service, String identifier) throws SerializationException
+    {
+        try
+        {
+            for (ApplicationInformation application : getApplications(service))
+            {
+                try
+                {
+                    InteropParameters parameters = new InteropParameters();
+                    parameters.addParameter(new InteropParameter("service", application.serverServiceName));
+                    parameters.addParameter(new InteropParameter("operation", "getDevice"));
+                    parameters.addParameter(new InteropParameter("identifier", identifier));
+                    parameters.addParameter(new InteropParameter("language", Shared.configuration.general.language));
+                    InteropResponse response = (InteropResponse)Serialization.invoke("get", parameters, application.serverAddress, application.serverPort, 30000);
+                    return (Device)response.getValue()[0];
+                }
+                catch (Exception exception)
+                {
+                }
+            }
+        }
+        catch (Exception e)
+        {
+        }
+        
+        throw new SerializationException("Device not found");
+    }
+    
+    
+    
+    public List<Device> getDevices(String service) throws SerializationException
+    {
+        List<Device> result = new ArrayList<Device>();
+        ApplicationInformation[] applications = getApplications(service);
+
+        for (ApplicationInformation application : applications)
+        {
+            if (service.equalsIgnoreCase(application.serverServiceName))
+            {
+                try
+                {
+                    InteropParameters parameters = new InteropParameters();
+                    parameters.addParameter(new InteropParameter("service", application.serverServiceName));
+                    parameters.addParameter(new InteropParameter("operation", "getDevices"));
+                    parameters.addParameter(new InteropParameter("language", Shared.configuration.general.language));
+                    InteropResponse response = (InteropResponse)Serialization.invoke("get", parameters, application.serverAddress, application.serverPort, 30000);
+                    Device[] devices = Arrays.copyOf(response.getValue(), response.getValue().length, Device[].class);
+                    result.addAll(Arrays.asList(devices));
+                }
+                catch (Exception exception)
+                {
+                }
+            }
+        }
+        
+        return result;
+    }
+    
+    
+    public List<Device> getDevices() throws SerializationException
+    {
+        List<Device> result = new ArrayList<Device>();
+        
+        for (ApplicationInformation application : getApplications())
+        {
+            try
+            {
+                InteropParameters parameters = new InteropParameters();
+                parameters.addParameter(new InteropParameter("service", application.serverServiceName));
+                parameters.addParameter(new InteropParameter("operation", "getDevices"));
+                parameters.addParameter(new InteropParameter("language", Shared.configuration.general.language));
+                InteropResponse response = (InteropResponse)Serialization.invoke("get", parameters, application.serverAddress, application.serverPort, 30000);
+                Device[] devices = Arrays.copyOf(response.getValue(), response.getValue().length, Device[].class);
+                result.addAll(Arrays.asList(devices));
+            }
+            catch (Exception exception)
+            {
+            }
+        }
+        
+        return result;
+    }
+    
+    
+    
+    
+    
+    public ApplicationInformation getApplication(String service) throws SerializationException
+    {
+        for (ApplicationInformation application : getApplications(service))
+        {
+            if (service.equalsIgnoreCase(application.serverServiceName))
+            {
+                return(application);
+            }
+        }
+        
+        throw new SerializationException("Application not found");
+    }
+
+}
diff --git a/servers/server/src/art/servers/controller/ControllerUserPermissions.java b/servers/server/src/art/servers/controller/ControllerUserPermissions.java
new file mode 100644
index 0000000..beb6635
--- /dev/null
+++ b/servers/server/src/art/servers/controller/ControllerUserPermissions.java
@@ -0,0 +1,216 @@
+package art.servers.controller;
+
+import art.library.model.devices.user.User;
+import art.library.model.devices.user.UserPermission;
+import art.library.model.transactions.traces.Trace;
+import art.library.utils.licence.Licence;
+import art.library.utils.synchro.Mutex;
+import art.servers.Shared;
+import static java.lang.Thread.sleep;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+
+public class ControllerUserPermissions extends Controller
+{
+    private HashMap<String, UserPermission> permissions = new HashMap<String, UserPermission>();
+    private Mutex mutexUserPermissions = new Mutex();
+    private String name = null;
+    
+    public ControllerUserPermissions()
+    {
+        this.name = Shared.getMessage("Controller user permissions");
+        this.setName(name);
+        start();
+    }
+    
+    
+ 
+    public void run()
+    {
+        Shared.traceInformation(name, "Starting");
+
+        long lastTimestamp = System.currentTimeMillis();
+        
+        while ((isInterrupted() == false) && (exit == false))
+        {
+            if (Shared.isServerEnabled() == true)
+            {
+                try
+                {
+                    // reload
+                    
+                    // reload();  // LO quito a ver si baja el consumo de memoria
+                    
+                    // Wait 
+
+                    long timesleep = (300000) - (System.currentTimeMillis() - lastTimestamp);
+
+                    if ((timesleep > 0) && (timesleep < 300000))
+                    {
+                        sleep(timesleep);
+                    }
+                }
+                catch (Exception e)
+                {
+                }
+            }
+
+            try{sleep(50);} catch (Exception exception){};
+        }
+
+        Shared.println(Trace.getTraceInformation(Shared.getApplicationName(), name, Shared.getMessage("Finishing"), Shared.getMessage("Success")), true);
+    }
+
+
+    
+    
+    private void reload()
+    {
+        try
+        {
+            for (String username : getUsernames())
+            {
+                try
+                {
+                    User user = (User)Shared.model.getDeviceExternal(Licence.encrypt(username));
+                    setUserPermission(username, user.getDeviceConfiguration().permissions);
+                }
+                catch (Exception e)
+                {
+                    User user = (User)Shared.model.getDeviceExternal(username);
+                    setUserPermission(username, user.getDeviceConfiguration().permissions);
+                }
+            }
+        }
+        catch (Exception e)
+        {
+        }
+    }
+    
+    
+    
+
+
+    public UserPermission getUserPermission(String username)
+    {
+        mutexUserPermissions.lockRead();
+        UserPermission permission = permissions.get(username);
+        mutexUserPermissions.releaseRead();
+        
+        try
+        {
+            if (permission == null)
+            {
+                try
+                {
+                    User user = (User)Shared.model.getDeviceExternal(Licence.encrypt(username));
+                    permission = user.getDeviceConfiguration().permissions;
+                    setUserPermission(username, permission);
+                }
+                catch (Exception e)
+                {
+                    User user = (User)Shared.model.getDeviceExternal(username);
+                    permission = user.getDeviceConfiguration().permissions;
+                    setUserPermission(username, permission);
+                }
+            }
+
+            return permission;
+        }
+        catch (Exception e)
+        {
+
+        }
+
+        return null;
+    }
+    
+    
+    
+    
+    
+    public UserPermission getUserPermission(String profile, String username)
+    {
+        mutexUserPermissions.lockRead();
+        UserPermission permission = permissions.get(username);
+        mutexUserPermissions.releaseRead();
+        
+        try
+        {
+        
+            if (permission == null)
+            {
+                try
+                {
+                    User user = (User)Shared.model.getDeviceExternal(Licence.encrypt(username));
+                    permission = user.getDeviceConfiguration().permissions;
+                    setUserPermission(username, permission);
+                }
+                catch (Exception e)
+                {
+                    User user = (User)Shared.model.getDeviceExternal(username);
+                    permission = user.getDeviceConfiguration().permissions;
+                    setUserPermission(username, permission);
+                }
+            }
+            
+            if (permission != null) return permission;
+            
+        }
+        catch (Exception e)
+        {
+        }
+        
+        return getUserPermission(profile);
+    }
+    
+    
+    
+    
+    
+    
+
+    private List<String> getUsernames()
+    {
+        mutexUserPermissions.lockRead();
+        
+        try
+        {
+            return new ArrayList<String>(permissions.keySet());
+        }
+        catch (Exception e)
+        {
+            return(null);
+        }
+        finally
+        {
+            mutexUserPermissions.releaseRead();
+        }
+    }
+    
+
+    
+    
+    
+    private void setUserPermission(String username, UserPermission permission)
+    {
+        mutexUserPermissions.lockWrite();
+        try
+        {
+            permissions.put(username, permission);
+        }
+        catch (Exception e)
+        {
+        }
+        finally
+        {
+            mutexUserPermissions.releaseWrite();
+        }
+    }
+
+
+
+    
+    
+}
diff --git a/servers/server/src/art/servers/controller/FactoryController.java b/servers/server/src/art/servers/controller/FactoryController.java
new file mode 100644
index 0000000..c5f4f97
--- /dev/null
+++ b/servers/server/src/art/servers/controller/FactoryController.java
@@ -0,0 +1,110 @@
+package art.servers.controller;
+
+import art.library.model.devices.Device;
+import art.servers.Shared;
+import java.util.HashMap;
+
+
+
+public class FactoryController extends Thread
+{
+    public HashMap<ControllerDevice, Long> timestamps = new HashMap<ControllerDevice, Long>();
+            
+            
+    public FactoryController()
+    {
+        super();
+        this.setName("Factory controller");
+    }
+    
+
+    public void run()
+    {
+        while (true)
+        {
+            try
+            {
+                // Add controllers 
+
+                for (Device device : Shared.model.getDevices())
+                {
+                    if (Shared.existsDeviceController(device) == false)
+                    {
+                        ControllerDevice controller = addController(device);
+                        timestamps.put(controller, device.getLastTimestampInformationUpdate());
+                    }
+                }
+            }
+            catch (Exception e)
+            {
+            }
+
+            try
+            {
+                // Remove controllers 
+
+                for (Controller controller : Shared.lcontroller)
+                {
+                    if (controller instanceof ControllerDevice)
+                    {
+                        Device device = ((ControllerDevice)controller).getDevice();
+
+                        if (Shared.model.existsDevice(device.getIdentifier()) == false)
+                        {
+                            removeController((ControllerDevice)controller);
+                        }
+                        else if ((Long)timestamps.get(controller) != device.getLastTimestampInformationUpdate())
+                        {
+                            // Information has changed, we delete controller and will be executed again
+                            // May be some changes in connections changed
+                            removeController((ControllerDevice)controller);
+                        }
+                    }
+                }
+            }
+            catch (Exception e)
+            {
+            }
+            
+                
+            try
+            {
+                sleep(5000);
+            }
+            catch (Exception e)
+            {
+            }
+                
+        }
+    }
+         
+    
+    public ControllerDevice addController(Device device) 
+    {
+        return null;
+    }
+    
+    
+
+    public void removeController(ControllerDevice controller)
+    {
+        try
+        {
+            timestamps.remove(controller);
+            controller.close();
+            Shared.lcontroller.remove(controller);
+            
+            if (Shared.window != null)
+            {
+                Device device = controller.getDevice();
+                Shared.window.getArticPanel().removeTab(Shared.getMessage(device.information.name));
+            }
+        }
+        catch (Exception e)
+        {
+        }
+    }
+    
+    
+        
+}
diff --git a/servers/server/src/art/servers/controller/ListenerImplementation.java b/servers/server/src/art/servers/controller/ListenerImplementation.java
new file mode 100644
index 0000000..6fa49eb
--- /dev/null
+++ b/servers/server/src/art/servers/controller/ListenerImplementation.java
@@ -0,0 +1,1791 @@
+package art.servers.controller;
+
+import art.library.interop.InteropParameter;
+import art.library.interop.InteropParameters;
+import art.library.interop.InteropResponse;
+import art.library.interop.serialization.Serialization;
+import art.library.interop.serialization.SerializationException;
+import art.library.model.devices.Device;
+import art.library.model.devices.DeviceInformation;
+import art.library.model.devices.DeviceRealtime;
+import art.library.model.devices.application.ApplicationRealtime;
+import art.library.model.devices.user.User;
+import art.library.model.devices.user.UserPermission;
+import art.library.model.devices.user.configuration.ConfigurationLockLogin;
+import art.library.model.general.ModelFile;
+import art.library.model.transactions.traces.Trace;
+import art.library.model.transactions.traces.TraceResult;
+import art.library.utils.licence.Licence;
+import art.library.utils.resources.Resources;
+import art.servers.ServerException;
+import art.servers.Shared;
+import art.servers.types.HttpAuthentication;
+import art.servers.types.HttpToken;
+import java.io.BufferedOutputStream;
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.InputStreamReader;
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.lang.reflect.Array;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.nio.file.Files;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.TimeZone;
+import java.util.stream.Stream;
+
+
+public class ListenerImplementation 
+{
+    public InteropResponse logout(InteropParameters parameters, String address) throws SerializationException
+    {
+        String language = (String)parameters.getParameterValue("language");
+        String username = (String)parameters.getParameterValue("username");
+        String resource = Shared.getMessage(language, "Username") + " : " + username;
+        resource += ", " + Shared.getMessage(language, "Address") + " : " + address;
+        Shared.traceInformation(Shared.getApplicationName(), Shared.getMessage(language, "Logout"), resource, null, language);
+        return(new InteropResponse(true));
+    }
+
+
+    public InteropResponse login(InteropParameters parameters, String type, String address) throws SerializationException
+    {
+        String language = (String)parameters.getParameterValue("language");
+
+        ConfigurationLockLogin lockLogin = new ConfigurationLockLogin();
+        lockLogin.maximumAddressAttempts = 5;
+        lockLogin.maximumUserAttempts = 5;
+        lockLogin.minutesUserLocked = 5;
+        lockLogin.minutesAddressLocked = 5;
+
+        return(login(parameters, type, address, lockLogin));
+    }
+    
+        
+    public InteropResponse login(InteropParameters parameters, String type, String address, ConfigurationLockLogin lockLogin) throws SerializationException
+    {
+        String language = (String)parameters.getParameterValue("language");
+        String username = (String)parameters.getParameterValue("username");
+        String password = (String)parameters.getParameterValue("password");
+        HttpAuthentication authentication = null;
+        String resource = null;
+
+        try
+        {
+            resource = Shared.getMessage(language, "Username") + " : " + username;
+            resource += ", " + Shared.getMessage(language, "Address") + " : " + address;
+
+            authentication = login(username, password, address, lockLogin);
+
+            if (type.equalsIgnoreCase("json"))
+            {
+                HttpToken httptoken = authentication.getHttpToken();
+                if ((httptoken.resultCode == Shared.RESULT_OK) || (httptoken.resultCode == Shared.ERROR_FIRST_ACCESS))
+                {
+                    Shared.traceInformation(Shared.getApplicationName(), "Login", username, authentication, language);
+                }
+                else if (httptoken.resultCode == Shared.ERROR_WRONG_PASSWORD)
+                {
+                   Shared.traceError(Shared.getApplicationName(), Shared.getMessage(language, "Login"), resource, new SerializationException(Shared.getMessage(language, "Wrong username or password")), authentication, language);
+                }
+                else if (httptoken.resultCode == Shared.ERROR_BLOCKED_ADDRESS)
+                {
+                   Shared.traceError(Shared.getApplicationName(), Shared.getMessage(language, "Login"), resource, new SerializationException(Shared.getMessage(language, "Blocked address")), authentication, language);
+                }
+                else if (httptoken.resultCode == Shared.ERROR_BLOCKED_USER)
+                {
+                   Shared.traceError(Shared.getApplicationName(), Shared.getMessage(language, "Login"), resource, new SerializationException(Shared.getMessage(language, "Blocked user")), authentication, language);
+                }
+
+                InteropResponse response = new InteropResponse(httptoken);
+                return response;
+            }
+            else
+            {
+                HttpToken httptoken = authentication.getHttpToken();
+                if ((httptoken.resultCode == Shared.RESULT_OK) || (httptoken.resultCode == Shared.ERROR_FIRST_ACCESS))
+                {
+                    Shared.traceInformation(Shared.getApplicationName(), "Login", username, authentication, language);
+                }
+                else if (httptoken.resultCode == Shared.ERROR_WRONG_PASSWORD)
+                {
+                   Shared.traceError(Shared.getApplicationName(), Shared.getMessage(language, "Login"), resource, new SerializationException(Shared.getMessage(language, "Wrong username or password")), authentication, language);
+                }
+                else if (httptoken.resultCode == Shared.ERROR_BLOCKED_ADDRESS)
+                {
+                   Shared.traceError(Shared.getApplicationName(), Shared.getMessage(language, "Login"), resource, new SerializationException(Shared.getMessage(language, "Blocked address")), authentication, language);
+                }
+                else if (httptoken.resultCode == Shared.ERROR_BLOCKED_USER)
+                {
+                   Shared.traceError(Shared.getApplicationName(), Shared.getMessage(language, "Login"), resource, new SerializationException(Shared.getMessage(language, "Blocked user")), authentication, language);
+                }
+
+                InteropResponse response = new InteropResponse(httptoken.token);
+                response.mime = "text/plain";
+                return response;
+            }
+        }
+        catch (Exception exception)
+        {
+           Shared.traceError(Shared.getApplicationName(), Shared.getMessage(language, "Login"), resource, exception, authentication, language);
+           throw new SerializationException(Shared.getMessage(language, "Authentication error"));
+        }
+    }
+
+
+    public HttpAuthentication login(String username, String password, String address) throws Exception
+    { 
+        ConfigurationLockLogin lockLogin = new ConfigurationLockLogin();
+        lockLogin.maximumAddressAttempts = 5;
+        lockLogin.maximumUserAttempts = 5;
+        lockLogin.minutesUserLocked = 5;
+        lockLogin.minutesAddressLocked = 5;
+
+        return(login(username, password, address, lockLogin));
+    }
+
+
+    private HttpAuthentication login(String username, String password, String address, ConfigurationLockLogin lockLogin) throws Exception
+    { 
+        // Check user autenthication
+
+        User user = null;
+
+        // TODO: esto cada vez es muy ineficiente, revisar.......
+       
+        try
+        {
+            user = (User)Shared.model.getDeviceExternal(Licence.encrypt(username));
+        }
+        catch (Exception e)
+        {
+            try
+            {
+                Shared.printstack(username, e);
+                user = (User)Shared.model.getDeviceExternal(username);
+                
+            }
+            catch (Exception ex)
+            {
+                // TODO Check blocked address
+                Shared.printstack(username, e);
+                HttpAuthentication authentication = new HttpAuthentication(username, password, address, Shared.ERROR_WRONG_PASSWORD, Shared.getMessage("Authentication error"));
+                return(authentication);
+            }
+        }
+
+        // TODO : volver a poner
+/*        
+        
+        if (user.getDeviceInformation().password.equals(Licence.encrypt(password)) == false)
+        {
+            // Check blocked users
+            // Increase in 1 userstatus.loginErrors
+            // If loginErrors >= 5 then 
+            //      block user
+            //      if (userstatus.unlockTimestamp > 0) nothing to do
+            //      else user.unlockTimestamp = currenttime + configuration.minutesBlocked
+            // return error_wrong_password
+
+            User newuser = Serialization.clone(user);
+            UserStatus status = newuser.getDeviceStatus();
+            if (status == null)
+            {
+                newuser.status = new UserStatus();
+                status = newuser.getDeviceStatus();
+            }
+            status.loginErrors = status.loginErrors + 1;
+            if (status.loginErrors >= lockLogin.maximumUserAttempts)
+            {
+                if (status.unlockTimestamp <= 0)
+                {
+                    status.unlockTimestamp = System.currentTimeMillis() + (lockLogin.minutesUserLocked * 60000L);
+                }
+            }
+
+            Shared.model.updateDevice(user, newuser);
+            HttpAuthentication authentication = new HttpAuthentication(username, password, address, Shared.ERROR_WRONG_PASSWORD, Shared.getMessage("Authentication error, passsword error"));
+            return(authentication);
+        }
+
+        // Check correct accesses
+        // if (currenttime < userstatus.unlockTimestamp) return error_blocked_user
+        // userstatus.loginErrors = 0
+        // user.unlockTimestamp = -1
+        // return ok
+
+        User newuser = Serialization.clone(user);
+        UserStatus status = newuser.getDeviceStatus();
+        if (status == null)
+        {
+            newuser.status = new UserStatus();
+            status = newuser.getDeviceStatus();
+        }
+
+        if (System.currentTimeMillis() < status.unlockTimestamp)
+        {
+            HttpAuthentication authentication = new HttpAuthentication(username, password, address, Shared.ERROR_BLOCKED_USER, Shared.getMessage("Authentication error, blocked user"));
+            return(authentication);
+        }
+
+        if (status.lastLogin < 0)
+        {
+            status.loginErrors = 0;
+            status.unlockTimestamp = -1;
+            status.lastLogin = System.currentTimeMillis();
+            Shared.model.updateDevice(user, newuser);
+
+            HttpAuthentication authentication = new HttpAuthentication(username, password, address, Shared.ERROR_FIRST_ACCESS, Shared.getMessage("Authentication error, first access"));
+            return(authentication);
+        }
+
+        status.loginErrors = 0;
+        status.unlockTimestamp = -1;
+        status.lastLogin = System.currentTimeMillis();
+        Shared.model.updateDevice(user, newuser);
+*/
+
+        HttpAuthentication authentication = new HttpAuthentication(username, password, address, user.getDeviceInformation().group);
+        return authentication;
+    }
+        
+    
+    
+    public InteropResponse art(InteropParameters parameters) throws SerializationException
+    {
+        return artic(parameters);
+    }
+    
+    
+    public InteropResponse artic(InteropParameters parameters) throws SerializationException
+    {
+        String language = (String)parameters.getParameterValue("language");
+                
+        try
+        {
+            // Check permissions
+
+            HttpAuthentication authentication = getHttpAuthentication(parameters);
+           
+            UserPermission permission = Shared.controllerUserPermissions.getUserPermission(authentication.username);
+            
+            if (permission.hasPermissionsParameters(Shared.getApplicationName(), parameters) == false)
+            {
+                throw new SerializationException(Shared.getMessage(language, "Not allowed"));
+            }
+            
+            String operation = (String)parameters.getParameterValue("operation");
+            Method method = this.getClass().getMethod(operation, parameters.getClass());
+            InteropResponse response = (InteropResponse)method.invoke(this, parameters);
+            return response;
+        }
+        catch (NoSuchMethodException e)
+        {
+            StringWriter sw = new StringWriter();
+            e.printStackTrace(new PrintWriter(sw));
+            throw new SerializationException(Shared.getMessage(language, "Bad operation"), sw.toString());
+        }
+        catch (InvocationTargetException e)
+        {
+            if (e.getCause() instanceof SerializationException) throw (SerializationException)e.getCause();
+            Throwable cause = e.getCause();
+            StringWriter sw = new StringWriter();
+            cause.printStackTrace(new PrintWriter(sw));
+            throw new SerializationException(Shared.getMessage(language, cause.getMessage()), sw.toString());
+        }
+        catch (Exception e)
+        {
+           StringWriter sw = new StringWriter();
+           e.printStackTrace(new PrintWriter(sw));
+           throw new SerializationException(Shared.getMessage(language, e.getMessage()), sw.toString()); 
+        }
+    }
+        
+    
+    
+    
+    public InteropResponse articweb(InteropParameters parameters) throws SerializationException
+    {
+        String language = (String)parameters.getParameterValue("language");
+        
+                
+        try
+        {
+            String operation = (String)parameters.getParameterValue("operation");
+            Method method = this.getClass().getMethod(operation, parameters.getClass());
+            InteropResponse response = (InteropResponse)method.invoke(this, parameters);
+            return response;
+        }
+        catch (NoSuchMethodException e)
+        {
+            StringWriter sw = new StringWriter();
+            e.printStackTrace(new PrintWriter(sw));
+            throw new SerializationException(Shared.getMessage(language, "Bad operation"), sw.toString());
+        }
+        catch (InvocationTargetException e)
+        {
+            if (e.getCause() instanceof SerializationException) throw (SerializationException)e.getCause();
+            Throwable cause = e.getCause();
+            StringWriter sw = new StringWriter();
+            cause.printStackTrace(new PrintWriter(sw));
+            throw new SerializationException(Shared.getMessage(language, cause.getMessage()), sw.toString());
+        }
+        catch (Exception e)
+        {
+           StringWriter sw = new StringWriter();
+           e.printStackTrace(new PrintWriter(sw));
+           throw new SerializationException(Shared.getMessage(language, e.getMessage()), sw.toString()); 
+        }
+    }
+
+
+
+    public InteropResponse gis(String uri) throws SerializationException
+    {
+        // Implemented by bridge application
+        
+       throw new SerializationException("Not available");
+    }
+
+
+
+    public InteropResponse saml(InteropParameters parameters) throws SerializationException
+    {
+       // Implemented by bridge application
+       throw new SerializationException("Not available");
+    }
+    
+
+    
+    
+    public InteropResponse get(InteropParameters parameters) throws SerializationException
+    {
+        String language = (String)parameters.getParameterValue("language");
+        String operation = null;
+        
+        try
+        {
+            operation = (String)parameters.getParameterValue("operation");
+
+            if ((operation.indexOf("get") != 0) && (operation.indexOf("list") != 0))
+            {
+                throw new Exception("Not allowed");
+            }
+
+            Method method = this.getClass().getMethod(operation, parameters.getClass());
+            InteropResponse response = (InteropResponse)method.invoke(this, parameters);
+            return response;
+        }
+        catch (NoSuchMethodException e)
+        {
+            Shared.printstack("Listener", e);
+            StringWriter sw = new StringWriter();
+            e.printStackTrace(new PrintWriter(sw));
+            throw new SerializationException(Shared.getMessage(language, "Bad operation"), sw.toString());
+        }
+        catch (InvocationTargetException e)
+        {
+            if (e.getCause() instanceof SerializationException) throw (SerializationException)e.getCause();
+            Throwable cause = e.getCause();
+            StringWriter sw = new StringWriter();
+            cause.printStackTrace(new PrintWriter(sw));
+            throw new SerializationException(Shared.getMessage(language, cause.getMessage()), sw.toString());
+        }
+        catch (Exception e)
+        {
+           StringWriter sw = new StringWriter();
+           e.printStackTrace(new PrintWriter(sw));
+           throw new SerializationException(Shared.getMessage(language, e.getMessage()), sw.toString()); 
+        }
+    }
+    
+
+    
+    
+
+        
+    public InteropResponse set(InteropParameters parameters) throws SerializationException
+    {
+        String language = (String)parameters.getParameterValue("language");
+        
+        try
+        {
+            String operation = (String)parameters.getParameterValue("operation");
+            Method method = this.getClass().getMethod(operation, parameters.getClass());
+            InteropResponse response = (InteropResponse)method.invoke(this, parameters);
+            return response;
+        }
+        catch (NoSuchMethodException e)
+        {
+            Shared.printstack("Listener", e);
+            StringWriter sw = new StringWriter();
+            e.printStackTrace(new PrintWriter(sw));
+            throw new SerializationException(Shared.getMessage(language, "Bad operation"), sw.toString());
+        }
+        catch (InvocationTargetException e)
+        {
+            if (e.getCause() instanceof SerializationException) throw (SerializationException)e.getCause();
+            Throwable cause = e.getCause();
+            StringWriter sw = new StringWriter();
+            cause.printStackTrace(new PrintWriter(sw));
+            throw new SerializationException(Shared.getMessage(language, cause.getMessage()), sw.toString());
+        }
+        catch (Exception e)
+        {
+           Shared.printstack("Listener", e);
+           StringWriter sw = new StringWriter();
+           e.printStackTrace(new PrintWriter(sw));
+           throw new SerializationException(Shared.getMessage(language, e.getMessage()), sw.toString()); 
+        }
+    }
+
+
+   
+    
+    
+
+    public InteropResponse session(InteropParameters parameters) throws SerializationException
+    {
+        String language = (String)parameters.getParameterValue("language");
+        
+        try
+        {
+            String operation = (String)parameters.getParameterValue("operation");
+            Method method = this.getClass().getMethod(operation, parameters.getClass());
+            InteropResponse response = (InteropResponse)method.invoke(this, parameters);
+            return response;
+        }
+        catch (NoSuchMethodException e)
+        {
+            StringWriter sw = new StringWriter();
+            e.printStackTrace(new PrintWriter(sw));
+            throw new SerializationException(Shared.getMessage(language, "Bad operation"), sw.toString());
+        }
+        catch (InvocationTargetException e)
+        {
+            Throwable cause = e.getCause();
+            if (!(cause instanceof ServerException)) cause.printStackTrace();
+            StringWriter sw = new StringWriter();
+            cause.printStackTrace(new PrintWriter(sw));
+            throw new SerializationException(Shared.getMessage(language, cause.getMessage()), sw.toString());
+        }
+        catch (Exception e)
+        {
+           StringWriter sw = new StringWriter();
+           e.printStackTrace(new PrintWriter(sw));
+           throw new SerializationException(Shared.getMessage(language, e.getMessage())); 
+        }
+    }
+    
+
+    
+    
+    
+    // <editor-fold defaultstate="collapsed" desc="Devices">
+
+    
+    public InteropResponse getGroups(InteropParameters parameters) throws SerializationException 
+    {
+        String language = (String)parameters.getParameterValue("language");        
+           
+        try
+        {
+            List<String> lgroup = Shared.model.getGroups();
+            String[] result = lgroup.toArray(new String[lgroup.size()]);
+            return new InteropResponse(result);
+        }
+        catch (Exception e)
+        {
+            throw getException(language, e);
+        }
+    }
+        
+    
+    
+    // http:///gddkia-lublin-dk.pl:7017/get?operation=getDevices&timestamp=0
+    // http:///gddkia-lublin-dk.pl:7017/get?operation=getDevices&identifier=location-krzewica-1&from=0&to=99999999999999
+    // http:///gddkia-lublin-dk.pl:7017/get?operation=getDevices&when=1522308992106;
+    // http:///gddkia-lublin-dk.pl:7017/get?operation=getDevices&when=2018-03-28T10:15:00.000Z;
+    
+    
+    public InteropResponse getDevices(InteropParameters parameters) throws SerializationException 
+    {
+        String language = (String)parameters.getParameterValue("language");        
+           
+        try
+        {
+            String identifier = (String)parameters.getParameterValue("identifier");
+            if (identifier == null) identifier = (parameters.hasParameter("device") == true) ? (String)parameters.getParameterValue("device") : null;
+            String username = (String)parameters.getParameterValue("username");
+            User user = null;
+            if (username != null)
+            {
+                try{user = (User)Shared.model.getDeviceExternal(identifier);} catch (Exception e){};
+                if (user == null)
+                {
+                    try{user = (User)Shared.model.getDeviceExternal(Licence.encrypt(identifier));} catch (Exception e){};
+                }
+            }
+
+            if (parameters.hasParameter("timestamp"))
+            {
+                long timestamp = getTimestamp((String)parameters.getParameterValue("timestamp"));
+                Device[] devices = checkDevices(user, Shared.model.getDevices(identifier, timestamp));
+                return new InteropResponse(devices);
+            }
+            else if (parameters.hasParameter("groups"))
+            {
+                String[] lGroup = getStringArray(parameters.getParameter("groups"));
+                return new InteropResponse(Shared.model.getDevices(lGroup));
+            }
+            else if ((parameters.hasParameter("from")) && (parameters.hasParameter("to")))
+            {
+                long timestamp1 = getTimestamp((String)parameters.getParameterValue("from"));
+                long timestamp2 = getTimestamp((String)parameters.getParameterValue("to"));
+                return new InteropResponse(Shared.model.getDevices(identifier, (long)timestamp1, (long)timestamp2));
+            }
+            else if (parameters.hasParameter("when"))
+            {
+                long timestamp = getTimestamp((String)parameters.getParameterValue("when"));
+                return new InteropResponse(Shared.model.getDevicesWhen(identifier, (long)timestamp));
+            }
+            else if (parameters.hasParameter("next"))
+            {
+                long timestamp = getTimestamp((String)parameters.getParameterValue("next"));
+                return new InteropResponse(Shared.model.getDevicesNext(identifier, (long)timestamp));
+            }
+            else
+            {
+                return new InteropResponse(Shared.model.getDevices(0));
+            }
+        }
+        catch (Exception e)
+        {
+            throw getException(language, e);
+        }
+        
+    }
+
+    
+
+    public InteropResponse getDevicesInformation(InteropParameters parameters) throws SerializationException 
+    {
+        return new InteropResponse(getDevicesInformation((Device[])getDevices(parameters).getValue()));
+    }
+        
+    
+    
+    public InteropResponse getDevicesConfiguration(InteropParameters parameters) throws SerializationException 
+    {
+        return new InteropResponse(getDevicesConfiguration((Device[])getDevices(parameters).getValue()));
+    }
+    
+    
+
+    public InteropResponse getDevicesStatus(InteropParameters parameters) throws SerializationException 
+    {
+        return new InteropResponse(getDevicesStatus((Device[])getDevices(parameters).getValue()));
+    }
+                
+    
+
+    public InteropResponse getDevicesAlarms(InteropParameters parameters) throws SerializationException 
+    {
+        return new InteropResponse(getDevicesAlarms((Device[])getDevices(parameters).getValue()));
+    }
+    
+    
+    public InteropResponse getDevicesStatusAlarms(InteropParameters parameters) throws SerializationException 
+    {
+        return new InteropResponse(getDevicesStatusAlarms((Device[])getDevices(parameters).getValue()));
+    }
+    
+    
+    public InteropResponse getDevice(InteropParameters parameters) throws SerializationException 
+    {
+        String language = (String)parameters.getParameterValue("language");        
+           
+        try
+        {
+            String identifier = (String)parameters.getParameterValue("identifier");
+            if (identifier == null) identifier = (parameters.hasParameter("device") == true) ? (String)parameters.getParameterValue("device") : null;
+            return new InteropResponse(Shared.model.getDevice(identifier));
+        }
+        catch (Exception e)
+        {
+            throw getException(language, e);
+        }
+    }
+    
+    
+    public InteropResponse getDeviceInformation(InteropParameters parameters) throws SerializationException 
+    {
+        return new InteropResponse(getDeviceInformation((Device)getDevice(parameters).getValue()[0]));
+    }
+    
+    
+    public InteropResponse getDeviceConfiguration(InteropParameters parameters) throws SerializationException 
+    {
+        return new InteropResponse(getDeviceConfiguration((Device)getDevice(parameters).getValue()[0]));
+    }
+    
+    
+    public InteropResponse getDeviceStatus(InteropParameters parameters) throws SerializationException 
+    {
+        return new InteropResponse(getDeviceStatus((Device)getDevice(parameters).getValue()[0]));
+    }
+    
+    
+    public InteropResponse getDeviceAlarms(InteropParameters parameters) throws SerializationException 
+    {
+        return new InteropResponse(getDeviceAlarms((Device)getDevice(parameters).getValue()[0]));
+    }
+    
+    
+    public InteropResponse getDeviceStatusAlarms(InteropParameters parameters) throws SerializationException 
+    {
+        return new InteropResponse(getDeviceStatusAlarms((Device)getDevice(parameters).getValue()[0]));
+    }
+    
+
+    
+    
+    public InteropResponse existDevice(InteropParameters parameters) throws SerializationException
+    {
+        String language = (String) parameters.getParameterValue("language");
+
+        try
+        {
+            String identifier = (String)parameters.getParameterValue("identifier");
+            if (identifier == null) identifier = (parameters.hasParameter("device") == true) ? (String)parameters.getParameterValue("device") : null;
+            return new InteropResponse(Shared.model.existsDevice(identifier));
+        } 
+        catch (Exception exception)
+        {
+            throw new SerializationException(Shared.getMessage(language, exception.getMessage()), exception);
+        }
+    }
+    
+    
+    public InteropResponse addDevice (InteropParameters parameters) throws SerializationException
+    {
+        String language = (String)parameters.getParameterValue("language");
+        String bodyContent = null;
+        
+        try
+        {
+            Class clazzDevice = Class.forName(Shared.model.deviceClassName);
+            bodyContent = (String)parameters.getParameterValue("body-content");
+            Device device = (Device)Serialization.deserialize(clazzDevice, bodyContent);
+            addDevices(language, bodyContent);
+            Shared.model.updateDevice(new Device[]{device});
+            return new InteropResponse(new Boolean(true));
+        }
+        catch (ClassCastException exception)
+        {
+        }
+        catch (Exception exception)
+        {
+            throw new SerializationException(Shared.getMessage(language, exception.getMessage()), exception);
+        }
+        
+        return addDevices(language, bodyContent);
+    }
+    
+    
+    
+    
+    public InteropResponse addDevices (InteropParameters parameters) throws SerializationException
+    {
+        String language = (String)parameters.getParameterValue("language");
+        String bodyContent = null;
+        
+        try
+        {
+            System.out.println("1.AddDevices: " + Shared.model.deviceClassName);
+            Class clazzDevice = Class.forName(Shared.model.deviceClassName);
+            System.out.println("2.AddDevices: " + clazzDevice);
+            // bodyContent = (String)parameters.getParameterValue("body-content");
+            Class<?> clazzArray = (Class<?>)Array.newInstance(clazzDevice, 0).getClass();
+            Device[] ldevice = parameters.getBodyContentValue(clazzArray);
+            // System.out.println("3.AddDevices: " + bodyContent);
+            // Device[] ldevice = (Device[])Serialization.deserialize(clazzArray, bodyContent);
+            System.out.println("4.AddDevices: " + ldevice);
+            if ((ldevice != null) && (ldevice.length > 0))
+            {
+                System.out.println("5.AddDevices: " + ldevice[0]);
+                if (ldevice[0] != null)
+                {
+                    System.out.println("6.AddDevices: " + ldevice[0].getIdentifier());
+                    Shared.model.addDevices(Stream.of(ldevice).map(dev -> dev.getDeviceInformation()).toArray(DeviceInformation[]::new));
+                    Shared.model.updateDevice(ldevice);
+                    return new InteropResponse(new Boolean(true));
+                }
+            }
+        }
+        catch (ClassCastException exception)
+        {
+            exception.printStackTrace();
+        }
+        catch (Exception exception)
+        {
+            throw new SerializationException(Shared.getMessage(language, exception.getMessage()), exception);
+        }
+        
+        return addDevices(language, bodyContent);
+    }
+    
+    
+    
+    
+    private InteropResponse addDevices (String language, String bodyContent) throws SerializationException
+    {
+        try
+        {
+            Class clazzInformation = Class.forName(Shared.model.deviceInformationClassName);
+            Class<?> clazzArray = (Class<?>)Array.newInstance(clazzInformation, 0).getClass();
+            DeviceInformation[] linformation = (DeviceInformation[])(Serialization.deserialize(clazzArray, bodyContent));
+            Shared.model.addDevices(linformation);
+            return new InteropResponse(new Boolean(true));
+        }
+        catch (Exception exception)
+        {
+            throw new SerializationException(Shared.getMessage(language, exception.getMessage()), exception);
+        }
+    }
+
+    
+    public InteropResponse deleteDevice (InteropParameters parameters) throws SerializationException
+    {
+        String language = (String)parameters.getParameterValue("language");
+        
+        try
+        {
+            String identifier = null;
+
+            if (parameters.hasParameter("device") == true)
+            {
+                identifier = (String)parameters.getParameterValue("device");
+            }
+            else if (parameters.hasParameter("identifier") == true)
+            {
+                identifier = (String)parameters.getParameterValue("identifier");
+            }
+            
+            Shared.model.deleteDevices(new String[]{identifier});
+            return new InteropResponse(new Boolean(true));
+        }
+        catch (ServerException exception)
+        {
+            throw new SerializationException(Shared.getMessage(language, exception.getMessage()));
+        }
+        catch (Exception exception)
+        {
+            throw new SerializationException(Shared.getMessage(language, exception.getMessage()), exception);
+        }
+    }
+
+    
+    
+    public InteropResponse deleteDevices (InteropParameters parameters) throws SerializationException
+    {
+        String language = (String)parameters.getParameterValue("language");
+        
+        try
+        {
+            String[] lidentifier = new String[0];
+
+            if (parameters.hasParameter("devices") == true)
+            {
+                lidentifier = ((String)parameters.getParameterValue("devices")).split(",");
+            }
+            else if (parameters.hasParameter("identifiers") == true)
+            {
+                lidentifier = ((String)parameters.getParameterValue("identifiers")).split(",");
+            }
+            else
+            {
+                lidentifier = (String[])Serialization.deserialize(String[].class, (String)parameters.getParameterValue("body-content"));
+            }
+            
+            Shared.model.deleteDevices(lidentifier);
+           
+            return new InteropResponse(new Boolean(true));
+        }
+        catch (ServerException exception)
+        {
+            throw new SerializationException(Shared.getMessage(language, exception.getMessage()));
+        }
+        catch (Exception exception)
+        {
+            throw new SerializationException(Shared.getMessage(language, exception.getMessage()), exception);
+        }
+    }
+    
+    
+    
+
+    public InteropResponse getDeviceRealtime(InteropParameters parameters) throws SerializationException 
+    {
+        String language = (String)parameters.getParameterValue("language");        
+           
+        try
+        {
+            String identifier = (String)parameters.getParameterValue("identifier");
+            if (identifier == null) identifier = (parameters.hasParameter("device") == true) ? (String)parameters.getParameterValue("device") : null;
+            long timestamp = (parameters.hasParameter("timestamp") == true) ? Long.parseLong((String)parameters.getParameterValue("timestamp")) : 0;
+            DeviceRealtime realtime = Shared.model.getDevice(identifier).getDeviceRealtime();
+            if (realtime.lastTimestampUpdate > timestamp) return new InteropResponse(realtime);
+        }
+        catch (Exception e)
+        {
+            throw getException(language, e);
+        }
+        
+        throw new SerializationException("Realtime does not exists");
+    }
+    
+    
+
+    
+
+    public InteropResponse getDevicesRealtime(InteropParameters parameters) throws SerializationException 
+    {
+        String language = (String)parameters.getParameterValue("language");
+        long timestamp = (parameters.hasParameter("timestamp") == true) ? Long.parseLong((String)parameters.getParameterValue("timestamp")) : 0;
+
+        try
+        {
+            List<DeviceRealtime> lrealtime = new ArrayList<DeviceRealtime>();
+
+            Device[] ldevice = art.servers.Shared.model.getDevicesCopy();
+            for (Device device : ldevice)
+            {
+                DeviceRealtime realtime = device.getDeviceRealtime();
+                
+                if (realtime != null)
+                {
+                    if (realtime.lastTimestampUpdate > timestamp) 
+                    {
+                        realtime.identifier = device.getIdentifier();
+                        lrealtime.add(realtime);
+                    }
+                }
+            }
+
+            return new InteropResponse(lrealtime.toArray(new DeviceRealtime[lrealtime.size()]));
+        }
+        catch (Exception e)
+        {
+            throw getException(language, e);
+        }
+    }
+        
+    
+    
+    
+    
+    private Device[] getDevicesInformation(Device[] ldevice) throws SerializationException 
+    {
+        Device[] result = new Device[ldevice.length];
+        
+        for (int i=0; i<ldevice.length; i++)
+        {
+            result[i] = Serialization.clone((Device)ldevice[i]);
+            result[i].configuration = null;
+            result[i].status = null;
+            result[i].alarms = null;
+        }
+        
+        return result;
+    }
+        
+    
+
+    
+    private Device[] getDevicesConfiguration(Device[] ldevice) throws SerializationException 
+    {
+        Device[] result = new Device[ldevice.length];
+        
+        for (int i=0; i<ldevice.length; i++)
+        {
+            result[i] = Serialization.clone((Device)ldevice[i]);
+            result[i].information = new DeviceInformation();
+            result[i].information.setIdentifier(((Device)ldevice[i]).getIdentifier());
+            result[i].status = null;
+            result[i].alarms = null;
+        }
+        
+        return result;
+    }
+            
+    
+    
+
+    private Device[] getDevicesStatus(Device[] ldevice) throws SerializationException 
+    {
+        Device[] result = new Device[ldevice.length];
+        
+        for (int i=0; i<ldevice.length; i++)
+        {
+            result[i] = Serialization.clone((Device)ldevice[i]);
+            result[i].information = new DeviceInformation();
+            result[i].information.setIdentifier(((Device)ldevice[i]).getIdentifier());
+            result[i].configuration = null;
+            result[i].alarms = null;
+        }
+        
+        return result;
+    }
+                
+    
+
+    private Device[] getDevicesAlarms(Device[] ldevice) throws SerializationException 
+    {
+        Device[] result = new Device[ldevice.length];
+        
+        for (int i=0; i<ldevice.length; i++)
+        {
+            result[i] = Serialization.clone((Device)ldevice[i]);
+            result[i].information = new DeviceInformation();
+            result[i].information.setIdentifier(((Device)ldevice[i]).getIdentifier());
+            result[i].configuration = null;
+            result[i].status = null;
+        }
+        
+        return result;
+    }
+    
+    
+
+
+    private Device[] getDevicesStatusAlarms(Device[] ldevice) throws SerializationException 
+    {
+        Device[] result = new Device[ldevice.length];
+        
+        for (int i=0; i<ldevice.length; i++)
+        {
+            result[i] = Serialization.clone((Device)ldevice[i]);
+            result[i].information = new DeviceInformation();
+            result[i].information.setIdentifier(((Device)ldevice[i]).getIdentifier());
+            result[i].configuration = null;
+        }
+        
+        return result;
+    }
+            
+    
+    
+
+    private Device getDeviceInformation(Device device) throws SerializationException 
+    {
+        Device result = Serialization.clone(device);
+        result.configuration = null;
+        result.status = null;
+        result.alarms = null;
+
+        return result;
+    }
+            
+    
+    
+
+    private Device getDeviceConfiguration(Device device) throws SerializationException 
+    {
+        Device result = Serialization.clone(device);
+        result.information = new DeviceInformation();
+        result.information.setIdentifier(device.getIdentifier());
+        result.status = null;
+        result.alarms = null;
+
+        return result;
+    }
+            
+    
+    
+
+    private Device getDeviceStatus(Device device) throws SerializationException 
+    {
+        Device result = Serialization.clone(device);
+        result.information = new DeviceInformation();
+        result.information.setIdentifier(device.getIdentifier());
+        result.configuration = null;
+        result.alarms = null;
+
+        return result;
+    }
+            
+    
+    
+
+    private Device getDeviceAlarms(Device device) throws SerializationException 
+    {
+        Device result = Serialization.clone(device);
+        result.information = new DeviceInformation();
+        result.information.setIdentifier(device.getIdentifier());
+        result.status = null;
+        result.configuration = null;
+
+        return result;
+    }
+            
+    
+    
+
+    private Device getDeviceStatusAlarms(Device device) throws SerializationException 
+    {
+        Device result = Serialization.clone(device);
+        result.information = new DeviceInformation();
+        result.information.setIdentifier(device.getIdentifier());
+        result.configuration = null;
+
+        return result;
+    }
+
+    
+    // </editor-fold>
+    
+
+    // <editor-fold defaultstate="collapsed" desc="Symbols">    
+    
+    public InteropResponse getSymbols(InteropParameters parameters) throws SerializationException 
+    {
+        String language = (String)parameters.getParameterValue("language");        
+           
+        try
+        {
+            if (parameters.hasParameter("timestamp"))
+            {
+                long timestamp = Long.parseLong((String)parameters.getParameterValue("timestamp"));
+                return new InteropResponse(Shared.model.getSymbols(timestamp));
+            }
+            else
+            {
+                return new InteropResponse(Shared.model.getSymbols(0));
+            }
+        }
+        catch (Exception e)
+        {
+            throw getException(language, e);
+        }
+    }    
+    
+    
+    // </editor-fold> 
+    
+    
+    // <editor-fold defaultstate="collapsed" desc="Scalable Vector Graphics">    
+    
+  
+    public InteropResponse listScalableVectorGraphics (InteropParameters parameters) throws SerializationException 
+    {
+        String language = (String)parameters.getParameterValue("language");        
+           
+        try
+        {
+            String identifier = (String)parameters.getParameterValue("identifier");
+            if (identifier == null) identifier = (String)parameters.getParameterValue("device");
+
+            File folder = new File("data/" + Shared.getApplicationName() + "/svgs/" + identifier + "/");
+
+            List<ModelFile> lfiles = new ArrayList<ModelFile>();
+                
+            for (File file : folder.listFiles())
+            {
+                ModelFile modelFile = new ModelFile();
+                modelFile.name = file.getName().substring(0, file.getName().lastIndexOf('.'));
+                modelFile.mime = "image/svg+xml";
+                lfiles.add(modelFile);
+            }
+
+            InteropResponse response = new InteropResponse(lfiles);
+            return response;
+        }
+        catch (Exception e)
+        {
+            throw getException(language, e);
+        }
+    }        
+
+
+
+    
+    
+    public InteropResponse getScalableVectorGraphics (InteropParameters parameters) throws SerializationException 
+    {
+        String language = (String)parameters.getParameterValue("language");        
+           
+        try
+        {
+            String identifier = (String)parameters.getParameterValue("identifier");
+            if (identifier == null) identifier = (String)parameters.getParameterValue("device");
+            String name = (String)parameters.getParameterValue("name");
+            
+            if (name != null)
+            {
+                String filename = "data/" + Shared.getApplicationName() + "/svgs/" + identifier + "/" + name + ".svg"; 
+                byte[] data = Resources.getExternalFileBytes(filename);
+                if (data.length == 0) data = Resources.getResourceBytes(filename);
+                InteropResponse response = new InteropResponse(data);
+                response.mime = "image/svg+xml";
+                return response;
+            }
+            else
+            {
+                File folder = new File("data/" + Shared.getApplicationName() + "/svgs/" + identifier + "/");
+
+                List<ModelFile> lfiles = new ArrayList<ModelFile>();
+                
+                for (File file : folder.listFiles())
+                {
+                    ModelFile modelFile = new ModelFile();
+                    modelFile.data = Files.readAllBytes(file.toPath());
+                    modelFile.name = file.getName().substring(0, file.getName().lastIndexOf('.'));
+                    modelFile.mime = "image/svg+xml";
+                    lfiles.add(modelFile);
+                }
+
+                InteropResponse response = new InteropResponse(lfiles);
+                return response;
+            }
+        }
+        catch (Exception e)
+        {
+            throw getException(language, e);
+        }
+    }        
+
+    
+
+  
+    public InteropResponse addScalableVectorGraphics (InteropParameters parameters) throws SerializationException 
+    {
+        String language = (String)parameters.getParameterValue("language");        
+           
+        try
+        {
+            String identifier = (String)parameters.getParameterValue("identifier");
+            if (identifier == null) identifier = (String)parameters.getParameterValue("device");
+            String name = (String)parameters.getParameterValue("name");
+            byte[] data = parameters.getParameterValue("body-content");
+            String filename = "data/" + Shared.getApplicationName() + "/svgs/" + identifier + "/" + name + ".svg"; 
+            File file = new File(filename);
+            file.getParentFile().mkdirs();
+            FileOutputStream fos = new FileOutputStream(file);
+            fos.write(data);
+            fos.close();
+            return new InteropResponse(new Boolean(true));
+        }
+        catch (Exception e)
+        {
+            throw getException(language, e);
+        }
+    }        
+    
+    
+
+  
+    public InteropResponse removeScalableVectorGraphics (InteropParameters parameters) throws SerializationException 
+    {
+        String language = (String)parameters.getParameterValue("language");        
+           
+        try
+        {
+            String identifier = (String)parameters.getParameterValue("identifier");
+            if (identifier == null) identifier = (String)parameters.getParameterValue("device");
+            String name = (String)parameters.getParameterValue("name");
+            String filename = "data/" + Shared.getApplicationName() + "/svgs/" + identifier + "/" + name + ".svg"; 
+            File file = new File(filename);
+            return new InteropResponse(new Boolean(file.delete()));
+        }
+        catch (Exception e)
+        {
+            throw getException(language, e);
+        }
+    }            
+    
+    
+    // </editor-fold>    
+    
+    
+    // <editor-fold defaultstate="collapsed" desc="Application">
+    
+    public InteropResponse getApplication(InteropParameters parameters) throws SerializationException 
+    {
+        String language = (String)parameters.getParameterValue("language");        
+           
+        try
+        {
+            if (parameters.hasParameter("timestamp"))
+            {
+                long timestamp = Long.parseLong((String)parameters.getParameterValue("timestamp"));
+                return new InteropResponse(Shared.model.getApplication(timestamp));
+            }
+            else if ((parameters.hasParameter("from")) && (parameters.hasParameter("to")))
+            {
+                long timestamp1 = Long.parseLong((String)parameters.getParameterValue("from"));
+                long timestamp2 = Long.parseLong((String)parameters.getParameterValue("to"));
+                return new InteropResponse(Shared.model.getApplication((long)timestamp1, (long)timestamp2));
+            }
+            else if (parameters.getParametersNumber() == 1)
+            {
+                return new InteropResponse(Shared.model.getApplication(0));
+            }
+            else
+            {
+                throw new Exception("Bad parameters");
+            }
+            
+        }
+        catch (Exception e)
+        {
+            throw getException(language, e);
+        }
+    }
+
+    
+    // </editor-fold>
+    
+    
+    // <editor-fold defaultstate="collapsed" desc="Documents">
+    
+    public InteropResponse listDocuments(InteropParameters parameters) throws SerializationException
+    {
+        String language = parameters.getParameterValue("language");
+        
+        try
+        {
+            String folder = (String)parameters.getParameterValue("folder");
+            List<String> ldocument = new ArrayList<String>();
+            File directory = new File("documents/" + folder);
+            if (directory.exists() == false) throw new ServerException("No documents");
+            for (File file : directory.listFiles()) ldocument.add(file.getName());
+            InteropResponse response = new InteropResponse(ldocument.toArray(new String[ldocument.size()]));
+            return response;
+        }
+        catch (ServerException exception)
+        {
+            throw new SerializationException(Shared.getMessage(language, exception.getMessage()));
+        }
+        catch (Exception exception)
+        {
+            throw new SerializationException(Shared.getMessage(language, exception.getMessage()), exception);
+        }
+    }    
+    
+    
+
+    public InteropResponse getDocument(InteropParameters parameters) throws SerializationException
+    {
+        String language = (String)parameters.getParameterValue("language");
+        
+        try
+        {
+            String name = (String)parameters.getParameterValue("name");
+            String folder = (String)parameters.getParameterValue("folder");
+            File file = new File("documents/" + folder + "/" + name);
+            if (file.exists() == false) throw new ServerException("Document does not exists");
+            byte[] data = new byte[(int)file.length()];
+            FileInputStream fis = new FileInputStream(file);
+            fis.read(data);
+            fis.close();
+            InteropResponse response = new InteropResponse(data);
+            return response;
+        }
+        catch (ServerException exception)
+        {
+            throw new SerializationException(Shared.getMessage(language, exception.getMessage()));
+        }
+        catch (Exception exception)
+        {
+            throw new SerializationException(Shared.getMessage(language, exception.getMessage()), exception);
+        }
+    }      
+    
+    
+    
+    public InteropResponse addDocument(InteropParameters parameters) throws SerializationException
+    {
+        String language = (String)parameters.getParameterValue("language");
+        
+        try
+        {
+            String name = parameters.getParameterValue("name");
+            String folder = (String)parameters.getParameterValue("folder");
+            byte[] data = parameters.getParameterValue("body-content");
+            File file = new File("documents/" + folder + "/" + name);
+            file.getParentFile().mkdirs();
+            FileOutputStream fos = new FileOutputStream(file);
+            fos.write(data);
+            fos.close();
+            return new InteropResponse(new Boolean(true));
+        }
+        catch (Exception exception)
+        {
+            throw new SerializationException(Shared.getMessage(language, exception.getMessage()), exception);
+        }
+    }            
+
+        
+
+    public InteropResponse deleteDocument(InteropParameters parameters) throws SerializationException
+    {
+        String language = (String)parameters.getParameterValue("language");
+        
+        try
+        {
+            String name = (parameters.hasParameter("name") == true) ? (String)parameters.getParameterValue("name") : null;
+            String folder = (String)parameters.getParameterValue("folder");
+            File file = new File("documents/" + folder + "/" + name);
+            if (file.exists() == true) return new InteropResponse(new Boolean(file.delete()));
+            throw new ServerException("Document does not exists");
+        }
+        catch (ServerException exception)
+        {
+            throw new SerializationException(Shared.getMessage(language, exception.getMessage()));
+        }
+        catch (Exception exception)
+        {
+            throw new SerializationException(Shared.getMessage(language, exception.getMessage()), exception);
+        }
+    }            
+        
+    
+    // </editor-fold>        
+    
+
+    // <editor-fold defaultstate="collapsed" desc="Maps">
+    
+    public InteropResponse listMaps(InteropParameters parameters) throws SerializationException
+    {
+        String language = parameters.getParameterValue("language");
+        
+        try
+        {
+            String identifier = (String)parameters.getParameterValue("device");
+
+            List<String> maps = new ArrayList<String>();
+            File folder = new File("data/" + Shared.getApplicationName() + "/maps/" + identifier);
+            if (folder.exists() == false) throw new SerializationException(Shared.getMessage(language, "No maps"));
+            for (File file : folder.listFiles()) maps.add(file.getName().replace(".svg", ""));
+            InteropResponse response = new InteropResponse(maps.toArray(new String[maps.size()]));
+            return response;
+        }
+        catch (SerializationException exception)
+        {
+            throw exception;
+        }
+        catch (Exception exception)
+        {
+            throw new SerializationException(Shared.getMessage(language, exception.getMessage()), exception);
+        }
+    }    
+    
+        
+    
+
+    
+    public InteropResponse getMap(InteropParameters parameters) throws SerializationException
+    {
+        String language = (String)parameters.getParameterValue("language");
+
+        try
+        {
+            String identifier = (String)parameters.getParameterValue("device");
+            String name = (String)parameters.getParameterValue("name");
+
+            File file = new File("data/" + Shared.getApplicationName() + "/maps/" + identifier + "/" + name + ".svg");
+            if (file.exists() == false) throw new SerializationException(Shared.getMessage(language, "Map does not exists"));
+            byte[] data = new byte[(int)file.length()];
+            FileInputStream fis = new FileInputStream(file);
+            fis.read(data);
+            fis.close();
+            InteropResponse response = new InteropResponse(data);
+            response.mime = "image/svg+xml";
+            return response;
+        }
+        catch (SerializationException exception)
+        {
+            throw exception;
+        }
+        catch (Exception exception)
+        {
+            throw new SerializationException(Shared.getMessage(language, exception.getMessage()), exception);
+        }
+    }      
+    
+    
+    
+
+    public InteropResponse addMap(InteropParameters parameters) throws SerializationException
+    {
+        String language = (String)parameters.getParameterValue("language");
+
+        try
+        {
+            String identifier = (String)parameters.getParameterValue("device");
+            String name = parameters.getParameterValue("name");
+
+            byte[] data = parameters.getParameterValue("body-content");
+            File file = new File("data/" + Shared.getApplicationName() + "/maps/" + identifier + "/" + name + ".svg");
+            file.getParentFile().mkdirs();
+            BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(file));
+            bos.write(data);
+            bos.close();
+            
+            return new InteropResponse(new Boolean(true));
+        }
+        catch (Exception exception)
+        {
+            throw new SerializationException(Shared.getMessage(language, exception.getMessage()), exception);
+        }
+    }            
+
+    
+
+    
+    public InteropResponse deleteMap(InteropParameters parameters) throws SerializationException
+    {
+        String language = (String)parameters.getParameterValue("language");
+
+        try
+        {
+            String identifier = (String)parameters.getParameterValue("device");
+            String name = parameters.getParameterValue("name");
+            
+            File file = new File("data/" + Shared.getApplicationName() + "/maps/" + identifier + "/" + name + ".svg");
+            if (file.exists() == true) return new InteropResponse(new Boolean(file.delete()));
+            throw new SerializationException(Shared.getMessage(language, "Map does not exists"));
+        }
+        catch (SerializationException exception)
+        {
+            throw exception;
+        }
+        catch (Exception exception)
+        {
+            throw new SerializationException(Shared.getMessage(language, exception.getMessage()), exception);
+        }
+    }            
+    
+    // </editor-fold>
+    
+    
+    // <editor-fold defaultstate="collapsed" desc="Traces">
+    
+    public InteropResponse getTraceValues (InteropParameters parameters) throws SerializationException
+    {
+        String language = (String)parameters.getParameterValue("language");
+        
+        try
+        {
+            String field = (String)parameters.getParameterValue("field");
+            List<String> traces = Shared.model.getTraceValues(field, Shared.getApplicationName());
+            InteropResponse response = new InteropResponse(traces, true);
+            return response;
+        }
+        catch (Exception exception)
+        {           
+            throw new SerializationException(Shared.getMessage(language, exception.getMessage()), exception);
+        }
+    }
+
+
+    
+
+    public InteropResponse getTraces (InteropParameters parameters) throws SerializationException
+    {
+        String language = (String)parameters.getParameterValue("language");
+        
+        try
+        {
+            TraceResult result = new TraceResult();
+            
+            if (parameters.hasParameter("timestamp") == true)
+            {
+                long timestamp = getTimestamp((String)parameters.getParameterValue("timestamp"));
+                ApplicationRealtime realtime = (ApplicationRealtime)Shared.controllerStatus.getApplication().getDeviceRealtime();
+                result.traces = realtime.getTraces(timestamp);
+                result.timestampfrom = timestamp;
+                result.application = Shared.getApplicationName();
+            }
+            else
+            {
+                result.timestampfrom = getTimestamp((String)parameters.getParameterValue("from"));
+                result.timestampto = getTimestamp((String)parameters.getParameterValue("to"));
+                result.type = (parameters.hasParameter("type") == true) ? Integer.parseInt((String)parameters.getParameterValue("type")) : Trace.TRACE_NONE;
+                result.username = (String)parameters.getParameterValue("username");
+                result.application = Shared.getApplicationName();
+                result.service = (String)parameters.getParameterValue("controller");
+                result.offset = (parameters.hasParameter("offset") == true) ? Integer.parseInt((String)parameters.getParameterValue("offset")) : 0;
+                result.limit = (parameters.hasParameter("limit") == true) ? Integer.parseInt((String)parameters.getParameterValue("limit")) : 1000;
+                result.limit = Math.min(1000, result.limit);
+            }
+            
+            
+            InteropResponse response = new InteropResponse(Shared.model.getTraces(result), false);
+            return response;
+        }
+        catch (Exception exception)
+        {
+            throw new SerializationException(Shared.getMessage(language, exception.getMessage()), exception);
+        }
+    }
+    
+    
+    
+    
+    
+    // </editor-fold>
+    
+    
+    // <editor-fold defaultstate="collapsed" desc="Others">
+    
+
+    public InteropResponse heartbeat(InteropParameters parameters) throws SerializationException 
+    {
+        String language = (String)parameters.getParameterValue("language");        
+        
+        try
+        {
+            return new InteropResponse(new Boolean(true));
+        }
+        catch (Exception e)
+        {
+            throw getException(language, e);
+        }
+    }
+ 
+
+    
+    
+    public InteropResponse restart(InteropParameters parameters) throws SerializationException 
+    {
+        String language = (String)parameters.getParameterValue("language");        
+        
+        try
+        {
+            Shared.exit();
+            return new InteropResponse(new Boolean(true));
+        }
+        catch (Exception e)
+        {
+            throw getException(language, e);
+        }
+    }
+
+    
+    
+    
+    public InteropResponse disable(InteropParameters parameters) throws SerializationException 
+    {
+        String language = (String)parameters.getParameterValue("language");        
+        
+        try
+        {
+            Shared.controllerStatus.getApplication().alarms.clear();
+            Shared.controllerStatus.getApplication().setAlarm("alarm_disabled", true);
+            Shared.model.clearDevices();
+            return new InteropResponse(new Boolean(true));
+        }
+        catch (Exception e)
+        {
+            throw getException(language, e);
+        }
+    }
+    
+    
+    
+    public InteropResponse enable(InteropParameters parameters) throws SerializationException 
+    {
+        String language = (String)parameters.getParameterValue("language");        
+        
+        try
+        {
+            Shared.model.readDevices();
+            Shared.controllerStatus.getApplication().setAlarm("alarm_disabled", false);
+            return new InteropResponse(new Boolean(true));
+        }
+        catch (Exception e)
+        {
+            throw getException(language, e);
+        }
+    }
+
+    
+
+    public static InteropResponse shell(InteropParameters parameters)
+    {
+        try
+        {
+            String command = (String)parameters.getParameterValue("command");
+            Process process = Runtime.getRuntime().exec(command);
+            process.getOutputStream().close();
+            
+            BufferedReader stderr = new BufferedReader(new InputStreamReader(process.getErrorStream()));
+            String error = "";
+            String line;
+            while ((line = stderr.readLine()) != null) error = error + line + "\r\n";
+            stderr.close();
+            if (error.length() == 0) return new InteropResponse(true);
+        }
+        catch (Exception e)
+        {
+        }
+        
+        return new InteropResponse(false);
+    }
+
+    
+
+    
+    protected HttpAuthentication getHttpAuthentication(InteropParameters parameters) throws SerializationException
+    {
+        try
+        {
+            String[] login = ((String)parameters.getParameterValue("token")).split(",");
+            String username = login[0];
+            String password = login[1];
+            String computer = (String)parameters.getParameterValue("computer");
+
+            HttpAuthentication authentication = login(username, password, computer);
+            return authentication;
+        }
+        catch (Exception exception)
+        {
+
+        }
+            
+        try
+        {
+            String token = Licence.decrypt((String)parameters.getParameterValue("token"));
+            HttpAuthentication authentication = (HttpAuthentication)Serialization.deserialize(HttpAuthentication.class, token);
+            return authentication;
+        }
+        catch (Exception exception)
+        {
+
+        }
+        
+        throw new SerializationException("Authentication token error");
+    }
+    
+    
+    
+    
+   // </editor-fold>
+
+
+    private Device[] checkDevices (User user, Device[] devices)
+    {
+        try
+        {
+            if (user == null) return(devices);
+            List<Device> list = new ArrayList<Device>();
+            for (Device device : devices)
+            {
+                if ((user.getDeviceInformation().municipality != null) && (device.getDeviceInformation().municipality != null) &&
+                    (user.getDeviceInformation().municipality.equalsIgnoreCase(device.getDeviceInformation().municipality)))
+                {
+                    list.add(device);
+                }
+            }
+
+            return(list.toArray(new Device[0]));
+        }
+        catch (Exception e)
+        {
+            return(devices);
+        }
+    }
+
+    
+    // <editor-fold defaultstate="collapsed" desc="static">
+    
+    protected static SerializationException getException(String language, Exception exception)
+    {
+        StringWriter sw = new StringWriter();
+        exception.printStackTrace(new PrintWriter(sw));
+        return new SerializationException(Shared.getMessage(language, exception.getMessage()), sw.toString());
+    }
+    
+    
+    
+    protected static String[] getStringArray(InteropParameter parameter)
+    {
+        if (parameter.getValue() instanceof String[])
+        {
+            return (String[])parameter.getValue();
+        }
+        
+        return ((String)parameter.getValue()).split(",");
+    }
+
+    
+
+    public static long getTimestamp(String timestamp)
+    {
+        try
+        {
+            if ((timestamp.contains("/") == false) && (timestamp.contains("-") == false))
+            {
+                if (timestamp.length() == 4) return new SimpleDateFormat("HHmm").parse(timestamp).getTime(); 
+                if (timestamp.length() == 6) return new SimpleDateFormat("HHmmss").parse(timestamp).getTime(); 
+                if (timestamp.length() == 9) return new SimpleDateFormat("HHmmssSSS").parse(timestamp).getTime(); 
+                
+                if (timestamp.length() == 8) return new SimpleDateFormat("yyyyMMdd").parse(timestamp).getTime(); 
+                if (timestamp.length() == 10) return new SimpleDateFormat("yyyyMMddHH").parse(timestamp).getTime(); 
+                if (timestamp.length() == 12) return new SimpleDateFormat("yyyyMMddHHmm").parse(timestamp).getTime(); 
+                if (timestamp.length() == 14) return new SimpleDateFormat("yyyyMMddHHmmss").parse(timestamp).getTime(); 
+                if (timestamp.length() == 17) return new SimpleDateFormat("yyyyMMddHHmmssSSS").parse(timestamp).getTime(); 
+            }
+
+            if (timestamp.indexOf("Z") == 23) 
+            {
+                SimpleDateFormat ISO8601DATEFORMAT = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'");
+                ISO8601DATEFORMAT.setTimeZone(TimeZone.getTimeZone("GMT"));
+                return ISO8601DATEFORMAT.parse(timestamp).getTime();
+            }
+            
+            if ((timestamp.indexOf("/") == 4) && (timestamp.length() == 7)) return new SimpleDateFormat("yyyy/MM").parse(timestamp).getTime();
+            if ((timestamp.indexOf("/") == 2) && (timestamp.length() == 7)) return new SimpleDateFormat("MM/yyyy").parse(timestamp).getTime(); 
+            if ((timestamp.indexOf("-") == 4) && (timestamp.length() == 7)) return new SimpleDateFormat("yyyy-MM").parse(timestamp).getTime();
+            if ((timestamp.indexOf("-") == 2) && (timestamp.length() == 7)) return new SimpleDateFormat("MM-yyyy").parse(timestamp).getTime();
+
+            if ((timestamp.indexOf("/") == 4) && (timestamp.length() == 10)) return new SimpleDateFormat("yyyy/MM/dd").parse(timestamp).getTime(); 
+            if ((timestamp.indexOf("/") == 2) && (timestamp.length() == 10)) return new SimpleDateFormat("dd/MM/yyyy").parse(timestamp).getTime();
+            if ((timestamp.indexOf("-") == 4) && (timestamp.length() == 10)) return new SimpleDateFormat("yyyy-MM-dd").parse(timestamp).getTime();
+            if ((timestamp.indexOf("-") == 2) && (timestamp.length() == 10)) return new SimpleDateFormat("dd-MM-yyyy").parse(timestamp).getTime();
+            
+            if ((timestamp.indexOf("/") == 4) && (timestamp.length() == 16)) return new SimpleDateFormat("yyyy/MM/dd HH:mm").parse(timestamp).getTime(); 
+            if ((timestamp.indexOf("/") == 2) && (timestamp.length() == 16)) return new SimpleDateFormat("dd/MM/yyyy HH:mm").parse(timestamp).getTime();
+            if ((timestamp.indexOf("-") == 4) && (timestamp.length() == 16)) return new SimpleDateFormat("yyyy-MM-dd HH:mm").parse(timestamp).getTime();
+            if ((timestamp.indexOf("-") == 2) && (timestamp.length() == 16)) return new SimpleDateFormat("dd-MM-yyyy HH:mm").parse(timestamp).getTime();
+
+            if ((timestamp.indexOf("/") == 4) && (timestamp.length() == 19)) return new SimpleDateFormat("yyyy/MM/dd HH:mm:ss").parse(timestamp).getTime(); 
+            if ((timestamp.indexOf("/") == 2) && (timestamp.length() == 19)) return new SimpleDateFormat("dd/MM/yyyy HH:mm:ss").parse(timestamp).getTime();
+            if ((timestamp.indexOf("-") == 4) && (timestamp.length() == 19)) return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(timestamp).getTime();
+            if ((timestamp.indexOf("-") == 2) && (timestamp.length() == 19)) return new SimpleDateFormat("dd-MM-yyyy HH:mm:ss").parse(timestamp).getTime();
+            
+            if ((timestamp.indexOf("/") == 4) && (timestamp.length() == 23)) return new SimpleDateFormat("yyyy/MM/dd HH:mm:ss.SSS").parse(timestamp).getTime(); 
+            if ((timestamp.indexOf("/") == 2) && (timestamp.length() == 23)) return new SimpleDateFormat("dd/MM/yyyy HH:mm:ss.SSS").parse(timestamp).getTime();
+            if ((timestamp.indexOf("-") == 4) && (timestamp.length() == 23)) return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS").parse(timestamp).getTime();
+            if ((timestamp.indexOf("-") == 2) && (timestamp.length() == 23)) return new SimpleDateFormat("dd-MM-yyyy HH:mm:ss.SSS").parse(timestamp).getTime();
+
+            return Long.parseLong(timestamp);
+        }
+        catch (Exception exception)
+        {
+        }
+        
+        return 0;
+    }       
+
+    
+    // </editor-fold>
+}
+
diff --git a/servers/server/src/art/servers/controller/http/webpages/Page.java b/servers/server/src/art/servers/controller/http/webpages/Page.java
new file mode 100644
index 0000000..4a35463
--- /dev/null
+++ b/servers/server/src/art/servers/controller/http/webpages/Page.java
@@ -0,0 +1,573 @@
+package art.servers.controller.http.webpages;
+
+
+import art.servers.Shared;
+import art.servers.types.HttpAuthentication;
+import java.lang.reflect.Array;
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.text.DecimalFormat;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.List;
+
+public class Page
+{
+    public HttpAuthentication authentication = null;
+    public String html = null;
+    
+    
+    public Page(HttpAuthentication authentication)
+    {
+        this.authentication = authentication;
+    }
+
+
+    
+    public byte[] toHTML() throws Exception
+    {
+        return new byte[0];
+    }
+
+    
+    
+    // <editor-fold defaultstate="collapsed" desc="Values">    
+    
+
+    protected String value_double(long value)
+    {
+        DecimalFormat formato1 = new DecimalFormat("###,###,###");
+        return formato1.format(value);
+    }    
+
+    
+    protected String value_double(double value)
+    {
+        DecimalFormat formato1 = new DecimalFormat("###,###,###.#");
+        return  formato1.format(value);
+    }    
+    
+    
+    protected String value_datetime(long timestamp)
+    {
+        SimpleDateFormat formato1 = new SimpleDateFormat(Shared.getMessage("dd/MM/yyyy HH:mm:ss"));
+        if (timestamp == 0) return "";
+        return formato1.format(timestamp);
+    }
+
+    // </editor-fold>  
+
+
+    
+    // <editor-fold defaultstate="collapsed" desc="tr">    
+    
+
+    protected String tr_string(String tag, String value)
+    {
+        if (value != null)
+        {
+            return "<tr><td>" + Shared.getMessage(tag) + "</td><td>" + value + "</td></tr>";
+        }
+        else
+        {
+            return "<tr><td>" + Shared.getMessage(tag) + "</td><td></td></tr>";
+        }
+    }
+    
+    
+    protected String tr_string(String tag, String value, String units)
+    {
+        if (value != null)
+        {
+            return "<tr><td>" + Shared.getMessage(tag) + "</td><td>" + value + " " + units + "</td></tr>";
+        }
+        else
+        {
+            return "<tr><td>" + Shared.getMessage(tag) + "</td><td></td></tr>";
+        }
+    }
+    
+    
+
+    protected String tr_integer(String tag, long value, String units)
+    {
+        DecimalFormat formato1 = new DecimalFormat("###,###,###");
+        return "<tr><td>" + Shared.getMessage(tag) + "</td><td>" + formato1.format(value) + " " + units + "</td></tr>";
+    }    
+
+
+    
+    protected String tr_double(String tag, double value, String units)
+    {
+        DecimalFormat formato1 = new DecimalFormat("###,###,###.#");
+        return "<tr><td>" + Shared.getMessage(tag) + "</td><td>" + formato1.format(value) + " " + units + "</td></tr>";
+    }    
+
+
+
+    protected String tr_boolean(String tag, boolean value, boolean reverse)
+    {
+        if (reverse == false)
+        {
+            if (value == true)
+            {
+                return "<tr><td>" + Shared.getMessage(tag) + "</td><td><label>" + Shared.getMessage("Yes") + "</label><span class=\"icon_ok\"></span></td></tr>";
+            }
+            else
+            {
+                return "<tr><td>" + Shared.getMessage(tag) + "</td><td><label>" + Shared.getMessage("No") + "</label><span class=\"icon_ko\"></span></td></tr>";
+            }
+        }
+        else
+        {
+            if (value == false)
+            {
+                return "<tr><td>" + Shared.getMessage(tag) + "</td><td><label>" + Shared.getMessage("No") + "</label><span class=\"icon_ok\"></span></td></tr>";
+            }
+            else
+            {
+                return "<tr><td>" + Shared.getMessage(tag) + "</td><td><label>" + Shared.getMessage("Yes") + "</label><span class=\"icon_ko\"></span></td></tr>";
+            }
+        }
+    }    
+    
+    
+    
+    protected String tr_datetimeicon(String tag, long timestamp)
+    {
+        SimpleDateFormat formato1 = new SimpleDateFormat(Shared.getMessage("dd/MM/yyyy HH:mm:ss"));
+        
+        if (timestamp > 0)
+        {
+            return "<tr><td>" + tag + "</td><td><span class=\"icon_ko\"></span><label>" + formato1.format(timestamp) + "</label></td></tr>";
+        }
+        else
+        {
+            return "<tr><td>" + tag + "</td><td><span class=\"icon_ok\"></span><label></label></td></tr>";
+        }
+    }
+    
+    
+    
+
+    protected String tr_datetime(String tag, long timestamp)
+    {
+        SimpleDateFormat formato1 = new SimpleDateFormat(Shared.getMessage("dd/MM/yyyy HH:mm:ss"));
+        
+        if (timestamp == 0)
+        {
+            return "<tr><td>" + tag + "</td><td></td></tr>";
+        }
+        else
+        {
+            return "<tr><td>" + tag + "</td><td>" + formato1.format(timestamp) + "</td></tr>";
+        }
+    }
+    
+    
+    protected String tr_datetimemillis(String tag, long timestamp)
+    {
+        SimpleDateFormat formato1 = new SimpleDateFormat(Shared.getMessage("dd/MM/yyyy HH:mm:ss.SSS"));
+        
+        if (timestamp == 0)
+        {
+            return "<tr><td>" + tag + "</td><td></td></tr>";
+        }
+        else
+        {
+            return "<tr><td>" + tag + "</td><td>" + formato1.format(timestamp) + "</td></tr>";
+        }
+    }
+    
+    
+    // </editor-fold>  
+
+
+    
+    // <editor-fold defaultstate="collapsed" desc="Fields">    
+    
+    
+    public List<String> getFields(String html) throws Exception
+    {
+        List<String> result = new ArrayList<String>(); 
+            
+        int current = 0;
+        
+        try
+        {
+            while (current >=0)
+            {
+                int index1 = html.indexOf("{{", current);
+                int index2 = html.indexOf("}}", index1 + 3) + 2;
+                result.add(html.substring(index1, index2));
+                current = index2 + 1;
+            }
+            
+        }
+        catch (Exception e)
+        {
+        }
+        
+        return result;
+    }
+    
+    
+    
+    
+    
+    protected String invoke(String html, String field)
+    {
+        try
+        {
+            String[] values = field.replace("{{", "").replaceAll("}}", "").split(";");
+            
+            if ((values[0].equalsIgnoreCase("read") == true) && (values[2].equalsIgnoreCase("this") == true))
+            {
+                return html.replace(field, getValue(this, values[3]).toString());
+            }            
+            
+        }
+        catch (Exception e)
+        {
+            e.printStackTrace();
+        }
+
+        return html.replace(field, "");
+        
+    }
+    
+    
+    // </editor-fold>  
+    
+    
+    
+    // <editor-fold defaultstate="collapsed" desc="Reflection">    
+    
+
+    protected Object getValue(Object object, String name) throws Exception
+    {
+        int indice = name.indexOf(".");
+
+        if (indice > 0)
+        {
+            // Es un campo de una clase
+            
+            String nombreClase = name.substring(0, indice);
+            String nombreRestante = name.substring(indice + 1, name.length());
+            
+            try
+            {
+                Field field = getDeclaredField(object.getClass(), nombreClase);
+                field.setAccessible(true);
+                Object child = field.get(object);
+                Object value = getValue(child, nombreRestante);
+                if (value == null) return "";
+                return value;
+            }
+            catch (Exception e)
+            {
+                try
+                {
+                    Method method = getDeclaredMethod(object.getClass(), nombreClase);
+                    method.setAccessible(true);
+                    Object child = method.invoke(object, new Object[0]);
+                    Object value = getValue(child, nombreRestante);
+                    if (value == null) return "";
+                    return value;
+                }
+                catch (Exception exception)
+                {
+                    return "";
+                }
+            }
+        } 
+        else
+        {
+            try
+            {
+                Field field = null;
+                int fieldArrayIndex = 0;
+                
+                // Array
+                
+                if (name.indexOf("@") > 0)
+                {
+                    String[] tokens = name.split("@");
+                    field = getDeclaredField(object.getClass(), tokens[0]);                    
+                    fieldArrayIndex = Integer.parseInt(tokens[1]);
+                    field.setAccessible(true);
+                    return getValue(field.get(object), fieldArrayIndex);
+                }
+
+                field = getDeclaredField(object.getClass(), name);
+                field.setAccessible(true);
+                return field.get(object);
+            } 
+            catch (Exception e)
+            {
+                try
+                {
+                    Method method = getDeclaredMethod(object.getClass(), name);
+                    method.setAccessible(true);
+                    return method.invoke(object, new Object[0]);
+                }
+                catch (Exception exception)
+                {
+                    return "";
+                }
+            }
+        }
+    }
+    
+    
+    
+
+    protected Object getValue(Object object, String name, Object parameter) throws Exception
+    {
+        int indice = name.indexOf(".");
+
+        if (indice > 0)
+        {
+            // Es un campo de una clase
+            
+            String nombreClase = name.substring(0, indice);
+            String nombreRestante = name.substring(indice + 1, name.length());
+            
+            try
+            {
+                Method method = getDeclaredMethod(object.getClass(), nombreClase);
+                method.setAccessible(true);
+                Object child = method.invoke(object, parameter);
+                return getValue(child, nombreRestante, parameter);
+            }
+            catch (Exception exception)
+            {
+                return null;
+            }
+        } 
+        else
+        {
+            try
+            {
+                Method method = getDeclaredMethod(object.getClass(), name);
+                method.setAccessible(true);
+                return method.invoke(object, parameter);
+            }
+            catch (Exception exception)
+            {
+                return "";
+            }
+        }    
+    }
+    
+    
+    
+    
+    
+    
+    protected Method getDeclaredMethod(Class clazz, String name) throws NoSuchMethodException
+    {
+        try
+        {
+            Method method = clazz.getDeclaredMethod(name);
+            return method;
+        }
+        catch (NoSuchMethodException e)
+        {
+            for (Method declaredMethod : clazz.getDeclaredMethods())
+            {
+                if (declaredMethod.getName().equals(name))
+                {
+                    return declaredMethod;
+                }
+            }
+            
+            if (clazz.getSuperclass() != null)
+            {
+                return getDeclaredMethod(clazz.getSuperclass(), name);
+            }
+            
+        }
+        catch (Exception e)
+        {
+            if (clazz.getSuperclass() != null)
+            {
+                return getDeclaredMethod(clazz.getSuperclass(), name);
+            }
+        }
+        
+        throw new NoSuchMethodException();
+    }
+    
+        
+    protected Field getDeclaredField(Class clase, String name) throws NoSuchFieldException
+    {
+        try
+        {
+            return clase.getDeclaredField(name);
+        } 
+        catch (NoSuchFieldException e)
+        {
+            Class superclase = clase.getSuperclass();
+            return getDeclaredField(superclase, name);
+        }
+    }    
+
+    
+    
+    protected void setValue(String name, Object value, Object object) throws Exception
+    {
+        if ((name == null) || (object == null)) return;
+        
+        int indice = name.indexOf(".");
+
+        if (indice > 0)
+        {
+            // Es un campo de una clase
+
+            String nombreClase = name.substring(0, indice);
+            String nombreRestante = name.substring(indice + 1, name.length());
+            Field field = object.getClass().getDeclaredField(nombreClase);
+            field.setAccessible(true);
+            Object child = field.get(object);
+            setValue(nombreRestante, value, child);
+        } 
+        else
+        {
+            try
+            {
+                Field field = null;
+                int fieldArrayIndex = 0;
+                
+                // Array
+                
+                if (name.indexOf("@") > 0)
+                {
+                    String[] tokens = name.split("@");
+                    field = getDeclaredField(object.getClass(), tokens[0]);
+                    fieldArrayIndex = Integer.parseInt(tokens[1]);
+                }
+                else
+                {
+                    field = getDeclaredField(object.getClass(), name);
+                }
+                
+                field.setAccessible(true);
+                Class classType = field.getType();
+                
+                if (value instanceof String)
+                {
+                    if (classType.isAssignableFrom(Boolean.class) || classType.isAssignableFrom(boolean.class))field.set(object, ((String)value).equalsIgnoreCase("true"));
+                    else if (classType.isAssignableFrom(Byte.class) || classType.isAssignableFrom(byte.class)) field.set(object, Byte.parseByte((String)value));
+                    else if (classType.isAssignableFrom(Short.class) || classType.isAssignableFrom(short.class)) field.set(object, Short.parseShort((String)value));
+                    else if (classType.isAssignableFrom(Integer.class) || classType.isAssignableFrom(int.class)) field.set(object, Integer.parseInt((String)value));
+                    else if (classType.isAssignableFrom(Long.class) || classType.isAssignableFrom(long.class)) field.set(object, Long.parseLong((String)value));
+                    else if (classType.isAssignableFrom(Float.class) || classType.isAssignableFrom(float.class)) field.set(object, Float.parseFloat((String)value));
+                    else if (classType.isAssignableFrom(Double.class) || classType.isAssignableFrom(double.class)) field.set(object, Double.parseDouble((String)value));
+                    else if (classType.isAssignableFrom(String.class)) field.set(object, value);
+                    else if (classType.isArray() == true)
+                    {
+                        Class<?> componentType = classType.getComponentType();
+                        
+                        if ((componentType.isAssignableFrom(Boolean.class)) || componentType.isAssignableFrom(boolean.class)) 
+                        {
+                            boolean[] array = (boolean[])field.get(object); Array.set(array, fieldArrayIndex, ((String)value).equalsIgnoreCase("true"));
+                        }
+                        else if ((componentType.isAssignableFrom(Byte.class)) || componentType.isAssignableFrom(byte.class)) 
+                        {
+                            byte[] array = (byte[])field.get(object); Array.set(array, fieldArrayIndex, Byte.parseByte((String)value));
+                        }
+                        else if ((componentType.isAssignableFrom(Short.class)) || componentType.isAssignableFrom(short.class)) 
+                        {
+                            short[] array = (short[])field.get(object); Array.set(array, fieldArrayIndex, Short.parseShort((String)value));
+                        }
+                        else if ((componentType.isAssignableFrom(Integer.class)) || componentType.isAssignableFrom(int.class)) 
+                        {
+                            int[] array = (int[])field.get(object); Array.set(array, fieldArrayIndex, Integer.parseInt((String)value));
+                        }
+                        else if ((componentType.isAssignableFrom(Long.class)) || componentType.isAssignableFrom(long.class)) 
+                        {
+                            long[] array = (long[])field.get(object); Array.set(array, fieldArrayIndex, Long.parseLong((String)value));
+                        }
+                        else if ((componentType.isAssignableFrom(Float.class)) || componentType.isAssignableFrom(float.class)) 
+                        {
+                            float[] array = (float[])field.get(object); Array.set(array, fieldArrayIndex, Float.parseFloat((String)value));
+                        }
+                        else if ((componentType.isAssignableFrom(Double.class)) || componentType.isAssignableFrom(double.class)) 
+                        {
+                            double[] array = (double[])field.get(object); Array.set(array, fieldArrayIndex, Double.parseDouble((String)value));
+                        }
+                        else
+                        {
+                        }
+                    }
+                    
+                    else field.set(object, value);
+                }
+                else 
+                {
+                    field.set(object, value);
+                }
+            } 
+            catch (Exception e)
+            {
+                for (Method method : object.getClass().getDeclaredMethods())
+                {
+                    if (method.getName().equals(name))
+                    {
+                        Object finalvalue = value;
+                        Class classType = method.getParameterTypes()[0];
+                        
+                        if (value instanceof String)
+                        {
+                            if (classType.isAssignableFrom(Boolean.class) || classType.isAssignableFrom(boolean.class)) finalvalue = new Boolean(value.toString().equalsIgnoreCase("true"));
+                            else if (classType.isAssignableFrom(Byte.class) || classType.isAssignableFrom(byte.class)) finalvalue = new Byte(value.toString());
+                            else if (classType.isAssignableFrom(Short.class) || classType.isAssignableFrom(short.class)) finalvalue = new Short(value.toString());
+                            else if (classType.isAssignableFrom(Integer.class) || classType.isAssignableFrom(int.class)) finalvalue = new Integer(value.toString());
+                            else if (classType.isAssignableFrom(Long.class) || classType.isAssignableFrom(long.class)) finalvalue = new Long(value.toString());
+                            else if (classType.isAssignableFrom(Float.class) || classType.isAssignableFrom(float.class)) finalvalue = new Float(value.toString());
+                            else if (classType.isAssignableFrom(Double.class) || classType.isAssignableFrom(double.class))finalvalue = new Double(value.toString());
+                            else if (classType.isAssignableFrom(String.class)) finalvalue = value.toString();
+                        }
+                        
+                        method.setAccessible(true);
+                        method.invoke(object, finalvalue);
+                        return;
+                    }
+                }
+                
+            }
+        }
+    }
+    
+
+
+    protected Object getValue(Object value, int arrayIndex)
+    {
+        try
+        {
+            if(value.getClass().isArray())
+            {
+                if(value instanceof Object[])
+                {
+                    return ((Object[])value)[arrayIndex];
+                }
+                else // box primitive arrays
+                {
+                    return Array.get(value, arrayIndex); // automatic boxing
+                }
+            }
+        }
+        catch (Exception e)
+        {
+        }
+        
+        return null;
+    }
+
+
+    // </editor-fold>      
+           
+
+    
+}
diff --git a/servers/server/src/art/servers/gui/ArticPanel.java b/servers/server/src/art/servers/gui/ArticPanel.java
new file mode 100644
index 0000000..3ace295
--- /dev/null
+++ b/servers/server/src/art/servers/gui/ArticPanel.java
@@ -0,0 +1,178 @@
+package art.servers.gui;
+
+import art.library.gui.flat.FlatButton;
+import art.library.gui.flat.FlatPanel;
+import art.library.gui.flat.FlatTabbedPane;
+import art.library.utils.resources.Resources;
+import art.servers.Shared;
+import art.servers.gui.components.PanelGeneric;
+import art.servers.gui.components.PanelProcess;
+import art.servers.gui.components.PanelTraces;
+import art.servers.gui.components.PanelTracesHistorical;
+import java.awt.BorderLayout;
+import java.awt.Dimension;
+import java.util.ArrayList;
+import java.util.List;
+import javax.swing.border.EmptyBorder;
+import javax.swing.event.ChangeEvent;
+import javax.swing.event.ChangeListener;
+
+
+
+
+public class ArticPanel extends PanelGeneric
+{
+    public FlatTabbedPane flatTabbedPane = null;
+    private List<PanelGeneric> lPanel = new ArrayList<PanelGeneric>();
+    private FlatButton buttonReload = null;
+    private ArticWindow window = null;
+    public PanelProcess panelSystem = null;
+    public PanelTraces panelLogger = null;
+    public PanelTraces panelTraces = null;
+    public PanelTracesHistorical panelTracesHistorical = null;
+
+    
+    public ArticPanel(ArticWindow window)
+    {
+        this.window = window;
+        
+        flatTabbedPane = new FlatTabbedPane();
+        flatTabbedPane.allowTitleChange(false);
+        flatTabbedPane.allowTitleChange(false);
+        {
+            panelSystem = new PanelProcess(window);
+            lPanel.add(panelSystem);
+            flatTabbedPane.addTab(Shared.getMessage("Process"), panelSystem);
+            flatTabbedPane.addChangeListener(new MyChangeListener());            
+        }
+        {
+            panelLogger = new PanelTraces(window);
+            lPanel.add(panelLogger);
+            flatTabbedPane.addTab(Shared.getMessage("Logger"), panelLogger);
+            flatTabbedPane.addChangeListener(new MyChangeListener());            
+        }
+        flatTabbedPane.allowTitleChange(false);
+        {
+            panelTraces = new PanelTraces(window);
+            lPanel.add(panelTraces);
+            flatTabbedPane.addTab(Shared.getMessage("Traces"), panelTraces);
+            flatTabbedPane.addChangeListener(new MyChangeListener());            
+        }
+        flatTabbedPane.allowTitleChange(false);
+        {
+            panelTracesHistorical = new PanelTracesHistorical(window);
+            lPanel.add(panelTracesHistorical);
+            flatTabbedPane.addTab(Shared.getMessage("Traces historical"), panelTracesHistorical);
+            flatTabbedPane.addChangeListener(new MyChangeListener());            
+        }
+        
+
+        buttonReload = new FlatButton(Shared.getMessage("&Reload"));
+        buttonReload.setIcon(Resources.getResourceURL("data/art.library.server/icons/24x24/arrows.png"));
+        buttonReload.setPreferredSize(new Dimension(buttonReload.getStringWidth(), 0));
+        buttonReload.addActionListener(new java.awt.event.ActionListener()
+        {
+            public void actionPerformed(java.awt.event.ActionEvent evt)
+            {
+                reload();
+            }
+        });
+        buttonReload.revalidate();
+        
+
+        
+        window.addButtonMenu(buttonReload);
+        window.addButtonSeparator();
+        this.setLayout(new BorderLayout());
+        FlatPanel panel1 = new FlatPanel();
+        panel1.setLayout(new BorderLayout());
+        panel1.setBorder(new EmptyBorder(10,5,5,5));
+        panel1.add(flatTabbedPane, BorderLayout.CENTER);
+        this.add(panel1, BorderLayout.CENTER);
+        lPanel.get(0).selection();
+        flatTabbedPane.setSelectedIndex(0);
+    }
+    
+    
+    
+    public void addTab(String name, PanelGeneric panel)
+    {
+        lPanel.add(panel);
+        flatTabbedPane.addTab(name, panel);
+    }
+    
+    
+
+    
+    
+    
+    public void removeTab(String name)
+    {
+        for (int i=0; i<flatTabbedPane.getTabCount(); i++)
+        {
+            if (flatTabbedPane.getTitleAt(i).equalsIgnoreCase(name))
+            {
+                flatTabbedPane.removeTabAt(i);
+                lPanel.remove(flatTabbedPane.getComponentAt(i));
+            }
+        }
+    }
+    
+    
+    
+    public ArticWindow getWindow()
+    {
+        return window;
+    }
+    
+    
+    public void reload()
+    {
+        try
+        {
+            for (PanelGeneric panel : lPanel)
+            {
+                panel.reload();
+            }
+        }
+        catch (Exception e)
+        {
+        }
+    }
+
+
+    public void timer()
+    {
+        try
+        {
+            for (PanelGeneric panel : lPanel)
+            {
+                panel.timer();
+            }
+        }
+        catch (Exception e)
+        {
+        }
+        
+    }
+    
+
+    
+    private class MyChangeListener implements ChangeListener
+    {
+        public void stateChanged(ChangeEvent e)
+        {
+            for (PanelGeneric panel : lPanel) panel.deselection();
+            
+            if (flatTabbedPane.getSelectedComponent() != null)
+            {
+                ((PanelGeneric)flatTabbedPane.getSelectedComponent()).selection();
+                ((PanelGeneric)flatTabbedPane.getSelectedComponent()).reload();
+            }
+        }
+    }    
+
+    
+    
+}
+
diff --git a/servers/server/src/art/servers/gui/ArticWindow.java b/servers/server/src/art/servers/gui/ArticWindow.java
new file mode 100644
index 0000000..4768f84
--- /dev/null
+++ b/servers/server/src/art/servers/gui/ArticWindow.java
@@ -0,0 +1,442 @@
+package art.servers.gui;
+
+import art.library.gui.FlatGUI;
+import art.library.gui.flat.FlatButton;
+import art.library.gui.flat.FlatDialog;
+import art.library.gui.flat.FlatMenu;
+import art.library.gui.flat.FlatMenuBar;
+import art.library.gui.flat.FlatMenuItem;
+import art.library.gui.flat.FlatToggleButton;
+import art.library.gui.flat.FlatWindow;
+import art.library.model.transactions.traces.Trace;
+import art.library.utils.resources.Resources;
+import art.servers.Shared;
+import art.servers.gui.components.PanelClock;
+import java.awt.Dimension;
+import java.awt.Font;
+import java.awt.GraphicsDevice;
+import java.awt.GraphicsEnvironment;
+import java.awt.Image;
+import java.awt.MenuItem;
+import java.awt.MouseInfo;
+import java.awt.PointerInfo;
+import java.awt.PopupMenu;
+import java.awt.SystemTray;
+import java.awt.TrayIcon;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.WindowAdapter;
+import java.awt.event.WindowEvent;
+import javax.swing.JFrame;
+import javax.swing.JOptionPane;
+import javax.swing.JToolBar;
+import javax.swing.SwingUtilities;
+
+public class ArticWindow extends FlatWindow
+{
+    protected ArticWindow window;
+    protected MenuListener menuListener;
+    protected MyActionListener myActionListener;
+    protected javax.swing.Timer secondTimer = null;
+    private FlatButton buttonExit = null;
+    private FlatButton buttonHide = null;
+    private FlatMenuItem menuExit = null;
+    private FlatMenuItem menuHide = null;
+    private PanelClock panelReloj;
+    private ArticPanel articPanel;
+
+    
+    
+    public ArticWindow()
+    {
+        super();
+        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
+        this.window = this;
+        myActionListener = new MyActionListener();
+        this.setIcon(Resources.getResourceURL(Shared.configuration.general.windowIcon));
+        this.setTitle(Shared.configuration.general.windowTitle);
+        this.setDefaultCloseOperation(javax.swing.WindowConstants.DO_NOTHING_ON_CLOSE);
+
+        secondTimer = new javax.swing.Timer(1000, new ActionListener()
+        {
+            public void actionPerformed(ActionEvent e)
+            {
+                timer();
+            }
+        });
+
+        menuWindow();
+        menuBar();
+        menuButtons();
+        content();
+        footer();
+        reload();
+        secondTimer.start();
+        systemTry();
+        
+        addWindowListener(new WindowAdapter()
+        {
+            @Override
+            public void windowClosing(WindowEvent evt)
+            {
+                int answer = FlatDialog.showDialog(ArticWindow.this, Shared.getMessage("Closing"), Shared.getMessage("Do you really want to close?"), true, FlatDialog.DIALOG_QUESTION);
+
+                if (answer == JOptionPane.YES_OPTION)
+                {
+                    Shared.exit();
+                }
+            }
+        });
+    }
+    
+    
+
+
+    public void addTrace(Object object)
+    {
+        if (object instanceof Trace)
+        {
+            articPanel.panelTraces.addTrace(object);    
+        }
+            
+        articPanel.panelLogger.addTrace(object);
+    }
+        
+        
+    
+    
+    public ArticPanel getArticPanel()
+    {
+        return articPanel;
+    }
+    
+    
+    private void menuWindow() 
+    {
+    }
+    
+    
+    private void menuBar()
+    {
+        FlatMenuBar menuBar = new FlatMenuBar();
+
+        FlatMenu menu = new FlatMenu();
+        menu.setText(Shared.getMessage("&File"));
+
+        menuExit = new FlatMenuItem();
+        menuExit.setText(Shared.getMessage("E&xit"));
+        menuExit.addActionListener(new java.awt.event.ActionListener()
+        {
+            public void actionPerformed(java.awt.event.ActionEvent evt)
+            {
+                salir(true);
+            }
+        });
+
+        menuHide = new FlatMenuItem();
+        menuHide.setText(Shared.getMessage("&Hide"));
+        menuHide.addActionListener(new java.awt.event.ActionListener()
+        {
+            public void actionPerformed(java.awt.event.ActionEvent evt)
+            {
+                setVisible(false);
+            }
+        });
+
+        menu.add(menuHide);
+        menu.addSeparator();
+        menu.add(menuExit);
+        menuBar.add(menu);
+        this.setMenuBar(menuBar);
+
+    }
+    
+    
+    
+
+    private void menuButtons()
+    {
+        JToolBar toolbar = new JToolBar();
+        this.setMenuButtons(toolbar);
+
+        buttonExit = new FlatButton(Shared.getMessage("E&xit"));
+        buttonExit.setIcon(Resources.getResourceURL("data/art.library.server/icons/24x24/exit10.png"));
+        buttonExit.setPreferredSize(new Dimension(buttonExit.getStringWidth(), 0));
+        buttonExit.addActionListener(new java.awt.event.ActionListener()
+        {
+            public void actionPerformed(java.awt.event.ActionEvent evt)
+            {
+                salir(true);
+            }
+        });
+
+        buttonHide = new FlatButton(Shared.getMessage("&Hide"));
+        buttonHide.setIcon(Resources.getResourceURL("data/art.library.server/icons/24x24/hide.png"));
+        buttonHide.setPreferredSize(new Dimension(buttonHide.getStringWidth(), 0));
+        buttonHide.addActionListener(new java.awt.event.ActionListener()
+        {
+            public void actionPerformed(java.awt.event.ActionEvent evt)
+            {
+                setVisible(false);
+            }
+        });
+
+        
+        this.addButtonMenu(buttonExit);
+        this.addButtonMenu(buttonHide);
+        this.addButtonSeparator();
+        
+    }
+    
+    
+    
+    private void footer()
+    {
+        panelReloj = new PanelClock();
+        setFooter(panelReloj, new Dimension(24, 24));        
+    }
+    
+
+    public void messageFooter(String text)
+    {
+        panelReloj.message(text);
+    }    
+
+    private void content()
+    {
+        articPanel = new ArticPanel(this);
+        this.setContent(articPanel);
+        articPanel.selection();
+    }
+    
+    
+    
+    private void salir(boolean ask)
+    {
+        if (ask == true)
+        {
+            int answer = FlatDialog.showDialog(ArticWindow.this, Shared.getMessage("Closing"), Shared.getMessage("Do you really want to close?"), true, FlatDialog.DIALOG_QUESTION);
+            if (answer != JOptionPane.YES_OPTION) return;
+        }
+        
+        Shared.traceInformation(Shared.getMessage("Graphic interface"), "Finishing");
+        Shared.exit();
+    }
+    
+    
+    
+    public void reload() 
+    {
+        articPanel.reload();
+        panelReloj.reload();
+    };
+    
+    
+    
+    
+    public void grants() {};
+    public void help() {};
+    
+    
+    public void timer() 
+    {
+        if (this.isShowing() == true)
+        {
+            panelReloj.timer();
+            articPanel.timer();
+        }
+    }    
+    
+    public void edit(boolean value) {};
+
+    public void setMenuListener(MenuListener menuListener)
+    {
+        this.menuListener = menuListener;
+    }
+
+    public MenuListener getMenuListener()
+    {
+        return menuListener;
+    }
+
+    public void startGUI()
+    {
+        Runnable runnable = new Runnable()
+        {
+            public void run()
+            {
+                showGUI(true);
+            }
+        };
+
+        SwingUtilities.invokeLater(runnable);
+    }
+
+
+    public void showGUI(int x, int y, int w, int h, boolean resizable, boolean automaticSystemLocation)
+    {
+        setLocation(x, y);
+        if (automaticSystemLocation == true)
+        {
+            setLocationByPlatform(true);
+        }
+        setPreferredSize(new Dimension(w, h));
+        setResizable(resizable);
+        setVisible(true);
+        pack();
+    }
+
+    
+    public void showGUI(boolean automaticSystemLocation)
+    {
+        PointerInfo pointerInfo = MouseInfo.getPointerInfo();
+        GraphicsDevice gd = GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice();
+        int x = (int) pointerInfo.getLocation().getX();
+        int y = (int) pointerInfo.getLocation().getY();
+        int screenWidth = gd.getDisplayMode().getWidth();
+        int screenHeight = gd.getDisplayMode().getHeight();
+        int w = screenWidth - (x % screenWidth);
+        int h = screenHeight - (y % screenHeight);
+        setLocation(x, y);
+        if (automaticSystemLocation == true)
+        {
+            setLocationByPlatform(true);
+        }
+        setPreferredSize(new Dimension(w, h));
+        setResizable(true);
+        setVisible(true);
+        pack();
+
+    }
+
+    
+    
+    private class MyActionListener implements ActionListener
+    {
+
+        public void actionPerformed(ActionEvent e)
+        {
+            String action = null;
+
+            if (e.getSource() instanceof FlatMenuItem)
+            {
+                FlatMenuItem menuItem = (FlatMenuItem) e.getSource();
+                action = menuItem.getName();
+            } 
+            else if (e.getSource() instanceof FlatButton)
+            {
+                FlatButton button = (FlatButton) e.getSource();
+                action = button.getName();
+            } 
+            else if (e.getSource() instanceof FlatToggleButton)
+            {
+                FlatToggleButton button = (FlatToggleButton) e.getSource();
+                action = button.getName();
+            }
+
+            MenuListener listener = window.getMenuListener();
+
+            if ((action != null) && (listener != null))
+            {
+                if (listener != null)
+                {
+                    listener.menuSelection(action);
+                }
+            }
+
+        }
+
+    }
+    
+
+    
+    private SystemTray tray = null;
+    private TrayIcon trayIcon = null;
+    private Image icon_STATUS = Resources.getResourceImage("data/" + Shared.getApplicationName() + "/icons/16x16/status-white.png");
+    
+    
+    private void systemTry()
+    {
+        try
+        {
+            if (!SystemTray.isSupported()) 
+            {
+                return;
+            }       
+
+            PopupMenu popup = new PopupMenu();
+            trayIcon = new TrayIcon(icon_STATUS, Shared.configuration.general.windowTitle);
+            trayIcon.setPopupMenu(popup);
+            tray = SystemTray.getSystemTray();        
+
+            MenuItem aboutItem = new MenuItem(Shared.configuration.general.windowTitle);
+            aboutItem.setFont(getFont().deriveFont(Font.BOLD));
+            MenuItem lookItem = new MenuItem(Shared.getMessage("Look"));
+            MenuItem showItem = new MenuItem(Shared.getMessage("Show"));
+            MenuItem hideItem = new MenuItem(Shared.getMessage("Hide"));
+            MenuItem exitItem = new MenuItem(Shared.getMessage("Exit")); 
+
+            //Add components to pop-up menu
+
+            popup.add(aboutItem);
+            popup.addSeparator();
+            popup.add(lookItem);
+            popup.addSeparator();
+            popup.add(showItem);
+            popup.add(hideItem);
+            popup.addSeparator();
+            popup.add(exitItem);
+            
+            
+            lookItem.addActionListener(new java.awt.event.ActionListener() 
+            {
+                public void actionPerformed(java.awt.event.ActionEvent evt) 
+                {
+                    FlatGUI.initialise();
+                    repaint();
+                }
+            });
+            
+            showItem.addActionListener(new java.awt.event.ActionListener() 
+            {
+                public void actionPerformed(java.awt.event.ActionEvent evt) 
+                {
+                    setExtendedState(JFrame.NORMAL);
+                    setVisible(true);
+                }
+            });
+            
+            hideItem.addActionListener(new java.awt.event.ActionListener() 
+            {
+                public void actionPerformed(java.awt.event.ActionEvent evt) 
+                {
+                    setVisible(false);
+                }
+            });
+            
+            exitItem.addActionListener(new java.awt.event.ActionListener() 
+            {
+                public void actionPerformed(java.awt.event.ActionEvent evt) 
+                {
+                    salir(false);
+                }
+            });
+            
+            tray.add(trayIcon);
+            
+        }
+        catch (Exception e)
+        {
+        }
+    }
+    
+    
+
+    public abstract class MenuListener
+    {
+        public abstract void menuSelection(String option);
+    }
+
+}
+
+
diff --git a/servers/server/src/art/servers/gui/components/PanelClock.java b/servers/server/src/art/servers/gui/components/PanelClock.java
new file mode 100644
index 0000000..3218748
--- /dev/null
+++ b/servers/server/src/art/servers/gui/components/PanelClock.java
@@ -0,0 +1,72 @@
+package art.servers.gui.components;
+
+import art.library.gui.flat.FlatLabel;
+import art.library.utils.resources.Resources;
+import art.servers.Shared;
+import java.awt.BorderLayout;
+import java.awt.Dimension;
+import java.text.SimpleDateFormat;
+import javax.swing.SwingConstants;
+
+
+public class PanelClock extends PanelGeneric
+{
+    private FlatLabel message = null;
+    private FlatLabel clock = null;
+    
+    public PanelClock()
+    {
+        this.setLayout(new BorderLayout());
+        message = new FlatLabel();
+        clock = new FlatLabel();
+        clock.setPreferredSize(new Dimension(224, 25));
+        clock.getLook().horizontalAlignment = SwingConstants.RIGHT;
+        message.getLook().horizontalAlignment = SwingConstants.LEFT;
+        message.setIcon(Resources.getResourceURL("data/art.library.server/icons/16x16/group2.png"));
+        clock.setIcon(Resources.getResourceURL("data/art.library.server/icons/16x16/schedule2.png"));
+        clock.revalidate();
+        message.revalidate();
+        this.add(message, BorderLayout.CENTER);
+        this.add(clock, BorderLayout.EAST);
+    }
+    
+    
+
+    public void reload()
+    {
+        SimpleDateFormat formato1 = new SimpleDateFormat("EEEE, d MMMM yyyy HH:mm:ss", Shared.configuration.getLocale());
+        String text = formato1.format(System.currentTimeMillis());
+        clock.setText(text);
+        clock.setPreferredSize(new Dimension(clock.getStringWidth() + 8, 21));
+    }
+    
+    
+    
+    public void timer()
+    {
+        reload();
+    }
+    
+    
+    
+    public void message(String text)
+    {
+        if (text != null)
+        {
+            if (text.length()> 0)
+            {
+                this.message.setText(text);
+            }
+            else
+            {
+                this.message.setText(text);
+            }
+        }
+        else
+        {
+            this.message.setText("");
+        }
+    }
+    
+    
+}
diff --git a/servers/server/src/art/servers/gui/components/PanelGeneric.java b/servers/server/src/art/servers/gui/components/PanelGeneric.java
new file mode 100644
index 0000000..aea620d
--- /dev/null
+++ b/servers/server/src/art/servers/gui/components/PanelGeneric.java
@@ -0,0 +1,30 @@
+package art.servers.gui.components;
+
+import art.library.gui.flat.FlatPanel;
+import art.servers.gui.ArticPanel;
+import art.servers.gui.ArticWindow;
+import java.awt.Component;
+
+
+public class PanelGeneric extends FlatPanel
+{
+    
+    public void reload() {}
+    public void timer() {}
+    public void selection() {}
+    public void deselection() {}
+    
+    
+    
+    public ArticWindow getWindow(Component component)
+    {
+        if ((component instanceof ArticPanel) == true)
+        {
+            return ((ArticPanel)component).getWindow();
+        }
+
+        return getWindow(component.getParent());
+    }
+        
+    
+}
diff --git a/servers/server/src/art/servers/gui/components/PanelProcess.java b/servers/server/src/art/servers/gui/components/PanelProcess.java
new file mode 100644
index 0000000..a001b4e
--- /dev/null
+++ b/servers/server/src/art/servers/gui/components/PanelProcess.java
@@ -0,0 +1,123 @@
+package art.servers.gui.components;
+
+import art.library.gui.flat.FlatPanel;
+import art.library.gui.flat.FlatSplitPane;
+import art.library.gui.flat.FlatWindow;
+import art.library.model.devices.application.ApplicationStatus;
+import art.servers.Shared;
+import java.awt.BorderLayout;
+import java.awt.GridLayout;
+import java.awt.event.ComponentAdapter;
+import java.awt.event.ComponentEvent;
+import javax.swing.JSplitPane;
+
+
+public class PanelProcess extends PanelGeneric
+{
+    private FlatWindow window = null;
+    private FlatSplitPane flatSplitPane1 = null;
+    private PanelProcess_Information panelSystem_Information = null;
+    private PanelProcess_Chart panelSystem_CPU = null;
+    private PanelProcess_Chart panelSystem_Memory = null;
+    private PanelProcess_Chart panelProcess_CPU = null;
+    private PanelProcess_Chart panelProcess_Memory = null;
+
+    
+    public PanelProcess(FlatWindow window) 
+    {
+        this.window = window;
+        initialise();
+    }
+    
+    
+    public void selection() 
+    {
+    }
+    
+    
+    public void deselection() 
+    {
+    }
+    
+    
+    public void timer()
+    {
+        ApplicationStatus status = Shared.controllerProcessInformation.getApplicationStatus();
+                
+        if (panelSystem_Information != null) panelSystem_Information.reload(status);
+        if (panelSystem_CPU != null) panelSystem_CPU.reload(status.system.systemCpuLoad * 100);
+        if (panelSystem_Memory != null) 
+        {
+            long totalPhysicalMemory = status.system.totalPhysicalMemorySize / 1048576;
+            long usedMemory = (status.system.totalPhysicalMemorySize - status.system.freePhysicalMemorySize) / 1048576;
+            panelSystem_Memory.reload(totalPhysicalMemory, usedMemory);
+        }
+        if (panelProcess_CPU != null) panelProcess_CPU.reload(status.system.processCpuLoad * 100);
+        if (panelProcess_Memory != null) 
+        {
+            long totalPhysicalMemory = status.memory.heapMemoryUsage_max / 1048576;
+            long usedMemory = status.memory.usedMemory / 1048576L;
+            panelProcess_Memory.reload(totalPhysicalMemory, usedMemory);
+        }
+    }
+
+
+    
+    private void initialise()
+    {
+        flatSplitPane1 = new FlatSplitPane();
+        {
+            FlatPanel panel1 = new FlatPanel();
+            {
+                panelSystem_Information = new PanelProcess_Information();
+                panel1.setLayout(new BorderLayout());
+                panel1.add(panelSystem_Information, BorderLayout.CENTER);
+            }
+            
+            FlatPanel panel2 = new FlatPanel();
+            {
+                panelSystem_CPU = new PanelProcess_Chart("System %CPU", "System %CPU");
+                panelSystem_Memory = new PanelProcess_Chart("System, used memory (MB)", "System, used memory (MB)");
+                panelProcess_CPU = new PanelProcess_Chart("Process %CPU", "Process %CPU");
+                panelProcess_Memory = new PanelProcess_Chart("Process, used memory (MB)", "Process, used memory (MB)");
+                panel2.setLayout(new GridLayout(2, 2));
+                panel2.add(panelSystem_CPU);
+                panel2.add(panelSystem_Memory);
+                panel2.add(panelProcess_CPU);
+                panel2.add(panelProcess_Memory);
+            }
+            
+            flatSplitPane1.setOrientation(JSplitPane.HORIZONTAL_SPLIT);
+            flatSplitPane1.setLeftComponent(panel1);
+            flatSplitPane1.setRightComponent(panel2);
+            flatSplitPane1.setOneTouchExpandable();
+            flatSplitPane1.changeDividerSize(16);
+
+            flatSplitPane1.addComponentListener(new ComponentAdapter() 
+            {
+                public void componentResized(ComponentEvent e) 
+                {
+                    flatSplitPane1.setDividerLocation(480);
+                }       
+            });                
+            
+        }
+        
+        this.setLayout(new BorderLayout());
+        this.add(flatSplitPane1, BorderLayout.CENTER);
+        
+    }
+    
+    
+    
+    
+    
+    
+ 
+    
+    
+    
+    
+}
+
+
diff --git a/servers/server/src/art/servers/gui/components/PanelProcess_Chart.java b/servers/server/src/art/servers/gui/components/PanelProcess_Chart.java
new file mode 100644
index 0000000..c68246d
--- /dev/null
+++ b/servers/server/src/art/servers/gui/components/PanelProcess_Chart.java
@@ -0,0 +1,140 @@
+package art.servers.gui.components;
+
+import art.library.gui.flat.FlatButton;
+import art.library.gui.flat.FlatPanel;
+import art.servers.Shared;
+import java.awt.BorderLayout;
+import java.awt.Color;
+import java.awt.Font;
+import org.jfree.chart.ChartFactory;
+import org.jfree.chart.ChartPanel;
+import org.jfree.chart.JFreeChart;
+import org.jfree.chart.axis.CategoryAxis;
+import org.jfree.chart.axis.CategoryLabelPositions;
+import org.jfree.chart.axis.NumberAxis;
+import org.jfree.chart.plot.CategoryPlot;
+import org.jfree.chart.plot.PlotOrientation;
+import org.jfree.chart.renderer.category.BarRenderer;
+import org.jfree.data.Range;
+import org.jfree.data.category.CategoryDataset;
+import org.jfree.data.category.DefaultCategoryDataset;
+
+
+public class PanelProcess_Chart extends FlatPanel
+{
+    private JFreeChart chart1;
+    private DefaultCategoryDataset dataset1;
+    private String title = null;
+    private String description = null;
+    private Color background = new FlatButton().getLook().colorForegroundSelected;
+    
+    public PanelProcess_Chart(String title, String description)
+    {
+        this.title = title;
+        this.description = description;
+        initialise();
+    }
+    
+            
+    
+    public void reload(double value)
+    {
+        try
+        {
+            dataset1.clear();
+            dataset1.addValue(value, "", "");
+            CategoryPlot plot = chart1.getCategoryPlot();
+            BarRenderer renderer = (BarRenderer)plot.getRenderer();
+            renderer.setSeriesPaint(0, background);  
+        }
+        catch (Exception e)
+        {
+        }
+    }
+
+    
+
+    
+    public void reload(double total, double value)
+    {
+        try
+        {
+            CategoryPlot plot = chart1.getCategoryPlot();
+            NumberAxis rangeAxis = (NumberAxis) plot.getRangeAxis();                 
+            rangeAxis.setRange(new Range(0,total));
+
+            dataset1.clear();
+            dataset1.addValue(value, "", "");
+            BarRenderer renderer = (BarRenderer)plot.getRenderer();
+            renderer.setSeriesPaint(0, background);  
+        }
+        catch (Exception e)
+        {
+        }
+    }
+
+
+    
+    
+    
+    
+    private void initialise()
+    {
+        dataset1 = new DefaultCategoryDataset();
+        chart1 = createChart(dataset1, 0, 100);
+        ChartPanel chartPanel1 = new ChartPanel(chart1);
+        
+        this.setLayout(new java.awt.BorderLayout());
+        this.add(chartPanel1, BorderLayout.CENTER);
+    }
+    
+    
+    
+
+    private JFreeChart createChart (CategoryDataset dataset, double min, double max)
+    {
+        // create the chart...
+
+        final JFreeChart chart = ChartFactory.createBarChart
+        (
+            Shared.getMessage(title),    // chart title
+            "",                          // domain axis label
+            "",                          // range axis label
+            dataset,                     // data
+            PlotOrientation.VERTICAL,    // orientation
+            false,                       // include legend
+            false,                       // tooltips?
+            false                        // URLs?
+        );
+        
+        FlatButton reference = new FlatButton();
+        chart.setTitle(new org.jfree.chart.title.TextTitle(Shared.getMessage(description), reference.getFont().deriveFont(Font.PLAIN, 12)));
+        chart.setBackgroundPaint(this.getBackground());
+
+        // get a reference to the plot for further customisation...
+        CategoryPlot plot = chart.getCategoryPlot();
+        plot.setBackgroundPaint(Color.black);
+        plot.setForegroundAlpha(1.0f);
+        plot.setDomainGridlinePaint(reference.getLook().colorForegroundRollover);
+        plot.setRangeGridlinePaint(reference.getLook().colorForegroundRollover);
+        
+        // set the range axis to display integers only...
+        NumberAxis rangeAxis = (NumberAxis) plot.getRangeAxis();
+        rangeAxis.setStandardTickUnits(NumberAxis.createIntegerTickUnits());
+        rangeAxis.setRange(new Range(min,max));
+        rangeAxis.setVisible(true);
+
+        // disable bar outlines...
+        BarRenderer renderer = (BarRenderer)plot.getRenderer();
+        renderer.setDrawBarOutline(true);
+        renderer.setShadowVisible(false);
+
+        // set up gradient paints for series...
+        CategoryAxis domainAxis = plot.getDomainAxis();
+        domainAxis.setCategoryLabelPositions(CategoryLabelPositions.createUpRotationLabelPositions(Math.PI / 6.0));
+        domainAxis.setVisible(false);
+
+        return chart;
+
+    }    
+}
diff --git a/servers/server/src/art/servers/gui/components/PanelProcess_Information.java b/servers/server/src/art/servers/gui/components/PanelProcess_Information.java
new file mode 100644
index 0000000..e977052
--- /dev/null
+++ b/servers/server/src/art/servers/gui/components/PanelProcess_Information.java
@@ -0,0 +1,236 @@
+package art.servers.gui.components;
+
+import art.library.gui.flat.FlatPanel;
+import art.library.gui.flat.FlatTabbedPane;
+import art.library.gui.flat.FlatTableInput;
+import art.library.model.devices.application.ApplicationStatus;
+import art.library.utils.common.DateUtils;
+import art.servers.Shared;
+import java.awt.BorderLayout;
+import java.awt.Dimension;
+import java.text.DecimalFormat;
+import java.text.SimpleDateFormat;
+import javax.swing.SwingConstants;
+
+
+public class PanelProcess_Information extends FlatPanel
+{
+    private FlatTableInput table1 = null;
+    private FlatTableInput table2 = null;
+    private FlatTableInput table3 = null;
+    private FlatTableInput table4 = null;
+    
+    public PanelProcess_Information()
+    {
+        initialise();
+    }
+    
+    
+    
+
+
+    public void reload(ApplicationStatus status)
+    {
+        SimpleDateFormat formato1 = new SimpleDateFormat(Shared.getMessage("dd/MM/yyyy HH:mm:ss"));
+        DecimalFormat formato2 = new DecimalFormat("###,###.##");
+
+        table1.setValue(Shared.getMessage("Timestamp"), formato1.format(status.system.timestamp));
+        table1.setValue(Shared.getMessage("Name"), status.system.name);
+        table1.setValue(Shared.getMessage("Version"), status.system.version);
+        table1.setValue(Shared.getMessage("Architecture"), status.system.arch);
+        table1.setValue(Shared.getMessage("Available processors"), status.system.availableProcessors);
+        table1.setValue(Shared.getMessage("System cpu current"), String.format("%.1f", status.system.systemCpuLoad * 100));
+        table1.setValue(Shared.getMessage("System cpu average"), String.format("%.1f", status.system.systemLoadAverage));
+        table1.setValue(Shared.getMessage("Total physical memory size"), formato2.format(status.system.totalPhysicalMemorySize/1048576L));
+        table1.setValue(Shared.getMessage("Used physical memory size"), formato2.format((status.system.totalPhysicalMemorySize - status.system.freePhysicalMemorySize) / 1048576));
+        table1.setValue(Shared.getMessage("Free physical memory size"), formato2.format(status.system.freePhysicalMemorySize/1048576L));
+        table1.setValue(Shared.getMessage("Committed virtual memory size"), formato2.format(status.system.committedVirtualMemorySize/1048576L));
+        table1.setValue(Shared.getMessage("Total swap space size"), formato2.format(status.system.totalSwapSpaceSize/1048576L));
+        table1.setValue(Shared.getMessage("Free swap space size"), formato2.format(status.system.freeSwapSpaceSize/1048576L));
+
+        table2.setValue(Shared.getMessage("Timestamp"), formato1.format(status.runtime.timestamp));
+        table2.setValue(Shared.getMessage("Start time"), formato1.format(status.runtime.startTime));
+        table2.setValue(Shared.getMessage("Up time"), DateUtils.getTimeddHHMMSS(status.runtime.upTime));
+        table2.setValue(Shared.getMessage("Process cpu time"), DateUtils.getTimeddHHMMSS(status.system.processCpuTime/1000000L));
+        table2.setValue(Shared.getMessage("Process cpu current"), String.format("%.1f", status.system.processCpuLoad * 100));
+        table2.setValue(Shared.getMessage("Process cpu average"), String.format("%.1f", 100*(((double)status.system.processCpuTime/1000000)/(double)status.runtime.upTime)));
+        table2.setValue(Shared.getMessage("Java specification version"), status.runtime.javaVmSpecificationVersion);
+        table2.setValue(Shared.getMessage("Java runtime version"), status.runtime.javaRuntimeVersion);
+        table2.setValue(Shared.getMessage("Java class  version"), status.runtime.javaClassVersion);
+        table2.setValue(Shared.getMessage("Time zone"), status.runtime.userTimeZone);
+        table2.setValue(Shared.getMessage("Country"), status.runtime.userCountry);
+        table2.setValue(Shared.getMessage("Language"), status.runtime.userLanguage);
+        
+        table3.setValue(Shared.getMessage("Timestamp"), formato1.format(status.memory.timestamp));
+        table3.setValue(Shared.getMessage("Used memory"), formato2.format(status.memory.usedMemory/1048576L));
+        table3.setValue(Shared.getMessage("Heap memory usage init"), formato2.format(status.memory.heapMemoryUsage_init/1048576L));
+        table3.setValue(Shared.getMessage("Heap memory usage used"), formato2.format(status.memory.heapMemoryUsage_used/1048576L));
+        table3.setValue(Shared.getMessage("Heap memory usage commited"), formato2.format(status.memory.heapMemoryUsage_committed/1048576L));
+        table3.setValue(Shared.getMessage("Heap memory usage max"), formato2.format(status.memory.heapMemoryUsage_max/1048576L));
+        table3.setValue(Shared.getMessage("Non heap memory usage init"), formato2.format(status.memory.nonheapMemoryUsage_init/1048576L));
+        table3.setValue(Shared.getMessage("Non heap memory usage used"), formato2.format(status.memory.nonheapMemoryUsage_used/1048576L));
+        table3.setValue(Shared.getMessage("Non heap memory usage commited"), formato2.format(status.memory.nonheapMemoryUsage_committed/1048576L));
+        table3.setValue(Shared.getMessage("Non heap memory usage max"), formato2.format(status.memory.nonheapMemoryUsage_max/1048576L));
+        
+        table4.setValue(Shared.getMessage("Timestamp"), formato1.format(status.thread.timestamp));
+        table4.setValue(Shared.getMessage("Thread count"), formato2.format(status.thread.threadCount));
+        table4.setValue(Shared.getMessage("Peak thread count"), formato2.format(status.thread.peakThreadCount));
+        table4.setValue(Shared.getMessage("Total started thread count"), formato2.format(status.thread.totalStartedThreadCount));
+        table4.setValue(Shared.getMessage("Daemon thread count"), formato2.format(status.thread.daemonThreadCount));
+    }
+
+
+
+    
+    
+    private void initialise()
+    {
+        FlatPanel panel1 = new FlatPanel();
+        {
+        }
+        
+        
+            
+        FlatPanel panel2 = new FlatPanel();
+        {
+            FlatTabbedPane flatTabbedPane1 = new FlatTabbedPane();
+            {
+                FlatPanel panel2_1 = new FlatPanel();
+                {
+                    table1 = new FlatTableInput(250);
+                    {
+                        table1.addTextField(Shared.getMessage("Timestamp"), 22);
+                        table1.addTextField(Shared.getMessage("Name"), 22);
+                        table1.addTextField(Shared.getMessage("Version"), 22);
+                        table1.addTextField(Shared.getMessage("Architecture"), 22);
+                        table1.addTextField(Shared.getMessage("Available processors"), 22);
+                        table1.addTextField(Shared.getMessage("System cpu current"), 22);
+                        table1.addTextField(Shared.getMessage("System cpu average"), 22);
+                        table1.addTextField(Shared.getMessage("Total physical memory size"), 22);
+                        table1.addTextField(Shared.getMessage("Used physical memory size"), 22);
+                        table1.addTextField(Shared.getMessage("Free physical memory size"), 22);
+                        table1.addTextField(Shared.getMessage("Committed virtual memory size"), 22);
+                        table1.addTextField(Shared.getMessage("Total swap space size"), 22);
+                        table1.addTextField(Shared.getMessage("Free swap space size"), 22);
+                        
+                        table1.setMeasurementUnits(Shared.getMessage("System cpu current"), Shared.getMessage("%"), 100, SwingConstants.CENTER);
+                        table1.setMeasurementUnits(Shared.getMessage("System cpu average"), Shared.getMessage("%"), 100, SwingConstants.CENTER);
+                        table1.setMeasurementUnits(Shared.getMessage("Total physical memory size"), Shared.getMessage("MB"), 100, SwingConstants.CENTER);
+                        table1.setMeasurementUnits(Shared.getMessage("Used physical memory size"), Shared.getMessage("MB"), 100, SwingConstants.CENTER);
+                        table1.setMeasurementUnits(Shared.getMessage("Free physical memory size"), Shared.getMessage("MB"), 100, SwingConstants.CENTER);
+                        table1.setMeasurementUnits(Shared.getMessage("Committed virtual memory size"), Shared.getMessage("MB"), 100, SwingConstants.CENTER);
+                        table1.setMeasurementUnits(Shared.getMessage("Total swap space size"), Shared.getMessage("MB"), 100, SwingConstants.CENTER);
+                        table1.setMeasurementUnits(Shared.getMessage("Free swap space size"), Shared.getMessage("MB"), 100, SwingConstants.CENTER);
+
+
+                        table1.setEditable(false);
+                        table1.revalidate();
+                    }
+
+                    panel2_1.setLayout(new BorderLayout());
+                    panel2_1.setPreferredSize(new Dimension(0, table1.getDimensionHeight() + 1));
+                    panel2_1.add(table1.getScrollPane(), BorderLayout.CENTER);
+                    flatTabbedPane1.addTab(Shared.getMessage("System"), panel2_1);
+                }
+
+                FlatPanel panel2_2 = new FlatPanel();
+                {
+                    table2 = new FlatTableInput(250);
+                    {
+                        table2.addTextField(Shared.getMessage("Timestamp"), 22);
+                        table2.addTextField(Shared.getMessage("Start time"), 22);
+                        table2.addTextField(Shared.getMessage("Up time"), 22);
+                        table2.addTextField(Shared.getMessage("Process cpu time"), 22);
+                        table2.addTextField(Shared.getMessage("Process cpu current"), 22);
+                        table2.addTextField(Shared.getMessage("Process cpu average"), 22);
+                        table2.addTextField(Shared.getMessage("Java specification version"), 22);
+                        table2.addTextField(Shared.getMessage("Java runtime version"), 22);
+                        table2.addTextField(Shared.getMessage("Java class  version"), 22);
+                        table2.addTextField(Shared.getMessage("Time zone"), 22);
+                        table2.addTextField(Shared.getMessage("Country"), 22);
+                        table2.addTextField(Shared.getMessage("Language"), 22);
+                        
+                        table2.setMeasurementUnits(Shared.getMessage("Up time"), Shared.getMessage("d,HH:mm:ss"), 100, SwingConstants.CENTER);
+                        table2.setMeasurementUnits(Shared.getMessage("Process cpu time"), Shared.getMessage("d, HH:mm:ss"), 100, SwingConstants.CENTER);
+                        table2.setMeasurementUnits(Shared.getMessage("Process cpu current"), Shared.getMessage("%"), 100, SwingConstants.CENTER);
+                        table2.setMeasurementUnits(Shared.getMessage("Process cpu average"), Shared.getMessage("%"), 100, SwingConstants.CENTER);
+                        
+                        table2.setEditable(false);
+                        table2.revalidate();
+                    }
+
+                    panel2_2.setLayout(new BorderLayout());
+                    panel2_2.setPreferredSize(new Dimension(0, table2.getDimensionHeight() + 1));
+                    panel2_2.add(table2.getScrollPane(), BorderLayout.CENTER);
+                    flatTabbedPane1.addTab(Shared.getMessage("Process runtime"), panel2_2);
+                }
+
+                FlatPanel panel2_3 = new FlatPanel();
+                {
+                    table3 = new FlatTableInput(250);
+                    {
+                        table3.addTextField(Shared.getMessage("Timestamp"), 22);
+                        table3.addTextField(Shared.getMessage("Used memory"), 22);
+                        table3.addTextField(Shared.getMessage("Heap memory usage init"), 22);
+                        table3.addTextField(Shared.getMessage("Heap memory usage used"), 22);
+                        table3.addTextField(Shared.getMessage("Heap memory usage commited"), 22);
+                        table3.addTextField(Shared.getMessage("Heap memory usage max"), 22);
+                        table3.addTextField(Shared.getMessage("Non heap memory usage init"), 22);
+                        table3.addTextField(Shared.getMessage("Non heap memory usage used"), 22);
+                        table3.addTextField(Shared.getMessage("Non heap memory usage commited"), 22);
+                        table3.addTextField(Shared.getMessage("Non heap memory usage max"), 22);
+                        
+                        table3.setMeasurementUnits(Shared.getMessage("Heap memory usage init"), Shared.getMessage("MB"), 100, SwingConstants.CENTER);
+                        table3.setMeasurementUnits(Shared.getMessage("Heap memory usage used"), Shared.getMessage("MB"), 100, SwingConstants.CENTER);
+                        table3.setMeasurementUnits(Shared.getMessage("Heap memory usage commited"), Shared.getMessage("MB"), 100, SwingConstants.CENTER);
+                        table3.setMeasurementUnits(Shared.getMessage("Heap memory usage max"), Shared.getMessage("MB"), 100, SwingConstants.CENTER);
+                        table3.setMeasurementUnits(Shared.getMessage("Non heap memory usage init"), Shared.getMessage("MB"), 100, SwingConstants.CENTER);
+                        table3.setMeasurementUnits(Shared.getMessage("Non heap memory usage used"), Shared.getMessage("MB"), 100, SwingConstants.CENTER);
+                        table3.setMeasurementUnits(Shared.getMessage("Non heap memory usage commited"), Shared.getMessage("MB"), 100, SwingConstants.CENTER);
+                        table3.setMeasurementUnits(Shared.getMessage("Non heap memory usage max"), Shared.getMessage("MB"), 100, SwingConstants.CENTER);
+                                                
+                        table3.setEditable(false);
+                        table3.revalidate();
+                    }
+
+                    panel2_3.setLayout(new BorderLayout());
+                    panel2_3.setPreferredSize(new Dimension(0, table3.getDimensionHeight() + 1));
+                    panel2_3.add(table3.getScrollPane(), BorderLayout.CENTER);
+                    flatTabbedPane1.addTab(Shared.getMessage("Process memory"), panel2_3);
+                }
+                
+
+                FlatPanel panel2_4 = new FlatPanel();
+                {
+                    table4 = new FlatTableInput(250);
+                    {
+                        table4.addTextField(Shared.getMessage("Timestamp"), 22);
+                        table4.addTextField(Shared.getMessage("Total started thread count"), 22);
+                        table4.addTextField(Shared.getMessage("Thread count"), 22);
+                        table4.addTextField(Shared.getMessage("Peak thread count"), 22);
+                        table4.addTextField(Shared.getMessage("Daemon thread count"), 22);
+                        table4.setEditable(false);
+                        table4.revalidate();
+                    }
+
+                    panel2_4.setLayout(new BorderLayout());
+                    panel2_4.setPreferredSize(new Dimension(0, table4.getDimensionHeight() + 1));
+                    panel2_4.add(table4.getScrollPane(), BorderLayout.CENTER);
+                    flatTabbedPane1.addTab(Shared.getMessage("Process threads"), panel2_4);
+                }
+                
+            }
+
+            panel2.setLayout(new BorderLayout());
+            panel2.setPreferredSize(new Dimension(0, table1.getDimensionHeight() + 1));
+            panel2.add(flatTabbedPane1, BorderLayout.CENTER);
+        }
+        
+        this.setLayout(new BorderLayout());
+        this.add(panel1, BorderLayout.NORTH);
+        this.add(panel2, BorderLayout.CENTER);
+    }
+    
+
+    
+}
diff --git a/servers/server/src/art/servers/gui/components/PanelTraces.java b/servers/server/src/art/servers/gui/components/PanelTraces.java
new file mode 100644
index 0000000..037063c
--- /dev/null
+++ b/servers/server/src/art/servers/gui/components/PanelTraces.java
@@ -0,0 +1,531 @@
+package art.servers.gui.components;
+
+import art.library.gui.FlatGUI;
+import art.library.gui.flat.FlatButton;
+import art.library.gui.flat.FlatScrollPane;
+import art.library.gui.flat.FlatToggleButton;
+import art.library.gui.flat.FlatWindow;
+import art.library.model.transactions.traces.Note;
+import art.library.model.transactions.traces.Trace;
+import art.library.utils.resources.Resources;
+import art.library.utils.synchro.Mutex;
+import art.servers.Shared;
+import java.awt.BorderLayout;
+import java.awt.Color;
+import java.awt.Dimension;
+import java.awt.Insets;
+import java.awt.Toolkit;
+import java.awt.datatransfer.Clipboard;
+import java.awt.datatransfer.StringSelection;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Timer;
+import java.util.TimerTask;
+import javax.swing.JScrollPane;
+import javax.swing.JTextPane;
+import javax.swing.text.DefaultStyledDocument;
+import javax.swing.text.Element;
+import javax.swing.text.Style;
+import javax.swing.text.StyleConstants;
+import javax.swing.text.StyleContext;
+
+
+public class PanelTraces extends PanelGeneric
+{
+    public static final int SCREEN_RESET = 0;
+    public static final int SCREEN_BRIGHT = 1;
+    public static final int SCREEN_DIM = 2;
+    public static final int SCREEN_BLINK = 3;
+    public static final int SCREEN_UNDERLINE = 4;
+    public static final int SCREEN_REVERSE = 7;
+    public static final int SCREEN_HIDDEN = 8;
+
+    public static final int SCREEN_BLACK = 0;
+    public static final int SCREEN_RED = 1;
+    public static final int SCREEN_GREEN = 2;
+    public static final int SCREEN_YELLOW = 3;
+    public static final int SCREEN_BLUE = 4;
+    public static final int SCREEN_MAGENTA = 5;
+    public static final int SCREEN_CYAN = 6;
+    public static final int SCREEN_WHITE = 7;
+
+
+    protected Color myblack = new Color(35,35,35);
+    protected FlatScrollPane scrollPane = new FlatScrollPane();
+    protected DefaultStyledDocument document = new DefaultStyledDocument();
+    protected JTextPane textpane = new JTextPane(document);
+    protected StyleContext context = new StyleContext();    
+    protected Style style = context.getStyle(StyleContext.DEFAULT_STYLE);
+    protected boolean autoscroll = true;
+    protected int totalLines = 1000;
+    protected FlatToggleButton buttonView = null;
+    protected FlatButton buttonCopy = null;
+    protected FlatButton buttonTrash = null;
+    protected FlatToggleButton buttonAutoscroll = null;
+    protected FlatWindow window = null;
+    protected List<Object> traces = new ArrayList<Object>();
+    protected Mutex mutex = new Mutex();
+    
+
+    public PanelTraces(FlatWindow window, int totalLines)
+    {
+        this.window = window;
+        this.totalLines = totalLines;
+        this.
+        initialise();
+    }
+
+
+    public PanelTraces(FlatWindow window)
+    {
+        this.window = window;
+        initialise();
+    }
+    
+
+
+    public void selection()
+    {
+        try
+        {
+            window.addButtonSeparator();
+            window.addButtonMenu(buttonView);
+            window.addButtonMenu(buttonCopy);
+            window.addButtonMenu(buttonTrash);
+            window.addButtonMenu(buttonAutoscroll);
+        }
+        catch (Exception e)
+        {
+        }
+    }
+    
+    
+    
+    
+    public void deselection()
+    {
+        try
+        {
+            window.removeComponentMenu(buttonView);
+            window.removeComponentMenu(buttonCopy);
+            window.removeComponentMenu(buttonTrash);
+            window.removeComponentMenu(buttonAutoscroll);
+        }
+        catch (Exception e)
+        {
+        }
+    }
+
+    
+    
+    protected void initialise()
+    {
+        buttonView = new FlatToggleButton(Shared.getMessage("&View"));
+        buttonView.setIcon(Resources.getResourceURL("data/art.library.server/icons/24x24/list.png"));
+        buttonView.setPreferredSize(new Dimension(buttonView.getStringWidth(), 0));
+        buttonView.setPreferredSize(new Dimension(buttonView.getStringWidth(), 0));
+        buttonView.addActionListener(new java.awt.event.ActionListener()
+        {
+            public void actionPerformed(java.awt.event.ActionEvent evt)
+            {
+                view(buttonView.isSelected()); 
+            }
+        });
+        
+        
+        buttonCopy = new FlatButton(Shared.getMessage("&Copy"));
+        buttonCopy.setIcon(Resources.getResourceURL("data/art.library.server/icons/24x24/copy.png"));
+        buttonCopy.setPreferredSize(new Dimension(buttonCopy.getStringWidth(), 0));
+        buttonCopy.setPreferredSize(new Dimension(buttonCopy.getStringWidth(), 0));
+        buttonCopy.addActionListener(new java.awt.event.ActionListener()
+        {
+            public void actionPerformed(java.awt.event.ActionEvent evt)
+            {
+                copyToClipboard(); 
+            }
+        });
+        
+        
+        buttonTrash = new FlatButton(Shared.getMessage("Clea&r"));
+        buttonTrash.setIcon(Resources.getResourceURL("data/art.library.server/icons/24x24/clear.png"));
+        buttonTrash.setPreferredSize(new Dimension(buttonTrash.getStringWidth(), 0));
+        buttonTrash.setPreferredSize(new Dimension(buttonTrash.getStringWidth(), 0));
+        buttonTrash.addActionListener(new java.awt.event.ActionListener()
+        {
+            public void actionPerformed(java.awt.event.ActionEvent evt)
+            {
+                clear();
+            }
+        });
+        
+        
+        buttonAutoscroll = new FlatToggleButton(Shared.getMessage("&Autoscroll"));
+        buttonAutoscroll.setSelected(true);
+        buttonAutoscroll.setIcon(Resources.getResourceURL("data/art.library.server/icons/24x24/escalator-down.png"));
+        buttonAutoscroll.setPreferredSize(new Dimension(buttonAutoscroll.getStringWidth(), 0));
+        buttonAutoscroll.addActionListener(new java.awt.event.ActionListener()
+        {
+            public void actionPerformed(java.awt.event.ActionEvent evt)
+            {
+                autoscroll(buttonAutoscroll.isSelected());
+            }
+        });
+        
+        
+                
+        document = new DefaultStyledDocument();
+        textpane = new JTextPane(document);
+        //textpane.setContentType("text/html;charset=UTF-8");
+        textpane.setEditable(false);
+        textpane.setEditable(false);
+        textpane.setBackground(myblack);
+        textpane.setMargin(new Insets(10,10,10,10));
+        StyleConstants.setSpaceAbove(style, 10);
+        StyleConstants.setSpaceBelow(style, 10);
+        StyleConstants.setFontSize(style, 12);
+        StyleConstants.setFontFamily(style, "Monospaced");
+        StyleConstants.setForeground(style, Color.white);
+        StyleConstants.setBackground(style, myblack);
+
+        
+        scrollPane.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
+        scrollPane.getViewport().setBackground(Color.black);
+        scrollPane.getViewport().add(textpane);
+        this.getLook().background = FlatGUI.lookDesign.getColor("button.color.rollover.background");
+        this.setLayout(new BorderLayout());
+        this.add(scrollPane, BorderLayout.CENTER);
+        scrollPane.setVisible(false);
+        
+        TimerTask timerTask = new TimerTask()
+        {
+            public void run() 
+            {
+                reload();
+            }
+        }; 
+     
+        Timer timer = new Timer();
+        timer.scheduleAtFixedRate(timerTask, 0, 1000);         
+    }
+    
+    
+    public void addTrace(Object object)
+    {
+        mutex.lockWrite();
+        {
+            traces.add(object);
+        }
+        mutex.releaseWrite();
+    }
+    
+
+    
+    public void reload()
+    {
+        try
+        {
+            List<Object> localtraces = new ArrayList<Object>();
+            
+            mutex.lockWrite();
+            {
+                localtraces.addAll(this.traces);
+                this.traces.clear();
+            }
+            mutex.releaseWrite();
+            
+            
+            SimpleDateFormat formato1 = new SimpleDateFormat(Shared.getMessage("dd/MM/yyyy HH:mm:ss.SSS"));
+            
+            for(Object object : localtraces)
+            {
+                String result = "";
+
+                if (object instanceof Trace)
+                {   
+                    Trace trace = (Trace)object;
+                    result = result + color(SCREEN_RESET, SCREEN_WHITE, SCREEN_BLACK);
+                    result = result + formato1.format(trace.timestamp) + "\n";
+
+                    switch (trace.type)
+                    {
+                        case Trace.TRACE_NONE: result = result = result + color(SCREEN_RESET, SCREEN_WHITE, SCREEN_BLACK); break;
+                        case Trace.TRACE_INFORMATION:  result = result = result + color(SCREEN_RESET, SCREEN_CYAN, SCREEN_BLACK); break;
+                        case Trace.TRACE_WARNING: result = result + color(SCREEN_RESET, SCREEN_YELLOW, SCREEN_BLACK); break;
+                        case Trace.TRACE_ERROR: result = result + color(SCREEN_RESET, SCREEN_RED, SCREEN_BLACK); break;
+                        case Trace.TRACE_CORRECT: result = result + color(SCREEN_RESET, SCREEN_RED, SCREEN_BLACK); break;
+                    }
+                    result = result + "{\n";
+                    if (trace.sourceComputer != null) result = result + "   " + Shared.getMessage("Source") + " : " + trace.sourceComputer + "\n";
+                    if (trace.username != null) result = result + "   " + Shared.getMessage("Username") + " : " + trace.username + "\n";
+                    if (trace.profile != null) result = result + "   " + Shared.getMessage("Profile") + " : " + trace.profile + "\n";
+                    if (trace.service != null) result = result + "   " + Shared.getMessage("Service") + " : " + trace.service + "\n";
+                    if (trace.action != null) result = result + "   " + Shared.getMessage("Action") + " : " + trace.action + "\n";
+                    if (trace.resource != null) result = result + "   " + Shared.getMessage("Resource") + " : " + trace.resource + "\n";
+                    if (trace.result != null) result = result + "   " + Shared.getMessage("Result") + " : " + trace.result + "\n";
+                    if (trace.stack != null) result = result + "   " + Shared.getMessage("Stack") + " : " + trace.stack + "\n";
+                    result = result + "}\n";
+                    newLine(result);
+                }
+                else if (object instanceof Note)
+                {
+                    Note note = (Note)object;
+                    result = result + color(SCREEN_RESET, SCREEN_WHITE, SCREEN_BLACK);
+                    result = result + formato1.format(note.timestamp) + " : ";
+                    
+                    switch (note.type)
+                    {
+                        case Trace.TRACE_NONE: result = result = result + color(SCREEN_RESET, SCREEN_WHITE, SCREEN_BLACK); break;
+                        case Trace.TRACE_INFORMATION:  result = result = result + color(SCREEN_RESET, SCREEN_CYAN, SCREEN_BLACK); break;
+                        case Trace.TRACE_WARNING: result = result + color(SCREEN_RESET, SCREEN_YELLOW, SCREEN_BLACK); break;
+                        case Trace.TRACE_ERROR: result = result + color(SCREEN_RESET, SCREEN_RED, SCREEN_BLACK); break;
+                        case Trace.TRACE_CORRECT: result = result + color(SCREEN_RESET, SCREEN_GREEN, SCREEN_BLACK); break;
+                    }
+
+                    result = result + note.message;
+                    newLine(result);
+                    
+                }
+                else
+                {
+                    result = result + color(SCREEN_RESET, SCREEN_WHITE, SCREEN_BLACK);
+                    result = result + formato1.format(System.currentTimeMillis()) + " : ";
+                    result = result + color(SCREEN_RESET, SCREEN_CYAN, SCREEN_BLACK);
+                    result = result + object.toString().trim();
+                    newLine(result);
+                }
+            }
+        }
+        catch (Exception e)
+        {
+        }
+    }
+    
+    
+    
+        
+    
+    
+    
+    public void view(boolean value)
+    {
+        scrollPane.setVisible(value);
+    }    
+    
+
+    
+    
+    public void autoscroll(boolean value)
+    {
+        this.autoscroll = value;
+    }    
+    
+
+    
+    
+    public void copyToClipboard()
+    {
+        try
+        {
+            Clipboard clpbrd = Toolkit.getDefaultToolkit ().getSystemClipboard ();
+            clpbrd.setContents (new StringSelection (textpane.getDocument().getText(0, textpane.getDocument().getLength())), null);
+        }
+        catch (Exception e)
+        {
+        }
+    }
+    
+
+    public void clear()
+    {
+        try
+        {
+            document.remove(0,document.getLength());
+        }
+        catch (Exception e)
+        {
+        }
+    }    
+    
+    
+    public void newLine(String text)
+    {
+       try
+       {
+          List<Message> lmessage = getMessages(text);
+          
+          for (Message message : lmessage)
+          {
+              if (message.foreground != null) StyleConstants.setForeground(style, message.foreground);
+              if (message.background != null) StyleConstants.setBackground(style, message.background);
+              document.insertString(document.getLength(), message.text, style);
+          }
+          
+
+          document.insertString(document.getLength(), "\n", style);
+          
+          if (autoscroll == true)
+          {
+              textpane.setCaretPosition(textpane.getDocument().getLength());
+          }
+          
+          if (totalLines > 0)
+          {
+             Element root = textpane.getDocument().getDefaultRootElement();
+             while (root.getElementCount() > totalLines)
+             {
+                 Element first = root.getElement(0);
+                 textpane.getDocument().remove(first.getStartOffset(), first.getEndOffset());
+             }
+          }
+       }
+       catch (Exception e)
+       {
+       }
+    }        
+    
+    
+    
+
+    protected List getMessages(String text)
+    {
+        byte[] data = text.getBytes();
+        List<Message> lmessage = new ArrayList<Message>();
+        
+        int position = 0;
+        while (position >= 0) position = nextMessage(data, position, lmessage);
+        
+        return lmessage;
+    }        
+
+
+    
+    
+    protected int nextMessage(byte[] data, int position, List<Message> lmessage)
+    {
+        for (int i=0; i<data.length; i++)
+        {
+            int position1 = getCharacter(data, position, (byte)27);
+            int position2 = getCharacter(data, position1 + 10, (byte)27);
+            if (position2 == -1) position2 = data.length;
+                    
+            
+            if (position1 == -1)
+            {
+                byte[] aux1 = new byte[0];
+                Message message = new Message(new String(aux1), new String(data));
+                lmessage.add(message);
+                return -1;
+            }
+            
+
+            byte[] aux1 = new byte[10];
+            byte[] aux2 = new byte[position2-position1-10];
+            System.arraycopy(data, position1, aux1, 0, aux1.length);
+            System.arraycopy(data, position1+10, aux2, 0, aux2.length);
+            Message message = new Message(new String(aux1), new String(aux2));
+            lmessage.add(message);
+            
+            if (position2 == data.length) return -1;
+            
+            return position2;
+        }
+        
+        return -1;
+    }    
+    
+    
+    
+    protected int getCharacter(byte[] data, int position, byte character)
+    {
+        if (position < 0) return -1;
+            
+        for (int i=position; i<data.length; i++)
+        {
+            if (data[i] == character)
+            {
+                return i;
+            }
+        }
+        
+        return -1;
+    }
+
+    
+    
+
+    // 	
+    // %c[%d;%d;%dm   --> ESC[attributes;foreground;brackground
+    //
+    // ESC : 27
+    //
+    // attributes
+    //    SCREEN_RESET		0 
+    //    SCREEN_BRIGHT 	1
+    //    SCREEN_DIM		2
+    //    SCREEN_BLINK		3
+    //    SCREEN_UNDERLINE 	4
+    //    SCREEN_REVERSE	7
+    //    SCREEN_HIDDEN		8    
+    //
+    // colors
+    //    SCREEN_BLACK 		0
+    //    SCREEN_RED	    1
+    //    SCREEN_GREEN		2
+    //    SCREEN_YELLOW		3
+    //    SCREEN_BLUE		4
+    //    SCREEN_MAGENTA	5
+    //    SCREEN_CYAN	    6
+    //    SCREEN_WHITE		7
+        
+    
+    protected class Message
+    {
+        public String text;
+        public Color foreground = null;
+        public Color background = null;
+        
+        public Message(String control, String text)
+        {
+            this.text = text;
+            
+            if (control.length() == 10)
+            {
+                foreground = color(Integer.parseInt(control.substring(4,6)) - 30);
+                background = color(Integer.parseInt(control.substring(4,6)) - 40);
+            }
+        }
+        
+        
+        protected Color color(int color)
+        {
+            switch (color)
+            {
+                case 0 : return myblack;
+                case 1 : return Color.red;
+                case 2 : return Color.green;
+                case 3 : return Color.yellow;
+                case 4 : return Color.blue;
+                case 5 : return Color.magenta;
+                case 6 : return Color.cyan;
+                case 7 : return Color.white;
+            }
+            
+            return myblack;
+        }
+    }
+    
+    
+    
+
+
+    protected static String color (int attributes, int foreground, int background)
+    {
+       return "\033[" + attributes + ";" + (foreground + 30) + ";" + (background + 40) + "m";
+    }    
+    
+
+
+    
+    
+}
diff --git a/servers/server/src/art/servers/gui/components/PanelTracesHistorical.java b/servers/server/src/art/servers/gui/components/PanelTracesHistorical.java
new file mode 100644
index 0000000..4cf4577
--- /dev/null
+++ b/servers/server/src/art/servers/gui/components/PanelTracesHistorical.java
@@ -0,0 +1,231 @@
+package art.servers.gui.components;
+
+import art.library.gui.flat.FlatButton;
+import art.library.gui.flat.FlatDatePicker;
+import art.library.gui.flat.FlatLabel;
+import art.library.gui.flat.FlatPanel;
+import art.library.gui.flat.FlatTextField;
+import art.library.gui.flat.FlatWindow;
+import art.library.model.transactions.traces.Trace;
+import art.servers.Shared;
+import static art.servers.gui.components.PanelTraces.color;
+import java.awt.BorderLayout;
+import java.awt.Dimension;
+import java.awt.GridLayout;
+import java.awt.Insets;
+import java.awt.Point;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.text.SimpleDateFormat;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.List;
+import javax.swing.SwingConstants;
+
+
+public class PanelTracesHistorical extends PanelTraces
+{
+    private FlatDatePicker datePicker1 = null;
+    private FlatDatePicker datePicker2 = null;
+    private FlatButton button1 = null;
+    private FlatTextField textfield1 = null;
+    private int totalTraces = 100;
+
+    
+    public PanelTracesHistorical(FlatWindow window)
+    {
+        super(window, 0);
+        this.initialisePanelTracesHistorical();
+    }
+
+
+    
+    protected void initialisePanelTracesHistorical()
+    {
+        Calendar calendar = Calendar.getInstance();
+        calendar.setTimeInMillis(System.currentTimeMillis());
+        calendar.set(Calendar.HOUR_OF_DAY, 0);
+        calendar.set(Calendar.MINUTE, 0);
+        calendar.set(Calendar.SECOND, 0);
+        calendar.set(Calendar.MILLISECOND, 0);
+        datePicker1 = new FlatDatePicker(FlatDatePicker.TYPE_PICKER_DAY, SwingConstants.LEFT, true, false);
+        datePicker1.setLocale(Shared.configuration.getLocale());
+        datePicker1.setTimestamp(calendar.getTimeInMillis());
+
+        calendar.add(Calendar.DATE, 1);
+        datePicker2 = new FlatDatePicker(FlatDatePicker.TYPE_PICKER_DAY, SwingConstants.LEFT, true, false);
+        datePicker2.setLocale(Shared.configuration.getLocale());
+        datePicker2.setTimestamp(calendar.getTimeInMillis());
+        
+        FlatPanel panel1 = new FlatPanel();
+        {
+            FlatPanel panel1_1 = new FlatPanel();
+            {
+                FlatPanel panel1_1_1 = new FlatPanel();
+                {
+                    panel1_1_1.setRaisedBorder(0, 0, 0, 1);
+                    panel1_1_1.setLayout(new BorderLayout());
+                    panel1_1_1.add(datePicker1, BorderLayout.CENTER);
+                }
+
+                FlatPanel panel1_1_2 = new FlatPanel();
+                {
+                    panel1_1_2.setRaisedBorder(0, 1, 0, 1);
+                    panel1_1_2.setLayout(new BorderLayout());
+                    panel1_1_2.add(datePicker2, BorderLayout.CENTER);
+                }
+                
+                FlatPanel panel1_1_3 = new FlatPanel();
+                {
+                    
+                    FlatPanel panel1_1_3_1 = new FlatPanel();
+                    {
+                        FlatLabel label1 = new FlatLabel("Limit");
+                        textfield1 = new FlatTextField();
+                        textfield1.setText("" + totalTraces);
+                        textfield1.setNumeric(true, 1, 1000);
+                        panel1_1_3_1.setLayout(new GridLayout(1, 2));
+                        panel1_1_3_1.add(label1);
+                        panel1_1_3_1.add(textfield1);
+                    }
+                    
+                    panel1_1_3.setLayout(new BorderLayout());
+                    panel1_1_3.setPanelMargins(new Insets(4, 4, 4, 4));
+                    panel1_1_3.setRaisedBorder(0, 1, 0, 0);
+                    panel1_1_3.add(panel1_1_3_1, BorderLayout.CENTER);
+                }
+                
+                panel1_1.setLayout(new GridLayout(1, 3));
+                panel1_1.add(panel1_1_1);
+                panel1_1.add(panel1_1_2);
+                panel1_1.add(panel1_1_3);
+                panel1_1.setRaisedBorder(0,0,1,0);
+            }
+            
+            FlatPanel panel1_2 = new FlatPanel();
+            {
+                button1 = new FlatButton(Shared.getMessage("Execute"));
+                button1.getLook().horizontalAlignment = SwingConstants.CENTER;
+                panel1_2.setPreferredSize(new Dimension(44,44));
+                panel1_2.setLayout(new BorderLayout());
+                panel1_2.add(button1, BorderLayout.CENTER);
+                panel1_2.setRaisedBorder(1,0,1,0);
+                panel1_2.setPanelMargins(new Insets(4, 4, 4, 4));
+            }
+            
+            
+            panel1.setPreferredSize(new Dimension(0,80));
+            panel1.setLayout(new BorderLayout());
+            panel1.add(panel1_1, BorderLayout.CENTER);
+            panel1.add(panel1_2, BorderLayout.SOUTH);
+            button1.addActionListener(new ActionListener() 
+            {
+                public void actionPerformed(ActionEvent e) 
+                {
+                    listTraces();
+                }
+            });
+        }
+        
+        
+        this.add(panel1, BorderLayout.NORTH);
+    }
+    
+    
+    
+    
+    public void addTrace(Object object)
+    {
+        mutex.lockWrite();
+        {
+            traces.add(object);
+        }
+        mutex.releaseWrite();
+    }
+    
+
+    
+    public void reload()
+    {
+    }
+    
+    
+    
+    public void view(boolean value)
+    {
+        scrollPane.setVisible(value);
+    }    
+
+    
+
+    
+    private void listTraces()
+    {
+        clear();
+        
+        SimpleDateFormat formato1 = new SimpleDateFormat(Shared.getMessage("dd/MM/yyyy HH:mm:ss.SSS"));
+        
+        try
+        {
+            totalTraces = Integer.parseInt(textfield1.getText());
+        }
+        catch (Exception e)
+        {
+            totalTraces = 100;
+            textfield1.setText("" + totalTraces );
+        }
+        
+               
+        
+        
+        try
+        {
+            long from = datePicker1.getCalendar().getTimeInMillis();
+            long to = datePicker2.getCalendar().getTimeInMillis();
+            
+            List<Trace> ltrace =  Shared.model.getTraces(Shared.getLanguage(), from, to, Shared.getApplicationName(), totalTraces);
+            
+            for (Trace trace : ltrace) 
+            {
+                String result = "";
+                result = result + color(SCREEN_RESET, SCREEN_WHITE, SCREEN_BLACK);
+                result = result + formato1.format(trace.timestamp) + "\n";
+
+                switch (trace.type)
+                {
+                    case Trace.TRACE_NONE: result = result = result + color(SCREEN_RESET, SCREEN_WHITE, SCREEN_BLACK); break;
+                    case Trace.TRACE_INFORMATION:  result = result = result + color(SCREEN_RESET, SCREEN_CYAN, SCREEN_BLACK); break;
+                    case Trace.TRACE_WARNING: result = result + color(SCREEN_RESET, SCREEN_YELLOW, SCREEN_BLACK); break;
+                    case Trace.TRACE_ERROR: result = result + color(SCREEN_RESET, SCREEN_RED, SCREEN_BLACK); break;
+                    case Trace.TRACE_CORRECT: result = result + color(SCREEN_RESET, SCREEN_GREEN, SCREEN_BLACK); break;
+                }
+                result = result + "{\n";
+                if (trace.sourceComputer != null) result = result + "   " + Shared.getMessage("Source") + " : " + trace.sourceComputer + "\n";
+                if (trace.username != null) result = result + "   " + Shared.getMessage("Username") + " : " + trace.username + "\n";
+                if (trace.profile != null) result = result + "   " + Shared.getMessage("Profile") + " : " + trace.profile + "\n";
+                if (trace.service != null) result = result + "   " + Shared.getMessage("Service") + " : " + trace.service + "\n";
+                if (trace.action != null) result = result + "   " + Shared.getMessage("Action") + " : " + trace.action + "\n";
+                if (trace.resource != null) result = result + "   " + Shared.getMessage("Resource") + " : " + trace.resource + "\n";
+                if (trace.result != null) result = result + "   " + Shared.getMessage("Result") + " : " + trace.result + "\n";
+                if (trace.stack != null) result = result + "   " + Shared.getMessage("Stack") + " : " + trace.stack + "\n";
+                result = result + "}\n";
+                newLine(result);
+                addTrace(trace);
+            }
+        }
+        catch (Exception e)
+        {
+        }
+        
+        scrollPane.getViewport().setViewPosition(new Point(0,0));
+        buttonView.setSelected(true);
+        scrollPane.setVisible(true);
+                    
+        
+    }
+    
+        
+
+    
+    
+}
diff --git a/servers/server/src/art/servers/types/HttpAuthentication.java b/servers/server/src/art/servers/types/HttpAuthentication.java
new file mode 100644
index 0000000..37c29af
--- /dev/null
+++ b/servers/server/src/art/servers/types/HttpAuthentication.java
@@ -0,0 +1,190 @@
+package art.servers.types;
+
+import art.library.interop.serialization.Serialization;
+import art.library.model.devices.Device;
+import art.library.model.devices.user.User;
+import art.library.utils.licence.Licence;
+import art.servers.Shared;
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.annotation.JsonPropertyOrder;
+import java.net.URLEncoder;
+import java.nio.charset.StandardCharsets;
+
+
+
+@JsonPropertyOrder
+({
+    "Username",
+    "Password",
+    "Address",
+    "Creation",
+    "Expiration",
+    "Inactivity",
+    "Profile web"
+})
+      
+
+
+public class HttpAuthentication
+{
+    
+    @JsonProperty("Username")
+    public String username = null;
+    
+    @JsonProperty("Password")
+    public String password = null;
+    
+    @JsonProperty("Address")
+    public String address = null;
+    
+    @JsonProperty("Creation")
+    public long tokenCreationTimestamp = 0;
+
+    @JsonProperty("Expiration")
+    public long tokenExpirationTimestamp = 0;
+    
+
+    /**
+     * Inactivity to expire in seconds
+     */
+    @JsonProperty("Inactivity")
+    public long inactivity = 300;
+
+
+    /**
+     * For WEB access
+     */
+    
+    public static final byte PROFILE_NONE = 0;
+    public static final byte PROFILE_DOWNLOAD = 1;
+    public static final byte PROFILE_READ = 2;
+    public static final byte PROFILE_WRITE = 3;
+    public static final byte PROFILE_ADMIN = 4;
+    
+    @JsonProperty("Profile web")
+    public int profileWebServer = HttpAuthentication.PROFILE_NONE;
+    
+    /**
+     * JsonProperty("Result code")<br>
+     * Code representing the result status of login request<br>
+     * Possible values are:<br>
+     * 0 : Ok<br>
+     * 1 : Wrong user/password<br>
+     * 2 : First access, password must be changed<br>
+     * 3 : Username blocked<br>
+     * 4 : Ip address blocked
+     */
+    @JsonProperty("Result code")
+    public int resultCode = 0;
+    
+    @JsonProperty("Result message")
+    public String resultMessage = null;
+    
+    @JsonProperty("User profile")
+    public String profile = null;
+
+    @JsonIgnore
+    public User user = null;
+    
+    @JsonIgnore
+    public long lastRequestTimestamp = 0;
+
+    @JsonIgnore
+    public String userAgent = null;
+    
+    
+
+    public HttpAuthentication()
+    {
+    }
+
+    
+    @JsonIgnore
+    public HttpAuthentication(String username, String password, String address) throws Exception
+    {
+        this.username = username;
+        this.password = password;
+        this.address = address;
+        this.tokenCreationTimestamp = System.currentTimeMillis();
+        this.tokenExpirationTimestamp = this.tokenCreationTimestamp;
+    }
+
+    
+    @JsonIgnore
+    public HttpAuthentication(String username, String password, String address, int resultCode, String resultMessage) throws Exception
+    {
+        this.username = username;
+        this.password = password;
+        this.address = address;
+        this.resultCode = resultCode;
+        this.resultMessage = resultMessage;
+        this.tokenCreationTimestamp = System.currentTimeMillis();
+        this.tokenExpirationTimestamp = this.tokenCreationTimestamp;
+    }
+
+    
+    @JsonIgnore
+    public HttpAuthentication(String username, String password, String address, String profile) throws Exception
+    {
+        this.username = username;
+        this.password = password;
+        this.address = address;
+        this.profile = profile;
+        this.tokenCreationTimestamp = System.currentTimeMillis();
+        this.tokenExpirationTimestamp = this.tokenCreationTimestamp;
+    }
+    
+    
+    public HttpAuthentication(String username, String password, String address, byte profile) throws Exception
+    {
+        this.username = username;
+        this.password = password;
+        this.address = address;
+        this.profileWebServer = profile;
+        this.tokenExpirationTimestamp = this.tokenCreationTimestamp;
+        this.tokenExpirationTimestamp = System.currentTimeMillis();
+    }    
+    
+    
+    
+    @JsonIgnore
+    public boolean isTokenValid(String remoteAddress) throws Exception
+    {
+        if (remoteAddress.equalsIgnoreCase(address) == false) return false;
+        if (tokenExpirationTimestamp == tokenCreationTimestamp) return true;
+        //TODO, update lastRequestTimestamp
+        //if ((lastRequestTimestamp > 0) && (System.currentTimeMillis() - lastRequestTimestamp) > (inactivity * 1000L)) return false;
+        return (tokenExpirationTimestamp >= System.currentTimeMillis());
+    }
+    
+
+    
+    @JsonIgnore 
+    public HttpToken getHttpToken() throws Exception
+    {
+        HttpToken httptoken = new HttpToken();
+        if ((this.resultCode == Shared.RESULT_OK) || (this.resultCode == Shared.ERROR_FIRST_ACCESS))
+        {
+            httptoken.token = URLEncoder.encode(Licence.encrypt(Serialization.toString(this)), StandardCharsets.UTF_8.toString()); 
+        }
+
+        httptoken.profile = this.profile;
+        httptoken.resultCode = this.resultCode;
+        httptoken.resultMessage = this.resultMessage;
+        return httptoken;
+    }
+
+
+    
+    
+    
+
+    
+    @JsonIgnore 
+    public void updateExpirationTimestamp()
+    {
+        // TODO
+    }
+    
+}
diff --git a/servers/server/src/art/servers/types/HttpStatus.java b/servers/server/src/art/servers/types/HttpStatus.java
new file mode 100644
index 0000000..b481e3c
--- /dev/null
+++ b/servers/server/src/art/servers/types/HttpStatus.java
@@ -0,0 +1,6 @@
+package art.servers.types;
+
+public class HttpStatus
+{
+    
+}
diff --git a/servers/server/src/art/servers/types/HttpToken.java b/servers/server/src/art/servers/types/HttpToken.java
new file mode 100644
index 0000000..f052598
--- /dev/null
+++ b/servers/server/src/art/servers/types/HttpToken.java
@@ -0,0 +1,49 @@
+package art.servers.types;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.annotation.JsonPropertyOrder;
+
+
+@JsonPropertyOrder
+({
+    "Token",
+    "Profile",
+    "Result code",
+    "Result message"
+})
+      
+
+
+public class HttpToken
+{
+    @JsonProperty("Token")
+    public String token = null;
+
+
+    /**
+     * JsonProperty("Profile")
+     */
+    @JsonProperty("Profile")
+    public String profile = null;
+
+
+    /**
+     * JsonProperty("Result code")<br>
+     * Code representing the result status of login request<br>
+     * Possible values are:<br>
+     * 0 : Ok<br>
+     * 1 : Wrong user/password<br>
+     * 2 : First access, password must be changed<br>
+     * 3 : Username blocked<br>
+     * 4 : Ip address blocked
+     */
+    @JsonProperty("Result code")
+    public int resultCode = 0;
+
+
+    /**
+     * JsonProperty("Result message")
+     */
+    @JsonProperty("Result message")
+    public String resultMessage = null;
+}
diff --git a/servers/server/src/art/servers/types/HttpTokenException.java b/servers/server/src/art/servers/types/HttpTokenException.java
new file mode 100644
index 0000000..8bd02d3
--- /dev/null
+++ b/servers/server/src/art/servers/types/HttpTokenException.java
@@ -0,0 +1,6 @@
+package art.servers.types;
+
+public class HttpTokenException extends Exception
+{
+    
+}
diff --git a/servers/server/src/art/servers/types/IPv4.java b/servers/server/src/art/servers/types/IPv4.java
new file mode 100644
index 0000000..5d72989
--- /dev/null
+++ b/servers/server/src/art/servers/types/IPv4.java
@@ -0,0 +1,47 @@
+package art.servers.types;
+
+public class IPv4 
+{
+    public static long toLong(int mask) throws Exception
+    {
+        long result = 0xFFFFFFFFL;
+        
+        for(int i=0; i<(32-mask); i++)
+        {
+            result = result ^ ((long)1 << i);
+        }
+        
+        return result;
+    }
+    
+    
+    public static long toLong(String ipAddress) throws Exception
+    {
+        if (ipAddress == null || ipAddress.isEmpty()) throw new Exception();
+        String[] octets = ipAddress.split(java.util.regex.Pattern.quote("."));
+        if (octets.length != 4) throw new Exception();
+        long ip = 0;
+        for (int i = 3; i >= 0; i--) 
+        {
+            long octet = Long.parseLong(octets[3 - i]);
+            if (octet > 255 || octet < 0) throw new Exception();
+            ip |= octet << (i * 8);
+        }
+        return ip;
+    }
+
+    
+
+    public static String toString (long ip) throws Exception 
+    {
+        if (ip > 4294967295l || ip < 0) throw new Exception();
+        StringBuilder ipAddress = new StringBuilder();
+        for (int i = 3; i >= 0; i--) 
+        {
+            int shift = i * 8;
+            ipAddress.append((ip & (0xff << shift)) >> shift);
+            if (i > 0)  ipAddress.append(".");
+        }
+        return ipAddress.toString();
+    }
+}
diff --git a/servers/server/src/server.version.properties b/servers/server/src/server.version.properties
new file mode 100644
index 0000000..e6fa5ef
--- /dev/null
+++ b/servers/server/src/server.version.properties
@@ -0,0 +1,7 @@
+#Thu, 24 Oct 2024 11:50:41 +0200
+
+date=24/10/2024
+major=1
+minor=0
+revision=0
+build=89

--
Gitblit v1.10.0