Register   Login   About   Study   Enterprise   Share
Internet / AI Technology University (ITU/AITU)
Fast Login - available after registration







|

Top Links: >> 80. Technology >> Internet Technology Summit Program >> 4. Web Apps Frameworks >> 4.4. Spring with Apache Maven and Data Service Frameworks >> 4.4.4.Data Service Framework and Troubleshooting
Current Topic: 4.4.4.6.Data Service Library
Sub-Topics: 4.4.4.6.1. Handling actions and related configurations | 4.4.4.6.2. DataService handling DB connections | 4.4.4.6.3.Get and Set Data with Data Service
-- Scroll to check for more content below...
You have a privilege to create a quiz (QnA) related to this subject and obtain creativity score...
4.4.4.6.Data Service Library
DataService Framework includes a small footprint library com.its.util.jar available at https://ituniversity.us/downloads/com.its.util.jar

The API is provided with Javadoc and available at https://ituniversity.us/javadoc/index.html

The library offers input/output facilities with the IOMaster class, text parsing utilities with the Stringer and Parser classes.
The most commonly used utilities are collected in the following packages:
- com.its.util - general purposes.
- com.its.ds - database handling utilities
- com.its.helpers - higher level utilities often connecting first two into data processing utilities

Database utilities are based on the DataService class that gives the name to the framework.
For example, these several methods of IOMaster provide reading a file from a file system:

static byte[] readBinFile(java.lang.String filename)
method readBinFile() reads binary file

static byte[] readByteStream(java.io.InputStream in, int iLength)
reads a stream of bytes

static java.lang.String readTextFile(java.lang.String iFilename)
method readTextFile() uses readBinFile(iFilename) if iFilename starts with "http" or "www", the method will read an HTML page from the Internet Example: String textFile = IOMaster.readTextFile("c:/UST/resources/myText.txt"); String webPage = IOMaster.readTextFile("http://ITUniversity.us/about/publications.html");

But actually the same method readTextFile(String iFilename) can also read a page from the web.
The method will choose how to behave based on the beginning of the filename. If the location starts with http or www, the method will work as a browser reading a web page for you. Otherwise, the method will read from the file system.

Writing files with IOMaster is also easy.

static boolean writeBinFile(java.lang.String iFilename, byte[] iData)
write binary file

static boolean writeTextFile(java.lang.String iFilename, java.lang.String iData)
writeTextFile() method writes a string of text data into a file


There are many more methods to explore in this class.
There is a subclass IODeamon which extends IOMaster.
IODeamon speciality is working with client and server sockets, threads, and executing command line commends from Java.

static java.lang.String clientSocketRequest(java.lang.String host, int portNumber, java.lang.String serviceRequest)
clientSocketRequest() method establishes a socket connection and sends a request for service The operation is inside the try - catch statements as any network operation.

static java.lang.Process exec(java.lang.String commandLine, boolean output)
The exec() can kill or start a process with or without output

static void serverSocketService(int portNumber)
This is a simple server socket that provide requested services.

static void startServerDaemon(int portNumber, java.lang.String serviceName, java.lang.String methodName)
This is a simple server socket example with two static methods: server daemon waiting for clients and service provider.

static void startTextServerDaemon(int portNumber, java.lang.String serviceName, java.lang.String methodName)
This is a simple server socket example with two static methods: server daemon waiting for clients and service provider.

And yet another subclass of IOMaster is the IOZipper class.
IOZipper specialty is compressing and uncompressing files.

static java.util.Vector unzip(java.lang.String zipFilename, byte[] bytes)
unzip() is to extract a file or a set of files from a ZIP file

static int zip(java.lang.String dataPath, java.lang.String zipFile, java.util.Vector filenames)
The zip() method will zip a set of files pointed in a vector of names

Another interesting class that deals with input/output including posting to the web, is CsvMaster.
The name acknowledges that this class can work with Excel files stored as Comma Separated Values (CSV).

static java.lang.String createCsvFileText(java.util.List listOfLines)
The createCsvFileText() transforms a list of string arrays (cells) into a comma separated text of Csv file

static java.lang.String csvToHtml(java.lang.String url, boolean noInsideCommas)

static java.lang.String[] getCsvLines(java.lang.String appName, java.lang.String path, java.lang.String spreadsheetUrl, boolean noInsideCommas)
The getCsvLines() method reads Csv file and splits into lines

