From 3b9a791048f92d5d7914b0a47b262b17727bf40b Mon Sep 17 00:00:00 2001
From: Beeant <huangxb0512@gmail.com>
Date: Sat, 24 Sep 2022 05:04:27 +0000
Subject: [PATCH 01/10] 7.2.0.204

---
 .github/workflows/docker-image.yml | 3 ++-
 Dockerfile                         | 4 ++--
 2 files changed, 4 insertions(+), 3 deletions(-)

diff --git a/.github/workflows/docker-image.yml b/.github/workflows/docker-image.yml
index 05b4a37..360adc8 100644
--- a/.github/workflows/docker-image.yml
+++ b/.github/workflows/docker-image.yml
@@ -21,4 +21,5 @@ jobs:
         username: ${{ secrets.DOCKER_USERNAME }}
         password: ${{ secrets.DOCKER_PASSWORD }}
         repository: xbeeant/oo-unlimit
-        tags: latest
+        tags: latest, 7.2.0.204
+
diff --git a/Dockerfile b/Dockerfile
index 460d57d..8759404 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -1,5 +1,5 @@
-ARG product_version=7.1.1
-ARG build_number=23
+ARG product_version=7.2.0
+ARG build_number=204
 ARG oo_root='/var/www/onlyoffice/documentserver'
 
 ## Setup

From a05666ba58a620a5b4fef7eeb3b8bc478e32c3fc Mon Sep 17 00:00:00 2001
From: Beeant <huangxb0512@gmail.com>
Date: Sat, 24 Sep 2022 13:42:15 +0000
Subject: [PATCH 02/10] 7.2 patch

---
 server.patch   |  134 ++--
 web-apps.patch | 1629 ++----------------------------------------------
 2 files changed, 112 insertions(+), 1651 deletions(-)

diff --git a/server.patch b/server.patch
index 1278c2d..0727519 100644
--- a/server.patch
+++ b/server.patch
@@ -1,9 +1,22 @@
-diff --git a/Common/sources/constants.js b/Common/sources/constants.js
-index 0663ead..490582a 100644
---- a/Common/sources/constants.js
-+++ b/Common/sources/constants.js
-@@ -75,7 +75,7 @@ exports.LICENSE_RESULT = {
-   ExpiredLimited: 11
+From 3c58d272005a300ad8fe575457d5ce25710833e9 Mon Sep 17 00:00:00 2001
+From: Beeant <huangxb0512@gmail.com>
+Date: Sat, 24 Sep 2022 21:38:51 +0800
+Subject: [PATCH] build: license
+
+---
+ Common/sources/constants.js              |  2 +-
+ Common/sources/license.js                | 16 ++++++++--------
+ DocService/sources/server.js             |  2 +-
+ FileConverter/sources/convertermaster.js |  1 -
+ Makefile                                 |  2 +-
+ 5 files changed, 11 insertions(+), 12 deletions(-)
+
+diff --git a/Common/sources/constants.js b/Common/sources/constants.js
+index 65d4c6f..39a7e56 100644
+--- a/Common/sources/constants.js
++++ b/Common/sources/constants.js
+@@ -83,7 +83,7 @@ exports.LICENSE_RESULT = {
+   UsersViewCountOS: 15
  };
  
 -exports.LICENSE_CONNECTIONS = 20;
@@ -11,11 +24,11 @@ index 0663ead..490582a 100644
  exports.LICENSE_EXPIRE_USERS_ONE_DAY = 24 * 60 * 60; // day in seconds
  
  exports.AVS_OFFICESTUDIO_FILE_UNKNOWN =  0x0000;
-diff --git a/Common/sources/license.js b/Common/sources/license.js
-index c273afe..8786f62 100644
---- a/Common/sources/license.js
-+++ b/Common/sources/license.js
-@@ -45,20 +45,20 @@ exports.readLicense = function*() {
+diff --git a/Common/sources/license.js b/Common/sources/license.js
+index fbd5ec8..203dcb0 100644
+--- a/Common/sources/license.js
++++ b/Common/sources/license.js
+@@ -45,22 +45,22 @@ exports.readLicense = function*() {
  		count: 1,
  		type: c_LR.Success,
  		light: false,
@@ -25,10 +38,12 @@ index c273afe..8786f62 100644
 -		branding: false,
 +		branding: true,
  		connections: constants.LICENSE_CONNECTIONS,
+ 		connectionsView: constants.LICENSE_CONNECTIONS,
 -		customization: false,
 -		usersCount: 0,
 +		customization: true,
 +		usersCount: constants.LICENSE_CONNECTIONS,
+ 		usersViewCount: 0,
  		usersExpire: constants.LICENSE_EXPIRE_USERS_ONE_DAY,
 -		hasLicense: false,
 -		plugins: false,
@@ -37,70 +52,51 @@ index c273afe..8786f62 100644
  		buildDate: oBuildDate,
  		startDate: startDate,
 -		endDate: null,
--		customerId: ""
-+		customerId: "",
-+		endDate: new Date("2099-01-01T23:59:59.000Z")
++		endDate: new Date("2099-01-01T23:59:59.000Z"),
+ 		customerId: ""
  	}, null];
  };
  
 -exports.packageType = constants.PACKAGE_TYPE_OS;
 +exports.packageType = constants.PACKAGE_TYPE_I;
