diff --git a/CMakeLists.txt b/CMakeLists.txt index 9b843e6..6be25c3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -9,19 +9,24 @@ set(EXECUTABLE_OUTPUT_PATH ${wsjcpp-jsonrpc20_SOURCE_DIR}) # include header dirs list (APPEND WSJCPP_INCLUDE_DIRS "src") +list (APPEND WSJCPP_INCLUDE_DIRS "src/app") -list (APPEND WSJCPP_SOURCES "src/main.cpp") +# package list (APPEND WSJCPP_SOURCES "src/wsjcpp_jsonrpc20.h") list (APPEND WSJCPP_SOURCES "src/wsjcpp_jsonrpc20.cpp") - +list (APPEND WSJCPP_SOURCES "src/wsjcpp_jsonrpc20_export_cli_base.h") +list (APPEND WSJCPP_SOURCES "src/wsjcpp_jsonrpc20_export_cli_base.cpp") list (APPEND WSJCPP_SOURCES "src/wsjcpp_jsonrpc20_export_cli_python.h") list (APPEND WSJCPP_SOURCES "src/wsjcpp_jsonrpc20_export_cli_python.cpp") - -# examples -list (APPEND WSJCPP_SOURCES "./src/examples/wsjcpp_json_rpc20_handler_game_create.h") -list (APPEND WSJCPP_SOURCES "./src/examples/wsjcpp_json_rpc20_handler_game_create.cpp") -list (APPEND WSJCPP_SOURCES "./src/examples/wsjcpp_json_rpc20_handler_auth.h") -list (APPEND WSJCPP_SOURCES "./src/examples/wsjcpp_json_rpc20_handler_auth.cpp") +list (APPEND WSJCPP_SOURCES "src/wsjcpp_jsonrpc20_export_cli_webjs.h") +list (APPEND WSJCPP_SOURCES "src/wsjcpp_jsonrpc20_export_cli_webjs.cpp") + +# app +list (APPEND WSJCPP_SOURCES "src/app/main.cpp") +list (APPEND WSJCPP_SOURCES "./src/app/wsjcpp_json_rpc20_handler_game_create.h") +list (APPEND WSJCPP_SOURCES "./src/app/wsjcpp_json_rpc20_handler_game_create.cpp") +list (APPEND WSJCPP_SOURCES "./src/app/wsjcpp_json_rpc20_handler_auth.h") +list (APPEND WSJCPP_SOURCES "./src/app/wsjcpp_json_rpc20_handler_auth.cpp") #### BEGIN_WSJCPP_APPEND #### END_WSJCPP_APPEND diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..fa5ff77 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2019 Evgenii Sopov + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. \ No newline at end of file diff --git a/README.md b/README.md index 5bc9bb3..a7e323c 100644 --- a/README.md +++ b/README.md @@ -1,13 +1,17 @@ # wsjcpp-jsonrpc20 -[![Build Status](https://api.travis-ci.com/wsjcpp/wsjcpp-jsonrpc20.svg?branch=master)](https://travis-ci.com/wsjcpp/wsjcpp-jsonrpc20) [![Total alerts](https://img.shields.io/lgtm/alerts/g/wsjcpp/wsjcpp-jsonrpc20.svg?logo=lgtm&logoWidth=18)](https://lgtm.com/projects/g/wsjcpp/wsjcpp-jsonrpc20/alerts/) [![Language grade: C/C++](https://img.shields.io/lgtm/grade/cpp/g/wsjcpp/wsjcpp-jsonrpc20.svg?logo=lgtm&logoWidth=18)](https://lgtm.com/projects/g/wsjcpp/wsjcpp-jsonrpc20/context:cpp) [![Language grade: Python](https://img.shields.io/lgtm/grade/python/g/wsjcpp/wsjcpp-jsonrpc20.svg?logo=lgtm&logoWidth=18)](https://lgtm.com/projects/g/wsjcpp/wsjcpp-jsonrpc20/context:python) +[![Build Status](https://api.travis-ci.com/wsjcpp/wsjcpp-jsonrpc20.svg?branch=master)](https://travis-ci.com/wsjcpp/wsjcpp-jsonrpc20) [![Total alerts](https://img.shields.io/lgtm/alerts/g/wsjcpp/wsjcpp-jsonrpc20.svg?logo=lgtm&logoWidth=18)](https://lgtm.com/projects/g/wsjcpp/wsjcpp-jsonrpc20/alerts/) [![Language grade: C/C++](https://img.shields.io/lgtm/grade/cpp/g/wsjcpp/wsjcpp-jsonrpc20.svg?logo=lgtm&logoWidth=18)](https://lgtm.com/projects/g/wsjcpp/wsjcpp-jsonrpc20/context:cpp) [![Language grade: Python](https://img.shields.io/lgtm/grade/python/g/wsjcpp/wsjcpp-jsonrpc20.svg?logo=lgtm&logoWidth=18)](https://lgtm.com/projects/g/wsjcpp/wsjcpp-jsonrpc20/context:python) [![deepcode](https://www.deepcode.ai/api/gh/badge?key=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJwbGF0Zm9ybTEiOiJnaCIsIm93bmVyMSI6IndzamNwcCIsInJlcG8xIjoid3NqY3BwLWpzb25ycGMyMCIsImluY2x1ZGVMaW50IjpmYWxzZSwiYXV0aG9ySWQiOjE1NjQxLCJpYXQiOjE2MDE2MTM0MTh9.gErsnFaMiBhySNjNeNqAjFgxFP41QJZVYeJJffWmaDw)](https://www.deepcode.ai/app/gh/wsjcpp/wsjcpp-jsonrpc20/_/dashboard?utm_content=gh%2Fwsjcpp%2Fwsjcpp-jsonrpc20) C++ Implementation for JsonRPC 2.0 (oriented on websockets) +Got information about this protocol here [https://www.simple-is-better.org/json-rpc/jsonrpc20.html](https://www.simple-is-better.org/json-rpc/jsonrpc20.html) +But used not all standart + ## Features * Collect all handlers for jsonrpc20 * Including system of define validators +* Can generate client library on python (Include control pypi files) ## Integration @@ -20,7 +24,8 @@ $ wsjcpp install https://github.com/wsjcpp/wsjcpp-jsonrpc20:master ### Include files * src.wsjcpp/nlohmann_json/json.hpp -* src.wsjcpp/wsjcpp_core.h +* src.wsjcpp/wsjcpp_core/wsjcpp_core.h +* src.wsjcpp/wsjcpp_core/wsjcpp_core.cpp * src.wsjcpp/wsjcpp_validators/wsjcpp_validators.h * src.wsjcpp/wsjcpp_validators/wsjcpp_validators.cpp * src/wsjcpp_jsonrpc20.h diff --git a/example-of-exported/py3/API.md b/example-of-exported/py3/API.md index 01c4757..568ad4d 100644 --- a/example-of-exported/py3/API.md +++ b/example-of-exported/py3/API.md @@ -1,8 +1,8 @@ # SomeClient Python Library Automatically generated by wsjcpp-jsonrpc20. -* Version: v0.0.3 -* Date: Fri, 18 Sep 2020 03:27:31 GMT +* Version: v0.0.4 +* Date: Wed, 07 Oct 2020 17:03:09 GMT Example connect/disconnect: ``` diff --git a/example-of-exported/py3/libwsjcppjson20client/SomeClient.py b/example-of-exported/py3/libwsjcppjson20client/SomeClient.py index a1b4f02..cdcff55 100644 --- a/example-of-exported/py3/libwsjcppjson20client/SomeClient.py +++ b/example-of-exported/py3/libwsjcppjson20client/SomeClient.py @@ -1,8 +1,8 @@ #!/usr/bin/env python3 # -*- coding: utf-8 -*- ### This file was automatically generated by wsjcpp-jsonrpc20 -### Version: v0.0.3 -### Date: Fri, 18 Sep 2020 03:27:31 GMT +### Version: v0.0.4 +### Date: Wed, 07 Oct 2020 17:03:09 GMT import asyncio import websocket @@ -13,7 +13,7 @@ class SomeClient: __ws = None __url = None - __cli_version = 'v0.0.3' + __cli_version = 'v0.0.4' __loop = None __token = None __connecting = False @@ -44,6 +44,7 @@ def hasConnection(self): def getToken(self): return self.__token + def setToken(self, token): if self.__token is None: self.__token = token diff --git a/example-of-exported/py3/setup.py b/example-of-exported/py3/setup.py index 46b7c77..d2900c5 100644 --- a/example-of-exported/py3/setup.py +++ b/example-of-exported/py3/setup.py @@ -5,7 +5,7 @@ setuptools.setup( name='libwsjcppjson20client', - version='v0.0.3', + version='v0.0.4', packages=['libwsjcppjson20client'], install_requires=['websocket-client>=0.56.0', 'requests>=2.21.0'], keywords=['wsjcpp-jsonrpc20', 'wsjcpp', 'wsjcpp-jsonrpc20', 'example-python-client'], diff --git a/example-of-exported/webjs/API.md b/example-of-exported/webjs/API.md new file mode 100644 index 0000000..4a8b39e --- /dev/null +++ b/example-of-exported/webjs/API.md @@ -0,0 +1,185 @@ +# libwsjcppjson20client + + Automatically generated by wsjcpp-jsonrpc20. + * Version: v0.0.4 + * Date: 07 Oct 2020 + + Include script ```dist/libwsjcppjson20client.js``` + Example connect: +``` +var client = new SomeClient(); +client.bind('server', function(data) { console.log('server', data)}) +client.bind('notify', function(data) { console.log('notify', data)}) +client.bind('chat', function(data) { console.log('chat', data)}) +client.bind('connected', function(data) { console.log('connected', data)}) +client.bind('reconnecting', function(data) { console.log('reconnecting', data)}) +client.bind('disconnected', function(data) { console.log('disconnected', data)}) +client.bind('broken', function(data) { console.log('broken', data)}) +client.bind('userdata', function(data) { console.log('userdata', data)}) +client.bind('connected', function(data) { console.log('connected', data)}) +// connect +client.init({'baseUrl': 'ws://localhost:1234/'}) +// disconnect +client.deinit() +``` + +
+auth_login + +## auth_login + +Auth by login and password + +Access: unauthorized - **yes**, user - **no**, tester - **no**, admin - **no** + + #### Input params + + * login - string, required; User Login + * password - string, required; User Password + * client_app_name - string, optional; Client app name + * client_app_version - string, optional; Client app version + + + #### example call method + +``` +client.auth_login({ + "login": "", + "password": "", + "client_app_name": "", + "client_app_version": "" +}).done(function(r) { + console.log('Success: ', r); +}).fail(function(err) { + console.error('Error:', err); +}); +``` + +
+ +
+auth_logoff + +## auth_logoff + +Logoff + +Access: unauthorized - **no**, user - **yes**, tester - **yes**, admin - **yes** + + #### Input params + + + + #### example call method + +``` +client.auth_logoff({ + +}).done(function(r) { + console.log('Success: ', r); +}).fail(function(err) { + console.error('Error:', err); +}); +``` + +
+ +
+auth_token + +## auth_token + +Auth by token + +Access: unauthorized - **yes**, user - **no**, tester - **no**, admin - **no** + + #### Input params + + * token - string, required; Token + * client_app_name - string, optional; Client app name + * client_app_version - string, optional; Client app version + + + #### example call method + +``` +client.auth_token({ + "token": "", + "client_app_name": "", + "client_app_version": "" +}).done(function(r) { + console.log('Success: ', r); +}).fail(function(err) { + console.error('Error:', err); +}); +``` + +
+ +
+game_create + +## game_create + +Some example of description + +Access: unauthorized - **no**, user - **yes**, tester - **yes**, admin - **yes** + + #### Input params + + * uuid - string, required; object uuid + * name - string, optional; Name of object + * cost - integer, required; Name of object + * age - integer, optional; Name of object + * public - boolean, required; True if object is public + * activated - boolean, optional; If object can handle + * custom - json, optional; Some custom json + + + #### example call method + +``` +client.game_create({ + "uuid": "", + "name": "", + "cost": 0, + "age": 0, + "public": "", + "activated": "", + "custom": "" +}).done(function(r) { + console.log('Success: ', r); +}).fail(function(err) { + console.error('Error:', err); +}); +``` + +
+ +
+server_api + +## server_api + +This method Will be return list of all handlers + +Access: unauthorized - **yes**, user - **yes**, tester - **yes**, admin - **yes** + + #### Input params + + + + #### example call method + +``` +client.server_api({ + +}).done(function(r) { + console.log('Success: ', r); +}).fail(function(err) { + console.error('Error:', err); +}); +``` + +
+ diff --git a/example-of-exported/webjs/dist/libwsjcppjson20client.js b/example-of-exported/webjs/dist/libwsjcppjson20client.js new file mode 100644 index 0000000..638998b --- /dev/null +++ b/example-of-exported/webjs/dist/libwsjcppjson20client.js @@ -0,0 +1,290 @@ +// This file was automatically generated by wsjcpp-jsonrpc20 (v0.0.4), date: 07 Oct 2020 +window.SomeClient = window.SomeClient || (function() { + var self = {}; + self.appName = 'wsjcpp-jsonrpc20'; + self.appVersion = 'v0.0.4'; + self.appBuildDate = '07 Oct 2020'; + var _lastm = 0; + var _listeners = {}; + var _connectionState = '?'; + var _tokenValue = ''; + var _events = { + 'server': [], + 'notify': [], + 'chat': [], + 'connected': [], + 'reconnecting': [], + 'disconnected': [], + 'broken': [], + 'userdata': [], + }; + function _lm() { _lastm++; return 'm' + _lastm; }; + console.warn('SomeClient (v0.0.4)'); + self.promise = function() { + return { + completed: false, failed: false, successed: false, + done: function(callback) { + this.done_callback = callback; + if (this.completed && typeof this.done_callback === 'function' && this.successed) { + this.done_callback.apply(this, this.result_arguments); + } + return this; + }, + fail: function(callback) { + this.fail_callback = callback; + if (this.completed && typeof this.fail_callback === 'function' && this.failed) { + this.fail_callback.apply(this, this.error_arguments); + } + return this; + }, + resolve: function() { + if (!this.completed) { + this.result_arguments = arguments; // []; + if (typeof this.done_callback === 'function') { + this.done_callback.apply(this, this.result_arguments); + } + } + this.successed = true; + this.completed = true; + }, + reject: function() { + if (!this.completed) { + this.error_arguments = arguments; + if (typeof this.fail_callback === 'function') { + this.fail_callback.apply(this, this.error_arguments); + } + } + this.failed = true; + this.completed = true; + } + }; // end of promise + }; + self.waitAllPromises = function(arr_promise) { + var p = self.promise(); + var max_len = arr_promise.length; + var result = []; + function cmpl(r) { + result.push(r); + if (result.length == max_len) { + p.resolve(result); + } + }; + for (var i in arr_promise) { + arr_promise[i].done(cmpl).fail(cmpl); + } + return p; + }; + self.setToken = function(token) { + var date = new Date( new Date().getTime() + (7 * 24 * 60 * 60 * 1000) ); // cookie on week + document.cookie = 'SomeClienttoken=' + encodeURIComponent(token) + '; path=/; expires='+date.toUTCString(); + } + self.removeToken = function() { + _tokenValue = ''; document.cookie = 'SomeClienttoken=; path=/;'; + } + self.getToken = function() { + var matches = document.cookie.match(new RegExp( + '(?:^|; )' + 'SomeClienttoken'.replace(/([\.$?*|{}\(\)\[\]\\\/\+^])/g, '\\$1') + '=([^;]*)' + )); + return matches ? decodeURIComponent(matches[1]) : ''; + } + _tokenValue = self.getToken(); + self.bind = function(name, f) { _events[name].push(f); } + self.unbind = function(name) { _events[name] = []; } + function _call(name, data) { + function __call(f, data) { setTimeout(function() { f(data) },1)} for (var i = 0; i < _events[name].length; i++) { + __call(_events[name][i], data); + } + } + self.bind('server', function(response) { + console.warn('All: ', response); + if (response.app != self.appName) { + console.error('AppName: ' + response.app + ', but expected ' + self.appName); + } + if (response.version != self.appVersion) { + console.error('AppVersion: ' + response.version + ', but expected ' + self.appVersion); + } + }); + self.handleCommand = function(response) { + var lstn = _listeners[response.m]; + if (lstn) { + setTimeout(function() { + if (response['error']) { + lstn.reject(response); + } else { + lstn.resolve(response); + } + delete _listeners[response.m]; + },1); + } else if (_events[response.cmd]) { + _call(response.cmd, response); } else { + console.error('Not found handler for [' + response.cmd + '/' + response.m + ']'); + } + }; + self.send = function(obj, def) { + obj.m = obj.m || _lm(); + _listeners[obj.m] = def || self.promise(); + try { + if (self.socket.readyState == 0) { + setTimeout(function() { + self.send(obj, _listeners[obj.m]); + },1000); + } else { + self.socket.send(JSON.stringify(obj)); + } + } catch(e) { + console.error(e); + } + return _listeners[obj.m]; + } + self.init = function(initParams) { + if (!initParams.baseUrl) console.error('Expected baseUrl on initParams'); + self.socket = new WebSocket(initParams.baseUrl); + self.socket.onopen = function() { + console.log('WS Opened'); + _call('connected', {}); + if (_tokenValue != '') self.token(); + }; + self.socket.onclose = function(event) { + console.log('Closed'); + if (event.wasClean) { + _call('disconnected', {}); + } else { + _call('broken', {}); + setTimeout(function() { + _call('reconnecting', {}); + self.init(initParams); + }, 10000); + // Try reconnect after 5 sec + } + console.log('Code: ' + event.code + ' Reason: ' + event.reason); + }; + self.socket.onmessage = function(event) { + // console.log('Received: ' + event.data); + try { + var response = JSON.parse(event.data); + self.handleCommand(response); + } catch(e) { + console.error(e); + } + + }; + self.socket.onerror = function(error) { + console.log('Error: ' + error.message); + }; + } + self.deinit = function(initParams) { + self.removeToken(); + self.socket.close(); + } + self.userProfile = {bInitUserProfile: false} + self.updateUserProfileAsync = function() { + setTimeout(function() { + self.user().done(function(r) { + self.userProfile.bInitUserProfile == true; + self.userProfile.university = r.data.university; + self.userProfile.country = r.data.country; + self.userProfile.city = r.data.city; + self.userinfo = {}; + self.userinfo.id = r.data.id; + self.userinfo.nick = r.data.nick; + self.userinfo.email = r.data.email; + self.userinfo.role = r.data.role; + self.userinfo.logo = r.data.logo; + _call('userdata', r.data); + }).fail(function() { + self.removeToken(); + _call('userdata', {}); + }); + },10); + } + self.auth_login = function(params) { + // Access unauthorized: yes + // Access user: no + // Access tester: no + // Access admin: no + // Activated From Version: v0.0.2 + // Input params: + // * login - string, required (User Login) + // * password - string, required (User Password) + // * client_app_name - string, optional (Client app name) + // * client_app_version - string, optional (Client app version) + params = params || {}; + params.cmd = 'auth_login'; + if (params['login'] == undefined) { + console.error('Parameter "login" expected (lib)'); + } + if (params['password'] == undefined) { + console.error('Parameter "password" expected (lib)'); + } + return self.send(params); + } + + self.auth_logoff = function(params) { + // Access unauthorized: no + // Access user: yes + // Access tester: yes + // Access admin: yes + // Activated From Version: v0.0.2 + params = params || {}; + params.cmd = 'auth_logoff'; + return self.send(params); + } + + self.auth_token = function(params) { + // Access unauthorized: yes + // Access user: no + // Access tester: no + // Access admin: no + // Activated From Version: v0.0.2 + // Input params: + // * token - string, required (Token) + // * client_app_name - string, optional (Client app name) + // * client_app_version - string, optional (Client app version) + params = params || {}; + params.cmd = 'auth_token'; + if (params['token'] == undefined) { + console.error('Parameter "token" expected (lib)'); + } + return self.send(params); + } + + self.game_create = function(params) { + // Access unauthorized: no + // Access user: yes + // Access tester: yes + // Access admin: yes + // Activated From Version: v0.0.2 + // Input params: + // * uuid - string, required (object uuid) + // * name - string, optional (Name of object) + // * cost - integer, required (Name of object) + // * age - integer, optional (Name of object) + // * public - boolean, required (True if object is public) + // * activated - boolean, optional (If object can handle) + // * custom - json, optional (Some custom json) + params = params || {}; + params.cmd = 'game_create'; + if (params['uuid'] == undefined) { + console.error('Parameter "uuid" expected (lib)'); + } + if (params['cost'] == undefined) { + console.error('Parameter "cost" expected (lib)'); + } + if (params['public'] == undefined) { + console.error('Parameter "public" expected (lib)'); + } + return self.send(params); + } + + self.server_api = function(params) { + // Access unauthorized: yes + // Access user: yes + // Access tester: yes + // Access admin: yes + params = params || {}; + params.cmd = 'server_api'; + return self.send(params); + } + + return self; +})(); diff --git a/example-of-exported/webjs/package.json b/example-of-exported/webjs/package.json new file mode 100644 index 0000000..6d123d1 --- /dev/null +++ b/example-of-exported/webjs/package.json @@ -0,0 +1,25 @@ +{ + "name": "libwsjcppjson20client", + "version": "v0.0.4", + "description": "SomeClient JavaScript Web Client Library for wsjcpp-jsonrpc20", + "main": "dist/libwsjcppjson20client.js", + "repository": { + "type": "git", + "url": "https://github.com/wsjcpp/wsjcpp-jsonrpc20.git" + }, + "keywords": [ + "wsjcpp-jsonrpc20", + "wsjcpp", + "jsonrpc20", + "example-client-webjs" + ], + "bugs": { + "url": "https://github.com/wsjcpp/wsjcpp-jsonrpc20/issues" + }, + "author": "Evgenii Sopov ", + "license": "MIT", + "licenses": [{ + "type": "MIT", + "url": "https://raw.githubusercontent.com/wsjcpp/wsjcpp-jsonrpc20/master/LICENSE" + }] +} diff --git a/example-of-exported/webjs/sample.html b/example-of-exported/webjs/sample.html new file mode 100644 index 0000000..e10deae --- /dev/null +++ b/example-of-exported/webjs/sample.html @@ -0,0 +1,69 @@ + + + + + + +
+

Connect to Server

+
+ +
+ + + +

+
+
diff --git a/src.wsjcpp/CMakeLists.txt b/src.wsjcpp/CMakeLists.txt
index 3a217c9..7cc31e7 100644
--- a/src.wsjcpp/CMakeLists.txt
+++ b/src.wsjcpp/CMakeLists.txt
@@ -1,7 +1,7 @@
-# Automaticly generated by wsjcpp@v0.1.7
+# Automaticly generated by wsjcpp@v0.2.0
 cmake_minimum_required(VERSION 3.0)
 
-add_definitions(-DWSJCPP_APP_VERSION="v0.0.3")
+add_definitions(-DWSJCPP_APP_VERSION="v0.0.4")
 add_definitions(-DWSJCPP_APP_NAME="wsjcpp-jsonrpc20")
 
 if (${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
@@ -17,12 +17,10 @@ set (WSJCPP_SOURCES "")
 find_package(Threads REQUIRED)
 list (APPEND WSJCPP_LIBRARIES ${CMAKE_THREAD_LIBS_INIT})
 
-# wsjcpp-core:v0.2.0
+# wsjcpp-core:v0.2.1
 list (APPEND WSJCPP_INCLUDE_DIRS "./src.wsjcpp/wsjcpp_core/")
 list (APPEND WSJCPP_SOURCES "./src.wsjcpp/wsjcpp_core/wsjcpp_core.cpp")
 list (APPEND WSJCPP_SOURCES "./src.wsjcpp/wsjcpp_core/wsjcpp_core.h")
-list (APPEND WSJCPP_SOURCES "./src.wsjcpp/wsjcpp_core/wsjcpp_resources_manager.h")
-list (APPEND WSJCPP_SOURCES "./src.wsjcpp/wsjcpp_core/wsjcpp_resources_manager.cpp")
 
 # nlohmann/json:v3.9.1
 list (APPEND WSJCPP_INCLUDE_DIRS "./src.wsjcpp/nlohmann_json/")
@@ -33,4 +31,7 @@ list (APPEND WSJCPP_INCLUDE_DIRS "./src.wsjcpp/wsjcpp_validators/")
 list (APPEND WSJCPP_SOURCES "./src.wsjcpp/wsjcpp_validators/wsjcpp_validators.h")
 list (APPEND WSJCPP_SOURCES "./src.wsjcpp/wsjcpp_validators/wsjcpp_validators.cpp")
 
+# required-libraries
+list (APPEND WSJCPP_LIBRARIES "-lpthread")
+
 
diff --git a/src.wsjcpp/nlohmann_json/json.hpp b/src.wsjcpp/nlohmann_json/json.hpp
index 7d107f2..e821c79 100644
--- a/src.wsjcpp/nlohmann_json/json.hpp
+++ b/src.wsjcpp/nlohmann_json/json.hpp
@@ -119,11 +119,11 @@ struct position_t
  * SPDX-License-Identifier: CC0-1.0
  */
 
-#if !defined(JSON_HEDLEY_VERSION) || (JSON_HEDLEY_VERSION < 13)
+#if !defined(JSON_HEDLEY_VERSION) || (JSON_HEDLEY_VERSION < 14)
 #if defined(JSON_HEDLEY_VERSION)
     #undef JSON_HEDLEY_VERSION
 #endif
-#define JSON_HEDLEY_VERSION 13
+#define JSON_HEDLEY_VERSION 14
 
 #if defined(JSON_HEDLEY_STRINGIFY_EX)
     #undef JSON_HEDLEY_STRINGIFY_EX
@@ -196,18 +196,18 @@ struct position_t
 #if defined(JSON_HEDLEY_MSVC_VERSION)
     #undef JSON_HEDLEY_MSVC_VERSION
 #endif
-#if defined(_MSC_FULL_VER) && (_MSC_FULL_VER >= 140000000)
+#if defined(_MSC_FULL_VER) && (_MSC_FULL_VER >= 140000000) && !defined(__ICL)
     #define JSON_HEDLEY_MSVC_VERSION JSON_HEDLEY_VERSION_ENCODE(_MSC_FULL_VER / 10000000, (_MSC_FULL_VER % 10000000) / 100000, (_MSC_FULL_VER % 100000) / 100)
-#elif defined(_MSC_FULL_VER)
+#elif defined(_MSC_FULL_VER) && !defined(__ICL)
     #define JSON_HEDLEY_MSVC_VERSION JSON_HEDLEY_VERSION_ENCODE(_MSC_FULL_VER / 1000000, (_MSC_FULL_VER % 1000000) / 10000, (_MSC_FULL_VER % 10000) / 10)
-#elif defined(_MSC_VER)
+#elif defined(_MSC_VER) && !defined(__ICL)
     #define JSON_HEDLEY_MSVC_VERSION JSON_HEDLEY_VERSION_ENCODE(_MSC_VER / 100, _MSC_VER % 100, 0)
 #endif
 
 #if defined(JSON_HEDLEY_MSVC_VERSION_CHECK)
     #undef JSON_HEDLEY_MSVC_VERSION_CHECK
 #endif
-#if !defined(_MSC_VER)
+#if !defined(JSON_HEDLEY_MSVC_VERSION)
     #define JSON_HEDLEY_MSVC_VERSION_CHECK(major,minor,patch) (0)
 #elif defined(_MSC_VER) && (_MSC_VER >= 1400)
     #define JSON_HEDLEY_MSVC_VERSION_CHECK(major,minor,patch) (_MSC_FULL_VER >= ((major * 10000000) + (minor * 100000) + (patch)))
@@ -220,9 +220,9 @@ struct position_t
 #if defined(JSON_HEDLEY_INTEL_VERSION)
     #undef JSON_HEDLEY_INTEL_VERSION
 #endif
-#if defined(__INTEL_COMPILER) && defined(__INTEL_COMPILER_UPDATE)
+#if defined(__INTEL_COMPILER) && defined(__INTEL_COMPILER_UPDATE) && !defined(__ICL)
     #define JSON_HEDLEY_INTEL_VERSION JSON_HEDLEY_VERSION_ENCODE(__INTEL_COMPILER / 100, __INTEL_COMPILER % 100, __INTEL_COMPILER_UPDATE)
-#elif defined(__INTEL_COMPILER)
+#elif defined(__INTEL_COMPILER) && !defined(__ICL)
     #define JSON_HEDLEY_INTEL_VERSION JSON_HEDLEY_VERSION_ENCODE(__INTEL_COMPILER / 100, __INTEL_COMPILER % 100, 0)
 #endif
 
@@ -235,6 +235,22 @@ struct position_t
     #define JSON_HEDLEY_INTEL_VERSION_CHECK(major,minor,patch) (0)
 #endif
 
+#if defined(JSON_HEDLEY_INTEL_CL_VERSION)
+    #undef JSON_HEDLEY_INTEL_CL_VERSION
+#endif
+#if defined(__INTEL_COMPILER) && defined(__INTEL_COMPILER_UPDATE) && defined(__ICL)
+    #define JSON_HEDLEY_INTEL_CL_VERSION JSON_HEDLEY_VERSION_ENCODE(__INTEL_COMPILER, __INTEL_COMPILER_UPDATE, 0)
+#endif
+
+#if defined(JSON_HEDLEY_INTEL_CL_VERSION_CHECK)
+    #undef JSON_HEDLEY_INTEL_CL_VERSION_CHECK
+#endif
+#if defined(JSON_HEDLEY_INTEL_CL_VERSION)
+    #define JSON_HEDLEY_INTEL_CL_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_INTEL_CL_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch))
+#else
+    #define JSON_HEDLEY_INTEL_CL_VERSION_CHECK(major,minor,patch) (0)
+#endif
+
 #if defined(JSON_HEDLEY_PGI_VERSION)
     #undef JSON_HEDLEY_PGI_VERSION
 #endif
@@ -787,6 +803,72 @@ struct position_t
     #define JSON_HEDLEY_GCC_HAS_WARNING(warning,major,minor,patch) JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch)
 #endif
 
+#if \
+    (defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)) || \
+    defined(__clang__) || \
+    JSON_HEDLEY_GCC_VERSION_CHECK(3,0,0) || \
+    JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \
+    JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0) || \
+    JSON_HEDLEY_PGI_VERSION_CHECK(18,4,0) || \
+    JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \
+    JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \
+    JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,7,0) || \
+    JSON_HEDLEY_TI_CL430_VERSION_CHECK(2,0,1) || \
+    JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,1,0) || \
+    JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,0,0) || \
+    JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \
+    JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \
+    JSON_HEDLEY_CRAY_VERSION_CHECK(5,0,0) || \
+    JSON_HEDLEY_TINYC_VERSION_CHECK(0,9,17) || \
+    JSON_HEDLEY_SUNPRO_VERSION_CHECK(8,0,0) || \
+    (JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) && defined(__C99_PRAGMA_OPERATOR))
+    #define JSON_HEDLEY_PRAGMA(value) _Pragma(#value)
+#elif JSON_HEDLEY_MSVC_VERSION_CHECK(15,0,0)
+    #define JSON_HEDLEY_PRAGMA(value) __pragma(value)
+#else
+    #define JSON_HEDLEY_PRAGMA(value)
+#endif
+
+#if defined(JSON_HEDLEY_DIAGNOSTIC_PUSH)
+    #undef JSON_HEDLEY_DIAGNOSTIC_PUSH
+#endif
+#if defined(JSON_HEDLEY_DIAGNOSTIC_POP)
+    #undef JSON_HEDLEY_DIAGNOSTIC_POP
+#endif
+#if defined(__clang__)
+    #define JSON_HEDLEY_DIAGNOSTIC_PUSH _Pragma("clang diagnostic push")
+    #define JSON_HEDLEY_DIAGNOSTIC_POP _Pragma("clang diagnostic pop")
+#elif JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0)
+    #define JSON_HEDLEY_DIAGNOSTIC_PUSH _Pragma("warning(push)")
+    #define JSON_HEDLEY_DIAGNOSTIC_POP _Pragma("warning(pop)")
+#elif JSON_HEDLEY_GCC_VERSION_CHECK(4,6,0)
+    #define JSON_HEDLEY_DIAGNOSTIC_PUSH _Pragma("GCC diagnostic push")
+    #define JSON_HEDLEY_DIAGNOSTIC_POP _Pragma("GCC diagnostic pop")
+#elif \
+    JSON_HEDLEY_MSVC_VERSION_CHECK(15,0,0) || \
+    JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0)
+    #define JSON_HEDLEY_DIAGNOSTIC_PUSH __pragma(warning(push))
+    #define JSON_HEDLEY_DIAGNOSTIC_POP __pragma(warning(pop))
+#elif JSON_HEDLEY_ARM_VERSION_CHECK(5,6,0)
+    #define JSON_HEDLEY_DIAGNOSTIC_PUSH _Pragma("push")
+    #define JSON_HEDLEY_DIAGNOSTIC_POP _Pragma("pop")
+#elif \
+    JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \
+    JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \
+    JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,4,0) || \
+    JSON_HEDLEY_TI_CL6X_VERSION_CHECK(8,1,0) || \
+    JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \
+    JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0)
+    #define JSON_HEDLEY_DIAGNOSTIC_PUSH _Pragma("diag_push")
+    #define JSON_HEDLEY_DIAGNOSTIC_POP _Pragma("diag_pop")
+#elif JSON_HEDLEY_PELLES_VERSION_CHECK(2,90,0)
+    #define JSON_HEDLEY_DIAGNOSTIC_PUSH _Pragma("warning(push)")
+    #define JSON_HEDLEY_DIAGNOSTIC_POP _Pragma("warning(pop)")
+#else
+    #define JSON_HEDLEY_DIAGNOSTIC_PUSH
+    #define JSON_HEDLEY_DIAGNOSTIC_POP
+#endif
+
 /* JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_ is for
    HEDLEY INTERNAL USE ONLY.  API subject to change without notice. */
 #if defined(JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_)
