=== modified file 'src/com/goldencode/p2j/ui/ClientExports.java'
--- src/com/goldencode/p2j/ui/ClientExports.java	2019-07-01 17:33:15 +0000
+++ src/com/goldencode/p2j/ui/ClientExports.java	2019-09-13 09:26:59 +0000
@@ -316,7 +316,7 @@
  * design policies are required to maximize the performance of the remote
  * UI as well as to keep the remote UI implementation as simple as possible.
  */
-public interface ClientExports
+public interface ClientExports extends ObjectStorage
 {
    /**
     * Rings a bell on the terminal.

=== added file 'src/com/goldencode/p2j/ui/ClientStorageProxy.java'
--- src/com/goldencode/p2j/ui/ClientStorageProxy.java	1970-01-01 00:00:00 +0000
+++ src/com/goldencode/p2j/ui/ClientStorageProxy.java	2019-09-13 09:26:59 +0000
@@ -0,0 +1,200 @@
+/*
+** Module   : ClientStorageProxy.java
+** Abstract : Implements the proxy for the client object storage that can be used on the server.
+**
+** Copyright (c) 2019, Golden Code Development Corporation.
+**
+** -#- -I- --Date-- ---------------------------------Description---------------------------------
+** 001 SBI 20190911 Created initial version.
+*/
+
+/*
+** This program is free software: you can redistribute it and/or modify
+** it under the terms of the GNU Affero General Public License as
+** published by the Free Software Foundation, either version 3 of the
+** License, or (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+** GNU Affero General Public License for more details.
+**
+** You may find a copy of the GNU Affero GPL version 3 at the following
+** location: https://www.gnu.org/licenses/agpl-3.0.en.html
+** 
+** Additional terms under GNU Affero GPL version 3 section 7:
+** 
+**   Under Section 7 of the GNU Affero GPL version 3, the following additional
+**   terms apply to the works covered under the License.  These additional terms
+**   are non-permissive additional terms allowed under Section 7 of the GNU
+**   Affero GPL version 3 and may not be removed by you.
+** 
+**   0. Attribution Requirement.
+** 
+**     You must preserve all legal notices or author attributions in the covered
+**     work or Appropriate Legal Notices displayed by works containing the covered
+**     work.  You may not remove from the covered work any author or developer
+**     credit already included within the covered work.
+** 
+**   1. No License To Use Trademarks.
+** 
+**     This license does not grant any license or rights to use the trademarks
+**     Golden Code, FWD, any Golden Code or FWD logo, or any other trademarks
+**     of Golden Code Development Corporation. You are not authorized to use the
+**     name Golden Code, FWD, or the names of any author or contributor, for
+**     publicity purposes without written authorization.
+** 
+**   2. No Misrepresentation of Affiliation.
+** 
+**     You may not represent yourself as Golden Code Development Corporation or FWD.
+** 
+**     You may not represent yourself for publicity purposes as associated with
+**     Golden Code Development Corporation, FWD, or any author or contributor to
+**     the covered work, without written authorization.
+** 
+**   3. No Misrepresentation of Source or Origin.
+** 
+**     You may not represent the covered work as solely your work.  All modified
+**     versions of the covered work must be marked in a reasonable way to make it
+**     clear that the modified work is not originating from Golden Code Development
+**     Corporation or FWD.  All modified versions must contain the notices of
+**     attribution required in this license.
+*/
+
+package com.goldencode.p2j.ui;
+
+
+/**
+ * Represents the server side client storage proxy
+ */
+public class ClientStorageProxy implements ObjectStorage
+{
+   /** The client exported API */
+   private final ClientExports client;
+   
+   /**
+    * Creates a proxy object.
+    * 
+    * @param    client
+    *           The delegate that represents the client exported API.
+    */
+   public ClientStorageProxy(ClientExports client)
+   {
+      this.client = client;
+   }
+
+   /**
+    * Retrieves the number value of the given key from this storage.
+    * 
+    * @param    key
+    *           The given key
+    * 
+    * @return   The number value of the given key 
+    */
+   @Override
+   public Number getNumber(String key)
+   {
+      return client.getNumber(key);
+   }
+
+   /**
+    * Saves the number value of this key in this storage.
+    * 
+    * @param    key
+    *           The given key
+    * @param    value
+    *           The value of the given key
+    */
+   @Override
+   public void setNumber(String key, Number value)
+   {
+      client.setNumber(key, value);
+   }
+
+   /**
+    * Retrieves the boolean value of the given key from this storage.
+    * 
+    * @param    key
+    *           The given key
+    * 
+    * @return   The boolean value of the given key
+    */
+   @Override
+   public Boolean getBoolean(String key)
+   {
+      return client.getBoolean(key);
+   }
+
+   /**
+    * Saves the boolean value of this key in this storage.
+    * 
+    * @param    key
+    *           The given key
+    * @param    value
+    *           The value of the given key
+    */
+   @Override
+   public void setBoolean(String key, Boolean value)
+   {
+      client.setBoolean(key, value);
+   }
+
+   /**
+    * Retrieves the string value of the given key from this storage.
+    * 
+    * @param    key
+    *           The given key
+    * 
+    * @return   The string value of the given key
+    */
+   @Override
+   public String getString(String key)
+   {
+      return client.getString(key);
+   }
+
+   /**
+    * Saves the string value of this key in this storage.
+    * 
+    * @param    key
+    *           The given key
+    * @param    value
+    *           The value of the given key
+    */
+   @Override
+   public void setString(String key, String value)
+   {
+      client.setString(key, value);
+   }
+
+   /**
+    * Retrieves the object value of the given key from this storage.
+    * 
+    * @param    key
+    *           The given key
+    * @param    clazz
+    *           The java class that represents this object
+    * 
+    * @return   The object value of the given key
+    */
+   @SuppressWarnings("rawtypes")
+   @Override
+   public Object getObject(String key, Class clazz)
+   {
+      return client.getObject(key, clazz);
+   }
+
+   /**
+    * Sets the object value of the given key for this storage.
+    * 
+    * @param    key
+    *           The given key
+    * @param    value
+    *           The object value
+    */
+   @Override
+   public void setObject(String key, Object value)
+   {
+      client.setObject(key, value);
+   }
+}

=== added file 'src/com/goldencode/p2j/ui/KeyValueStorage.java'
--- src/com/goldencode/p2j/ui/KeyValueStorage.java	1970-01-01 00:00:00 +0000
+++ src/com/goldencode/p2j/ui/KeyValueStorage.java	2019-09-13 09:26:59 +0000
@@ -0,0 +1,131 @@
+/*
+** Module   : KeyValueStorage.java
+** Abstract : Defines methods to store and retrieve key and value pairs.
+**
+** Copyright (c) 2019, Golden Code Development Corporation.
+**
+** -#- -I- --Date-- ---------------------------------Description---------------------------------
+** 001 SBI 20190911 Created initial version.
+*/
+
+/*
+** This program is free software: you can redistribute it and/or modify
+** it under the terms of the GNU Affero General Public License as
+** published by the Free Software Foundation, either version 3 of the
+** License, or (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+** GNU Affero General Public License for more details.
+**
+** You may find a copy of the GNU Affero GPL version 3 at the following
+** location: https://www.gnu.org/licenses/agpl-3.0.en.html
+** 
+** Additional terms under GNU Affero GPL version 3 section 7:
+** 
+**   Under Section 7 of the GNU Affero GPL version 3, the following additional
+**   terms apply to the works covered under the License.  These additional terms
+**   are non-permissive additional terms allowed under Section 7 of the GNU
+**   Affero GPL version 3 and may not be removed by you.
+** 
+**   0. Attribution Requirement.
+** 
+**     You must preserve all legal notices or author attributions in the covered
+**     work or Appropriate Legal Notices displayed by works containing the covered
+**     work.  You may not remove from the covered work any author or developer
+**     credit already included within the covered work.
+** 
+**   1. No License To Use Trademarks.
+** 
+**     This license does not grant any license or rights to use the trademarks
+**     Golden Code, FWD, any Golden Code or FWD logo, or any other trademarks
+**     of Golden Code Development Corporation. You are not authorized to use the
+**     name Golden Code, FWD, or the names of any author or contributor, for
+**     publicity purposes without written authorization.
+** 
+**   2. No Misrepresentation of Affiliation.
+** 
+**     You may not represent yourself as Golden Code Development Corporation or FWD.
+** 
+**     You may not represent yourself for publicity purposes as associated with
+**     Golden Code Development Corporation, FWD, or any author or contributor to
+**     the covered work, without written authorization.
+** 
+**   3. No Misrepresentation of Source or Origin.
+** 
+**     You may not represent the covered work as solely your work.  All modified
+**     versions of the covered work must be marked in a reasonable way to make it
+**     clear that the modified work is not originating from Golden Code Development
+**     Corporation or FWD.  All modified versions must contain the notices of
+**     attribution required in this license.
+*/
+
+package com.goldencode.p2j.ui;
+
+
+/**
+ * This interface defines access methods for a key value storage.
+ */
+public interface KeyValueStorage
+{
+   /**
+    * Retrieves the number value of the given key from this storage.
+    * 
+    * @param    key
+    *           The given key
+    * 
+    * @return   The number value of the given key 
+    */
+   Number getNumber(String key);
+   
+   /**
+    * Saves the number value of this key in this storage.
+    * 
+    * @param    key
+    *           The given key
+    * @param    value
+    *           The value of the given key
+    */
+   void setNumber(String key, Number value);
+   
+   /**
+    * Retrieves the boolean value of the given key from this storage.
+    * 
+    * @param    key
+    *           The given key
+    * 
+    * @return   The boolean value of the given key
+    */
+   Boolean getBoolean(String key);
+   
+   /**
+    * Saves the boolean value of this key in this storage.
+    * 
+    * @param    key
+    *           The given key
+    * @param    value
+    *           The value of the given key
+    */
+   void setBoolean(String key, Boolean value);
+   
+   /**
+    * Retrieves the string value of the given key from this storage.
+    * 
+    * @param    key
+    *           The given key
+    * 
+    * @return   The string value of the given key
+    */
+   String getString(String key);
+   
+   /**
+    * Saves the string value of this key in this storage.
+    * 
+    * @param    key
+    *           The given key
+    * @param    value
+    *           The value of the given key
+    */
+   void setString(String key, String value);
+}

=== added file 'src/com/goldencode/p2j/ui/KeyValueStorageAdapter.java'
--- src/com/goldencode/p2j/ui/KeyValueStorageAdapter.java	1970-01-01 00:00:00 +0000
+++ src/com/goldencode/p2j/ui/KeyValueStorageAdapter.java	2019-09-13 09:26:59 +0000
@@ -0,0 +1,246 @@
+/*
+** Module   : KeyValueStorageAdapter.java
+** Abstract : Implements the adapter for the KeyValueStorage backend and the client object storage.
+**
+** Copyright (c) 2019, Golden Code Development Corporation.
+**
+** -#- -I- --Date-- ---------------------------------Description---------------------------------
+** 001 SBI 20190911 Created initial version.
+*/
+
+/*
+** This program is free software: you can redistribute it and/or modify
+** it under the terms of the GNU Affero General Public License as
+** published by the Free Software Foundation, either version 3 of the
+** License, or (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+** GNU Affero General Public License for more details.
+**
+** You may find a copy of the GNU Affero GPL version 3 at the following
+** location: https://www.gnu.org/licenses/agpl-3.0.en.html
+** 
+** Additional terms under GNU Affero GPL version 3 section 7:
+** 
+**   Under Section 7 of the GNU Affero GPL version 3, the following additional
+**   terms apply to the works covered under the License.  These additional terms
+**   are non-permissive additional terms allowed under Section 7 of the GNU
+**   Affero GPL version 3 and may not be removed by you.
+** 
+**   0. Attribution Requirement.
+** 
+**     You must preserve all legal notices or author attributions in the covered
+**     work or Appropriate Legal Notices displayed by works containing the covered
+**     work.  You may not remove from the covered work any author or developer
+**     credit already included within the covered work.
+** 
+**   1. No License To Use Trademarks.
+** 
+**     This license does not grant any license or rights to use the trademarks
+**     Golden Code, FWD, any Golden Code or FWD logo, or any other trademarks
+**     of Golden Code Development Corporation. You are not authorized to use the
+**     name Golden Code, FWD, or the names of any author or contributor, for
+**     publicity purposes without written authorization.
+** 
+**   2. No Misrepresentation of Affiliation.
+** 
+**     You may not represent yourself as Golden Code Development Corporation or FWD.
+** 
+**     You may not represent yourself for publicity purposes as associated with
+**     Golden Code Development Corporation, FWD, or any author or contributor to
+**     the covered work, without written authorization.
+** 
+**   3. No Misrepresentation of Source or Origin.
+** 
+**     You may not represent the covered work as solely your work.  All modified
+**     versions of the covered work must be marked in a reasonable way to make it
+**     clear that the modified work is not originating from Golden Code Development
+**     Corporation or FWD.  All modified versions must contain the notices of
+**     attribution required in this license.
+*/
+
+package com.goldencode.p2j.ui;
+
+import java.io.*;
+
+import com.fasterxml.jackson.core.*;
+import com.fasterxml.jackson.databind.*;
+
+
+/**
+ * Implements a string key value user's storage backed by java user preferences file storage.
+ */
+public class KeyValueStorageAdapter implements ObjectStorage
+{
+   /** Object to JSON converter*/
+   private final ObjectMapper mapper;
+   
+   /** The backed key and value storage */
+   private KeyValueStorage backend;
+   
+   /**
+    * Creates this adapter.
+    */
+   public KeyValueStorageAdapter()
+   {
+      this.mapper = new ObjectMapper();
+   }
+   
+   /**
+    * Retrieves the number value of the given key from this storage.
+    * 
+    * @param    key
+    *           The given key
+    * 
+    * @return   The number value of the given key 
+    */
+   @Override
+   public Number getNumber(String key)
+   {
+      return this.backend.getNumber(key);
+   }
+
+   /**
+    * Saves the number value of this key in this storage.
+    * 
+    * @param    key
+    *           The given key
+    * @param    value
+    *           The value of the given key
+    */
+   @Override
+   public void setNumber(String key, Number value)
+   {
+      this.backend.setNumber(key, value);
+   }
+
+   /**
+    * Retrieves the boolean value of the given key from this storage.
+    * 
+    * @param    key
+    *           The given key
+    * 
+    * @return   The boolean value of the given key
+    */
+   @Override
+   public Boolean getBoolean(String key)
+   {
+      return this.backend.getBoolean(key);
+   }
+
+   /**
+    * Saves the boolean value of this key in this storage.
+    * 
+    * @param    key
+    *           The given key
+    * @param    value
+    *           The value of the given key
+    */
+   @Override
+   public void setBoolean(String key, Boolean value)
+   {
+      this.backend.setBoolean(key, value);
+   }
+
+   /**
+    * Retrieves the string value of the given key from this storage.
+    * 
+    * @param    key
+    *           The given key
+    * 
+    * @return   The string value of the given key
+    */
+   @Override
+   public String getString(String key)
+   {
+      return this.backend.getString(key);
+   }
+
+   @Override
+   public void setString(String key, String value)
+   {
+      this.backend.setString(key, value);
+   }
+
+   /**
+    * Sets the backend key and value storage.
+    * 
+    * @param    backend
+    *           The backend key and value storage
+    */
+   public void setBackend(KeyValueStorage backend)
+   {
+      this.backend = backend;
+   }
+   
+   /**
+    * Retrieves the object value of the given key from this storage.
+    * 
+    * @param    key
+    *           The given key
+    * @param    clazz
+    *           The java class that represents this object
+    * 
+    * @return   The object value of the given key
+    */
+   @SuppressWarnings("rawtypes")
+   @Override
+   public Object getObject(String key, Class clazz)
+   {
+      return parseJSON(key, clazz);
+   }
+
+   /**
+    * Sets the object value of the given key for this storage.
+    * 
+    * @param    key
+    *           The given key
+    * @param    value
+    *           The object value
+    */
+   public void setObject(String key, Object value)
+   {
+      try
+      {
+         String json = mapper.writeValueAsString(value);
+         backend.setString(key, json);
+      }
+      catch (JsonProcessingException e)
+      {
+         e.printStackTrace();
+      }
+
+   }
+
+   /**
+    * The template method to get the object from its json presentation retrieved from the storage
+    * by the given key.
+    * 
+    * @param    key
+    *           The given key
+    * @param    clazz
+    *           The java class that represents this object
+    * 
+    * @return   The object value of the given key
+    */
+   private <T> T parseJSON(String key, Class<T> clazz)
+   {
+      String content = backend.getString(key);
+      
+      if (content != null)
+      {
+         try
+         {
+            return mapper.readValue(content, clazz);
+         }
+         catch (IOException e)
+         {
+            e.printStackTrace();
+         }
+      }
+      
+      return null;
+   }
+}

=== modified file 'src/com/goldencode/p2j/ui/LogicalTerminal.java'
--- src/com/goldencode/p2j/ui/LogicalTerminal.java	2019-05-22 03:03:31 +0000
+++ src/com/goldencode/p2j/ui/LogicalTerminal.java	2019-09-13 09:27:00 +0000
@@ -1216,6 +1216,8 @@
    /** Helper to use the TM without any context local lookups. */
    private TransactionManager.TransactionHelper tm;
    
+   /** The client local storage proxy */
+   private ObjectStorage clientLocalStorage;
    /**
     * Constructor.
     */
@@ -1251,6 +1253,8 @@
          client = (ClientExports) RemoteObject.obtainLocalInstance(ClientExports.class, true);
       }
       
