Improved web application performance.

Ylian Saint-Hilaire committed Jan 22, 2019 at 11:44 UTC 6fbcb8ea4d4194ab04ed3d1bd48b0d551141bc38
5 files changed +95 -106
meshagent.js
+4
@@ -163,6 +163,10 @@ module.exports.CreateMeshAgent = function (parent, db, ws, req, args, domain) {
163 if (err) { return console.error(err); }
164 obj.agentUpdate = { oldHash: agenthash, ptr: 0, buf: Buffer.alloc(agentUpdateBlockSize + 4), fd: fd };
165
166 + // MeshCommand_CoreModule, ask mesh agent to clear the core.
167 + // The new core will only be sent after the agent updates.
168 + obj.send(obj.common.ShortToStr(10) + obj.common.ShortToStr(0));
169 +
170 // We got the agent file open on the server side, tell the agent we are sending an update starting with the SHA384 hash of the result
171 //console.log("Agent update file open.");
172 obj.send(obj.common.ShortToStr(13) + obj.common.ShortToStr(0)); // Command 13, start mesh agent download
package.json
+1 -1
@@ -1,6 +1,6 @@
1 {
2 "name": "meshcentral",
3 - "version": "0.2.6-o",
3 + "version": "0.2.6-q",
4 "keywords": [
5 "Remote Management",
6 "Intel AMT",
swarmserver.js
+26 -14
@@ -22,6 +22,7 @@ module.exports.CreateSwarmServer = function (parent, db, args, certificates) {
22 obj.certificates = certificates;
23 obj.legacyAgentConnections = {};
24 obj.migrationAgents = {};
25 + obj.agentActionCount = {};
26 const common = require('./common.js');
27 //const net = require('net');
28 const tls = require('tls');
@@ -170,7 +171,7 @@ module.exports.CreateSwarmServer = function (parent, db, args, certificates) {
171 if (!socket.tag.clientCert.subject) { /*console.log("Swarm Connection, no client cert: " + socket.remoteAddress);*/ socket.write('HTTP/1.1 200 OK\r\nContent-Type: text/plain\r\nConnection: close\r\n\r\nMeshCentral2 legacy swarm server.\r\nNo client certificate given.'); socket.end(); return; }
172
173 try {
173 - // Parse all of the APF data we can
174 + // Parse all of the agent binary command data we can
175 var l = 0;
176 do { l = ProcessCommand(socket); if (l > 0) { socket.tag.accumulator = socket.tag.accumulator.substring(l); } } while (l > 0);
177 if (l < 0) { socket.end(); }
@@ -195,21 +196,32 @@ module.exports.CreateSwarmServer = function (parent, db, args, certificates) {
196 if ((nodeblock != null) && (nodeblock.agenttype != null) && (nodeblock.agentversion != null)) {
197 Debug(3, 'Swarm:NODEPUSH:' + JSON.stringify(nodeblock));
198
198 - // Figure out what is the next agent version we need.
199 - var nextAgentVersion = 0;
200 - if (nodeblock.agentversion < 201) { nextAgentVersion = 201; } // If less then 201, move to transitional MC1 agent.
201 - if (nodeblock.agentversion == 201) { nextAgentVersion = 202; } // If at 201, move to first MC2 agent.
202 -
203 - // See if we need to start the agent update
204 - if ((nextAgentVersion > 0) && (obj.migrationAgents[nodeblock.agenttype] != null) && (obj.migrationAgents[nodeblock.agenttype][nextAgentVersion] != null)) {
205 - // Start the update
206 - socket.tag.update = obj.migrationAgents[nodeblock.agenttype][nextAgentVersion];
207 - socket.tag.updatePtr = 0;
208 - console.log('Performing legacy agent update from ' + nodeblock.agentversion + '.' + nodeblock.agenttype + ' to ' + socket.tag.update.ver + '.' + socket.tag.update.arch + ' on ' + nodeblock.agentname + '.');
209 - obj.SendCommand(socket, LegacyMeshProtocol.GETSTATE, common.IntToStr(5) + common.IntToStr(0)); // agent.SendQuery(5, 0); // Start the agent download
199 + // Check if this agent is asking of updates over and over again.
200 + var actionCount = obj.agentActionCount[nodeblock.nodeidhex];
201 + if (actionCount == null) { actionCount = 0; }
202 + if (actionCount > 2) {
203 + // Already tried to update this agent two times, something is not right.
204 + //console.log('SWARM: ' + actionCount + ' update actions on ' + nodeblock.nodeidhex + ', holding.');
205 } else {
211 - console.log('No legacy agent update for ' + nodeblock.agentversion + '.' + nodeblock.agenttype + ' on ' + nodeblock.agentname + '.');
206 + // Figure out what is the next agent version we need.
207 + var nextAgentVersion = 0;
208 + if (nodeblock.agentversion < 201) { nextAgentVersion = 201; } // If less then 201, move to transitional MC1 agent.
209 + if (nodeblock.agentversion == 201) { nextAgentVersion = 202; } // If at 201, move to first MC2 agent.
210 +
211 + // See if we need to start the agent update
212 + if ((nextAgentVersion > 0) && (obj.migrationAgents[nodeblock.agenttype] != null) && (obj.migrationAgents[nodeblock.agenttype][nextAgentVersion] != null)) {
213 + // Start the update
214 + socket.tag.update = obj.migrationAgents[nodeblock.agenttype][nextAgentVersion];
215 + socket.tag.updatePtr = 0;
216 + //console.log('Performing legacy agent update from ' + nodeblock.agentversion + '.' + nodeblock.agenttype + ' to ' + socket.tag.update.ver + '.' + socket.tag.update.arch + ' on ' + nodeblock.agentname + '.');
217 + obj.SendCommand(socket, LegacyMeshProtocol.GETSTATE, common.IntToStr(5) + common.IntToStr(0)); // agent.SendQuery(5, 0); // Start the agent download
218 + } else {
219 + //console.log('No legacy agent update for ' + nodeblock.agentversion + '.' + nodeblock.agenttype + ' on ' + nodeblock.agentname + '.');
220 + }
221 }
222 +
223 + // Mark this agent
224 + obj.agentActionCount[nodeblock.nodeidhex] = ++actionCount;
225 }
226 break;
227 }
views/default-mobile.handlebars
+1 -1
@@ -2334,7 +2334,7 @@
2334 files.sendText({ action: 'ls', reqid: 1, path: '' });
2335 break;
2336 default:
2337 - console.log('Unknown onFilesStateChange state', state);
2337 + //console.log('Unknown onFilesStateChange state', state);
2338 break;
2339 }
2340 }
views/default.handlebars
+63 -90
@@ -162,7 +162,7 @@
162 <td id=devListToolbar class=style14>
163 &nbsp;&nbsp;<input type="button" id="SelectAllButton" onclick="selectallButtonFunction();" value="Select All" />&nbsp;
164 <input type=button id=GroupActionButton disabled="disabled" value="Group Action" onclick=groupActionFunction() />&nbsp;
165 - <input id=SearchInput type=text style=width:120px placeholder=Filter onchange=onSearchInputChanged() onkeyup=onSearchInputChanged() autocomplete=off onfocus=onSearchFocus(1) onblur=onSearchFocus(0) />&nbsp;
165 + <input id=SearchInput type=text style=width:120px placeholder=Filter onchange=masterUpdate(5) onkeyup=masterUpdate(5) autocomplete=off onfocus=onSearchFocus(1) onblur=onSearchFocus(0) />&nbsp;
166 <input type=checkbox id=RealNameCheckBox onclick=onRealNameCheckBox() /><span title="Show devices operating system name">OS Name</span>
167 </td>
168 <td id=kvmListToolbar class=style14 style=height:100%>
@@ -188,7 +188,7 @@
188 </div>
189 <div style=float:right id=devListToolbarSort>
190 Sort
191 - <select id=sortselect onchange=onSortSelectChange()>
191 + <select id=sortselect onchange=masterUpdate(6)>
192 <option>Group</option>
193 <option>Power</option>
194 <option>Device</option>
@@ -920,8 +920,8 @@
920 document.onkeypress = ondockeypress;
921 document.onkeydown = ondockeydown;
922 document.onkeyup = ondockeyup;
923 - window.onresize = center;
924 - center();
923 + window.onresize = function () { masterUpdate(512); }
924 + masterUpdate(512);
925
926 // Connect to the mesh server
927 meshserver = MeshServerCreateControl(domainUrl);
@@ -939,8 +939,7 @@
939 Q('DeskControl').checked = (getstore('DeskControl', 1) == 1);
940
941 // Display the page devices
942 - onSortSelectChange(true);
943 - onSearchInputChanged();
942 + masterUpdate(3)
943 for (var j = 1; j < 5; j++) { Q('devViewButton' + j).classList.remove('viewSelectorSel'); }
944 Q('devViewButton' + Q('viewselect').value).classList.add('viewSelectorSel');
945
@@ -1018,7 +1017,8 @@
1017 QV('UserDummyMenuSpan', (xxcurrentView < 10) && webPageFullScreen);
1018 QV('page_leftbar', true);
1019 }
1021 - center();
1020 + //center();
1021 + masterUpdate(512);
1022 QV('body', true);
1023 }
1024
@@ -1106,31 +1106,28 @@
1106 if ((siteRights & 21) != 0) { meshserver.send({ action: 'serverstats', interval: 10000 }); }
1107 }
1108
1109 - // When the list of events needs to be updated, put a small delay so that the browser
1110 - // performs much less work when event storms happen.
1111 - var updateEventsNaggleTimer = null;
1112 - function updateEventsNaggle() {
1113 - if (updateEventsNaggleTimer == null) {
1114 - updateEventsNaggleTimer = setTimeout(function () {
1115 - events_update();
1116 - updateEventsNaggleTimer = null;
1117 - }, 100);
1118 - }
1119 - }
1120 -
1121 - // When the list of devices needs to be updated, put a small delay so that the browser
1122 - // performs much less work when event storms happen.
1123 - var updateDevicesNaggleTimer = null;
1124 - function updateDevicesNaggle() {
1125 - if (updateDevicesNaggleTimer == null) {
1126 - updateDevicesNaggleTimer = setTimeout(function () {
1127 - onSortSelectChange(true);
1128 - drawNotifications();
1129 - onSearchInputChanged();
1130 - updateDevices();
1131 - updateMapMarkers();
1132 - updateDevicesNaggleTimer = null;
1133 - }, 100);
1109 + // To boost the speed of the web page when even floods occur, this method perform a delayed update on the web page.
1110 + var updateNaggleTimer = null;
1111 + var updateNaggleFlags = 0;
1112 + function masterUpdate(flags) {
1113 + updateNaggleFlags |= flags;
1114 + if (updateNaggleTimer == null) {
1115 + updateNaggleTimer = setTimeout(function () {
1116 + if (updateNaggleFlags & 512) { center(); }
1117 + if (updateNaggleFlags & 1) { onSearchInputChanged(); }
1118 + if (updateNaggleFlags & 2) { onSortSelectChange(true); }
1119 + if (updateNaggleFlags & 128) { updateMeshes(); }
1120 + if (updateNaggleFlags & 4) { updateDevices(); }
1121 + if (updateNaggleFlags & 8) { drawNotifications(); }
1122 + if (updateNaggleFlags & 16) { updateMapMarkers(); }
1123 + if (updateNaggleFlags & 32) { eventsUpdate(); }
1124 + if (updateNaggleFlags & 64) { refreshMap(false, true); }
1125 + if (updateNaggleFlags & 256) { drawDeviceTimeline(); }
1126 + if (updateNaggleFlags & 1024) { deviceEventsUpdate(); }
1127 + if (updateNaggleFlags & 2048) { userEventsUpdate(); }
1128 + updateNaggleTimer = null;
1129 + updateNaggleFlags = 0;
1130 + }, 150);
1131 }
1132 }
1133
@@ -1167,8 +1164,7 @@
1164 case 'meshes': {
1165 meshes = {};
1166 for (var m in message.meshes) { meshes[message.meshes[m]._id] = message.meshes[m]; }
1170 - updateMeshes();
1171 - updateDevices();
1167 + masterUpdate(4 + 128);
1168 break;
1169 }
1170 case 'files': {
@@ -1194,11 +1190,8 @@
1190 nodes.push(message.nodes[m][n]);
1191 }
1192 }
1197 - //onSortSelectChange(true);
1198 - //onSearchInputChanged();
1199 - //updateDevices();
1200 - updateDevicesNaggle();
1201 - refreshMap(false, true);
1193 + masterUpdate(1 | 2 | 4 | 64);
1194 +
1195 if (xxcurrentView == 0) { if ('{{viewmode}}' != '') { go(parseInt('{{viewmode}}')); } else { setDialogMode(0); go(1); } }
1196 if ('{{currentNode}}' != '') { gotoDevice('{{currentNode}}',parseInt('{{viewmode}}'));}
1197 break;
@@ -1208,7 +1201,7 @@
1201 powerTimelineNode = message.nodeid;
1202 powerTimeline = message.timeline;
1203 powerTimelineUpdate = Date.now() + 300000; // Update every 5 minutes
1211 - if (currentNode._id == message.nodeid) { drawDeviceTimeline(); }
1204 + if (currentNode._id == message.nodeid) { masterUpdate(256); }
1205 break;
1206 }
1207 case 'lastconnect': {
@@ -1307,14 +1300,13 @@
1300 case 'events': {
1301 if ((message.nodeid != null) && (message.nodeid == currentNode._id)) {
1302 currentDeviceEvents = message.events;
1310 - devevents_update();
1303 + masterUpdate(1024);
1304 } else if ((message.user != null) && (message.user == currentUser.name)) {
1305 currentUserEvents = message.events;
1313 - userEvents_update();
1306 + masterUpdate(2048);
1307 } else {
1308 events = message.events;
1316 - updateEventsNaggle();
1317 - //events_update();
1309 + masterUpdate(32);
1310 }
1311 break;
1312 }
@@ -1369,8 +1361,7 @@
1361 events.unshift(message.event);
1362 var eventLimit = parseInt(p3limitdropdown.value);
1363 while (events.length > eventLimit) { events.pop(); } // Remove element(s) at the end
1372 - updateEventsNaggle();
1373 - //events_update();
1364 + masterUpdate(32);
1365 }
1366 switch (message.event.action) {
1367 case 'accountcreate':
@@ -1401,8 +1392,7 @@
1392 // A new mesh was created
1393 if (message.event.links['user/' + domain + '/' + userinfo.name.toLowerCase()] != null) { // Check if this is a mesh create for a mesh we own. If site administrator, we get all messages so need to ignore some.
1394 meshes[message.event.meshid] = { _id: message.event.meshid, name: message.event.name, mtype: message.event.mtype, desc: message.event.desc, links: message.event.links };
1404 - updateMeshes();
1405 - updateDevices();
1395 + masterUpdate(4 + 128);
1396 meshserver.send({ action: 'files' });
1397 }
1398 break;
@@ -1434,8 +1424,7 @@
1424 if (xxcurrentView >= 10 && xxcurrentView < 20 && currentNode && currentNode.meshid == message.event.meshid) { setDialogMode(0); go(1); }
1425 }
1426 }
1437 - updateMeshes();
1438 - updateDevices();
1427 + masterUpdate(4 + 128);
1428 meshserver.send({ action: 'files' });
1429
1430 // If we are looking at a mesh that is now deleted, move back to "My Account"
@@ -1446,7 +1435,7 @@
1435 // Delete the mesh
1436 if (meshes[message.event.meshid]) {
1437 delete meshes[message.event.meshid];
1449 - updateMeshes();
1438 + masterUpdate(128);
1439 meshserver.send({ action: 'files' });
1440 }
1441
@@ -1454,7 +1443,7 @@
1443 var newnodes = [];
1444 for (var i in nodes) { if (nodes[i].meshid != message.event.meshid) { newnodes.push(nodes[i]); } }
1445 nodes = newnodes;
1457 - updateDevices();
1446 + masterUpdate(4);
1447
1448 // If we are looking at a mesh that is now deleted, move back to "My Account"
1449 if (xxcurrentView >= 20 && xxcurrentView < 30 && currentMesh._id == message.event.meshid) { setDialogMode(0); go(2); }
@@ -1475,11 +1464,7 @@
1464 nodes.push(node);
1465
1466 // Web page update
1478 - updateDevicesNaggle();
1479 - //onSortSelectChange(true);
1480 - //onSearchInputChanged();
1481 - //updateDevices();
1482 - //updateMapMarkers();
1467 + masterUpdate(1 | 2 | 4 | 16);
1468
1469 break;
1470 }
@@ -1496,9 +1481,7 @@
1481 nodes.splice(index, 1);
1482
1483 // Web page update
1499 - updateDevicesNaggle();
1500 - //updateDevices();
1501 - //updateMapMarkers();
1484 + masterUpdate(4 | 16);
1485 }
1486 break;
1487 }
@@ -1542,10 +1525,10 @@
1525 if (message.event.node.icon) { node.icon = message.event.node.icon; }
1526
1527 // Web page update
1545 - updateDevicesNaggle();
1528 //onSortSelectChange(true);
1529 //drawNotifications();
1530 //updateMapMarkers();
1531 + masterUpdate(2 | 8 | 16);
1532
1533 refreshDevice(node._id);
1534
@@ -1565,9 +1548,7 @@
1548 node.pwr = message.event.pwr;
1549
1550 // Web page update
1568 - updateDevicesNaggle();
1569 - //updateDevices();
1570 - //updateMapMarkers();
1551 + masterUpdate(4 | 16);
1552
1553 refreshDevice(node._id);
1554 }
@@ -1587,8 +1568,7 @@
1568 }
1569 case 'clearevents': {
1570 events = [];
1590 - updateEventsNaggle();
1591 - //events_update();
1571 + masterUpdate(32);
1572 break;
1573 }
1574 case 'login': {
@@ -1647,7 +1627,7 @@
1627 function onRealNameCheckBox() {
1628 showRealNames = Q('RealNameCheckBox').checked;
1629 putstore("showRealNames", showRealNames ? 1 : 0);
1650 - onSortSelectChange(true);
1630 + masterUpdate(6)
1631 return;
1632 }
1633
@@ -1657,7 +1637,7 @@
1637 Q('devViewButton' + Q('viewselect').value).classList.add('viewSelectorSel');
1638 putstore("deviceView", Q('viewselect').value);
1639 putstore("viewsize", Q('sizeselect').value);
1660 - updateDevices();
1640 + masterUpdate(4);
1641 }
1642
1643 function ondockeypress(e) {
@@ -1681,7 +1661,7 @@
1661 showRealNames = !showRealNames;
1662 Q('RealNameCheckBox').value = showRealNames;
1663 putstore("showRealNames", showRealNames ? 1 : 0);
1684 - onSortSelectChange(true);
1664 + masterUpdate(6)
1665 return;
1666 }
1667 if (e.ctrlKey == true || e.altKey == true || e.metaKey == true) return;
@@ -1694,7 +1674,7 @@
1674 } else {
1675 if (e.charCode != 0 && searchFocus == 0) { Q('SearchInput').value = ((Q('SearchInput').value + String.fromCharCode(e.charCode))); processed = 1; }
1676 }
1697 - if (processed > 0) { if (processed == 1) { onSearchInputChanged(); } return haltEvent(e); }
1677 + if (processed > 0) { if (processed == 1) { masterUpdate(5); } return haltEvent(e); }
1678 }
1679 if (Q('viewselect').value == 3) {
1680 if (e.key) {
@@ -1716,14 +1696,14 @@
1696 if (!xxdialogMode && xxcurrentView == 4) {
1697 if (e.keyCode === 8 && userSearchFocus == 0) { var x = Q('UserSearchInput').value; Q('UserSearchInput').value = (x.substring(0, x.length - 1)); processed = 1; }
1698 if (e.keyCode === 27) { Q('UserSearchInput').value = ''; processed = 1; }
1719 - if (processed > 0) { if (processed == 1) { onSearchInputChanged(); } return haltEvent(e); }
1699 + if (processed > 0) { if (processed == 1) { masterUpdate(5); } return haltEvent(e); }
1700 }
1701 if (xxdialogMode || xxcurrentView != 1 || e.ctrlKey == true || e.altKey == true || e.metaKey == true) return;
1702 var processed = 0;
1703 if (Q('viewselect').value < 3) {
1704 if (e.keyCode === 8 && searchFocus == 0) { var x = Q('SearchInput').value; Q('SearchInput').value = (x.substring(0, x.length - 1)); processed = 1; }
1705 if (e.keyCode === 27) { Q('SearchInput').value = ''; processed = 1; }
1726 - if (processed > 0) { if (processed == 1) { onSearchInputChanged(); } return haltEvent(e); }
1706 + if (processed > 0) { if (processed == 1) { masterUpdate(5); } return haltEvent(e); }
1707 }
1708 if (Q('viewselect').value == 3) {
1709 if (e.keyCode === 8 && mapSearchFocus == 0) { var x = Q('mapSearchLocation').value; Q('mapSearchLocation').value = (x.substring(0, x.length - 1)); processed = 1; }
@@ -1742,10 +1722,6 @@
1722 if (Q('viewselect').value == 3) { if ((e.keyCode === 8 && mapSearchFocus == 0) || e.keyCode === 27) { return haltEvent(e); } }
1723 }
1724
1745 - // Since the update device call can be quite frequent, we can moderate it and only call it at most 5 times a second.
1746 - var updateDevicesTimer = null;
1747 - function updateDevices() { if (updateDevicesTimer != null) return; updateDevicesTimer = setTimeout(updateDevicesEx, 200); }
1748 -
1725 // Highlights the device being hovered
1726 function devMouseHover(element, over) {
1727 var view = Q('viewselect').value;
@@ -1778,8 +1754,8 @@
1754 var deviceHeaderCount;
1755 var deviceHeaders = {};
1756 var oldviewmode = 0;
1781 - function updateDevicesEx() {
1782 - if (updateDevicesTimer != null) { clearTimeout(updateDevicesTimer); updateDevicesTimer = null; }
1757 + function updateDevices() {
1758 + if (xxcurrentView != 1) return;
1759 var r = '', c = 0, current = null, count = 0, displayedMeshes = {}, view = Q('viewselect').value, groups = {}, groupCount = {};
1760 QV('xdevices', view < 4);
1761 QV('xdevicesmap', view == 4);
@@ -2444,7 +2420,6 @@
2420 function onSortSelectChange(skipsave) {
2421 sort = document.getElementById("sortselect").selectedIndex;
2422 if (!skipsave) { putstore("sort", sort); }
2447 - updateDevicesEx();
2423 }
2424
2425 function meshSort(a, b) { if (a.meshnamel > b.meshnamel) return 1; if (a.meshnamel < b.meshnamel) return -1; if (a.meshid == b.meshid) { if (showRealNames == true) { if (a.rnamel > b.rnamel) return 1; if (a.rnamel < b.rnamel) return -1; return 0; } else { if (a.namel > b.namel) return 1; if (a.namel < b.namel) return -1; return 0; } } return 0; }
@@ -2478,10 +2453,8 @@
2453 }
2454 } catch (ex) { for (var d in nodes) { nodes[d].v = true; } }
2455 }
2481 - updateDevices();
2456 }
2457
2484 -
2458 var contextelement = null;
2459 function handleContextMenu(event) {
2460 hideContextMenu();
@@ -3302,7 +3275,7 @@
3275 QH('p10html', x);
3276
3277 // Show node last 7 days timeline
3305 - drawDeviceTimeline();
3278 + masterUpdate(256);
3279
3280 // Show bottom buttons
3281 x = '<div style=float:right;font-size:x-small>';
@@ -4460,7 +4433,7 @@
4433 files.sendText({ action: 'ls', reqid: 1, path: '' });
4434 break;
4435 default:
4463 - console.log('Unknown onFilesStateChange state', state);
4436 + //console.log('Unknown onFilesStateChange state', state);
4437 break;
4438 }
4439 }
@@ -4897,7 +4870,7 @@
4870 //
4871
4872 var currentDeviceEvents = null;
4900 - function devevents_update() {
4873 + function deviceEventsUpdate() {
4874 var x = '', dateHeader = null;
4875 for (var i in currentDeviceEvents) {
4876 var event = currentDeviceEvents[i];
@@ -5788,7 +5761,7 @@
5761 if (over == 1) { e.children[1].classList.add('g1s'); e.children[3].classList.add('g2s'); }
5762 }
5763
5791 - function events_update() {
5764 + function eventsUpdate() {
5765 var x = '', dateHeader = null;
5766 for (var i in events) {
5767 var event = events[i];
@@ -6219,7 +6192,7 @@
6192 //
6193
6194 var currentUserEvents = null;
6222 - function userEvents_update() {
6195 + function userEventsUpdate() {
6196 var x = '', dateHeader = null;
6197 for (var i in currentUserEvents) {
6198 var event = currentUserEvents[i];
@@ -6538,9 +6511,9 @@
6511
6512 function center() {
6513 QS('dialog').left = ((((getDocWidth() - 400) / 2)) + "px");
6541 - if (xxcurrentView == 11) { deskAdjust(); deskAdjust(); }
6542 - else if (xxcurrentView == 10) { drawDeviceTimeline(); }
6543 - else if (xxcurrentView == 1) { updateDevicesEx(); }
6514 + if (xxcurrentView == 11) { deskAdjust(); } //deskAdjust(); }
6515 + else if (xxcurrentView == 10) { masterUpdate(256); }
6516 + else if (xxcurrentView == 1) { masterUpdate(4); }
6517 }
6518 function messagebox(t, m) { QH('id_dialogMessage', m); setDialogMode(1, t, 1); }
6519 function statusbox(t, m) { QH('id_dialogMessage', m); setDialogMode(1, t); }
@@ -6615,7 +6588,7 @@
6588 Q(panels[i]).classList.add((x == i) ? 'style3sel' : 'style3x');
6589 }
6590
6618 - if (x == 1) updateDevicesEx();
6591 + if (x == 1) masterUpdate(4);
6592 }
6593
6594 // Generic methods