java.lang.String post(boolean iResponse)
The post() method is used to post multipart/form-data

static java.lang.String postFile(java.lang.String parameters, java.lang.String localFilePath, java.lang.String remoteFileName, java.lang.String contentType, java.lang.String url)
The postFile() method connects to a web server via the URL and posts parameters and a file content

static byte[] postUDP(java.lang.String host, int port, int[] command)
The postUDP() method is responsible for communication with UDP (Datagram sockets) For example, UDP can be used by a CDPD device

static java.lang.String readCsvFile(java.lang.String appName, java.lang.String csvPathName, java.lang.String filename, java.lang.String account)
The readCsvFile() method reads Csv file

static java.lang.String sendFileToWeb(java.lang.String localFilePath, java.lang.String remotePath, java.lang.String url, java.lang.String userId)


The Stringer and StringMaster classes provide manipulations on text strings.
Here are just several methods:

static int[] getClosestIndexOf(java.lang.String src, int startingIndex, java.lang.String[] patterns)
The getClosestIndexOf() looks for the closest of the patterns

static java.lang.String[] getInternalStringsOf(java.lang.String source, java.lang.String startPattern, java.lang.String endPattern)

static java.lang.String getStringAfter(java.lang.String source, java.lang.String pattern)
The getStringAfter() returns text after a pattern

static java.lang.String getStringBefore(java.lang.String iString, int iStart, java.lang.String iEndPattern)
getStringBefore() returns a string after a pattern between start and end index

static java.lang.String getStringBetweenTags(java.lang.String source, java.lang.String tag)
getStringBetweenTags() returns a string between "" and " "

static java.lang.String getStringOf(java.lang.String iString, java.lang.String iPattern, int iStart, java.lang.String iEndPattern)
getStringOf() returns a string after a pattern between start and end if startPattern is not equals endPattern the method checks for possibilities of nested occurrences.

The Parser class includes the methods to parse the text files and log file streams in real-time. The Parser might provide semantic analysis for specific time windows.
Here are a small subset of the methods:

static java.lang.String parseWhileReading(java.lang.String filename, java.lang.String[] patterns, java.util.Hashtable details)
The parseWhileReading() method is reading a log file on-the-fly and looking for patterns

static java.lang.String parseWithPatterns(java.lang.String text, java.lang.String patternsInString)
The parseWithPatterns() search the text according to the patterns.
This version of the parseWithPatterns() method takes an array of patterns In the array the first value is a key, such as "before" or "after" or "before last" or "after ignorecase" etc.
Example: String port = Parser.parseWithPatterns(source, "after,http,after,:,before,/");
Was it clear so far?


The DataService class is responsible for database management.
The DataService class is a facade for data layer methods extends DataBaseService, which extends JpaDataService. The DataService class is the core class of DataService framework by ITS. The framework allows developers describe dependencies and desirable objects as configuration parameters saving a lot of coding efforts.
DataService expects a simple configuration file with DB properties. SQL statements are not provided with Java code but stored separately in the {project}/config/sql/ - directory as small SQL files.
DataService works with other framework classes, such as IOMaster and Stats to read configuration details and SQL statements nd store them in a static Hashtable called appDetails.

At runtime DataService? methods take the name of an SQL file as an argument and retrieves the statement from the Hashtable. This allows to separate two different languages and makes easy testing SQL statements with existing SQL tools.

Preferred way of database access is via PreparedStatement. PreparedStatement is safer than Statement objects from security prospects, often accelerate performance, and provides better handling for data with unexpected characters, such as single quote, which can confuse a regular Statement processing.

Database access is implemented mostly via JPA/Hibernate libraries, which are extensively used in the JpaDataService class. Read more about Jpa/Hibernate in the following sections.


Recommended usage:
1. Prepare configuration parameters describing your databases (can be more than one):

1.a. To create and populate the table provide the following parameters in the web.xml:



dsNames
sampledb,anotherdb





sampledb-dbParams
sampledb,its,admin,sampledb,config/sql,localhost,3306,mysql



sampledb-tables
Accounts



sampledb-AccountsTableKeys
email,password,firstName,lastName



sampledb-AccountsInitData

john@gmail.com,Ja@track5,John,Track|joe@gmail.com,Joe%make34,Joe,Carter




The first section of sampledb-dbParams defines the following database parameters: the name of the database or SID, dbUserName, the password, the name of a data source (again) associated with the database, which will be used in a Java program as dsName variable. The following parameters defines a location for SQL statements (relative to the deployment path), the hostname, port, and the type of the database.

The database types can be any from the list: oracle,mysql,mssql,postgres.

In Eclipse, place all SQL statements in under the project webapps/config/sql ? directory. After the project is deployed, the location of the SQL statements is under the deployment directory, then under the project name (appName) and under the config/sql/ ? directory.

While working with the Maven project (next section), your SQL statements will be usually under src/main/webapp/config/sql/ - directory.



* 2. Create SQL statements and store them in the SQL location with the extension ".sql"
Example:
select * from users where userName = ? and job = ?
* Store the line above in the file webapps/config/sql/selectUsersByNameAndJob.sql
* Use DataService.getPrepDataBySqlName(sqlName, params, dsName); - source line in a Java class to select data
* Provide run-time parameters with this line:
String[] params = new String[] {userName, job); // userName and job must be available as dynamic variables
*
* 3. At application start read configuration and associate a Database with its data source name (dsName) to
* prepare for work with the pool of connections. The method below will also read all SQL files into a Hashtable.
DataService.init(applicationName, dataSourceLogicalName, pathToConfigurationPropertyFile);
*
* 4. In the application at runtime use the method below, which will find a proper SQL statement and replace runtime variables
Example:
List listOfRecords = DataService.getPrepDataBySqlName("selectUsersByNameAndJob", new String[] {userName,job}, dsName);

To insert, update or delete data most commonly used statement is:

DataService.setPrepDataBySqlName(sqlName, runTimeParams, dsName);

For example, to update the record with new job, create an SQL file,
"{projectName}/config/sql/updateUsersJob.sql", with the following statement:

update users set job=? where userID = ?

Then in the Java program provide the following two lines:

String[] runTimeParams = new String[] {job, userID};
DataService.setPrepDataBySqlName("updateUsersJob", runTimeParams, dsName);


The DataService class has many more method. Explore and try some of them.
DataService library API is available at http://ITUniversity.us/downloads/html/api/index.html
Assignments:
1. Create a new Maven Dynamic Web project (similar to previous) 4.4.4.6.DataServiceWithLibrary.
2. In this project use:
- At least 4 different API of IOMaster to work with local files and read from the web
- Several methods of Stringer and Parser.parseWithPatterns
- Database with at least 4 tables, with the SQL statements: select, update, insert, delete.
3. Place in the resources directory and email to dean@ituniversity.us MS Word document with Business requirements and Design spec, which describe creating a blog support application with user login and registration, posting blogs and comments.
4. Use Algular to calculate number of words in the text field, when a user is typing a blog or a comment, and make it visible to a user at all times.
6. Provide search for a content.
7. Use Angular to place drop-down list of options for a user, each option allows a user add some GUI to the screen, button, another drop-down list, image or a mp4 clip (for the last two should arrange "upload file"). Each time user select an option, result should be immediately visible on the screen (a single-page-app with support from server via Ajax when needed)
8. Use Bootstrap to make sure that the application is visible on a mobile phone.
9. Email working application with all necessary sources as a zip file to deploy to dean@ituniversity.us
| Check Your Progress | Propose QnA | Have a question or comments for open discussion?
<br/>static byte[]	readBinFile(java.lang.String filename)
<br/>method readBinFile() reads binary file
<br/>
<br/>static byte[]	readByteStream(java.io.InputStream in, int iLength)
<br/>reads a stream of bytes
<br/>
<br/>static java.lang.String	readTextFile(java.lang.String iFilename)
<br/>method readTextFile() uses readBinFile(iFilename) if iFilename starts with "http" or "www", the method will read an HTML page from the Internet Example: String textFile = IOMaster.readTextFile("c:/UST/resources/myText.txt"); String webPage = IOMaster.readTextFile("http://ITUniversity.us/about/publications.html");
<br/>

But actually the same method readTextFile(String iFilename) can also read a page from the web.
The method will choose how to behave based on the beginning of the filename. If the location starts with http or www, the method will work as a browser reading a web page for you. Otherwise, the method will read from the file system.