+      clientLocalStorage = new ClientStorageProxy(client);
+      
       ErrorManager.setSystemAlertBoxes(!client.isChui());
 
       // create the main window BUT DO NOT PUSH IT since a duplicate instance
@@ -7807,6 +7811,16 @@
    }
    
    /**
+    * Gets the client local storage.
+    * 
+    * @return   The client local storage
+    */
+   public static ObjectStorage getClientStorage()
+   {
+      return locate().clientLocalStorage;
+   }
+   
+   /**
     * Read the legacy text metrics for all the texts and each font defined in the font table, for
     * this user.
     *

=== added file 'src/com/goldencode/p2j/ui/ObjectStorage.java'
--- src/com/goldencode/p2j/ui/ObjectStorage.java	1970-01-01 00:00:00 +0000
+++ src/com/goldencode/p2j/ui/ObjectStorage.java	2019-09-13 09:27:00 +0000
@@ -0,0 +1,95 @@
+/*
+** Module   : ObjectStorage.java
+** Abstract : Extends a key and value storage to be used as a client object storage.
+**
+** Copyright (c) 2019, Golden Code Development Corporation.
+**
+** -#- -I- --Date-- ---------------------------------Description---------------------------------
+** 001 SBI 20190911 Created initial version.
+*/
+
+/*
+** This program is free software: you can redistribute it and/or modify
+** it under the terms of the GNU Affero General Public License as
+** published by the Free Software Foundation, either version 3 of the
+** License, or (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+** GNU Affero General Public License for more details.
+**
+** You may find a copy of the GNU Affero GPL version 3 at the following
+** location: https://www.gnu.org/licenses/agpl-3.0.en.html
+** 
+** Additional terms under GNU Affero GPL version 3 section 7:
+** 
+**   Under Section 7 of the GNU Affero GPL version 3, the following additional
+**   terms apply to the works covered under the License.  These additional terms
+**   are non-permissive additional terms allowed under Section 7 of the GNU
+**   Affero GPL version 3 and may not be removed by you.
+** 
+**   0. Attribution Requirement.
+** 
+**     You must preserve all legal notices or author attributions in the covered
+**     work or Appropriate Legal Notices displayed by works containing the covered
+**     work.  You may not remove from the covered work any author or developer
+**     credit already included within the covered work.
+** 
+**   1. No License To Use Trademarks.
+** 
+**     This license does not grant any license or rights to use the trademarks
+**     Golden Code, FWD, any Golden Code or FWD logo, or any other trademarks
+**     of Golden Code Development Corporation. You are not authorized to use the
+**     name Golden Code, FWD, or the names of any author or contributor, for
+**     publicity purposes without written authorization.
+** 
+**   2. No Misrepresentation of Affiliation.
+** 
+**     You may not represent yourself as Golden Code Development Corporation or FWD.
+** 
+**     You may not represent yourself for publicity purposes as associated with
+**     Golden Code Development Corporation, FWD, or any author or contributor to
+**     the covered work, without written authorization.
+** 
+**   3. No Misrepresentation of Source or Origin.
+** 
+**     You may not represent the covered work as solely your work.  All modified
+**     versions of the covered work must be marked in a reasonable way to make it
+**     clear that the modified work is not originating from Golden Code Development
+**     Corporation or FWD.  All modified versions must contain the notices of
+**     attribution required in this license.
+*/
+
+package com.goldencode.p2j.ui;
+
+
+/**
+ * Added methods to persist object values of keys. Extends this key value storage interface to be
+ * an object storage interface. 
+ */
+public interface ObjectStorage extends KeyValueStorage
+{
+   /**
+    * Retrieves the object value of the given key from this storage.
+    * 
+    * @param    key
+    *           The given key
+    * @param    clazz
+    *           The java class that represents this object
+    * 
+    * @return   The object value of the given key
+    */
+   @SuppressWarnings("rawtypes")
+   Object getObject(String key, Class clazz);
+   
+   /**
+    * Sets the object value of the given key for this storage.
+    * 
+    * @param    key
+    *           The given key
+    * @param    value
+    *           The object value
+    */
+   void setObject(String key, Object value);
+}