-diff --git a/DocService/sources/DocsCoServer.js b/DocService/sources/DocsCoServer.js
-index b654c9c..31bdf2d 100644
---- a/DocService/sources/DocsCoServer.js
-+++ b/DocService/sources/DocsCoServer.js
-@@ -165,7 +165,7 @@ let connections = []; // Активные соединения
- let lockDocumentsTimerId = {};//to drop connection that can't unlockDocument
- let pubsub;
- let queue;
--let licenseInfo = {type: constants.LICENSE_RESULT.Error, light: false, branding: false, customization: false, plugins: false};
-+let licenseInfo = license.readLicense().next().value[0];
- let licenseOriginal = null;
- let shutdownFlag = false;
- let expDocumentsStep = gc.getCronStep(cfgExpDocumentsCron);
-@@ -3328,7 +3328,7 @@ exports.install = function(server, callbackFunction) {
-   });
- };
- exports.setLicenseInfo = function(data, original ) {
--  licenseInfo = data;
-+  logger.debug('Not updating license info', data);
-   licenseOriginal = original;
- };
- exports.getLicenseInfo = function() {
-diff --git a/DocService/sources/server.js b/DocService/sources/server.js
-index ccc232b..7c4e80d 100644
---- a/DocService/sources/server.js
-+++ b/DocService/sources/server.js
-@@ -147,7 +147,6 @@ try {
- } catch (e) {
- 	logger.warn('Failed to subscribe to plugin folder updates. When changing the list of plugins, you must restart the server. https://nodejs.org/docs/latest/api/fs.html#fs_availability');
- }
--fs.watchFile(configCommon.get('license').get('license_file'), updateLicense);
- setInterval(updateLicense, 86400000);
- 
- // Если захочется использовать 'development' и 'production',
-diff --git a/FileConverter/sources/convertermaster.js b/FileConverter/sources/convertermaster.js
-index 2c4526f..ec07464 100644
---- a/FileConverter/sources/convertermaster.js
-+++ b/FileConverter/sources/convertermaster.js
-@@ -85,7 +85,6 @@ if (cluster.isMaster) {
+diff --git a/DocService/sources/server.js b/DocService/sources/server.js
+index cf3ba90..d256724 100644
+--- a/DocService/sources/server.js
++++ b/DocService/sources/server.js
+@@ -110,7 +110,7 @@ if (!(cfgTokenEnableBrowser && cfgTokenEnableRequestInbox && cfgTokenEnableReque
  
+ if (!tenantManager.isMultitenantMode()) {
+ 	updateLicense();
+-	fs.watchFile(cfgLicenseFile, updateLicense);
++	
+ 	setInterval(updateLicense, 86400000);
+ }
+ 
+diff --git a/FileConverter/sources/convertermaster.js b/FileConverter/sources/convertermaster.js
+index 2a0b366..96468f9 100644
+--- a/FileConverter/sources/convertermaster.js
++++ b/FileConverter/sources/convertermaster.js
+@@ -93,7 +93,6 @@ if (cluster.isMaster) {
    updateLicense();
  
--  fs.watchFile(configCommon.get('license').get('license_file'), updateLicense);
-   setInterval(updateLicense, 86400000);
+   if (!tenantManager.isMultitenantMode()) {
+-    fs.watchFile(cfgLicenseFile, updateLicense);
+     setInterval(updateLicense, 86400000);
+   }
  } else {
-   const converter = require('./converter');
-diff --git a/Makefile b/Makefile
-index e8e1308..23f7e2e 100644
---- a/Makefile
-+++ b/Makefile
-@@ -87,7 +87,7 @@ DEBUG = $(BRANDING_DIR)/debug.js
- .PHONY: all clean install uninstall build-date
- 
- .NOTPARALLEL:
--all: $(SPELLCHECKER_DICTIONARIES) $(TOOLS) $(SCHEMA) $(CORE_FONTS) $(DOCUMENT_TEMPLATES) $(LICENSE) $(WELCOME) $(INFO) build-date
-+all: $(SCHEMA) $(LICENSE) $(WELCOME) $(INFO) build-date
- 
- build-date: $(GRUNT_FILES)
- 	sed "s|\(const buildVersion = \).*|\1'${PRODUCT_VERSION}';|" -i $(COMMON_DEFINES_JS)
+diff --git a/Makefile b/Makefile
+index e8e1308..a4b0a51 100644
+--- a/Makefile
++++ b/Makefile
+@@ -87,7 +87,7 @@ DEBUG = $(BRANDING_DIR)/debug.js
+ .PHONY: all clean install uninstall build-date
+ 
+ .NOTPARALLEL:
+-all: $(SPELLCHECKER_DICTIONARIES) $(TOOLS) $(SCHEMA) $(CORE_FONTS) $(DOCUMENT_TEMPLATES) $(LICENSE) $(WELCOME) $(INFO) build-date
++all: $(SPELLCHECKER_DICTIONARIES) $(TOOLS) $(SCHEMA) $(CORE_FONTS) $(DOCUMENT_TEMPLATES) $(WELCOME) $(INFO) build-date
+ 
+ build-date: $(GRUNT_FILES)
+ 	sed "s|\(const buildVersion = \).*|\1'${PRODUCT_VERSION}';|" -i $(COMMON_DEFINES_JS)
+-- 
+2.31.1.windows.1
+
diff --git a/web-apps.patch b/web-apps.patch
index 8c0b4d2..e657ef0 100644
--- a/web-apps.patch
+++ b/web-apps.patch
@@ -1,1586 +1,51 @@
-From b99b3c2013521042374601e514d9e91c93372016 Mon Sep 17 00:00:00 2001
-From: Alexander Hofbauer <alex@derhofbauer.at>
-Date: Sat, 3 Jul 2021 08:29:29 +0200
-Subject: [PATCH] Revert "disable mobile editing"
+From 692bef4561ef9978c6b8663dd618211bf526b69f Mon Sep 17 00:00:00 2001
+From: Beeant <huangxb0512@gmail.com>
+Date: Sat, 24 Sep 2022 21:39:36 +0800
+Subject: [PATCH] build: license
 
-partially brings back mobile editing, especially via:
-
-  - 631cea5e0683c472ec5070f9f73f628def1fa259
-  - ae69d00eb7ca8874d7d645289f7bfecce2af5d37
-  - 35ea66e4407b8c948d5f5bb75b96c93a719ef210
-  - 19e4859e1051fe16697272be3bacaacc06cc9f40
-  - dc46e1b97f6aa80eb3b5039c5a13ab10637115ac
-  - 1ed80f9497222038da8845985786f5f0f4f5ad79
-  - 2ab911a439c904a1e1da81283b77639a1f1aa6b1
 ---
- .../mobile/app/controller/Main.js             |  9 +--
- .../mobile/app/controller/add/AddImage.js     |  7 ++
- .../mobile/app/controller/add/AddOther.js     | 63 +++++++++++++++++-
- .../mobile/app/controller/add/AddShape.js     |  7 ++
- .../mobile/app/controller/add/AddTable.js     | 26 +++++++-
- .../mobile/app/controller/edit/EditChart.js   | 32 +++++++++-
- .../app/controller/edit/EditParagraph.js      | 54 +++++++++++++++-
- .../mobile/app/controller/edit/EditShape.js   | 20 ++++++
- .../mobile/app/controller/edit/EditTable.js   | 25 ++++++++
- .../mobile/app/controller/edit/EditText.js    | 34 +++++++++-
- .../mobile/app/controller/Main.js             |  5 +-
- .../mobile/app/controller/add/AddImage.js     |  7 ++
- .../mobile/app/controller/add/AddLink.js      | 61 +++++++++++++++++-
- .../mobile/app/controller/add/AddShape.js     |  7 ++
- .../mobile/app/controller/add/AddSlide.js     | 34 +++++++++-
- .../mobile/app/controller/add/AddTable.js     | 31 ++++++++-
- .../mobile/app/controller/edit/EditChart.js   | 26 +++++++-
- .../mobile/app/controller/edit/EditShape.js   | 16 +++++
- .../mobile/app/controller/edit/EditSlide.js   | 45 ++++++++++++-
- .../mobile/app/controller/edit/EditTable.js   | 23 +++++++
- .../mobile/app/controller/edit/EditText.js    | 42 +++++++++++-
- .../mobile/app/controller/Main.js             |  5 +-
- .../mobile/app/controller/add/AddChart.js     |  4 ++
- .../mobile/app/controller/add/AddFunction.js  | 41 +++++++++++-
- .../mobile/app/controller/add/AddLink.js      | 47 +++++++++++++-
- .../mobile/app/controller/add/AddOther.js     | 10 +++
- .../mobile/app/controller/add/AddShape.js     |  6 ++
- .../mobile/app/controller/edit/EditCell.js    | 45 ++++++++++++-
- .../mobile/app/controller/edit/EditChart.js   | 64 ++++++++++++++++++-
- .../mobile/app/controller/edit/EditShape.js   | 19 ++++++
- 30 files changed, 786 insertions(+), 29 deletions(-)
+ apps/documenteditor/mobile/src/lib/patch.jsx     | 2 +-
+ apps/presentationeditor/mobile/src/lib/patch.jsx | 2 +-
+ apps/spreadsheeteditor/mobile/src/lib/patch.jsx  | 2 +-
+ 3 files changed, 3 insertions(+), 3 deletions(-)
 
-diff --git a/apps/documenteditor/mobile/app/controller/Main.js b/apps/documenteditor/mobile/app/controller/Main.js
-index b53ab6578..661444a9c 100644
---- a/apps/documenteditor/mobile/app/controller/Main.js
-+++ b/apps/documenteditor/mobile/app/controller/Main.js
-@@ -289,7 +289,7 @@ define([
-                     docInfo.asc_putIsEnabledMacroses(!!enable);
-                     enable = !this.editorConfig.customization || (this.editorConfig.customization.plugins!==false);
-                     docInfo.asc_putIsEnabledPlugins(!!enable);
--                    
-+
-                     var type = /^(?:(pdf|djvu|xps))$/.exec(data.doc.fileType);
-                     if (type && typeof type[1] === 'string') {
-                         this.permissions.edit = this.permissions.review = false;
-@@ -843,7 +843,7 @@ define([
-                 Common.Utils.UserInfoParser.setParser(me.appOptions.canUseReviewPermissions);
-                 Common.Utils.UserInfoParser.setCurrentName(me.appOptions.user.fullname);
-                 me.appOptions.canUseReviewPermissions && Common.Utils.UserInfoParser.setReviewPermissions(me.permissions.reviewGroups, me.editorConfig.customization.reviewPermissions);
--                
-+
-                 me.applyModeCommonElements();
-                 me.applyModeEditorElements();
- 
-@@ -1244,6 +1244,7 @@ define([
-             },
- 
-             onSendThemeColors: function(colors, standart_colors) {
-+               Common.Utils.ThemeColor.setColors(colors, standart_colors);
-             },
- 
-             onAdvancedOptions: function(type, advOptions, mode, formatOptions) {
-@@ -1449,7 +1450,7 @@ define([
-             },
- 
-             isSupportEditFeature: function() {
--                return false;
-+                return true;
-             },
- 
-             onRunAutostartMacroses: function() {
-@@ -1658,4 +1659,4 @@ define([
-             errorLang: 'The interface language is not loaded.<br>Please contact your Document Server administrator.'
-         }
-     })(), DE.Controllers.Main || {}))
--});
-\ No newline at end of file
-+});
-diff --git a/apps/documenteditor/mobile/app/controller/add/AddImage.js b/apps/documenteditor/mobile/app/controller/add/AddImage.js
-index 16ab14528..0a5faaa2d 100644
---- a/apps/documenteditor/mobile/app/controller/add/AddImage.js
-+++ b/apps/documenteditor/mobile/app/controller/add/AddImage.js
-@@ -98,6 +98,10 @@ define([
- 
-             onInsertByFile: function (e) {
-                 DE.getController('AddContainer').hideModal();
-+
-+                if (this.api) {
-+                    this.api.asc_addImage();
-+                }
-             },
- 
-             onUrlChange: function (e) {
-@@ -114,6 +118,9 @@ define([
-                     if (!_.isEmpty(value)) {
-                         if ((/((^https?)|(^ftp)):\/\/.+/i.test(value))) {
-                             DE.getController('AddContainer').hideModal();
-+                            _.defer(function () {
-+                                me.api.AddImageUrl(value);
-+                            });
-                         } else {
-                             uiApp.alert(me.txtNotUrl, me.notcriticalErrorTitle);
-                         }
-diff --git a/apps/documenteditor/mobile/app/controller/add/AddOther.js b/apps/documenteditor/mobile/app/controller/add/AddOther.js
-index 9dca563e3..ff5fc6bc8 100644
---- a/apps/documenteditor/mobile/app/controller/add/AddOther.js
-+++ b/apps/documenteditor/mobile/app/controller/add/AddOther.js
-@@ -238,7 +238,40 @@ define([
-             },
- 
-             onClickInsertFootnote: function() {
--                DE.getController('AddContainer').hideModal();
-+                var me = this,
-+                    format = $('input[name="doc-footnote-format"]:checked').data('value'),
-+                    start = $('#start-at-footnote .item-after label').text(),
-+                    position = $('input[name="doc-footnote-pos"]:checked').data('value'),
-+                    props = new Asc.CAscFootnotePr(),
-+                    isEndNote = (position === 2);
-+
-+                var startTo10;
-+                if (me.fromCustomFormat) {
-+                    startTo10 =  parseInt(me.fromCustomFormat(start));
-+                } else {
-+                    startTo10 = me.api.asc_GetFootnoteProps().get_NumStart();
-+                }
-+                props.put_Pos(position);
-+                props.put_NumFormat(format);
-+                props.put_NumStart(startTo10);
-+                props.put_NumRestart(Asc.c_oAscFootnoteRestart.Continuous);
-+
-+                if (me.api) {
-+                    if (isEndNote) {
-+                        me.api.asc_SetEndnoteProps(props, false);
-+                    } else {
-+                        me.api.asc_SetFootnoteProps(props, false);
-+                    }
-+
-+                    setTimeout(function() {
-+                        if (isEndNote) {
-+                            me.api.asc_AddEndnote();
-+                        } else {
-+                            me.api.asc_AddFootnote();
-+                        }
-+                    }, 1);
-+                    DE.getController('AddContainer').hideModal();
-+                }
-             },
- 
-             onFormatFootnoteChange: function(e) {
-@@ -299,6 +332,32 @@ define([
-             },
- 
-             onInsertLink: function (e) {
-+                var me      = this,
-+                    url     = $('#add-link-url input').val(),
-+                    display = $('#add-link-display input').val(),
-+                    tip     = $('#add-link-tip input').val(),
-+                    urltype = me.api.asc_getUrlType($.trim(url)),
-+                    isEmail = (urltype == 2);
-+
-+                if (urltype < 1) {
-+                    uiApp.alert(me.txtNotUrl);
-+                    return;
-+                }
-+
-+                url = url.replace(/^\s+|\s+$/g,'');
-+
-+                if (! /(((^https?)|(^ftp)):\/\/)|(^mailto:)/i.test(url) )
-+                    url = (isEmail ? 'mailto:' : 'http://' ) + url;
-+
-+                url = url.replace(new RegExp("%20",'g')," ");
-+
-+                var props = new Asc.CHyperlinkProperty();
-+                props.put_Value(url);
-+                props.put_Text(_.isEmpty(display) ? url : display);
-+                props.put_ToolTip(tip);
-+
-+                me.api.add_Hyperlink(props);
-+
-                 DE.getController('AddContainer').hideModal();
-             },
- 
-@@ -472,4 +531,4 @@ define([
-             notcriticalErrorTitle: 'Warning'
-         }
-     })(), DE.Controllers.AddOther || {}))
--});
-\ No newline at end of file
-+});
-diff --git a/apps/documenteditor/mobile/app/controller/add/AddShape.js b/apps/documenteditor/mobile/app/controller/add/AddShape.js
-index 32047d3dd..c8345c7af 100644
---- a/apps/documenteditor/mobile/app/controller/add/AddShape.js
-+++ b/apps/documenteditor/mobile/app/controller/add/AddShape.js
-@@ -215,6 +215,13 @@ define([
-             },
- 
-             onShapeClick: function (e) {
-+                var me = this,
-+                    $target = $(e.currentTarget);
-+
-+                if ($target && me.api) {
-+                    me.api.AddShapeOnCurrentPage($target.data('type'));
-+                }
-+
-                 DE.getController('AddContainer').hideModal();
-             },
- 
-diff --git a/apps/documenteditor/mobile/app/controller/add/AddTable.js b/apps/documenteditor/mobile/app/controller/add/AddTable.js
-index fef864537..a9dd39cf6 100644
---- a/apps/documenteditor/mobile/app/controller/add/AddTable.js
-+++ b/apps/documenteditor/mobile/app/controller/add/AddTable.js
-@@ -74,6 +74,8 @@ define([
-             setApi: function (api) {
-                 var me = this;
-                 me.api = api;
-+
-+                me.api.asc_registerCallback('asc_onInitTableTemplates', _.bind(me.onApiInitTemplates, me));
-             },
- 
-             onLaunch: function () {
-@@ -81,6 +83,12 @@ define([
-             },
- 
-             initEvents: function () {
-+                if (!this._initDefaultStyles) {
-+                    this._initDefaultStyles = true;
-+
-+                    this.api.asc_GetDefaultTableStyles();
-+                }
-+
-                 $('#add-table li').single('click',  _.buffered(this.onStyleClick, 100, this));
-             },
- 
-@@ -159,10 +167,26 @@ define([
-                 return this._styles;
-             },
- 
-+            // API handlers
-+
-+            onApiInitTemplates: function(templates) {
-+                var me = this;
-+                if (this._styles.length < 1) {
-+                    _.each(templates, function(template) {
-+                        me._styles.push({
-+                            imageUrl    : template.asc_getImage(),
-+                            templateId  : template.asc_getId()
-+                        });
-+                    });
-+
-+                    this.getView('AddTable').render();
-+                }
-+            },
-+
-             textTableSize: 'Table Size',
-             textColumns: 'Columns',
-             textRows: 'Rows',
-             textCancel: 'Cancel'
-         }
-     })(), DE.Controllers.AddTable || {}))
--});
-\ No newline at end of file
-+});
-diff --git a/apps/documenteditor/mobile/app/controller/edit/EditChart.js b/apps/documenteditor/mobile/app/controller/edit/EditChart.js
-index b2cc3d9cd..8b27b1c8c 100644
---- a/apps/documenteditor/mobile/app/controller/edit/EditChart.js
-+++ b/apps/documenteditor/mobile/app/controller/edit/EditChart.js
-@@ -135,6 +135,7 @@ define([
-                 me.api = api;
- 
-                 me.api.asc_registerCallback('asc_onFocusObject',        _.bind(me.onApiFocusObject, me));
-+                me.api.asc_registerCallback('asc_onUpdateChartStyles',  _.bind(me.onApiUpdateChartStyles, me));
-             },
- 
-             onLaunch: function () {
-@@ -301,6 +302,23 @@ define([
-             // Handlers
- 
-             onType: function (e) {
-+                var me = this,
-+                    $target = $(e.currentTarget),
-+                    type = $target.data('type');
-+
-+                var image = new Asc.asc_CImgProperty(),
-+                    chart = me._chartObject.get_ChartProperties();
-+
-+                chart.changeType(type);
-+                image.put_ChartProperties(chart);
-+
-+                me.api.ImgApply(image);
-+
-+                $('.chart-types li').removeClass('active');
-+                $target.addClass('active');
-+
-+                // Force update styles
-+                me._updateChartStyles(me.api.asc_getChartPreviews(chart.getType()));
-             },
- 
-             onStyle: function (e) {
-@@ -309,7 +327,7 @@ define([
-                     type = $target.data('type');
- 
-                 if (!me._chartObject) return;
--                
-+
-                 var image = new Asc.asc_CImgProperty(),
-                     chart = me._chartObject.get_ChartProperties();
- 
-@@ -549,9 +567,19 @@ define([
-                 _shapeObject = getTopObject(shapes);
-             },
- 
-+            onApiUpdateChartStyles: function () {
-+                if (this.api && this._chartObject && this._chartObject.get_ChartProperties()) {
-+                    this._updateChartStyles(this.api.asc_getChartPreviews(this._chartObject.get_ChartProperties().getType()));
-+                }
-+            },
-+
-             // Helpers
- 
-             _updateChartStyles: function(styles) {
-+                Common.SharedSettings.set('chartstyles', styles);
-+                Common.NotificationCenter.trigger('chartstyles:load', styles);
-+
-+                $('#tab-chart-style li').single('click', _.bind(this.onStyle, this));
-             },
- 
-             _uiTransformByWrap: function(type) {
-@@ -582,4 +610,4 @@ define([
-             }
-         };
-     })(), DE.Controllers.EditChart || {}))
--});
-\ No newline at end of file
-+});
-diff --git a/apps/documenteditor/mobile/app/controller/edit/EditParagraph.js b/apps/documenteditor/mobile/app/controller/edit/EditParagraph.js
-index 114601e6a..778d62bdd 100644
---- a/apps/documenteditor/mobile/app/controller/edit/EditParagraph.js
-+++ b/apps/documenteditor/mobile/app/controller/edit/EditParagraph.js
-@@ -75,6 +75,7 @@ define([
-                 });
- 
-                 this._styles = [];
-+                this._stack = [];
-                 this._styleThumbSize = undefined;
-                 this._paragraphObject = undefined;
-             },
-@@ -82,6 +83,12 @@ define([
-             setApi: function (api) {
-                 var me = this;
-                 me.api = api;
-+
-+                me.api.asc_setParagraphStylesSizes(330, 38);
-+
-+                me.api.asc_registerCallback('asc_onInitEditorStyles',   _.bind(me.onApiInitEditorStyles, me));
-+                me.api.asc_registerCallback('asc_onFocusObject',        _.bind(me.onApiFocusObject, me));
-+                me.api.asc_registerCallback('asc_onParaStyleName',      _.bind(me.onApiParagraphStyleChange, me));
-             },
- 
-             onLaunch: function () {
-@@ -128,7 +135,7 @@ define([
-                 if (selectedElements && _.isArray(selectedElements)) {
-                     for (var i = selectedElements.length - 1; i >= 0; i--) {
-                         if (Asc.c_oAscTypeSelectElement.Paragraph == selectedElements[i].get_ObjectType()) {
--                            _paragraphProperty = selectedElements[i].get_ObjectValue(); 
-+                            _paragraphProperty = selectedElements[i].get_ObjectValue();
-                             break;
-                         }
-                     }
-@@ -363,10 +370,53 @@ define([
- 
-             // API handlers
- 
-+            onApiFocusObject: function (objects) {
-+                this._stack = objects;
-+
-+                var paragraphs = [];
-+
-+                _.each(this._stack, function(object) {
-+                    if (object.get_ObjectType() == Asc.c_oAscTypeSelectElement.Paragraph) {
-+                        paragraphs.push(object);
-+                    }
-+                });
-+
-+                if (paragraphs.length > 0) {
-+                    var object = paragraphs[paragraphs.length - 1]; // get top
-+                    this._paragraphObject = object.get_ObjectValue();
-+                } else {
-+                    this._paragraphObject = undefined;
-+                }
-+            },
-+
-+            onApiInitEditorStyles: function (styles) {
-+                window.styles_loaded = false;
-+
-+                if (styles.length < 1) {
-+                    return;
-+                }
-+
-+                var me = this;
-+                this._styles = [];
-+                this._styleThumbSize = {
-+                    width   : styles.STYLE_THUMBNAIL_WIDTH,
-+                    height  : styles.STYLE_THUMBNAIL_HEIGHT
-+                };
-+
-+                _.each(styles.get_MergedStyles(), function(style) {
-+                    me._styles.push({
-+                        image   : style.asc_getImage(),
-+                        name    : style.get_Name()
-+                    });
-+                });
-+
-+                window.styles_loaded = true;
-+            },
-+
-             onApiParagraphStyleChange: function(name) {
-                 _styleName = name;
-                 $('#paragraph-list input[name=paragraph-style]').val([_styleName]);
-             }
-         }
-     })(), DE.Controllers.EditParagraph || {}))
--});
-\ No newline at end of file
-+});
-diff --git a/apps/documenteditor/mobile/app/controller/edit/EditShape.js b/apps/documenteditor/mobile/app/controller/edit/EditShape.js
-index 996c13543..76a4e68a1 100644
---- a/apps/documenteditor/mobile/app/controller/edit/EditShape.js
-+++ b/apps/documenteditor/mobile/app/controller/edit/EditShape.js
-@@ -302,9 +302,29 @@ define([
-             },
- 
-             onReorder: function (e) {
-+                var $target = $(e.currentTarget),
-+                    type = $target.data('type');
-+
-+                var properties = new Asc.asc_CImgProperty();
-+
-+                if ('all-up' == type) {
-+                    properties.put_ChangeLevel(Asc.c_oAscChangeLevel.BringToFront);
-+                } else if ('all-down' == type) {
-+                    properties.put_ChangeLevel(Asc.c_oAscChangeLevel.SendToBack);
-+                } else if ('move-up' == type) {
-+                    properties.put_ChangeLevel(Asc.c_oAscChangeLevel.BringForward);
-+                } else if ('move-down' == type) {
-+                    properties.put_ChangeLevel(Asc.c_oAscChangeLevel.BringBackward);
-+                }
-+
-+                this.api.ImgApply(properties);
-             },
- 
-             onReplace: function (e) {
-+                var $target = $(e.currentTarget),
-+                    type = $target.data('type');
-+
-+                this.api.ChangeShapeType(type);
-             },
- 
-             onWrapType: function (e) {
-diff --git a/apps/documenteditor/mobile/app/controller/edit/EditTable.js b/apps/documenteditor/mobile/app/controller/edit/EditTable.js
-index c94825acb..02cb7557d 100644
---- a/apps/documenteditor/mobile/app/controller/edit/EditTable.js
-+++ b/apps/documenteditor/mobile/app/controller/edit/EditTable.js
-@@ -123,6 +123,9 @@ define([
-             setApi: function (api) {
-                 var me = this;
-                 me.api = api;
-+
-+                me.api.asc_registerCallback('asc_onFocusObject',        _.bind(me.onApiFocusObject, me));
-+                me.api.asc_registerCallback('asc_onInitTableTemplates', _.bind(me.onApiInitTemplates, me));
-             },
- 
-             onLaunch: function () {
-@@ -131,6 +134,15 @@ define([
- 
-             initEvents: function () {
-                 var me = this;
-+
-+                $('#table-remove-all').single('click',                  _.bind(function(){me.api.remTable(); me._closeIfNeed()}, me));
-+                $('#insert-column-left').single('click',                _.bind(function(){me.api.addColumnLeft(); me._closeIfNeed()}, me));
-+                $('#insert-column-right').single('click',               _.bind(function(){me.api.addColumnRight(); me._closeIfNeed()}, me));
-+                $('#insert-row-above').single('click',                  _.bind(function(){me.api.addRowAbove(); me._closeIfNeed()}, me));
-+                $('#insert-row-below').single('click',                  _.bind(function(){me.api.addRowBelow(); me._closeIfNeed()}, me));
-+                $('#remove-column').single('click',                     _.bind(function(){me.api.remColumn(); me._closeIfNeed()}, me));
-+                $('#remove-row').single('click',                        _.bind(function(){me.api.remRow(); me._closeIfNeed()}, me));
-+
-                 me.initSettings();
-             },
- 
-@@ -638,6 +650,19 @@ define([
-                 }
-             },
- 
-+            onApiInitTemplates: function(templates) {
-+                var styles = [];
-+
-+                _.each(templates, function(template){
-+                    styles.push({
-+                        imageUrl    : template.asc_getImage(),
-+                        templateId  : template.asc_getId()
-+                    });
-+                });
-+
-+                this.getView('EditTable').updateStyles(styles);
-+            },
-+
-             // Helpers
- 
-             _closeIfNeed: function () {
-diff --git a/apps/documenteditor/mobile/app/controller/edit/EditText.js b/apps/documenteditor/mobile/app/controller/edit/EditText.js
-index 08f0ba0af..5126050f1 100644
---- a/apps/documenteditor/mobile/app/controller/edit/EditText.js
-+++ b/apps/documenteditor/mobile/app/controller/edit/EditText.js
-@@ -78,6 +78,21 @@ define([
-             setApi: function (api) {
-                 var me = this;
-                 me.api = api;
-+
-+                me.api.asc_registerCallback('asc_onInitEditorFonts',    _.bind(me.onApiLoadFonts, me));
-+                me.api.asc_registerCallback('asc_onFocusObject',        _.bind(me.onApiFocusObject, me));
-+                me.api.asc_registerCallback('asc_onFontFamily',         _.bind(me.onApiChangeFont, me));
-+                me.api.asc_registerCallback('asc_onFontSize',           _.bind(me.onApiFontSize, me));
-+                me.api.asc_registerCallback('asc_onBold',               _.bind(me.onApiBold, me));
-+                me.api.asc_registerCallback('asc_onItalic',             _.bind(me.onApiItalic, me));
-+                me.api.asc_registerCallback('asc_onUnderline',          _.bind(me.onApiUnderline, me));
-+                me.api.asc_registerCallback('asc_onStrikeout',          _.bind(me.onApiStrikeout, me));
-+                me.api.asc_registerCallback('asc_onVerticalAlign',      _.bind(me.onApiVerticalAlign, me));
-+                me.api.asc_registerCallback('asc_onListType',           _.bind(me.onApiBullets, me));
-+                me.api.asc_registerCallback('asc_onPrAlign',            _.bind(me.onApiParagraphAlign, me));
-+                me.api.asc_registerCallback('asc_onTextColor',          _.bind(me.onApiTextColor, me));
-+                me.api.asc_registerCallback('asc_onParaSpacingLine',    _.bind(me.onApiLineSpacing, me));
-+                me.api.asc_registerCallback('asc_onTextShd',            _.bind(me.onApiTextShd, me));
-             },
- 
-             onLaunch: function () {
-@@ -396,6 +411,23 @@ define([
- 
-             // API handlers
- 
-+            onApiLoadFonts: function (fonts, select) {
-+                var me = this;
-+
-+                _.each(fonts, function(font) {
-+                    var fontId = font.asc_getFontId();
-+                    me._fontsArray.push({
-+                        id          : fontId,
-+                        name        : font.asc_getFontName(),
-+    //                    displayValue: font.asc_getFontName(),
-+                        imgidx      : font.asc_getFontThumbnail(),
-+                        type        : font.asc_getFontType()
-+                    });
-+                });
-+
-+                Common.NotificationCenter.trigger('fonts:load', this._fontsArray, select);
-+            },
-+
-             onApiFocusObject: function (objects) {
-                 _stack = objects;
- 
-@@ -555,4 +587,4 @@ define([
-             textPt: 'pt'
-         }
-     })(), DE.Controllers.EditText || {}))
--});
-\ No newline at end of file
-+});
-diff --git a/apps/presentationeditor/mobile/app/controller/Main.js b/apps/presentationeditor/mobile/app/controller/Main.js
-index 012b4ce3d..c36e6396a 100644
---- a/apps/presentationeditor/mobile/app/controller/Main.js
-+++ b/apps/presentationeditor/mobile/app/controller/Main.js
-@@ -1190,6 +1190,7 @@ define([
-             },
- 
-             onSendThemeColors: function(colors, standart_colors) {
-+               Common.Utils.ThemeColor.setColors(colors, standart_colors);
-             },
- 
-             onFocusObject: function(SelectedObjects) {
-@@ -1350,7 +1351,7 @@ define([
-             },
- 
-             isSupportEditFeature: function() {
--                return false;
-+                return true;
-             },
- 
-             onRunAutostartMacroses: function() {
-@@ -1588,4 +1589,4 @@ define([
-             errorLang: 'The interface language is not loaded.<br>Please contact your Document Server administrator.'
-         }
-     })(), PE.Controllers.Main || {}))
--});
-\ No newline at end of file
-+});
-diff --git a/apps/presentationeditor/mobile/app/controller/add/AddImage.js b/apps/presentationeditor/mobile/app/controller/add/AddImage.js
-index d95a8859a..617152918 100644
---- a/apps/presentationeditor/mobile/app/controller/add/AddImage.js
-+++ b/apps/presentationeditor/mobile/app/controller/add/AddImage.js
-@@ -95,6 +95,10 @@ define([
- 
-             onInsertByFile: function (e) {
-                 PE.getController('AddContainer').hideModal();
-+
-+                if (this.api) {
-+                    this.api.asc_addImage();
-+                }
-             },
- 
-             onUrlChange: function (e) {
-@@ -111,6 +115,9 @@ define([
-                     if (!_.isEmpty(value)) {
-                         if ((/((^https?)|(^ftp)):\/\/.+/i.test(value))) {
-                             PE.getController('AddContainer').hideModal();
-+                            _.defer(function () {
-+                                me.api.AddImageUrl(value);
-+                            });
-                         } else {
-                             uiApp.alert(me.txtNotUrl, me.notcriticalErrorTitle);
-                         }
-diff --git a/apps/presentationeditor/mobile/app/controller/add/AddLink.js b/apps/presentationeditor/mobile/app/controller/add/AddLink.js
-index ee2a12938..624df79c0 100644
---- a/apps/presentationeditor/mobile/app/controller/add/AddLink.js
-+++ b/apps/presentationeditor/mobile/app/controller/add/AddLink.js
-@@ -169,6 +169,65 @@ define([
-             // Handlers
- 
-             onInsertLink: function (e) {
-+                var display = $('#add-link-display input').val(),
-+                    tip     = $('#add-link-tip input').val(),
-+                    props   = new Asc.CHyperlinkProperty(),
-+                    def_display = '';
-+
-+                if (this._linkType==c_oHyperlinkType.WebLink) {
-+                    var url = $('#add-link-url input').val(),
-+                        urltype = this.api.asc_getUrlType($.trim(url)),
-+                        isEmail = (urltype == 2);
-+                    if (urltype < 1) {
-+                        uiApp.alert(this.txtNotUrl);
-+                        return;
-+                    }
-+
-+                    url = url.replace(/^\s+|\s+$/g,'');
-+                    if (! /(((^https?)|(^ftp)):\/\/)|(^mailto:)/i.test(url) )
-+                        url = (isEmail ? 'mailto:' : 'http://' ) + url;
-+                    url = url.replace(new RegExp("%20",'g')," ");
-+
-+                    props.put_Value( url );
-+                    props.put_ToolTip(tip);
-+                    def_display = url;
-+                } else {
-+                    var url = "ppaction://hlink";
-+                    var slidetip = '';
-+                    switch (this._slideLink) {
-+                        case 0:
-+                            url = url + "showjump?jump=nextslide";
-+                            slidetip = this.textNext;
-+                            break;
-+                        case 1:
-+                            url = url + "showjump?jump=previousslide";
-+                            slidetip = this.textPrev;
-+                            break;
-+                        case 2:
-+                            url = url + "showjump?jump=firstslide";
-+                            slidetip = this.textFirst;
-+                            break;
-+                        case 3:
-+                            url = url + "showjump?jump=lastslide";
-+                            slidetip = this.textLast;
-+                            break;
-+                        case 4:
-+                            url = url + "sldjumpslide" + this._slideNum;
-+                            slidetip = this.textSlide + ' ' + (this._slideNum+1);
-+                            break;
-+                    }
-+                    props.put_Value( url );
-+                    props.put_ToolTip(_.isEmpty(tip) ? slidetip : tip);
-+                    def_display = slidetip;
-+                }
-+
-+                if (!$('#add-link-display').hasClass('disabled')) {
-+                    props.put_Text(_.isEmpty(display) ? def_display : display);
-+                } else
-+                    props.put_Text(null);
-+
-+                this.api.add_Hyperlink(props);
-+
-                 PE.getController('AddContainer').hideModal();
-             },
- 
-@@ -213,4 +272,4 @@ define([
-             notcriticalErrorTitle: 'Warning'
-         }
-     })(), PE.Controllers.AddLink || {}))
--});
-\ No newline at end of file
-+});
-diff --git a/apps/presentationeditor/mobile/app/controller/add/AddShape.js b/apps/presentationeditor/mobile/app/controller/add/AddShape.js
-index be2ef1ecf..12c4c9f17 100644
---- a/apps/presentationeditor/mobile/app/controller/add/AddShape.js
-+++ b/apps/presentationeditor/mobile/app/controller/add/AddShape.js
-@@ -212,6 +212,13 @@ define([
-             },
- 
-             onShapeClick: function (e) {
-+                var me = this,
-+                    $target = $(e.currentTarget);
-+
-+                if ($target && me.api) {
-+                    me.api.AddShapeOnCurrentPage($target.data('type'));
-+                }
-+
-                 PE.getController('AddContainer').hideModal();
-             },
- 
-diff --git a/apps/presentationeditor/mobile/app/controller/add/AddSlide.js b/apps/presentationeditor/mobile/app/controller/add/AddSlide.js
-index 4ffccc101..4e5148d90 100644
---- a/apps/presentationeditor/mobile/app/controller/add/AddSlide.js
-+++ b/apps/presentationeditor/mobile/app/controller/add/AddSlide.js
-@@ -63,6 +63,7 @@ define([
-             setApi: function (api) {
-                 var me = this;
-                 me.api = api;
-+                me.api.asc_registerCallback('asc_onUpdateLayout', _.bind(me.onUpdateLayout, me));
-             },
- 
-             onLaunch: function () {
-@@ -76,6 +77,12 @@ define([
-             },
- 
-             onLayoutClick: function (e) {
-+                var me = this,
-+                    $target = $(e.currentTarget),
-+                    type = $target.data('type');
-+
-+                me.api.AddSlide(type);
-+
-                 PE.getController('AddContainer').hideModal();
-             },
- 
-@@ -83,7 +90,32 @@ define([
- 
-             getLayouts: function () {
-                 return this._layouts;
-+            },
-+
-+            // API handlers
-+
-+            onUpdateLayout: function(layouts){
-+                var me = this;
-+                this._layouts = [];
-+                if (!_.isEmpty(layouts)){
-+                    _.each(layouts, function(layout) {
-+                        var name = layout.get_Name();
-+                        me._layouts.push({
-+                            imageUrl    : layout.get_Image(),
-+                            title       : (name !== '') ? name : PE.getController('Main').layoutNames[layout.getType()],
-+                            itemWidth   : layout.get_Width(),
-+                            itemHeight  : layout.get_Height(),
-+                            idx         : layout.getIndex()
-+                        });
-+                    });
-+                }
-+
-+                Common.SharedSettings.set('slidelayouts', this._layouts);
-+                Common.NotificationCenter.trigger('slidelayouts:load', this._layouts);
-+
-+                this.getView('AddSlide').updateLayouts(this._layouts);
-+                $('#add-slide .slide-layout li').single('click',  _.buffered(me.onLayoutClick, 100, me));
-             }
-         }
-     })(), PE.Controllers.AddSlide || {}))
--});
-\ No newline at end of file
-+});
-diff --git a/apps/presentationeditor/mobile/app/controller/add/AddTable.js b/apps/presentationeditor/mobile/app/controller/add/AddTable.js
-index 193e9ea59..7fa075c05 100644
---- a/apps/presentationeditor/mobile/app/controller/add/AddTable.js
-+++ b/apps/presentationeditor/mobile/app/controller/add/AddTable.js
-@@ -57,15 +57,27 @@ define([
-             initialize: function () {
-                 this._styles = [];
-                 this._initDefaultStyles = false;
-+
-+                //TODO is this needed? Common.NotificationCenter.on('addcontainer:show', _.bind(this.initEvents, this));
-             },
- 
-             setApi: function (api) {
-                 var me = this;
-                 me.api = api;
-+
-+                me.api.asc_registerCallback('asc_onInitTableTemplates', _.bind(me.onApiInitTemplates, me));
-             },
- 
-             initEvents: function () {
-                 var me = this;
-+
-+                if (!me._initDefaultStyles) {
-+                    me._initDefaultStyles = true;
-+                    me._styles = [];
-+
-+                    me.api.asc_GetDefaultTableStyles && me.api.asc_GetDefaultTableStyles();
-+                }
-+
-                 $('.page[data-page="addother-insert-table"] li').single('click',  _.buffered(me.onStyleClick, 100, me));
-             },
- 
-@@ -142,10 +154,27 @@ define([
- 
-             // API handlers
- 
-+            onApiInitTemplates: function(templates){
-+                var me = this;
-+                if (this._styles.length < 1) {
-+                    _.each(templates, function(template) {
-+                        me._styles.push({
-+                            imageUrl    : template.asc_getImage(),
-+                            templateId  : template.asc_getId()
-+                        });
-+                    });
-+
-+                    this.getView('AddTable').render();
-+                }
-+
-+                Common.SharedSettings.set('tablestyles', this._styles);
-+                Common.NotificationCenter.trigger('tablestyles:load', this._styles);
-+            },
-+
-             textTableSize: 'Table Size',
-             textColumns: 'Columns',
-             textRows: 'Rows',
-             textCancel: 'Cancel'
-         }
-     })(), PE.Controllers.AddTable || {}))
--});
-\ No newline at end of file
-+});
-diff --git a/apps/presentationeditor/mobile/app/controller/edit/EditChart.js b/apps/presentationeditor/mobile/app/controller/edit/EditChart.js
-index c80df4edc..0d5642e6c 100644
---- a/apps/presentationeditor/mobile/app/controller/edit/EditChart.js
-+++ b/apps/presentationeditor/mobile/app/controller/edit/EditChart.js
-@@ -106,6 +106,7 @@ define([
-                 me.api = api;
- 
-                 me.api.asc_registerCallback('asc_onFocusObject',        _.bind(me.onApiFocusObject, me));
-+                me.api.asc_registerCallback('asc_onUpdateChartStyles',  _.bind(me.onApiUpdateChartStyles, me));
-             },
- 
-             onLaunch: function () {
-@@ -233,6 +234,19 @@ define([
-             // Handlers
- 
-             onType: function (e) {
-+                var me = this,
-+                    $target = $(e.currentTarget),
-+                    type = $target.data('type');
-+
-+                var chart = new Asc.CAscChartProp();
-+                chart.changeType(type);
-+                me.api.ChartApply(chart);
-+
-+                $('.chart-types li').removeClass('active');
-+                $target.addClass('active');
-+
-+                // Force update styles
-+                me._updateChartStyles(me.api.asc_getChartPreviews(chart.getType()));
-             },
- 
-             onStyle: function (e) {
-@@ -395,9 +409,19 @@ define([
-                 _shapeObject = getTopObject(shapes);
-             },
- 
-+            onApiUpdateChartStyles: function () {
-+                if (this.api && this._chartObject) {
-+                    this._updateChartStyles(this.api.asc_getChartPreviews(this._chartObject.getType()));
-+                }
-+            },
-+
-             // Helpers
- 
-             _updateChartStyles: function(styles) {
-+                Common.SharedSettings.set('chartstyles', styles);
-+                Common.NotificationCenter.trigger('chartstyles:load', styles);
-+
-+                $('#tab-chart-style li').single('click', _.bind(this.onStyle, this));
-             },
- 
-             _closeIfNeed: function () {
-@@ -420,4 +444,4 @@ define([
-             }
-         };
-     })(), PE.Controllers.EditChart || {}))
--});
-\ No newline at end of file
-+});
-diff --git a/apps/presentationeditor/mobile/app/controller/edit/EditShape.js b/apps/presentationeditor/mobile/app/controller/edit/EditShape.js
-index aa22af261..1c23e264d 100644
---- a/apps/presentationeditor/mobile/app/controller/edit/EditShape.js
-+++ b/apps/presentationeditor/mobile/app/controller/edit/EditShape.js
-@@ -235,6 +235,18 @@ define([
-             },
- 
-             onReorder: function (e) {
-+                var $target = $(e.currentTarget),
-+                    type = $target.data('type');
-+
-+                if ('all-up' == type) {
-+                    this.api.shapes_bringToFront();
-+                } else if ('all-down' == type) {
-+                    this.api.shapes_bringToBack();
-+                } else if ('move-up' == type) {
-+                    this.api.shapes_bringForward();
-+                } else if ('move-down' == type) {
-+                    this.api.shapes_bringBackward();
-+                }
-             },
- 
-             onAlign: function (e) {
-@@ -261,6 +273,10 @@ define([
-             },
- 
-             onReplace: function (e) {
-+                var $target = $(e.currentTarget),
-+                    type = $target.data('type');
-+
-+                this.api.ChangeShapeType(type);
-             },
- 
-             onBorderSize: function (e) {
-diff --git a/apps/presentationeditor/mobile/app/controller/edit/EditSlide.js b/apps/presentationeditor/mobile/app/controller/edit/EditSlide.js
-index eaceadccd..0275e300d 100644
---- a/apps/presentationeditor/mobile/app/controller/edit/EditSlide.js
-+++ b/apps/presentationeditor/mobile/app/controller/edit/EditSlide.js
-@@ -89,6 +89,7 @@ define([
-                 me.api = api;
- 
-                 me.api.asc_registerCallback('asc_onFocusObject',        _.bind(me.onApiFocusObject, me));
-+                me.api.asc_registerCallback('asc_onInitEditorStyles',   _.bind(me.onApiInitEditorStyles, me));
-                 me.api.asc_registerCallback('asc_onUpdateThemeIndex',   _.bind(me.onApiUpdateThemeIndex, me));
-             },
- 
-@@ -217,9 +218,22 @@ define([
-             // Handlers
- 
-             onLayoutClick: function (e) {
-+                var me = this,
-+                    $target = $(e.currentTarget),
-+                    type = $target.data('type');
-+
-+                me.api.ChangeLayout(type);
-             },
- 
-             onThemeClick: function (e) {
-+                var me = this,
-+                    $target = $(e.currentTarget),
-+                    type = $target.data('type');
-+
-+                $('.container-edit .slide-theme div').removeClass('active');
-+                $target.addClass('active');
-+
-+                me.api.ChangeTheme(type);
-             },
- 
-             onRemoveSlide: function () {
-@@ -380,6 +394,35 @@ define([
-                 }
-             },
- 
-+            onApiInitEditorStyles: function(themes) {
-+                if (themes) {
-+                    window.styles_loaded = false;
-+
-+                    var me = this,
-+                        defaultThemes = themes[0] || [],
-+                        docThemes     = themes[1] || [];
-+
-+                    this._themes = [];
-+
-+                    _.each(defaultThemes, function(theme, index) {
-+                        me._themes.push({
-+                            themeId : theme.get_Index(),
-+                            offsety     : index * 38
-+                        });
-+                    });
-+
-+                    _.each(docThemes, function(theme) {
-+                        me._themes.push({
-+                            imageUrl: theme.get_Image(),
-+                            themeId : theme.get_Index(),
-+                            offsety     : 0
-+                        });
-+                    });
-+
-+                    window.styles_loaded = true;
-+                }
-+            },
-+
-             onApiUpdateThemeIndex: function(themeId) {
-                 _themeId = themeId;
-                 $('.container-edit .slide-theme .row div').removeClass('active');
-@@ -410,4 +453,4 @@ define([
-             textSec: 's'
-         };
-     })(), PE.Controllers.EditSlide || {}))
--});
-\ No newline at end of file
-+});
-diff --git a/apps/presentationeditor/mobile/app/controller/edit/EditTable.js b/apps/presentationeditor/mobile/app/controller/edit/EditTable.js
-index 280165d27..4e44175a5 100644
---- a/apps/presentationeditor/mobile/app/controller/edit/EditTable.js
-+++ b/apps/presentationeditor/mobile/app/controller/edit/EditTable.js
-@@ -112,6 +112,9 @@ define([
-             setApi: function (api) {
-                 var me = this;
-                 me.api = api;
-+
-+                me.api.asc_registerCallback('asc_onFocusObject',        _.bind(me.onApiFocusObject, me));
-+                me.api.asc_registerCallback('asc_onInitTableTemplates', _.bind(me.onApiInitTemplates, me));
-             },
- 
-             onLaunch: function () {
-@@ -121,6 +124,13 @@ define([
-             initEvents: function () {
-                 var me = this;
- 
-+                $('#table-remove-all').single('click',                  _.bind(function(){me.api.remTable(); me._closeIfNeed()}, me));
-+                $('#insert-column-left').single('click',                _.bind(function(){me.api.addColumnLeft(); me._closeIfNeed()}, me));
-+                $('#insert-column-right').single('click',               _.bind(function(){me.api.addColumnRight(); me._closeIfNeed()}, me));
-+                $('#insert-row-above').single('click',                  _.bind(function(){me.api.addRowAbove(); me._closeIfNeed()}, me));
-+                $('#insert-row-below').single('click',                  _.bind(function(){me.api.addRowBelow(); me._closeIfNeed()}, me));
-+                $('#remove-column').single('click',                     _.bind(function(){me.api.remColumn(); me._closeIfNeed()}, me));
-+                $('#remove-row').single('click',                        _.bind(function(){me.api.remRow(); me._closeIfNeed()}, me));
-                 $('#table-options-margins input').single('change touchend',      _.buffered(me.onOptionMargin, 100, me));
-                 $('#table-options-margins input').single('input',       _.bind(me.onOptionMarginChanging, me));
- 
-@@ -538,6 +548,19 @@ define([
-                 });
- 
-                 return tableExist;
-+            },
-+
-+            onApiInitTemplates: function(templates) {
-+                var styles = [];
-+
-+                _.each(templates, function(template){
-+                    styles.push({
-+                        imageUrl    : template.asc_getImage(),
-+                        templateId  : template.asc_getId()
-+                    });
-+                });
-+
-+                this.getView('EditTable').updateStyles(styles);
-             }
-         }
-     })(), PE.Controllers.EditTable || {}))
-diff --git a/apps/presentationeditor/mobile/app/controller/edit/EditText.js b/apps/presentationeditor/mobile/app/controller/edit/EditText.js
-index 116758067..e40fde1ac 100644
---- a/apps/presentationeditor/mobile/app/controller/edit/EditText.js
-+++ b/apps/presentationeditor/mobile/app/controller/edit/EditText.js
-@@ -80,6 +80,30 @@ define([
-             setApi: function (api) {
-                 var me = this;
-                 me.api = api;
-+
-+                me.api.asc_registerCallback('asc_onInitEditorFonts',    _.bind(me.onApiLoadFonts, me));
-+                me.api.asc_registerCallback('asc_onFocusObject',        _.bind(me.onApiFocusObject, me));
-+                me.api.asc_registerCallback('asc_onFontFamily',         _.bind(me.onApiChangeFont, me));
-+                me.api.asc_registerCallback('asc_onFontSize',           _.bind(me.onApiFontSize, me));
-+                me.api.asc_registerCallback('asc_onBold',               _.bind(me.onApiBold, me));
-+                me.api.asc_registerCallback('asc_onItalic',             _.bind(me.onApiItalic, me));
-+                me.api.asc_registerCallback('asc_onUnderline',          _.bind(me.onApiUnderline, me));
-+                me.api.asc_registerCallback('asc_onStrikeout',          _.bind(me.onApiStrikeout, me));
-+                me.api.asc_registerCallback('asc_onVerticalAlign',      _.bind(me.onApiVerticalAlign, me));
-+                me.api.asc_registerCallback('asc_onTextColor',          _.bind(me.onApiTextColor, me));
-+
-+                me.api.asc_registerCallback('asc_onListType',           _.bind(me.onApiBullets, me));
-+                me.api.asc_registerCallback('asc_onPrAlign',            _.bind(me.onApiParagraphAlign, me));
-+                me.api.asc_registerCallback('asc_canIncreaseIndent',      _.bind(me.onApiCanIncreaseIndent, me));
-+                me.api.asc_registerCallback('asc_canDecreaseIndent',      _.bind(me.onApiCanDecreaseIndent, me));
-+                me.api.asc_registerCallback('asc_onLineSpacing',          _.bind(me.onApiLineSpacing, me));
-+                me.api.asc_registerCallback('asc_onVerticalTextAlign',    _.bind(me.onApiVerticalTextAlign, me));
-+
-+                // me.api.asc_registerCallback('asc_onUpdateThemeIndex',     _.bind(this.onApiUpdateThemeIndex, this));
-+                // me.api.asc_registerCallback('asc_onCanGroup',             _.bind(this.onApiCanGroup, this));
-+                // me.api.asc_registerCallback('asc_onCanUnGroup',           _.bind(this.onApiCanUnGroup, this));
-+                // me.api.asc_registerCallback('asc_onPresentationSize',     _.bind(this.onApiPageSize, this));
-+                // me.api.asc_registerCallback('asc_onInitEditorStyles',     _.bind(this.onApiInitEditorStyles, this));
-             },
- 
-             onLaunch: function () {
-@@ -472,6 +496,22 @@ define([
- 
-             // API handlers
- 
-+            onApiLoadFonts: function (fonts, select) {
-+                var me = this;
-+                _.each(fonts, function(font) {
-+                    var fontId = font.asc_getFontId();
-+                    me._fontsArray.push({
-+                        id          : fontId,
-+                        name        : font.asc_getFontName(),
-+//                    displayValue: font.asc_getFontName(),
-+                        imgidx      : font.asc_getFontThumbnail(),
-+                        type        : font.asc_getFontType()
-+                    });
-+                });
-+
-+                Common.NotificationCenter.trigger('fonts:load', this._fontsArray, select);
-+            },
-+
-             onApiFocusObject: function (objects) {
-                 _stack = objects;
- 
-@@ -619,4 +659,4 @@ define([
-             textPt: 'pt'
-         }
-     })(), PE.Controllers.EditText || {}))
--});
-\ No newline at end of file
-+});
-diff --git a/apps/spreadsheeteditor/mobile/app/controller/Main.js b/apps/spreadsheeteditor/mobile/app/controller/Main.js
-index 71f96d868..883eca8cd 100644
---- a/apps/spreadsheeteditor/mobile/app/controller/Main.js
-+++ b/apps/spreadsheeteditor/mobile/app/controller/Main.js
-@@ -1332,6 +1332,7 @@ define([
-             },
- 
-             onSendThemeColors: function(colors, standart_colors) {
-+               Common.Utils.ThemeColor.setColors(colors, standart_colors);
-             },
- 
-             onAdvancedOptions: function(type, advOptions, mode, formatOptions) {
-@@ -1553,7 +1554,7 @@ define([
-             },
- 
-             isSupportEditFeature: function() {
--                return false;
-+                return true;
-             },
- 
-             onRunAutostartMacroses: function() {
-@@ -1810,4 +1811,4 @@ define([
-             errorLang: 'The interface language is not loaded.<br>Please contact your Document Server administrator.'
-         }
-     })(), SSE.Controllers.Main || {}))
--});
-\ No newline at end of file
-+});
-diff --git a/apps/spreadsheeteditor/mobile/app/controller/add/AddChart.js b/apps/spreadsheeteditor/mobile/app/controller/add/AddChart.js
-index bb91e2c39..58015d747 100644
---- a/apps/spreadsheeteditor/mobile/app/controller/add/AddChart.js
-+++ b/apps/spreadsheeteditor/mobile/app/controller/add/AddChart.js
-@@ -78,6 +78,10 @@ define([
- 
-             onInsertChart: function (type) {
-                 SSE.getController('AddContainer').hideModal();
-+
-+                var settings = this.api.asc_getChartObject();
-+                settings.changeType(type);
-+                this.api.asc_addChartDrawingObject(settings);
-             },
- 
-             txtDiagramTitle:    'Chart Title',
-diff --git a/apps/spreadsheeteditor/mobile/app/controller/add/AddFunction.js b/apps/spreadsheeteditor/mobile/app/controller/add/AddFunction.js
-index 2f8e89353..964438c17 100644
---- a/apps/spreadsheeteditor/mobile/app/controller/add/AddFunction.js
-+++ b/apps/spreadsheeteditor/mobile/app/controller/add/AddFunction.js
-@@ -112,17 +112,52 @@ define([
- 
-                 editorLang = (editorLang ? editorLang : 'en').split(/[\-\_]/)[0].toLowerCase();
- 
--                var localizationFunctionsDesc = function (data) {};
-+                var localizationFunctionsDesc = function (data) {
-+                    var jsonDesc = {},
-+                        view = me.getView('AddFunction');
-+
-+                    me.fd = data;
-+
-+                    try {
-+                        jsonDesc = JSON.parse(me.fd);
-+                    } catch (e) {
-+                        jsonDesc = me.fd
-+                    }
-+
-+                    var grouparr = me.api.asc_getFormulasInfo();
-+                    for (var g in grouparr) {
-+                        var group = grouparr[g];
-+                        var groupname = group.asc_getGroupName();
-+                        var funcarr = group.asc_getFormulasArray();
-+
-+                        for (var f in funcarr) {
-+                            var func = funcarr[f];
-+                            var _name = func.asc_getName();
-+                            functions[_name] = {
-+                                type:       _name,
-+                                group:      groupname,
-+                                caption:    func.asc_getLocaleName(),
-+                                args:       (jsonDesc && jsonDesc[_name]) ? jsonDesc[_name].a : '',
-+                                descr:      (jsonDesc && jsonDesc[_name]) ? jsonDesc[_name].d : ''
-+                            };
-+                        }
-+                    }
-+
-+                    view.setFunctions(functions, editorLang);
-+                    view.render();
-+                };
- 
-                 $.getJSON(Common.Utils.String.format("{0}/{1}_desc.json", "resources/l10n/functions", editorLang), function(json) {
-                     localizationFunctionsDesc(json);
-                 }).fail(function() {
--                    localizationFunctionsDesc(fd);
-+                    localizationFunctionsDesc(me.fd);
-                 });
-             },
- 
-             onInsertFunction: function (type) {
-                 SSE.getController('AddContainer').hideModal();
-+
-+                this.api.asc_insertFormula(this.api.asc_getFormulaLocaleName(type), Asc.c_oAscPopUpSelectorType.Func, true);
-             },
- 
-             onFunctionInfo: function (type) {
-@@ -130,4 +165,4 @@ define([
-             }
-         }
-     })(), SSE.Controllers.AddFunction || {}))
--});
-\ No newline at end of file
-+});
-diff --git a/apps/spreadsheeteditor/mobile/app/controller/add/AddLink.js b/apps/spreadsheeteditor/mobile/app/controller/add/AddLink.js
-index de4821e92..100de77e8 100644
---- a/apps/spreadsheeteditor/mobile/app/controller/add/AddLink.js
-+++ b/apps/spreadsheeteditor/mobile/app/controller/add/AddLink.js
-@@ -171,6 +171,51 @@ define([
-             },
- 
-             onInsertLink: function(args){
-+                var link = new Asc.asc_CHyperlink();
-+
-+                if ( args.type == 'ext' ) {
-+                    var url     = args.url,
-+                        urltype = this.api.asc_getUrlType($.trim(url)),
-+                        isEmail = (urltype == 2);
-+
-+                    if (urltype < 1) {
-+                        uiApp.alert(this.txtNotUrl);
-+                        return;
-+                    }
-+
-+                    url = url.replace(/^\s+|\s+$/g,'');
-+
-+                    if (! /(((^https?)|(^ftp)):\/\/)|(^mailto:)/i.test(url) )
-+                        url = (isEmail ? 'mailto:' : 'http://' ) + url;
-+
-+                    url = url.replace(new RegExp("%20",'g')," ");
-+
-+                    link.asc_setType(Asc.c_oAscHyperlinkType.WebLink);
-+                    link.asc_setHyperlinkUrl(url);
-+                    display = url;
-+                } else {
-+                    var isValid = /^[A-Z]+[1-9]\d*:[A-Z]+[1-9]\d*$/.test(args.url);
-+
-+                    if (!isValid)
-+                        isValid = /^[A-Z]+[1-9]\d*$/.test(args.url);
-+
-+                    if (!isValid) {
-+                        uiApp.alert(this.textInvalidRange);
-+                        return;
-+                    }
-+
-+                    link.asc_setType(Asc.c_oAscHyperlinkType.RangeLink);
-+                    link.asc_setSheet(args.sheet);
-+                    link.asc_setRange(args.url);
-+
-+                    var display = args.sheet + '!' + args.url;
-+                }
-+
-+                link.asc_setText(args.text == null ? null : !!args.text ? args.text : display);
-+                link.asc_setTooltip(args.tooltip);
-+
-+                this.api.asc_insertHyperlink(link);
-+
-                 SSE.getController('AddContainer').hideModal();
-             },
- 
-@@ -179,4 +224,4 @@ define([
-             notcriticalErrorTitle: 'Warning'
-         }
-     })(), SSE.Controllers.AddLink || {}))
--});
-\ No newline at end of file
-+});
-diff --git a/apps/spreadsheeteditor/mobile/app/controller/add/AddOther.js b/apps/spreadsheeteditor/mobile/app/controller/add/AddOther.js
-index dd1096405..776d18f92 100644
---- a/apps/spreadsheeteditor/mobile/app/controller/add/AddOther.js
-+++ b/apps/spreadsheeteditor/mobile/app/controller/add/AddOther.js
-@@ -174,6 +174,10 @@ define([
-                     if (!_.isEmpty(url)) {
-                         if ((/((^https?)|(^ftp)):\/\/.+/i.test(url))) {
-                             SSE.getController('AddContainer').hideModal();
-+
-+                            _.defer(function () {
-+                                me.api.asc_addImageDrawingObject(url);
-+                            });
-                         } else {
-                             uiApp.alert(me.txtNotUrl, me.notcriticalErrorTitle);
-                         }
-@@ -182,6 +186,7 @@ define([
-                     }
-                 } else {
-                     SSE.getController('AddContainer').hideModal();
-+                    this.api.asc_addImage();
-                 }
-             },
- 
-@@ -190,6 +195,11 @@ define([
-             },
- 
-             onInsertFilter: function(checked) {
-+                var formatTableInfo = this.api.asc_getCellInfo().asc_getFormatTableInfo();
-+                var tablename = (formatTableInfo) ? formatTableInfo.asc_getTableName() : undefined;
-+                if (checked)
-+                    this.api.asc_addAutoFilter(); else
-+                    this.api.asc_changeAutoFilter(tablename, Asc.c_oAscChangeFilterOptions.filter, checked);
-             },
- 
-             onError: function(id, level, errData) {
-diff --git a/apps/spreadsheeteditor/mobile/app/controller/add/AddShape.js b/apps/spreadsheeteditor/mobile/app/controller/add/AddShape.js
-index b7a1cbcf2..b3411de3b 100644
---- a/apps/spreadsheeteditor/mobile/app/controller/add/AddShape.js
-+++ b/apps/spreadsheeteditor/mobile/app/controller/add/AddShape.js
-@@ -211,6 +211,12 @@ define([
-             },
- 
-             onShapeClick: function (e) {
-+                var $target = $(e.currentTarget);
-+
-+                if ($target && this.api) {
-+                    this.api.asc_addShapeOnSheet($target.data('type'));
-+                }
-+
-                 SSE.getController('AddContainer').hideModal();
-             },
- 
-diff --git a/apps/spreadsheeteditor/mobile/app/controller/edit/EditCell.js b/apps/spreadsheeteditor/mobile/app/controller/edit/EditCell.js
-index ef9666471..d75035de8 100644
---- a/apps/spreadsheeteditor/mobile/app/controller/edit/EditCell.js
-+++ b/apps/spreadsheeteditor/mobile/app/controller/edit/EditCell.js
-@@ -85,8 +85,10 @@ define([
- 
-                 me.api.asc_setThumbnailStylesSizes(me._styleSize.width, me._styleSize.height);
- 
-+                me.api.asc_registerCallback('asc_onInitEditorFonts',            _.bind(me.onApiLoadFonts, me));
-                 me.api.asc_registerCallback('asc_onSelectionChanged',           _.bind(me.onApiSelectionChanged, me));
-                 me.api.asc_registerCallback('asc_onEditorSelectionChanged',     _.bind(me.onApiEditorSelectionChanged, me));
-+                me.api.asc_registerCallback('asc_onInitEditorStyles',           _.bind(me.onApiInitEditorStyles, me));
-             },
- 
-             setMode: function (mode) {
-@@ -349,6 +351,15 @@ define([
-                 me.initTextFormat();
-             },
- 
-+            onApiInitEditorStyles: function(styles){
-+                window.styles_loaded = false;
-+                this._cellStyles = styles;
-+
-+                this.getView('EditCell').renderStyles(styles);
-+
-+                window.styles_loaded = true;
-+            },
-+
-             // Handlers
- 
-             onFontSize: function (e) {
-@@ -448,6 +459,10 @@ define([
-             },
- 
-             onCellFormat: function (e) {
-+                var $target = $(e.currentTarget),
-+                    type = decodeURIComponent(atob($target.data('type')));
-+
-+                this.api.asc_setCellFormat(type);
-             },
- 
-             onBorderStyle: function (e) {
-@@ -483,10 +498,38 @@ define([
- 
-             // API handlers
- 
-+            onApiLoadFonts: function(fonts, select) {
-+                var me = this;
-+                _.each(fonts, function(font) {
-+                    var fontId = font.asc_getFontId();
-+                    me._fontsArray.push({
-+                        id          : fontId,
-+                        name        : font.asc_getFontName(),
-+//                    displayValue: font.asc_getFontName(),
-+                        imgidx      : font.asc_getFontThumbnail(),
-+                        type        : font.asc_getFontType()
-+                    });
-+                });
-+
-+                Common.NotificationCenter.trigger('fonts:load', this._fontsArray, select);
-+            },
-+
-             onApiEditorSelectionChanged: function(fontObj) {
-+                if (!this._isEdit) {
-+                    return;
-+                }
-+
-+                this._fontInfo = fontObj;
-+                this.initFontSettings(fontObj);
-             },
- 
-             onApiSelectionChanged: function(cellInfo) {
-+                if (!this._isEdit) {
-+                    return;
-+                }
-+
-+                this._cellInfo = cellInfo;
-+                this.initCellSettings(cellInfo);
-             },
- 
-             // Helpers
-@@ -559,4 +602,4 @@ define([
-             textPt: 'pt'
-         }
-     })(), SSE.Controllers.EditCell || {}))
--});
-\ No newline at end of file
-+});
-diff --git a/apps/spreadsheeteditor/mobile/app/controller/edit/EditChart.js b/apps/spreadsheeteditor/mobile/app/controller/edit/EditChart.js
-index 0bacfd0e2..5fa56e946 100644
---- a/apps/spreadsheeteditor/mobile/app/controller/edit/EditChart.js
-+++ b/apps/spreadsheeteditor/mobile/app/controller/edit/EditChart.js
-@@ -107,7 +107,13 @@ define([
-                 var me = this;
-                 me.api = api;
- 
-+                me.api.asc_registerCallback('asc_onSelectionChanged',   _.bind(me.onApiSelectionChanged, me));
-                 me.api.asc_registerCallback('asc_onFocusObject',        _.bind(me.onApiFocusObject, me));
-+
-+                me.api.asc_registerCallback('asc_onUpdateChartStyles',  _.bind(me.onApiUpdateChartStyles, me));
-+                // me.api.asc_registerCallback('asc_onSelectionChanged',           _.bind(me.onApiSelectionChanged, me));
-+                // me.api.asc_registerCallback('asc_onEditorSelectionChanged',     _.bind(me.onApiEditorSelectionChanged, me));
-+                // me.api.asc_registerCallback('asc_onInitEditorStyles',           _.bind(me.onApiInitEditorStyles, me)); // TODO: It does not work until the error in the SDK
-             },
- 
-             setMode: function (mode) {
-@@ -166,7 +172,7 @@ define([
-             },
- 
-             getChart: function () {
--                return _chartObject;
-+                return this._chartObject;
-             },
- 
-             initRootPage: function () {
-@@ -564,9 +570,41 @@ define([
-             },
- 
-             onType: function (e) {
-+                var me = this,
-+                    $target = $(e.currentTarget),
-+                    type = $target.data('type');
-+
-+                $('.chart-types li').removeClass('active');
-+                $target.addClass('active');
-+
-+                _.defer(function() {
-+                    var image = new Asc.asc_CImgProperty(),
-+                        chart = me._chartObject.get_ChartProperties();
-+
-+                    chart.changeType(type);
-+                    image.put_ChartProperties(chart);
-+
-+                    me.api.asc_setGraphicObjectProps(image);
-+
-+                    // Force update styles
-+                    me._updateChartStyles(me.api.asc_getChartPreviews(chart.getType()));
-+
-+                    me.updateAxisProps(type);
-+                });
-             },
- 
-             onStyle: function (e) {
-+                var me = this,
-+                    $target = $(e.currentTarget),
-+                    type = $target.data('type');
-+
-+                var image = new Asc.asc_CImgProperty(),
-+                    chart = this._chartObject.get_ChartProperties();
-+
-+                chart.putStyle(type);
-+                image.put_ChartProperties(chart);
-+
-+                me.api.asc_setGraphicObjectProps(image);
-             },
- 
-             onFillColor:function (palette, color) {
-@@ -906,6 +944,28 @@ define([
- 
-             // API handlers
- 
-+            onApiUpdateChartStyles: function () {
-+                if (this.api && this._chartObject && this._chartObject.get_ChartProperties()) {
-+                    this._updateChartStyles(this.api.asc_getChartPreviews(this._chartObject.get_ChartProperties().getType()));
-+                }
-+            },
-+
-+            onApiSelectionChanged: function(info) {
-+                if (!this._isEdit) {
-+                    return;
-+                }
-+
-+                var me = this,
-+                    selectedObjects = [],
-+                    selectType = info.asc_getSelectionType();
-+
-+                if (selectType == Asc.c_oAscSelectionType.RangeChart) {
-+                    selectedObjects = me.api.asc_getGraphicObjectProps();
-+                }
-+
-+                me.onApiFocusObject(selectedObjects);
-+            },
-+
-             onApiFocusObject: function (objects) {
-                 _stack = objects;
- 
-@@ -1057,4 +1117,4 @@ define([
-             textFit: 'Fit Width'
-         }
-     })(), SSE.Controllers.EditChart || {}))
--});
-\ No newline at end of file
-+});
-diff --git a/apps/spreadsheeteditor/mobile/app/controller/edit/EditShape.js b/apps/spreadsheeteditor/mobile/app/controller/edit/EditShape.js
-index 83e225529..5f701a46d 100644
---- a/apps/spreadsheeteditor/mobile/app/controller/edit/EditShape.js
-+++ b/apps/spreadsheeteditor/mobile/app/controller/edit/EditShape.js
-@@ -242,9 +242,28 @@ define([
-             },
- 
-             onReorder: function(e) {
-+                var $target = $(e.currentTarget),
-+                    type = $target.data('type'),
-+                    ascType;
-+
-+                if (type == 'all-up') {
-+                    ascType = Asc.c_oAscDrawingLayerType.BringToFront;
-+                } else if (type == 'all-down') {
-+                    ascType = Asc.c_oAscDrawingLayerType.SendToBack;
-+                } else if (type == 'move-up') {
-+                    ascType = Asc.c_oAscDrawingLayerType.BringForward;
-+                } else {
-+                    ascType = Asc.c_oAscDrawingLayerType.SendBackward;
-+                }
-+
-+                this.api.asc_setSelectedDrawingObjectLayer(ascType);
-             },
- 
-             onReplace: function (e) {
-+                var $target = $(e.currentTarget),
-+                    type = $target.data('type');
-+
-+                this.api.asc_changeShapeType(type);
-             },
- 
-             onBorderSize: function (e) {
+diff --git a/apps/documenteditor/mobile/src/lib/patch.jsx b/apps/documenteditor/mobile/src/lib/patch.jsx
+index 963aca451..1ee48e856 100644
+--- a/apps/documenteditor/mobile/src/lib/patch.jsx
++++ b/apps/documenteditor/mobile/src/lib/patch.jsx
+@@ -4,7 +4,7 @@ const EditorUIController = () => {
+ };
+ 
+ EditorUIController.isSupportEditFeature = () => {
+-    return false
++    return true
+ };
+ 
+ EditorUIController.getToolbarOptions = () => {
+diff --git a/apps/presentationeditor/mobile/src/lib/patch.jsx b/apps/presentationeditor/mobile/src/lib/patch.jsx
+index ec7b37a2c..bfd879583 100644
+--- a/apps/presentationeditor/mobile/src/lib/patch.jsx
++++ b/apps/presentationeditor/mobile/src/lib/patch.jsx
+@@ -1,6 +1,6 @@
+ 
+ const EditorUIController = () => null;
+ 
+-EditorUIController.isSupportEditFeature = () => false;
++EditorUIController.isSupportEditFeature = () => true;
+ 
+ export default EditorUIController;
+diff --git a/apps/spreadsheeteditor/mobile/src/lib/patch.jsx b/apps/spreadsheeteditor/mobile/src/lib/patch.jsx
+index ec7b37a2c..bfd879583 100644
+--- a/apps/spreadsheeteditor/mobile/src/lib/patch.jsx
++++ b/apps/spreadsheeteditor/mobile/src/lib/patch.jsx
+@@ -1,6 +1,6 @@
+ 
+ const EditorUIController = () => null;
+ 
+-EditorUIController.isSupportEditFeature = () => false;
++EditorUIController.isSupportEditFeature = () => true;
+ 
+ export default EditorUIController;
 -- 
-2.32.0.rc2
+2.31.1.windows.1
+

From 08a94a6678e27fcc3d4c050b8f6c8fbec68a7e1f Mon Sep 17 00:00:00 2001
From: Beeant <huangxb0512@gmail.com>
Date: Sat, 24 Sep 2022 21:47:37 +0800
Subject: [PATCH 03/10] Update server.patch

---
 server.patch | 1 -
 1 file changed, 1 deletion(-)

diff --git a/server.patch b/server.patch
index 0727519..b70f41b 100644
--- a/server.patch
+++ b/server.patch
@@ -68,7 +68,6 @@ index cf3ba90..d256724 100644
  if (!tenantManager.isMultitenantMode()) {
  	updateLicense();
 -	fs.watchFile(cfgLicenseFile, updateLicense);
-+	
  	setInterval(updateLicense, 86400000);
  }
  

From 112a54bc541369ec5f934fef6d893131e4771260 Mon Sep 17 00:00:00 2001
From: xbeeant <huangxb0512@gmail.com>
Date: Sun, 30 Oct 2022 16:48:24 +0800
Subject: [PATCH 04/10] patch

# Conflicts:
#	Dockerfile
#	server.patch
---
 Dockerfile         |  31 ++--
 Makefile           | 188 +++++++++++++++++++++++
 constants.js       | 304 +++++++++++++++++++++++++++++++++++++
 convertermaster.js | 109 ++++++++++++++
 license.js         |  68 +++++++++
 server.js          | 362 +++++++++++++++++++++++++++++++++++++++++++++
 server.patch       | 101 -------------
 7 files changed, 1049 insertions(+), 114 deletions(-)
 create mode 100644 Makefile
 create mode 100644 constants.js
 create mode 100644 convertermaster.js
 create mode 100644 license.js
 create mode 100644 server.js
 delete mode 100644 server.patch

diff --git a/Dockerfile b/Dockerfile
index 8759404..7991cf8 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -1,5 +1,5 @@
-ARG product_version=7.2.0
-ARG build_number=204
+ARG product_version=7.2.1
+ARG build_number=34
 ARG oo_root='/var/www/onlyoffice/documentserver'
 
 ## Setup
@@ -26,19 +26,24 @@ ARG tag=v${PRODUCT_VERSION}.${BUILD_NUMBER}
 RUN git clone --quiet --branch $tag --depth 1 https://github.com/ONLYOFFICE/build_tools.git /build/build_tools
 RUN git clone --quiet --branch $tag --depth 1 https://github.com/ONLYOFFICE/server.git      /build/server
 
-COPY server.patch /build/server.patch
-RUN cd /build/server   && git apply /build/server.patch
-
-# Clone old version of sdk and webapp to get an old version of the mobile editor
-
-ARG tag=v6.3.1.79 # Working mobile editor
-RUN git clone --quiet --branch $tag --depth 1 https://github.com/ONLYOFFICE/sdkjs.git       /build/sdkjs
-RUN git clone --quiet --branch $tag --depth 1 https://github.com/ONLYOFFICE/web-apps.git    /build/web-apps
-COPY web-apps.patch /build/
-RUN cd /build/web-apps && git apply /build/web-apps.patch
+# Working mobile editor
+RUN git clone --quiet --depth 1 https://github.com/ONLYOFFICE/sdkjs.git       /build/sdkjs
+RUN git clone --quiet --depth 1 https://github.com/ONLYOFFICE/web-apps.git    /build/web-apps
 
 ## Build
-FROM clone-stage as build-stage
+FROM clone-stage as path-stage
+
+# patch
+COPY web-apps.patch /build/web-apps.patch
+RUN cd /build/web-apps   && git apply /build/web-apps.patch
+COPY convertermaster.js /build/server/FileConverter/sources/convertermaster.js
+COPY license.js /build/server/Common/sources/license.js
+COPY Makefile /build/server/Makefile
+COPY server.js /build/server/DocService/sources/server.js
+COPY constants.js /build/server/Common/srouces/constants.js
+
+## Build
+FROM path-stage as build-stage
 
 # build server with license checks patched
 WORKDIR /build/server
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..23f7e2e
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,188 @@
+GRUNT = grunt
+GRUNT_FLAGS = --no-color -v
+
+GRUNT_FILES = Gruntfile.js.out
+
+PRODUCT_VERSION ?= 0.0.0
+BUILD_NUMBER ?= 0
+
+PUBLISHER_NAME ?= Ascensio System SIA
+PUBLISHER_URL ?= https://www.onlyoffice.com/
+
+GRUNT_ENV += PRODUCT_VERSION=$(PRODUCT_VERSION)
+GRUNT_ENV += BUILD_NUMBER=$(BUILD_NUMBER)
+GRUNT_ENV += PUBLISHER_NAME="$(PUBLISHER_NAME)"
+GRUNT_ENV += PUBLISHER_URL="$(PUBLISHER_URL)"
+
+BRANDING_DIR ?= ./branding
+
+DOCUMENT_ROOT ?= /var/www/onlyoffice/documentserver
+
+ifeq ($(OS),Windows_NT)
+    PLATFORM := win
+    EXEC_EXT := .exe
+    SHARED_EXT := .dll
+    ifeq ($(PROCESSOR_ARCHITECTURE),AMD64)
+        ARCHITECTURE := 64
+    endif
+    ifeq ($(PROCESSOR_ARCHITECTURE),x86)
+        ARCHITECTURE := 32
+    endif
+else
+    UNAME_S := $(shell uname -s)
+    ifeq ($(UNAME_S),Linux)
+        PLATFORM := linux
+        SHARED_EXT := .so*
+        LIB_PREFIX := lib
+    endif
+    UNAME_M := $(shell uname -m)
+    ifeq ($(UNAME_M),x86_64)
+        ARCHITECTURE := 64
+    endif
+    ifneq ($(filter %86,$(UNAME_M)),)
+        ARCHITECTURE := 32
+    endif
+endif
+
+TARGET := $(PLATFORM)_$(ARCHITECTURE)
+
+OUTPUT = ../build_tools/out/$(TARGET)/onlyoffice/documentserver/server
+
+SPELLCHECKER_DICTIONARIES := $(OUTPUT)/../dictionaries
+SPELLCHECKER_DICTIONARY_FILES += ../dictionaries/*_*
+
+SCHEMA_DIR = schema
+SCHEMA_FILES = $(SCHEMA_DIR)/**
+SCHEMA = $(OUTPUT)/$(SCHEMA_DIR)/
+
+TOOLS_DIR = tools
+TOOLS_FILES += ../core/build/bin/$(TARGET)/allfontsgen$(EXEC_EXT)
+TOOLS_FILES += ../core/build/bin/$(TARGET)/allthemesgen$(EXEC_EXT)
+TOOLS = $(OUTPUT)/$(TOOLS_DIR)
+
+LICENSE_FILES = LICENSE.txt 3rd-Party.txt license/
+LICENSE = $(addsuffix $(OUTPUT)/, LICENSE_FILES)
+
+LICENSE_JS := $(OUTPUT)/Common/sources/license.js
+COMMON_DEFINES_JS := $(OUTPUT)/Common/sources/commondefines.js
+
+WELCOME_DIR = welcome
+WELCOME_FILES = $(BRANDING_DIR)/$(WELCOME_DIR)/**
+WELCOME = $(OUTPUT)/$(WELCOME_DIR)/
+
+INFO_DIR = info
+INFO_FILES = $(BRANDING_DIR)/$(INFO_DIR)/**
+INFO = $(OUTPUT)/$(INFO_DIR)/
+
+CORE_FONTS_DIR = core-fonts
+CORE_FONTS_FILES = ../$(CORE_FONTS_DIR)/**
+CORE_FONTS = $(OUTPUT)/../$(CORE_FONTS_DIR)/
+
+DOCUMENT_TEMPLATES_DIR = document-templates
+DOCUMENT_TEMPLATES_FILES = ../$(DOCUMENT_TEMPLATES_DIR)/**
+DOCUMENT_TEMPLATES = $(OUTPUT)/../$(DOCUMENT_TEMPLATES_DIR)/
+
+DEBUG = $(BRANDING_DIR)/debug.js
+
+.PHONY: all clean install uninstall build-date
+
+.NOTPARALLEL:
+all: $(SCHEMA) $(LICENSE) $(WELCOME) $(INFO) build-date
+
+build-date: $(GRUNT_FILES)
+	sed "s|\(const buildVersion = \).*|\1'${PRODUCT_VERSION}';|" -i $(COMMON_DEFINES_JS)
+	sed "s|\(const buildNumber = \).*|\1${BUILD_NUMBER};|" -i $(COMMON_DEFINES_JS)
+	sed "s|\(const buildDate = \).*|\1'$$(date +%F)';|" -i $(LICENSE_JS)
+	test -e $(DEBUG) && \
+	cp $(DEBUG) $(OUTPUT)/Common/sources || true
+
+$(SPELLCHECKER_DICTIONARIES): $(GRUNT_FILES)
+	mkdir -p $(SPELLCHECKER_DICTIONARIES) && \
+		cp -r -t $(SPELLCHECKER_DICTIONARIES) $(SPELLCHECKER_DICTIONARY_FILES)
+
+$(SCHEMA):
+	mkdir -p $(SCHEMA) && \
+		cp -r -t $(SCHEMA) $(SCHEMA_FILES)
+
+$(TOOLS):
+	mkdir -p $(TOOLS) && \
+		cp -r -t $(TOOLS) $(TOOLS_FILES)
+
+$(LICENSE):
+	mkdir -p $(OUTPUT) && \
+		cp -r -t $(OUTPUT) $(LICENSE_FILES)
+
+$(GRUNT_FILES):
+	cd $(@D) && \
+		npm install && \
+		$(GRUNT_ENV) $(GRUNT) $(GRUNT_FLAGS)
+		mkdir -p $(OUTPUT)
+		cp -r -t $(OUTPUT) ./build/server/*
+	echo "Done" > $@
+
+$(WELCOME):
+	mkdir -p $(WELCOME) && \
+		cp -r -t $(WELCOME) $(WELCOME_FILES)
+
+$(INFO):
+	mkdir -p $(INFO) && \
+		cp -r -t $(INFO) $(INFO_FILES)
+
+$(CORE_FONTS):
+	mkdir -p $(CORE_FONTS) && \
+		cp -r -t $(CORE_FONTS) $(CORE_FONTS_FILES)
+
+$(DOCUMENT_TEMPLATES):
+	mkdir -p $(DOCUMENT_TEMPLATES) && \
+		cp -r -t $(DOCUMENT_TEMPLATES) $(DOCUMENT_TEMPLATES_FILES)
+
+clean:
+	rm -rf $(GRUNT_FILES)
+
+install:
+	mkdir -pv ${DESTDIR}/var/www/onlyoffice
+	if ! id -u onlyoffice > /dev/null 2>&1; then useradd -m -d /var/www/onlyoffice -r -U onlyoffice; fi
+
+	mkdir -p ${DESTDIR}${DOCUMENT_ROOT}/fonts
+	mkdir -p ${DESTDIR}/var/log/onlyoffice/documentserver
+	mkdir -p ${DESTDIR}/var/lib/onlyoffice/documentserver/App_Data
+
+	cp -fr -t ${DESTDIR}${DOCUMENT_ROOT} build/* ../web-apps/deploy/*
+	mkdir -p ${DESTDIR}/etc/onlyoffice/documentserver
+	mv ${DESTDIR}${DOCUMENT_ROOT}/server/Common/config/* ${DESTDIR}/etc/onlyoffice/documentserver
+
+	chown onlyoffice:onlyoffice -R ${DESTDIR}/var/www/onlyoffice
+	chown onlyoffice:onlyoffice -R ${DESTDIR}/var/log/onlyoffice
+	chown onlyoffice:onlyoffice -R ${DESTDIR}/var/lib/onlyoffice
+
+	# Make symlinks for shared libs
+	find \
+		${DESTDIR}${DOCUMENT_ROOT}/server/FileConverter/bin \
+		-maxdepth 1 \
+		-name *$(SHARED_EXT) \
+		-exec sh -c 'ln -sf {} ${DESTDIR}/lib/$$(basename {})' \;
+
+	sudo -u onlyoffice "${DESTDIR}${DOCUMENT_ROOT}/server/tools/allfontsgen"\
+		--input="${DESTDIR}${DOCUMENT_ROOT}/core-fonts"\
+		--allfonts-web="${DESTDIR}${DOCUMENT_ROOT}/sdkjs/common/AllFonts.js"\
+		--allfonts="${DESTDIR}${DOCUMENT_ROOT}/server/FileConverter/bin/AllFonts.js"\
+		--images="${DESTDIR}${DOCUMENT_ROOT}/sdkjs/common/Images"\
+		--selection="${DESTDIR}${DOCUMENT_ROOT}/server/FileConverter/bin/font_selection.bin"\
+		--output-web="${DESTDIR}${DOCUMENT_ROOT}/fonts"\
+		--use-system="true"
+
+	sudo -u onlyoffice "${DESTDIR}${DOCUMENT_ROOT}/server/tools/allthemesgen"\
+		--converter-dir="${DESTDIR}${DOCUMENT_ROOT}/server/FileConverter/bin"\
+		--src="${DESTDIR}${DOCUMENT_ROOT}/sdkjs/slide/themes"\
+		--output="${DESTDIR}${DOCUMENT_ROOT}/sdkjs/common/Images"
+
+uninstall:
+	userdel onlyoffice
+
+	# Unlink installed shared libs
+	find /lib -type l | while IFS= read -r lnk; do if (readlink "$$lnk" | grep -q '^${DOCUMENT_ROOT}/server/FileConverter/bin/'); then rm "$$lnk"; fi; done
+
+	rm -rf /var/www/onlyoffice/documentserver
+	rm -rf /var/log/onlyoffice/documentserver
+	rm -rf /var/lib/onlyoffice/documentserver
+	rm -rf /etc/onlyoffice/documentserver
diff --git a/constants.js b/constants.js
new file mode 100644
index 0000000..3116fbb
--- /dev/null
+++ b/constants.js
@@ -0,0 +1,304 @@
+/*
+ * (c) Copyright Ascensio System SIA 2010-2019
+ *
+ * This program is a free software product. You can redistribute it and/or
+ * modify it under the terms of the GNU Affero General Public License (AGPL)
+ * version 3 as published by the Free Software Foundation. In accordance with
+ * Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect
+ * that Ascensio System SIA expressly excludes the warranty of non-infringement
+ * of any third-party rights.
+ *
+ * This program is distributed WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR  PURPOSE. For
+ * details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
+ *
+ * You can contact Ascensio System SIA at 20A-12 Ernesta Birznieka-Upisha
+ * street, Riga, Latvia, EU, LV-1050.
+ *
+ * The  interactive user interfaces in modified source and object code versions
+ * of the Program must display Appropriate Legal Notices, as required under
+ * Section 5 of the GNU AGPL version 3.
+ *
+ * Pursuant to Section 7(b) of the License you must retain the original Product
+ * logo when distributing the program. Pursuant to Section 7(e) we decline to
+ * grant you any rights under trademark law for use of our trademarks.
+ *
+ * All the Product's GUI elements, including illustrations and icon sets, as
+ * well as technical writing content are licensed under the terms of the
+ * Creative Commons Attribution-ShareAlike 4.0 International. See the License
+ * terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
+ *
+ */
+
+'use strict';
+
+exports.DOC_ID_PATTERN = '0-9-.a-zA-Z_=';
+exports.DOC_ID_REGEX = new RegExp("^[" + exports.DOC_ID_PATTERN + "]*$", 'i');
+exports.DOC_ID_REPLACE_REGEX = new RegExp("[^" + exports.DOC_ID_PATTERN + "]", 'g');
+exports.DOC_ID_SOCKET_PATTERN = new RegExp("^/doc/([" + exports.DOC_ID_PATTERN + "]*)/c.+", 'i');
+exports.DOC_ID_MAX_LENGTH = 240;
+exports.USER_ID_MAX_LENGTH = 240;//255-240=15 symbols to make user id unique
+exports.USER_NAME_MAX_LENGTH = 255;
+exports.PASSWORD_MAX_LENGTH = 255;//set password limit for DoS protection with long password
+exports.EXTENTION_REGEX = /^[a-zA-Z0-9]*$/;
+exports.CHAR_DELIMITER = String.fromCharCode(5);
+exports.OUTPUT_NAME = 'output';
+exports.ONLY_OFFICE_URL_PARAM = 'ooname';
+exports.DISPLAY_PREFIX = 'display';
+exports.CHANGES_NAME = 'changes';
+exports.VIEWER_ONLY = /^(?:(pdf|djvu|xps|oxps))$/;
+exports.DEFAULT_DOC_ID = 'docId';
+exports.DEFAULT_USER_ID = 'userId';
+
+exports.RIGHTS = {
+  None    : 0,
+  Edit    : 1,
+  Review  : 2,
+  Comment : 3,
+  View    : 4
+};
+
+exports.LICENSE_MODE = {
+  None: 0,
+  Trial: 1,
+  Developer: 2,
+  Limited: 4
+};
+
+exports.LICENSE_RESULT = {
+  Error         : 1,
+  Expired       : 2,
+  Success       : 3,
+  UnknownUser   : 4,
+  Connections   : 5,
+  ExpiredTrial  : 6,
+  SuccessLimit  : 7,
+  UsersCount    : 8,
+  ConnectionsOS : 9,
+  UsersCountOS  : 10,
+  ExpiredLimited: 11,
+  ConnectionsLiveOS: 12,
+  ConnectionsLive: 13,
+  UsersViewCount: 14,
+  UsersViewCountOS: 15
+};
+
+exports.LICENSE_CONNECTIONS = 99999;
+exports.LICENSE_EXPIRE_USERS_ONE_DAY = 24 * 60 * 60; // day in seconds
+
+exports.AVS_OFFICESTUDIO_FILE_UNKNOWN =  0x0000;
+exports.AVS_OFFICESTUDIO_FILE_DOCUMENT = 0x0040;
+exports.AVS_OFFICESTUDIO_FILE_DOCUMENT_DOCX = exports.AVS_OFFICESTUDIO_FILE_DOCUMENT + 0x0001;
+exports.AVS_OFFICESTUDIO_FILE_DOCUMENT_DOC = exports.AVS_OFFICESTUDIO_FILE_DOCUMENT + 0x0002;
+exports.AVS_OFFICESTUDIO_FILE_DOCUMENT_ODT = exports.AVS_OFFICESTUDIO_FILE_DOCUMENT + 0x0003;
+exports.AVS_OFFICESTUDIO_FILE_DOCUMENT_RTF = exports.AVS_OFFICESTUDIO_FILE_DOCUMENT + 0x0004;
+exports.AVS_OFFICESTUDIO_FILE_DOCUMENT_TXT = exports.AVS_OFFICESTUDIO_FILE_DOCUMENT + 0x0005;
+exports.AVS_OFFICESTUDIO_FILE_DOCUMENT_HTML = exports.AVS_OFFICESTUDIO_FILE_DOCUMENT + 0x0006;
+exports.AVS_OFFICESTUDIO_FILE_DOCUMENT_MHT = exports.AVS_OFFICESTUDIO_FILE_DOCUMENT + 0x0007;
+exports.AVS_OFFICESTUDIO_FILE_DOCUMENT_EPUB = exports.AVS_OFFICESTUDIO_FILE_DOCUMENT + 0x0008;
+exports.AVS_OFFICESTUDIO_FILE_DOCUMENT_FB2 = exports.AVS_OFFICESTUDIO_FILE_DOCUMENT + 0x0009;
+exports.AVS_OFFICESTUDIO_FILE_DOCUMENT_MOBI = exports.AVS_OFFICESTUDIO_FILE_DOCUMENT + 0x000a;
+exports.AVS_OFFICESTUDIO_FILE_DOCUMENT_DOCM = exports.AVS_OFFICESTUDIO_FILE_DOCUMENT + 0x000b;
+exports.AVS_OFFICESTUDIO_FILE_DOCUMENT_DOTX = exports.AVS_OFFICESTUDIO_FILE_DOCUMENT + 0x000c;
+exports.AVS_OFFICESTUDIO_FILE_DOCUMENT_DOTM = exports.AVS_OFFICESTUDIO_FILE_DOCUMENT + 0x000d;
+exports.AVS_OFFICESTUDIO_FILE_DOCUMENT_ODT_FLAT = exports.AVS_OFFICESTUDIO_FILE_DOCUMENT + 0x000e;
+exports.AVS_OFFICESTUDIO_FILE_DOCUMENT_OTT = exports.AVS_OFFICESTUDIO_FILE_DOCUMENT + 0x000f;
+exports.AVS_OFFICESTUDIO_FILE_DOCUMENT_DOC_FLAT = exports.AVS_OFFICESTUDIO_FILE_DOCUMENT + 0x0010;
+exports.AVS_OFFICESTUDIO_FILE_DOCUMENT_DOCX_FLAT = exports.AVS_OFFICESTUDIO_FILE_DOCUMENT + 0x0011;
+exports.AVS_OFFICESTUDIO_FILE_DOCUMENT_HTML_IN_CONTAINER = exports.AVS_OFFICESTUDIO_FILE_DOCUMENT + 0x0012;
+exports.AVS_OFFICESTUDIO_FILE_DOCUMENT_DOCX_PACKAGE = exports.AVS_OFFICESTUDIO_FILE_DOCUMENT + 0x0014;
+exports.AVS_OFFICESTUDIO_FILE_DOCUMENT_OFORM = exports.AVS_OFFICESTUDIO_FILE_DOCUMENT + 0x0015;
+exports.AVS_OFFICESTUDIO_FILE_DOCUMENT_DOCXF = exports.AVS_OFFICESTUDIO_FILE_DOCUMENT + 0x0016;
+
+exports.AVS_OFFICESTUDIO_FILE_PRESENTATION = 0x0080;
+exports.AVS_OFFICESTUDIO_FILE_PRESENTATION_PPTX = exports.AVS_OFFICESTUDIO_FILE_PRESENTATION + 0x0001;
+exports.AVS_OFFICESTUDIO_FILE_PRESENTATION_PPT = exports.AVS_OFFICESTUDIO_FILE_PRESENTATION + 0x0002;
+exports.AVS_OFFICESTUDIO_FILE_PRESENTATION_ODP = exports.AVS_OFFICESTUDIO_FILE_PRESENTATION + 0x0003;
+exports.AVS_OFFICESTUDIO_FILE_PRESENTATION_PPSX = exports.AVS_OFFICESTUDIO_FILE_PRESENTATION + 0x0004;
+exports.AVS_OFFICESTUDIO_FILE_PRESENTATION_PPTM = exports.AVS_OFFICESTUDIO_FILE_PRESENTATION + 0x0005;
+exports.AVS_OFFICESTUDIO_FILE_PRESENTATION_PPSM = exports.AVS_OFFICESTUDIO_FILE_PRESENTATION + 0x0006;
+exports.AVS_OFFICESTUDIO_FILE_PRESENTATION_POTX = exports.AVS_OFFICESTUDIO_FILE_PRESENTATION + 0x0007;
+exports.AVS_OFFICESTUDIO_FILE_PRESENTATION_POTM = exports.AVS_OFFICESTUDIO_FILE_PRESENTATION + 0x0008;
+exports.AVS_OFFICESTUDIO_FILE_PRESENTATION_ODP_FLAT = exports.AVS_OFFICESTUDIO_FILE_PRESENTATION + 0x0009;
+exports.AVS_OFFICESTUDIO_FILE_PRESENTATION_OTP = exports.AVS_OFFICESTUDIO_FILE_PRESENTATION + 0x000a;
+exports.AVS_OFFICESTUDIO_FILE_PRESENTATION_PPTX_PACKAGE = exports.AVS_OFFICESTUDIO_FILE_PRESENTATION + 0x000b;
+
+exports.AVS_OFFICESTUDIO_FILE_SPREADSHEET = 0x0100;
+exports.AVS_OFFICESTUDIO_FILE_SPREADSHEET_XLSX = exports.AVS_OFFICESTUDIO_FILE_SPREADSHEET + 0x0001;
+exports.AVS_OFFICESTUDIO_FILE_SPREADSHEET_XLS = exports.AVS_OFFICESTUDIO_FILE_SPREADSHEET + 0x0002;
+exports.AVS_OFFICESTUDIO_FILE_SPREADSHEET_ODS = exports.AVS_OFFICESTUDIO_FILE_SPREADSHEET + 0x0003;
+exports.AVS_OFFICESTUDIO_FILE_SPREADSHEET_CSV = exports.AVS_OFFICESTUDIO_FILE_SPREADSHEET + 0x0004;
+exports.AVS_OFFICESTUDIO_FILE_SPREADSHEET_XLSM = exports.AVS_OFFICESTUDIO_FILE_SPREADSHEET + 0x0005;
+exports.AVS_OFFICESTUDIO_FILE_SPREADSHEET_XLTX = exports.AVS_OFFICESTUDIO_FILE_SPREADSHEET + 0x0006;
+exports.AVS_OFFICESTUDIO_FILE_SPREADSHEET_XLTM = exports.AVS_OFFICESTUDIO_FILE_SPREADSHEET + 0x0007;
+exports.AVS_OFFICESTUDIO_FILE_SPREADSHEET_XLSB = exports.AVS_OFFICESTUDIO_FILE_SPREADSHEET + 0x0008;
+exports.AVS_OFFICESTUDIO_FILE_SPREADSHEET_ODS_FLAT = exports.AVS_OFFICESTUDIO_FILE_SPREADSHEET + 0x0009;
+exports.AVS_OFFICESTUDIO_FILE_SPREADSHEET_OTS = exports.AVS_OFFICESTUDIO_FILE_SPREADSHEET + 0x000a;
+exports.AVS_OFFICESTUDIO_FILE_SPREADSHEET_XLSX_FLAT = exports.AVS_OFFICESTUDIO_FILE_SPREADSHEET + 0x000b;
+exports.AVS_OFFICESTUDIO_FILE_SPREADSHEET_XLSX_PACKAGE = exports.AVS_OFFICESTUDIO_FILE_SPREADSHEET + 0x000c;
+
+exports.AVS_OFFICESTUDIO_FILE_CROSSPLATFORM = 0x0200;
+exports.AVS_OFFICESTUDIO_FILE_CROSSPLATFORM_PDF = exports.AVS_OFFICESTUDIO_FILE_CROSSPLATFORM + 0x0001;
+exports.AVS_OFFICESTUDIO_FILE_CROSSPLATFORM_SWF = exports.AVS_OFFICESTUDIO_FILE_CROSSPLATFORM + 0x0002;
+exports.AVS_OFFICESTUDIO_FILE_CROSSPLATFORM_DJVU = exports.AVS_OFFICESTUDIO_FILE_CROSSPLATFORM + 0x0003;
+exports.AVS_OFFICESTUDIO_FILE_CROSSPLATFORM_XPS = exports.AVS_OFFICESTUDIO_FILE_CROSSPLATFORM + 0x0004;
+exports.AVS_OFFICESTUDIO_FILE_CROSSPLATFORM_SVG = exports.AVS_OFFICESTUDIO_FILE_CROSSPLATFORM + 0x0005;
+exports.AVS_OFFICESTUDIO_FILE_CROSSPLATFORM_HTMLR = exports.AVS_OFFICESTUDIO_FILE_CROSSPLATFORM + 0x0006;
+exports.AVS_OFFICESTUDIO_FILE_CROSSPLATFORM_HTMLR_MENU = exports.AVS_OFFICESTUDIO_FILE_CROSSPLATFORM + 0x0007;
+exports.AVS_OFFICESTUDIO_FILE_CROSSPLATFORM_HTMLR_CANVAS = exports.AVS_OFFICESTUDIO_FILE_CROSSPLATFORM + 0x0008;
+exports.AVS_OFFICESTUDIO_FILE_CROSSPLATFORM_PDFA = exports.AVS_OFFICESTUDIO_FILE_CROSSPLATFORM + 0x0009;
+exports.AVS_OFFICESTUDIO_FILE_IMAGE = 0x0400;
+exports.AVS_OFFICESTUDIO_FILE_IMAGE_JPG = exports.AVS_OFFICESTUDIO_FILE_IMAGE + 0x0001;
+exports.AVS_OFFICESTUDIO_FILE_IMAGE_TIFF = exports.AVS_OFFICESTUDIO_FILE_IMAGE + 0x0002;
+exports.AVS_OFFICESTUDIO_FILE_IMAGE_TGA = exports.AVS_OFFICESTUDIO_FILE_IMAGE + 0x0003;
+exports.AVS_OFFICESTUDIO_FILE_IMAGE_GIF = exports.AVS_OFFICESTUDIO_FILE_IMAGE + 0x0004;
+exports.AVS_OFFICESTUDIO_FILE_IMAGE_PNG = exports.AVS_OFFICESTUDIO_FILE_IMAGE + 0x0005;
+exports.AVS_OFFICESTUDIO_FILE_IMAGE_EMF = exports.AVS_OFFICESTUDIO_FILE_IMAGE + 0x0006;
+exports.AVS_OFFICESTUDIO_FILE_IMAGE_WMF = exports.AVS_OFFICESTUDIO_FILE_IMAGE + 0x0007;
+exports.AVS_OFFICESTUDIO_FILE_IMAGE_BMP = exports.AVS_OFFICESTUDIO_FILE_IMAGE + 0x0008;
+exports.AVS_OFFICESTUDIO_FILE_IMAGE_CR2 = exports.AVS_OFFICESTUDIO_FILE_IMAGE + 0x0009;
+exports.AVS_OFFICESTUDIO_FILE_IMAGE_PCX = exports.AVS_OFFICESTUDIO_FILE_IMAGE + 0x000a;
+exports.AVS_OFFICESTUDIO_FILE_IMAGE_RAS = exports.AVS_OFFICESTUDIO_FILE_IMAGE + 0x000b;
+exports.AVS_OFFICESTUDIO_FILE_IMAGE_PSD = exports.AVS_OFFICESTUDIO_FILE_IMAGE + 0x000c;
+exports.AVS_OFFICESTUDIO_FILE_IMAGE_ICO = exports.AVS_OFFICESTUDIO_FILE_IMAGE + 0x000d;
+exports.AVS_OFFICESTUDIO_FILE_OTHER = 0x0800;
+exports.AVS_OFFICESTUDIO_FILE_OTHER_EXTRACT_IMAGE = exports.AVS_OFFICESTUDIO_FILE_OTHER + 0x0001;
+exports.AVS_OFFICESTUDIO_FILE_OTHER_MS_OFFCRYPTO = exports.AVS_OFFICESTUDIO_FILE_OTHER + 0x0002;
+exports.AVS_OFFICESTUDIO_FILE_OTHER_HTMLZIP = exports.AVS_OFFICESTUDIO_FILE_OTHER + 0x0003;
+exports.AVS_OFFICESTUDIO_FILE_OTHER_OLD_DOCUMENT = exports.AVS_OFFICESTUDIO_FILE_OTHER + 0x0004;
+exports.AVS_OFFICESTUDIO_FILE_OTHER_OLD_PRESENTATION = exports.AVS_OFFICESTUDIO_FILE_OTHER + 0x0005;
+exports.AVS_OFFICESTUDIO_FILE_OTHER_OLD_DRAWING = exports.AVS_OFFICESTUDIO_FILE_OTHER + 0x0006;
+exports.AVS_OFFICESTUDIO_FILE_OTHER_OOXML = exports.AVS_OFFICESTUDIO_FILE_OTHER + 0x0007;
+exports.AVS_OFFICESTUDIO_FILE_OTHER_JSON = exports.AVS_OFFICESTUDIO_FILE_OTHER + 0x0008; // Для mail-merge
+exports.AVS_OFFICESTUDIO_FILE_OTHER_ODF = exports.AVS_OFFICESTUDIO_FILE_OTHER + 0x000a;
+exports.AVS_OFFICESTUDIO_FILE_OTHER_MS_MITCRYPTO = exports.AVS_OFFICESTUDIO_FILE_OTHER + 0x000b;
+
+exports.AVS_OFFICESTUDIO_FILE_TEAMLAB = 0x1000;
+exports.AVS_OFFICESTUDIO_FILE_TEAMLAB_DOCY = exports.AVS_OFFICESTUDIO_FILE_TEAMLAB + 0x0001;
+exports.AVS_OFFICESTUDIO_FILE_TEAMLAB_XLSY = exports.AVS_OFFICESTUDIO_FILE_TEAMLAB + 0x0002;
+exports.AVS_OFFICESTUDIO_FILE_TEAMLAB_PPTY = exports.AVS_OFFICESTUDIO_FILE_TEAMLAB + 0x0003;
+exports.AVS_OFFICESTUDIO_FILE_CANVAS = 0x2000;
+exports.AVS_OFFICESTUDIO_FILE_CANVAS_WORD = exports.AVS_OFFICESTUDIO_FILE_CANVAS + 0x0001;
+exports.AVS_OFFICESTUDIO_FILE_CANVAS_SPREADSHEET = exports.AVS_OFFICESTUDIO_FILE_CANVAS + 0x0002;
+exports.AVS_OFFICESTUDIO_FILE_CANVAS_PRESENTATION = exports.AVS_OFFICESTUDIO_FILE_CANVAS + 0x0003;
+
+exports.NO_ERROR = 0;
+exports.UNKNOWN = -1;
+exports.READ_REQUEST_STREAM = -3;
+exports.WEB_REQUEST = -4;
+exports.CHANGE_DOC_INFO = -5;
+exports.TASK_QUEUE = -20;
+exports.TASK_RESULT = -40;
+exports.STORAGE = -60;
+exports.STORAGE_FILE_NO_FOUND = -61;
+exports.STORAGE_READ = -62;
+exports.STORAGE_WRITE = -63;
+exports.STORAGE_REMOVE_DIR = -64;
+exports.STORAGE_CREATE_DIR = -65;
+exports.STORAGE_GET_INFO = -66;
+exports.CONVERT = -80;
+exports.CONVERT_DOWNLOAD = -81;
+exports.CONVERT_UNKNOWN_FORMAT = -82;
+exports.CONVERT_TIMEOUT = -83;
+exports.CONVERT_READ_FILE = -84;
+exports.CONVERT_DRM_UNSUPPORTED = -85;
+exports.CONVERT_CORRUPTED = -86;
+exports.CONVERT_LIBREOFFICE = -87;
+exports.CONVERT_PARAMS = -88;
+exports.CONVERT_NEED_PARAMS = -89;
+exports.CONVERT_DRM = -90;
+exports.CONVERT_PASSWORD = -91;
+exports.CONVERT_ICU = -92;
+exports.CONVERT_LIMITS = -93;
+exports.CONVERT_DEAD_LETTER = -99;
+exports.UPLOAD = -100;
+exports.UPLOAD_CONTENT_LENGTH = -101;
+exports.UPLOAD_EXTENSION = -102;
+exports.UPLOAD_COUNT_FILES = -103;
+exports.UPLOAD_URL = -104;
+exports.VKEY = -120;
+exports.VKEY_ENCRYPT = -121;
+exports.VKEY_KEY_EXPIRE = -122;
+exports.VKEY_USER_COUNT_EXCEED = -123;
+exports.VKEY_TIME_EXPIRE = -124;
+exports.VKEY_TIME_INCORRECT = -125;
+exports.EDITOR_CHANGES = -160;
+exports.PASSWORD = -180;
+
+exports.QUEUE_PRIORITY_VERY_LOW = 0;
+exports.QUEUE_PRIORITY_LOW = 1;
+exports.QUEUE_PRIORITY_NORMAL = 2;
+exports.QUEUE_PRIORITY_HIGH = 3;
+exports.QUEUE_PRIORITY_VERY_HIGH = 4;
+
+exports.EDITOR_TYPE_WORD = 0;
+exports.EDITOR_TYPE_SPREADSHEET = 1;
+exports.EDITOR_TYPE_PRESENTATION = 2;
+exports.EDITOR_TYPE_CONVERTATION = 3;
+
+exports.PACKAGE_TYPE_OS = 0;
+exports.PACKAGE_TYPE_I = 1;
+exports.PACKAGE_TYPE_D = 2;
+
+exports.REDIS_KEY_PUBSUB = 'pubsub';
+exports.REDIS_KEY_SAVE_LOCK = 'savelock:';
+exports.REDIS_KEY_PRESENCE_HASH = 'presence:hash:';
+exports.REDIS_KEY_PRESENCE_SET = 'presence:set:';
+exports.REDIS_KEY_PRESENCE_UNIQUE_USERS = 'presence:unique:users';
+exports.REDIS_KEY_PRESENCE_UNIQUE_USERS_HASH = 'presence:unique:users:hash';
+exports.REDIS_KEY_PRESENCE_MONTH_UNIQUE_USERS_HASH = 'presence:unique:users:month';
+exports.REDIS_KEY_PRESENCE_UNIQUE_USERS_VIEW = 'presence:unique:usersview';
+exports.REDIS_KEY_PRESENCE_UNIQUE_USERS_VIEW_HASH = 'presence:unique:usersview:hash';
+exports.REDIS_KEY_PRESENCE_MONTH_UNIQUE_USERS_VIEW_HASH = 'presence:unique:usersview:month';
+exports.REDIS_KEY_LOCKS = 'locks:';
+exports.REDIS_KEY_LOCK_DOCUMENT = 'lockdocument:';
+exports.REDIS_KEY_MESSAGE = 'message:';
+exports.REDIS_KEY_DOCUMENTS = 'documents';
+exports.REDIS_KEY_LAST_SAVE = 'lastsave:';
+exports.REDIS_KEY_FORCE_SAVE = 'forcesave:';
+exports.REDIS_KEY_FORCE_SAVE_TIMER = 'forcesavetimer';
+exports.REDIS_KEY_FORCE_SAVE_TIMER_LOCK = 'forcesavetimerlock:';
+exports.REDIS_KEY_SAVED = 'saved:';
+exports.REDIS_KEY_SHUTDOWN = 'shutdown';
+exports.REDIS_KEY_COLLECT_LOST = 'collectlost';
+exports.REDIS_KEY_LICENSE = 'license';
+exports.REDIS_KEY_LICENSE_T = 'licenseT';
+exports.REDIS_KEY_EDITOR_CONNECTIONS = 'editorconnections';
+exports.REDIS_KEY_SHARD_CONNECTIONS_EDIT_ZSET = 'shardconnections:edit:zset';
+exports.REDIS_KEY_SHARD_CONNECTIONS_EDIT_HASH = 'shardconnections:edit:hash';
+exports.REDIS_KEY_SHARD_CONNECTIONS_LIVE_VIEW_ZSET = 'shardconnections:liveview:zset';
+exports.REDIS_KEY_SHARD_CONNECTIONS_LIVE_VIEW_HASH = 'shardconnections:liveview:hash';
+exports.REDIS_KEY_SHARD_CONNECTIONS_VIEW_ZSET = 'shardconnections:view:zset';
+exports.REDIS_KEY_SHARD_CONNECTIONS_VIEW_HASH = 'shardconnections:view:hash';
+
+exports.SHUTDOWN_CODE = 4001;
+exports.SHUTDOWN_REASON = 'server shutdown';
+exports.SESSION_IDLE_CODE = 4002;
+exports.SESSION_IDLE_REASON = 'idle session expires';
+exports.SESSION_ABSOLUTE_CODE = 4003;
+exports.SESSION_ABSOLUTE_REASON = 'absolute session expires';
+exports.ACCESS_DENIED_CODE = 4004;
+exports.ACCESS_DENIED_REASON = 'access deny';
+exports.JWT_EXPIRED_CODE = 4005;
+exports.JWT_EXPIRED_REASON = 'token:';
+exports.JWT_ERROR_CODE = 4006;
+exports.JWT_ERROR_REASON = 'token:';
+exports.DROP_CODE = 4007;
+exports.DROP_REASON = 'drop';
+exports.UPDATE_VERSION_CODE = 4008;
+exports.UPDATE_VERSION = 'update version';
+exports.NO_CACHE_CODE = 4009;
+exports.NO_CACHE = 'no cache';
+exports.RESTORE_CODE = 4010;
+exports.RESTORE = 'no cache';
+
+exports.CONTENT_DISPOSITION_INLINE = 'inline';
+exports.CONTENT_DISPOSITION_ATTACHMENT = 'attachment';
+
+exports.CONN_CLOSED = 3;
+
+exports.FILE_STATUS_OK = 'ok';
+exports.FILE_STATUS_UPDATE_VERSION = 'updateversion';
+
+exports.ACTIVEMQ_QUEUE_PREFIX = 'queue://';
+exports.ACTIVEMQ_TOPIC_PREFIX = 'topic://';
diff --git a/convertermaster.js b/convertermaster.js
new file mode 100644
index 0000000..757905e
--- /dev/null
+++ b/convertermaster.js
@@ -0,0 +1,109 @@
+/*
+ * (c) Copyright Ascensio System SIA 2010-2019
+ *
+ * This program is a free software product. You can redistribute it and/or
+ * modify it under the terms of the GNU Affero General Public License (AGPL)
+ * version 3 as published by the Free Software Foundation. In accordance with
+ * Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect
+ * that Ascensio System SIA expressly excludes the warranty of non-infringement
+ * of any third-party rights.
+ *
+ * This program is distributed WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR  PURPOSE. For
+ * details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
+ *
+ * You can contact Ascensio System SIA at 20A-12 Ernesta Birznieka-Upisha
+ * street, Riga, Latvia, EU, LV-1050.
+ *
+ * The  interactive user interfaces in modified source and object code versions
+ * of the Program must display Appropriate Legal Notices, as required under
+ * Section 5 of the GNU AGPL version 3.
+ *
+ * Pursuant to Section 7(b) of the License you must retain the original Product
+ * logo when distributing the program. Pursuant to Section 7(e) we decline to
+ * grant you any rights under trademark law for use of our trademarks.
+ *
+ * All the Product's GUI elements, including illustrations and icon sets, as
+ * well as technical writing content are licensed under the terms of the
+ * Creative Commons Attribution-ShareAlike 4.0 International. See the License
+ * terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
+ *
+ */
+
+'use strict';
+
+const cluster = require('cluster');
+const logger = require('./../../Common/sources/logger');
+const operationContext = require('./../../Common/sources/operationContext');
+
+if (cluster.isMaster) {
+  const fs = require('fs');
+  const co = require('co');
+  const numCPUs = require('os').cpus().length;
+  const configCommon = require('config');
+  const config = configCommon.get('FileConverter.converter');
+  const license = require('./../../Common/sources/license');
+  const tenantManager = require('./../../Common/sources/tenantManager');
+
+  const cfgLicenseFile = configCommon.get('license.license_file');
+
+  const cfgMaxProcessCount = config.get('maxprocesscount');
+  var workersCount = 0;
+  const readLicense = function* () {
+    workersCount = Math.ceil(numCPUs * cfgMaxProcessCount);
+    if (!tenantManager.isMultitenantMode()) {
+      let [licenseInfo] = yield* license.readLicense(cfgLicenseFile);
+      workersCount = Math.min(licenseInfo.count, workersCount);
+    }
+  };
+  const updateWorkers = () => {
+    var i;
+    const arrKeyWorkers = Object.keys(cluster.workers);
+    if (arrKeyWorkers.length < workersCount) {
+      for (i = arrKeyWorkers.length; i < workersCount; ++i) {
+        const newWorker = cluster.fork();
+        operationContext.global.logger.warn('worker %s started.', newWorker.process.pid);
+      }
+    } else {
+      for (i = workersCount; i < arrKeyWorkers.length; ++i) {
+        const killWorker = cluster.workers[arrKeyWorkers[i]];
+        if (killWorker) {
+          killWorker.kill();
+        }
+      }
+    }
+  };
+  const updateLicense = () => {
+    return co(function*() {
+      try {
+        yield* readLicense();
+        operationContext.global.logger.warn('update cluster with %s workers', workersCount);
+        updateWorkers();
+      } catch (err) {
+        operationContext.global.logger.error('updateLicense error: %s', err.stack);
+      }
+    });
+  };
+
+  cluster.on('exit', (worker, code, signal) => {
+    operationContext.global.logger.warn('worker %s died (code = %s; signal = %s).', worker.process.pid, code, signal);
+    updateWorkers();
+  });
+
+  updateLicense();
+
+  if (!tenantManager.isMultitenantMode()) {
+    setInterval(updateLicense, 86400000);
+  }
+} else {
+  const converter = require('./converter');
+  converter.run();
+}
+
+process.on('uncaughtException', (err) => {
+  operationContext.global.logger.error((new Date).toUTCString() + ' uncaughtException:', err.message);
+  operationContext.global.logger.error(err.stack);
+  logger.shutdown(() => {
+    process.exit(1);
+  });
+});
diff --git a/license.js b/license.js
new file mode 100644
index 0000000..cce68fd
--- /dev/null
+++ b/license.js
@@ -0,0 +1,68 @@
+/*
+ * (c) Copyright Ascensio System SIA 2010-2019
+ *
+ * This program is a free software product. You can redistribute it and/or
+ * modify it under the terms of the GNU Affero General Public License (AGPL)
+ * version 3 as published by the Free Software Foundation. In accordance with
+ * Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect
+ * that Ascensio System SIA expressly excludes the warranty of non-infringement
+ * of any third-party rights.
+ *
+ * This program is distributed WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR  PURPOSE. For
+ * details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
+ *
+ * You can contact Ascensio System SIA at 20A-12 Ernesta Birznieka-Upisha
+ * street, Riga, Latvia, EU, LV-1050.
+ *
+ * The  interactive user interfaces in modified source and object code versions
+ * of the Program must display Appropriate Legal Notices, as required under
+ * Section 5 of the GNU AGPL version 3.
+ *
+ * Pursuant to Section 7(b) of the License you must retain the original Product
+ * logo when distributing the program. Pursuant to Section 7(e) we decline to
+ * grant you any rights under trademark law for use of our trademarks.
+ *
+ * All the Product's GUI elements, including illustrations and icon sets, as
+ * well as technical writing content are licensed under the terms of the
+ * Creative Commons Attribution-ShareAlike 4.0 International. See the License
+ * terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
+ *
+ */
+
+'use strict';
+
+const constants = require('./constants');
+
+const buildDate = '6/29/2016';
+const oBuildDate = new Date(buildDate);
+
+exports.readLicense = function*() {
+	const c_LR = constants.LICENSE_RESULT;
+	var now = new Date();
+	var startDate = new Date(Date.UTC(now.getUTCFullYear(), now.getUTCMonth(), 1));//first day of current month
+	return [{
+		count: 1,
+		type: c_LR.Success,
+		light: true,
+		packageType: constants.PACKAGE_TYPE_I,
+		mode: constants.LICENSE_MODE.None,
+		branding: true,
+		connections: constants.LICENSE_CONNECTIONS,
+		connectionsView: constants.LICENSE_CONNECTIONS,
+		customization: true,
+		advancedApi: true,
+		usersCount: constants.LICENSE_CONNECTIONS,
+		usersViewCount: constants.LICENSE_CONNECTIONS,
+		usersExpire: constants.LICENSE_EXPIRE_USERS_ONE_DAY,
+		hasLicense: true,
+		plugins: true,
+		buildDate: oBuildDate,
+		startDate: startDate,
+		endDate: new Date("2099-01-01T23:59:59.000Z"),
+		customerId: "",
+		alias: "community"
+	}, null];
+};
+
+exports.packageType = constants.PACKAGE_TYPE_I;
diff --git a/server.js b/server.js
new file mode 100644
index 0000000..edfb423
--- /dev/null
+++ b/server.js
@@ -0,0 +1,362 @@
+/*
+ * (c) Copyright Ascensio System SIA 2010-2019
+ *
+ * This program is a free software product. You can redistribute it and/or
+ * modify it under the terms of the GNU Affero General Public License (AGPL)
+ * version 3 as published by the Free Software Foundation. In accordance with
+ * Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect
+ * that Ascensio System SIA expressly excludes the warranty of non-infringement
+ * of any third-party rights.
+ *
+ * This program is distributed WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR  PURPOSE. For
+ * details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
+ *
+ * You can contact Ascensio System SIA at 20A-12 Ernesta Birznieka-Upisha
+ * street, Riga, Latvia, EU, LV-1050.
+ *
+ * The  interactive user interfaces in modified source and object code versions
+ * of the Program must display Appropriate Legal Notices, as required under
+ * Section 5 of the GNU AGPL version 3.
+ *
+ * Pursuant to Section 7(b) of the License you must retain the original Product
+ * logo when distributing the program. Pursuant to Section 7(e) we decline to
+ * grant you any rights under trademark law for use of our trademarks.
+ *
+ * All the Product's GUI elements, including illustrations and icon sets, as
+ * well as technical writing content are licensed under the terms of the
+ * Creative Commons Attribution-ShareAlike 4.0 International. See the License
+ * terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
+ *
+ */
+
+'use strict';
+
+const configCommon = require('config');
+const config = configCommon.get('services.CoAuthoring');
+//process.env.NODE_ENV = config.get('server.mode');
+const logger = require('./../../Common/sources/logger');
+const co = require('co');
+const license = require('./../../Common/sources/license');
+const fs = require('fs');
+
+const express = require('express');
+const http = require('http');
+const urlModule = require('url');
+const path = require('path');
+const bodyParser = require("body-parser");
+const multer = require('multer');
+const mime = require('mime');
+const apicache = require('apicache');
+const docsCoServer = require('./DocsCoServer');
+const canvasService = require('./canvasservice');
+const converterService = require('./converterservice');
+const fileUploaderService = require('./fileuploaderservice');
+const wopiClient = require('./wopiClient');
+const constants = require('./../../Common/sources/constants');
+const utils = require('./../../Common/sources/utils');
+const commonDefines = require('./../../Common/sources/commondefines');
+const operationContext = require('./../../Common/sources/operationContext');
+const tenantManager = require('./../../Common/sources/tenantManager');
+const configStorage = configCommon.get('storage');
+
+const cfgWopiEnable = configCommon.get('wopi.enable');
+const cfgHtmlTemplate = configCommon.get('wopi.htmlTemplate');
+const cfgTokenEnableBrowser = configCommon.get('services.CoAuthoring.token.enable.browser');
+const cfgTokenEnableRequestInbox = configCommon.get('services.CoAuthoring.token.enable.request.inbox');
+const cfgTokenEnableRequestOutbox = configCommon.get('services.CoAuthoring.token.enable.request.outbox');
+const cfgLicenseFile = configCommon.get('license.license_file');
+
+const app = express();
+app.disable('x-powered-by');
+//path.resolve uses __dirname by default(unexpected path in pkg)
+app.set("views", path.resolve(process.cwd(), cfgHtmlTemplate));
+app.set("view engine", "ejs");
+const server = http.createServer(app);
+
+let licenseInfo, licenseOriginal, updatePluginsTime, userPlugins, pluginsLoaded;
+
+const updatePlugins = (eventType, filename) => {
+	operationContext.global.logger.info('update Folder: %s ; %s', eventType, filename);
+	if (updatePluginsTime && 1000 >= (new Date() - updatePluginsTime)) {
+		return;
+	}
+	operationContext.global.logger.info('update Folder true: %s ; %s', eventType, filename);
+	updatePluginsTime = new Date();
+	pluginsLoaded = false;
+};
+const readLicense = function*() {
+	[licenseInfo, licenseOriginal] = yield* license.readLicense(cfgLicenseFile);
+};
+const updateLicense = () => {
+	return co(function*() {
+		try {
+			yield* readLicense();
+			docsCoServer.setLicenseInfo(licenseInfo, licenseOriginal);
+			operationContext.global.logger.info('End updateLicense');
+		} catch (err) {
+			operationContext.global.logger.error('updateLicense error: %s', err.stack);
+		}
+	});
+};
+
+operationContext.global.logger.warn('Express server starting...');
+
+if (!(cfgTokenEnableBrowser && cfgTokenEnableRequestInbox && cfgTokenEnableRequestOutbox)) {
+	operationContext.global.logger.warn('Set services.CoAuthoring.token.enable.browser, services.CoAuthoring.token.enable.request.inbox, ' +
+				'services.CoAuthoring.token.enable.request.outbox in the Document Server config ' +
+				'to prevent an unauthorized access to your documents and the substitution of important parameters in ONLYOFFICE Document Server requests.');
+}
+
+if (!tenantManager.isMultitenantMode()) {
+	updateLicense();
+	setInterval(updateLicense, 86400000);
+}
+
+if (config.has('server.static_content')) {
+	const staticContent = config.get('server.static_content');
+	for (let i in staticContent) {
+		if (staticContent.hasOwnProperty(i)) {
+			app.use(i, express.static(staticContent[i]['path'], staticContent[i]['options']));
+		}
+	}
+}
+
+if (configStorage.has('fs.folderPath')) {
+	const cfgBucketName = configStorage.get('bucketName');
+	const cfgStorageFolderName = configStorage.get('storageFolderName');
+	app.use('/' + cfgBucketName + '/' + cfgStorageFolderName, (req, res, next) => {
+		const index = req.url.lastIndexOf('/');
+		if ('GET' === req.method && -1 != index) {
+			let sendFileOptions = {
+				root: configStorage.get('fs.folderPath'), dotfiles: 'deny', headers: {
+					'Content-Disposition': 'attachment'
+				}
+			};
+			const urlParsed = urlModule.parse(req.url);
+			if (urlParsed && urlParsed.pathname) {
+				const filename = decodeURIComponent(path.basename(urlParsed.pathname));
+				sendFileOptions.headers['Content-Type'] = mime.getType(filename);
+			}
+			const realUrl = req.url.substring(0, index);
+			res.sendFile(realUrl, sendFileOptions, (err) => {
+				if (err) {
+					operationContext.global.logger.error(err);
+					res.status(400).end();
+				}
+			});
+		} else {
+			res.sendStatus(404)
+		}
+	});
+}
+
+try {
+	fs.watch(config.get('plugins.path'), updatePlugins);
+} catch (e) {
+	operationContext.global.logger.warn('Failed to subscribe to plugin folder updates. When changing the list of plugins, you must restart the server. https://nodejs.org/docs/latest/api/fs.html#fs_availability');
+}
+
+// Если захочется использовать 'development' и 'production',
+// то с помощью app.settings.env (https://github.com/strongloop/express/issues/936)
+// Если нужна обработка ошибок, то теперь она такая https://github.com/expressjs/errorhandler
+docsCoServer.install(server, () => {
+	operationContext.global.logger.info('Start callbackFunction');
+
+	server.listen(config.get('server.port'), () => {
+		operationContext.global.logger.warn("Express server listening on port %d in %s mode. Version: %s. Build: %s", config.get('server.port'), app.settings.env, commonDefines.buildVersion, commonDefines.buildNumber);
+	});
+
+	app.get('/index.html', (req, res) => {
+		return co(function*() {
+			let ctx = new operationContext.Context();
+			try {
+				ctx.initFromRequest(req);
+				let licenseInfo = yield tenantManager.getTenantLicense(ctx);
+				let buildVersion = commonDefines.buildVersion;
+				let buildNumber = commonDefines.buildNumber;
+				let buildDate, packageType, customerId = "", alias = "";
+				if (licenseInfo) {
+					buildDate = licenseInfo.buildDate.toISOString();
+					packageType = licenseInfo.packageType;
+					customerId = licenseInfo.customerId;
+					alias = licenseInfo.alias;
+				}
+				let output = `Server is functioning normally. Version: ${buildVersion}. Build: ${buildNumber}`;
+				output += `. Release date: ${buildDate}. Package type: ${packageType}. Customer Id: ${customerId}. Alias: ${alias}`;
+				res.send(output);
+			} catch (err) {
+				ctx.logger.error('index.html error: %s', err.stack);
+				res.sendStatus(400);
+			}
+		});
+	});
+	const rawFileParser = bodyParser.raw(
+		{inflate: true, limit: config.get('server.limits_tempfile_upload'), type: function() {return true;}});
+	const urleEcodedParser = bodyParser.urlencoded({ extended: false });
+	let forms = multer();
+
+	app.get('/coauthoring/CommandService.ashx', utils.checkClientIp, rawFileParser, docsCoServer.commandFromServer);
+	app.post('/coauthoring/CommandService.ashx', utils.checkClientIp, rawFileParser,
+		docsCoServer.commandFromServer);
+
+	app.get('/ConvertService.ashx', utils.checkClientIp, rawFileParser, converterService.convertXml);
+	app.post('/ConvertService.ashx', utils.checkClientIp, rawFileParser, converterService.convertXml);
+	app.post('/converter', utils.checkClientIp, rawFileParser, converterService.convertJson);
+
+
+	app.get('/FileUploader.ashx', utils.checkClientIp, rawFileParser, fileUploaderService.uploadTempFile);
+	app.post('/FileUploader.ashx', utils.checkClientIp, rawFileParser, fileUploaderService.uploadTempFile);
+
+	app.param('docid', (req, res, next, val) => {
+		if (constants.DOC_ID_REGEX.test(val)) {
+			next();
+		} else {
+			res.sendStatus(403);
+		}
+	});
+	app.param('index', (req, res, next, val) => {
+		if (!isNaN(parseInt(val))) {
+			next();
+		} else {
+			res.sendStatus(403);
+		}
+	});
+	//'*' for backward compatible
+	app.post('/uploadold/:docid*', fileUploaderService.uploadImageFileOld);
+	app.post('/upload/:docid*', rawFileParser, fileUploaderService.uploadImageFile);
+
+	app.post('/downloadas/:docid', rawFileParser, canvasService.downloadAs);
+	app.post('/savefile/:docid', rawFileParser, canvasService.saveFile);
+	app.get('/printfile/:docid/:filename', canvasService.printFile);
+	app.get('/downloadfile/:docid', canvasService.downloadFile);
+	app.get('/healthcheck', utils.checkClientIp, docsCoServer.healthCheck);
+
+	app.get('/baseurl', (req, res) => {
+		res.send(utils.getBaseUrlByRequest(req));
+	});
+
+	app.get('/robots.txt', (req, res) => {
+		res.setHeader('Content-Type', 'plain/text');
+		res.send("User-agent: *\nDisallow: /");
+	});
+
+	app.post('/docbuilder', utils.checkClientIp, rawFileParser, (req, res) => {
+		converterService.builder(req, res);
+	});
+	app.get('/info/info.json', utils.checkClientIp, docsCoServer.licenseInfo);
+	app.put('/internal/cluster/inactive', utils.checkClientIp, docsCoServer.shutdown);
+	app.delete('/internal/cluster/inactive', utils.checkClientIp, docsCoServer.shutdown);
+
+	if (cfgWopiEnable) {
+		app.get('/hosting/discovery', utils.checkClientIp, wopiClient.discovery);
+		app.get('/hosting/capabilities', utils.checkClientIp, wopiClient.collaboraCapabilities);
+		app.post('/hosting/wopi/:documentType/:mode', urleEcodedParser, forms.none(), utils.lowercaseQueryString, wopiClient.getEditorHtml);
+	}
+
+	app.post('/dummyCallback', utils.checkClientIp, rawFileParser, function(req, res){
+		let ctx = new operationContext.Context();
+		ctx.initFromRequest(req);
+		ctx.logger.debug(`dummyCallback req.body:%s`, req.body);
+		utils.fillResponseSimple(res, JSON.stringify({error: 0}, "application/json"));
+	});
+
+	const sendUserPlugins = (res, data) => {
+		pluginsLoaded = true;
+		res.setHeader('Content-Type', 'application/json');
+		res.send(JSON.stringify(data));
+	};
+	app.get('/plugins.json', (req, res) => {
+		if (userPlugins && pluginsLoaded) {
+			sendUserPlugins(res, userPlugins);
+			return;
+		}
+
+		if (!config.has('server.static_content') || !config.has('plugins.uri')) {
+			res.sendStatus(404);
+			return;
+		}
+
+		let staticContent = config.get('server.static_content');
+		let pluginsUri = config.get('plugins.uri');
+		let pluginsPath = undefined;
+		let pluginsAutostart = config.get('plugins.autostart');
+
+		if (staticContent[pluginsUri]) {
+			pluginsPath = staticContent[pluginsUri].path;
+		}
+
+		let baseUrl = '../../../..';
+		utils.listFolders(pluginsPath, true).then((values) => {
+			return co(function*() {
+				const configFile = 'config.json';
+				let stats = null;
+				let result = [];
+				for (let i = 0; i < values.length; ++i) {
+					try {
+						stats = yield utils.fsStat(path.join(values[i], configFile));
+					} catch (err) {
+						stats = null;
+					}
+
+					if (stats && stats.isFile) {
+						result.push( baseUrl + pluginsUri + '/' + path.basename(values[i]) + '/' + configFile);
+					}
+				}
+
+				userPlugins = {'url': '', 'pluginsData': result, 'autostart': pluginsAutostart};
+				sendUserPlugins(res, userPlugins);
+			});
+		});
+	});
+	app.get('/themes.json', apicache.middleware("5 minutes"), (req, res) => {
+		return co(function*() {
+			let themes = [];
+			let ctx = new operationContext.Context();
+			try {
+				ctx.initFromRequest(req);
+				ctx.logger.info('themes.json start');
+				if (!config.has('server.static_content') || !config.has('themes.uri')) {
+					return;
+				}
+				let staticContent = config.get('server.static_content');
+				let themesUri = config.get('themes.uri');
+				let themesList = [];
+
+				for (let i in staticContent) {
+					if (staticContent.hasOwnProperty(i) && themesUri.startsWith(i)) {
+						let dir = staticContent[i].path + themesUri.substring(i.length);
+						themesList = yield utils.listObjects(dir, true);
+						ctx.logger.debug('themes.json dir:%s', dir);
+						ctx.logger.debug('themes.json themesList:%j', themesList);
+						for (let j = 0; j < themesList.length; ++j) {
+							if (themesList[j].endsWith('.json')) {
+								let data = yield utils.readFile(themesList[j], true);
+								themes.push(JSON.parse(data.toString('utf-8')));
+							}
+						}
+						break;
+					}
+				}
+			} catch (err) {
+				ctx.logger.error('themes.json error:%s', err.stack);
+			} finally {
+				if (themes.length > 0) {
+					res.setHeader('Content-Type', 'application/json');
+					res.send({"themes": themes});
+				} else {
+					res.sendStatus(404);
+				}
+				ctx.logger.info('themes.json end');
+			}
+		});
+	});
+});
+
+process.on('uncaughtException', (err) => {
+	operationContext.global.logger.error((new Date).toUTCString() + ' uncaughtException:', err.message);
+	operationContext.global.logger.error(err.stack);
+	logger.shutdown(() => {
+		process.exit(1);
+	});
+});
diff --git a/server.patch b/server.patch
deleted file mode 100644
index b70f41b..0000000
--- a/server.patch
+++ /dev/null
@@ -1,101 +0,0 @@
-From 3c58d272005a300ad8fe575457d5ce25710833e9 Mon Sep 17 00:00:00 2001
-From: Beeant <huangxb0512@gmail.com>
-Date: Sat, 24 Sep 2022 21:38:51 +0800
-Subject: [PATCH] build: license
-
----
- Common/sources/constants.js              |  2 +-
- Common/sources/license.js                | 16 ++++++++--------
- DocService/sources/server.js             |  2 +-
- FileConverter/sources/convertermaster.js |  1 -
- Makefile                                 |  2 +-
- 5 files changed, 11 insertions(+), 12 deletions(-)
-
-diff --git a/Common/sources/constants.js b/Common/sources/constants.js
-index 65d4c6f..39a7e56 100644
---- a/Common/sources/constants.js
-+++ b/Common/sources/constants.js
-@@ -83,7 +83,7 @@ exports.LICENSE_RESULT = {
-   UsersViewCountOS: 15
- };
- 
--exports.LICENSE_CONNECTIONS = 20;
-+exports.LICENSE_CONNECTIONS = 9999;
- exports.LICENSE_EXPIRE_USERS_ONE_DAY = 24 * 60 * 60; // day in seconds
- 
- exports.AVS_OFFICESTUDIO_FILE_UNKNOWN =  0x0000;
-diff --git a/Common/sources/license.js b/Common/sources/license.js
-index fbd5ec8..203dcb0 100644
---- a/Common/sources/license.js
-+++ b/Common/sources/license.js
-@@ -45,22 +45,22 @@ exports.readLicense = function*() {
- 		count: 1,
- 		type: c_LR.Success,
- 		light: false,
--		packageType: constants.PACKAGE_TYPE_OS,
-+		packageType: constants.PACKAGE_TYPE_I,
- 		mode: constants.LICENSE_MODE.None,
--		branding: false,
-+		branding: true,
- 		connections: constants.LICENSE_CONNECTIONS,
- 		connectionsView: constants.LICENSE_CONNECTIONS,
--		customization: false,
--		usersCount: 0,
-+		customization: true,
-+		usersCount: constants.LICENSE_CONNECTIONS,
- 		usersViewCount: 0,
- 		usersExpire: constants.LICENSE_EXPIRE_USERS_ONE_DAY,
--		hasLicense: false,
--		plugins: false,
-+		hasLicense: true,
-+		plugins: true,
- 		buildDate: oBuildDate,
- 		startDate: startDate,
--		endDate: null,
-+		endDate: new Date("2099-01-01T23:59:59.000Z"),
- 		customerId: ""
- 	}, null];
- };
- 
--exports.packageType = constants.PACKAGE_TYPE_OS;
-+exports.packageType = constants.PACKAGE_TYPE_I;
-diff --git a/DocService/sources/server.js b/DocService/sources/server.js
-index cf3ba90..d256724 100644
---- a/DocService/sources/server.js
-+++ b/DocService/sources/server.js
-@@ -110,7 +110,7 @@ if (!(cfgTokenEnableBrowser && cfgTokenEnableRequestInbox && cfgTokenEnableReque
- 
- if (!tenantManager.isMultitenantMode()) {
- 	updateLicense();
--	fs.watchFile(cfgLicenseFile, updateLicense);
- 	setInterval(updateLicense, 86400000);
- }
- 
-diff --git a/FileConverter/sources/convertermaster.js b/FileConverter/sources/convertermaster.js
-index 2a0b366..96468f9 100644
---- a/FileConverter/sources/convertermaster.js
-+++ b/FileConverter/sources/convertermaster.js
-@@ -93,7 +93,6 @@ if (cluster.isMaster) {
-   updateLicense();
- 
-   if (!tenantManager.isMultitenantMode()) {
--    fs.watchFile(cfgLicenseFile, updateLicense);
-     setInterval(updateLicense, 86400000);
-   }
- } else {
-diff --git a/Makefile b/Makefile
-index e8e1308..a4b0a51 100644
---- a/Makefile
-+++ b/Makefile
-@@ -87,7 +87,7 @@ DEBUG = $(BRANDING_DIR)/debug.js
- .PHONY: all clean install uninstall build-date
- 
- .NOTPARALLEL:
--all: $(SPELLCHECKER_DICTIONARIES) $(TOOLS) $(SCHEMA) $(CORE_FONTS) $(DOCUMENT_TEMPLATES) $(LICENSE) $(WELCOME) $(INFO) build-date
-+all: $(SPELLCHECKER_DICTIONARIES) $(TOOLS) $(SCHEMA) $(CORE_FONTS) $(DOCUMENT_TEMPLATES) $(WELCOME) $(INFO) build-date
- 
- build-date: $(GRUNT_FILES)
- 	sed "s|\(const buildVersion = \).*|\1'${PRODUCT_VERSION}';|" -i $(COMMON_DEFINES_JS)
--- 
-2.31.1.windows.1
-

From 570aed1ecaf00b495bee3c31cda943d717d2b46b Mon Sep 17 00:00:00 2001
From: Beeant <huangxb0512@gmail.com>
Date: Sun, 30 Oct 2022 17:24:35 +0800
Subject: [PATCH 05/10] Update docker-image.yml

---
 .github/workflows/docker-image.yml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/.github/workflows/docker-image.yml b/.github/workflows/docker-image.yml
index 360adc8..542c7a0 100644
--- a/.github/workflows/docker-image.yml
+++ b/.github/workflows/docker-image.yml
@@ -21,5 +21,5 @@ jobs:
         username: ${{ secrets.DOCKER_USERNAME }}
         password: ${{ secrets.DOCKER_PASSWORD }}
         repository: xbeeant/oo-unlimit
-        tags: latest, 7.2.0.204
+        tags: latest, 7.2.1.34
 

From 1ac167657e319c2be7a09cfe60f0ff77f6a9f823 Mon Sep 17 00:00:00 2001
From: Beeant <huangxb0512@gmail.com>
Date: Mon, 31 Oct 2022 14:19:14 +0000
Subject: [PATCH 06/10] fix: patch

---
 Dockerfile       |   1 +
 tenantManager.js | 163 +++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 164 insertions(+)
 create mode 100644 tenantManager.js

diff --git a/Dockerfile b/Dockerfile
index 7991cf8..f7d35da 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -41,6 +41,7 @@ COPY license.js /build/server/Common/sources/license.js
 COPY Makefile /build/server/Makefile
 COPY server.js /build/server/DocService/sources/server.js
 COPY constants.js /build/server/Common/srouces/constants.js
+COPY tenantManager.js /build/server/Common/srouces/tenantManager.js
 
 ## Build
 FROM path-stage as build-stage
diff --git a/tenantManager.js b/tenantManager.js
new file mode 100644
index 0000000..5c15103
--- /dev/null
+++ b/tenantManager.js
@@ -0,0 +1,163 @@
+*
+ * (c) Copyright Ascensio System SIA 2010-2019
+ *
+ * This program is a free software product. You can redistribute it and/or
+ * modify it under the terms of the GNU Affero General Public License (AGPL)
+ * version 3 as published by the Free Software Foundation. In accordance with
+ * Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect
+ * that Ascensio System SIA expressly excludes the warranty of non-infringement
+ * of any third-party rights.
+ *
+ * This program is distributed WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR  PURPOSE. For
+ * details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
+ *
+ * You can contact Ascensio System SIA at 20A-12 Ernesta Birznieka-Upisha
+ * street, Riga, Latvia, EU, LV-1050.
+ *
+ * The  interactive user interfaces in modified source and object code versions
+ * of the Program must display Appropriate Legal Notices, as required under
+ * Section 5 of the GNU AGPL version 3.
+ *
+ * Pursuant to Section 7(b) of the License you must retain the original Product
+ * logo when distributing the program. Pursuant to Section 7(e) we decline to
+ * grant you any rights under trademark law for use of our trademarks.
+ *
+ * All the Product's GUI elements, including illustrations and icon sets, as
+ * well as technical writing content are licensed under the terms of the
+ * Creative Commons Attribution-ShareAlike 4.0 International. See the License
+ * terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
+ *
+ */
+
+'use strict';
+
+const config = require('config');
+const co = require('co');
+const NodeCache = require( "node-cache" );
+const license = require('./../../Common/sources/license');
+const constants = require('./../../Common/sources/constants');
+const commonDefines = require('./../../Common/sources/commondefines');
+const utils = require('./../../Common/sources/utils');
+const { readFile } = require('fs/promises');
+const path = require('path');
+
+const oPackageType = config.get('license.packageType');
+const cfgTenantsBaseDomain = config.get('tenants.baseDomain');
+const cfgTenantsBaseDir = config.get('tenants.baseDir');
+const cfgTenantsFilenameSecret = config.get('tenants.filenameSecret');
+const cfgTenantsFilenameLicense = config.get('tenants.filenameLicense');
+const cfgTenantsDefaultTenant = config.get('tenants.defaultTenant');
+const cfgTenantsCache = config.get('tenants.cache');
+const cfgSecretInbox = config.get('services.CoAuthoring.secret.inbox');
+const cfgSecretOutbox = config.get('services.CoAuthoring.secret.outbox');
+const cfgSecretSession = config.get('services.CoAuthoring.secret.session');
+
+let licenseInfo;
+let licenseOriginal;
+
+const nodeCache = new NodeCache(cfgTenantsCache);
+
+function getDefautTenant() {
+  return cfgTenantsDefaultTenant;
+}
+function getTenant(ctx, domain) {
+  let tenant = getDefautTenant();
+  if (domain) {
+    //remove port
+    domain = domain.replace(/\:.*$/, '');
+    tenant = domain;
+    if (cfgTenantsBaseDomain) {
+      let index = domain.indexOf('.' + cfgTenantsBaseDomain);
+      if (-1 !== index) {
+        tenant = domain.substring(0, index);
+      }
+    }
+  }
+  return tenant;
+}
+function getTenantByConnection(ctx, conn) {
+  return isMultitenantMode() ? getTenant(ctx, utils.getDomainByConnection(ctx, conn)) : getDefautTenant();
+}
+function getTenantByRequest(ctx, req) {
+  return isMultitenantMode() ? getTenant(ctx, utils.getDomainByRequest(ctx, req)) : getDefautTenant();
+}
+function getTenantPathPrefix(ctx) {
+  return isMultitenantMode() ? utils.removeIllegalCharacters(ctx.tenant) + '/' : '';
+}
+function getTenantSecret(ctx, type) {
+  return co(function*() {
+    let res = undefined;
+    if (isMultitenantMode()) {
+      let tenantPath = utils.removeIllegalCharacters(ctx.tenant);
+      let secretPath = path.join(cfgTenantsBaseDir, tenantPath, cfgTenantsFilenameSecret);
+      res = nodeCache.get(secretPath);
+      if (res) {
+        ctx.logger.debug('getTenantSecret from cache');
+      } else {
+        res = yield readFile(secretPath, {encoding: 'utf8'});
+        nodeCache.set(secretPath, res);
+        ctx.logger.debug('getTenantSecret from %s', secretPath);
+      }
+    } else {
+      switch (type) {
+        case commonDefines.c_oAscSecretType.Browser:
+        case commonDefines.c_oAscSecretType.Inbox:
+          res = utils.getSecretByElem(cfgSecretInbox);
+          break;
+        case commonDefines.c_oAscSecretType.Outbox:
+          res = utils.getSecretByElem(cfgSecretOutbox);
+          break;
+        case commonDefines.c_oAscSecretType.Session:
+          res = utils.getSecretByElem(cfgSecretSession);
+          break;
+      }
+    }
+    return res;
+  });
+}
+
+function setDefLicense(data, original) {
+  licenseInfo = data;
+  licenseOriginal = original;
+}
+function getTenantLicense(ctx) {
+  return co(function*() {
+    let res = {
+		count: 1,
+		type: c_LR.Success,
+		light: true,
+		packageType: constants.PACKAGE_TYPE_I,
+		mode: constants.LICENSE_MODE.None,
+		branding: true,
+		connections: constants.LICENSE_CONNECTIONS,
+		connectionsView: constants.LICENSE_CONNECTIONS,
+		customization: true,
+		advancedApi: true,
+		usersCount: constants.LICENSE_CONNECTIONS,
+		usersViewCount: constants.LICENSE_CONNECTIONS,
+		usersExpire: constants.LICENSE_EXPIRE_USERS_ONE_DAY,
+		hasLicense: true,
+		plugins: true,
+		buildDate: oBuildDate,
+		startDate: startDate,
+		endDate: new Date("2099-01-01T23:59:59.000Z"),
+		customerId: "",
+		alias: "community"
+	};
+    
+    return res;
+  });
+}
+function isMultitenantMode() {
+  return !!cfgTenantsBaseDir;
+}
+
+exports.getDefautTenant = getDefautTenant;
+exports.getTenantByConnection = getTenantByConnection;
+exports.getTenantByRequest = getTenantByRequest;
+exports.getTenantPathPrefix = getTenantPathPrefix;
+exports.getTenantSecret = getTenantSecret;
+exports.getTenantLicense = getTenantLicense;
+exports.setDefLicense = setDefLicense;
+exports.isMultitenantMode = isMultitenantMode;
\ No newline at end of file

From 76d36fc5b8ee34775e573f26177322b21731c62c Mon Sep 17 00:00:00 2001
From: Beeant <huangxb0512@gmail.com>
Date: Sun, 18 Dec 2022 05:41:19 +0000
Subject: [PATCH 07/10] try patch 7.2.1.34

---
 .gitpod.yml        |   8 +
 Dockerfile         |  20 ++-
 Makefile           | 188 -----------------------
 constants.js       | 304 -------------------------------------
 convertermaster.js | 109 --------------
 license.js         |  68 ---------
 server.js          | 362 ---------------------------------------------
 server.patch       |  90 +++++++++++
 tenantManager.js   | 163 --------------------
 9 files changed, 112 insertions(+), 1200 deletions(-)
 create mode 100644 .gitpod.yml
 delete mode 100644 Makefile
 delete mode 100644 constants.js
 delete mode 100644 convertermaster.js
 delete mode 100644 license.js
 delete mode 100644 server.js
 create mode 100644 server.patch
 delete mode 100644 tenantManager.js

diff --git a/.gitpod.yml b/.gitpod.yml
new file mode 100644
index 0000000..6c59e39
--- /dev/null
+++ b/.gitpod.yml
@@ -0,0 +1,8 @@
+# This configuration file was automatically generated by Gitpod.
+# Please adjust to your needs (see https://www.gitpod.io/docs/config-gitpod-file)
+# and commit this file to your remote git repository to share the goodness with others.
+
+tasks:
+  - init: make
+
+
diff --git a/Dockerfile b/Dockerfile
index f7d35da..5079856 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -13,6 +13,7 @@ ENV BUILD_NUMBER=${build_number}
 
 ARG build_deps="git make g++ nodejs npm"
 RUN apt-get update && apt-get install -y ${build_deps}
+#RUN npm config set registry https://registry.npm.taobao.org
 RUN npm install -g pkg grunt grunt-cli
 
 WORKDIR /build
@@ -36,12 +37,19 @@ FROM clone-stage as path-stage
 # patch
 COPY web-apps.patch /build/web-apps.patch
 RUN cd /build/web-apps   && git apply /build/web-apps.patch
-COPY convertermaster.js /build/server/FileConverter/sources/convertermaster.js
-COPY license.js /build/server/Common/sources/license.js
-COPY Makefile /build/server/Makefile
-COPY server.js /build/server/DocService/sources/server.js
-COPY constants.js /build/server/Common/srouces/constants.js
-COPY tenantManager.js /build/server/Common/srouces/tenantManager.js
+
+
+COPY server.patch /build/server.patch
+RUN cd /build/server   && git apply /build/server.patch
+
+
+
+#COPY convertermaster.js /build/server/FileConverter/sources/convertermaster.js
+#COPY license.js /build/server/Common/sources/license.js
+#COPY Makefile /build/server/Makefile
+#COPY server.js /build/server/DocService/sources/server.js
+#COPY constants.js /build/server/Common/srouces/constants.js
+#COPY tenantManager.js /build/server/Common/srouces/tenantManager.js
 
 ## Build
 FROM path-stage as build-stage
diff --git a/Makefile b/Makefile
deleted file mode 100644
index 23f7e2e..0000000
--- a/Makefile
+++ /dev/null
@@ -1,188 +0,0 @@
-GRUNT = grunt
-GRUNT_FLAGS = --no-color -v
-
-GRUNT_FILES = Gruntfile.js.out
-
-PRODUCT_VERSION ?= 0.0.0
-BUILD_NUMBER ?= 0
-
-PUBLISHER_NAME ?= Ascensio System SIA
-PUBLISHER_URL ?= https://www.onlyoffice.com/
-
-GRUNT_ENV += PRODUCT_VERSION=$(PRODUCT_VERSION)
-GRUNT_ENV += BUILD_NUMBER=$(BUILD_NUMBER)
-GRUNT_ENV += PUBLISHER_NAME="$(PUBLISHER_NAME)"
-GRUNT_ENV += PUBLISHER_URL="$(PUBLISHER_URL)"
-
-BRANDING_DIR ?= ./branding
-
-DOCUMENT_ROOT ?= /var/www/onlyoffice/documentserver
-
-ifeq ($(OS),Windows_NT)
-    PLATFORM := win
-    EXEC_EXT := .exe
-    SHARED_EXT := .dll
-    ifeq ($(PROCESSOR_ARCHITECTURE),AMD64)
-        ARCHITECTURE := 64
-    endif
-    ifeq ($(PROCESSOR_ARCHITECTURE),x86)
-        ARCHITECTURE := 32
-    endif
-else
-    UNAME_S := $(shell uname -s)
-    ifeq ($(UNAME_S),Linux)
-        PLATFORM := linux
-        SHARED_EXT := .so*
-        LIB_PREFIX := lib
-    endif
-    UNAME_M := $(shell uname -m)
-    ifeq ($(UNAME_M),x86_64)
-        ARCHITECTURE := 64
-    endif
-    ifneq ($(filter %86,$(UNAME_M)),)
-        ARCHITECTURE := 32
-    endif
-endif
-
-TARGET := $(PLATFORM)_$(ARCHITECTURE)
-
-OUTPUT = ../build_tools/out/$(TARGET)/onlyoffice/documentserver/server
-
-SPELLCHECKER_DICTIONARIES := $(OUTPUT)/../dictionaries
-SPELLCHECKER_DICTIONARY_FILES += ../dictionaries/*_*
-
-SCHEMA_DIR = schema
-SCHEMA_FILES = $(SCHEMA_DIR)/**
-SCHEMA = $(OUTPUT)/$(SCHEMA_DIR)/
-
-TOOLS_DIR = tools
-TOOLS_FILES += ../core/build/bin/$(TARGET)/allfontsgen$(EXEC_EXT)
-TOOLS_FILES += ../core/build/bin/$(TARGET)/allthemesgen$(EXEC_EXT)
-TOOLS = $(OUTPUT)/$(TOOLS_DIR)
-
-LICENSE_FILES = LICENSE.txt 3rd-Party.txt license/
-LICENSE = $(addsuffix $(OUTPUT)/, LICENSE_FILES)
-
-LICENSE_JS := $(OUTPUT)/Common/sources/license.js
-COMMON_DEFINES_JS := $(OUTPUT)/Common/sources/commondefines.js
-
-WELCOME_DIR = welcome
-WELCOME_FILES = $(BRANDING_DIR)/$(WELCOME_DIR)/**
-WELCOME = $(OUTPUT)/$(WELCOME_DIR)/
-
-INFO_DIR = info
-INFO_FILES = $(BRANDING_DIR)/$(INFO_DIR)/**
-INFO = $(OUTPUT)/$(INFO_DIR)/
-
-CORE_FONTS_DIR = core-fonts
-CORE_FONTS_FILES = ../$(CORE_FONTS_DIR)/**
-CORE_FONTS = $(OUTPUT)/../$(CORE_FONTS_DIR)/
-
-DOCUMENT_TEMPLATES_DIR = document-templates
-DOCUMENT_TEMPLATES_FILES = ../$(DOCUMENT_TEMPLATES_DIR)/**
-DOCUMENT_TEMPLATES = $(OUTPUT)/../$(DOCUMENT_TEMPLATES_DIR)/
-
-DEBUG = $(BRANDING_DIR)/debug.js
-
-.PHONY: all clean install uninstall build-date
-
-.NOTPARALLEL:
-all: $(SCHEMA) $(LICENSE) $(WELCOME) $(INFO) build-date
-
-build-date: $(GRUNT_FILES)
-	sed "s|\(const buildVersion = \).*|\1'${PRODUCT_VERSION}';|" -i $(COMMON_DEFINES_JS)
-	sed "s|\(const buildNumber = \).*|\1${BUILD_NUMBER};|" -i $(COMMON_DEFINES_JS)
-	sed "s|\(const buildDate = \).*|\1'$$(date +%F)';|" -i $(LICENSE_JS)
-	test -e $(DEBUG) && \
-	cp $(DEBUG) $(OUTPUT)/Common/sources || true
-
-$(SPELLCHECKER_DICTIONARIES): $(GRUNT_FILES)
-	mkdir -p $(SPELLCHECKER_DICTIONARIES) && \
-		cp -r -t $(SPELLCHECKER_DICTIONARIES) $(SPELLCHECKER_DICTIONARY_FILES)
-
-$(SCHEMA):
-	mkdir -p $(SCHEMA) && \
-		cp -r -t $(SCHEMA) $(SCHEMA_FILES)
-
-$(TOOLS):
-	mkdir -p $(TOOLS) && \
-		cp -r -t $(TOOLS) $(TOOLS_FILES)
-
-$(LICENSE):
-	mkdir -p $(OUTPUT) && \
-		cp -r -t $(OUTPUT) $(LICENSE_FILES)
-
-$(GRUNT_FILES):
-	cd $(@D) && \
-		npm install && \
-		$(GRUNT_ENV) $(GRUNT) $(GRUNT_FLAGS)
-		mkdir -p $(OUTPUT)
-		cp -r -t $(OUTPUT) ./build/server/*
-	echo "Done" > $@
-
-$(WELCOME):
-	mkdir -p $(WELCOME) && \
-		cp -r -t $(WELCOME) $(WELCOME_FILES)
-
-$(INFO):
-	mkdir -p $(INFO) && \
-		cp -r -t $(INFO) $(INFO_FILES)
-
-$(CORE_FONTS):
-	mkdir -p $(CORE_FONTS) && \
-		cp -r -t $(CORE_FONTS) $(CORE_FONTS_FILES)
-
-$(DOCUMENT_TEMPLATES):
-	mkdir -p $(DOCUMENT_TEMPLATES) && \
-		cp -r -t $(DOCUMENT_TEMPLATES) $(DOCUMENT_TEMPLATES_FILES)
-
-clean:
-	rm -rf $(GRUNT_FILES)
-
-install:
-	mkdir -pv ${DESTDIR}/var/www/onlyoffice
-	if ! id -u onlyoffice > /dev/null 2>&1; then useradd -m -d /var/www/onlyoffice -r -U onlyoffice; fi
-
-	mkdir -p ${DESTDIR}${DOCUMENT_ROOT}/fonts
-	mkdir -p ${DESTDIR}/var/log/onlyoffice/documentserver
-	mkdir -p ${DESTDIR}/var/lib/onlyoffice/documentserver/App_Data
-
-	cp -fr -t ${DESTDIR}${DOCUMENT_ROOT} build/* ../web-apps/deploy/*
-	mkdir -p ${DESTDIR}/etc/onlyoffice/documentserver
-	mv ${DESTDIR}${DOCUMENT_ROOT}/server/Common/config/* ${DESTDIR}/etc/onlyoffice/documentserver
-
-	chown onlyoffice:onlyoffice -R ${DESTDIR}/var/www/onlyoffice
-	chown onlyoffice:onlyoffice -R ${DESTDIR}/var/log/onlyoffice
-	chown onlyoffice:onlyoffice -R ${DESTDIR}/var/lib/onlyoffice
-
-	# Make symlinks for shared libs
-	find \
-		${DESTDIR}${DOCUMENT_ROOT}/server/FileConverter/bin \
-		-maxdepth 1 \
-		-name *$(SHARED_EXT) \
-		-exec sh -c 'ln -sf {} ${DESTDIR}/lib/$$(basename {})' \;
-
-	sudo -u onlyoffice "${DESTDIR}${DOCUMENT_ROOT}/server/tools/allfontsgen"\
-		--input="${DESTDIR}${DOCUMENT_ROOT}/core-fonts"\
-		--allfonts-web="${DESTDIR}${DOCUMENT_ROOT}/sdkjs/common/AllFonts.js"\
-		--allfonts="${DESTDIR}${DOCUMENT_ROOT}/server/FileConverter/bin/AllFonts.js"\
-		--images="${DESTDIR}${DOCUMENT_ROOT}/sdkjs/common/Images"\
-		--selection="${DESTDIR}${DOCUMENT_ROOT}/server/FileConverter/bin/font_selection.bin"\
-		--output-web="${DESTDIR}${DOCUMENT_ROOT}/fonts"\
-		--use-system="true"
-
-	sudo -u onlyoffice "${DESTDIR}${DOCUMENT_ROOT}/server/tools/allthemesgen"\
-		--converter-dir="${DESTDIR}${DOCUMENT_ROOT}/server/FileConverter/bin"\
-		--src="${DESTDIR}${DOCUMENT_ROOT}/sdkjs/slide/themes"\
-		--output="${DESTDIR}${DOCUMENT_ROOT}/sdkjs/common/Images"
-
-uninstall:
-	userdel onlyoffice
-
-	# Unlink installed shared libs
-	find /lib -type l | while IFS= read -r lnk; do if (readlink "$$lnk" | grep -q '^${DOCUMENT_ROOT}/server/FileConverter/bin/'); then rm "$$lnk"; fi; done
-
-	rm -rf /var/www/onlyoffice/documentserver
-	rm -rf /var/log/onlyoffice/documentserver
-	rm -rf /var/lib/onlyoffice/documentserver
-	rm -rf /etc/onlyoffice/documentserver
diff --git a/constants.js b/constants.js
deleted file mode 100644
index 3116fbb..0000000
--- a/constants.js
+++ /dev/null
@@ -1,304 +0,0 @@
-/*
- * (c) Copyright Ascensio System SIA 2010-2019
- *
- * This program is a free software product. You can redistribute it and/or
- * modify it under the terms of the GNU Affero General Public License (AGPL)
- * version 3 as published by the Free Software Foundation. In accordance with
- * Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect
- * that Ascensio System SIA expressly excludes the warranty of non-infringement
- * of any third-party rights.
- *
- * This program is distributed WITHOUT ANY WARRANTY; without even the implied
- * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR  PURPOSE. For
- * details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
- *
- * You can contact Ascensio System SIA at 20A-12 Ernesta Birznieka-Upisha
- * street, Riga, Latvia, EU, LV-1050.
- *
- * The  interactive user interfaces in modified source and object code versions
- * of the Program must display Appropriate Legal Notices, as required under
- * Section 5 of the GNU AGPL version 3.
- *
- * Pursuant to Section 7(b) of the License you must retain the original Product
- * logo when distributing the program. Pursuant to Section 7(e) we decline to
- * grant you any rights under trademark law for use of our trademarks.
- *
- * All the Product's GUI elements, including illustrations and icon sets, as
- * well as technical writing content are licensed under the terms of the
- * Creative Commons Attribution-ShareAlike 4.0 International. See the License
- * terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
- *
- */
-
-'use strict';
-
-exports.DOC_ID_PATTERN = '0-9-.a-zA-Z_=';
-exports.DOC_ID_REGEX = new RegExp("^[" + exports.DOC_ID_PATTERN + "]*$", 'i');
-exports.DOC_ID_REPLACE_REGEX = new RegExp("[^" + exports.DOC_ID_PATTERN + "]", 'g');
-exports.DOC_ID_SOCKET_PATTERN = new RegExp("^/doc/([" + exports.DOC_ID_PATTERN + "]*)/c.+", 'i');
-exports.DOC_ID_MAX_LENGTH = 240;
-exports.USER_ID_MAX_LENGTH = 240;//255-240=15 symbols to make user id unique
-exports.USER_NAME_MAX_LENGTH = 255;
-exports.PASSWORD_MAX_LENGTH = 255;//set password limit for DoS protection with long password
-exports.EXTENTION_REGEX = /^[a-zA-Z0-9]*$/;
-exports.CHAR_DELIMITER = String.fromCharCode(5);
-exports.OUTPUT_NAME = 'output';
-exports.ONLY_OFFICE_URL_PARAM = 'ooname';
-exports.DISPLAY_PREFIX = 'display';
-exports.CHANGES_NAME = 'changes';
-exports.VIEWER_ONLY = /^(?:(pdf|djvu|xps|oxps))$/;
-exports.DEFAULT_DOC_ID = 'docId';
-exports.DEFAULT_USER_ID = 'userId';
-
-exports.RIGHTS = {
-  None    : 0,
-  Edit    : 1,
-  Review  : 2,
-  Comment : 3,
-  View    : 4
-};
-
-exports.LICENSE_MODE = {
-  None: 0,
-  Trial: 1,
-  Developer: 2,
-  Limited: 4
-};
-
-exports.LICENSE_RESULT = {
-  Error         : 1,
-  Expired       : 2,
-  Success       : 3,
-  UnknownUser   : 4,
-  Connections   : 5,
-  ExpiredTrial  : 6,
-  SuccessLimit  : 7,
-  UsersCount    : 8,
-  ConnectionsOS : 9,
-  UsersCountOS  : 10,
-  ExpiredLimited: 11,
-  ConnectionsLiveOS: 12,
-  ConnectionsLive: 13,
-  UsersViewCount: 14,
-  UsersViewCountOS: 15
-};
-
-exports.LICENSE_CONNECTIONS = 99999;
-exports.LICENSE_EXPIRE_USERS_ONE_DAY = 24 * 60 * 60; // day in seconds
-
-exports.AVS_OFFICESTUDIO_FILE_UNKNOWN =  0x0000;
-exports.AVS_OFFICESTUDIO_FILE_DOCUMENT = 0x0040;
-exports.AVS_OFFICESTUDIO_FILE_DOCUMENT_DOCX = exports.AVS_OFFICESTUDIO_FILE_DOCUMENT + 0x0001;
-exports.AVS_OFFICESTUDIO_FILE_DOCUMENT_DOC = exports.AVS_OFFICESTUDIO_FILE_DOCUMENT + 0x0002;
-exports.AVS_OFFICESTUDIO_FILE_DOCUMENT_ODT = exports.AVS_OFFICESTUDIO_FILE_DOCUMENT + 0x0003;
-exports.AVS_OFFICESTUDIO_FILE_DOCUMENT_RTF = exports.AVS_OFFICESTUDIO_FILE_DOCUMENT + 0x0004;
-exports.AVS_OFFICESTUDIO_FILE_DOCUMENT_TXT = exports.AVS_OFFICESTUDIO_FILE_DOCUMENT + 0x0005;
-exports.AVS_OFFICESTUDIO_FILE_DOCUMENT_HTML = exports.AVS_OFFICESTUDIO_FILE_DOCUMENT + 0x0006;
-exports.AVS_OFFICESTUDIO_FILE_DOCUMENT_MHT = exports.AVS_OFFICESTUDIO_FILE_DOCUMENT + 0x0007;
-exports.AVS_OFFICESTUDIO_FILE_DOCUMENT_EPUB = exports.AVS_OFFICESTUDIO_FILE_DOCUMENT + 0x0008;
-exports.AVS_OFFICESTUDIO_FILE_DOCUMENT_FB2 = exports.AVS_OFFICESTUDIO_FILE_DOCUMENT + 0x0009;
-exports.AVS_OFFICESTUDIO_FILE_DOCUMENT_MOBI = exports.AVS_OFFICESTUDIO_FILE_DOCUMENT + 0x000a;
-exports.AVS_OFFICESTUDIO_FILE_DOCUMENT_DOCM = exports.AVS_OFFICESTUDIO_FILE_DOCUMENT + 0x000b;
-exports.AVS_OFFICESTUDIO_FILE_DOCUMENT_DOTX = exports.AVS_OFFICESTUDIO_FILE_DOCUMENT + 0x000c;
-exports.AVS_OFFICESTUDIO_FILE_DOCUMENT_DOTM = exports.AVS_OFFICESTUDIO_FILE_DOCUMENT + 0x000d;
-exports.AVS_OFFICESTUDIO_FILE_DOCUMENT_ODT_FLAT = exports.AVS_OFFICESTUDIO_FILE_DOCUMENT + 0x000e;
-exports.AVS_OFFICESTUDIO_FILE_DOCUMENT_OTT = exports.AVS_OFFICESTUDIO_FILE_DOCUMENT + 0x000f;
-exports.AVS_OFFICESTUDIO_FILE_DOCUMENT_DOC_FLAT = exports.AVS_OFFICESTUDIO_FILE_DOCUMENT + 0x0010;
-exports.AVS_OFFICESTUDIO_FILE_DOCUMENT_DOCX_FLAT = exports.AVS_OFFICESTUDIO_FILE_DOCUMENT + 0x0011;
-exports.AVS_OFFICESTUDIO_FILE_DOCUMENT_HTML_IN_CONTAINER = exports.AVS_OFFICESTUDIO_FILE_DOCUMENT + 0x0012;
-exports.AVS_OFFICESTUDIO_FILE_DOCUMENT_DOCX_PACKAGE = exports.AVS_OFFICESTUDIO_FILE_DOCUMENT + 0x0014;
-exports.AVS_OFFICESTUDIO_FILE_DOCUMENT_OFORM = exports.AVS_OFFICESTUDIO_FILE_DOCUMENT + 0x0015;
-exports.AVS_OFFICESTUDIO_FILE_DOCUMENT_DOCXF = exports.AVS_OFFICESTUDIO_FILE_DOCUMENT + 0x0016;
-
-exports.AVS_OFFICESTUDIO_FILE_PRESENTATION = 0x0080;
-exports.AVS_OFFICESTUDIO_FILE_PRESENTATION_PPTX = exports.AVS_OFFICESTUDIO_FILE_PRESENTATION + 0x0001;
-exports.AVS_OFFICESTUDIO_FILE_PRESENTATION_PPT = exports.AVS_OFFICESTUDIO_FILE_PRESENTATION + 0x0002;
-exports.AVS_OFFICESTUDIO_FILE_PRESENTATION_ODP = exports.AVS_OFFICESTUDIO_FILE_PRESENTATION + 0x0003;
-exports.AVS_OFFICESTUDIO_FILE_PRESENTATION_PPSX = exports.AVS_OFFICESTUDIO_FILE_PRESENTATION + 0x0004;
-exports.AVS_OFFICESTUDIO_FILE_PRESENTATION_PPTM = exports.AVS_OFFICESTUDIO_FILE_PRESENTATION + 0x0005;
-exports.AVS_OFFICESTUDIO_FILE_PRESENTATION_PPSM = exports.AVS_OFFICESTUDIO_FILE_PRESENTATION + 0x0006;
-exports.AVS_OFFICESTUDIO_FILE_PRESENTATION_POTX = exports.AVS_OFFICESTUDIO_FILE_PRESENTATION + 0x0007;
-exports.AVS_OFFICESTUDIO_FILE_PRESENTATION_POTM = exports.AVS_OFFICESTUDIO_FILE_PRESENTATION + 0x0008;
-exports.AVS_OFFICESTUDIO_FILE_PRESENTATION_ODP_FLAT = exports.AVS_OFFICESTUDIO_FILE_PRESENTATION + 0x0009;
-exports.AVS_OFFICESTUDIO_FILE_PRESENTATION_OTP = exports.AVS_OFFICESTUDIO_FILE_PRESENTATION + 0x000a;
-exports.AVS_OFFICESTUDIO_FILE_PRESENTATION_PPTX_PACKAGE = exports.AVS_OFFICESTUDIO_FILE_PRESENTATION + 0x000b;
-
-exports.AVS_OFFICESTUDIO_FILE_SPREADSHEET = 0x0100;
-exports.AVS_OFFICESTUDIO_FILE_SPREADSHEET_XLSX = exports.AVS_OFFICESTUDIO_FILE_SPREADSHEET + 0x0001;
-exports.AVS_OFFICESTUDIO_FILE_SPREADSHEET_XLS = exports.AVS_OFFICESTUDIO_FILE_SPREADSHEET + 0x0002;
-exports.AVS_OFFICESTUDIO_FILE_SPREADSHEET_ODS = exports.AVS_OFFICESTUDIO_FILE_SPREADSHEET + 0x0003;
-exports.AVS_OFFICESTUDIO_FILE_SPREADSHEET_CSV = exports.AVS_OFFICESTUDIO_FILE_SPREADSHEET + 0x0004;
-exports.AVS_OFFICESTUDIO_FILE_SPREADSHEET_XLSM = exports.AVS_OFFICESTUDIO_FILE_SPREADSHEET + 0x0005;
-exports.AVS_OFFICESTUDIO_FILE_SPREADSHEET_XLTX = exports.AVS_OFFICESTUDIO_FILE_SPREADSHEET + 0x0006;
-exports.AVS_OFFICESTUDIO_FILE_SPREADSHEET_XLTM = exports.AVS_OFFICESTUDIO_FILE_SPREADSHEET + 0x0007;
-exports.AVS_OFFICESTUDIO_FILE_SPREADSHEET_XLSB = exports.AVS_OFFICESTUDIO_FILE_SPREADSHEET + 0x0008;
-exports.AVS_OFFICESTUDIO_FILE_SPREADSHEET_ODS_FLAT = exports.AVS_OFFICESTUDIO_FILE_SPREADSHEET + 0x0009;
-exports.AVS_OFFICESTUDIO_FILE_SPREADSHEET_OTS = exports.AVS_OFFICESTUDIO_FILE_SPREADSHEET + 0x000a;
-exports.AVS_OFFICESTUDIO_FILE_SPREADSHEET_XLSX_FLAT = exports.AVS_OFFICESTUDIO_FILE_SPREADSHEET + 0x000b;
-exports.AVS_OFFICESTUDIO_FILE_SPREADSHEET_XLSX_PACKAGE = exports.AVS_OFFICESTUDIO_FILE_SPREADSHEET + 0x000c;
-
-exports.AVS_OFFICESTUDIO_FILE_CROSSPLATFORM = 0x0200;
-exports.AVS_OFFICESTUDIO_FILE_CROSSPLATFORM_PDF = exports.AVS_OFFICESTUDIO_FILE_CROSSPLATFORM + 0x0001;
-exports.AVS_OFFICESTUDIO_FILE_CROSSPLATFORM_SWF = exports.AVS_OFFICESTUDIO_FILE_CROSSPLATFORM + 0x0002;
-exports.AVS_OFFICESTUDIO_FILE_CROSSPLATFORM_DJVU = exports.AVS_OFFICESTUDIO_FILE_CROSSPLATFORM + 0x0003;
-exports.AVS_OFFICESTUDIO_FILE_CROSSPLATFORM_XPS = exports.AVS_OFFICESTUDIO_FILE_CROSSPLATFORM + 0x0004;
-exports.AVS_OFFICESTUDIO_FILE_CROSSPLATFORM_SVG = exports.AVS_OFFICESTUDIO_FILE_CROSSPLATFORM + 0x0005;
-exports.AVS_OFFICESTUDIO_FILE_CROSSPLATFORM_HTMLR = exports.AVS_OFFICESTUDIO_FILE_CROSSPLATFORM + 0x0006;
-exports.AVS_OFFICESTUDIO_FILE_CROSSPLATFORM_HTMLR_MENU = exports.AVS_OFFICESTUDIO_FILE_CROSSPLATFORM + 0x0007;
-exports.AVS_OFFICESTUDIO_FILE_CROSSPLATFORM_HTMLR_CANVAS = exports.AVS_OFFICESTUDIO_FILE_CROSSPLATFORM + 0x0008;
-exports.AVS_OFFICESTUDIO_FILE_CROSSPLATFORM_PDFA = exports.AVS_OFFICESTUDIO_FILE_CROSSPLATFORM + 0x0009;
-exports.AVS_OFFICESTUDIO_FILE_IMAGE = 0x0400;
-exports.AVS_OFFICESTUDIO_FILE_IMAGE_JPG = exports.AVS_OFFICESTUDIO_FILE_IMAGE + 0x0001;
-exports.AVS_OFFICESTUDIO_FILE_IMAGE_TIFF = exports.AVS_OFFICESTUDIO_FILE_IMAGE + 0x0002;
-exports.AVS_OFFICESTUDIO_FILE_IMAGE_TGA = exports.AVS_OFFICESTUDIO_FILE_IMAGE + 0x0003;
-exports.AVS_OFFICESTUDIO_FILE_IMAGE_GIF = exports.AVS_OFFICESTUDIO_FILE_IMAGE + 0x0004;
-exports.AVS_OFFICESTUDIO_FILE_IMAGE_PNG = exports.AVS_OFFICESTUDIO_FILE_IMAGE + 0x0005;
-exports.AVS_OFFICESTUDIO_FILE_IMAGE_EMF = exports.AVS_OFFICESTUDIO_FILE_IMAGE + 0x0006;
-exports.AVS_OFFICESTUDIO_FILE_IMAGE_WMF = exports.AVS_OFFICESTUDIO_FILE_IMAGE + 0x0007;
-exports.AVS_OFFICESTUDIO_FILE_IMAGE_BMP = exports.AVS_OFFICESTUDIO_FILE_IMAGE + 0x0008;
-exports.AVS_OFFICESTUDIO_FILE_IMAGE_CR2 = exports.AVS_OFFICESTUDIO_FILE_IMAGE + 0x0009;
-exports.AVS_OFFICESTUDIO_FILE_IMAGE_PCX = exports.AVS_OFFICESTUDIO_FILE_IMAGE + 0x000a;
-exports.AVS_OFFICESTUDIO_FILE_IMAGE_RAS = exports.AVS_OFFICESTUDIO_FILE_IMAGE + 0x000b;
-exports.AVS_OFFICESTUDIO_FILE_IMAGE_PSD = exports.AVS_OFFICESTUDIO_FILE_IMAGE + 0x000c;
-exports.AVS_OFFICESTUDIO_FILE_IMAGE_ICO = exports.AVS_OFFICESTUDIO_FILE_IMAGE + 0x000d;
-exports.AVS_OFFICESTUDIO_FILE_OTHER = 0x0800;
-exports.AVS_OFFICESTUDIO_FILE_OTHER_EXTRACT_IMAGE = exports.AVS_OFFICESTUDIO_FILE_OTHER + 0x0001;
-exports.AVS_OFFICESTUDIO_FILE_OTHER_MS_OFFCRYPTO = exports.AVS_OFFICESTUDIO_FILE_OTHER + 0x0002;
-exports.AVS_OFFICESTUDIO_FILE_OTHER_HTMLZIP = exports.AVS_OFFICESTUDIO_FILE_OTHER + 0x0003;
-exports.AVS_OFFICESTUDIO_FILE_OTHER_OLD_DOCUMENT = exports.AVS_OFFICESTUDIO_FILE_OTHER + 0x0004;
-exports.AVS_OFFICESTUDIO_FILE_OTHER_OLD_PRESENTATION = exports.AVS_OFFICESTUDIO_FILE_OTHER + 0x0005;
-exports.AVS_OFFICESTUDIO_FILE_OTHER_OLD_DRAWING = exports.AVS_OFFICESTUDIO_FILE_OTHER + 0x0006;
-exports.AVS_OFFICESTUDIO_FILE_OTHER_OOXML = exports.AVS_OFFICESTUDIO_FILE_OTHER + 0x0007;
-exports.AVS_OFFICESTUDIO_FILE_OTHER_JSON = exports.AVS_OFFICESTUDIO_FILE_OTHER + 0x0008; // Для mail-merge
-exports.AVS_OFFICESTUDIO_FILE_OTHER_ODF = exports.AVS_OFFICESTUDIO_FILE_OTHER + 0x000a;
-exports.AVS_OFFICESTUDIO_FILE_OTHER_MS_MITCRYPTO = exports.AVS_OFFICESTUDIO_FILE_OTHER + 0x000b;
-
-exports.AVS_OFFICESTUDIO_FILE_TEAMLAB = 0x1000;
-exports.AVS_OFFICESTUDIO_FILE_TEAMLAB_DOCY = exports.AVS_OFFICESTUDIO_FILE_TEAMLAB + 0x0001;
-exports.AVS_OFFICESTUDIO_FILE_TEAMLAB_XLSY = exports.AVS_OFFICESTUDIO_FILE_TEAMLAB + 0x0002;
-exports.AVS_OFFICESTUDIO_FILE_TEAMLAB_PPTY = exports.AVS_OFFICESTUDIO_FILE_TEAMLAB + 0x0003;
-exports.AVS_OFFICESTUDIO_FILE_CANVAS = 0x2000;
-exports.AVS_OFFICESTUDIO_FILE_CANVAS_WORD = exports.AVS_OFFICESTUDIO_FILE_CANVAS + 0x0001;
-exports.AVS_OFFICESTUDIO_FILE_CANVAS_SPREADSHEET = exports.AVS_OFFICESTUDIO_FILE_CANVAS + 0x0002;
-exports.AVS_OFFICESTUDIO_FILE_CANVAS_PRESENTATION = exports.AVS_OFFICESTUDIO_FILE_CANVAS + 0x0003;
-
-exports.NO_ERROR = 0;
-exports.UNKNOWN = -1;
-exports.READ_REQUEST_STREAM = -3;
-exports.WEB_REQUEST = -4;
-exports.CHANGE_DOC_INFO = -5;
-exports.TASK_QUEUE = -20;
-exports.TASK_RESULT = -40;
-exports.STORAGE = -60;
-exports.STORAGE_FILE_NO_FOUND = -61;
-exports.STORAGE_READ = -62;
-exports.STORAGE_WRITE = -63;
-exports.STORAGE_REMOVE_DIR = -64;
-exports.STORAGE_CREATE_DIR = -65;
-exports.STORAGE_GET_INFO = -66;
-exports.CONVERT = -80;
-exports.CONVERT_DOWNLOAD = -81;
-exports.CONVERT_UNKNOWN_FORMAT = -82;
-exports.CONVERT_TIMEOUT = -83;
-exports.CONVERT_READ_FILE = -84;
-exports.CONVERT_DRM_UNSUPPORTED = -85;
-exports.CONVERT_CORRUPTED = -86;
-exports.CONVERT_LIBREOFFICE = -87;
-exports.CONVERT_PARAMS = -88;
-exports.CONVERT_NEED_PARAMS = -89;
-exports.CONVERT_DRM = -90;
-exports.CONVERT_PASSWORD = -91;
-exports.CONVERT_ICU = -92;
-exports.CONVERT_LIMITS = -93;
-exports.CONVERT_DEAD_LETTER = -99;
-exports.UPLOAD = -100;
-exports.UPLOAD_CONTENT_LENGTH = -101;
-exports.UPLOAD_EXTENSION = -102;
-exports.UPLOAD_COUNT_FILES = -103;
-exports.UPLOAD_URL = -104;
-exports.VKEY = -120;
-exports.VKEY_ENCRYPT = -121;
-exports.VKEY_KEY_EXPIRE = -122;
-exports.VKEY_USER_COUNT_EXCEED = -123;
-exports.VKEY_TIME_EXPIRE = -124;
-exports.VKEY_TIME_INCORRECT = -125;
-exports.EDITOR_CHANGES = -160;
-exports.PASSWORD = -180;
-
-exports.QUEUE_PRIORITY_VERY_LOW = 0;
-exports.QUEUE_PRIORITY_LOW = 1;
-exports.QUEUE_PRIORITY_NORMAL = 2;
-exports.QUEUE_PRIORITY_HIGH = 3;
-exports.QUEUE_PRIORITY_VERY_HIGH = 4;
-
-exports.EDITOR_TYPE_WORD = 0;
-exports.EDITOR_TYPE_SPREADSHEET = 1;
-exports.EDITOR_TYPE_PRESENTATION = 2;
-exports.EDITOR_TYPE_CONVERTATION = 3;
-
-exports.PACKAGE_TYPE_OS = 0;
-exports.PACKAGE_TYPE_I = 1;
-exports.PACKAGE_TYPE_D = 2;
-
-exports.REDIS_KEY_PUBSUB = 'pubsub';
-exports.REDIS_KEY_SAVE_LOCK = 'savelock:';
-exports.REDIS_KEY_PRESENCE_HASH = 'presence:hash:';
-exports.REDIS_KEY_PRESENCE_SET = 'presence:set:';
-exports.REDIS_KEY_PRESENCE_UNIQUE_USERS = 'presence:unique:users';
-exports.REDIS_KEY_PRESENCE_UNIQUE_USERS_HASH = 'presence:unique:users:hash';
-exports.REDIS_KEY_PRESENCE_MONTH_UNIQUE_USERS_HASH = 'presence:unique:users:month';
-exports.REDIS_KEY_PRESENCE_UNIQUE_USERS_VIEW = 'presence:unique:usersview';
-exports.REDIS_KEY_PRESENCE_UNIQUE_USERS_VIEW_HASH = 'presence:unique:usersview:hash';
-exports.REDIS_KEY_PRESENCE_MONTH_UNIQUE_USERS_VIEW_HASH = 'presence:unique:usersview:month';
-exports.REDIS_KEY_LOCKS = 'locks:';
-exports.REDIS_KEY_LOCK_DOCUMENT = 'lockdocument:';
-exports.REDIS_KEY_MESSAGE = 'message:';
-exports.REDIS_KEY_DOCUMENTS = 'documents';
-exports.REDIS_KEY_LAST_SAVE = 'lastsave:';
-exports.REDIS_KEY_FORCE_SAVE = 'forcesave:';
-exports.REDIS_KEY_FORCE_SAVE_TIMER = 'forcesavetimer';
-exports.REDIS_KEY_FORCE_SAVE_TIMER_LOCK = 'forcesavetimerlock:';
-exports.REDIS_KEY_SAVED = 'saved:';
-exports.REDIS_KEY_SHUTDOWN = 'shutdown';
-exports.REDIS_KEY_COLLECT_LOST = 'collectlost';
-exports.REDIS_KEY_LICENSE = 'license';
-exports.REDIS_KEY_LICENSE_T = 'licenseT';
-exports.REDIS_KEY_EDITOR_CONNECTIONS = 'editorconnections';
-exports.REDIS_KEY_SHARD_CONNECTIONS_EDIT_ZSET = 'shardconnections:edit:zset';
-exports.REDIS_KEY_SHARD_CONNECTIONS_EDIT_HASH = 'shardconnections:edit:hash';
-exports.REDIS_KEY_SHARD_CONNECTIONS_LIVE_VIEW_ZSET = 'shardconnections:liveview:zset';
-exports.REDIS_KEY_SHARD_CONNECTIONS_LIVE_VIEW_HASH = 'shardconnections:liveview:hash';
-exports.REDIS_KEY_SHARD_CONNECTIONS_VIEW_ZSET = 'shardconnections:view:zset';
-exports.REDIS_KEY_SHARD_CONNECTIONS_VIEW_HASH = 'shardconnections:view:hash';
-
-exports.SHUTDOWN_CODE = 4001;
-exports.SHUTDOWN_REASON = 'server shutdown';
-exports.SESSION_IDLE_CODE = 4002;
-exports.SESSION_IDLE_REASON = 'idle session expires';
-exports.SESSION_ABSOLUTE_CODE = 4003;
-exports.SESSION_ABSOLUTE_REASON = 'absolute session expires';
-exports.ACCESS_DENIED_CODE = 4004;
-exports.ACCESS_DENIED_REASON = 'access deny';
-exports.JWT_EXPIRED_CODE = 4005;
-exports.JWT_EXPIRED_REASON = 'token:';
-exports.JWT_ERROR_CODE = 4006;
-exports.JWT_ERROR_REASON = 'token:';
-exports.DROP_CODE = 4007;
-exports.DROP_REASON = 'drop';
-exports.UPDATE_VERSION_CODE = 4008;
-exports.UPDATE_VERSION = 'update version';
-exports.NO_CACHE_CODE = 4009;
-exports.NO_CACHE = 'no cache';
-exports.RESTORE_CODE = 4010;
-exports.RESTORE = 'no cache';
-
-exports.CONTENT_DISPOSITION_INLINE = 'inline';
-exports.CONTENT_DISPOSITION_ATTACHMENT = 'attachment';
-
-exports.CONN_CLOSED = 3;
-
-exports.FILE_STATUS_OK = 'ok';
-exports.FILE_STATUS_UPDATE_VERSION = 'updateversion';
-
-exports.ACTIVEMQ_QUEUE_PREFIX = 'queue://';
-exports.ACTIVEMQ_TOPIC_PREFIX = 'topic://';
diff --git a/convertermaster.js b/convertermaster.js
deleted file mode 100644
index 757905e..0000000
--- a/convertermaster.js
+++ /dev/null
@@ -1,109 +0,0 @@
-/*
- * (c) Copyright Ascensio System SIA 2010-2019
- *
- * This program is a free software product. You can redistribute it and/or
- * modify it under the terms of the GNU Affero General Public License (AGPL)
- * version 3 as published by the Free Software Foundation. In accordance with
- * Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect
- * that Ascensio System SIA expressly excludes the warranty of non-infringement
- * of any third-party rights.
- *
- * This program is distributed WITHOUT ANY WARRANTY; without even the implied
- * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR  PURPOSE. For
- * details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
- *
- * You can contact Ascensio System SIA at 20A-12 Ernesta Birznieka-Upisha
- * street, Riga, Latvia, EU, LV-1050.
- *
- * The  interactive user interfaces in modified source and object code versions
- * of the Program must display Appropriate Legal Notices, as required under
- * Section 5 of the GNU AGPL version 3.
- *
- * Pursuant to Section 7(b) of the License you must retain the original Product
- * logo when distributing the program. Pursuant to Section 7(e) we decline to
- * grant you any rights under trademark law for use of our trademarks.
- *
- * All the Product's GUI elements, including illustrations and icon sets, as
- * well as technical writing content are licensed under the terms of the
- * Creative Commons Attribution-ShareAlike 4.0 International. See the License
- * terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
- *
- */
-
-'use strict';
-
-const cluster = require('cluster');
-const logger = require('./../../Common/sources/logger');
-const operationContext = require('./../../Common/sources/operationContext');
-
-if (cluster.isMaster) {
-  const fs = require('fs');
-  const co = require('co');
-  const numCPUs = require('os').cpus().length;
-  const configCommon = require('config');
-  const config = configCommon.get('FileConverter.converter');
-  const license = require('./../../Common/sources/license');
-  const tenantManager = require('./../../Common/sources/tenantManager');
-
-  const cfgLicenseFile = configCommon.get('license.license_file');
-
-  const cfgMaxProcessCount = config.get('maxprocesscount');
-  var workersCount = 0;
-  const readLicense = function* () {
-    workersCount = Math.ceil(numCPUs * cfgMaxProcessCount);
-    if (!tenantManager.isMultitenantMode()) {
-      let [licenseInfo] = yield* license.readLicense(cfgLicenseFile);
-      workersCount = Math.min(licenseInfo.count, workersCount);
-    }
-  };
-  const updateWorkers = () => {
-    var i;
-    const arrKeyWorkers = Object.keys(cluster.workers);
-    if (arrKeyWorkers.length < workersCount) {
-      for (i = arrKeyWorkers.length; i < workersCount; ++i) {
-        const newWorker = cluster.fork();
-        operationContext.global.logger.warn('worker %s started.', newWorker.process.pid);
-      }
-    } else {
-      for (i = workersCount; i < arrKeyWorkers.length; ++i) {
-        const killWorker = cluster.workers[arrKeyWorkers[i]];
-        if (killWorker) {
-          killWorker.kill();
-        }
-      }
-    }
-  };
-  const updateLicense = () => {
-    return co(function*() {
-      try {
-        yield* readLicense();
-        operationContext.global.logger.warn('update cluster with %s workers', workersCount);
-        updateWorkers();
-      } catch (err) {
-        operationContext.global.logger.error('updateLicense error: %s', err.stack);
-      }
-    });
-  };
-
-  cluster.on('exit', (worker, code, signal) => {
-    operationContext.global.logger.warn('worker %s died (code = %s; signal = %s).', worker.process.pid, code, signal);
-    updateWorkers();
-  });
-
-  updateLicense();
-
-  if (!tenantManager.isMultitenantMode()) {
-    setInterval(updateLicense, 86400000);
-  }
-} else {
-  const converter = require('./converter');
-  converter.run();
-}
-
-process.on('uncaughtException', (err) => {
-  operationContext.global.logger.error((new Date).toUTCString() + ' uncaughtException:', err.message);
-  operationContext.global.logger.error(err.stack);
-  logger.shutdown(() => {
-    process.exit(1);
-  });
-});
diff --git a/license.js b/license.js
deleted file mode 100644
index cce68fd..0000000
--- a/license.js
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * (c) Copyright Ascensio System SIA 2010-2019
- *
- * This program is a free software product. You can redistribute it and/or
- * modify it under the terms of the GNU Affero General Public License (AGPL)
- * version 3 as published by the Free Software Foundation. In accordance with
- * Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect
- * that Ascensio System SIA expressly excludes the warranty of non-infringement
- * of any third-party rights.
- *
- * This program is distributed WITHOUT ANY WARRANTY; without even the implied
- * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR  PURPOSE. For
- * details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
- *
- * You can contact Ascensio System SIA at 20A-12 Ernesta Birznieka-Upisha
- * street, Riga, Latvia, EU, LV-1050.
- *
- * The  interactive user interfaces in modified source and object code versions
- * of the Program must display Appropriate Legal Notices, as required under
- * Section 5 of the GNU AGPL version 3.
- *
- * Pursuant to Section 7(b) of the License you must retain the original Product
- * logo when distributing the program. Pursuant to Section 7(e) we decline to
- * grant you any rights under trademark law for use of our trademarks.
- *
- * All the Product's GUI elements, including illustrations and icon sets, as
- * well as technical writing content are licensed under the terms of the
- * Creative Commons Attribution-ShareAlike 4.0 International. See the License
- * terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
- *
- */
-
-'use strict';
-
-const constants = require('./constants');
-
-const buildDate = '6/29/2016';
-const oBuildDate = new Date(buildDate);
-
-exports.readLicense = function*() {
-	const c_LR = constants.LICENSE_RESULT;
-	var now = new Date();
-	var startDate = new Date(Date.UTC(now.getUTCFullYear(), now.getUTCMonth(), 1));//first day of current month
-	return [{
-		count: 1,
-		type: c_LR.Success,
-		light: true,
-		packageType: constants.PACKAGE_TYPE_I,
-		mode: constants.LICENSE_MODE.None,
-		branding: true,
-		connections: constants.LICENSE_CONNECTIONS,
-		connectionsView: constants.LICENSE_CONNECTIONS,
-		customization: true,
-		advancedApi: true,
-		usersCount: constants.LICENSE_CONNECTIONS,
-		usersViewCount: constants.LICENSE_CONNECTIONS,
-		usersExpire: constants.LICENSE_EXPIRE_USERS_ONE_DAY,
-		hasLicense: true,
-		plugins: true,
-		buildDate: oBuildDate,
-		startDate: startDate,
-		endDate: new Date("2099-01-01T23:59:59.000Z"),
-		customerId: "",
-		alias: "community"
-	}, null];
-};
-
-exports.packageType = constants.PACKAGE_TYPE_I;
diff --git a/server.js b/server.js
deleted file mode 100644
index edfb423..0000000
--- a/server.js
+++ /dev/null
@@ -1,362 +0,0 @@
-/*
- * (c) Copyright Ascensio System SIA 2010-2019
- *
- * This program is a free software product. You can redistribute it and/or
- * modify it under the terms of the GNU Affero General Public License (AGPL)
- * version 3 as published by the Free Software Foundation. In accordance with
- * Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect
- * that Ascensio System SIA expressly excludes the warranty of non-infringement
- * of any third-party rights.
- *
- * This program is distributed WITHOUT ANY WARRANTY; without even the implied
- * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR  PURPOSE. For
- * details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
- *
- * You can contact Ascensio System SIA at 20A-12 Ernesta Birznieka-Upisha
- * street, Riga, Latvia, EU, LV-1050.
- *
- * The  interactive user interfaces in modified source and object code versions
- * of the Program must display Appropriate Legal Notices, as required under
- * Section 5 of the GNU AGPL version 3.
- *
- * Pursuant to Section 7(b) of the License you must retain the original Product
- * logo when distributing the program. Pursuant to Section 7(e) we decline to
- * grant you any rights under trademark law for use of our trademarks.
- *
- * All the Product's GUI elements, including illustrations and icon sets, as
- * well as technical writing content are licensed under the terms of the
- * Creative Commons Attribution-ShareAlike 4.0 International. See the License
- * terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
- *
- */
-
-'use strict';
-
-const configCommon = require('config');
-const config = configCommon.get('services.CoAuthoring');
-//process.env.NODE_ENV = config.get('server.mode');
-const logger = require('./../../Common/sources/logger');
-const co = require('co');
-const license = require('./../../Common/sources/license');
-const fs = require('fs');
-
-const express = require('express');
-const http = require('http');
-const urlModule = require('url');
-const path = require('path');
-const bodyParser = require("body-parser");
-const multer = require('multer');
-const mime = require('mime');
-const apicache = require('apicache');
-const docsCoServer = require('./DocsCoServer');
-const canvasService = require('./canvasservice');
-const converterService = require('./converterservice');
-const fileUploaderService = require('./fileuploaderservice');
-const wopiClient = require('./wopiClient');
-const constants = require('./../../Common/sources/constants');
-const utils = require('./../../Common/sources/utils');
-const commonDefines = require('./../../Common/sources/commondefines');
-const operationContext = require('./../../Common/sources/operationContext');
-const tenantManager = require('./../../Common/sources/tenantManager');
-const configStorage = configCommon.get('storage');
-
-const cfgWopiEnable = configCommon.get('wopi.enable');
-const cfgHtmlTemplate = configCommon.get('wopi.htmlTemplate');
-const cfgTokenEnableBrowser = configCommon.get('services.CoAuthoring.token.enable.browser');
-const cfgTokenEnableRequestInbox = configCommon.get('services.CoAuthoring.token.enable.request.inbox');
-const cfgTokenEnableRequestOutbox = configCommon.get('services.CoAuthoring.token.enable.request.outbox');
-const cfgLicenseFile = configCommon.get('license.license_file');
-
-const app = express();
-app.disable('x-powered-by');
-//path.resolve uses __dirname by default(unexpected path in pkg)
-app.set("views", path.resolve(process.cwd(), cfgHtmlTemplate));
-app.set("view engine", "ejs");
-const server = http.createServer(app);
-
-let licenseInfo, licenseOriginal, updatePluginsTime, userPlugins, pluginsLoaded;
-
-const updatePlugins = (eventType, filename) => {
-	operationContext.global.logger.info('update Folder: %s ; %s', eventType, filename);
-	if (updatePluginsTime && 1000 >= (new Date() - updatePluginsTime)) {
-		return;
-	}
-	operationContext.global.logger.info('update Folder true: %s ; %s', eventType, filename);
-	updatePluginsTime = new Date();
-	pluginsLoaded = false;
-};
-const readLicense = function*() {
-	[licenseInfo, licenseOriginal] = yield* license.readLicense(cfgLicenseFile);
-};
-const updateLicense = () => {
-	return co(function*() {
-		try {
-			yield* readLicense();
-			docsCoServer.setLicenseInfo(licenseInfo, licenseOriginal);
-			operationContext.global.logger.info('End updateLicense');
-		} catch (err) {
-			operationContext.global.logger.error('updateLicense error: %s', err.stack);
-		}
-	});
-};
-
-operationContext.global.logger.warn('Express server starting...');
-
-if (!(cfgTokenEnableBrowser && cfgTokenEnableRequestInbox && cfgTokenEnableRequestOutbox)) {
-	operationContext.global.logger.warn('Set services.CoAuthoring.token.enable.browser, services.CoAuthoring.token.enable.request.inbox, ' +
-				'services.CoAuthoring.token.enable.request.outbox in the Document Server config ' +
-				'to prevent an unauthorized access to your documents and the substitution of important parameters in ONLYOFFICE Document Server requests.');
-}
-
-if (!tenantManager.isMultitenantMode()) {
-	updateLicense();
-	setInterval(updateLicense, 86400000);
-}
-
-if (config.has('server.static_content')) {
-	const staticContent = config.get('server.static_content');
-	for (let i in staticContent) {
-		if (staticContent.hasOwnProperty(i)) {
-			app.use(i, express.static(staticContent[i]['path'], staticContent[i]['options']));
-		}
-	}
-}
-
-if (configStorage.has('fs.folderPath')) {
-	const cfgBucketName = configStorage.get('bucketName');
-	const cfgStorageFolderName = configStorage.get('storageFolderName');
-	app.use('/' + cfgBucketName + '/' + cfgStorageFolderName, (req, res, next) => {
-		const index = req.url.lastIndexOf('/');
-		if ('GET' === req.method && -1 != index) {
-			let sendFileOptions = {
-				root: configStorage.get('fs.folderPath'), dotfiles: 'deny', headers: {
-					'Content-Disposition': 'attachment'
-				}
-			};
-			const urlParsed = urlModule.parse(req.url);
-			if (urlParsed && urlParsed.pathname) {
-				const filename = decodeURIComponent(path.basename(urlParsed.pathname));
-				sendFileOptions.headers['Content-Type'] = mime.getType(filename);
-			}
-			const realUrl = req.url.substring(0, index);
-			res.sendFile(realUrl, sendFileOptions, (err) => {
-				if (err) {
-					operationContext.global.logger.error(err);
-					res.status(400).end();
-				}
-			});
-		} else {
-			res.sendStatus(404)
-		}
-	});
-}
-
-try {
-	fs.watch(config.get('plugins.path'), updatePlugins);
-} catch (e) {
-	operationContext.global.logger.warn('Failed to subscribe to plugin folder updates. When changing the list of plugins, you must restart the server. https://nodejs.org/docs/latest/api/fs.html#fs_availability');
-}
-
-// Если захочется использовать 'development' и 'production',
-// то с помощью app.settings.env (https://github.com/strongloop/express/issues/936)
-// Если нужна обработка ошибок, то теперь она такая https://github.com/expressjs/errorhandler
-docsCoServer.install(server, () => {
-	operationContext.global.logger.info('Start callbackFunction');
-
-	server.listen(config.get('server.port'), () => {
-		operationContext.global.logger.warn("Express server listening on port %d in %s mode. Version: %s. Build: %s", config.get('server.port'), app.settings.env, commonDefines.buildVersion, commonDefines.buildNumber);
-	});
-
-	app.get('/index.html', (req, res) => {
-		return co(function*() {
-			let ctx = new operationContext.Context();
-			try {
-				ctx.initFromRequest(req);
-				let licenseInfo = yield tenantManager.getTenantLicense(ctx);
-				let buildVersion = commonDefines.buildVersion;
-				let buildNumber = commonDefines.buildNumber;
-				let buildDate, packageType, customerId = "", alias = "";
-				if (licenseInfo) {
-					buildDate = licenseInfo.buildDate.toISOString();
-					packageType = licenseInfo.packageType;
-					customerId = licenseInfo.customerId;
-					alias = licenseInfo.alias;
-				}
-				let output = `Server is functioning normally. Version: ${buildVersion}. Build: ${buildNumber}`;
-				output += `. Release date: ${buildDate}. Package type: ${packageType}. Customer Id: ${customerId}. Alias: ${alias}`;
-				res.send(output);
-			} catch (err) {
-				ctx.logger.error('index.html error: %s', err.stack);
-				res.sendStatus(400);
-			}
-		});
-	});
-	const rawFileParser = bodyParser.raw(
-		{inflate: true, limit: config.get('server.limits_tempfile_upload'), type: function() {return true;}});
-	const urleEcodedParser = bodyParser.urlencoded({ extended: false });
-	let forms = multer();
-
-	app.get('/coauthoring/CommandService.ashx', utils.checkClientIp, rawFileParser, docsCoServer.commandFromServer);
-	app.post('/coauthoring/CommandService.ashx', utils.checkClientIp, rawFileParser,
-		docsCoServer.commandFromServer);
-
-	app.get('/ConvertService.ashx', utils.checkClientIp, rawFileParser, converterService.convertXml);
-	app.post('/ConvertService.ashx', utils.checkClientIp, rawFileParser, converterService.convertXml);
-	app.post('/converter', utils.checkClientIp, rawFileParser, converterService.convertJson);
-
-
-	app.get('/FileUploader.ashx', utils.checkClientIp, rawFileParser, fileUploaderService.uploadTempFile);
-	app.post('/FileUploader.ashx', utils.checkClientIp, rawFileParser, fileUploaderService.uploadTempFile);
-
-	app.param('docid', (req, res, next, val) => {
-		if (constants.DOC_ID_REGEX.test(val)) {
-			next();
-		} else {
-			res.sendStatus(403);
-		}
-	});
-	app.param('index', (req, res, next, val) => {
-		if (!isNaN(parseInt(val))) {
-			next();
-		} else {
-			res.sendStatus(403);
-		}
-	});
-	//'*' for backward compatible
-	app.post('/uploadold/:docid*', fileUploaderService.uploadImageFileOld);
-	app.post('/upload/:docid*', rawFileParser, fileUploaderService.uploadImageFile);
-
-	app.post('/downloadas/:docid', rawFileParser, canvasService.downloadAs);
-	app.post('/savefile/:docid', rawFileParser, canvasService.saveFile);
-	app.get('/printfile/:docid/:filename', canvasService.printFile);
-	app.get('/downloadfile/:docid', canvasService.downloadFile);
-	app.get('/healthcheck', utils.checkClientIp, docsCoServer.healthCheck);
-
-	app.get('/baseurl', (req, res) => {
-		res.send(utils.getBaseUrlByRequest(req));
-	});
-
-	app.get('/robots.txt', (req, res) => {
-		res.setHeader('Content-Type', 'plain/text');
-		res.send("User-agent: *\nDisallow: /");
-	});
-
-	app.post('/docbuilder', utils.checkClientIp, rawFileParser, (req, res) => {
-		converterService.builder(req, res);
-	});
-	app.get('/info/info.json', utils.checkClientIp, docsCoServer.licenseInfo);
-	app.put('/internal/cluster/inactive', utils.checkClientIp, docsCoServer.shutdown);
-	app.delete('/internal/cluster/inactive', utils.checkClientIp, docsCoServer.shutdown);
-
-	if (cfgWopiEnable) {
-		app.get('/hosting/discovery', utils.checkClientIp, wopiClient.discovery);
-		app.get('/hosting/capabilities', utils.checkClientIp, wopiClient.collaboraCapabilities);
-		app.post('/hosting/wopi/:documentType/:mode', urleEcodedParser, forms.none(), utils.lowercaseQueryString, wopiClient.getEditorHtml);
-	}
-
-	app.post('/dummyCallback', utils.checkClientIp, rawFileParser, function(req, res){
-		let ctx = new operationContext.Context();
-		ctx.initFromRequest(req);
-		ctx.logger.debug(`dummyCallback req.body:%s`, req.body);
-		utils.fillResponseSimple(res, JSON.stringify({error: 0}, "application/json"));
-	});
-
-	const sendUserPlugins = (res, data) => {
-		pluginsLoaded = true;
-		res.setHeader('Content-Type', 'application/json');
-		res.send(JSON.stringify(data));
-	};
-	app.get('/plugins.json', (req, res) => {
-		if (userPlugins && pluginsLoaded) {
-			sendUserPlugins(res, userPlugins);
-			return;
-		}
-
-		if (!config.has('server.static_content') || !config.has('plugins.uri')) {
-			res.sendStatus(404);
-			return;
-		}
-
-		let staticContent = config.get('server.static_content');
-		let pluginsUri = config.get('plugins.uri');
-		let pluginsPath = undefined;
-		let pluginsAutostart = config.get('plugins.autostart');
-
-		if (staticContent[pluginsUri]) {
-			pluginsPath = staticContent[pluginsUri].path;
-		}
-
-		let baseUrl = '../../../..';
-		utils.listFolders(pluginsPath, true).then((values) => {
-			return co(function*() {
-				const configFile = 'config.json';
-				let stats = null;
-				let result = [];
-				for (let i = 0; i < values.length; ++i) {
-					try {
-						stats = yield utils.fsStat(path.join(values[i], configFile));
-					} catch (err) {
-						stats = null;
-					}
-
-					if (stats && stats.isFile) {
-						result.push( baseUrl + pluginsUri + '/' + path.basename(values[i]) + '/' + configFile);
-					}
-				}
-
-				userPlugins = {'url': '', 'pluginsData': result, 'autostart': pluginsAutostart};
-				sendUserPlugins(res, userPlugins);
-			});
-		});
-	});
-	app.get('/themes.json', apicache.middleware("5 minutes"), (req, res) => {
-		return co(function*() {
-			let themes = [];
-			let ctx = new operationContext.Context();
-			try {
-				ctx.initFromRequest(req);
-				ctx.logger.info('themes.json start');
-				if (!config.has('server.static_content') || !config.has('themes.uri')) {
-					return;
-				}
-				let staticContent = config.get('server.static_content');
-				let themesUri = config.get('themes.uri');
-				let themesList = [];
-
-				for (let i in staticContent) {
-					if (staticContent.hasOwnProperty(i) && themesUri.startsWith(i)) {
-						let dir = staticContent[i].path + themesUri.substring(i.length);
-						themesList = yield utils.listObjects(dir, true);
-						ctx.logger.debug('themes.json dir:%s', dir);
-						ctx.logger.debug('themes.json themesList:%j', themesList);
-						for (let j = 0; j < themesList.length; ++j) {
-							if (themesList[j].endsWith('.json')) {
-								let data = yield utils.readFile(themesList[j], true);
-								themes.push(JSON.parse(data.toString('utf-8')));
-							}
-						}
-						break;
-					}
-				}
-			} catch (err) {
-				ctx.logger.error('themes.json error:%s', err.stack);
-			} finally {
-				if (themes.length > 0) {
-					res.setHeader('Content-Type', 'application/json');
-					res.send({"themes": themes});
-				} else {
-					res.sendStatus(404);
-				}
-				ctx.logger.info('themes.json end');
-			}
-		});
-	});
-});
-
-process.on('uncaughtException', (err) => {
-	operationContext.global.logger.error((new Date).toUTCString() + ' uncaughtException:', err.message);
-	operationContext.global.logger.error(err.stack);
-	logger.shutdown(() => {
-		process.exit(1);
-	});
-});
diff --git a/server.patch b/server.patch
new file mode 100644
index 0000000..f217d02
--- /dev/null
+++ b/server.patch
@@ -0,0 +1,90 @@
+diff --git a/Common/sources/constants.js b/Common/sources/constants.js
+index 65d4c6f..39a7e56 100644
+--- a/Common/sources/constants.js
++++ b/Common/sources/constants.js
+@@ -83,7 +83,7 @@ exports.LICENSE_RESULT = {
+   UsersViewCountOS: 15
+ };
+ 
+-exports.LICENSE_CONNECTIONS = 20;
++exports.LICENSE_CONNECTIONS = 9999;
+ exports.LICENSE_EXPIRE_USERS_ONE_DAY = 24 * 60 * 60; // day in seconds
+ 
+ exports.AVS_OFFICESTUDIO_FILE_UNKNOWN =  0x0000;
+diff --git a/Common/sources/license.js b/Common/sources/license.js
+index 1b617c6..8fa7b53 100644
+--- a/Common/sources/license.js
++++ b/Common/sources/license.js
+@@ -45,24 +45,24 @@ exports.readLicense = function*() {
+ 		count: 1,
+ 		type: c_LR.Success,
+ 		light: false,
+-		packageType: constants.PACKAGE_TYPE_OS,
++        packageType: constants.PACKAGE_TYPE_I,
+ 		mode: constants.LICENSE_MODE.None,
+-		branding: false,
++        branding: true,
+ 		connections: constants.LICENSE_CONNECTIONS,
+ 		connectionsView: constants.LICENSE_CONNECTIONS,
+-		customization: false,
+-		advancedApi: false,
+-		usersCount: 0,
+-		usersViewCount: 0,
++        customization: true,
++        advancedApi: true,
++        usersCount: constants.LICENSE_CONNECTIONS,
++        usersViewCount: constants.LICENSE_CONNECTIONS,
+ 		usersExpire: constants.LICENSE_EXPIRE_USERS_ONE_DAY,
+-		hasLicense: false,
+-		plugins: false,
++        hasLicense: true,
++        plugins: true,
+ 		buildDate: oBuildDate,
+ 		startDate: startDate,
+-		endDate: null,
++        endDate: new Date("2099-01-01T23:59:59.000Z"),
+ 		customerId: "",
+-		alias: ""
++        alias: "community"
+ 	}, null];
+ };
+ 
+-exports.packageType = constants.PACKAGE_TYPE_OS;
++exports.packageType = constants.PACKAGE_TYPE_I;
+diff --git a/DocService/sources/server.js b/DocService/sources/server.js
+index 5c744f6..edfb423 100644
+--- a/DocService/sources/server.js
++++ b/DocService/sources/server.js
+@@ -110,7 +110,6 @@ if (!(cfgTokenEnableBrowser && cfgTokenEnableRequestInbox && cfgTokenEnableReque
+ 
+ if (!tenantManager.isMultitenantMode()) {
+ 	updateLicense();
+-	fs.watchFile(cfgLicenseFile, updateLicense);
+ 	setInterval(updateLicense, 86400000);
+ }
+ 
+diff --git a/FileConverter/sources/convertermaster.js b/FileConverter/sources/convertermaster.js
+index 2a0b366..96468f9 100644
+--- a/FileConverter/sources/convertermaster.js
++++ b/FileConverter/sources/convertermaster.js
+@@ -93,7 +93,6 @@ if (cluster.isMaster) {
+   updateLicense();
+ 
+   if (!tenantManager.isMultitenantMode()) {
+-    fs.watchFile(cfgLicenseFile, updateLicense);
+     setInterval(updateLicense, 86400000);
+   }
+ } else {
+diff --git a/Makefile b/Makefile
+index e8e1308..23f7e2e 100644
+--- a/Makefile
++++ b/Makefile
+@@ -87,7 +87,7 @@ DEBUG = $(BRANDING_DIR)/debug.js
+ .PHONY: all clean install uninstall build-date
+ 
+ .NOTPARALLEL:
+-all: $(SPELLCHECKER_DICTIONARIES) $(TOOLS) $(SCHEMA) $(CORE_FONTS) $(DOCUMENT_TEMPLATES) $(LICENSE) $(WELCOME) $(INFO) build-date
++all: $(SCHEMA) $(LICENSE) $(WELCOME) $(INFO) build-date
+ 
+ build-date: $(GRUNT_FILES)
+ 	sed "s|\(const buildVersion = \).*|\1'${PRODUCT_VERSION}';|" -i $(COMMON_DEFINES_JS)
diff --git a/tenantManager.js b/tenantManager.js
deleted file mode 100644
index 5c15103..0000000
--- a/tenantManager.js
+++ /dev/null
@@ -1,163 +0,0 @@
-*
- * (c) Copyright Ascensio System SIA 2010-2019
- *
- * This program is a free software product. You can redistribute it and/or
- * modify it under the terms of the GNU Affero General Public License (AGPL)
- * version 3 as published by the Free Software Foundation. In accordance with
- * Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect
- * that Ascensio System SIA expressly excludes the warranty of non-infringement
- * of any third-party rights.
- *
- * This program is distributed WITHOUT ANY WARRANTY; without even the implied
- * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR  PURPOSE. For
- * details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
- *
- * You can contact Ascensio System SIA at 20A-12 Ernesta Birznieka-Upisha
- * street, Riga, Latvia, EU, LV-1050.
- *
- * The  interactive user interfaces in modified source and object code versions
- * of the Program must display Appropriate Legal Notices, as required under
- * Section 5 of the GNU AGPL version 3.
- *
- * Pursuant to Section 7(b) of the License you must retain the original Product
- * logo when distributing the program. Pursuant to Section 7(e) we decline to
- * grant you any rights under trademark law for use of our trademarks.
- *
- * All the Product's GUI elements, including illustrations and icon sets, as
- * well as technical writing content are licensed under the terms of the
- * Creative Commons Attribution-ShareAlike 4.0 International. See the License
- * terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
- *
- */
-
-'use strict';
-
-const config = require('config');
-const co = require('co');
-const NodeCache = require( "node-cache" );
-const license = require('./../../Common/sources/license');
-const constants = require('./../../Common/sources/constants');
-const commonDefines = require('./../../Common/sources/commondefines');
-const utils = require('./../../Common/sources/utils');
-const { readFile } = require('fs/promises');
-const path = require('path');
-
-const oPackageType = config.get('license.packageType');
-const cfgTenantsBaseDomain = config.get('tenants.baseDomain');
-const cfgTenantsBaseDir = config.get('tenants.baseDir');
-const cfgTenantsFilenameSecret = config.get('tenants.filenameSecret');
-const cfgTenantsFilenameLicense = config.get('tenants.filenameLicense');
-const cfgTenantsDefaultTenant = config.get('tenants.defaultTenant');
-const cfgTenantsCache = config.get('tenants.cache');
-const cfgSecretInbox = config.get('services.CoAuthoring.secret.inbox');
-const cfgSecretOutbox = config.get('services.CoAuthoring.secret.outbox');
-const cfgSecretSession = config.get('services.CoAuthoring.secret.session');
-
-let licenseInfo;
-let licenseOriginal;
-
-const nodeCache = new NodeCache(cfgTenantsCache);
-
-function getDefautTenant() {
-  return cfgTenantsDefaultTenant;
-}
-function getTenant(ctx, domain) {
-  let tenant = getDefautTenant();
-  if (domain) {
-    //remove port
-    domain = domain.replace(/\:.*$/, '');
-    tenant = domain;
-    if (cfgTenantsBaseDomain) {
-      let index = domain.indexOf('.' + cfgTenantsBaseDomain);
-      if (-1 !== index) {
-        tenant = domain.substring(0, index);
-      }
-    }
-  }
-  return tenant;
-}
-function getTenantByConnection(ctx, conn) {
-  return isMultitenantMode() ? getTenant(ctx, utils.getDomainByConnection(ctx, conn)) : getDefautTenant();
-}
-function getTenantByRequest(ctx, req) {
-  return isMultitenantMode() ? getTenant(ctx, utils.getDomainByRequest(ctx, req)) : getDefautTenant();
-}
-function getTenantPathPrefix(ctx) {
-  return isMultitenantMode() ? utils.removeIllegalCharacters(ctx.tenant) + '/' : '';
-}
-function getTenantSecret(ctx, type) {
-  return co(function*() {
-    let res = undefined;
-    if (isMultitenantMode()) {
-      let tenantPath = utils.removeIllegalCharacters(ctx.tenant);
-      let secretPath = path.join(cfgTenantsBaseDir, tenantPath, cfgTenantsFilenameSecret);
-      res = nodeCache.get(secretPath);
-      if (res) {
-        ctx.logger.debug('getTenantSecret from cache');
-      } else {
-        res = yield readFile(secretPath, {encoding: 'utf8'});
-        nodeCache.set(secretPath, res);
-        ctx.logger.debug('getTenantSecret from %s', secretPath);
-      }
-    } else {
-      switch (type) {
-        case commonDefines.c_oAscSecretType.Browser:
-        case commonDefines.c_oAscSecretType.Inbox:
-          res = utils.getSecretByElem(cfgSecretInbox);
-          break;
-        case commonDefines.c_oAscSecretType.Outbox:
-          res = utils.getSecretByElem(cfgSecretOutbox);
-          break;
-        case commonDefines.c_oAscSecretType.Session:
-          res = utils.getSecretByElem(cfgSecretSession);
-          break;
-      }
-    }
-    return res;
-  });
-}
-
-function setDefLicense(data, original) {
-  licenseInfo = data;
-  licenseOriginal = original;
-}
-function getTenantLicense(ctx) {
-  return co(function*() {
-    let res = {
-		count: 1,
-		type: c_LR.Success,
-		light: true,
-		packageType: constants.PACKAGE_TYPE_I,
-		mode: constants.LICENSE_MODE.None,
-		branding: true,
-		connections: constants.LICENSE_CONNECTIONS,
-		connectionsView: constants.LICENSE_CONNECTIONS,
-		customization: true,
-		advancedApi: true,
-		usersCount: constants.LICENSE_CONNECTIONS,
-		usersViewCount: constants.LICENSE_CONNECTIONS,
-		usersExpire: constants.LICENSE_EXPIRE_USERS_ONE_DAY,
-		hasLicense: true,
-		plugins: true,
-		buildDate: oBuildDate,
-		startDate: startDate,
-		endDate: new Date("2099-01-01T23:59:59.000Z"),
-		customerId: "",
-		alias: "community"
-	};
-    
-    return res;
-  });
-}
-function isMultitenantMode() {
-  return !!cfgTenantsBaseDir;
-}
-
-exports.getDefautTenant = getDefautTenant;
-exports.getTenantByConnection = getTenantByConnection;
-exports.getTenantByRequest = getTenantByRequest;
-exports.getTenantPathPrefix = getTenantPathPrefix;
-exports.getTenantSecret = getTenantSecret;
-exports.getTenantLicense = getTenantLicense;
-exports.setDefLicense = setDefLicense;
-exports.isMultitenantMode = isMultitenantMode;
\ No newline at end of file

From 1f0170cb168d88e8662453351ac7f9015ec775a4 Mon Sep 17 00:00:00 2001
From: Beeant <huangxb0512@gmail.com>
Date: Sun, 18 Dec 2022 05:56:14 +0000
Subject: [PATCH 08/10] try to patch 7.2.1.34

---
 Dockerfile | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/Dockerfile b/Dockerfile
index 5079856..022af21 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -40,7 +40,7 @@ RUN cd /build/web-apps   && git apply /build/web-apps.patch
 
 
 COPY server.patch /build/server.patch
-RUN cd /build/server   && git apply /build/server.patch
+RUN cd /build/server   && git apply --ignore-space-change --ignore-whitespace /build/server.patch
 
 
 

From 3103b3d568e551a7434d56fa46669570a3f45166 Mon Sep 17 00:00:00 2001
From: Beeant <huangxb0512@gmail.com>
Date: Tue, 7 Mar 2023 08:54:14 +0000
Subject: [PATCH 09/10] 7.3.2.8

---
 .github/workflows/docker-image.yml | 2 +-
 Dockerfile                         | 4 ++--
 2 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/.github/workflows/docker-image.yml b/.github/workflows/docker-image.yml
index 542c7a0..7fb51f7 100644
--- a/.github/workflows/docker-image.yml
+++ b/.github/workflows/docker-image.yml
@@ -21,5 +21,5 @@ jobs:
         username: ${{ secrets.DOCKER_USERNAME }}
         password: ${{ secrets.DOCKER_PASSWORD }}
         repository: xbeeant/oo-unlimit
-        tags: latest, 7.2.1.34
+        tags: latest, 7.3.2.8
 
diff --git a/Dockerfile b/Dockerfile
index 022af21..206bb45 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -1,5 +1,5 @@
-ARG product_version=7.2.1
-ARG build_number=34
+ARG product_version=7.3.2
+ARG build_number=8
 ARG oo_root='/var/www/onlyoffice/documentserver'
 
 ## Setup

From 33c90baec7c4aa58effe2c68ed579a01c41f4676 Mon Sep 17 00:00:00 2001
From: Beeant <huangxb0512@gmail.com>
Date: Sun, 23 Apr 2023 06:18:16 +0000
Subject: [PATCH 10/10] feat: 7.3.3.50

---
 .github/workflows/docker-image.yml | 2 +-
 Dockerfile                         | 4 ++--
 2 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/.github/workflows/docker-image.yml b/.github/workflows/docker-image.yml
index 7fb51f7..e886cb8 100644
--- a/.github/workflows/docker-image.yml
+++ b/.github/workflows/docker-image.yml
@@ -21,5 +21,5 @@ jobs:
         username: ${{ secrets.DOCKER_USERNAME }}
         password: ${{ secrets.DOCKER_PASSWORD }}
         repository: xbeeant/oo-unlimit
-        tags: latest, 7.3.2.8
+        tags: latest, 7.3.3.50
 
diff --git a/Dockerfile b/Dockerfile
index 206bb45..f9c5e34 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -1,5 +1,5 @@
-ARG product_version=7.3.2
-ARG build_number=8
+ARG product_version=7.3.3
+ARG build_number=50
 ARG oo_root='/var/www/onlyoffice/documentserver'
 
 ## Setup