Writing files with IOMaster is also easy.
<br/>static boolean	writeBinFile(java.lang.String iFilename, byte[] iData)
<br/>write binary file
<br/>
<br/>static boolean	writeTextFile(java.lang.String iFilename, java.lang.String iData)
<br/>writeTextFile() method writes a string of text data into a file
<br/>


There are many more methods to explore in this class.
There is a subclass IODeamon which extends IOMaster.
IODeamon speciality is working with client and server sockets, threads, and executing command line commends from Java.
<br/>static java.lang.String	clientSocketRequest(java.lang.String host, int portNumber, java.lang.String serviceRequest)
<br/>clientSocketRequest() method establishes a socket connection and sends a request for service The operation is inside the try - catch statements as any network operation.
<br/>
<br/>static java.lang.Process	exec(java.lang.String commandLine, boolean output)
<br/>The exec() can kill or start a process with or without output
<br/>
<br/>static void	serverSocketService(int portNumber)
<br/>This is a simple server socket that provide requested services.
<br/>
<br/>static void	startServerDaemon(int portNumber, java.lang.String serviceName, java.lang.String methodName)
<br/>This is a simple server socket example with two static methods: server daemon waiting for clients and service provider.
<br/>
<br/>static void	startTextServerDaemon(int portNumber, java.lang.String serviceName, java.lang.String methodName)
<br/>This is a simple server socket example with two static methods: server daemon waiting for clients and service provider.
<br/>

And yet another subclass of IOMaster is the IOZipper class.
IOZipper specialty is compressing and uncompressing files.
<br/>static java.util.Vector	unzip(java.lang.String zipFilename, byte[] bytes)
<br/>unzip() is to extract a file or a set of files from a ZIP file
<br/>
<br/>static int	zip(java.lang.String dataPath, java.lang.String zipFile, java.util.Vector filenames)
<br/>The zip() method will zip a set of files pointed in a vector of names
<br/>

Another interesting class that deals with input/output including posting to the web, is CsvMaster.
The name acknowledges that this class can work with Excel files stored as Comma Separated Values (CSV).
<br/>static java.lang.String	createCsvFileText(java.util.List<java.lang.String[]> listOfLines)
<br/>The createCsvFileText() transforms a list of string arrays (cells) into a comma separated text of Csv file
<br/>
<br/>static java.lang.String	csvToHtml(java.lang.String url, boolean noInsideCommas) 
<br/>
<br/>static java.lang.String[]	getCsvLines(java.lang.String appName, java.lang.String path, java.lang.String spreadsheetUrl, boolean noInsideCommas)
<br/>The getCsvLines() method reads Csv file and splits into lines
<br/>
<br/>java.lang.String	post(boolean iResponse)
<br/>The post() method is used to post multipart/form-data
<br/>
<br/>static java.lang.String	postFile(java.lang.String parameters, java.lang.String localFilePath, java.lang.String remoteFileName, java.lang.String contentType, java.lang.String url)
<br/>The postFile() method connects to a web server via the URL and posts parameters and a file content
<br/>
<br/>static byte[]	postUDP(java.lang.String host, int port, int[] command)
<br/>The postUDP() method is responsible for communication with UDP (Datagram sockets) For example, UDP can be used by a CDPD device
<br/>
<br/>static java.lang.String	readCsvFile(java.lang.String appName, java.lang.String csvPathName, java.lang.String filename, java.lang.String account)
<br/>The readCsvFile() method reads Csv file
<br/>
<br/>static java.lang.String	sendFileToWeb(java.lang.String localFilePath, java.lang.String remotePath, java.lang.String url, java.lang.String userId)
<br/>


The Stringer and StringMaster classes provide manipulations on text strings.
Here are just several methods:
<br/>static int[]	getClosestIndexOf(java.lang.String src, int startingIndex, java.lang.String[] patterns)
<br/>The getClosestIndexOf() looks for the closest of the patterns
<br/>
<br/>static java.lang.String[]	getInternalStringsOf(java.lang.String source, java.lang.String startPattern, java.lang.String endPattern)
<br/>
<br/>static java.lang.String	getStringAfter(java.lang.String source, java.lang.String pattern)
<br/>The getStringAfter() returns text after a pattern
<br/>
<br/>static java.lang.String	getStringBefore(java.lang.String iString, int iStart, java.lang.String iEndPattern)
<br/>getStringBefore() returns a string after a pattern between start and end index
<br/>
<br/>static java.lang.String	getStringBetweenTags(java.lang.String source, java.lang.String tag)
<br/>getStringBetweenTags() returns a string between "<tag>" and "</tag> "
<br/>
<br/>static java.lang.String	getStringOf(java.lang.String iString, java.lang.String iPattern, int iStart, java.lang.String iEndPattern)
<br/>getStringOf() returns a string after a pattern between start and end if startPattern is not equals endPattern the method checks for possibilities of nested occurrences.
<br/>

The Parser class includes the methods to parse the text files and log file streams in real-time. The Parser might provide semantic analysis for specific time windows.
Here are a small subset of the methods:
<br/>static java.lang.String	parseWhileReading(java.lang.String filename, java.lang.String[] patterns, java.util.Hashtable details)
<br/>The parseWhileReading() method is reading a log file on-the-fly and looking for patterns
<br/>
<br/>static java.lang.String	parseWithPatterns(java.lang.String text, java.lang.String patternsInString)
<br/>The parseWithPatterns() search the text according to the patterns. 
<br/>This version of the parseWithPatterns() method takes an array of patterns In the array the first value is a key, such as "before" or "after" or "before last" or "after ignorecase" etc.
<br/>Example: String port = Parser.parseWithPatterns(source, "after,http,after,:,before,/");
<br/>






Was it clear so far?



The DataService class is responsible for database management.
The DataService class is a facade for data layer methods extends DataBaseService, which extends JpaDataService. The DataService class is the core class of DataService framework by ITS. The framework allows developers describe dependencies and desirable objects as configuration parameters saving a lot of coding efforts.
DataService expects a simple configuration file with DB properties. SQL statements are not provided with Java code but stored separately in the {project}/config/sql/ - directory as small SQL files.
DataService works with other framework classes, such as IOMaster and Stats to read configuration details and SQL statements nd store them in a static Hashtable called appDetails.

At runtime DataService? methods take the name of an SQL file as an argument and retrieves the statement from the Hashtable. This allows to separate two different languages and makes easy testing SQL statements with existing SQL tools.

Preferred way of database access is via PreparedStatement. PreparedStatement is safer than Statement objects from security prospects, often accelerate performance, and provides better handling for data with unexpected characters, such as single quote, which can confuse a regular Statement processing.

Database access is implemented mostly via JPA/Hibernate libraries, which are extensively used in the JpaDataService class. Read more about Jpa/Hibernate in the following sections.

<br/> Recommended usage:
<br/>  1. Prepare configuration parameters describing your databases (can be more than one):
<br/> 
<br/> 1.a. To create and populate the table provide the following parameters in the web.xml:
<br/><!-- Provide the list of all data source names, separated by comma -->
<br/>
<br/>  <context-param>
<br/>    <param-name>dsNames</param-name>
<br/>    <param-value>sampledb,anotherdb</param-value>
<br/>   </context-param>
<br/>
<br/><!-- Describe all parameters for each Data Source, usually keep data source name same as dbName and while using JPA (next section) same as JpaUnitName -->
<br/><!-- dbName (SID), dbUserName, psw, dsName, sqlLocation related to deploypath, hostname, dbPort, dbType-->   
<br/>   <context-param>
<br/>    <param-name>sampledb-dbParams</param-name>
<br/>    <param-value>sampledb,its,admin,sampledb,config/sql,localhost,3306,mysql</param-value>
<br/>   </context-param>  
<br/><!-- Describe the tables (only tables that you need to create/initialize) for this data source separated by comma -->   
<br/>   <context-param>
<br/>    <param-name>sampledb-tables</param-name>
<br/>    <param-value>Accounts</param-value>
<br/>   </context-param>   
<br/><!-- Describe the field names of for the table, which name starts the param-name -->   
<br/>   <context-param>
<br/>    <param-name>sampledb-AccountsTableKeys</param-name>
<br/>    <param-value>email,password,firstName,lastName</param-value>
<br/>   </context-param>  
<br/><!-- Describe initial table records if necessary, with the records separated by "|" -->
<br/>   <context-param>
<br/>    <param-name>sampledb-AccountsInitData</param-name>
<br/>    <param-value>
<br/>    john@gmail.com,Ja@track5,John,Track|joe@gmail.com,Joe%make34,Joe,Carter    
<br/>    </param-value>
<br/></context-param>
<br/>


The first section of sampledb-dbParams defines the following database parameters: the name of the database or SID, dbUserName, the password, the name of a data source (again) associated with the database, which will be used in a Java program as dsName variable. The following parameters defines a location for SQL statements (relative to the deployment path), the hostname, port, and the type of the database.

The database types can be any from the list: oracle,mysql,mssql,postgres.

In Eclipse, place all SQL statements in under the project webapps/config/sql ? directory. After the project is deployed, the location of the SQL statements is under the deployment directory, then under the project name (appName) and under the config/sql/ ? directory.

While working with the Maven project (next section), your SQL statements will be usually under src/main/webapp/config/sql/ - directory.


<br/>* 2. Create SQL statements and store them in the SQL location with the extension ".sql"
<br/>  Example:
<br/>  select * from users where userName = ? and job = ?
<br/> * Store the line above in the file <b>webapps/config/sql/selectUsersByNameAndJob.sql</b>
<br/> * Use <b>DataService.getPrepDataBySqlName(sqlName, params, dsName);</b> - source line in a Java class to select data
<br/>* Provide run-time parameters with this line:
<br/>String[] params = new String[] {userName, job); // userName and job must be available as dynamic variables
<br/> * 
<br/> * 3. At application start read configuration and associate a Database with its data source name (dsName) to 
<br/> * prepare for work with the pool of connections. The method below will also read all SQL files into a Hashtable.  
<br/>DataService.init(applicationName, dataSourceLogicalName, pathToConfigurationPropertyFile);
<br/> * 
<br/> * 4. In the application at runtime use the method below, which will find a proper SQL statement and replace runtime variables
<br/>  Example:
<br/> List<String[]> listOfRecords = DataService.getPrepDataBySqlName("selectUsersByNameAndJob", new String[] {userName,job}, dsName);
<br/> 
<br/>   To insert, update or delete data most commonly used statement is:
<br/>
<br/>DataService.setPrepDataBySqlName(sqlName, runTimeParams, dsName);
<br/>
<br/>   For example, to update the record with new job, create an SQL file, 
<br/>   "{projectName}/config/sql/updateUsersJob.sql", with the following statement:
<br/>   
<br/>   update users set job=? where userID = ?
<br/>
<br/>    Then in the Java program provide the following two lines:
<br/>     
<br/>String[] runTimeParams = new String[] {job, userID};
<br/>DataService.setPrepDataBySqlName("updateUsersJob", runTimeParams, dsName);
<br/>


The DataService class has many more method. Explore and try some of them.
DataService library API is available at http://ITUniversity.us/downloads/html/api/index.html
Assignments:
1. Create a new Maven Dynamic Web project (similar to previous) 4.4.4.6.DataServiceWithLibrary.
2. In this project use:
- At least 4 different API of IOMaster to work with local files and read from the web
- Several methods of Stringer and Parser.parseWithPatterns
- Database with at least 4 tables, with the SQL statements: select, update, insert, delete.
3. Place in the resources directory and email to dean@ituniversity.us MS Word document with Business requirements and Design spec, which describe creating a blog support application with user login and registration, posting blogs and comments.
4. Use Algular to calculate number of words in the text field, when a user is typing a blog or a comment, and make it visible to a user at all times.
6. Provide search for a content.
7. Use Angular to place drop-down list of options for a user, each option allows a user add some GUI to the screen, button, another drop-down list, image or a mp4 clip (for the last two should arrange "upload file"). Each time user select an option, result should be immediately visible on the screen (a single-page-app with support from server via Ajax when needed)
8. Use Bootstrap to make sure that the application is visible on a mobile phone.
9. Email working application with all necessary sources as a zip file to deploy to dean@ituniversity.us

| Check Your Progress | Propose QnA | Have a question or comments for open discussion?

Have a suggestion? - shoot an email
Looking for something special? - Talk to me
Read: IT of the future: AI and Semantic Cloud Architecture | Fixing Education
Do you want to move from theory to practice and become a magician? Learn and work with us at Internet Technology University (ITU) - JavaSchool.com.

Technology that we offer and How this works: English | Spanish | Russian | French

Internet Technology University | JavaSchool.com | Copyrights © Since 1997 | All Rights Reserved
Patents: US10956676, US7032006, US7774751, US7966093, US8051026, US8863234
Including conversational semantic decision support systems (CSDS) and bringing us closer to The message from 2040
Privacy Policy