=== added file 'src/com/goldencode/p2j/ui/UserPreferences.java'
--- src/com/goldencode/p2j/ui/UserPreferences.java	1970-01-01 00:00:00 +0000
+++ src/com/goldencode/p2j/ui/UserPreferences.java	2019-09-13 09:27:00 +0000
@@ -0,0 +1,180 @@
+/*
+** Module   : UserPreferences.java
+** Abstract : Implements the key and value storage that can be used to persist users settings.
+**
+** Copyright (c) 2019, Golden Code Development Corporation.
+**
+** -#- -I- --Date-- ---------------------------------Description---------------------------------
+** 001 SBI 20190911 Created initial version.
+*/
+
+/*
+** This program is free software: you can redistribute it and/or modify
+** it under the terms of the GNU Affero General Public License as
+** published by the Free Software Foundation, either version 3 of the
+** License, or (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+** GNU Affero General Public License for more details.
+**
+** You may find a copy of the GNU Affero GPL version 3 at the following
+** location: https://www.gnu.org/licenses/agpl-3.0.en.html
+** 
+** Additional terms under GNU Affero GPL version 3 section 7:
+** 
+**   Under Section 7 of the GNU Affero GPL version 3, the following additional
+**   terms apply to the works covered under the License.  These additional terms
+**   are non-permissive additional terms allowed under Section 7 of the GNU
+**   Affero GPL version 3 and may not be removed by you.
+** 
+**   0. Attribution Requirement.
+** 
+**     You must preserve all legal notices or author attributions in the covered
+**     work or Appropriate Legal Notices displayed by works containing the covered
+**     work.  You may not remove from the covered work any author or developer
+**     credit already included within the covered work.
+** 
+**   1. No License To Use Trademarks.
+** 
+**     This license does not grant any license or rights to use the trademarks
+**     Golden Code, FWD, any Golden Code or FWD logo, or any other trademarks
+**     of Golden Code Development Corporation. You are not authorized to use the
+**     name Golden Code, FWD, or the names of any author or contributor, for
+**     publicity purposes without written authorization.
+** 
+**   2. No Misrepresentation of Affiliation.
+** 
+**     You may not represent yourself as Golden Code Development Corporation or FWD.
+** 
+**     You may not represent yourself for publicity purposes as associated with
+**     Golden Code Development Corporation, FWD, or any author or contributor to
+**     the covered work, without written authorization.
+** 
+**   3. No Misrepresentation of Source or Origin.
+** 
+**     You may not represent the covered work as solely your work.  All modified
+**     versions of the covered work must be marked in a reasonable way to make it
+**     clear that the modified work is not originating from Golden Code Development
+**     Corporation or FWD.  All modified versions must contain the notices of
+**     attribution required in this license.
+*/
+
+package com.goldencode.p2j.ui;
+
+import java.util.prefs.*;
+
+/**
+ * Implements the user's key and value storage based on java user preferences API.
+ */
+public class UserPreferences implements KeyValueStorage
+{
+   /** The back end key and value storage */
+   private final Preferences backend = Preferences.userRoot();
+   
+   /**
+    * Retrieves the value of the given key from this storage.
+    * 
+    * @param    key
+    *           The given key
+    * 
+    * @return   The number value of the given key 
+    */
+   @Override
+   public Number getNumber(String key)
+   {
+      String stringValue = backend.get(key,null);
+      
+      if (stringValue == null || "null".equals(stringValue))
+      {
+         return null;
+      }
+      
+      return Double.valueOf(stringValue);
+   }
+
+   /**
+    * Saves the number value of this key in this storage.
+    * 
+    * @param    key
+    *           The given key
+    * @param    value
+    *           The value of the given key
+    */
+   @Override
+   public void setNumber(String key, Number value)
+   {
+      backend.put(key, String.valueOf(value));
+   }
+
+   /**
+    * Retrieves the boolean value of the given key from this storage.
+    * 
+    * @param    key
+    *           The given key
+    * 
+    * @return   The boolean value of the given key
+    */
+   @Override
+   public Boolean getBoolean(String key)
+   {
+      String stringValue = backend.get(key,null);
+      
+      if (stringValue == null || "null".equals(stringValue))
+      {
+         return null;
+      }
+      
+      return Boolean.valueOf(stringValue);
+   }
+
+   /**
+    * Saves the boolean value of this key in this storage.
+    * 
+    * @param    key
+    *           The given key
+    * @param    value
+    *           The value of the given key
+    */
+   @Override
+   public void setBoolean(String key, Boolean value)
+   {
+      backend.put(key, String.valueOf(value));
+   }
+
+   /**
+    * Retrieves the string value of the given key from this storage.
+    * 
+    * @param    key
+    *           The given key
+    * 
+    * @return   The string value of the given key
+    */
+   @Override
+   public String getString(String key)
+   {
+      String stringValue = backend.get(key,null);
+      
+      if (stringValue == null || "null".equals(stringValue))
+      {
+         return null;
+      }
+      
+      return stringValue;
+   }
+
+   /**
+    * Saves the string value of this key in this storage.
+    * 
+    * @param    key
+    *           The given key
+    * @param    value
+    *           The value of the given key
+    */
+   @Override
+   public void setString(String key, String value)
+   {
+      backend.put(key, String.valueOf(value));
+   }
+}