@@ -795,12 +877,22 @@ struct position_t
 #if defined(__cplusplus)
 #  if JSON_HEDLEY_HAS_WARNING("-Wc++98-compat")
 #    if JSON_HEDLEY_HAS_WARNING("-Wc++17-extensions")
-#      define JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_(xpr) \
+#      if JSON_HEDLEY_HAS_WARNING("-Wc++1z-extensions")
+#        define JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_(xpr) \
+    JSON_HEDLEY_DIAGNOSTIC_PUSH \
+    _Pragma("clang diagnostic ignored \"-Wc++98-compat\"") \
+    _Pragma("clang diagnostic ignored \"-Wc++17-extensions\"") \
+    _Pragma("clang diagnostic ignored \"-Wc++1z-extensions\"") \
+    xpr \
+    JSON_HEDLEY_DIAGNOSTIC_POP
+#      else
+#        define JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_(xpr) \
     JSON_HEDLEY_DIAGNOSTIC_PUSH \
     _Pragma("clang diagnostic ignored \"-Wc++98-compat\"") \
     _Pragma("clang diagnostic ignored \"-Wc++17-extensions\"") \
     xpr \
     JSON_HEDLEY_DIAGNOSTIC_POP
+#      endif
 #    else
 #      define JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_(xpr) \
     JSON_HEDLEY_DIAGNOSTIC_PUSH \
@@ -865,7 +957,7 @@ struct position_t
 #    define JSON_HEDLEY_CPP_CAST(T, expr) \
     JSON_HEDLEY_DIAGNOSTIC_PUSH \
     _Pragma("diag_suppress=Pe137") \
-    JSON_HEDLEY_DIAGNOSTIC_POP \
+    JSON_HEDLEY_DIAGNOSTIC_POP
 #  else
 #    define JSON_HEDLEY_CPP_CAST(T, expr) ((T) (expr))
 #  endif
@@ -873,70 +965,6 @@ struct position_t
 #  define JSON_HEDLEY_CPP_CAST(T, expr) (expr)
 #endif
 
-#if \
-    (defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)) || \
-    defined(__clang__) || \
-    JSON_HEDLEY_GCC_VERSION_CHECK(3,0,0) || \
-    JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \
-    JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0) || \
-    JSON_HEDLEY_PGI_VERSION_CHECK(18,4,0) || \
-    JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \
-    JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \
-    JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,7,0) || \
-    JSON_HEDLEY_TI_CL430_VERSION_CHECK(2,0,1) || \
-    JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,1,0) || \
-    JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,0,0) || \
-    JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \
-    JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \
-    JSON_HEDLEY_CRAY_VERSION_CHECK(5,0,0) || \
-    JSON_HEDLEY_TINYC_VERSION_CHECK(0,9,17) || \
-    JSON_HEDLEY_SUNPRO_VERSION_CHECK(8,0,0) || \
-    (JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) && defined(__C99_PRAGMA_OPERATOR))
-    #define JSON_HEDLEY_PRAGMA(value) _Pragma(#value)
-#elif JSON_HEDLEY_MSVC_VERSION_CHECK(15,0,0)
-    #define JSON_HEDLEY_PRAGMA(value) __pragma(value)
-#else
-    #define JSON_HEDLEY_PRAGMA(value)
-#endif
-
-#if defined(JSON_HEDLEY_DIAGNOSTIC_PUSH)
-    #undef JSON_HEDLEY_DIAGNOSTIC_PUSH
-#endif
-#if defined(JSON_HEDLEY_DIAGNOSTIC_POP)
-    #undef JSON_HEDLEY_DIAGNOSTIC_POP
-#endif
-#if defined(__clang__)
-    #define JSON_HEDLEY_DIAGNOSTIC_PUSH _Pragma("clang diagnostic push")
-    #define JSON_HEDLEY_DIAGNOSTIC_POP _Pragma("clang diagnostic pop")
-#elif JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0)
-    #define JSON_HEDLEY_DIAGNOSTIC_PUSH _Pragma("warning(push)")
-    #define JSON_HEDLEY_DIAGNOSTIC_POP _Pragma("warning(pop)")
-#elif JSON_HEDLEY_GCC_VERSION_CHECK(4,6,0)
-    #define JSON_HEDLEY_DIAGNOSTIC_PUSH _Pragma("GCC diagnostic push")
-    #define JSON_HEDLEY_DIAGNOSTIC_POP _Pragma("GCC diagnostic pop")
-#elif JSON_HEDLEY_MSVC_VERSION_CHECK(15,0,0)
-    #define JSON_HEDLEY_DIAGNOSTIC_PUSH __pragma(warning(push))
-    #define JSON_HEDLEY_DIAGNOSTIC_POP __pragma(warning(pop))
-#elif JSON_HEDLEY_ARM_VERSION_CHECK(5,6,0)
-    #define JSON_HEDLEY_DIAGNOSTIC_PUSH _Pragma("push")
-    #define JSON_HEDLEY_DIAGNOSTIC_POP _Pragma("pop")
-#elif \
-    JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \
-    JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \
-    JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,4,0) || \
-    JSON_HEDLEY_TI_CL6X_VERSION_CHECK(8,1,0) || \
-    JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \
-    JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0)
-    #define JSON_HEDLEY_DIAGNOSTIC_PUSH _Pragma("diag_push")
-    #define JSON_HEDLEY_DIAGNOSTIC_POP _Pragma("diag_pop")
-#elif JSON_HEDLEY_PELLES_VERSION_CHECK(2,90,0)
-    #define JSON_HEDLEY_DIAGNOSTIC_PUSH _Pragma("warning(push)")
-    #define JSON_HEDLEY_DIAGNOSTIC_POP _Pragma("warning(pop)")
-#else
-    #define JSON_HEDLEY_DIAGNOSTIC_PUSH
-    #define JSON_HEDLEY_DIAGNOSTIC_POP
-#endif
-
 #if defined(JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED)
     #undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED
 #endif
@@ -944,6 +972,10 @@ struct position_t
     #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("clang diagnostic ignored \"-Wdeprecated-declarations\"")
 #elif JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0)
     #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("warning(disable:1478 1786)")
+#elif JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0)
+    #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED __pragma(warning(disable:1478 1786))
+#elif JSON_HEDLEY_PGI_VERSION_CHECK(20,7,0)
+    #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("diag_suppress 1215,1216,1444,1445")
 #elif JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0)
     #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("diag_suppress 1215,1444")
 #elif JSON_HEDLEY_GCC_VERSION_CHECK(4,3,0)
@@ -982,6 +1014,8 @@ struct position_t
     #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("clang diagnostic ignored \"-Wunknown-pragmas\"")
 #elif JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0)
     #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("warning(disable:161)")
+#elif JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0)
+    #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS __pragma(warning(disable:161))
 #elif JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0)
     #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("diag_suppress 1675")
 #elif JSON_HEDLEY_GCC_VERSION_CHECK(4,3,0)
@@ -1011,8 +1045,12 @@ struct position_t
     #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("GCC diagnostic ignored \"-Wdeprecated-declarations\"")
 #elif JSON_HEDLEY_INTEL_VERSION_CHECK(17,0,0)
     #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("warning(disable:1292)")
+#elif JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0)
+    #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES __pragma(warning(disable:1292))
 #elif JSON_HEDLEY_MSVC_VERSION_CHECK(19,0,0)
     #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES __pragma(warning(disable:5030))
+#elif JSON_HEDLEY_PGI_VERSION_CHECK(20,7,0)
+    #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("diag_suppress 1097,1098")
 #elif JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0)
     #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("diag_suppress 1097")
 #elif JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,14,0) && defined(__cplusplus)
@@ -1047,12 +1085,11 @@ struct position_t
 #if defined(JSON_HEDLEY_DEPRECATED_FOR)
     #undef JSON_HEDLEY_DEPRECATED_FOR
 #endif
-#if JSON_HEDLEY_MSVC_VERSION_CHECK(14,0,0)
+#if \
+    JSON_HEDLEY_MSVC_VERSION_CHECK(14,0,0) || \
+    JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0)
     #define JSON_HEDLEY_DEPRECATED(since) __declspec(deprecated("Since " # since))
     #define JSON_HEDLEY_DEPRECATED_FOR(since, replacement) __declspec(deprecated("Since " #since "; use " #replacement))
-#elif defined(__cplusplus) && (__cplusplus >= 201402L)
-    #define JSON_HEDLEY_DEPRECATED(since) JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[deprecated("Since " #since)]])
-    #define JSON_HEDLEY_DEPRECATED_FOR(since, replacement) JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[deprecated("Since " #since "; use " #replacement)]])
 #elif \
     JSON_HEDLEY_HAS_EXTENSION(attribute_deprecated_with_message) || \
     JSON_HEDLEY_GCC_VERSION_CHECK(4,5,0) || \
@@ -1067,6 +1104,9 @@ struct position_t
     JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,3,0)
     #define JSON_HEDLEY_DEPRECATED(since) __attribute__((__deprecated__("Since " #since)))
     #define JSON_HEDLEY_DEPRECATED_FOR(since, replacement) __attribute__((__deprecated__("Since " #since "; use " #replacement)))
+#elif defined(__cplusplus) && (__cplusplus >= 201402L)
+    #define JSON_HEDLEY_DEPRECATED(since) JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[deprecated("Since " #since)]])
+    #define JSON_HEDLEY_DEPRECATED_FOR(since, replacement) JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[deprecated("Since " #since "; use " #replacement)]])
 #elif \
     JSON_HEDLEY_HAS_ATTRIBUTE(deprecated) || \
     JSON_HEDLEY_GCC_VERSION_CHECK(3,1,0) || \
@@ -1086,7 +1126,8 @@ struct position_t
     #define JSON_HEDLEY_DEPRECATED_FOR(since, replacement) __attribute__((__deprecated__))
 #elif \
     JSON_HEDLEY_MSVC_VERSION_CHECK(13,10,0) || \
-    JSON_HEDLEY_PELLES_VERSION_CHECK(6,50,0)
+    JSON_HEDLEY_PELLES_VERSION_CHECK(6,50,0) || \
+    JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0)
     #define JSON_HEDLEY_DEPRECATED(since) __declspec(deprecated)
     #define JSON_HEDLEY_DEPRECATED_FOR(since, replacement) __declspec(deprecated)
 #elif JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0)
@@ -1115,13 +1156,7 @@ struct position_t
 #if defined(JSON_HEDLEY_WARN_UNUSED_RESULT_MSG)
     #undef JSON_HEDLEY_WARN_UNUSED_RESULT_MSG
 #endif
-#if (JSON_HEDLEY_HAS_CPP_ATTRIBUTE(nodiscard) >= 201907L)
-    #define JSON_HEDLEY_WARN_UNUSED_RESULT JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[nodiscard]])
-    #define JSON_HEDLEY_WARN_UNUSED_RESULT_MSG(msg) JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[nodiscard(msg)]])
-#elif JSON_HEDLEY_HAS_CPP_ATTRIBUTE(nodiscard)
-    #define JSON_HEDLEY_WARN_UNUSED_RESULT JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[nodiscard]])
-    #define JSON_HEDLEY_WARN_UNUSED_RESULT_MSG(msg) JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[nodiscard]])
-#elif \
+#if \
     JSON_HEDLEY_HAS_ATTRIBUTE(warn_unused_result) || \
     JSON_HEDLEY_GCC_VERSION_CHECK(3,4,0) || \
     JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \
@@ -1140,6 +1175,12 @@ struct position_t
     JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0)
     #define JSON_HEDLEY_WARN_UNUSED_RESULT __attribute__((__warn_unused_result__))
     #define JSON_HEDLEY_WARN_UNUSED_RESULT_MSG(msg) __attribute__((__warn_unused_result__))
+#elif (JSON_HEDLEY_HAS_CPP_ATTRIBUTE(nodiscard) >= 201907L)
+    #define JSON_HEDLEY_WARN_UNUSED_RESULT JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[nodiscard]])
+    #define JSON_HEDLEY_WARN_UNUSED_RESULT_MSG(msg) JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[nodiscard(msg)]])
+#elif JSON_HEDLEY_HAS_CPP_ATTRIBUTE(nodiscard)
+    #define JSON_HEDLEY_WARN_UNUSED_RESULT JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[nodiscard]])
+    #define JSON_HEDLEY_WARN_UNUSED_RESULT_MSG(msg) JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[nodiscard]])
 #elif defined(_Check_return_) /* SAL */
     #define JSON_HEDLEY_WARN_UNUSED_RESULT _Check_return_
     #define JSON_HEDLEY_WARN_UNUSED_RESULT_MSG(msg) _Check_return_
@@ -1192,7 +1233,9 @@ struct position_t
     #define JSON_HEDLEY_NO_RETURN __attribute__((__noreturn__))
 #elif JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,10,0)
     #define JSON_HEDLEY_NO_RETURN _Pragma("does_not_return")
-#elif JSON_HEDLEY_MSVC_VERSION_CHECK(13,10,0)
+#elif \
+    JSON_HEDLEY_MSVC_VERSION_CHECK(13,10,0) || \
+    JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0)
     #define JSON_HEDLEY_NO_RETURN __declspec(noreturn)
 #elif JSON_HEDLEY_TI_CL6X_VERSION_CHECK(6,0,0) && defined(__cplusplus)
     #define JSON_HEDLEY_NO_RETURN _Pragma("FUNC_NEVER_RETURNS;")
@@ -1224,7 +1267,8 @@ struct position_t
 #endif
 #if \
     JSON_HEDLEY_MSVC_VERSION_CHECK(13,10,0) || \
-    JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0)
+    JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \
+    JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0)
     #define JSON_HEDLEY_ASSUME(expr) __assume(expr)
 #elif JSON_HEDLEY_HAS_BUILTIN(__builtin_assume)
     #define JSON_HEDLEY_ASSUME(expr) __builtin_assume(expr)
@@ -1356,7 +1400,7 @@ JSON_HEDLEY_DIAGNOSTIC_POP
     #define JSON_HEDLEY_UNPREDICTABLE(expr) __builtin_unpredictable((expr))
 #endif
 #if \
-  JSON_HEDLEY_HAS_BUILTIN(__builtin_expect_with_probability) || \
+  (JSON_HEDLEY_HAS_BUILTIN(__builtin_expect_with_probability) && !defined(JSON_HEDLEY_PGI_VERSION)) || \
   JSON_HEDLEY_GCC_VERSION_CHECK(9,0,0)
 #  define JSON_HEDLEY_PREDICT(expr, value, probability) __builtin_expect_with_probability(  (expr), (value), (probability))
 #  define JSON_HEDLEY_PREDICT_TRUE(expr, probability)   __builtin_expect_with_probability(!!(expr),    1   , (probability))
@@ -1364,7 +1408,7 @@ JSON_HEDLEY_DIAGNOSTIC_POP
 #  define JSON_HEDLEY_LIKELY(expr)                      __builtin_expect                 (!!(expr),    1                  )
 #  define JSON_HEDLEY_UNLIKELY(expr)                    __builtin_expect                 (!!(expr),    0                  )
 #elif \
-  JSON_HEDLEY_HAS_BUILTIN(__builtin_expect) || \
+  (JSON_HEDLEY_HAS_BUILTIN(__builtin_expect) && !defined(JSON_HEDLEY_INTEL_CL_VERSION)) || \
   JSON_HEDLEY_GCC_VERSION_CHECK(3,0,0) || \
   JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \
   (JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,15,0) && defined(__cplusplus)) || \
@@ -1428,7 +1472,9 @@ JSON_HEDLEY_DIAGNOSTIC_POP
     #define JSON_HEDLEY_MALLOC __attribute__((__malloc__))
 #elif JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,10,0)
     #define JSON_HEDLEY_MALLOC _Pragma("returns_new_memory")
-#elif JSON_HEDLEY_MSVC_VERSION_CHECK(14, 0, 0)
+#elif \
+    JSON_HEDLEY_MSVC_VERSION_CHECK(14,0,0) || \
+    JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0)
     #define JSON_HEDLEY_MALLOC __declspec(restrict)
 #else
     #define JSON_HEDLEY_MALLOC
@@ -1509,6 +1555,7 @@ JSON_HEDLEY_DIAGNOSTIC_POP
     JSON_HEDLEY_GCC_VERSION_CHECK(3,1,0) || \
     JSON_HEDLEY_MSVC_VERSION_CHECK(14,0,0) || \
     JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \
+    JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) || \
     JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \
     JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) || \
     JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0) || \
@@ -1539,6 +1586,7 @@ JSON_HEDLEY_DIAGNOSTIC_POP
     #define JSON_HEDLEY_INLINE __inline__
 #elif \
     JSON_HEDLEY_MSVC_VERSION_CHECK(12,0,0) || \
+    JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) || \
     JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \
     JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,1,0) || \
     JSON_HEDLEY_TI_CL430_VERSION_CHECK(3,1,0) || \
@@ -1573,7 +1621,9 @@ JSON_HEDLEY_DIAGNOSTIC_POP
   JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \
   JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0)
 #  define JSON_HEDLEY_ALWAYS_INLINE __attribute__((__always_inline__)) JSON_HEDLEY_INLINE
-#elif JSON_HEDLEY_MSVC_VERSION_CHECK(12,0,0)
+#elif \
+  JSON_HEDLEY_MSVC_VERSION_CHECK(12,0,0) || \
+  JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0)
 #  define JSON_HEDLEY_ALWAYS_INLINE __forceinline
 #elif defined(__cplusplus) && \
     ( \
@@ -1613,7 +1663,9 @@ JSON_HEDLEY_DIAGNOSTIC_POP
     JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \
     JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0)
     #define JSON_HEDLEY_NEVER_INLINE __attribute__((__noinline__))
-#elif JSON_HEDLEY_MSVC_VERSION_CHECK(13,10,0)
+#elif \
+    JSON_HEDLEY_MSVC_VERSION_CHECK(13,10,0) || \
+    JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0)
     #define JSON_HEDLEY_NEVER_INLINE __declspec(noinline)
 #elif JSON_HEDLEY_PGI_VERSION_CHECK(10,2,0)
     #define JSON_HEDLEY_NEVER_INLINE _Pragma("noinline")
@@ -1676,6 +1728,7 @@ JSON_HEDLEY_DIAGNOSTIC_POP
     #define JSON_HEDLEY_NO_THROW __attribute__((__nothrow__))
 #elif \
     JSON_HEDLEY_MSVC_VERSION_CHECK(13,1,0) || \
+    JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) || \
     JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0)
     #define JSON_HEDLEY_NO_THROW __declspec(nothrow)
 #else
@@ -1840,7 +1893,7 @@ JSON_HEDLEY_DIAGNOSTIC_POP
 #if \
   !defined(__cplusplus) && ( \
       (defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L)) || \
-      JSON_HEDLEY_HAS_FEATURE(c_static_assert) || \
+      (JSON_HEDLEY_HAS_FEATURE(c_static_assert) && !defined(JSON_HEDLEY_INTEL_CL_VERSION)) || \
       JSON_HEDLEY_GCC_VERSION_CHECK(6,0,0) || \
       JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \
       defined(_Static_assert) \
@@ -1848,7 +1901,8 @@ JSON_HEDLEY_DIAGNOSTIC_POP
 #  define JSON_HEDLEY_STATIC_ASSERT(expr, message) _Static_assert(expr, message)
 #elif \
   (defined(__cplusplus) && (__cplusplus >= 201103L)) || \
-  JSON_HEDLEY_MSVC_VERSION_CHECK(16,0,0)
+  JSON_HEDLEY_MSVC_VERSION_CHECK(16,0,0) || \
+  JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0)
 #  define JSON_HEDLEY_STATIC_ASSERT(expr, message) JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_(static_assert(expr, message))
 #else
 #  define JSON_HEDLEY_STATIC_ASSERT(expr, message)
@@ -1908,7 +1962,9 @@ JSON_HEDLEY_DIAGNOSTIC_POP
   JSON_HEDLEY_PGI_VERSION_CHECK(18,4,0) || \
   JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0)
 #  define JSON_HEDLEY_WARNING(msg) JSON_HEDLEY_PRAGMA(GCC warning msg)
-#elif JSON_HEDLEY_MSVC_VERSION_CHECK(15,0,0)
+#elif \
+  JSON_HEDLEY_MSVC_VERSION_CHECK(15,0,0) || \
+  JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0)
 #  define JSON_HEDLEY_WARNING(msg) JSON_HEDLEY_PRAGMA(message(msg))
 #else
 #  define JSON_HEDLEY_WARNING(msg) JSON_HEDLEY_MESSAGE(msg)
@@ -1946,6 +2002,8 @@ JSON_HEDLEY_DIAGNOSTIC_POP
 #endif
 #if JSON_HEDLEY_HAS_ATTRIBUTE(flag_enum)
     #define JSON_HEDLEY_FLAGS __attribute__((__flag_enum__))
+#else
+    #define JSON_HEDLEY_FLAGS
 #endif
 
 #if defined(JSON_HEDLEY_FLAGS_CAST)
@@ -1965,7 +2023,9 @@ JSON_HEDLEY_DIAGNOSTIC_POP
 #if defined(JSON_HEDLEY_EMPTY_BASES)
     #undef JSON_HEDLEY_EMPTY_BASES
 #endif
-#if JSON_HEDLEY_MSVC_VERSION_CHECK(19,0,23918) && !JSON_HEDLEY_MSVC_VERSION_CHECK(20,0,0)
+#if \
+    (JSON_HEDLEY_MSVC_VERSION_CHECK(19,0,23918) && !JSON_HEDLEY_MSVC_VERSION_CHECK(20,0,0)) || \
+    JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0)
     #define JSON_HEDLEY_EMPTY_BASES __declspec(empty_bases)
 #else
     #define JSON_HEDLEY_EMPTY_BASES
@@ -2100,6 +2160,13 @@ JSON_HEDLEY_DIAGNOSTIC_POP
     #define JSON_ASSERT(x) assert(x)
 #endif
 