=== modified file 'src/com/goldencode/p2j/ui/chui/ThinClient.java'
--- src/com/goldencode/p2j/ui/chui/ThinClient.java	2019-08-27 14:29:35 +0000
+++ src/com/goldencode/p2j/ui/chui/ThinClient.java	2019-09-13 09:27:00 +0000
@@ -23540,4 +23540,128 @@
          this.op = op;
       }
    }
+
+   /**
+    * Gets the client storage.
+    * 
+    * @return   The client storage
+    */
+   public ObjectStorage getClientStorage()
+   {
+      return getOutputManager().getDriver().getClientStorage();
+   }
+
+   /**
+    * Retrieves the object value of the given key from the client storage.
+    * 
+    * @param    key
+    *           The given key
+    * @param    clazz
+    *           The java class that represents this object
+    * 
+    * @return   The object value of the given key
+    */
+   @Override
+   public Object getObject(String key, Class clazz)
+   {
+      return getClientStorage().getObject(key, clazz);
+   }
+
+   /**
+    * Sets the object value of the given key for the client storage.
+    * 
+    * @param    key
+    *           The given key
+    * @param    value
+    *           The object value
+    */
+   @Override
+   public void setObject(String key, Object value)
+   {
+      getClientStorage().setObject(key, value);
+   }
+
+   /**
+    * Retrieves the number value of the given key from the client storage.
+    * 
+    * @param    key
+    *           The given key
+    * 
+    * @return   The number value of the given key 
+    */
+   @Override
+   public Number getNumber(String key)
+   {
+      return getClientStorage().getNumber(key);
+   }
+
+   /**
+    * Saves the number value of this key in the client storage.
+    * 
+    * @param    key
+    *           The given key
+    * @param    value
+    *           The value of the given key
+    */
+   @Override
+   public void setNumber(String key, Number value)
+   {
+      getClientStorage().setNumber(key, value);
+   }
+
+   /**
+    * Retrieves the boolean value of the given key from the client storage.
+    * 
+    * @param    key
+    *           The given key
+    * 
+    * @return   The boolean value of the given key
+    */
+   @Override
+   public Boolean getBoolean(String key)
+   {
+      return getClientStorage().getBoolean(key);
+   }
+
+   /**
+    * Saves the boolean value of this key in the client storage.
+    * 
+    * @param    key
+    *           The given key
+    * @param    value
+    *           The value of the given key
+    */
+   @Override
+   public void setBoolean(String key, Boolean value)
+   {
+      getClientStorage().setBoolean(key, value);
+   }
+
+   /**
+    * Retrieves the string value of the given key from the client storage.
+    * 
+    * @param    key
+    *           The given key
+    * 
+    * @return   The string value of the given key
+    */
+   @Override
+   public String getString(String key)
+   {
+      return getClientStorage().getString(key);
+   }
+
+   /**
+    * Saves the string value of this key in the client storage.
+    * 
+    * @param    key
+    *           The given key
+    * @param    value
+    *           The value of the given key
+    */
+   @Override
+   public void setString(String key, String value)
+   {
+      getClientStorage().setString(key, value);
+   }
 }

=== modified file 'src/com/goldencode/p2j/ui/client/driver/AbstractDriver.java'
--- src/com/goldencode/p2j/ui/client/driver/AbstractDriver.java	2017-04-01 23:33:34 +0000
+++ src/com/goldencode/p2j/ui/client/driver/AbstractDriver.java	2019-09-13 09:27:00 +0000
@@ -62,7 +62,9 @@
 
 package com.goldencode.p2j.ui.client.driver;
 
+
 import com.goldencode.p2j.main.*;
+import com.goldencode.p2j.ui.*;
 import com.goldencode.p2j.ui.client.*;
 
 /**
@@ -92,6 +94,9 @@
    /** Terminal type name. */
    private String term;
    
+   /** The driver local storage that is persistent over sessions */
+   private KeyValueStorageAdapter storage;
+   
    /**
     * Construct a new instance.
     *
@@ -110,6 +115,9 @@
       this.direct  = direct;
       this.isChui  = isChui;
       this.term    = term;
+      storage = new KeyValueStorageAdapter();
+      // set the default key value storage
+      storage.setBackend(new UserPreferences());
    }
 
    /**
@@ -222,6 +230,17 @@
    }
 
    /**
+    * Returns the client key and value storage.
+    * 
+    * @return   The client key and value storage
+    */
+   @Override
+   public KeyValueStorageAdapter getClientStorage()
+   {
+      return storage;
+   }
+
+   /**
     * Assigns the flag determining if the current driver is running in batch mode.
     * 
     * @param    batch

=== modified file 'src/com/goldencode/p2j/ui/client/driver/ScreenDriver.java'
--- src/com/goldencode/p2j/ui/client/driver/ScreenDriver.java	2019-03-10 09:48:21 +0000
+++ src/com/goldencode/p2j/ui/client/driver/ScreenDriver.java	2019-09-13 09:27:00 +0000
@@ -303,6 +303,13 @@
    public ChildProcessFactory getChildProcessFactory();
    
    /**
+    * Returns the client key and value storage.
+    * 
+    * @return   The client key and value storage
+    */
+   public ObjectStorage getClientStorage();
+   
+   /**
     * Driver initialization.
     */
    public void init();

=== modified file 'src/com/goldencode/p2j/ui/client/driver/web/WebClientMessageTypes.java'
--- src/com/goldencode/p2j/ui/client/driver/web/WebClientMessageTypes.java	2019-04-08 20:55:02 +0000
+++ src/com/goldencode/p2j/ui/client/driver/web/WebClientMessageTypes.java	2019-09-13 09:27:00 +0000
@@ -411,6 +411,12 @@
    /** Sets the background image for the virtual desktop. */
    public static final byte MSG_SET_DESKTOP_IMAGE = (byte) 0xF5;
 
+   /** Sets the value of the key for the client key and value storage. */
+   public static final byte MSG_SET_KEY_VALUE = (byte) 0xF6;
+
+   /** Gets the value of the key from the client key and value storage. */
+   public static final byte MSG_GET_KEY_VALUE = (byte) 0xF7;
+
    /** Wraps the large message from the client to the sequence of this partial type messages. */
    public static final byte MSG_PARTIAL = (byte) 0xFE;
    

=== modified file 'src/com/goldencode/p2j/ui/client/driver/web/res/p2j.socket.js'
--- src/com/goldencode/p2j/ui/client/driver/web/res/p2j.socket.js	2019-04-03 03:41:01 +0000
+++ src/com/goldencode/p2j/ui/client/driver/web/res/p2j.socket.js	2019-09-13 09:27:00 +0000
@@ -437,13 +437,13 @@
 
                   /** Destroy a driver-maintained widget. */
                   MSG_DESTROY_WIDGET : 0xB4,
-                
+                  
                   /** Place a driver-maintained widget. */
                   MSG_PLACE_WIDGET : 0xB5,
-               
+                  
                   /** Change the visibility for a driver-maintained widget. */
                   MSG_SET_WIDGET_VISIBILITY : 0xB6,
-               
+                  
                   /** Change the sensitivity for a driver-maintained widget. */
                   MSG_SET_WIDGET_SENSITIVITY : 0xB7,
    
@@ -462,6 +462,12 @@
                   /** Sets the background image for the virtual desktop. */
                   MSG_SET_DESKTOP_IMAGE : 0xF5,
                   
+                  /** Sets the value of the key for the client key and value storage. */
+                  MSG_SET_KEY_VALUE : 0xF6,
+
+                  /** Gets the value of the key from the client key and value storage. */
+                  MSG_GET_KEY_VALUE : 0xF7,
+
                   /** Wraps the large message from the client to the sequence of this partial type messages. */
                   MSG_PARTIAL : 0xFE,
                   