+// allow to access some private functions (needed by the test suite)
+#if defined(JSON_TESTS_PRIVATE)
+    #define JSON_PRIVATE_UNLESS_TESTED public
+#else
+    #define JSON_PRIVATE_UNLESS_TESTED private
+#endif
+
 /*!
 @brief macro to briefly define a mapping between an enum and JSON
 @def NLOHMANN_JSON_SERIALIZE_ENUM
@@ -10642,6 +10709,7 @@ class primitive_iterator_t
     static constexpr difference_type begin_value = 0;
     static constexpr difference_type end_value = begin_value + 1;
 
+  JSON_PRIVATE_UNLESS_TESTED:
     /// iterator as signed integer type
     difference_type m_it = (std::numeric_limits::min)();
 
@@ -10934,7 +11002,7 @@ class iter_impl
         return *this;
     }
 
-  private:
+  JSON_PRIVATE_UNLESS_TESTED:
     /*!
     @brief set the iterator to the first value
     @pre The iterator is initialized; i.e. `m_object != nullptr`.
@@ -11398,7 +11466,7 @@ class iter_impl
         return operator*();
     }
 
-  private:
+  JSON_PRIVATE_UNLESS_TESTED:
     /// associated JSON instance
     pointer m_object = nullptr;
     /// the actual iterator of the associated instance
@@ -11913,6 +11981,7 @@ class json_pointer
         return static_cast(res);
     }
 
+  JSON_PRIVATE_UNLESS_TESTED:
     json_pointer top() const
     {
         if (JSON_HEDLEY_UNLIKELY(empty()))
@@ -11925,6 +11994,7 @@ class json_pointer
         return result;
     }
 
+  private:
     /*!
     @brief create and return a reference to the pointed to value
 
@@ -12361,6 +12431,7 @@ class json_pointer
         {}
     }
 
+  JSON_PRIVATE_UNLESS_TESTED:
     /// escape "~" to "~0" and "/" to "~1"
     static std::string escape(std::string s)
     {
@@ -12376,6 +12447,7 @@ class json_pointer
         replace_substring(s, "~0", "~");
     }
 
+  private:
     /*!
     @param[in] reference_string  the reference string to the current value
     @param[in] value             the value to consider
@@ -15801,7 +15873,7 @@ class serializer
         }
     }
 
-  private:
+  JSON_PRIVATE_UNLESS_TESTED:
     /*!
     @brief dump escaped string
 
@@ -16064,6 +16136,7 @@ class serializer
         }
     }
 
+  private:
     /*!
     @brief count digits
 
@@ -16682,6 +16755,7 @@ class basic_json
     /// workaround type for MSVC
     using basic_json_t = NLOHMANN_BASIC_JSON_TPL;
 
+  JSON_PRIVATE_UNLESS_TESTED:
     // convenience aliases for types residing in namespace detail;
     using lexer = ::nlohmann::detail::lexer_base;
 
@@ -16697,6 +16771,7 @@ class basic_json
                 std::move(cb), allow_exceptions, ignore_comments);
     }
 
+  private:
     using primitive_iterator_t = ::nlohmann::detail::primitive_iterator_t;
     template
     using internal_iterator = ::nlohmann::detail::internal_iterator;
@@ -16713,6 +16788,7 @@ class basic_json
     using binary_reader = ::nlohmann::detail::binary_reader;
     template using binary_writer = ::nlohmann::detail::binary_writer;
 
+  JSON_PRIVATE_UNLESS_TESTED:
     using serializer = ::nlohmann::detail::serializer;
 
   public:
@@ -17427,6 +17503,7 @@ class basic_json
     // JSON value storage //
     ////////////////////////
 
+  JSON_PRIVATE_UNLESS_TESTED:
     /*!
     @brief a JSON value
 
@@ -17703,6 +17780,7 @@ class basic_json
         }
     };
 
+  private:
     /*!
     @brief checks the class invariants
 
@@ -23440,7 +23518,7 @@ class basic_json
     }
 
 
-  private:
+  JSON_PRIVATE_UNLESS_TESTED:
     //////////////////////
     // member variables //
     //////////////////////
@@ -25296,6 +25374,7 @@ inline nlohmann::json::json_pointer operator "" _json_pointer(const char* s, std
 #undef JSON_CATCH
 #undef JSON_THROW
 #undef JSON_TRY
+#undef JSON_PRIVATE_UNLESS_TESTED
 #undef JSON_HAS_CPP_14
 #undef JSON_HAS_CPP_17
 #undef NLOHMANN_BASIC_JSON_TPL_DECLARATION
@@ -25379,6 +25458,8 @@ inline nlohmann::json::json_pointer operator "" _json_pointer(const char* s, std
 #undef JSON_HEDLEY_IBM_VERSION_CHECK
 #undef JSON_HEDLEY_IMPORT
 #undef JSON_HEDLEY_INLINE
+#undef JSON_HEDLEY_INTEL_CL_VERSION
+#undef JSON_HEDLEY_INTEL_CL_VERSION_CHECK
 #undef JSON_HEDLEY_INTEL_VERSION
 #undef JSON_HEDLEY_INTEL_VERSION_CHECK
 #undef JSON_HEDLEY_IS_CONSTANT
diff --git a/src.wsjcpp/nlohmann_json/wsjcpp.hold.yml b/src.wsjcpp/nlohmann_json/wsjcpp.hold.yml
index d818495..39468d6 100644
--- a/src.wsjcpp/nlohmann_json/wsjcpp.hold.yml
+++ b/src.wsjcpp/nlohmann_json/wsjcpp.hold.yml
@@ -12,12 +12,11 @@ keywords:
 repositories:
   - type: main
     url: "https://github.com/nlohmann/json"
-
 authors:
   - name: "Niels Lohmann"
     email: "mail@nlohmann.me"
-
 distribution:
   - source-file: "single_include/nlohmann/json.hpp"
     target-file: "json.hpp"
     type: "source-code"
+    sha1: "c2131f667113fa880110c984e2e2ca357a0d96d7"
diff --git a/src.wsjcpp/wsjcpp_core/generate.Class b/src.wsjcpp/wsjcpp_core/generate.Class.wsjcpp-script
similarity index 100%
rename from src.wsjcpp/wsjcpp_core/generate.Class
rename to src.wsjcpp/wsjcpp_core/generate.Class.wsjcpp-script
diff --git a/src.wsjcpp/wsjcpp_core/generate.WsjcppUnitTest b/src.wsjcpp/wsjcpp_core/generate.WsjcppUnitTest.wsjcpp-script
similarity index 58%
rename from src.wsjcpp/wsjcpp_core/generate.WsjcppUnitTest
rename to src.wsjcpp/wsjcpp_core/generate.WsjcppUnitTest.wsjcpp-script
index 30db9d5..fdf4902 100644
--- a/src.wsjcpp/wsjcpp_core/generate.WsjcppUnitTest
+++ b/src.wsjcpp/wsjcpp_core/generate.WsjcppUnitTest.wsjcpp-script
@@ -6,35 +6,21 @@
 make_dir "./unit-tests.wsjcpp"
 make_dir "./unit-tests.wsjcpp/src"
 
-var user_class_name
-set_value user_class_name arg1
-normalize_class_name user_class_name
 var class_name
-set_value class_name "UnitTest"
-concat class_name user_class_name
-
-var base_filename
-convert_CamelCase_to_snake_case class_name base_filename
-# log_info base_filename
+set_value class_name arg1
+normalize_class_name class_name
 
 var filename_cpp
-concat filename_cpp "./unit-tests.wsjcpp/src/" base_filename ".cpp"
-
-var filename_h
-concat filename_h "./unit-tests.wsjcpp/src/" base_filename ".h"
-
-var ifndef_header
-set_value ifndef_header base_filename
-concat ifndef_header "_H"
-
-to_upper_case ifndef_header
-
-var content_header
-concat content_header "#ifndef " ifndef_header "
-#define " ifndef_header "
+set_value filename_cpp arg2
 
+var content_source
+concat content_source "
+#include 
 #include 
 
+// ---------------------------------------------------------------------
+// " class_name "
+
 class " class_name " : public WsjcppUnitTestBase {
     public:
         " class_name "();
@@ -43,17 +29,6 @@ class " class_name " : public WsjcppUnitTestBase {
         virtual bool doAfterTest() override;
 };
 
-#endif // " ifndef_header
-
- 
-var content_source
-concat content_source  "
-#include \"" base_filename ".h\"
-#include 
-
-// ---------------------------------------------------------------------
-// " class_name "
-
 REGISTRY_WSJCPP_UNIT_TEST(" class_name ")
 
 " class_name "::" class_name "()
@@ -63,7 +38,7 @@ REGISTRY_WSJCPP_UNIT_TEST(" class_name ")
 // ---------------------------------------------------------------------
 
 bool " class_name "::doBeforeTest() {
-    // nothing
+    // do something before test
     return true;
 }
 
@@ -77,16 +52,12 @@ void " class_name "::executeTest() {
 // ---------------------------------------------------------------------
 
 bool " class_name "::doAfterTest() {
-    // nothing
+    // do somethig after test
     return true;
 }
 
 "
 
-var file_source
-concat file_source "src/" filename_cpp
-
-write_file filename_h content_header
 write_file filename_cpp content_source
 
 log_info "
@@ -94,10 +65,6 @@ log_info "
 Generated class:
     - " class_name "
 Generated files:
-    - " filename_h "
     - " filename_cpp "
 ======
 "
-
-wsjcpp_yml_unit_test_add user_class_name filename_h
-wsjcpp_yml_unit_test_add user_class_name filename_cpp
\ No newline at end of file
diff --git a/src.wsjcpp/wsjcpp_core/wsjcpp.hold.yml b/src.wsjcpp/wsjcpp_core/wsjcpp.hold.yml
index 9539ed7..58ee505 100644
--- a/src.wsjcpp/wsjcpp_core/wsjcpp.hold.yml
+++ b/src.wsjcpp/wsjcpp_core/wsjcpp.hold.yml
@@ -3,7 +3,7 @@ cmake_cxx_standard: 11
 cmake_minimum_required: 3.0
 
 name: wsjcpp-core
-version: v0.2.0
+version: v0.2.1
 description: Basic Utils for wsjcpp
 issues: https://github.com/wsjcpp/wsjcpp-core/issues
 repositories:
@@ -16,35 +16,35 @@ keywords:
 authors:
   - name: Evgenii Sopov
     email: mrseakg@gmail.com
-
 distribution:
   - source-file: src/wsjcpp_core.cpp
     target-file: wsjcpp_core.cpp
     type: "source-code"
+    sha1: "09ef821bbc090fc1cd8a15bc4a57a9a2ce8ae00d"
   - source-file: src/wsjcpp_core.h
     target-file: wsjcpp_core.h
     type: "source-code" # todo must be header-file
+    sha1: "e6e4ab2067d3c942db08e3b79862486eaf851e4b"
   - source-file: "src/wsjcpp_unit_tests.cpp"
     target-file: "wsjcpp_unit_tests.cpp"
     type: "unit-tests"
+    sha1: "fd5989d1a83c8b90bdc4d5e9bc9c3051eaa1e6d2"
   - source-file: "src/wsjcpp_unit_tests.h"
     target-file: "wsjcpp_unit_tests.h"
     type: "unit-tests"
+    sha1: "83d4b6e046b6b58c42882ccae4be413e03c401c1"
   - source-file: "src/wsjcpp_unit_tests_main.cpp"
     target-file: "wsjcpp_unit_tests_main.cpp"
     type: "unit-tests"
-  - source-file: "scripts.wsjcpp/generate.WsjcppUnitTest"
-    target-file: "generate.WsjcppUnitTest"
+    sha1: "388ae269b325c5e161f6c3a5c598575714a4bffc"
+  - source-file: "scripts.wsjcpp/generate.WsjcppUnitTest.wsjcpp-script"
+    target-file: "generate.WsjcppUnitTest.wsjcpp-script"
     type: "safe-scripting-generate"
-  - source-file: "scripts.wsjcpp/generate.Class"
-    target-file: "generate.Class"
+    sha1: "a7c9c2d19bf81c5b00e659384b0b92a99319a4c1"
+  - source-file: "scripts.wsjcpp/generate.Class.wsjcpp-script"
+    target-file: "generate.Class.wsjcpp-script"
     type: "safe-scripting-generate"
-  - source-file: "src/wsjcpp_resources_manager.h"
-    target-file: "wsjcpp_resources_manager.h"
-    type: "source-code"
-  - source-file: "src/wsjcpp_resources_manager.cpp"
-    target-file: "wsjcpp_resources_manager.cpp"
-    type: "source-code"
+    sha1: "de1799907c685d606b93e08b821b540c2faa2db1"
 
 unit-tests:
   cases:
diff --git a/src.wsjcpp/wsjcpp_core/wsjcpp_core.cpp b/src.wsjcpp/wsjcpp_core/wsjcpp_core.cpp
index c92c433..5e937f3 100644
--- a/src.wsjcpp/wsjcpp_core/wsjcpp_core.cpp
+++ b/src.wsjcpp/wsjcpp_core/wsjcpp_core.cpp
@@ -1213,4 +1213,122 @@ void WsjcppLog::add(WsjcppColorModifier &clr, const std::string &sType, const st
     }
 }
 
+// ---------------------------------------------------------------------
+// WsjcppResourceFile
+
+WsjcppResourceFile::WsjcppResourceFile() {
+    WsjcppResourcesManager::add(this);
+}
+
+// ---------------------------------------------------------------------
+
+
+// ---------------------------------------------------------------------
+// WsjcppResourcesManager
+
+std::vector *g_pWsjcppResourceFiles = nullptr;
+
+void WsjcppResourcesManager::initGlobalVariables() {
+    if (g_pWsjcppResourceFiles == nullptr) {
+        g_pWsjcppResourceFiles = new std::vector();
+    }
+}
+
+// ---------------------------------------------------------------------
+
+void WsjcppResourcesManager::add(WsjcppResourceFile* pStorage) {
+    WsjcppResourcesManager::initGlobalVariables();
+    g_pWsjcppResourceFiles->push_back(pStorage);
+}
+
+// ---------------------------------------------------------------------
+
+bool WsjcppResourcesManager::has(const std::string &sFilename) {
+    WsjcppResourcesManager::initGlobalVariables();
+    for (int i = 0; i < WsjcppResourcesManager::list().size(); i++) {
+        if (WsjcppResourcesManager::list()[i]->getFilename() == sFilename) {
+            return true;
+        }
+    }
+    return false;
+}
+
+// ---------------------------------------------------------------------
+
+WsjcppResourceFile* WsjcppResourcesManager::get(const std::string &sFilename) {
+    WsjcppResourcesManager::initGlobalVariables();
+    for (int i = 0; i < WsjcppResourcesManager::list().size(); i++) {
+        if (WsjcppResourcesManager::list()[i]->getFilename() == sFilename) {
+            return WsjcppResourcesManager::list()[i];
+        }
+    }
+    return nullptr;
+}
+
+// ---------------------------------------------------------------------
+
+const std::vector &WsjcppResourcesManager::list() {
+    return *g_pWsjcppResourceFiles;
+}
+
+// ---------------------------------------------------------------------
+
+/*
+bool WsjcppResourcesManager::make(const std::string &sWorkspace) {
+    if (!WsjcppResourcesManager::createFolders(sWorkspace)) {
+        return false;
+    }
+    return WsjcppResourcesManager::extractFiles(sWorkspace);
+}
+
+// ---------------------------------------------------------------------
+
+bool WsjcppResourcesManager::createFolders(const std::string &sWorkspace) {
+    // prepare folders
+    std::vector vCreateDirs;
+    vCreateDirs.push_back(sWorkspace + "/logs");
+    vCreateDirs.push_back(sWorkspace + "/teams");
+    vCreateDirs.push_back(sWorkspace + "/checkers");
+    vCreateDirs.push_back(sWorkspace + "/html");
+    vCreateDirs.push_back(sWorkspace + "/html/css");
+    vCreateDirs.push_back(sWorkspace + "/html/js");
+    vCreateDirs.push_back(sWorkspace + "/html/images");
+    vCreateDirs.push_back(sWorkspace + "/html/images/teams");
+    vCreateDirs.push_back(sWorkspace + "/html/images/states");
+
+    for(int i = 0; i < vCreateDirs.size(); i++) {
+        std::string sPath = vCreateDirs[i];
+        // check dir existing
+        if (!FS::dirExists(sPath)) {
+            // try make dir
+            if (!FS::makeDir(sPath)) {
+                std::cout << "Could not create folder " << sPath << std::endl;
+                return false;
+            } else {
+                std::cout << "Created folder " << sPath << std::endl;
+            }
+        }
+    }
+    return true;
+}
+
+// ---------------------------------------------------------------------
+
+bool WsjcppResourcesManager::extractFiles(const std::string &sWorkspace) {
+    // TODO mkdir -p for files
+    const std::vector list = WsjcppResourcesManager::list();
+    for(int i = 0; i < list.size(); i++) {
+        std::string sFilename = sWorkspace + "/" + list[i]->filename();
+        if (!FS::fileExists(sFilename)) {
+            if (!FS::writeFile(sFilename, list[i]->buffer(), list[i]->bufferSize())) {
+                std::cout << "Could not write file " << sFilename << std::endl;
+                return false;
+            } else {
+                std::cout << "Created file " << sFilename << std::endl;
+            }
+        }
+    }
+    return true;
+}
+*/
 
diff --git a/src.wsjcpp/wsjcpp_core/wsjcpp_core.h b/src.wsjcpp/wsjcpp_core/wsjcpp_core.h
index 49142e5..249c693 100644
--- a/src.wsjcpp/wsjcpp_core/wsjcpp_core.h
+++ b/src.wsjcpp/wsjcpp_core/wsjcpp_core.h
@@ -194,6 +194,42 @@ class WsjcppLog {
         static void add(WsjcppColorModifier &clr, const std::string &sType, const std::string &sTag, const std::string &sMessage);
 };
 
+// ---------------------------------------------------------------------
+// WsjcppResourceFile
+
+class WsjcppResourceFile {
+    public:
+        WsjcppResourceFile();
+        virtual const std::string &getFilename() const = 0;
+        virtual const std::string &getPackAs() const = 0;
+        virtual int getBufferSize() const = 0;
+        virtual const char *getBuffer() const = 0;
+};
+
+
+// ---------------------------------------------------------------------
+// WsjcppResourcesManager
+
+extern std::vector *g_pWsjcppResourceFiles;
+
+class WsjcppResourcesManager {
+    public:
+        static void initGlobalVariables();
+        static void add(WsjcppResourceFile*);
+        static const std::vector &list();
+        static bool has(const std::string &sFilename);
+        static WsjcppResourceFile* get(const std::string &sFilename);
+        static bool make(const std::string &sWorkspace);
+        // static bool createFolders(const std::string &sWorkspace);
+        // static bool extractFiles(const std::string &sWorkspace);
+};
+
+// ---------------------------------------------------------------------
+// Registry WsjcppResourceFile
+#define REGISTRY_WSJCPP_RESOURCE_FILE( classname ) \
+    static classname * pRegistryWsjcppResourceFile ## classname = new classname(); \
+
+
 #endif // WSJCPP_CORE_H
 
 