@@ -2905,6 +2911,58 @@
             
             send(msg);
             break;
+         case types.MSG_GET_KEY_VALUE:
+            var offset = 1;
+
+            var msgId = me.readInt32BinaryMessage(message, offset);
+            offset = offset + 4;
+            
+            var keyLength = me.readInt32BinaryMessage(message, offset);
+            offset = offset + 4;
+
+            var key  = me.readStringBinaryMessageByLength(message, offset, keyLength);
+            offset = offset + keyLength * 2;
+            
+            var value = p2j.restoreObject(key, true);
+            var value = String(value);
+            var valueLength = value.length;
+            
+            // create the response message
+            var msg = new Uint8Array(1 + 4 + 4 + valueLength * 2);
+            
+            offset = 0;
+            msg[offset] = types.MSG_GET_KEY_VALUE;
+            offset += 1;
+
+            writeInt32BinaryMessage(msg, offset, msgId);
+            offset += 4;
+            
+            writeInt32BinaryMessage(msg, offset, valueLength);
+            offset += 4;
+            
+            writeStringBinaryMessage(msg, offset, value);
+            
+            send(msg);
+            break;
+         case types.MSG_SET_KEY_VALUE:
+            var offset = 1;
+
+            var msgId = me.readInt32BinaryMessage(message, offset);
+            offset = offset + 4;
+            
+            var keyLength = me.readInt32BinaryMessage(message, offset);
+            offset = offset + 4;
+
+            var key  = me.readStringBinaryMessageByLength(message, offset, keyLength);
+            offset = offset + keyLength * 2;
+            
+            var valueLength = me.readInt32BinaryMessage(message, offset);
+            offset = offset + 4;
+
+            var value  = me.readStringBinaryMessageByLength(message, offset, valueLength);
+            
+            p2j.saveObject(key, value, true);
+            break;
          case types.MSG_GET_TEXT_WIDTHS:
             // text widths
 

=== modified file 'src/com/goldencode/p2j/ui/client/gui/driver/web/GuiWebDriver.java'
--- src/com/goldencode/p2j/ui/client/gui/driver/web/GuiWebDriver.java	2019-05-10 18:14:14 +0000
+++ src/com/goldencode/p2j/ui/client/gui/driver/web/GuiWebDriver.java	2019-09-13 09:27:00 +0000
@@ -455,6 +455,7 @@
                                          new GenericWebSocketCreator<WebClientProtocol>(websock),
                                          cpres,
                                          hdlrs);
+      getClientStorage().setBackend(new WebClientKeyValueStorage(websock));
    }
 
    /**

=== modified file 'src/com/goldencode/p2j/ui/client/gui/driver/web/GuiWebSocket.java'
--- src/com/goldencode/p2j/ui/client/gui/driver/web/GuiWebSocket.java	2019-04-03 03:41:01 +0000
+++ src/com/goldencode/p2j/ui/client/gui/driver/web/GuiWebSocket.java	2019-09-13 09:27:00 +0000
@@ -3156,6 +3156,22 @@
          
          handled = true;
       }
+      else if (message[offset] == MSG_GET_KEY_VALUE)
+      {
+         offset = offset + 1;
+
+         int msgId = readMessageInt32(message, offset);
+         offset = offset + 4;
+         
+         int valueLen = readMessageInt32(message, offset);
+         offset = offset + 4;
+         
+         String value = readMessageText(message, offset, offset + 2 * valueLen);
+         
+         receiveResult(msgId, value);
+         
+         handled = true;
+      }
       
       return handled;
    }
@@ -3545,6 +3561,90 @@
    }
 
    /**
+    * Gets the string value of the given key from the browser local storage.
+    * 
+    * @param    key
+    *           The given key
+    * 
+    * @return   
+    */
+   public String getStringValue(String key)
+   {
+      int len = 1;   // type
+      len = len + 4; // msg ID
+      len = len + 4; // key.length()
+      int keyLen = key.length();
+      len = len + keyLen * 2; // key
+      
+      int offset = 0;
+      byte[] message = new byte[len];
+      int msgId = nextMessageId();
+
+      message[offset++] = MSG_GET_KEY_VALUE;
+
+      writeMessageInt32(message, offset, msgId);
+      offset += 4;
+
+      writeMessageInt32(message, offset, keyLen);
+      offset += 4;
+
+      writeMessageText(message, offset, key);
+
+      sendBinaryMessage(message);
+      
+      Object res = waitForResult(msgId);
+      
+      if (res instanceof String)
+      {
+         return (String) res;
+      }
+      
+      return null;
+   }
+
+   /**
+    * Sets the value of the given key into the browser local storage.
+    * 
+    * @param    key
+    *           The given key
+    * @param    value
+    *           The key value to be stored into the browser local storage.
+    */
+   public void setStringValue(String key, String value)
+   {
+      int len = 1;                // type
+      len = len + 4;              // msg ID
+      len = len + 4;              // key.length()
+      int keyLen = key.length();
+      len = len + keyLen * 2;     // key
+      len = len + 4;              // value.length()
+      int valueLen = value.length();
+      len = len + valueLen * 2;   // value
+      
+      int offset = 0;
+      byte[] message = new byte[len];
+      int msgId = nextMessageId();
+
+      message[offset++] = MSG_SET_KEY_VALUE;
+
+      writeMessageInt32(message, offset, msgId);
+      offset += 4;
+
+      writeMessageInt32(message, offset, keyLen);
+      offset += 4;
+
+      writeMessageText(message, offset, key);
+      offset += keyLen * 2;
+      
+      writeMessageInt32(message, offset, valueLen);
+      offset += 4;
+
+      writeMessageText(message, offset, value);
+
+      sendBinaryMessage(message);
+   }
+
+   /**
     * Get the widths of the specified texts, using the given fonts.
     *
     * @param    fonts

=== added file 'src/com/goldencode/p2j/ui/client/gui/driver/web/WebClientKeyValueStorage.java'
--- src/com/goldencode/p2j/ui/client/gui/driver/web/WebClientKeyValueStorage.java	1970-01-01 00:00:00 +0000
+++ src/com/goldencode/p2j/ui/client/gui/driver/web/WebClientKeyValueStorage.java	2019-09-13 09:27:00 +0000
@@ -0,0 +1,193 @@
+/*
+** Module   : WebClientKeyValueStorage.java
+** Abstract : Implements the web client key and value storage.
+**
+** Copyright (c) 2019, Golden Code Development Corporation.
+**
+** -#- -I- --Date-- ---------------------------------Description---------------------------------
+** 001 SBI 20190911 Created initial version.
+*/
+
+/*
+** This program is free software: you can redistribute it and/or modify
+** it under the terms of the GNU Affero General Public License as
+** published by the Free Software Foundation, either version 3 of the
+** License, or (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+** GNU Affero General Public License for more details.
+**
+** You may find a copy of the GNU Affero GPL version 3 at the following
+** location: https://www.gnu.org/licenses/agpl-3.0.en.html
+** 
+** Additional terms under GNU Affero GPL version 3 section 7:
+** 
+**   Under Section 7 of the GNU Affero GPL version 3, the following additional
+**   terms apply to the works covered under the License.  These additional terms
+**   are non-permissive additional terms allowed under Section 7 of the GNU
+**   Affero GPL version 3 and may not be removed by you.
+** 
+**   0. Attribution Requirement.
+** 
+**     You must preserve all legal notices or author attributions in the covered
+**     work or Appropriate Legal Notices displayed by works containing the covered
+**     work.  You may not remove from the covered work any author or developer
+**     credit already included within the covered work.
+** 
+**   1. No License To Use Trademarks.
+** 
+**     This license does not grant any license or rights to use the trademarks
+**     Golden Code, FWD, any Golden Code or FWD logo, or any other trademarks
+**     of Golden Code Development Corporation. You are not authorized to use the
+**     name Golden Code, FWD, or the names of any author or contributor, for
+**     publicity purposes without written authorization.
+** 
+**   2. No Misrepresentation of Affiliation.
+** 
+**     You may not represent yourself as Golden Code Development Corporation or FWD.
+** 
+**     You may not represent yourself for publicity purposes as associated with
+**     Golden Code Development Corporation, FWD, or any author or contributor to
+**     the covered work, without written authorization.
+** 
+**   3. No Misrepresentation of Source or Origin.
+** 
+**     You may not represent the covered work as solely your work.  All modified
+**     versions of the covered work must be marked in a reasonable way to make it
+**     clear that the modified work is not originating from Golden Code Development
+**     Corporation or FWD.  All modified versions must contain the notices of
+**     attribution required in this license.
+*/
+
+package com.goldencode.p2j.ui.client.gui.driver.web;
+
+import com.goldencode.p2j.ui.*;
+
+
+/**
+ * Represents the web client key and value storage.
+ */
+public class WebClientKeyValueStorage implements KeyValueStorage
+{
+   /** The web socket object that is responsible for the communication with the js client */
+   private final GuiWebSocket webSocket;
+   
+   
+   /**
+    * Creates the web client storage.
+    * 
+    * @param    webSocket
+    *           The web socket object
+    */
+   public WebClientKeyValueStorage(GuiWebSocket webSocket)
+   {
+      this.webSocket = webSocket;
+   }
+
+   /**
+    * Retrieves the number value of the given key from this storage.
+    * 
+    * @param    key
+    *           The given key
+    * 
+    * @return   The number value of the given key 
+    */
+   @Override
+   public Number getNumber(String key)
+   {
+      String stringValue = webSocket.getStringValue(key);
+      
+      if (stringValue == null || "null".equals(stringValue))
+      {
+         return null;
+      }
+      
+      return Double.valueOf(stringValue);
+   }
+
+   /**
+    * Saves the number value of this key in this storage.
+    * 
+    * @param    key
+    *           The given key
+    * @param    value
+    *           The value of the given key
+    */
+   @Override
+   public void setNumber(String key, Number value)
+   {
+      webSocket.setStringValue(key, String.valueOf(value));
+   }
+
+   /**
+    * Retrieves the boolean value of the given key from this storage.
+    * 
+    * @param    key
+    *           The given key
+    * 
+    * @return   The boolean value of the given key
+    */
+   @Override
+   public Boolean getBoolean(String key)
+   {
+      String stringValue = webSocket.getStringValue(key);
+      
+      if (stringValue == null || "null".equals(stringValue))
+      {
+         return null;
+      }
+      
+      return Boolean.valueOf(stringValue);
+   }
+
+   /**
+    * Saves the boolean value of this key in this storage.
+    * 
+    * @param    key
+    *           The given key
+    * @param    value
+    *           The value of the given key
+    */
+   @Override
+   public void setBoolean(String key, Boolean value)
+   {
+      webSocket.setStringValue(key, String.valueOf(value));
+   }
+
+   /**
+    * Retrieves the string value of the given key from this storage.
+    * 
+    * @param    key
+    *           The given key
+    * 
+    * @return   The string value of the given key
+    */
+   @Override
+   public String getString(String key)
+   {
+      String stringValue = webSocket.getStringValue(key);
+      
+      if (stringValue == null || "null".equals(stringValue))
+      {
+         return null;
+      }
+      
+      return stringValue;
+   }
+
+   /**
+    * Saves the string value of this key in this storage.
+    * 
+    * @param    key
+    *           The given key
+    * @param    value
+    *           The value of the given key
+    */
+   @Override
+   public void setString(String key, String value)
+   {
+      webSocket.setStringValue(key, String.valueOf(value));
+   }
+}