diff --git a/src.wsjcpp/wsjcpp_core/wsjcpp_resources_manager.cpp b/src.wsjcpp/wsjcpp_core/wsjcpp_resources_manager.cpp
deleted file mode 100644
index 062b617..0000000
--- a/src.wsjcpp/wsjcpp_core/wsjcpp_resources_manager.cpp
+++ /dev/null
@@ -1,117 +0,0 @@
-#include "wsjcpp_resources_manager.h"
-
-// ---------------------------------------------------------------------
-
-WsjcppResourceFile::WsjcppResourceFile() {
-    WsjcppResourcesManager::add(this);
-}
-
-// ---------------------------------------------------------------------
-
-std::vector *g_pWsjcppResourceFiles = nullptr;
-
-// ---------------------------------------------------------------------
-
-void WsjcppResourcesManager::initGlobalVariables() {
-    if (g_pWsjcppResourceFiles == nullptr) {
-        g_pWsjcppResourceFiles = new std::vector();
-    }
-}
-
-// ---------------------------------------------------------------------
-
-void WsjcppResourcesManager::add(WsjcppResourceFile* pStorage) {
-    WsjcppResourcesManager::initGlobalVariables();
-    g_pWsjcppResourceFiles->push_back(pStorage);
-}
-
-// ---------------------------------------------------------------------
-
-bool WsjcppResourcesManager::has(const std::string &sFilename) {
-    WsjcppResourcesManager::initGlobalVariables();
-    for (int i = 0; i < WsjcppResourcesManager::list().size(); i++) {
-        if (WsjcppResourcesManager::list()[i]->getFilename() == sFilename) {
-            return true;
-        }
-    }
-    return false;
-}
-
-// ---------------------------------------------------------------------
-
-WsjcppResourceFile* WsjcppResourcesManager::get(const std::string &sFilename) {
-    WsjcppResourcesManager::initGlobalVariables();
-    for (int i = 0; i < WsjcppResourcesManager::list().size(); i++) {
-        if (WsjcppResourcesManager::list()[i]->getFilename() == sFilename) {
-            return WsjcppResourcesManager::list()[i];
-        }
-    }
-    return nullptr;
-}
-
-// ---------------------------------------------------------------------
-
-const std::vector &WsjcppResourcesManager::list() {
-    return *g_pWsjcppResourceFiles;
-}
-
-// ---------------------------------------------------------------------
-
-/*
-bool WsjcppResourcesManager::make(const std::string &sWorkspace) {
-    if (!WsjcppResourcesManager::createFolders(sWorkspace)) {
-        return false;
-    }
-    return WsjcppResourcesManager::extractFiles(sWorkspace);
-}
-
-// ---------------------------------------------------------------------
-
-bool WsjcppResourcesManager::createFolders(const std::string &sWorkspace) {
-    // prepare folders
-    std::vector vCreateDirs;
-    vCreateDirs.push_back(sWorkspace + "/logs");
-    vCreateDirs.push_back(sWorkspace + "/teams");
-    vCreateDirs.push_back(sWorkspace + "/checkers");
-    vCreateDirs.push_back(sWorkspace + "/html");
-    vCreateDirs.push_back(sWorkspace + "/html/css");
-    vCreateDirs.push_back(sWorkspace + "/html/js");
-    vCreateDirs.push_back(sWorkspace + "/html/images");
-    vCreateDirs.push_back(sWorkspace + "/html/images/teams");
-    vCreateDirs.push_back(sWorkspace + "/html/images/states");
-
-    for(int i = 0; i < vCreateDirs.size(); i++) {
-        std::string sPath = vCreateDirs[i];
-        // check dir existing
-        if (!FS::dirExists(sPath)) {
-            // try make dir
-            if (!FS::makeDir(sPath)) {
-                std::cout << "Could not create folder " << sPath << std::endl;
-                return false;
-            } else {
-                std::cout << "Created folder " << sPath << std::endl;
-            }
-        }
-    }
-    return true;
-}
-
-// ---------------------------------------------------------------------
-
-bool WsjcppResourcesManager::extractFiles(const std::string &sWorkspace) {
-    // TODO mkdir -p for files
-    const std::vector list = WsjcppResourcesManager::list();
-    for(int i = 0; i < list.size(); i++) {
-        std::string sFilename = sWorkspace + "/" + list[i]->filename();
-        if (!FS::fileExists(sFilename)) {
-            if (!FS::writeFile(sFilename, list[i]->buffer(), list[i]->bufferSize())) {
-                std::cout << "Could not write file " << sFilename << std::endl;
-                return false;
-            } else {
-                std::cout << "Created file " << sFilename << std::endl;
-            }
-        }
-    }
-    return true;
-}
-*/
\ No newline at end of file
diff --git a/src.wsjcpp/wsjcpp_core/wsjcpp_resources_manager.h b/src.wsjcpp/wsjcpp_core/wsjcpp_resources_manager.h
deleted file mode 100644
index b741687..0000000
--- a/src.wsjcpp/wsjcpp_core/wsjcpp_resources_manager.h
+++ /dev/null
@@ -1,37 +0,0 @@
-#ifndef WSJCPP_RESOURCES_MANAGER_H
-#define WSJCPP_RESOURCES_MANAGER_H
-
-#include 
-#include 
-#include 
-#include 
-
-class WsjcppResourceFile {
-    public:
-        WsjcppResourceFile();
-        virtual const std::string &getFilename() const = 0;
-        virtual const std::string &getPackAs() const = 0;
-        virtual int getBufferSize() const = 0;
-        virtual const char *getBuffer() const = 0;
-};
-
-extern std::vector *g_pWsjcppResourceFiles;
-
-class WsjcppResourcesManager {
-    public:
-        static void initGlobalVariables();
-        static void add(WsjcppResourceFile*);
-        static const std::vector &list();
-        static bool has(const std::string &sFilename);
-        static WsjcppResourceFile* get(const std::string &sFilename);
-        static bool make(const std::string &sWorkspace);
-        // static bool createFolders(const std::string &sWorkspace);
-        // static bool extractFiles(const std::string &sWorkspace);
-};
-
-// ---------------------------------------------------------------------
-// Registry WsjcppResourceFile
-#define REGISTRY_WSJCPP_RESOURCE_FILE( classname ) \
-    static classname * pRegistryWsjcppResourceFile ## classname = new classname(); \
-
-#endif // WSJCPP_RESOURCES_MANAGER_H
\ No newline at end of file
diff --git a/src.wsjcpp/wsjcpp_core/wsjcpp_unit_tests.cpp b/src.wsjcpp/wsjcpp_core/wsjcpp_unit_tests.cpp
index 1b5e281..bd00383 100644
--- a/src.wsjcpp/wsjcpp_core/wsjcpp_unit_tests.cpp
+++ b/src.wsjcpp/wsjcpp_core/wsjcpp_unit_tests.cpp
@@ -63,27 +63,6 @@ bool WsjcppUnitTestBase::runTest() {
 
 // ---------------------------------------------------------------------
 
-bool WsjcppUnitTestBase::compareS(const std::string &sMark,
-    const std::string &sValue, const std::string &sExpected) {
-    if (sValue != sExpected) {
-        fail(" {" + sMark + "} Expected '" + sExpected + "', but got '" + sValue + "'");
-        return false;
-    }
-    return true;
-}
-
-// ---------------------------------------------------------------------
-
-bool WsjcppUnitTestBase::compareN(const std::string &sMark, int nValue, int nExpected) {
-    if (nValue != nExpected) {
-        fail(" {" + sMark + "} Expected '" + std::to_string(nExpected) + "', but got '" + std::to_string(nValue) + "'");
-        return false;
-    }
-    return true;
-}
-
-// ---------------------------------------------------------------------
-
 bool WsjcppUnitTestBase::compareD(const std::string &sMark, double nValue, double nExpected) {
     if (abs(nValue - nExpected) > std::numeric_limits::epsilon()) {
         fail(" {" + sMark + "} Expected '" + std::to_string(nExpected) + "', but got '" + std::to_string(nValue) + "'");
@@ -94,16 +73,6 @@ bool WsjcppUnitTestBase::compareD(const std::string &sMark, double nValue, doubl
 
 // ---------------------------------------------------------------------
 
-bool WsjcppUnitTestBase::compareB(const std::string &sMark, bool bValue, bool bExpected) {
-    if (bValue != bExpected) {
-        fail(" {" + sMark + "} Expected '" + (bExpected ? "true" : "false") + "', but got '" + (bValue ? "true" : "false") + "'");
-        return false;
-    }
-    return true;
-}
-
-// ---------------------------------------------------------------------
-
 std::vector *g_pWsjcppUnitTests = nullptr;
 
 void WsjcppUnitTests::initGlobalVariables() {
diff --git a/src.wsjcpp/wsjcpp_core/wsjcpp_unit_tests.h b/src.wsjcpp/wsjcpp_core/wsjcpp_unit_tests.h
index 2f2a2b3..c2d8eff 100644
--- a/src.wsjcpp/wsjcpp_core/wsjcpp_unit_tests.h
+++ b/src.wsjcpp/wsjcpp_core/wsjcpp_unit_tests.h
@@ -17,11 +17,8 @@ class WsjcppUnitTestBase {
         virtual bool doAfterTest() = 0;
     protected:
         std::string TAG;
-
-        bool compareS(const std::string &sMark, const std::string &sValue, const std::string &sExpected);
-        bool compareN(const std::string &sMark, int nValue, int nExpected);
+        
         bool compareD(const std::string &sMark, double nValue, double nExpected);
-        bool compareB(const std::string &sMark, bool bValue, bool bExpected);
         template bool compare(const std::string &sMark, T1 tGotValue, T2 tExpectedValue) {
             if (tGotValue != tExpectedValue) {
                 std::stringstream ss;
diff --git a/src.wsjcpp/wsjcpp_validators/wsjcpp.hold.yml b/src.wsjcpp/wsjcpp_validators/wsjcpp.hold.yml
index 1330aa5..c322598 100644
--- a/src.wsjcpp/wsjcpp_validators/wsjcpp.hold.yml
+++ b/src.wsjcpp/wsjcpp_validators/wsjcpp.hold.yml
@@ -13,15 +13,13 @@ keywords:
 
 required-libraries:
   - pthread
-  
+
 repositories:
   - type: main
     url: "https://github.com/wsjcpp/wsjcpp-validators"
-
 authors:
   - name: Evgenii Sopov
     email: mrseakg@gmail.com
-
 dependencies:
   - name: "wsjcpp-core"
     version: "v0.1.7"
@@ -33,14 +31,15 @@ dependencies:
     url: "https://github.com/nlohmann/json:develop"
     origin: "https://github.com/"
     installation-dir: "./src.wsjcpp/nlohmann_json"
-
 distribution:
   - source-file: "src/wsjcpp_validators.h"
     target-file: "wsjcpp_validators.h"
     type: "source-code"
+    sha1: "78e7f62c964f5e36f3940e03a4c8f673feaea289"
   - source-file: "src/wsjcpp_validators.cpp"
     target-file: "wsjcpp_validators.cpp"
     type: "source-code"
+    sha1: "9f4bd5c96b74aae164e785549d72d3a3e37ca8e8"
 
 unit-tests:
   cases:
diff --git a/src/app/main.cpp b/src/app/main.cpp
new file mode 100644
index 0000000..523ef43
--- /dev/null
+++ b/src/app/main.cpp
@@ -0,0 +1,75 @@
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+int main(int argc, const char* argv[]) {
+    std::string TAG = "MAIN";
+    std::string appName = std::string(WSJCPP_APP_NAME);
+    std::string appVersion = std::string(WSJCPP_APP_VERSION);
+    if (!WsjcppCore::dirExists(".logs")) {
+        WsjcppCore::makeDir(".logs");
+    }
+    WsjcppLog::setPrefixLogFile("wsjcpp");
+    WsjcppLog::setLogDirectory(".logs");
+
+    std::cout << "Generate client python library" << std::endl;
+
+    // export webjs
+    WsjcppJsonRpc20ExportCliPython exportCliPython(
+        "./example-of-exported/py3",
+        "libwsjcppjson20client"
+    );
+    exportCliPython.setAuthorName("Evgenii Sopov");
+    exportCliPython.setAuthorEmail("mrseakg@gmail.com");
+    exportCliPython.setAppName(std::string(WSJCPP_APP_NAME));
+    exportCliPython.setAppVersion(std::string(WSJCPP_APP_VERSION));
+    exportCliPython.setClassName("SomeClient");
+    exportCliPython.setUrl("https://github.com/wsjcpp/wsjcpp-jsonrpc20");
+    exportCliPython.setDownloadUrl("https://github.com/wsjcpp/wsjcpp-jsonrpc20/archive/" + std::string(WSJCPP_APP_NAME) + ".tar.gz");
+    exportCliPython.setKeywords({std::string(WSJCPP_APP_NAME), "wsjcpp", "wsjcpp-jsonrpc20", "example-python-client"});
+    exportCliPython.addLoginMethod("auth_login", "token");
+    exportCliPython.addLoginMethod("auth_token", "token");
+    exportCliPython.addLogoffMethod("auth_logoff");
+
+    if (!exportCliPython.doExportLib()) {
+        std::cout << "Python Client Library export failed!" << std::endl;
+    } else {
+        std::cout << "Python Client Library export success!" << std::endl;
+    }
+
+    // export WebJS
+
+    std::cout << "Generate client WebJS library" << std::endl;
+    WsjcppJsonRpc20ExportCliWebJs exportCliWebJs(
+        "./example-of-exported/webjs",
+        "libwsjcppjson20client"
+    );
+    exportCliWebJs.setAuthorName("Evgenii Sopov");
+    exportCliWebJs.setAuthorEmail("mrseakg@gmail.com");
+    exportCliWebJs.setAppName(std::string(WSJCPP_APP_NAME));
+    exportCliWebJs.setClassName("SomeClient");
+    exportCliWebJs.setAppVersion(std::string(WSJCPP_APP_VERSION));
+    exportCliWebJs.setIssuesURL("https://github.com/wsjcpp/wsjcpp-jsonrpc20/issues");
+    exportCliWebJs.setRepository("git", "https://github.com/wsjcpp/wsjcpp-jsonrpc20.git");
+    exportCliWebJs.setKeywords({std::string(WSJCPP_APP_NAME), "wsjcpp", "jsonrpc20", "example-client-webjs"});
+    exportCliWebJs.setLicense("MIT", "https://raw.githubusercontent.com/wsjcpp/wsjcpp-jsonrpc20/master/LICENSE");
+    exportCliWebJs.setDefaultConnectionString("ws://localhost:1234/");
+    
+    // exportCliWebJs.addLoginMethod("auth_login", "token");
+    // exportCliWebJs.addLoginMethod("auth_token", "token");
+    // exportCliWebJs.addLogoffMethod("auth_logoff");
+
+    if (!exportCliWebJs.doExportLib()) {
+        std::cout << "WebJS Client Library export failed!" << std::endl;
+    } else {
+        std::cout << "WebJS Client Library export success!" << std::endl;
+    }
+
+    return 0;
+}
+
+
diff --git a/src/examples/wsjcpp_json_rpc20_handler_auth.cpp b/src/app/wsjcpp_json_rpc20_handler_auth.cpp
similarity index 98%
rename from src/examples/wsjcpp_json_rpc20_handler_auth.cpp
rename to src/app/wsjcpp_json_rpc20_handler_auth.cpp
index 4546c18..a3aa0bb 100644
--- a/src/examples/wsjcpp_json_rpc20_handler_auth.cpp
+++ b/src/app/wsjcpp_json_rpc20_handler_auth.cpp
@@ -31,7 +31,6 @@ WsjcppJsonRpc20HandlerAuthLogin::WsjcppJsonRpc20HandlerAuthLogin()
 
 void WsjcppJsonRpc20HandlerAuthLogin::handle(WsjcppJsonRpc20Request *pRequest) {
     WsjcppLog::err(TAG, "Not implemented");
-    // TODO
     pRequest->fail(WsjcppJsonRpc20Error(501, "NOT_IMPLEMENTED"));
 }
 
@@ -56,7 +55,6 @@ WsjcppJsonRpc20HandlerAuthLogoff::WsjcppJsonRpc20HandlerAuthLogoff()
 
 void WsjcppJsonRpc20HandlerAuthLogoff::handle(WsjcppJsonRpc20Request *pRequest) {
     WsjcppLog::err(TAG, "Not implemented");
-    // TODO
     pRequest->fail(WsjcppJsonRpc20Error(501, "NOT_IMPLEMENTED"));
 }
 
@@ -87,8 +85,5 @@ WsjcppJsonRpc20HandlerAuthToken::WsjcppJsonRpc20HandlerAuthToken()
 
 void WsjcppJsonRpc20HandlerAuthToken::handle(WsjcppJsonRpc20Request *pRequest) {
     WsjcppLog::err(TAG, "Not implemented");
-    // TODO
     pRequest->fail(WsjcppJsonRpc20Error(501, "NOT_IMPLEMENTED"));
 }
-
-
diff --git a/src/examples/wsjcpp_json_rpc20_handler_auth.h b/src/app/wsjcpp_json_rpc20_handler_auth.h
similarity index 100%
rename from src/examples/wsjcpp_json_rpc20_handler_auth.h
rename to src/app/wsjcpp_json_rpc20_handler_auth.h
diff --git a/src/examples/wsjcpp_json_rpc20_handler_game_create.cpp b/src/app/wsjcpp_json_rpc20_handler_game_create.cpp
similarity index 99%
rename from src/examples/wsjcpp_json_rpc20_handler_game_create.cpp
rename to src/app/wsjcpp_json_rpc20_handler_game_create.cpp
index 7033a5f..b1f6868 100644
--- a/src/examples/wsjcpp_json_rpc20_handler_game_create.cpp
+++ b/src/app/wsjcpp_json_rpc20_handler_game_create.cpp
@@ -40,7 +40,6 @@ WsjcppJsonRpc20HandlerGameCreate::WsjcppJsonRpc20HandlerGameCreate()
 
 void WsjcppJsonRpc20HandlerGameCreate::handle(WsjcppJsonRpc20Request *pRequest) {
     WsjcppLog::err(TAG, "Not implemented");
-    // TODO
     pRequest->fail(WsjcppJsonRpc20Error(501, "NOT_IMPLEMENTED"));
 }
 
diff --git a/src/examples/wsjcpp_json_rpc20_handler_game_create.h b/src/app/wsjcpp_json_rpc20_handler_game_create.h
similarity index 100%
rename from src/examples/wsjcpp_json_rpc20_handler_game_create.h
rename to src/app/wsjcpp_json_rpc20_handler_game_create.h
diff --git a/src/main.cpp b/src/main.cpp
deleted file mode 100644
index aea16fb..0000000
--- a/src/main.cpp
+++ /dev/null
@@ -1,47 +0,0 @@
-#include 
-#include 
-#include 
-#include 
-#include 
-#include 
-
-int main(int argc, const char* argv[]) {
-    std::string TAG = "MAIN";
-    std::string appName = std::string(WSJCPP_APP_NAME);
-    std::string appVersion = std::string(WSJCPP_APP_VERSION);
-    if (!WsjcppCore::dirExists(".logs")) {
-        WsjcppCore::makeDir(".logs");
-    }
-    WsjcppLog::setPrefixLogFile("wsjcpp");
-    WsjcppLog::setLogDirectory(".logs");
-
-    std::cout << "Generate client python library" << std::endl;
-    
-    std::string sExportDir = "./example-of-exported-client-libraries";
-
-    WsjcppJsonRpc20ExportCliPython exportCliPython(
-        "./example-of-exported/py3",
-        "libwsjcppjson20client"
-    );
-    exportCliPython.setAuthorName("Evgenii Sopov");
-    exportCliPython.setAuthorEmail("mrseakg@gmail.com");
-    exportCliPython.setAppName(std::string(WSJCPP_APP_NAME));
-    exportCliPython.setAppVersion(std::string(WSJCPP_APP_VERSION));
-    exportCliPython.setUrl("https://github.com/wsjcpp/wsjcpp-jsonrpc20");
-    exportCliPython.setDownloadUrl("https://github.com/wsjcpp/wsjcpp-jsonrpc20/archive/" + std::string(WSJCPP_APP_NAME) + ".tar.gz");
-    exportCliPython.setKeywords({std::string(WSJCPP_APP_NAME), "wsjcpp", "wsjcpp-jsonrpc20", "example-python-client"});
-    exportCliPython.addLoginMethod("auth_login", "token");
-    exportCliPython.addLoginMethod("auth_token", "token");
-    exportCliPython.addLogoffMethod("auth_logoff");
-
-    if (!exportCliPython.doExportLib()) {
-        std::cout << "Failed!" << std::endl;
-    } else {
-        std::cout << "Success!" << std::endl;
-    }
-
-    // TODO your code here
-    return 0;
-}
-
-
diff --git a/src/wsjcpp_jsonrpc20.cpp b/src/wsjcpp_jsonrpc20.cpp
index 034e0b6..7b5c55f 100644
--- a/src/wsjcpp_jsonrpc20.cpp
+++ b/src/wsjcpp_jsonrpc20.cpp
@@ -475,6 +475,13 @@ void WsjcppJsonRpc20WebSocketServer::sendMessageToOne(WsjcppJsonRpc20WebSocketCl
 // ---------------------------------------------------------------------
 // WsjcppJsonRpc20ParamDef
 
+WsjcppJsonRpc20ParamDef::WsjcppJsonRpc20ParamDef() {
+    TAG = "WsjcppJsonRpc20ParamDef";
+    m_bRequired = true;
+}
+
+// ---------------------------------------------------------------------
+
 WsjcppJsonRpc20ParamDef::WsjcppJsonRpc20ParamDef(const std::string &sName, const std::string &sDescription) 
     : WsjcppJsonRpc20ParamDef()
 {
@@ -496,23 +503,18 @@ WsjcppJsonRpc20ParamDef::WsjcppJsonRpc20ParamDef(const std::string &sName, const
     }
 }
 
-// ---------------------------------------------------------------------
-
-WsjcppJsonRpc20ParamDef::WsjcppJsonRpc20ParamDef() {
-    TAG = "WsjcppJsonRpc20ParamDef";
-}
 
 // ---------------------------------------------------------------------
 
 WsjcppJsonRpc20ParamDef & WsjcppJsonRpc20ParamDef::optional() {
-    m_sRestrict = "optional";
+    m_bRequired = false;
     return *this;
 }
 
 // ---------------------------------------------------------------------
 
 WsjcppJsonRpc20ParamDef & WsjcppJsonRpc20ParamDef::required() {
-    m_sRestrict = "required";
+    m_bRequired = true;
     return *this;
 }
 
@@ -569,7 +571,7 @@ nlohmann::json WsjcppJsonRpc20ParamDef::toJson() {
     nlohmann::json obj;
     obj["name"] = m_sName;
     obj["type"] = m_sType;
-    obj["restrict"] = m_sRestrict;
+    obj["restrict"] = m_bRequired ? "required" : "optional";
     obj["description"] = m_sDescription;
     // TODO validator description
     return obj;
@@ -601,14 +603,8 @@ const std::string &WsjcppJsonRpc20ParamDef::getName() const {
 
 // ---------------------------------------------------------------------
 
-const std::string &WsjcppJsonRpc20ParamDef::getRestrict() {
-    return m_sRestrict;
-}
-
-// ---------------------------------------------------------------------
-
-const std::string &WsjcppJsonRpc20ParamDef::getRestrict() const {
-    return m_sRestrict;
+const std::string WsjcppJsonRpc20ParamDef::getRestrict() const {
+    return m_bRequired ? "required" : "optional";
 }
 
 // ---------------------------------------------------------------------
@@ -626,13 +622,13 @@ const std::string &WsjcppJsonRpc20ParamDef::getDescription() const {
 // ---------------------------------------------------------------------
 
 bool WsjcppJsonRpc20ParamDef::isRequired() {
-    return m_sRestrict == "required";
+    return m_bRequired;
 }
 
 // ---------------------------------------------------------------------
 
 bool WsjcppJsonRpc20ParamDef::isOptional() {
-    return m_sRestrict == "optional";
+    return !m_bRequired;
 }
 
 // ---------------------------------------------------------------------
@@ -1382,6 +1378,20 @@ WsjcppJsonRpc20HandlerBase * WsjcppJsonRpc20::findJsonRpc20Handler(const std::st
     return pHandler;
 }
 
+// ---------------------------------------------------------------------
+
+std::vector WsjcppJsonRpc20::getEventList() {
+    std::vector vEvents;
+    // TODO
+    return vEvents;
+}
+
+// ---------------------------------------------------------------------
+
+void WsjcppJsonRpc20::registryEventFabric(const std::string &sEventName, WsjcppJsonRpc20EventBase* pEventFabric) {
+    // TODO
+}
+
 // ---------------------------------------------------------------------
 // WsjcppJsonRpc20HandlerServerApi
 
diff --git a/src/wsjcpp_jsonrpc20.h b/src/wsjcpp_jsonrpc20.h
index 0116072..24db3be 100644
--- a/src/wsjcpp_jsonrpc20.h
+++ b/src/wsjcpp_jsonrpc20.h
@@ -190,8 +190,7 @@ class WsjcppJsonRpc20ParamDef {
         const std::string &getType() const;
         const std::string &getName();
         const std::string &getName() const;
-        const std::string &getRestrict();
-        const std::string &getRestrict() const;
+        const std::string getRestrict() const;
         const std::string &getDescription();
         const std::string &getDescription() const;
 
@@ -214,7 +213,7 @@ class WsjcppJsonRpc20ParamDef {
         std::string TAG;
         std::string m_sType;
         std::string m_sName;
-        std::string m_sRestrict;
+        bool m_bRequired;
         std::string m_sDescription;
 
         std::string JSONRPC20_PARAM_DEF_TYPE_INTEGER = "integer";
@@ -273,6 +272,23 @@ class WsjcppJsonRpc20Request {
         bool m_bResponseSend;
 };
 
+// ---------------------------------------------------------------------
+// WsjcppJsonRpc20EventBase - api handler basic class
+
+class WsjcppJsonRpc20EventBase {
+    public:
+        WsjcppJsonRpc20EventBase(const std::string &sEventName, const std::string &sDescription);
+
+    protected:
+        std::string TAG;
+        std::string m_sEventName;
+        std::string m_sDescription;
+};
+
+// Registry Wsjcpp JsonRpc20 Event Fabric
+#define REGISTRY_WSJCPP_JSONRPC20_EVENT_FABRIC( classname ) \
+    static classname * pRegistryWsjcppJsonRpc20 ## classname = new classname(); \
+
 // ---------------------------------------------------------------------
 // WsjcppJsonRpc20HandlerBase - api handler basic class
 
@@ -337,6 +353,8 @@ class WsjcppJsonRpc20 {
         static void initGlobalVariables();
         static void addHandler(const std::string &sName, WsjcppJsonRpc20HandlerBase* pCmdHandler);
         static WsjcppJsonRpc20HandlerBase *findJsonRpc20Handler(const std::string &sCmd);
+        static std::vector getEventList();
+        static void registryEventFabric(const std::string &sEventName, WsjcppJsonRpc20EventBase* pEventFabric);
 };
 
 // Registry Wsjcpp JsonRpc20 Handler
diff --git a/src/wsjcpp_jsonrpc20_export_cli_base.cpp b/src/wsjcpp_jsonrpc20_export_cli_base.cpp
new file mode 100644
index 0000000..387b592
--- /dev/null
+++ b/src/wsjcpp_jsonrpc20_export_cli_base.cpp
@@ -0,0 +1,107 @@
+#include "wsjcpp_jsonrpc20_export_cli_base.h"
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include  // put_time
+#include 
+#include 
+
+// ---------------------------------------------------------------------
+// WsjcppJsonRpc20ExportCliBase
+
+WsjcppJsonRpc20ExportCliBase::WsjcppJsonRpc20ExportCliBase(
+    const std::string &sExportDir,
+    const std::string &sPackageName
+) {
+    TAG = "WsjcppJsonRpc20ExportCliBase";
+    m_sExportDir = WsjcppCore::doNormalizePath(sExportDir);
+    m_sPackageName = sPackageName;
+    m_sAppName = "unknown";
+    m_sAppVersion = "unknown";
+    m_sAuthorName = "Unknown";
+    m_sAuthorEmail = "unknown";
+    m_sClassName = "Unknown";
+}
+
+// ---------------------------------------------------------------------
+
+std::string WsjcppJsonRpc20ExportCliBase::getExportDir() const {
+    return m_sExportDir;
+}
+
+// ---------------------------------------------------------------------
+
+std::string WsjcppJsonRpc20ExportCliBase::getPackageName() const {
+    return m_sPackageName;
+}
+
+// ---------------------------------------------------------------------
+
+void WsjcppJsonRpc20ExportCliBase::setAppName(const std::string &sAppName) {
+    m_sAppName = sAppName;
+}
+
+// ---------------------------------------------------------------------
+
+std::string WsjcppJsonRpc20ExportCliBase::getAppName() const {
+    return m_sAppName;
+}
+
+// ---------------------------------------------------------------------
+
+void WsjcppJsonRpc20ExportCliBase::setAppVersion(const std::string &sAppVersion) {
+    // https://www.python.org/dev/peps/pep-0440/
+    // [N!]N(.N)*[{a|b|rc}N][.postN][.devN]
+    // TODO regexp 
+    m_sAppVersion = sAppVersion;
+}
+
+// ---------------------------------------------------------------------
+
+std::string WsjcppJsonRpc20ExportCliBase::getAppVersion() const {
+    return m_sAppVersion;
+}
+
+// ---------------------------------------------------------------------
+
+void WsjcppJsonRpc20ExportCliBase::setAuthorName(const std::string &sAuthorName) {
+    m_sAuthorName = sAuthorName;
+}
+
+// ---------------------------------------------------------------------
+
+std::string WsjcppJsonRpc20ExportCliBase::getAuthorName() const {
+    return m_sAuthorName;
+}
+
+// ---------------------------------------------------------------------
+
+void WsjcppJsonRpc20ExportCliBase::setAuthorEmail(const std::string &sAuthorEmail) {
+    m_sAuthorEmail = sAuthorEmail;
+}
+
+// ---------------------------------------------------------------------
+
+std::string WsjcppJsonRpc20ExportCliBase::getAuthorEmail() const {
+    return m_sAuthorEmail;
+}
+
+// ---------------------------------------------------------------------
+
+void WsjcppJsonRpc20ExportCliBase::setClassName(const std::string &sClassName) {
+    m_sClassName = sClassName;
+}
+
+// ---------------------------------------------------------------------
+
+std::string WsjcppJsonRpc20ExportCliBase::getClassName() const {
+    return m_sClassName;
+}
+
+// ---------------------------------------------------------------------
\ No newline at end of file
diff --git a/src/wsjcpp_jsonrpc20_export_cli_base.h b/src/wsjcpp_jsonrpc20_export_cli_base.h
new file mode 100644
index 0000000..8d268ef
--- /dev/null
+++ b/src/wsjcpp_jsonrpc20_export_cli_base.h
@@ -0,0 +1,45 @@
+#ifndef WSJCPP_JSONRPC20_EXPORT_CLI_BASE_H
+#define WSJCPP_JSONRPC20_EXPORT_CLI_BASE_H
+
+#include "wsjcpp_core.h"
+#include "wsjcpp_jsonrpc20.h"
+#include 
+
+class WsjcppJsonRpc20ExportCliBase {
+    public:
+        WsjcppJsonRpc20ExportCliBase(
+            const std::string &sExportDir,
+            const std::string &sPackageName
+        );
+
+        std::string getExportDir() const;
+        std::string getPackageName() const;
+        void setAppName(const std::string &sAppName);
+        std::string getAppName() const;
+        void setAppVersion(const std::string &sAppVersion);
+        std::string getAppVersion() const;
+        void setAuthorName(const std::string &sAuthorName);
+        std::string getAuthorName() const;
+        void setAuthorEmail(const std::string &sAuthorEmail);
+        std::string getAuthorEmail() const;
+        void setClassName(const std::string &sClassName);
+        std::string getClassName() const;
+
+        virtual bool doExportLib() = 0;
+
+    protected:
+        std::string TAG;
+
+    private:
+        std::string m_sExportDir;
+        std::string m_sPackageName;
+        std::string m_sAppName;
+        std::string m_sAppVersion;
+
+        std::string m_sClassName;
+        std::string m_sAuthorName;
+        std::string m_sAuthorEmail;
+
+};
+
+#endif //  WSJCPP_JSONRPC20_EXPORT_CLI_BASE_H
\ No newline at end of file
diff --git a/src/wsjcpp_jsonrpc20_export_cli_python.cpp b/src/wsjcpp_jsonrpc20_export_cli_python.cpp
index 9014912..4a65b71 100644
--- a/src/wsjcpp_jsonrpc20_export_cli_python.cpp
+++ b/src/wsjcpp_jsonrpc20_export_cli_python.cpp
@@ -126,53 +126,13 @@ class PyCodeBuilder {
 WsjcppJsonRpc20ExportCliPython::WsjcppJsonRpc20ExportCliPython(
     const std::string &sExportDir,
     const std::string &sPackageName
-) {
+) : WsjcppJsonRpc20ExportCliBase(sExportDir, sPackageName) {
     TAG = "WsjcppJsonRpc20ExportCliPython";
-    m_sExportDir = WsjcppCore::doNormalizePath(sExportDir);
-    m_sPackageName = sPackageName;
-    m_sAuthorName = "Unknown";
-    m_sAuthorEmail = "unknown";
-    m_sAppName = "unknown";
-    m_sAppVersion = "unknown";
-    m_sClassName = "SomeClient";
     m_sUrl = "none";
 }
 
 // ---------------------------------------------------------------------
 
-void WsjcppJsonRpc20ExportCliPython::setAuthorName(const std::string &sAuthorName) {
-    m_sAuthorName = sAuthorName;
-}
-
-// ---------------------------------------------------------------------
-
-void WsjcppJsonRpc20ExportCliPython::setAuthorEmail(const std::string &sAuthorEmail) {
-    m_sAuthorEmail = sAuthorEmail;
-}
-
-// ---------------------------------------------------------------------
-
-void WsjcppJsonRpc20ExportCliPython::setAppName(const std::string &sAppName) {
-    m_sAppName = sAppName;
-}
-
-// ---------------------------------------------------------------------
-
-void WsjcppJsonRpc20ExportCliPython::setAppVersion(const std::string &sAppVersion) {
-    // https://www.python.org/dev/peps/pep-0440/
-    // [N!]N(.N)*[{a|b|rc}N][.postN][.devN]
-    // TODO regexp 
-    m_sAppVersion = sAppVersion;
-}
-
-// ---------------------------------------------------------------------
-
-void WsjcppJsonRpc20ExportCliPython::setClassName(const std::string &sClassName) {
-    m_sClassName = sClassName;
-}
-
-// ---------------------------------------------------------------------
-
 void WsjcppJsonRpc20ExportCliPython::setUrl(const std::string &sUrl) {
     m_sUrl = sUrl;
 }
@@ -235,7 +195,7 @@ bool WsjcppJsonRpc20ExportCliPython::doExportLib() {
 
 bool WsjcppJsonRpc20ExportCliPython::exportPrepareDirs() {
     std::vector vCreateDirs;
-    std::vector vSplited = WsjcppCore::split(m_sExportDir, "/");
+    std::vector vSplited = WsjcppCore::split(this->getExportDir(), "/");
     std::string sExportDir = "";
     for (int i = 0; i < vSplited.size(); i++) {
         if (i > 0) {
@@ -245,7 +205,7 @@ bool WsjcppJsonRpc20ExportCliPython::exportPrepareDirs() {
         sExportDir = WsjcppCore::doNormalizePath(sExportDir);
         vCreateDirs.push_back(sExportDir);
     }
-    sExportDir = WsjcppCore::doNormalizePath(sExportDir + "/" + m_sPackageName);
+    sExportDir = WsjcppCore::doNormalizePath(sExportDir + "/" + this->getPackageName());
     vCreateDirs.push_back(sExportDir);
 
     for (int i = 0; i < vCreateDirs.size(); i++) {
@@ -267,21 +227,21 @@ bool WsjcppJsonRpc20ExportCliPython::exportPrepareDirs() {
 // ---------------------------------------------------------------------
 
 bool WsjcppJsonRpc20ExportCliPython::prepareReadmeMdIfNeed() {
-    std::string sReadmeMd = m_sExportDir + "/README.md";
+    std::string sReadmeMd = this->getExportDir() + "/README.md";
     if (!WsjcppCore::fileExists(sReadmeMd)) {
         std::string sContentReadme = 
-            "#" + m_sPackageName + "\n\n"
-            + m_sClassName + " Python Library for " + m_sAppName + "\n\n"
+            "#" + this->getPackageName() + "\n\n"
+            + this->getClassName() + " Python Library for " + this->getAppName() + "\n\n"
             + "## Install \n\n"
             + "```\n"
-            + "$ pip3 install " + m_sPackageName + " --upgrade\n"
+            + "$ pip3 install " + this->getPackageName() + " --upgrade\n"
             + "```\n\n"
             + "## Example code\n\n"
             + "```\n"
             + "#!/usr/bin/env python3\n"
             + "# -*- coding: utf-8 -*-\n"
-            + "from " + m_sPackageName + " import " + m_sClassName + "\n\n"
-            + "client = " + m_sClassName + "(\"ws://host/ws-api/\")\n\n"
+            + "from " + this->getPackageName() + " import " + this->getClassName() + "\n\n"
+            + "client = " + this->getClassName() + "(\"ws://host/ws-api/\")\n\n"
             + "resp = client.server_api({})\n\n"
             + "print(resp)\n"
             + "```\n\n"
@@ -296,7 +256,7 @@ bool WsjcppJsonRpc20ExportCliPython::prepareReadmeMdIfNeed() {
 
 bool WsjcppJsonRpc20ExportCliPython::exportSetupPy() {
     std::ofstream setupPy;
-    std::string sFilename = m_sExportDir + "/setup.py";
+    std::string sFilename = this->getExportDir() + "/setup.py";
     WsjcppLog::info(TAG, "Prepare setup.py " + sFilename);
     
     // https://packaging.python.org/tutorials/packaging-projects/
@@ -307,14 +267,14 @@ bool WsjcppJsonRpc20ExportCliPython::exportSetupPy() {
         "    long_description = fh.read()\n"
         "\n"
         "setuptools.setup(\n"
-        "    name='" + m_sPackageName + "',\n"
-        "    version='" + m_sAppVersion + "',\n"
-        "    packages=['" + m_sPackageName + "'],\n"
+        "    name='" + this->getPackageName() + "',\n"
+        "    version='" + this->getAppVersion() + "',\n"
+        "    packages=['" + this->getPackageName() + "'],\n"
         "    install_requires=['websocket-client>=0.56.0', 'requests>=2.21.0'],\n"
         "    keywords=['" + WsjcppCore::join(m_vKeywords, "', '") + "'],\n"
-        "    author='" + m_sAuthorName + "',\n"
-        "    author_email='" + m_sAuthorEmail + "',\n"
-        "    description='" + m_sClassName + " Python Library for " + m_sAppName + "',\n"
+        "    author='" + this->getAuthorName() + "',\n"
+        "    author_email='" + this->getAuthorEmail() + "',\n"
+        "    description='" + this->getClassName() + " Python Library for " + this->getAppName() + "',\n"
         "    long_description=long_description,\n"
         "    long_description_content_type='text/markdown',\n"
         "    url='" + m_sUrl + "',\n"
@@ -345,21 +305,21 @@ bool WsjcppJsonRpc20ExportCliPython::exportSetupPy() {
 bool WsjcppJsonRpc20ExportCliPython::exportAPImd() {
     
     std::ofstream apimd;
-    std::string sFilename = m_sExportDir + "/API.md";
+    std::string sFilename = this->getExportDir() + "/API.md";
     WsjcppLog::info(TAG, "Prepare API.md " + sFilename);
 
     apimd.open(sFilename);
 
     long nSec = WsjcppCore::getCurrentTimeInSeconds();
 
-    apimd << "# " + m_sClassName + " Python Library \n\n";
-    apimd << "Automatically generated by " << m_sAppName << ". \n";
-    apimd << "* Version: " << m_sAppVersion << "\n";
+    apimd << "# " + this->getClassName() + " Python Library \n\n";
+    apimd << "Automatically generated by " << this->getAppName() << ". \n";
+    apimd << "* Version: " << this->getAppVersion() << "\n";
     apimd << "* Date: " << WsjcppCore::formatTimeForWeb(nSec) << "\n\n";
     apimd << "Example connect/disconnect:\n"
         << "```\n"
-        << "from " + m_sPackageName + " import " + m_sClassName + " \n\n"
-        << "client = " + m_sClassName + "('ws://host:1234')\n"
+        << "from " + getPackageName() + " import " + this->getClassName() + " \n\n"
+        << "client = " + this->getClassName() + "('ws://host:1234')\n"
         << " ... \n"
         << "client.close()\n"
         << "```\n";
@@ -426,11 +386,11 @@ bool WsjcppJsonRpc20ExportCliPython::exportAPImd() {
 // ---------------------------------------------------------------------
 
 bool WsjcppJsonRpc20ExportCliPython::exportInitPy() {
-    std::string sFilename = m_sExportDir + "/" + m_sPackageName + "/__init__.py";
+    std::string sFilename = this->getExportDir() + "/" + this->getPackageName() + "/__init__.py";
     WsjcppLog::info(TAG, "Prepare __init__.py " + sFilename);
     std::ofstream __init__;
     __init__.open (sFilename);
-    __init__ << "from ." << m_sClassName << " import " << m_sClassName << "\n";
+    __init__ << "from ." << this->getClassName() << " import " << this->getClassName() << "\n";
     WsjcppLog::ok(TAG, "Done: " + sFilename);
     return true;
 }
@@ -470,9 +430,11 @@ void exportCliPythonAddCheckDataTypeOfParam(
     }
 };
 
+// ---------------------------------------------------------------------
+
 bool WsjcppJsonRpc20ExportCliPython::exportClientPy() {
-    std::string sFilename = m_sExportDir + "/" + m_sPackageName + "/" + m_sClassName + ".py";
-    WsjcppLog::info(TAG, "Prepare " + m_sClassName + ".py: " + sFilename);
+    std::string sFilename = this->getExportDir() + "/" + this->getPackageName() + "/" + this->getClassName() + ".py";
+    WsjcppLog::info(TAG, "Prepare " + this->getClassName() + ".py: " + sFilename);
 
     std::ofstream clientpy;
     clientpy.open (sFilename);
@@ -483,8 +445,8 @@ bool WsjcppJsonRpc20ExportCliPython::exportClientPy() {
     builder
     .add("#!/usr/bin/env python3")
     .add("# -*- coding: utf-8 -*-")
-    .add("### This file was automatically generated by " + m_sAppName)
-    .add("### Version: " + m_sAppVersion)
+    .add("### This file was automatically generated by " + this->getAppName())
+    .add("### Version: " + this->getAppVersion())
     .add("### Date: " + WsjcppCore::formatTimeForWeb(nSec))
     .add("")
     .add("import asyncio")
@@ -493,10 +455,10 @@ bool WsjcppJsonRpc20ExportCliPython::exportClientPy() {
     .add("import select")
     .add("import time")
     .add("")
-    .sub("class " + m_sClassName + ":")
+    .sub("class " + this->getClassName() + ":")
         .add("__ws = None")
         .add("__url = None")
-        .add("__cli_version = '" + m_sAppVersion + "'")
+        .add("__cli_version = '" + this->getAppVersion() + "'")
         .add("__loop = None")
         .add("__token = None")
         .add("__connecting = False")
@@ -534,6 +496,7 @@ bool WsjcppJsonRpc20ExportCliPython::exportClientPy() {
         .sub("def getToken(self):")
             .add("return self.__token")
             .end()
+        .add("")
         .sub("def setToken(self, token):")
             .sub("if self.__token is None:")
                 .add("self.__token = token")
@@ -748,14 +711,14 @@ bool WsjcppJsonRpc20ExportCliPython::exportClientPy() {
             if (paramDef.isRequired()) {
                 builder
                 .sub("if " + sParamName + " is None: ")
-                    .add("raise Exception('Parameter \"" + sParamName + "\" expected (lib: " + m_sClassName + "." + sMethod + ")')")
+                    .add("raise Exception('Parameter \"" + sParamName + "\" expected (lib: " + this->getClassName() + "." + sMethod + ")')")
                     .end();
-                exportCliPythonAddCheckDataTypeOfParam(builder, paramDef, m_sClassName, sMethod);
+                exportCliPythonAddCheckDataTypeOfParam(builder, paramDef, this->getClassName(), sMethod);
                 builder.add("reqJson['params']['" + sParamName + "'] = " + sParamName);
             } else if (paramDef.isOptional()) {
                 builder
                     .sub("if " + sParamName + " != None: ");
-                exportCliPythonAddCheckDataTypeOfParam(builder, paramDef, m_sClassName, sMethod);
+                exportCliPythonAddCheckDataTypeOfParam(builder, paramDef, this->getClassName(), sMethod);
                     builder
                         .add("reqJson['params']['" + sParamName + "'] = " + sParamName)
                         .end();
diff --git a/src/wsjcpp_jsonrpc20_export_cli_python.h b/src/wsjcpp_jsonrpc20_export_cli_python.h
index 69d0b27..e58648c 100644
--- a/src/wsjcpp_jsonrpc20_export_cli_python.h
+++ b/src/wsjcpp_jsonrpc20_export_cli_python.h
@@ -1,37 +1,25 @@
 #ifndef WSJCPP_JSONRPC20_EXPORT_CLI_PYTHON_H
 #define WSJCPP_JSONRPC20_EXPORT_CLI_PYTHON_H
 
-#include 
+#include "wsjcpp_jsonrpc20_export_cli_base.h"
 #include 
 #include 
 
-class WsjcppJsonRpc20ExportCliPython {
+class WsjcppJsonRpc20ExportCliPython : public WsjcppJsonRpc20ExportCliBase {
     public:
         WsjcppJsonRpc20ExportCliPython(
             const std::string &sExportDir,
             const std::string &sPackageName
         );
-        void setAuthorName(const std::string &sAuthorName);
-        void setAuthorEmail(const std::string &sAuthorEmail);
-        void setAppName(const std::string &sAppName);
-        void setAppVersion(const std::string &sAppVersion);
-        void setClassName(const std::string &sClassName);
         void setUrl(const std::string &sUrl);
         void setDownloadUrl(const std::string &sDownloadUrl);
         void setKeywords(const std::vector &vKeywords);
         void addLoginMethod(const std::string &sMethod, const std::string &sResultVarName);
         void addLogoffMethod(const std::string &sMethod);
 
-        bool doExportLib();
+        virtual bool doExportLib() override;
     private:
-        std::string TAG;
-        std::string m_sExportDir;
-        std::string m_sPackageName;
-        std::string m_sAuthorName;
-        std::string m_sAuthorEmail;
-        std::string m_sAppName;
-        std::string m_sAppVersion;
-        std::string m_sClassName;
+
         std::string m_sUrl;
         std::string m_sDownloadUrl;
         std::vector m_vKeywords;
diff --git a/src/wsjcpp_jsonrpc20_export_cli_webjs.cpp b/src/wsjcpp_jsonrpc20_export_cli_webjs.cpp
new file mode 100644
index 0000000..cc2ff1e
--- /dev/null
+++ b/src/wsjcpp_jsonrpc20_export_cli_webjs.cpp
@@ -0,0 +1,1076 @@
+#include "wsjcpp_jsonrpc20_export_cli_webjs.h"
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include  // put_time
+#include 
+#include 
+
+// ---------------------------------------------------------------------
+
+WsjcppJsonRpc20ExportCliWebJs::WsjcppJsonRpc20ExportCliWebJs(
+    const std::string &sExportDir,
+    const std::string &sPackageName
+) : WsjcppJsonRpc20ExportCliBase(sExportDir, sPackageName) {
+    TAG = "WsjcppJsonRpc20ExportCliWebJs";
+    m_sDefaultConnectionString = "ws://localhost:1234/";
+
+    // TODO must be WsjcppJsonRpc20::eventsList() or something like
+    m_vEvents.push_back("server");
+    m_vEvents.push_back("notify");
+    m_vEvents.push_back("chat");
+    m_vEvents.push_back("connected");
+    m_vEvents.push_back("reconnecting");
+    m_vEvents.push_back("disconnected");
+    m_vEvents.push_back("broken");
+    m_vEvents.push_back("userdata");
+}
+
+// ---------------------------------------------------------------------
+
+void WsjcppJsonRpc20ExportCliWebJs::setIssuesURL(const std::string &sIssuesURL) {
+    m_sIssuesURL = sIssuesURL;
+}
+
+// ---------------------------------------------------------------------
+
+void WsjcppJsonRpc20ExportCliWebJs::setRepository(const std::string &sRepositoryType, const std::string &sRepositoryURL) {
+    m_sRepositoryType = sRepositoryType;
+    m_sRepositoryURL = sRepositoryURL;
+}
+
+// ---------------------------------------------------------------------
+
+void WsjcppJsonRpc20ExportCliWebJs::setKeywords(const std::vector &vKeywords) {
+    m_vKeywords = vKeywords;
+}
+
+// ---------------------------------------------------------------------
+
+void WsjcppJsonRpc20ExportCliWebJs::setLicense(const std::string &sLicenseType, const std::string &sLicenseURL) {
+    m_sLicenseType = sLicenseType;
+    m_sLicenseURL = sLicenseURL;
+}
+
+// ---------------------------------------------------------------------
+
+void WsjcppJsonRpc20ExportCliWebJs::setDefaultConnectionString(const std::string &sDefaultConnectionString) {
+    m_sDefaultConnectionString = sDefaultConnectionString;
+}
+
+// ---------------------------------------------------------------------
+
+bool WsjcppJsonRpc20ExportCliWebJs::doExportLib() {
+    std::string sBasicDir = "./" + this->getPackageName();
+
+    if (!prepareDirs()) {
+        return false;
+    }
+    if (!exportLibCliWebJSFile()) {
+        return false;
+    }
+
+    // exportLibCliWebServiceTSFile(sBasicDir);
+    exportSampleHtmlFile();
+    exportPackageJson();
+    exportAPImd();
+    return true;
+}
+
+// ---------------------------------------------------------------------
+
+bool WsjcppJsonRpc20ExportCliWebJs::prepareDirs() {
+    std::vector vDirs;
+    vDirs.push_back(this->getExportDir());
+    vDirs.push_back(this->getExportDir() + "/dist");
+    
+    for (int i = 0; i < vDirs.size(); i++) {
+        std::string sDir = vDirs[i];
+        if (!WsjcppCore::dirExists(sDir)) {
+            
+            if (WsjcppCore::makeDir(sDir)) {
+                WsjcppLog::ok(TAG, "Created directory '" + sDir + "'");
+            } else {
+                WsjcppLog::err(TAG, "Could not create directory '" + sDir + "'");
+                return false;
+            }
+        } else {
+            WsjcppLog::info(TAG, "Directory already exists '" + sDir + "'");
+        }
+    }
+    return true;
+}
+
+// ---------------------------------------------------------------------
+
+void WsjcppJsonRpc20ExportCliWebJs::exportPackageJson() {
+    std::ofstream packageJson;
+    std::cout << " * write code to " << this->getExportDir() << "/package.json " << std::endl;
+    packageJson.open (this->getExportDir() + "/package.json");
+
+    std::time_t t = std::time(nullptr);
+    std::stringstream buffer;
+    buffer << std::put_time(std::gmtime(&t), "%d %b %Y");
+
+    // look here an example https://github.com/jquery/jquery/blob/master/package.json
+    packageJson << 
+        "{\n"
+        "  \"name\": \"" + this->getPackageName() + "\",\n"
+        "  \"version\": \"" + this->getAppVersion() + "\",\n"
+        "  \"description\": \"" + this->getClassName() + " JavaScript Web Client Library for " + this->getAppName() + "\",\n"
+        "  \"main\": \"dist/" + this->getPackageName() + ".js\",\n"
+        "  \"repository\": {\n"
+        "    \"type\": \"" + m_sRepositoryType + "\",\n"
+        "    \"url\": \"" + m_sRepositoryURL + "\"\n"
+        "  },\n";
+    if (m_vKeywords.size() > 0) {
+        packageJson << 
+        "  \"keywords\": [\n    \"" + WsjcppCore::join(m_vKeywords, "\",\n    \"") + "\"\n  ],\n";
+    }
+    packageJson << 
+        "  \"bugs\": {\n"
+        "    \"url\": \"" + m_sIssuesURL + "\"\n"
+        "  },\n"
+        "  \"author\": \"" + this->getAuthorName() + " <" + this->getAuthorEmail() + ">\",\n"
+        "  \"license\": \"" + m_sLicenseType + "\",\n"
+        "  \"licenses\": [{\n"
+        "    \"type\": \"" + m_sLicenseType + "\",\n"
+        "    \"url\": \"" + m_sLicenseURL + "\"\n"
+        "  }]\n"
+        "}\n";
+    packageJson.close();
+    std::cout << "\t> OK" << std::endl;
+}
+
+// ---------------------------------------------------------------------
+
+void WsjcppJsonRpc20ExportCliWebJs::exportAPImd() {
+    
+    std::ofstream apimd;
+    std::cout << " * write file to " + this->getExportDir() + "/API.md" << std::endl;
+    apimd.open(this->getExportDir() + "/API.md");
+
+    std::time_t t = std::time(nullptr);
+    std::stringstream buffer;
+    buffer << std::put_time(std::gmtime(&t), "%d %b %Y");
+
+    apimd <<
+        "# " + this->getPackageName() + "\n\n"
+        " Automatically generated by " << this->getAppName() << ". \n"
+        " * Version: " << this->getAppVersion() << "\n"
+        " * Date: " << buffer.str() << "\n\n"
+        " Include script ```dist/" + this->getPackageName() + ".js```\n"
+        " Example connect:\n"
+        "```\n"
+        "var client = new " + this->getClassName() + "();\n"
+    ;
+    for (int i = 0; i < m_vEvents.size(); i++) {
+        apimd <<
+            "client.bind('" + m_vEvents[i] + "', function(data) { console.log('" + m_vEvents[i] + "', data)})\n";
+    }
+    apimd <<
+        "client.bind('connected', function(data) { console.log('connected', data)})\n"
+        "// connect\n"
+        "client.init({'baseUrl': '" + m_sDefaultConnectionString + "'})\n"
+        "// disconnect\n"
+        "client.deinit()\n"
+        "```\n"
+        "\n";
+
+    std::map::iterator it = g_pWsjcppJsonRpc20HandlerList->begin();
+    for (; it!=g_pWsjcppJsonRpc20HandlerList->end(); ++it) {
+        std::string sCmd = it->first;
+        WsjcppJsonRpc20HandlerBase* pWsjcppJsonRpc20HandlerBase = it->second;
+        
+        apimd <<
+            "
\n" + "" << sCmd << "\n\n" + "## " << sCmd << "\n\n"; + + if (pWsjcppJsonRpc20HandlerBase->getDescription() != "") { + apimd << pWsjcppJsonRpc20HandlerBase->getDescription() << "\n\n"; + } + apimd << + "Access: unauthorized - **" << (pWsjcppJsonRpc20HandlerBase->haveUnauthorizedAccess() ? "yes" : "no") << "**, " + " user - **" << (pWsjcppJsonRpc20HandlerBase->haveUserAccess() ? "yes" : "no") << "**, " + " tester - **" << (pWsjcppJsonRpc20HandlerBase->haveTesterAccess() ? "yes" : "no") << "**, " + " admin - **" << (pWsjcppJsonRpc20HandlerBase->haveAdminAccess() ? "yes" : "no") << "**\n" + "\n"; + + apimd << " #### Input params \n\n"; + + std::string jsTemplate = ""; + + std::vector vVin = pWsjcppJsonRpc20HandlerBase->getParamsDef(); + for (int i = 0; i < vVin.size(); i++) { + WsjcppJsonRpc20ParamDef inDef = vVin[i]; + std::string nameIn = std::string(inDef.getName()); + + apimd << " * " << inDef.getName() << " - " << inDef.getType() << ", " << inDef.getRestrict() << "; " << inDef.getDescription() << "\n"; + + if (jsTemplate != "") { + jsTemplate += ",\n"; + } + if (inDef.isInteger()) { + int nVal = 0; + if (inDef.getName() == "onpage") { + nVal = 10; + } + jsTemplate += " \"" + inDef.getName() + "\": " + std::to_string(nVal); + } else { + jsTemplate += " \"" + inDef.getName() + "\": \"\""; + } + } + apimd << + "\n\n" + " #### example call method \n\n" + "```\n" + "client." + sCmd + "({\n" + jsTemplate + "\n}).done(function(r) {\n" + " console.log('Success: ', r);\n" + "}).fail(function(err) {\n" + " console.error('Error:', err);\n" + "});\n" + "```" + "\n\n" + "
" + "\n\n"; + } + + apimd.close(); + std::cout << "\t> OK" << std::endl; +} + +// --------------------------------------------------------------------- + +void WsjcppJsonRpc20ExportCliWebJs::exportSampleHtmlFile() { + std::string sFilename = this->getExportDir() + "/sample.html"; + std::ofstream sample_html; + std::cout << " * write code to " << sFilename << std::endl; + sample_html.open(sFilename); + sample_html << + "\r\n" + "\r\n" + " \r\n" + " \r\n" + "\r\n" + "\r\n" + "
\r\n" + "

Connect to Server

\r\n" + "
\r\n" + " \r\n" + "
\r\n" + "\r\n" + "\r\n" + "\r\n" + "
\r\n"
+        "\r\n"
+        "\r\n";
+    sample_html.close();
+    std::cout << "\t> OK" << std::endl;
+}
+
+// ---------------------------------------------------------------------
+
+bool WsjcppJsonRpc20ExportCliWebJs::exportLibCliWebJSFile() {
+
+    std::string sFilename = this->getExportDir() + "/dist/" + this->getPackageName() + ".js";
+    std::ofstream libwjscppcli_web_js_file;
+    std::cout << " * write code to " << sFilename << std::endl;
+    libwjscppcli_web_js_file.open(sFilename);
+
+    // TODO move to fallen
+    std::time_t t = std::time(nullptr);
+    std::stringstream buffer;
+    buffer << std::put_time(std::gmtime(&t), "%d %b %Y");
+    std::string sBuildDate(buffer.str());
+    // now the result is in `buffer.str()`.
+
+    libwjscppcli_web_js_file <<
+        "// This file was automatically generated by " << this->getAppName() << " (" + this->getAppVersion() + "), date: " << sBuildDate << "\r\n"
+        "window." << this->getClassName() << " = window." << this->getClassName() << " || (function() { \r\n"
+        "    var self = {};\r\n"
+        "    self.appName = '" + this->getAppName() + "';\r\n"
+        "    self.appVersion = '" + this->getAppVersion() + "';\r\n"
+        "    self.appBuildDate = '" + sBuildDate + "';\r\n"
+        "    var _lastm = 0;\r\n"
+        "    var _listeners = {};\r\n"
+        "    var _connectionState = '?';\r\n"
+        "    var _tokenValue = '';\r\n"
+        "    var _events = {\r\n";
+    
+    for (int i = 0; i < m_vEvents.size(); i++) {
+        libwjscppcli_web_js_file <<
+        "        '" << m_vEvents[i] << "': [],\r\n";
+    }
+
+    libwjscppcli_web_js_file <<
+        "    };\r\n"
+        "    function _lm() { _lastm++; return 'm' + _lastm; };\r\n"
+        "    console.warn('" + this->getClassName() + " (" + this->getAppVersion() + ")');\r\n"
+        "    self.promise = function() {\r\n"
+        "        return {\r\n"
+        "            completed: false, failed: false, successed: false, \r\n"
+        "            done: function(callback) {\r\n"
+        "                this.done_callback = callback;\r\n"
+        "                if (this.completed && typeof this.done_callback === 'function' && this.successed) {\r\n"
+        "                    this.done_callback.apply(this, this.result_arguments);\r\n"
+        "                }\r\n"
+        "                return this;\r\n"
+        "            },\r\n"
+        "            fail: function(callback) {\r\n"
+        "                this.fail_callback = callback;\r\n"
+        "                if (this.completed && typeof this.fail_callback === 'function' && this.failed) {\r\n"
+        "                    this.fail_callback.apply(this, this.error_arguments);\r\n"
+        "                }\r\n"
+        "                return this;\r\n"
+        "            },\r\n"
+        "            resolve: function() {\r\n"
+        "                if (!this.completed) {\r\n"
+        "                    this.result_arguments = arguments; // [];\r\n"
+        "                    if (typeof this.done_callback === 'function') {\r\n"
+        "                        this.done_callback.apply(this, this.result_arguments);\r\n"
+        "                    }\r\n"
+        "                }\r\n"
+        "                this.successed = true;\r\n"
+        "                this.completed = true;\r\n"
+        "            },\r\n"
+        "            reject: function() {\r\n"
+        "                if (!this.completed) {\r\n"
+        "                    this.error_arguments = arguments;\r\n"
+        "                    if (typeof this.fail_callback === 'function') {\r\n"
+        "                        this.fail_callback.apply(this, this.error_arguments);\r\n"
+        "                    }\r\n"
+        "                }\r\n"
+        "                this.failed = true;\r\n"
+        "                this.completed = true;\r\n"
+        "            }\r\n"
+        "        }; // end of promise\r\n"
+        "    };\r\n"
+        "    self.waitAllPromises = function(arr_promise) {\r\n"
+        "        var p = self.promise();\r\n"
+        "        var max_len = arr_promise.length;\r\n"
+        "        var result = [];\r\n"
+        "        function cmpl(r) {\r\n"
+        "            result.push(r);\r\n"
+        "            if (result.length == max_len) {\r\n"
+        "                p.resolve(result);\r\n"
+        "            }\r\n"
+        "        };\r\n"
+        "        for (var i in arr_promise) {\r\n"
+        "            arr_promise[i].done(cmpl).fail(cmpl);\r\n"
+        "        }\r\n"
+        "        return p;\r\n"
+        "    };\r\n"
+        "    self.setToken = function(token) {\r\n"
+        "        var date = new Date( new Date().getTime() + (7 * 24 * 60 * 60 * 1000) ); // cookie on week\r\n"
+        "        document.cookie = '" + this->getClassName() + "token=' + encodeURIComponent(token) + '; path=/; expires='+date.toUTCString();\r\n"
+        "    }\r\n"
+        "    self.removeToken = function() {\r\n"
+        "        _tokenValue = '';"
+        "        document.cookie = '" + this->getClassName() + "token=; path=/;';\r\n"
+        "    }\r\n"
+        "    self.getToken = function() {\r\n"
+        "        var matches = document.cookie.match(new RegExp(\r\n"
+        "            '(?:^|; )' + '" + this->getClassName() + "token'.replace(/([\\.$?*|{}\\(\\)\\[\\]\\\\\\/\\+^])/g, '\\\\$1') + '=([^;]*)'\r\n"
+        "        ));\r\n"
+        "        return matches ? decodeURIComponent(matches[1]) : '';\r\n"
+        "    }\r\n"
+        "    _tokenValue = self.getToken();\r\n"
+        "    self.bind = function(name, f) { _events[name].push(f); }\r\n"
+        "    self.unbind = function(name) { _events[name] = []; }\r\n"
+        "    function _call(name, data) {\r\n"
+        "        function __call(f, data) { setTimeout(function() { f(data) },1)}"
+        "        for (var i = 0; i < _events[name].length; i++) {\r\n"
+        "            __call(_events[name][i], data);\r\n"
+        "        }\r\n"
+        "    }\r\n"
+        "    self.bind('server', function(response) { \r\n"
+        "       console.warn('All: ', response);\r\n"
+        "       if (response.app != self.appName) {\r\n"
+        "           console.error('AppName: ' + response.app + ', but expected ' + self.appName);\r\n"
+        "       }\r\n"
+        "       if (response.version != self.appVersion) {\r\n"
+        "           console.error('AppVersion: ' + response.version + ', but expected ' + self.appVersion);\r\n"
+        "       }\r\n"
+        "    }); \r\n"
+        "    self.handleCommand = function(response) {\r\n"
+        "       var lstn = _listeners[response.m];\r\n"
+        "       if (lstn) {\r\n"
+        "           setTimeout(function() {\r\n"
+        "               if (response['error']) {\r\n"
+        "                   lstn.reject(response);\r\n"
+        "               } else {\r\n"
+        "                   lstn.resolve(response);\r\n"
+        "               }\r\n"
+        "               delete _listeners[response.m];\r\n"
+        "           },1);\r\n"
+        "       } else if (_events[response.cmd]) {\r\n"
+        "           _call(response.cmd, response);"
+        "       } else {\r\n"
+        "           console.error('Not found handler for [' + response.cmd + '/' + response.m + ']');\r\n"
+        "       }\r\n"
+        "   };\r\n"
+        "   self.send = function(obj, def) {\r\n"
+        "       obj.m = obj.m || _lm();\r\n"
+        "       _listeners[obj.m] = def || self.promise();\r\n"
+        "       try {\r\n"
+        "           if (self.socket.readyState == 0) {\r\n"
+        "               setTimeout(function() {\r\n"
+        "                   self.send(obj, _listeners[obj.m]);\r\n"
+        "               },1000);\r\n"
+        "           } else {\r\n"
+        "               self.socket.send(JSON.stringify(obj));\r\n"
+        "           }\r\n"
+        "       } catch(e) {\r\n"
+        "           console.error(e);\r\n"
+        "       }\r\n"
+        "       return _listeners[obj.m];\r\n"
+        "    }\r\n"
+        "    self.init = function(initParams) {\r\n"
+        "        if (!initParams.baseUrl) console.error('Expected baseUrl on initParams');\r\n"
+        "        self.socket = new WebSocket(initParams.baseUrl);\r\n"
+        "        self.socket.onopen = function() {\r\n"
+        "           console.log('WS Opened');\r\n"
+        "           _call('connected', {});\r\n"
+        "           if (_tokenValue != '') self.token();\r\n"
+        "        };\r\n"
+        "        self.socket.onclose = function(event) {\r\n"
+        "           console.log('Closed');\r\n"
+        "           if (event.wasClean) {\r\n"
+        "               _call('disconnected', {});\r\n"
+        "           } else {\r\n"
+        "               _call('broken', {});\r\n"
+        "               setTimeout(function() {\r\n"
+        "                   _call('reconnecting', {});\r\n"
+        "                   self.init(initParams);\r\n"
+        "               }, 10000);\r\n"
+        "             // Try reconnect after 5 sec\r\n"
+        "           }\r\n"
+        "           console.log('Code: ' + event.code + ' Reason: ' + event.reason);\r\n"
+        "       };\r\n"
+        "       self.socket.onmessage = function(event) {\r\n"
+        "           // console.log('Received: ' + event.data);\r\n"
+        "           try {\r\n"
+        "               var response = JSON.parse(event.data);\r\n"
+        "               self.handleCommand(response);\r\n"
+        "           } catch(e) {\r\n"
+        "               console.error(e);\r\n"
+        "           }\r\n"
+        "           \r\n"
+        "       };\r\n"
+        "       self.socket.onerror = function(error) {\r\n"
+        "           console.log('Error: ' + error.message);\r\n"
+        "       };\r\n"
+        "    }\r\n"
+        "    self.deinit = function(initParams) {\r\n"
+        "       self.removeToken();\r\n"
+        "       self.socket.close();\r\n"
+        "    }\r\n"
+        "   self.userProfile = {bInitUserProfile: false}\r\n"
+        "   self.updateUserProfileAsync = function() {\r\n"
+        "       setTimeout(function() {\r\n"
+        "           self.user().done(function(r) {\r\n"
+        "               self.userProfile.bInitUserProfile == true;\r\n"
+        "               self.userProfile.university = r.data.university;\r\n"
+        "               self.userProfile.country = r.data.country;\r\n"
+        "               self.userProfile.city = r.data.city;\r\n"
+        "               self.userinfo = {};\r\n"
+        "               self.userinfo.id = r.data.id;\r\n"
+        "               self.userinfo.nick = r.data.nick;\r\n"
+        "               self.userinfo.email = r.data.email;\r\n"
+        "               self.userinfo.role = r.data.role;\r\n"
+        "               self.userinfo.logo = r.data.logo;\r\n"
+        "               _call('userdata', r.data);\r\n"
+        "           }).fail(function() {\r\n"
+        "               self.removeToken();\r\n"
+        "               _call('userdata', {});\r\n"
+        "           });\r\n"
+        "       },10);\r\n"
+        "   }\r\n";
+
+    std::map::iterator it = g_pWsjcppJsonRpc20HandlerList->begin();
+    for (; it!=g_pWsjcppJsonRpc20HandlerList->end(); ++it) {
+        std::string sCmd = it->first;
+        WsjcppJsonRpc20HandlerBase* pWsjcppJsonRpc20HandlerBase = it->second;
+        libwjscppcli_web_js_file <<
+            "    self." << sCmd << " = function(params) {\r\n";
+
+        libwjscppcli_web_js_file <<
+            "       // Access unauthorized: " << (pWsjcppJsonRpc20HandlerBase->haveUnauthorizedAccess() ? "yes" : "no") << "\r\n"
+            "       // Access user: " << (pWsjcppJsonRpc20HandlerBase->haveUserAccess() ? "yes" : "no") << "\r\n"
+            "       // Access tester: " << (pWsjcppJsonRpc20HandlerBase->haveTesterAccess() ? "yes" : "no") << "\r\n"
+            "       // Access admin: " << (pWsjcppJsonRpc20HandlerBase->haveAdminAccess() ? "yes" : "no") << "\r\n";
+        
+        if (pWsjcppJsonRpc20HandlerBase->getActivatedFromVersion() != "") {
+            libwjscppcli_web_js_file <<
+                "       // Activated From Version: " << pWsjcppJsonRpc20HandlerBase->getActivatedFromVersion() << "\r\n";
+        }
+        
+        if (pWsjcppJsonRpc20HandlerBase->getDeprecatedFromVersion() != "") {
+            libwjscppcli_web_js_file <<
+                "       // Deprecated From Version: " + pWsjcppJsonRpc20HandlerBase->getDeprecatedFromVersion() << "\r\n";
+        }
+        
+        std::vector vVin = pWsjcppJsonRpc20HandlerBase->getParamsDef();
+        if (vVin.size() > 0) {
+            libwjscppcli_web_js_file <<
+                "       // Input params:\r\n"; 
+        }
+        for (int i = 0; i < vVin.size(); i++) {
+            WsjcppJsonRpc20ParamDef inDef = vVin[i];
+            std::string nameIn = std::string(inDef.getName());
+            libwjscppcli_web_js_file <<
+                "       // * " + nameIn + " - " + inDef.getType() + ", " + inDef.getRestrict() + " (" + inDef.getDescription() + ") \r\n";
+        }
+
+        libwjscppcli_web_js_file <<
+            "        params = params || {};\r\n"
+            "        params.cmd = '" << sCmd << "';\r\n";
+            // check required
+        for (int i = 0; i < vVin.size(); i++) {
+            WsjcppJsonRpc20ParamDef inDef = vVin[i];
+            if (inDef.isRequired()) {
+                std::string nameIn = std::string(vVin[i].getName());
+                libwjscppcli_web_js_file <<
+                    "        if (params['" + nameIn + "'] == undefined) {\r\n"
+                    "             console.error('Parameter \"" << nameIn << "\" expected (lib)');\r\n"
+                    "        }\r\n";
+            }
+        }
+        if (sCmd == "login") {
+            libwjscppcli_web_js_file <<
+                "        var ret = self.promise()\r\n"
+                "        self.send(params).done(function(r) {\r\n"
+                "            _tokenValue = r.token;\r\n"
+                "            console.log(_tokenValue);\r\n"
+                "            self.userinfo = r.user;\r\n"
+                "            self.setToken(_tokenValue);\r\n"
+                "            self.updateUserProfileAsync();\r\n"
+                "            ret.resolve(r);\r\n"
+                "        }).fail(function(err) {\r\n"
+                "            self.removeToken();\r\n"
+                "            ret.reject(err);\r\n"
+                "        })\r\n"
+                "        return ret;\r\n";
+        } else if (sCmd == "token") {
+            libwjscppcli_web_js_file <<
+                "         if (_tokenValue != '') {\r\n"
+                "             var ret = self.promise()\r\n"
+                "             params.token = _tokenValue;\r\n"
+                "             self.send(params).done(function(r) {\r\n"
+                "                 self.updateUserProfileAsync();\r\n"
+                "                 ret.resolve(r);\r\n"
+                "             }).fail(function(err) {\r\n"
+                "                 self.removeToken();\r\n"
+                "                 _call('userdata', {});\r\n"
+                "                 ret.reject(err);\r\n"
+                "             })\r\n"
+                "             return ret;\r\n"
+                "         } else {\r\n"
+                "             return self.send(params);\r\n"
+                "         }\r\n";
+        } else {
+            libwjscppcli_web_js_file 
+                << "        return self.send(params);\r\n";
+        }
+
+        libwjscppcli_web_js_file 
+            << "    }\r\n\r\n";
+    }
+
+    libwjscppcli_web_js_file <<
+        "    return self;\r\n"
+        "})();\r\n";
+
+    libwjscppcli_web_js_file.close();
+    std::cout << "\t> OK" << std::endl;
+    return true;
+}
+
+// ---------------------------------------------------------------------
+
+void WsjcppJsonRpc20ExportCliWebJs::exportLibCliWebServiceTSFile() {
+    std::string sFilename = this->getExportDir() + "/dist/" + this->getPackageName() + ".service.ts";
+    std::ofstream libwjscppcli_web_service_ts_file;
+    std::cout << " * write code to " << sFilename << std::endl;
+    libwjscppcli_web_service_ts_file.open(sFilename);
+
+    // TODO move to fallen
+    std::time_t t = std::time(nullptr);
+    std::stringstream buffer;
+    buffer << std::put_time(std::gmtime(&t), "%d %b %Y");
+    std::string sBuildDate(buffer.str());
+    // now the result is in `buffer.str()`.
+
+    libwjscppcli_web_service_ts_file <<
+        "// This file was automatically generated by " << this->getAppName() << " (v" + this->getAppVersion() + "), date: " << sBuildDate << "\r\n"
+        "import { Injectable, EventEmitter } from '@angular/core';\r\n"
+        "import { PlatformLocation } from '@angular/common';\r\n"
+        "import { ToastrService } from 'ngx-toastr';\r\n"
+        "\r\n"
+        "declare var FreeHackQuestClientConfig: any;\r\n"
+        "\r\n"
+        "@Injectable({providedIn: 'root'})\r\n"
+        "export class " + this->getClassName() + " {\r\n"
+        "  private appName: string = '" + this->getAppName() + "';\r\n"
+        "  private appVersion: string = '" + this->getAppVersion() + "';\r\n"
+        "  private appBuildDate: string = '" + sBuildDate + "';\r\n"
+        "  isAuthorized: boolean = false;\r\n"
+        "  connectionState: string = '';\r\n"
+        "  serverHost: string = 'localhost';\r\n"
+        "  currentProtocol: string = 'http:';\r\n"
+        "  private _tokenName: string = '" + this->getClassName() + "_token';\r\n"
+        "  userdata: any = {};\r\n"
+        "  changedState = new EventEmitter();\r\n"
+        "  private _lastm: number = 0;\r\n"
+        "  private _listeners: any = {};\r\n"
+        "  private _connectionState: string = '?';\r\n"
+        "  private _tokenValue: string = '';\r\n"
+        "  private _socket: WebSocket = null;\r\n"
+        "  private _events: any = {\r\n";
+
+    for (int i = 0; i < m_vEvents.size(); i++) {
+        libwjscppcli_web_service_ts_file <<
+        "    '" << m_vEvents[i] << "': [],\r\n";
+    }
+
+    libwjscppcli_web_service_ts_file <<
+        "  };\r\n"
+        "  private _lastConnectionParams: any = null;\r\n"
+        "\r\n"
+        "  constructor(\r\n"
+        "    private _location: PlatformLocation,\r\n"
+        "  ) {\r\n"
+        "    this.serverHost = this._location.hostname;\r\n"
+        "    this.currentProtocol = this._location.protocol;\r\n"
+        "    console.warn('" + this->getClassName() + " (" + this->getAppVersion() + ")');\r\n"
+        "    this._tokenValue = this.getToken();\r\n"
+        "  }\r\n"
+        "\r\n"
+        "  setToken(token: string) {\r\n"
+        "    var date = new Date( new Date().getTime() + (7 * 24 * 60 * 60 * 1000) ); // cookie on week\r\n"
+        "    document.cookie = this._tokenName + '=' + encodeURIComponent(token) + '; path=/; expires='+date.toUTCString();\r\n"
+        "  }\r\n"
+        "  \r\n"
+        "  removeToken() {\r\n"
+        "    this._tokenValue = '';\r\n"
+        "    document.cookie = this._tokenName + '=; path=/;';\r\n"
+        "  }\r\n"
+        "\r\n"
+        "  getToken() {\r\n"
+        "    var matches = document.cookie.match(new RegExp(\r\n"
+        "      '(?:^|; )' + this._tokenName.replace(/([\\.$?*|{}\\(\\)\\[\\]\\\\\\/\\+^])/g, '\\\\$1') + '=([^;]*)'\r\n"
+        "    ));\r\n"
+        "    return matches ? decodeURIComponent(matches[1]) : '';\r\n"
+        "  }\r\n"
+        "\r\n"
+        "  bind(name: string, f: Function) {\r\n"
+        "    this._events[name].push(f);\r\n"
+        "  }\r\n"
+        "\r\n"
+        "  unbind(name: string) {\r\n"
+        "    this._events[name] = [];\r\n"
+        "  }\r\n"
+        "\r\n"
+        "  _call(name: string, data: any) {\r\n"
+        "    function __call(f: any, data: any) {\r\n"
+        "      setTimeout(function() { f(data) },1)\r\n"
+        "    }\r\n"
+        "    for (var i = 0; i < this._events[name].length; i++) {\r\n"
+        "      __call(this._events[name][i], data);\r\n"
+        "    }\r\n"
+        "  }\r\n"
+        "\r\n"
+        "  private socketOnOpen() {\r\n"
+        "    console.log('FreeHackQuestClient WS Opened');\r\n"
+        "    this._call('connected', {});\r\n"
+        "    if (this._tokenValue != '') this.token();\r\n"
+        "  }\r\n"
+        "\r\n"
+        "  private socketOnClose(event: any) {\r\n"
+        "    console.log('FreeHackQuestClient Closed');\r\n"
+        "    if (event.wasClean) {\r\n"
+        "        this._call('disconnected', {});\r\n"
+        "    } else {\r\n"
+        "        this._call('broken', {});\r\n"
+        "        setTimeout(function() {\r\n"
+        "            this._call('reconnecting', {});\r\n"
+        "            if (this._lastConnectionParams != null) {\r\n"
+        "                this.connectToServer(this._lastConnectionParams);\r\n"
+        "            }\r\n"
+        "        }, 10000);\r\n"
+        "        // Try reconnect after 10 sec\r\n"
+        "    }\r\n"
+        "    console.log('Code: ' + event.code + ' Reason: ' + event.reason);\r\n"
+        "  }\r\n"
+        "\r\n"
+        "  private _socketOnMessage(event: any) {\r\n"
+        "    console.log('FreeHackQuestClient Received: ' + event.data);\r\n"
+        "    try {\r\n"
+        "        var response = JSON.parse(event.data);\r\n"
+        "        // this._handleCommand(response);\r\n"
+        "    } catch(e) {\r\n"
+        "        console.error(e);\r\n"
+        "    }\r\n"
+        "  }\r\n"
+        "\r\n"
+        "  private _socketOnError(error: any) {\r\n"
+        "    console.log('FreeHackQuestClient Socket Error: ', error);\r\n"
+        "  }\r\n"
+        "\r\n"
+        "  connectToServer(initParams: any) {\r\n"
+        "    this._lastConnectionParams = null;\r\n"
+        "    if (!initParams.baseUrl) console.error('Expected baseUrl on initParams');\r\n"
+        "    this._lastConnectionParams = initParams;\r\n"
+        "    this._socket = new WebSocket(initParams.baseUrl);\r\n"
+        "    this._socket.onopen = (() => this.socketOnOpen());\r\n"
+        "    this._socket.onclose = ((event: any) => this.socketOnClose(event));\r\n"
+        "    this._socket.onmessage = ((event: any) => this._socketOnMessage(event));\r\n"
+        "    this._socket.onerror = ((error: any) => this._socketOnError(error));\r\n"
+        "  }\r\n"
+        "\r\n"
+        "  private _lm() { this._lastm++; return 'm' + this._lastm; };\r\n"
+        "\r\n";
+
+
+    libwjscppcli_web_service_ts_file <<
+        "    };\r\n"
+        "    function _lm() { _lastm++; return 'm' + _lastm; };\r\n"
+        "    self.promise = function() {\r\n"
+        "        return {\r\n"
+        "            completed: false, failed: false, successed: false, \r\n"
+        "            done: function(callback) {\r\n"
+        "                this.done_callback = callback;\r\n"
+        "                if (this.completed && typeof this.done_callback === 'function' && this.successed) {\r\n"
+        "                    this.done_callback.apply(this, this.result_arguments);\r\n"
+        "                }\r\n"
+        "                return this;\r\n"
+        "            },\r\n"
+        "            fail: function(callback) {\r\n"
+        "                this.fail_callback = callback;\r\n"
+        "                if (this.completed && typeof this.fail_callback === 'function' && this.failed) {\r\n"
+        "                    this.fail_callback.apply(this, this.error_arguments);\r\n"
+        "                }\r\n"
+        "                return this;\r\n"
+        "            },\r\n"
+        "            resolve: function() {\r\n"
+        "                if (!this.completed) {\r\n"
+        "                    this.result_arguments = arguments; // [];\r\n"
+        "                    if (typeof this.done_callback === 'function') {\r\n"
+        "                        this.done_callback.apply(this, this.result_arguments);\r\n"
+        "                    }\r\n"
+        "                }\r\n"
+        "                this.successed = true;\r\n"
+        "                this.completed = true;\r\n"
+        "            },\r\n"
+        "            reject: function() {\r\n"
+        "                if (!this.completed) {\r\n"
+        "                    this.error_arguments = arguments;\r\n"
+        "                    if (typeof this.fail_callback === 'function') {\r\n"
+        "                        this.fail_callback.apply(this, this.error_arguments);\r\n"
+        "                    }\r\n"
+        "                }\r\n"
+        "                this.failed = true;\r\n"
+        "                this.completed = true;\r\n"
+        "            }\r\n"
+        "        }; // end of promise\r\n"
+        "    };\r\n"
+        "    self.waitAllPromises = function(arr_promise) {\r\n"
+        "        var p = self.promise();\r\n"
+        "        var max_len = arr_promise.length;\r\n"
+        "        var result = [];\r\n"
+        "        function cmpl(r) {\r\n"
+        "            result.push(r);\r\n"
+        "            if (result.length == max_len) {\r\n"
+        "                p.resolve(result);\r\n"
+        "            }\r\n"
+        "        };\r\n"
+        "        for (var i in arr_promise) {\r\n"
+        "            arr_promise[i].done(cmpl).fail(cmpl);\r\n"
+        "        }\r\n"
+        "        return p;\r\n"
+        "    };\r\n"
+        "    self.setToken = function(token) {\r\n"
+        "        var date = new Date( new Date().getTime() + (7 * 24 * 60 * 60 * 1000) ); // cookie on week\r\n"
+        "        document.cookie = '" + this->getClassName() + "token=' + encodeURIComponent(token) + '; path=/; expires='+date.toUTCString();\r\n"
+        "    }\r\n"
+        "    self.removeToken = function() {\r\n"
+        "        _tokenValue = '';"
+        "        document.cookie = '" + this->getClassName() + "token=; path=/;';\r\n"
+        "    }\r\n"
+        "    self.getToken = function() {\r\n"
+        "        var matches = document.cookie.match(new RegExp(\r\n"
+        "            '(?:^|; )' + '" + this->getClassName() + "token'.replace(/([\\.$?*|{}\\(\\)\\[\\]\\\\\\/\\+^])/g, '\\\\$1') + '=([^;]*)'\r\n"
+        "        ));\r\n"
+        "        return matches ? decodeURIComponent(matches[1]) : '';\r\n"
+        "    }\r\n"
+        "    _tokenValue = self.getToken();\r\n"
+        "    self.bind = function(name, f) { _events[name].push(f); }\r\n"
+        "    self.unbind = function(name) { _events[name] = []; }\r\n"
+        "    function _call(name, data) {\r\n"
+        "        function __call(f, data) { setTimeout(function() { f(data) },1)}"
+        "        for (var i = 0; i < _events[name].length; i++) {\r\n"
+        "            __call(_events[name][i], data);\r\n"
+        "        }\r\n"
+        "    }\r\n"
+        "    self.bind('server', function(response) { \r\n"
+        "       console.warn('All: ', response);\r\n"
+        "       if (response.app != self.appName) {\r\n"
+        "           console.error('AppName: ' + response.app + ', but expected ' + self.appName);\r\n"
+        "       }\r\n"
+        "       if (response.version != self.appVersion) {\r\n"
+        "           console.error('AppVersion: ' + response.version + ', but expected ' + self.appVersion);\r\n"
+        "       }\r\n"
+        "    }); \r\n"
+        "    self.handleCommand = function(response) {\r\n"
+        "       var lstn = _listeners[response.m];\r\n"
+        "       if (lstn) {\r\n"
+        "           setTimeout(function() {\r\n"
+        "               if (response['error']) {\r\n"
+        "                   lstn.reject(response);\r\n"
+        "               } else {\r\n"
+        "                   lstn.resolve(response);\r\n"
+        "               }\r\n"
+        "               delete _listeners[response.m];\r\n"
+        "           },1);\r\n"
+        "       } else if (_events[response.cmd]) {\r\n"
+        "           _call(response.cmd, response);"
+        "       } else {\r\n"
+        "           console.error('Not found handler for [' + response.cmd + '/' + response.m + ']');\r\n"
+        "       }\r\n"
+        "   };\r\n"
+        "   self.send = function(obj, def) {\r\n"
+        "       obj.m = obj.m || _lm();\r\n"
+        "       _listeners[obj.m] = def || self.promise();\r\n"
+        "       try {\r\n"
+        "           if (self.socket.readyState == 0) {\r\n"
+        "               setTimeout(function() {\r\n"
+        "                   self.send(obj, _listeners[obj.m]);\r\n"
+        "               },1000);\r\n"
+        "           } else {\r\n"
+        "               self.socket.send(JSON.stringify(obj));\r\n"
+        "           }\r\n"
+        "       } catch(e) {\r\n"
+        "           console.error(e);\r\n"
+        "       }\r\n"
+        "       return _listeners[obj.m];\r\n"
+        "    }\r\n"
+        "    self.init = function(initParams) {\r\n"
+        "        if (!initParams.baseUrl) console.error('Expected baseUrl on initParams');\r\n"
+        "        self.socket = new WebSocket(initParams.baseUrl);\r\n"
+        "        self.socket.onopen = function() {\r\n"
+        "           console.log('WS Opened');\r\n"
+        "           _call('connected', {});\r\n"
+        "           if (_tokenValue != '') self.token();\r\n"
+        "        };\r\n"
+        "        self.socket.onclose = function(event) {\r\n"
+        "           console.log('Closed');\r\n"
+        "           if (event.wasClean) {\r\n"
+        "               _call('disconnected', {});\r\n"
+        "           } else {\r\n"
+        "               _call('broken', {});\r\n"
+        "               setTimeout(function() {\r\n"
+        "                   _call('reconnecting', {});\r\n"
+        "                   self.init(initParams);\r\n"
+        "               }, 10000);\r\n"
+        "             // Try reconnect after 5 sec\r\n"
+        "           }\r\n"
+        "           console.log('Code: ' + event.code + ' Reason: ' + event.reason);\r\n"
+        "       };\r\n"
+        "       self.socket.onmessage = function(event) {\r\n"
+        "           // console.log('Received: ' + event.data);\r\n"
+        "           try {\r\n"
+        "               var response = JSON.parse(event.data);\r\n"
+        "               self.handleCommand(response);\r\n"
+        "           } catch(e) {\r\n"
+        "               console.error(e);\r\n"
+        "           }\r\n"
+        "           \r\n"
+        "       };\r\n"
+        "       self.socket.onerror = function(error) {\r\n"
+        "           console.log('Error: ' + error.message);\r\n"
+        "       };\r\n"
+        "    }\r\n"
+        "    self.deinit = function(initParams) {\r\n"
+        "       self.removeToken();\r\n"
+        "       self.socket.close();\r\n"
+        "    }\r\n"
+        "   self.userProfile = {bInitUserProfile: false}\r\n"
+        "   self.updateUserProfileAsync = function() {\r\n"
+        "       setTimeout(function() {\r\n"
+        "           self.user().done(function(r) {\r\n"
+        "               self.userProfile.bInitUserProfile == true;\r\n"
+        "               self.userProfile.university = r.data.university;\r\n"
+        "               self.userProfile.country = r.data.country;\r\n"
+        "               self.userProfile.city = r.data.city;\r\n"
+        "               self.userinfo = {};\r\n"
+        "               self.userinfo.id = r.data.id;\r\n"
+        "               self.userinfo.nick = r.data.nick;\r\n"
+        "               self.userinfo.email = r.data.email;\r\n"
+        "               self.userinfo.role = r.data.role;\r\n"
+        "               self.userinfo.logo = r.data.logo;\r\n"
+        "               _call('userdata', r.data);\r\n"
+        "           }).fail(function() {\r\n"
+        "               self.removeToken();\r\n"
+        "               _call('userdata', {});\r\n"
+        "           });\r\n"
+        "       },10);\r\n"
+        "   }\r\n";
+
+    std::map::iterator it = g_pWsjcppJsonRpc20HandlerList->begin();
+    for (; it!=g_pWsjcppJsonRpc20HandlerList->end(); ++it) {
+        std::string sCmd = it->first;
+        WsjcppJsonRpc20HandlerBase* pWsjcppJsonRpc20HandlerBase = it->second;
+        libwjscppcli_web_service_ts_file <<
+            "    self." << sCmd << " = function(params) {\r\n";
+
+        libwjscppcli_web_service_ts_file <<
+            "       // Access unauthorized: " << (pWsjcppJsonRpc20HandlerBase->haveUnauthorizedAccess() ? "yes" : "no") << "\r\n"
+            "       // Access user: " << (pWsjcppJsonRpc20HandlerBase->haveUserAccess() ? "yes" : "no") << "\r\n"
+            "       // Access tester: " << (pWsjcppJsonRpc20HandlerBase->haveTesterAccess() ? "yes" : "no") << "\r\n"
+            "       // Access admin: " << (pWsjcppJsonRpc20HandlerBase->haveAdminAccess() ? "yes" : "no") << "\r\n";
+        
+        if (pWsjcppJsonRpc20HandlerBase->getActivatedFromVersion() != "") {
+            libwjscppcli_web_service_ts_file <<
+                "       // Activated From Version: " << pWsjcppJsonRpc20HandlerBase->getActivatedFromVersion() << "\r\n";
+        }
+        
+        if (pWsjcppJsonRpc20HandlerBase->getDeprecatedFromVersion() != "") {
+            libwjscppcli_web_service_ts_file <<
+                "       // Deprecated From Version: " + pWsjcppJsonRpc20HandlerBase->getDeprecatedFromVersion() << "\r\n";
+        }
+        
+        std::vector vVin = pWsjcppJsonRpc20HandlerBase->getParamsDef();
+        if (vVin.size() > 0) {
+            libwjscppcli_web_service_ts_file <<
+                "       // Input params:\r\n"; 
+        }
+        for (int i = 0; i < vVin.size(); i++) {
+            WsjcppJsonRpc20ParamDef inDef = vVin[i];
+            std::string nameIn = std::string(inDef.getName());
+            libwjscppcli_web_service_ts_file <<
+                "       // * " + nameIn + " - " + inDef.getType() + ", " + inDef.getRestrict() + " (" + inDef.getDescription() + ") \r\n";
+        }
+
+        libwjscppcli_web_service_ts_file <<
+            "        params = params || {};\r\n"
+            "        params.cmd = '" << sCmd << "';\r\n";
+            // check required
+        for (int i = 0; i < vVin.size(); i++) {
+            WsjcppJsonRpc20ParamDef inDef = vVin[i];
+            if (inDef.isRequired()) {
+                std::string nameIn = std::string(vVin[i].getName());
+                libwjscppcli_web_service_ts_file <<
+                    "        if (params['" + nameIn + "'] == undefined) {\r\n"
+                    "             console.error('Parameter \"" << nameIn << "\" expected (lib)');\r\n"
+                    "        }\r\n";
+            }
+        }
+        if (sCmd == "login") {
+            libwjscppcli_web_service_ts_file <<
+                "        var ret = self.promise()\r\n"
+                "        self.send(params).done(function(r) {\r\n"
+                "            _tokenValue = r.token;\r\n"
+                "            console.log(_tokenValue);\r\n"
+                "            self.userinfo = r.user;\r\n"
+                "            self.setToken(_tokenValue);\r\n"
+                "            self.updateUserProfileAsync();\r\n"
+                "            ret.resolve(r);\r\n"
+                "        }).fail(function(err) {\r\n"
+                "            self.removeToken();\r\n"
+                "            ret.reject(err);\r\n"
+                "        })\r\n"
+                "        return ret;\r\n";
+        } else if (sCmd == "token") {
+            libwjscppcli_web_service_ts_file <<
+                "         if (_tokenValue != '') {\r\n"
+                "             var ret = self.promise()\r\n"
+                "             params.token = _tokenValue;\r\n"
+                "             self.send(params).done(function(r) {\r\n"
+                "                 self.updateUserProfileAsync();\r\n"
+                "                 ret.resolve(r);\r\n"
+                "             }).fail(function(err) {\r\n"
+                "                 self.removeToken();\r\n"
+                "                 _call('userdata', {});\r\n"
+                "                 ret.reject(err);\r\n"
+                "             })\r\n"
+                "             return ret;\r\n"
+                "         } else {\r\n"
+                "             return self.send(params);\r\n"
+                "         }\r\n";
+        } else {
+            libwjscppcli_web_service_ts_file 
+                << "         return self.send(params);\r\n";
+        }
+
+        libwjscppcli_web_service_ts_file 
+            << "    }\r\n\r\n";
+    }
+
+    libwjscppcli_web_service_ts_file <<
+        "    return self;\r\n"
+        "})();\r\n";
+
+    libwjscppcli_web_service_ts_file.close();
+    std::cout << "\t> OK" << std::endl;
+}
\ No newline at end of file
diff --git a/src/wsjcpp_jsonrpc20_export_cli_webjs.h b/src/wsjcpp_jsonrpc20_export_cli_webjs.h
new file mode 100644
index 0000000..480e837
--- /dev/null
+++ b/src/wsjcpp_jsonrpc20_export_cli_webjs.h
@@ -0,0 +1,48 @@
+#ifndef WSJCPP_JSONRPC20_EXPORT_CLI_WEBJS_H
+#define WSJCPP_JSONRPC20_EXPORT_CLI_WEBJS_H
+
+#include "wsjcpp_jsonrpc20_export_cli_base.h"
+#include 
+
+class WsjcppJsonRpc20ExportCliWebJs : public WsjcppJsonRpc20ExportCliBase {
+    public:
+        WsjcppJsonRpc20ExportCliWebJs(
+            const std::string &sExportDir,
+            const std::string &sPackageName
+        );
+        // TODO homepage
+        void setIssuesURL(const std::string &sIssuesURL);
+        void setRepository(const std::string &sRepositoryType, const std::string &sRepositoryURL);
+        void setKeywords(const std::vector &vKeywords);
+        void setLicense(const std::string &sLicenseType, const std::string &sLicenseURL);
+        void setDefaultConnectionString(const std::string &sDefaultConnectionString);
+        virtual bool doExportLib() override;
+
+    private:
+        std::string TAG;
+        std::string m_sIssuesURL;
+        std::string m_sRepositoryType;
+        std::string m_sRepositoryURL;
+        std::vector m_vKeywords;
+        std::string m_sLicenseType;
+        std::string m_sLicenseURL;
+        std::string m_sDefaultConnectionString;
+
+        std::string m_sSampleUrlConnection;
+        
+        std::vector> m_vMethodsForKeepAuthToken;
+        std::vector m_vMethodsForClearAuthToken;
+
+        std::vector m_vEvents;
+
+        bool prepareDirs();
+        bool exportLibCliWebJSFile();
+
+        void exportPackageJson();
+        void exportAPImd();
+        
+        void exportLibCliWebServiceTSFile();
+        void exportSampleHtmlFile();
+};
+
+#endif //  WSJCPP_JSONRPC20_EXPORT_CLI_WEBJS_H
\ No newline at end of file
diff --git a/unit-tests.wsjcpp/CMakeLists.txt b/unit-tests.wsjcpp/CMakeLists.txt
index f220a38..3713a94 100644
--- a/unit-tests.wsjcpp/CMakeLists.txt
+++ b/unit-tests.wsjcpp/CMakeLists.txt
@@ -1,8 +1,8 @@
-# Automaticly generated by wsjcpp@v0.1.7
+# Automaticly generated by wsjcpp@v0.2.0
 cmake_minimum_required(VERSION 3.0)
 
 project(unit-tests C CXX)
-add_definitions(-DWSJCPP_APP_VERSION="ut-v0.0.3")
+add_definitions(-DWSJCPP_APP_VERSION="ut-v0.0.4")
 add_definitions(-DWSJCPP_APP_NAME="unit-tests-wsjcpp-jsonrpc20")
 
 if (${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
@@ -19,15 +19,13 @@ set (WSJCPP_SOURCES "")
 find_package(Threads REQUIRED)
 list (APPEND WSJCPP_LIBRARIES ${CMAKE_THREAD_LIBS_INIT})
 
-# wsjcpp-core:v0.2.0
+# wsjcpp-core:v0.2.1
 list (APPEND WSJCPP_INCLUDE_DIRS "../src.wsjcpp/wsjcpp_core/")
 list (APPEND WSJCPP_SOURCES "../src.wsjcpp/wsjcpp_core/wsjcpp_core.cpp")
 list (APPEND WSJCPP_SOURCES "../src.wsjcpp/wsjcpp_core/wsjcpp_core.h")
 list (APPEND WSJCPP_SOURCES "../src.wsjcpp/wsjcpp_core/wsjcpp_unit_tests.cpp")
 list (APPEND WSJCPP_SOURCES "../src.wsjcpp/wsjcpp_core/wsjcpp_unit_tests.h")
 list (APPEND WSJCPP_SOURCES "../src.wsjcpp/wsjcpp_core/wsjcpp_unit_tests_main.cpp")
-list (APPEND WSJCPP_SOURCES "../src.wsjcpp/wsjcpp_core/wsjcpp_resources_manager.h")
-list (APPEND WSJCPP_SOURCES "../src.wsjcpp/wsjcpp_core/wsjcpp_resources_manager.cpp")
 
 # nlohmann/json:v3.9.1
 list (APPEND WSJCPP_INCLUDE_DIRS "../src.wsjcpp/nlohmann_json/")
@@ -38,24 +36,23 @@ list (APPEND WSJCPP_INCLUDE_DIRS "../src.wsjcpp/wsjcpp_validators/")
 list (APPEND WSJCPP_SOURCES "../src.wsjcpp/wsjcpp_validators/wsjcpp_validators.h")
 list (APPEND WSJCPP_SOURCES "../src.wsjcpp/wsjcpp_validators/wsjcpp_validators.cpp")
 
-# wsjcpp-jsonrpc20:v0.0.3
+# wsjcpp-jsonrpc20:v0.0.4
 list (APPEND WSJCPP_INCLUDE_DIRS "../src")
 list (APPEND WSJCPP_SOURCES "../src/wsjcpp_jsonrpc20.h")
 list (APPEND WSJCPP_SOURCES "../src/wsjcpp_jsonrpc20.cpp")
 list (APPEND WSJCPP_SOURCES "../src/wsjcpp_jsonrpc20_export_cli_python.h")
 list (APPEND WSJCPP_SOURCES "../src/wsjcpp_jsonrpc20_export_cli_python.cpp")
+list (APPEND WSJCPP_SOURCES "../src/wsjcpp_jsonrpc20_export_cli_webjs.h")
+list (APPEND WSJCPP_SOURCES "../src/wsjcpp_jsonrpc20_export_cli_webjs.cpp")
+list (APPEND WSJCPP_SOURCES "../src/wsjcpp_jsonrpc20_export_cli_base.h")
+list (APPEND WSJCPP_SOURCES "../src/wsjcpp_jsonrpc20_export_cli_base.cpp")
 
 # unit-tests
 list (APPEND WSJCPP_INCLUDE_DIRS "src")
-list (APPEND WSJCPP_SOURCES "../unit-tests.wsjcpp/src/unit_test_json_rpc20_user_session.h")
 list (APPEND WSJCPP_SOURCES "../unit-tests.wsjcpp/src/unit_test_json_rpc20_user_session.cpp")
-list (APPEND WSJCPP_SOURCES "../unit-tests.wsjcpp/src/unit_test_json_rpc20_param_def.h")
 list (APPEND WSJCPP_SOURCES "../unit-tests.wsjcpp/src/unit_test_json_rpc20_param_def.cpp")
-list (APPEND WSJCPP_SOURCES "../unit-tests.wsjcpp/src/unit_test_request_server_api.h")
 list (APPEND WSJCPP_SOURCES "../unit-tests.wsjcpp/src/unit_test_request_server_api.cpp")
-list (APPEND WSJCPP_SOURCES "../unit-tests.wsjcpp/src/unit_test_parsing_request_params.h")
 list (APPEND WSJCPP_SOURCES "../unit-tests.wsjcpp/src/unit_test_parsing_request_params.cpp")
-list (APPEND WSJCPP_SOURCES "../unit-tests.wsjcpp/src/unit_test_request_parse_income_data.h")
 list (APPEND WSJCPP_SOURCES "../unit-tests.wsjcpp/src/unit_test_request_parse_income_data.cpp")
 
 include(${CMAKE_CURRENT_SOURCE_DIR}/CMakeLists.user-custom.txt)
@@ -67,11 +64,3 @@ add_executable ("unit-tests" ${WSJCPP_SOURCES})
 
 target_link_libraries("unit-tests" -lpthread ${WSJCPP_LIBRARIES} )
 
-install(
-    TARGETS
-        "unit-tests"
-    RUNTIME DESTINATION
-        /usr/bin
-)
-
-
diff --git a/unit-tests.wsjcpp/build_simple.sh b/unit-tests.wsjcpp/build_simple.sh
index 5c3dfd7..8b35d10 100755
--- a/unit-tests.wsjcpp/build_simple.sh
+++ b/unit-tests.wsjcpp/build_simple.sh
@@ -1,7 +1,7 @@
 #!/bin/bash
 
 if [ ! -d tmp ]; then
-	mkdir -p tmp
+    mkdir -p tmp
 fi
 
 cd tmp
diff --git a/unit-tests.wsjcpp/src/unit_test_json_rpc20_param_def.cpp b/unit-tests.wsjcpp/src/unit_test_json_rpc20_param_def.cpp
index 7442d2f..0f5cb47 100644
--- a/unit-tests.wsjcpp/src/unit_test_json_rpc20_param_def.cpp
+++ b/unit-tests.wsjcpp/src/unit_test_json_rpc20_param_def.cpp
@@ -33,55 +33,55 @@ void UnitTestJsonRpc20ParamDef::executeTest() {
     
     {
         WsjcppJsonRpc20ParamDef paramDef;
-        compareS("Empty paramDef - name", paramDef.getName(), "");
-        compareS("Empty paramDef - getType", paramDef.getType(), "");
-        compareS("Empty paramDef - getRestrict", paramDef.getRestrict(), "");
-        compareS("Empty paramDef - getDescription", paramDef.getDescription(), "");
-        compareB("Empty paramDef - isRequired", paramDef.isRequired(), false);
-        compareB("Empty paramDef - isOptional", paramDef.isOptional(), false);
-        compareB("Empty paramDef - isInteger", paramDef.isInteger(), false);
-        compareB("Empty paramDef - isString", paramDef.isString(), false);
-        compareB("Empty paramDef - isBool", paramDef.isBool(), false);
-        compareB("Empty paramDef - isJson", paramDef.isJson(), false);
+        compare("Empty paramDef - name", paramDef.getName(), "");
+        compare("Empty paramDef - getType", paramDef.getType(), "");
+        compare("Empty paramDef - getRestrict", paramDef.getRestrict(), "required"); // default
+        compare("Empty paramDef - getDescription", paramDef.getDescription(), "");
+        compare("Empty paramDef - isRequired", paramDef.isRequired(), true);
+        compare("Empty paramDef - isOptional", paramDef.isOptional(), false);
+        compare("Empty paramDef - isInteger", paramDef.isInteger(), false);
+        compare("Empty paramDef - isString", paramDef.isString(), false);
+        compare("Empty paramDef - isBool", paramDef.isBool(), false);
+        compare("Empty paramDef - isJson", paramDef.isJson(), false);
 
         nlohmann::json js_empty; 
         js_empty["description"] = "";
         js_empty["name"] = "";
-        js_empty["restrict"] = "";
+        js_empty["restrict"] = "required";
         js_empty["type"] = "";
-        compareS("Empty paramDef - toJson", paramDef.toJson().dump(), js_empty.dump());
+        compare("Empty paramDef - toJson", paramDef.toJson().dump(), js_empty.dump());
 
-        compareN("Empty paramDef - listOfStringValidators", paramDef.listOfStringValidators().size(), 0);
-        compareN("Empty paramDef - listOfIntegerValidators", paramDef.listOfIntegerValidators().size(), 0);
-        compareN("Empty paramDef - listOfJsonValidators", paramDef.listOfJsonValidators().size(), 0);
+        compare("Empty paramDef - listOfStringValidators", paramDef.listOfStringValidators().size(), 0);
+        compare("Empty paramDef - listOfIntegerValidators", paramDef.listOfIntegerValidators().size(), 0);
+        compare("Empty paramDef - listOfJsonValidators", paramDef.listOfJsonValidators().size(), 0);
     }
 
     {
         WsjcppJsonRpc20ParamDef paramDef2("arg2", "Some argument222222");
         paramDef2.string_().required()
             .addValidator(new WsjcppValidatorURL());
-        compareS("paramDef2 - name", paramDef2.getName(), "arg2");
-        compareS("paramDef2 - getType", paramDef2.getType(), "string");
-        compareS("paramDef2 - getRestrict", paramDef2.getRestrict(), "required");
-        compareS("paramDef2 - getDescription", paramDef2.getDescription(), "Some argument222222");
-        compareB("paramDef2 - isRequired", paramDef2.isRequired(), true);
-        compareB("paramDef2 - isOptional", paramDef2.isOptional(), false);
-        compareB("paramDef2 - isInteger", paramDef2.isInteger(), false);
-        compareB("paramDef2 - isString", paramDef2.isString(), true);
+        compare("paramDef2 - name", paramDef2.getName(), "arg2");
+        compare("paramDef2 - getType", paramDef2.getType(), "string");
+        compare("paramDef2 - getRestrict", paramDef2.getRestrict(), "required");
+        compare("paramDef2 - getDescription", paramDef2.getDescription(), "Some argument222222");
+        compare("paramDef2 - isRequired", paramDef2.isRequired(), true);
+        compare("paramDef2 - isOptional", paramDef2.isOptional(), false);
+        compare("paramDef2 - isInteger", paramDef2.isInteger(), false);
+        compare("paramDef2 - isString", paramDef2.isString(), true);
         
-        compareB("paramDef2 - isJson", paramDef2.isJson(), false);
-        compareB("paramDef2 - isBool", paramDef2.isBool(), false);
+        compare("paramDef2 - isJson", paramDef2.isJson(), false);
+        compare("paramDef2 - isBool", paramDef2.isBool(), false);
 
         nlohmann::json js2; 
         js2["description"] = "Some argument222222";
         js2["name"] = "arg2";
         js2["restrict"] = "required";
         js2["type"] = "string";
-        compareS("paramDef2 - toJson", paramDef2.toJson().dump(), js2.dump());
+        compare("paramDef2 - toJson", paramDef2.toJson().dump(), js2.dump());
 
-        compareN("paramDef2 - listOfStringValidators", paramDef2.listOfStringValidators().size(), 1);
-        compareN("paramDef2 - listOfIntegerValidators", paramDef2.listOfIntegerValidators().size(), 0);
-        compareN("paramDef2 - listOfJsonValidators", paramDef2.listOfJsonValidators().size(), 0);
+        compare("paramDef2 - listOfStringValidators", paramDef2.listOfStringValidators().size(), 1);
+        compare("paramDef2 - listOfIntegerValidators", paramDef2.listOfIntegerValidators().size(), 0);
+        compare("paramDef2 - listOfJsonValidators", paramDef2.listOfJsonValidators().size(), 0);
     }
 
     {
@@ -90,81 +90,81 @@ void UnitTestJsonRpc20ParamDef::executeTest() {
             .addValidator(new WsjcppValidatorIntegerMinValue(1))
             .addValidator(new WsjcppValidatorIntegerMaxValue(1000))
             ;
-        compareS("paramDef3 - name", paramDef3.getName(), "arg3");
-        compareS("paramDef3 - getType", paramDef3.getType(), "integer");
-        compareS("paramDef3 - getRestrict", paramDef3.getRestrict(), "optional");
-        compareS("paramDef3 - getDescription", paramDef3.getDescription(), "Some argument3");
-        compareB("paramDef3 - isRequired", paramDef3.isRequired(), false);
-        compareB("paramDef3 - isOptional", paramDef3.isOptional(), true);
-        compareB("paramDef3 - isInteger", paramDef3.isInteger(), true);
-        compareB("paramDef3 - isString", paramDef3.isString(), false);
-        compareB("paramDef3 - isJson", paramDef3.isJson(), false);
-        compareB("paramDef3 - isBool", paramDef3.isBool(), false);
+        compare("paramDef3 - name", paramDef3.getName(), "arg3");
+        compare("paramDef3 - getType", paramDef3.getType(), "integer");
+        compare("paramDef3 - getRestrict", paramDef3.getRestrict(), "optional");
+        compare("paramDef3 - getDescription", paramDef3.getDescription(), "Some argument3");
+        compare("paramDef3 - isRequired", paramDef3.isRequired(), false);
+        compare("paramDef3 - isOptional", paramDef3.isOptional(), true);
+        compare("paramDef3 - isInteger", paramDef3.isInteger(), true);
+        compare("paramDef3 - isString", paramDef3.isString(), false);
+        compare("paramDef3 - isJson", paramDef3.isJson(), false);
+        compare("paramDef3 - isBool", paramDef3.isBool(), false);
 
         nlohmann::json js3; 
         js3["description"] = "Some argument3";
         js3["name"] = "arg3";
         js3["restrict"] = "optional";
         js3["type"] = "integer";
-        compareS("paramDef3 - toJson", paramDef3.toJson().dump(), js3.dump());
+        compare("paramDef3 - toJson", paramDef3.toJson().dump(), js3.dump());
 
-        compareN("paramDef3 - listOfStringValidators", paramDef3.listOfStringValidators().size(), 0);
-        compareN("paramDef3 - listOfIntegerValidators", paramDef3.listOfIntegerValidators().size(), 2);
-        compareN("paramDef3 - listOfJsonValidators", paramDef3.listOfJsonValidators().size(), 0);
+        compare("paramDef3 - listOfStringValidators", paramDef3.listOfStringValidators().size(), 0);
+        compare("paramDef3 - listOfIntegerValidators", paramDef3.listOfIntegerValidators().size(), 2);
+        compare("paramDef3 - listOfJsonValidators", paramDef3.listOfJsonValidators().size(), 0);
     }
 
     {
         WsjcppJsonRpc20ParamDef paramDef4("arg4_1ddd", "Some argument4");
         paramDef4.json_().optional();
             
-        compareS("paramDef4 - name", paramDef4.getName(), "arg4_1ddd");
-        compareS("paramDef4 - getType", paramDef4.getType(), "json");
-        compareS("paramDef4 - getRestrict", paramDef4.getRestrict(), "optional");
-        compareS("paramDef4 - getDescription", paramDef4.getDescription(), "Some argument4");
-        compareB("paramDef4 - isRequired", paramDef4.isRequired(), false);
-        compareB("paramDef4 - isOptional", paramDef4.isOptional(), true);
-        compareB("paramDef4 - isInteger", paramDef4.isInteger(), false);
-        compareB("paramDef4 - isString", paramDef4.isString(), false);
-        compareB("paramDef4 - isJson", paramDef4.isJson(), true);
-        compareB("paramDef4 - isBool", paramDef4.isBool(), false);
+        compare("paramDef4 - name", paramDef4.getName(), "arg4_1ddd");
+        compare("paramDef4 - getType", paramDef4.getType(), "json");
+        compare("paramDef4 - getRestrict", paramDef4.getRestrict(), "optional");
+        compare("paramDef4 - getDescription", paramDef4.getDescription(), "Some argument4");
+        compare("paramDef4 - isRequired", paramDef4.isRequired(), false);
+        compare("paramDef4 - isOptional", paramDef4.isOptional(), true);
+        compare("paramDef4 - isInteger", paramDef4.isInteger(), false);
+        compare("paramDef4 - isString", paramDef4.isString(), false);
+        compare("paramDef4 - isJson", paramDef4.isJson(), true);
+        compare("paramDef4 - isBool", paramDef4.isBool(), false);
 
         nlohmann::json js4; 
         js4["description"] = "Some argument4";
         js4["name"] = "arg4_1ddd";
         js4["restrict"] = "optional";
         js4["type"] = "json";
-        compareS("paramDef4 - toJson", paramDef4.toJson().dump(), js4.dump());
+        compare("paramDef4 - toJson", paramDef4.toJson().dump(), js4.dump());
 
-        compareN("paramDef4 - listOfStringValidators", paramDef4.listOfStringValidators().size(), 0);
-        compareN("paramDef4 - listOfIntegerValidators", paramDef4.listOfIntegerValidators().size(), 0);
-        compareN("paramDef4 - listOfJsonValidators", paramDef4.listOfJsonValidators().size(), 0);
+        compare("paramDef4 - listOfStringValidators", paramDef4.listOfStringValidators().size(), 0);
+        compare("paramDef4 - listOfIntegerValidators", paramDef4.listOfIntegerValidators().size(), 0);
+        compare("paramDef4 - listOfJsonValidators", paramDef4.listOfJsonValidators().size(), 0);
         
     }
 
     {
         WsjcppJsonRpc20ParamDef paramDef5("arg5_0", "Some argument5");
         paramDef5.bool_().required();
-        compareS("paramDef5 - name", paramDef5.getName(), "arg5_0");
-        compareS("paramDef5 - getType", paramDef5.getType(), "boolean");
-        compareS("paramDef5 - getRestrict", paramDef5.getRestrict(), "required");
-        compareS("paramDef5 - getDescription", paramDef5.getDescription(), "Some argument5");
-        compareB("paramDef5 - isRequired", paramDef5.isRequired(), true);
-        compareB("paramDef5 - isOptional", paramDef5.isOptional(), false);
-        compareB("paramDef5 - isInteger", paramDef5.isInteger(), false);
-        compareB("paramDef5 - isString", paramDef5.isString(), false);
-        compareB("paramDef5 - isJson", paramDef5.isJson(), false);
-        compareB("paramDef5 - isBool", paramDef5.isBool(), true);
+        compare("paramDef5 - name", paramDef5.getName(), "arg5_0");
+        compare("paramDef5 - getType", paramDef5.getType(), "boolean");
+        compare("paramDef5 - getRestrict", paramDef5.getRestrict(), "required");
+        compare("paramDef5 - getDescription", paramDef5.getDescription(), "Some argument5");
+        compare("paramDef5 - isRequired", paramDef5.isRequired(), true);
+        compare("paramDef5 - isOptional", paramDef5.isOptional(), false);
+        compare("paramDef5 - isInteger", paramDef5.isInteger(), false);
+        compare("paramDef5 - isString", paramDef5.isString(), false);
+        compare("paramDef5 - isJson", paramDef5.isJson(), false);
+        compare("paramDef5 - isBool", paramDef5.isBool(), true);
 
         nlohmann::json js5; 
         js5["description"] = "Some argument5";
         js5["name"] = "arg5_0";
         js5["restrict"] = "required";
         js5["type"] = "boolean";
-        compareS("paramDef5 - toJson", paramDef5.toJson().dump(), js5.dump());
+        compare("paramDef5 - toJson", paramDef5.toJson().dump(), js5.dump());
 
-        compareN("paramDef5 - listOfStringValidators", paramDef5.listOfStringValidators().size(), 0);
-        compareN("paramDef5 - listOfIntegerValidators", paramDef5.listOfIntegerValidators().size(), 0);
-        compareN("paramDef5 - listOfJsonValidators", paramDef5.listOfJsonValidators().size(), 0);
+        compare("paramDef5 - listOfStringValidators", paramDef5.listOfStringValidators().size(), 0);
+        compare("paramDef5 - listOfIntegerValidators", paramDef5.listOfIntegerValidators().size(), 0);
+        compare("paramDef5 - listOfJsonValidators", paramDef5.listOfJsonValidators().size(), 0);
     }
 }
 
diff --git a/unit-tests.wsjcpp/src/unit_test_json_rpc20_param_def.h b/unit-tests.wsjcpp/src/unit_test_json_rpc20_param_def.h
deleted file mode 100644
index 397e005..0000000
--- a/unit-tests.wsjcpp/src/unit_test_json_rpc20_param_def.h
+++ /dev/null
@@ -1,5 +0,0 @@
-#ifndef UNIT_TEST_JSON_RPC20_PARAM_DEF_H
-#define UNIT_TEST_JSON_RPC20_PARAM_DEF_H
-
-#endif // UNIT_TEST_JSON_RPC20_PARAM_DEF_H
-
diff --git a/unit-tests.wsjcpp/src/unit_test_json_rpc20_user_session.cpp b/unit-tests.wsjcpp/src/unit_test_json_rpc20_user_session.cpp
index f34d05c..0fe3adb 100644
--- a/unit-tests.wsjcpp/src/unit_test_json_rpc20_user_session.cpp
+++ b/unit-tests.wsjcpp/src/unit_test_json_rpc20_user_session.cpp
@@ -1,4 +1,4 @@
-#include "unit_test_json_rpc20_user_session.h"
+#include 
 #include 
 #include 
 #include 
@@ -6,6 +6,14 @@
 // ---------------------------------------------------------------------
 // UnitTestJsonRpc20UserSession
 
+class UnitTestJsonRpc20UserSession : public WsjcppUnitTestBase {
+    public:
+        UnitTestJsonRpc20UserSession();
+        virtual bool doBeforeTest() override;
+        virtual void executeTest() override;
+        virtual bool doAfterTest() override;
+};
+
 REGISTRY_WSJCPP_UNIT_TEST(UnitTestJsonRpc20UserSession)
 
 UnitTestJsonRpc20UserSession::UnitTestJsonRpc20UserSession()
@@ -24,53 +32,53 @@ bool UnitTestJsonRpc20UserSession::doBeforeTest() {
 void UnitTestJsonRpc20UserSession::executeTest() {
 
     WsjcppJsonRpc20UserSession session0;
-    compareB("is admin (0)", session0.isAdmin(), false);
-    compareB("is user (0)", session0.isUser(), false);
-    compareB("is tester (0)", session0.isTester(), false);
-    compareB("has role (0)", session0.hasRole(), false);
+    compare("is admin (0)", session0.isAdmin(), false);
+    compare("is user (0)", session0.isUser(), false);
+    compare("is tester (0)", session0.isTester(), false);
+    compare("has role (0)", session0.hasRole(), false);
 
-    compareN("User Id (0)", session0.getUserId(), 0);
+    compare("User Id (0)", session0.getUserId(), 0);
 
-    compareS("User Uuid (0)", session0.getUserUuid(), "");
-    compareS("User Role (0)", session0.getUserRole(), "");
-    compareS("User Name (0)", session0.getUserName(), "");
-    compareS("User Email (0)", session0.getUserEmail(), "");
+    compare("User Uuid (0)", session0.getUserUuid(), "");
+    compare("User Role (0)", session0.getUserRole(), "");
+    compare("User Name (0)", session0.getUserName(), "");
+    compare("User Email (0)", session0.getUserEmail(), "");
 
-    compareS("Session Uuid (0)", session0.getSessionUuid(), "");
-    compareN("Session Created (0)", session0.getSessionCreated(), 0);
-    compareN("Session Updated (0)", session0.getSessionUpdated(), 0);
-    compareN("Session Expire At (0)", session0.getSessionExpireAt(), 0);
-    compareS("Session Custom (0)", session0.getSessionCustom().dump(), "null");
+    compare("Session Uuid (0)", session0.getSessionUuid(), "");
+    compare("Session Created (0)", session0.getSessionCreated(), 0);
+    compare("Session Updated (0)", session0.getSessionUpdated(), 0);
+    compare("Session Expire At (0)", session0.getSessionExpireAt(), 0);
+    compare("Session Custom (0)", session0.getSessionCustom().dump(), "null");
 
     // test fill role
     session0.setUserRole("admin");
-    compareB("is admin (1)", session0.isAdmin(), true);
-    compareB("is user (1)", session0.isUser(), false);
-    compareB("is tester (1)", session0.isTester(), false);
-    compareB("has role (1)", session0.hasRole(), true);
-    compareS("User Role (1)", session0.getUserRole(), "admin");
+    compare("is admin (1)", session0.isAdmin(), true);
+    compare("is user (1)", session0.isUser(), false);
+    compare("is tester (1)", session0.isTester(), false);
+    compare("has role (1)", session0.hasRole(), true);
+    compare("User Role (1)", session0.getUserRole(), "admin");
 
     session0.setUserRole("user");  
-    compareB("is admin (2)", session0.isAdmin(), false);
-    compareB("is user (2)", session0.isUser(), true);
-    compareB("is tester (2)", session0.isTester(), false);
-    compareB("has role (2)", session0.hasRole(), true);
-    compareS("User Role (2)", session0.getUserRole(), "user");
+    compare("is admin (2)", session0.isAdmin(), false);
+    compare("is user (2)", session0.isUser(), true);
+    compare("is tester (2)", session0.isTester(), false);
+    compare("has role (2)", session0.hasRole(), true);
+    compare("User Role (2)", session0.getUserRole(), "user");
 
     session0.setUserRole("tester");  
-    compareB("is admin (3)", session0.isAdmin(), false);
-    compareB("is user (3)", session0.isUser(), false);
-    compareB("is tester (3)", session0.isTester(), true);
-    compareB("has role (3)", session0.hasRole(), true);
-    compareS("User Role (3)", session0.getUserRole(), "tester");
+    compare("is admin (3)", session0.isAdmin(), false);
+    compare("is user (3)", session0.isUser(), false);
+    compare("is tester (3)", session0.isTester(), true);
+    compare("has role (3)", session0.hasRole(), true);
+    compare("User Role (3)", session0.getUserRole(), "tester");
 
     std::string sUserRole = "custom0";
     session0.setUserRole(sUserRole);
-    compareB("is admin (4)", session0.isAdmin(), false);
-    compareB("is user (4)", session0.isUser(), false);
-    compareB("is tester (4)", session0.isTester(), false);
-    compareB("has role (4)", session0.hasRole(), true);
-    compareS("User Role (4)", session0.getUserRole(), sUserRole);
+    compare("is admin (4)", session0.isAdmin(), false);
+    compare("is user (4)", session0.isUser(), false);
+    compare("is tester (4)", session0.isTester(), false);
+    compare("has role (4)", session0.hasRole(), true);
+    compare("User Role (4)", session0.getUserRole(), sUserRole);
 
     int nUserId = 1000;
     std::string sUserUuid = "b5bd63ce-0405-4ef5-8473-552f2729e7e9";
@@ -94,46 +102,46 @@ void UnitTestJsonRpc20UserSession::executeTest() {
     session0.setSessionExpireAt(nExpiredAt);
     session0.setSessionCustom(jsonCustom);
 
-    compareN("User Id (5)", session0.getUserId(), nUserId);
-    compareS("User Uuid (6)", session0.getUserUuid(), sUserUuid);
-    compareS("User Name (7)", session0.getUserName(), sUserName);
-    compareS("User Email (8)", session0.getUserEmail(), sUserEmail);
-    compareS("Session Uuid (9)", session0.getSessionUuid(), sSessionUuid);
-    compareN("Session Created (10)", session0.getSessionCreated(), nCreated);
-    compareN("Session Updated (11)", session0.getSessionUpdated(), nUpdated);
-    compareN("Session Expire At (12)", session0.getSessionExpireAt(), nExpiredAt);
-    compareS("Session Custom (13)", session0.getSessionCustom().dump(), sJsonCustom);
+    compare("User Id (5)", session0.getUserId(), nUserId);
+    compare("User Uuid (6)", session0.getUserUuid(), sUserUuid);
+    compare("User Name (7)", session0.getUserName(), sUserName);
+    compare("User Email (8)", session0.getUserEmail(), sUserEmail);
+    compare("Session Uuid (9)", session0.getSessionUuid(), sSessionUuid);
+    compare("Session Created (10)", session0.getSessionCreated(), nCreated);
+    compare("Session Updated (11)", session0.getSessionUpdated(), nUpdated);
+    compare("Session Expire At (12)", session0.getSessionExpireAt(), nExpiredAt);
+    compare("Session Custom (13)", session0.getSessionCustom().dump(), sJsonCustom);
 
     // test full json
     nlohmann::json jsonSession = session0.toJson();
     WsjcppLog::info(TAG, jsonSession.dump());
-    compareS("toJson Session uuid (14)", jsonSession["uuid"], sSessionUuid);
-    compareN("toJson Session created (14)", jsonSession["created"], nCreated);
-    compareN("toJson Session updated (14)", jsonSession["updated"], nUpdated);
-    compareN("toJson Session expire_at (14)", jsonSession["expire_at"], nExpiredAt);
+    compare("toJson Session uuid (14)", jsonSession["uuid"], sSessionUuid);
+    compare("toJson Session created (14)", jsonSession["created"], nCreated);
+    compare("toJson Session updated (14)", jsonSession["updated"], nUpdated);
+    compare("toJson Session expire_at (14)", jsonSession["expire_at"], nExpiredAt);
 
-    compareN("toJson Session user.id (14)", jsonSession["user"]["id"], nUserId);
-    compareS("toJson Session user.id (14)", jsonSession["user"]["uuid"], sUserUuid);
-    compareS("toJson Session user.id (14)", jsonSession["user"]["name"], sUserName);
-    compareS("toJson Session user.id (14)", jsonSession["user"]["role"], sUserRole);
-    compareS("toJson Session user.id (14)", jsonSession["user"]["email"], sUserEmail);
+    compare("toJson Session user.id (14)", jsonSession["user"]["id"], nUserId);
+    compare("toJson Session user.id (14)", jsonSession["user"]["uuid"], sUserUuid);
+    compare("toJson Session user.id (14)", jsonSession["user"]["name"], sUserName);
+    compare("toJson Session user.id (14)", jsonSession["user"]["role"], sUserRole);
+    compare("toJson Session user.id (14)", jsonSession["user"]["email"], sUserEmail);
 
     WsjcppJsonRpc20UserSession session1(jsonSession);
 
-    compareB("session1 is admin (0)", session1.isAdmin(), false);
-    compareB("session1 is user (0)", session1.isUser(), false);
-    compareB("session1 is tester (0)", session1.isTester(), false);
-    compareB("session1 has role (0)", session1.hasRole(), true);
-    compareN("session1 User Id (0)", session1.getUserId(), nUserId);
-    compareS("session1 User Uuid (0)", session1.getUserUuid(), sUserUuid);
-    compareS("session1 User Role (0)", session1.getUserRole(), sUserRole);
-    compareS("session1 User Name (0)", session1.getUserName(), sUserName);
-    compareS("session1 User Email (0)", session1.getUserEmail(), sUserEmail);
-    compareS("session1 Session Uuid (0)", session1.getSessionUuid(), sSessionUuid);
-    compareN("session1 Session Created (0)", session1.getSessionCreated(), nCreated);
-    compareN("session1 Session Updated (0)", session1.getSessionUpdated(), nUpdated);
-    compareN("session1 Session Expire At (0)", session1.getSessionExpireAt(), nExpiredAt);
-    compareS("session1 Session Custom (0)", session1.getSessionCustom().dump(), sJsonCustom);
+    compare("session1 is admin (0)", session1.isAdmin(), false);
+    compare("session1 is user (0)", session1.isUser(), false);
+    compare("session1 is tester (0)", session1.isTester(), false);
+    compare("session1 has role (0)", session1.hasRole(), true);
+    compare("session1 User Id (0)", session1.getUserId(), nUserId);
+    compare("session1 User Uuid (0)", session1.getUserUuid(), sUserUuid);
+    compare("session1 User Role (0)", session1.getUserRole(), sUserRole);
+    compare("session1 User Name (0)", session1.getUserName(), sUserName);
+    compare("session1 User Email (0)", session1.getUserEmail(), sUserEmail);
+    compare("session1 Session Uuid (0)", session1.getSessionUuid(), sSessionUuid);
+    compare("session1 Session Created (0)", session1.getSessionCreated(), nCreated);
+    compare("session1 Session Updated (0)", session1.getSessionUpdated(), nUpdated);
+    compare("session1 Session Expire At (0)", session1.getSessionExpireAt(), nExpiredAt);
+    compare("session1 Session Custom (0)", session1.getSessionCustom().dump(), sJsonCustom);
 
     // check rewrite data 
     WsjcppJsonRpc20UserSession session2;
diff --git a/unit-tests.wsjcpp/src/unit_test_json_rpc20_user_session.h b/unit-tests.wsjcpp/src/unit_test_json_rpc20_user_session.h
deleted file mode 100644
index 1f21535..0000000
--- a/unit-tests.wsjcpp/src/unit_test_json_rpc20_user_session.h
+++ /dev/null
@@ -1,15 +0,0 @@
-#ifndef UNIT_TEST_JSON_RPC20_USER_SESSION_H
-#define UNIT_TEST_JSON_RPC20_USER_SESSION_H
-
-#include 
-
-class UnitTestJsonRpc20UserSession : public WsjcppUnitTestBase {
-    public:
-        UnitTestJsonRpc20UserSession();
-        virtual bool doBeforeTest() override;
-        virtual void executeTest() override;
-        virtual bool doAfterTest() override;
-};
-
-#endif // UNIT_TEST_JSON_RPC20_USER_SESSION_H
-
diff --git a/unit-tests.wsjcpp/src/unit_test_parsing_request_params.cpp b/unit-tests.wsjcpp/src/unit_test_parsing_request_params.cpp
index fb753f3..588aad2 100644
--- a/unit-tests.wsjcpp/src/unit_test_parsing_request_params.cpp
+++ b/unit-tests.wsjcpp/src/unit_test_parsing_request_params.cpp
@@ -1,4 +1,4 @@
-#include "unit_test_parsing_request_params.h"
+#include 
 #include 
 #include 
 #include 
@@ -75,6 +75,15 @@ void WsjcppJsonRpc20HandlerGameCreate::handle(WsjcppJsonRpc20Request *pRequest)
 // ---------------------------------------------------------------------
 // UnitTestParsingRequestParams
 
+
+class UnitTestParsingRequestParams : public WsjcppUnitTestBase {
+    public:
+        UnitTestParsingRequestParams();
+        virtual bool doBeforeTest() override;
+        virtual void executeTest() override;
+        virtual bool doAfterTest() override;
+};
+
 REGISTRY_WSJCPP_UNIT_TEST(UnitTestParsingRequestParams)
 
 UnitTestParsingRequestParams::UnitTestParsingRequestParams()
diff --git a/unit-tests.wsjcpp/src/unit_test_parsing_request_params.h b/unit-tests.wsjcpp/src/unit_test_parsing_request_params.h
deleted file mode 100644
index 7a5f099..0000000
--- a/unit-tests.wsjcpp/src/unit_test_parsing_request_params.h
+++ /dev/null
@@ -1,15 +0,0 @@
-#ifndef UNIT_TEST_PARSING_REQUEST_PARAMS_H
-#define UNIT_TEST_PARSING_REQUEST_PARAMS_H
-
-#include 
-
-class UnitTestParsingRequestParams : public WsjcppUnitTestBase {
-    public:
-        UnitTestParsingRequestParams();
-        virtual bool doBeforeTest() override;
-        virtual void executeTest() override;
-        virtual bool doAfterTest() override;
-};
-
-#endif // UNIT_TEST_PARSING_REQUEST_PARAMS_H
-
diff --git a/unit-tests.wsjcpp/src/unit_test_request_parse_income_data.cpp b/unit-tests.wsjcpp/src/unit_test_request_parse_income_data.cpp
index 97fed55..607f24d 100644
--- a/unit-tests.wsjcpp/src/unit_test_request_parse_income_data.cpp
+++ b/unit-tests.wsjcpp/src/unit_test_request_parse_income_data.cpp
@@ -1,8 +1,16 @@
-#include "unit_test_request_parse_income_data.h"
+#include 
 #include 
 #include 
 #include 
 
+class UnitTestRequestParseIncomeData : public WsjcppUnitTestBase {
+    public:
+        UnitTestRequestParseIncomeData();
+        virtual bool doBeforeTest() override;
+        virtual void executeTest() override;
+        virtual bool doAfterTest() override;
+};
+
 REGISTRY_WSJCPP_UNIT_TEST(UnitTestRequestParseIncomeData)
 
 UnitTestRequestParseIncomeData::UnitTestRequestParseIncomeData()
@@ -28,17 +36,17 @@ void UnitTestRequestParseIncomeData::executeTest() {
     {
         pFakeClient->clearLastTextMessage();
         WsjcppJsonRpc20Request *pRequest = new WsjcppJsonRpc20Request(pClient, pWebSocketServer);
-        compareB("parseIncomeData empty", pRequest->parseIncomeData(""), false);
+        compare("parseIncomeData empty", pRequest->parseIncomeData(""), false);
         std::string sResponse0 = pFakeClient->getLastTextMessage();
         nlohmann::json jsonResponse = nlohmann::json::parse(sResponse0);
         std::string sErrorMessage = jsonResponse["error"]["message"];
-        compareS("parseIncomeData empty. error.message", sErrorMessage, "WRONG_JSON");
+        compare("parseIncomeData empty. error.message", sErrorMessage, "WRONG_JSON");
         int nErrorCode = jsonResponse["error"]["code"];
-        compareN("parseIncomeData empty. error.code", nErrorCode, 400);
+        compare("parseIncomeData empty. error.code", nErrorCode, 400);
         std::string sId = jsonResponse["id"];
-        compareS("parseIncomeData empty. id", sId, "unknown_id");
+        compare("parseIncomeData empty. id", sId, "unknown_id");
         std::string sMethod = jsonResponse["method"];
-        compareS("parseIncomeData empty. method", sMethod, "unknown_method");
+        compare("parseIncomeData empty. method", sMethod, "unknown_method");
         delete pRequest;
     }
     
@@ -50,17 +58,17 @@ void UnitTestRequestParseIncomeData::executeTest() {
         jsonRequest["method"] = "game_create";
         std::string sRequest = jsonRequest.dump();
         WsjcppJsonRpc20Request *pRequest = new WsjcppJsonRpc20Request(pClient, pWebSocketServer);
-        compareB("parseIncomeData missing id", pRequest->parseIncomeData(sRequest), false);
+        compare("parseIncomeData missing id", pRequest->parseIncomeData(sRequest), false);
         std::string sResponse = pFakeClient->getLastTextMessage();
         nlohmann::json jsonResponse = nlohmann::json::parse(sResponse);
         std::string sErrorMessage = jsonResponse["error"]["message"];
-        compareS("parseIncomeData missing id. error.message", sErrorMessage, "NOT_FOUND_ID_IN_REQUEST");
+        compare("parseIncomeData missing id. error.message", sErrorMessage, "NOT_FOUND_ID_IN_REQUEST");
         int nErrorCode = jsonResponse["error"]["code"];
-        compareN("parseIncomeData missing id. error.code", nErrorCode, 400);
+        compare("parseIncomeData missing id. error.code", nErrorCode, 400);
         std::string sId = jsonResponse["id"];
-        compareS("parseIncomeData missing id. id", sId, "unknown_id");
+        compare("parseIncomeData missing id. id", sId, "unknown_id");
         std::string sMethod = jsonResponse["method"];
-        compareS("parseIncomeData missing id. method", sMethod, "game_create");
+        compare("parseIncomeData missing id. method", sMethod, "game_create");
         delete pRequest;
     }
 
@@ -72,18 +80,18 @@ void UnitTestRequestParseIncomeData::executeTest() {
         jsonRequest["id"] = "id1";
         std::string sRequest = jsonRequest.dump();
         WsjcppJsonRpc20Request *pRequest = new WsjcppJsonRpc20Request(pClient, pWebSocketServer);
-        compareB("parseIncomeData missing method", pRequest->parseIncomeData(sRequest), false);
+        compare("parseIncomeData missing method", pRequest->parseIncomeData(sRequest), false);
         std::string sResponse = pFakeClient->getLastTextMessage();
         // std::cout << sResponse << std::endl;
         nlohmann::json jsonResponse = nlohmann::json::parse(sResponse);
         std::string sErrorMessage = jsonResponse["error"]["message"];
-        compareS("parseIncomeData missing method. error. message", sErrorMessage, "NOT_FOUND_METHOD_IN_REQUEST");
+        compare("parseIncomeData missing method. error. message", sErrorMessage, "NOT_FOUND_METHOD_IN_REQUEST");
         int nErrorCode = jsonResponse["error"]["code"];
-        compareN("parseIncomeData missing method. error. code", nErrorCode, 400);
+        compare("parseIncomeData missing method. error. code", nErrorCode, 400);
         std::string sId = jsonResponse["id"];
-        compareS("parseIncomeData missing method. id", sId, "id1");
+        compare("parseIncomeData missing method. id", sId, "id1");
         std::string sMethod = jsonResponse["method"];
-        compareS("parseIncomeData missing method. method", sMethod, "unknown_method");
+        compare("parseIncomeData missing method. method", sMethod, "unknown_method");
         delete pRequest;
     }
 
@@ -95,18 +103,18 @@ void UnitTestRequestParseIncomeData::executeTest() {
         jsonRequest["method"] = "game_create";
         std::string sRequest = jsonRequest.dump();
         WsjcppJsonRpc20Request *pRequest = new WsjcppJsonRpc20Request(pClient, pWebSocketServer);
-        compareB("parseIncomeData missing jsonrpc", pRequest->parseIncomeData(sRequest), false);
+        compare("parseIncomeData missing jsonrpc", pRequest->parseIncomeData(sRequest), false);
         std::string sResponse = pFakeClient->getLastTextMessage();
         // std::cout << sResponse << std::endl;
         nlohmann::json jsonResponse = nlohmann::json::parse(sResponse);
         std::string sErrorMessage = jsonResponse["error"]["message"];
-        compareS("parseIncomeData missing jsonrpc. error.message", sErrorMessage, "NOT_FOUND_FIELD_JSONRPC_IN_REQUEST");
+        compare("parseIncomeData missing jsonrpc. error.message", sErrorMessage, "NOT_FOUND_FIELD_JSONRPC_IN_REQUEST");
         int nErrorCode = jsonResponse["error"]["code"];
-        compareN("parseIncomeData missing jsonrpc. error.code", nErrorCode, 400);
+        compare("parseIncomeData missing jsonrpc. error.code", nErrorCode, 400);
         std::string sId = jsonResponse["id"];
-        compareS("parseIncomeData missing jsonrpc. id", sId, "id1");
+        compare("parseIncomeData missing jsonrpc. id", sId, "id1");
         std::string sMethod = jsonResponse["method"];
-        compareS("parseIncomeData missing jsonrpc. method", sMethod, "game_create");
+        compare("parseIncomeData missing jsonrpc. method", sMethod, "game_create");
         delete pRequest;
     }
 
@@ -119,18 +127,18 @@ void UnitTestRequestParseIncomeData::executeTest() {
         jsonRequest["method"] = "game_create";
         std::string sRequest = jsonRequest.dump();
         WsjcppJsonRpc20Request *pRequest = new WsjcppJsonRpc20Request(pClient, pWebSocketServer);
-        compareB("parseIncomeData jsonrpc is non string", pRequest->parseIncomeData(sRequest), false);
+        compare("parseIncomeData jsonrpc is non string", pRequest->parseIncomeData(sRequest), false);
         std::string sResponse = pFakeClient->getLastTextMessage();
         // std::cout << sResponse << std::endl;
         nlohmann::json jsonResponse = nlohmann::json::parse(sResponse);
         std::string sErrorMessage = jsonResponse["error"]["message"];
-        compareS("parseIncomeData jsonrpc is non string. error.message", sErrorMessage, "FIELD_JSONRPC_EXPECTED_AS_STRING_IN_REQUEST");
+        compare("parseIncomeData jsonrpc is non string. error.message", sErrorMessage, "FIELD_JSONRPC_EXPECTED_AS_STRING_IN_REQUEST");
         int nErrorCode = jsonResponse["error"]["code"];
-        compareN("parseIncomeData jsonrpc is non string. error.code", nErrorCode, 400);
+        compare("parseIncomeData jsonrpc is non string. error.code", nErrorCode, 400);
         std::string sId = jsonResponse["id"];
-        compareS("parseIncomeData jsonrpc is non string. id", sId, "id1");
+        compare("parseIncomeData jsonrpc is non string. id", sId, "id1");
         std::string sMethod = jsonResponse["method"];
-        compareS("parseIncomeData jsonrpc is non string. method", sMethod, "game_create");
+        compare("parseIncomeData jsonrpc is non string. method", sMethod, "game_create");
         delete pRequest;
     }
 
@@ -143,18 +151,18 @@ void UnitTestRequestParseIncomeData::executeTest() {
         jsonRequest["method"] = "game_create";
         std::string sRequest = jsonRequest.dump();
         WsjcppJsonRpc20Request *pRequest = new WsjcppJsonRpc20Request(pClient, pWebSocketServer);
-        compareB("parseIncomeData jsonrpc is no 2.0", pRequest->parseIncomeData(sRequest), false);
+        compare("parseIncomeData jsonrpc is no 2.0", pRequest->parseIncomeData(sRequest), false);
         std::string sResponse = pFakeClient->getLastTextMessage();
         // std::cout << sResponse << std::endl;
         nlohmann::json jsonResponse = nlohmann::json::parse(sResponse);
         std::string sErrorMessage = jsonResponse["error"]["message"];
-        compareS("parseIncomeData jsonrpc is no 2.0. error.message", sErrorMessage, "FIELD_JSONRPC_EXPECTED_2_DOT_0_IN_REQUEST");
+        compare("parseIncomeData jsonrpc is no 2.0. error.message", sErrorMessage, "FIELD_JSONRPC_EXPECTED_2_DOT_0_IN_REQUEST");
         int nErrorCode = jsonResponse["error"]["code"];
-        compareN("parseIncomeData jsonrpc is no 2.0. error.code", nErrorCode, 400);
+        compare("parseIncomeData jsonrpc is no 2.0. error.code", nErrorCode, 400);
         std::string sId = jsonResponse["id"];
-        compareS("parseIncomeData jsonrpc is no 2.0. id", sId, "id1");
+        compare("parseIncomeData jsonrpc is no 2.0. id", sId, "id1");
         std::string sMethod = jsonResponse["method"];
-        compareS("parseIncomeData jsonrpc is no 2.0. method", sMethod, "game_create");
+        compare("parseIncomeData jsonrpc is no 2.0. method", sMethod, "game_create");
         delete pRequest;
     }
 
@@ -168,18 +176,18 @@ void UnitTestRequestParseIncomeData::executeTest() {
         jsonRequest["params"] = nlohmann::json::array();
         std::string sRequest = jsonRequest.dump();
         WsjcppJsonRpc20Request *pRequest = new WsjcppJsonRpc20Request(pClient, pWebSocketServer);
-        compareB("parseIncomeData field params wrong", pRequest->parseIncomeData(sRequest), false);
+        compare("parseIncomeData field params wrong", pRequest->parseIncomeData(sRequest), false);
         std::string sResponse = pFakeClient->getLastTextMessage();
         // std::cout << sResponse << std::endl;
         nlohmann::json jsonResponse = nlohmann::json::parse(sResponse);
         std::string sErrorMessage = jsonResponse["error"]["message"];
-        compareS("parseIncomeData field params wrong. error.message", sErrorMessage, "FIELD_PARAMS_EXPECTED_AS_OBJECT_IN_REQUEST");
+        compare("parseIncomeData field params wrong. error.message", sErrorMessage, "FIELD_PARAMS_EXPECTED_AS_OBJECT_IN_REQUEST");
         int nErrorCode = jsonResponse["error"]["code"];
-        compareN("parseIncomeData field params wrong. error.code", nErrorCode, 400);
+        compare("parseIncomeData field params wrong. error.code", nErrorCode, 400);
         std::string sId = jsonResponse["id"];
-        compareS("parseIncomeData field params wrong. id", sId, "id1");
+        compare("parseIncomeData field params wrong. id", sId, "id1");
         std::string sMethod = jsonResponse["method"];
-        compareS("parseIncomeData field params wrong. method", sMethod, "game_create");
+        compare("parseIncomeData field params wrong. method", sMethod, "game_create");
         delete pRequest;
     }
 
@@ -193,9 +201,9 @@ void UnitTestRequestParseIncomeData::executeTest() {
         jsonRequest["params"] = nlohmann::json::object();
         std::string sRequest = jsonRequest.dump();
         WsjcppJsonRpc20Request *pRequest = new WsjcppJsonRpc20Request(pClient, pWebSocketServer);
-        compareB("parseIncomeData success parsing", pRequest->parseIncomeData(sRequest), true);
+        compare("parseIncomeData success parsing", pRequest->parseIncomeData(sRequest), true);
         std::string sResponse = pFakeClient->getLastTextMessage();
-        compareS("parseIncomeData success parsing. error must be empty", sResponse, "");
+        compare("parseIncomeData success parsing. error must be empty", sResponse, "");
         delete pRequest;
     }
 
diff --git a/unit-tests.wsjcpp/src/unit_test_request_parse_income_data.h b/unit-tests.wsjcpp/src/unit_test_request_parse_income_data.h
deleted file mode 100644
index 31412b4..0000000
--- a/unit-tests.wsjcpp/src/unit_test_request_parse_income_data.h
+++ /dev/null
@@ -1,15 +0,0 @@
-#ifndef UNIT_TEST_REQUEST_PARSE_INCOME_DATA_H
-#define UNIT_TEST_REQUEST_PARSE_INCOME_DATA_H
-
-#include 
-
-class UnitTestRequestParseIncomeData : public WsjcppUnitTestBase {
-    public:
-        UnitTestRequestParseIncomeData();
-        virtual bool doBeforeTest() override;
-        virtual void executeTest() override;
-        virtual bool doAfterTest() override;
-};
-
-#endif // UNIT_TEST_REQUEST_PARSE_INCOME_DATA_H
-
diff --git a/unit-tests.wsjcpp/src/unit_test_request_server_api.cpp b/unit-tests.wsjcpp/src/unit_test_request_server_api.cpp
index cbba7ad..b8ab835 100644
--- a/unit-tests.wsjcpp/src/unit_test_request_server_api.cpp
+++ b/unit-tests.wsjcpp/src/unit_test_request_server_api.cpp
@@ -1,4 +1,4 @@
-#include "unit_test_request_server_api.h"
+#include 
 #include 
 #include 
 #include 
@@ -6,6 +6,14 @@
 // ---------------------------------------------------------------------
 // UnitTestRequestServerApi
 
+class UnitTestRequestServerApi : public WsjcppUnitTestBase {
+    public:
+        UnitTestRequestServerApi();
+        virtual bool doBeforeTest() override;
+        virtual void executeTest() override;
+        virtual bool doAfterTest() override;
+};
+
 REGISTRY_WSJCPP_UNIT_TEST(UnitTestRequestServerApi)
 
 UnitTestRequestServerApi::UnitTestRequestServerApi()
@@ -36,7 +44,7 @@ void UnitTestRequestServerApi::executeTest() {
     requestJson["id"] = "id1";
     
     std::string sRequest = requestJson.dump();
-    compareB("Response: check method", pRequest->parseIncomeData(sRequest), true);
+    compare("Response: check method", pRequest->parseIncomeData(sRequest), true);
 
     pHandlerServerApi->handle(pRequest);
 
@@ -47,17 +55,17 @@ void UnitTestRequestServerApi::executeTest() {
     std::string sMethod = respJson["method"];
     std::string sId = respJson["id"];
     std::string sJsonRpc = respJson["jsonrpc"];
-    compareS("Response: check method", sMethod, "server_api");
-    compareS("Response: check id", sId, "id1");
-    compareS("Response: check jsonrpc", sJsonRpc, "2.0");
+    compare("Response: check method", sMethod, "server_api");
+    compare("Response: check id", sId, "id1");
+    compare("Response: check jsonrpc", sJsonRpc, "2.0");
 
     
     std::string sVersion = respJson["result"]["version"];
-    compareS("Response: check result.version", sVersion, std::string(WSJCPP_APP_VERSION));
+    compare("Response: check result.version", sVersion, std::string(WSJCPP_APP_VERSION));
     
     int nDataLength = respJson["result"]["data_length"];
     int nExpectedDataLength = respJson["result"]["data"].size();
-    compareN("Response: check result.data_length", nDataLength, nExpectedDataLength);
+    compare("Response: check result.data_length", nDataLength, nExpectedDataLength);
 
     int nId = 1;
     for (int i = 0; i < nExpectedDataLength; i++) {
@@ -73,16 +81,16 @@ void UnitTestRequestServerApi::executeTest() {
     bool bAccessTester = data0Json["access"]["tester"];
     bool bAccessAdmin = data0Json["access"]["admin"];
 
-    compareB("Response: check result.data[0].access.unauthorized", bAccessUnauthorized, true);
-    compareB("Response: check result.data[0].access.user", bAccessUser, true);
-    compareB("Response: check result.data[0].access.tester", bAccessTester, true);
-    compareB("Response: check result.data[0].access.admin", bAccessAdmin, true);
+    compare("Response: check result.data[0].access.unauthorized", bAccessUnauthorized, true);
+    compare("Response: check result.data[0].access.user", bAccessUser, true);
+    compare("Response: check result.data[0].access.tester", bAccessTester, true);
+    compare("Response: check result.data[0].access.admin", bAccessAdmin, true);
     
     sMethod = data0Json["method"];
-    compareS("Response: check result.data[0].method", sMethod, "server_api");
+    compare("Response: check result.data[0].method", sMethod, "server_api");
     std::string sDescription = data0Json["description"];
 
-    compareS("Response: check result.data[0].method", sDescription, pHandlerServerApi->getDescription());
+    compare("Response: check result.data[0].method", sDescription, pHandlerServerApi->getDescription());
 }
 
 // ---------------------------------------------------------------------
diff --git a/unit-tests.wsjcpp/src/unit_test_request_server_api.h b/unit-tests.wsjcpp/src/unit_test_request_server_api.h
deleted file mode 100644
index 6ab7fd7..0000000
--- a/unit-tests.wsjcpp/src/unit_test_request_server_api.h
+++ /dev/null
@@ -1,15 +0,0 @@
-#ifndef UNIT_TEST_REQUEST_SERVER_API_H
-#define UNIT_TEST_REQUEST_SERVER_API_H
-
-#include 
-
-class UnitTestRequestServerApi : public WsjcppUnitTestBase {
-    public:
-        UnitTestRequestServerApi();
-        virtual bool doBeforeTest() override;
-        virtual void executeTest() override;
-        virtual bool doAfterTest() override;
-};
-
-#endif // UNIT_TEST_REQUEST_SERVER_API_H
-
diff --git a/wsjcpp.yml b/wsjcpp.yml
index bdeb333..2c4a389 100644
--- a/wsjcpp.yml
+++ b/wsjcpp.yml
@@ -1,33 +1,38 @@
 name: "wsjcpp-jsonrpc20"
-version: v0.0.3
+version: v0.0.4
 cmake_minimum_required: "3.0"
 cmake_cxx_standard: "11"
 description: "Implementation of JsonRPC 2.0"
 authors:
   - name: "Evgenii Sopov"
     email: "mrseakg@gmail.com"
+
 origins:
   - address: "https://sea-kg.com/wsjcpp-package-registry/"
     type: "package-registry"
+
 keywords:
   - "c++"
 
 dependencies:
   - name: "wsjcpp-core"
-    version: "v0.2.0"
+    version: "v0.2.1"
     url: "https://github.com/wsjcpp/wsjcpp-core:master"
     origin: "https://github.com/"
     installation-dir: "./src.wsjcpp/wsjcpp_core"
+    installation-datetime: "Sat, 03 Oct 2020 12:31:01 GMT"
   - name: "nlohmann/json"
     version: "v3.9.1"
     url: "https://github.com/nlohmann/json:develop"
     origin: "https://github.com/"
     installation-dir: "./src.wsjcpp/nlohmann_json"
+    installation-datetime: "Fri, 02 Oct 2020 04:29:29 GMT"
   - name: "wsjcpp-validators"
     version: "v0.1.2"
     url: "https://github.com/wsjcpp/wsjcpp-validators:master"
     origin: "https://github.com/"
     installation-dir: "./src.wsjcpp/wsjcpp_validators"
+    installation-datetime: "Sat, 03 Oct 2020 12:46:55 GMT"
 
 distribution:
   - source-file: "src/wsjcpp_jsonrpc20.h"
@@ -45,6 +50,18 @@ distribution:
   - source-file: "scripts.wsjcpp/generate.WsjcppJsonRpc20Handler"
     target-file: "generate.WsjcppJsonRpc20Handler"
     type: "safe-scripting-generate"
+  - source-file: "src/wsjcpp_jsonrpc20_export_cli_webjs.h"
+    target-file: "wsjcpp_jsonrpc20_export_cli_webjs.h"
+    type: "source-code"
+  - source-file: "src/wsjcpp_jsonrpc20_export_cli_webjs.cpp"
+    target-file: "wsjcpp_jsonrpc20_export_cli_webjs.cpp"
+    type: "source-code"
+  - source-file: "src/wsjcpp_jsonrpc20_export_cli_base.h"
+    target-file: "wsjcpp_jsonrpc20_export_cli_base.h"
+    type: "source-code"
+  - source-file: "src/wsjcpp_jsonrpc20_export_cli_base.cpp"
+    target-file: "wsjcpp_jsonrpc20_export_cli_base.cpp"
+    type: "source-code"
 
 unit-tests:
   cases: