@aj-shadow/z-abs-corelayer-server 0.0.0-aj-beta.221

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (87) hide show
  1. package/.gitattributes +26 -0
  2. package/LICENSE.txt +96 -0
  3. package/README.md +5 -0
  4. package/npm-shrinkwrap.json +13 -0
  5. package/package.json +10 -0
  6. package/project/server/_build/Server-CoreLayer-server.bld +12 -0
  7. package/project/server/_build/z-abs-corelayer-server.prj +12 -0
  8. package/project/server/communication/core-protocol/decoder.js +404 -0
  9. package/project/server/communication/core-protocol/encoder.js +503 -0
  10. package/project/server/communication/messages/messages-s-to-c/message-persistent-init-response.js +14 -0
  11. package/project/server/communication/messages/messages-s-to-c/message-persistent-publish.js +16 -0
  12. package/project/server/communication/messages/messages-s-to-c/message-ws-init.js +14 -0
  13. package/project/server/communication/messages/messages-s-to-s/service-init-request.js +17 -0
  14. package/project/server/communication/messages/messages-s-to-s/service-init-response.js +18 -0
  15. package/project/server/communication/messages/messages-s-to-s/service-offer-off.js +15 -0
  16. package/project/server/communication/messages/messages-s-to-s/service-offer-on.js +15 -0
  17. package/project/server/communication/messages/messages-s-to-s/worker-init-request.js +15 -0
  18. package/project/server/data-response.js +588 -0
  19. package/project/server/high-resolution-timestamp.js +36 -0
  20. package/project/server/log/log-config.js +107 -0
  21. package/project/server/log/log-types.js +14 -0
  22. package/project/server/log/logger-console.js +36 -0
  23. package/project/server/log/logger.js +114 -0
  24. package/project/server/node/channel-input.js +65 -0
  25. package/project/server/node/channel-output.js +39 -0
  26. package/project/server/node/clients.js +80 -0
  27. package/project/server/node/connection-address.js +24 -0
  28. package/project/server/node/connection-data-ip.js +82 -0
  29. package/project/server/node/connection-data.js +25 -0
  30. package/project/server/node/const.js +44 -0
  31. package/project/server/node/external-services.js +209 -0
  32. package/project/server/node/http-cache.js +109 -0
  33. package/project/server/node/http-proxy.js +97 -0
  34. package/project/server/node/http-request-handler.js +219 -0
  35. package/project/server/node/http-server.js +36 -0
  36. package/project/server/node/http2-server.js +67 -0
  37. package/project/server/node/https-server.js +63 -0
  38. package/project/server/node/ip-client.js +98 -0
  39. package/project/server/node/ip-server.js +63 -0
  40. package/project/server/node/ip-subscription.js +46 -0
  41. package/project/server/node/message-channel.js +98 -0
  42. package/project/server/node/node-admin.js +513 -0
  43. package/project/server/node/node-data.js +25 -0
  44. package/project/server/node/node-settings.js +352 -0
  45. package/project/server/node/node-worker.js +76 -0
  46. package/project/server/node/node.js +156 -0
  47. package/project/server/node/servers.js +168 -0
  48. package/project/server/node/ws-client.js +12 -0
  49. package/project/server/node/ws-server.js +20 -0
  50. package/project/server/node/ws-web-server.js +52 -0
  51. package/project/server/node/wss-server.js +20 -0
  52. package/project/server/node/wss-web-server.js +82 -0
  53. package/project/server/path/actor-path-build.js +29 -0
  54. package/project/server/path/actor-path-content.js +51 -0
  55. package/project/server/path/actor-path-creator.js +90 -0
  56. package/project/server/path/actor-path-data.js +487 -0
  57. package/project/server/path/actor-path-dist.js +132 -0
  58. package/project/server/path/actor-path-generated.js +202 -0
  59. package/project/server/path/actor-path-project.js +181 -0
  60. package/project/server/path/actor-path.js +57 -0
  61. package/project/server/path/paths/actor-content-paths.js +34 -0
  62. package/project/server/path/paths/actor-data-paths.js +302 -0
  63. package/project/server/path/paths/actor-generated-paths.js +99 -0
  64. package/project/server/path/paths/actor-paths.js +22 -0
  65. package/project/server/plugin-base-multi.js +484 -0
  66. package/project/server/plugin-base.js +233 -0
  67. package/project/server/plugin-component.js +92 -0
  68. package/project/server/plugin-data/client/plugin_data_ClientGet.js +18 -0
  69. package/project/server/plugin-data/dialog-file/plugin_data_DialogFileGet.js +197 -0
  70. package/project/server/plugin-data/platform/plugin_data_PlatformPing.js +19 -0
  71. package/project/server/plugin-factor-protocol.js +35 -0
  72. package/project/server/plugin-factory.js +127 -0
  73. package/project/server/plugin-lock.js +164 -0
  74. package/project/server/response-queue.js +46 -0
  75. package/project/server/responses.js +20 -0
  76. package/project/server/service/plugin-service.js +264 -0
  77. package/project/server/service/service-export.js +47 -0
  78. package/project/server/service/service-manager.js +270 -0
  79. package/project/server/service/service-requests.js +49 -0
  80. package/project/server/session-cache.js +39 -0
  81. package/project/server/session.js +23 -0
  82. package/project/server/worker/worker-channel.js +175 -0
  83. package/project/server/worker/worker-core.js +58 -0
  84. package/project/server/worker/worker-main.js +165 -0
  85. package/project/server/worker/worker-pool.js +94 -0
  86. package/project/server/worker/worker-thread.js +128 -0
  87. package/project/z-abs-corelayer-server.tree +99 -0
@@ -0,0 +1,513 @@
1
+
2
+ 'use strict';
3
+
4
+
5
+ const NodeData = require('./node-data');
6
+ const ActorPath = require('../path/actor-path');
7
+ const ActorPathGenerated = require('../path/actor-path-generated');
8
+ const MessageChannel = require('./message-channel');
9
+ const ServiceAction = require('z-abs-corelayer-cs/clientServer/communication/service-action');
10
+ const CoreProtocolConst = require('z-abs-corelayer-cs/clientServer/communication/core-protocol/core-protocol-const');
11
+ require('z-abs-corelayer-cs/clientServer/debug-dashboard/log')
12
+ const ChildProcess = require('child_process');
13
+ const Fs = require('fs');
14
+ const Net = require('net');
15
+ const Path = require('path');
16
+
17
+
18
+ class NodeAdmin {
19
+ constructor(host, port, cbStatus) {
20
+ this.host = host;
21
+ this.port = port;
22
+ this.cbStatus = cbStatus;
23
+ this.messageChannels = new Map();
24
+ this.serverStatus = {
25
+ up: false,
26
+ upDate: null,
27
+ connected: false,
28
+ connectedName: ''
29
+ };
30
+ this.server = null;
31
+ this.serverUpDate = null;
32
+ this.serverDownReason = '';
33
+ this.nodeDatas = [];
34
+ this.nodesPersistent = new Map();
35
+ this.supervisorChildProcess = null;
36
+ this.nodesAtom = {
37
+ lock: false,
38
+ queue: []
39
+ };
40
+ this.initialized = false;
41
+ }
42
+
43
+ check(cb) {
44
+ let topPendings = 2;
45
+ let nodesStatus = [];
46
+ const nodesFound = [];
47
+ Fs.readFile(ActorPathGenerated.getNodesFile(), 'utf8', (err, data) => {
48
+ if(err) {
49
+ // TODO: add the file if it does not exist.
50
+ return cb(err);
51
+ }
52
+ const nodeDatas = JSON.parse(data).nodeDatas;
53
+ nodeDatas.forEach((node) => {
54
+ nodesStatus.push(NodeData.from(node));
55
+ });
56
+ if(0 === --topPendings) {
57
+ if(cb) {
58
+ this._calculateNodes(nodesStatus, nodesFound, cb);
59
+ }
60
+ }
61
+ });
62
+ const basePath = Path.resolve(`${ActorPath.getActorPath()}${Path.sep}..`);
63
+ Fs.readdir(basePath, (err, files) => {
64
+ if(err) {
65
+ return done(err);
66
+ }
67
+ if(undefined === files || 0 === files.length) {
68
+ return done();
69
+ }
70
+ let firstError = false;
71
+ let pendings = files.length;
72
+ const addFoundNode = (nodeDatas, name, shortName) => {
73
+ if(name.startsWith('actor')) {
74
+ nodeDatas.push(new NodeData(name, shortName, 'local'));
75
+ }
76
+ else if(name.startsWith('node-')) {
77
+ nodeDatas.push(new NodeData(name, shortName, 'node'));
78
+ }
79
+ else if(name.startsWith('persistant-node-')) {
80
+ nodeDatas.push(new NodeData(name, shortName, 'persistant-node', 'auto'));
81
+ }
82
+ else if(name.startsWith('web-node-')) {
83
+ console.log('NOT IMPLEMENTED');
84
+ }
85
+ };
86
+ files.forEach((dir) => {
87
+ Fs.lstat(`${basePath}${Path.sep}${dir}`, (err, stat) => {
88
+ if(!firstError) {
89
+ if(stat.isDirectory()) {
90
+ if(dir.startsWith('actor') || dir.startsWith('node-') || dir.startsWith('persistant-node-') || dir.startsWith('web-node-')) {
91
+ let sp = this.nodesPersistent.get(dir);
92
+ if(undefined === sp) {
93
+ ++pendings;
94
+ Fs.readFile(`${basePath}${Path.sep}${dir}${Path.sep}package.json`, 'utf8', (err, data) => {
95
+ if(!err) {
96
+ const packageJson = JSON.parse(data);
97
+ this.nodesPersistent.set(dir, packageJson);
98
+ addFoundNode(nodesFound, dir, packageJson.shortname);
99
+ }
100
+ if(0 === --pendings) {
101
+ if(0 === --topPendings) {
102
+ if(cb) {
103
+ this._calculateNodes(nodesStatus, nodesFound, cb);
104
+ }
105
+ }
106
+ }
107
+ });
108
+ }
109
+ else {
110
+ addFoundNode(nodesFound, dir, sp.shortname);
111
+ }
112
+ }
113
+ }
114
+ if(0 === --pendings) {
115
+ if(0 === --topPendings) {
116
+ if(cb) {
117
+ this._calculateNodes(nodesStatus, nodesFound, cb);
118
+ }
119
+ }
120
+ }
121
+ }
122
+ });
123
+ });
124
+ });
125
+ }
126
+
127
+ start(cbStatus) {
128
+ const supervisor = this._getSupervisor();
129
+ if('stopped' === supervisor.state) {
130
+ supervisor.state = 'starting';
131
+ cbStatus();
132
+ this._startSuperVisor((err) => {
133
+ const supervisor = this._getSupervisor();
134
+ if(err) {
135
+ supervisor.status = 'failure';
136
+ }
137
+ this._saveStatus((err) => {
138
+ cbStatus();
139
+ });
140
+ }, () => {
141
+ this._saveStatus((err) => {
142
+ cbStatus();
143
+ });
144
+ });
145
+ }
146
+ else {
147
+ ddb.warning('DROPPED START');
148
+ }
149
+ }
150
+
151
+ stop(cbStatus) {
152
+ const supervisor = this._getSupervisor();
153
+ if('started' === supervisor.state) {
154
+ supervisor.state = 'stopping';
155
+ cbStatus();
156
+ process.nextTick(() => {
157
+ const supervisor = this._getSupervisor();
158
+ const messageChannel = this._getMessageChannel(supervisor.name);
159
+ if(messageChannel) {
160
+ const request = messageChannel.request(new ServiceAction().addRequest('NodeSurveillanceStop', this.nodeDatas), undefined, (response) => {
161
+ response.responses.forEach((resp) => {
162
+ resp.data.forEach((d) => {
163
+ const foundNodeData = this.nodeDatas.find((nodeData) => {
164
+ return nodeData.name === d.name;
165
+ });
166
+ if(undefined !== foundNodeData) {
167
+ foundNodeData.pid = d.pid;
168
+ foundNodeData.state = -1 === d.pid ? 'stopped' : 'started';
169
+ }
170
+ });
171
+ this._saveStatus((err) => {
172
+ this.cbStatus();
173
+ });
174
+ });
175
+ try {
176
+ process.kill(supervisor.pid);
177
+ }
178
+ catch(e) {}
179
+ supervisor.state = 'stopped';
180
+ supervisor.pid = -1;
181
+ supervisor.ping = 0;
182
+ this._saveStatus((err) => {
183
+ cbStatus();
184
+ });
185
+ });
186
+ }
187
+ });
188
+ }
189
+ else {
190
+ ddb.warning('DROPPED STOP');
191
+ }
192
+ }
193
+
194
+ command(nodeName, nodeStatus, cbStatus) {
195
+ console.log(nodeName, nodeStatus);
196
+ const foundNodeData = this.nodeDatas.find((nodeData) => {
197
+ return nodeData.shortName === nodeName || nodeData.name === nodeName;
198
+ });
199
+ if(undefined !== foundNodeData) {
200
+ if(foundNodeData.status !== nodeStatus) {
201
+ if('on' === nodeStatus || 'off' === nodeStatus) {
202
+ foundNodeData.status = nodeStatus;
203
+ this._saveStatus((err) => {
204
+ cbStatus();
205
+ });
206
+ }
207
+ }
208
+ }
209
+ else {
210
+ ddb.writelnTime(ddb.red('Unknown node:'), `'${nodeName}'`);
211
+ }
212
+ }
213
+
214
+ _getNode(name) {
215
+ return this.nodeDatas.find((nodeData) => {
216
+ return name === nodeData.name;
217
+ });
218
+ }
219
+
220
+ _getSupervisor() {
221
+ return this._getNode('persistant-node-supervisor');
222
+ }
223
+
224
+ _handleStatusQueue(cbContinue) {
225
+ if(!this.nodesAtom.lock) {
226
+ this.nodesAtom.lock = true;
227
+ const done = () => {
228
+ if(0 !== this.nodesAtom.queue.length) {
229
+ process.nextTick(() => {
230
+ try {
231
+ this.nodesAtom.queue.shift()(done);
232
+ } catch(a) {ddb.error(a);}
233
+ });
234
+ }
235
+ else {
236
+ this.nodesAtom.lock = false;
237
+ }
238
+ };
239
+ cbContinue(done);
240
+ }
241
+ else {
242
+ this.nodesAtom.queue.push(cbContinue);
243
+ }
244
+ }
245
+
246
+ _readStatus(cb) {
247
+ this._handleStatusQueue((cbDone) => {
248
+ Fs.readFile(ActorPathGenerated.getNodesFile(), 'utf8', (err, data) => {
249
+ cb(err, data);
250
+ cbDone();
251
+ });
252
+ });
253
+ }
254
+
255
+
256
+ _saveStatus(cb) {
257
+ this._handleStatusQueue((cbDone) => {
258
+ Fs.writeFile(ActorPathGenerated.getNodesFile(), JSON.stringify({
259
+ nodeDatas: this.nodeDatas
260
+ }, null, 2), 'utf8', (err) => {
261
+ cb(err);
262
+ cbDone();
263
+ });
264
+ });
265
+ }
266
+
267
+ _mergeNodeData(sStatus, sFound) {
268
+ if(undefined === sStatus) {
269
+ this.nodeDatas.push(sFound);
270
+ }
271
+ else if(undefined === sFound) {
272
+ this.nodeDatas.push(sStatus);
273
+ sStatus.status = 'no repo';
274
+ }
275
+ else {
276
+ this.nodeDatas.push(sStatus);
277
+ }
278
+ }
279
+
280
+ _mergeNodeDatas(nodesStatus, nodesFound) {
281
+ while(0 !== nodesStatus.length) {
282
+ const sStatus = nodesStatus.shift();
283
+ const sFoundIndex = nodesFound.findIndex((s) => {
284
+ return s.name === sStatus.name;
285
+ });
286
+ if(-1 !== sFoundIndex) {
287
+ const sFound = nodesFound[sFoundIndex];
288
+ nodesFound.splice(sFoundIndex, 1);
289
+ this._mergeNodeData(sStatus, sFound);
290
+ }
291
+ else {
292
+ this._mergeNodeData(sStatus);
293
+ }
294
+ }
295
+ while(0 !== nodesFound.length) {
296
+ const sFound = nodesFound.shift();
297
+ const sStatusIndex = nodesStatus.findIndex((s) => {
298
+ return s.name === sFound.name;
299
+ });
300
+ if(-1 !== sStatusIndex) {
301
+ const sStatus = nodesStatus[sStatusIndex];
302
+ nodesStatus.splice(sStatusIndex, 1);
303
+ this._mergeNodeData(sStatus, sFound);
304
+ }
305
+ else {
306
+ this._mergeNodeData(undefined, sFound);
307
+ }
308
+ }
309
+ this.nodeDatas.sort((a, b) => {
310
+ if(a.name > b.name) {
311
+ return 1;
312
+ }
313
+ else if(a.name < b.name) {
314
+ return -1;
315
+ }
316
+ else {
317
+ return 0;
318
+ }
319
+ });
320
+ }
321
+
322
+ _getMessageChannel(name) {
323
+ const messageChannel = this.messageChannels.get(name);
324
+ if(!messageChannel) {
325
+ ddb.error(`Could not found message channel to: '${name}'. Message dropped.`);
326
+ }
327
+ return messageChannel;
328
+ }
329
+
330
+ _startedState() {
331
+ if(1 !== this.messageChannels.size) {
332
+ if(0 === this.messageChannels.size) {
333
+ this.serverStatus.connected = false;
334
+ }
335
+ return;
336
+ }
337
+ const supervisor = this._getSupervisor();
338
+ const messageChannel = this._getMessageChannel(supervisor.name);
339
+ if(messageChannel) {
340
+ const request = messageChannel.request(new ServiceAction('NodeSurveillanceInfo', this.nodeDatas), undefined, (response) => {
341
+ response.responses.forEach((resp) => {
342
+ resp.data.forEach((d) => {
343
+ const foundNodeData = this.nodeDatas.find((nodeData) => {
344
+ return nodeData.name === d.name;
345
+ });
346
+ if(undefined !== foundNodeData) {
347
+ foundNodeData.pid = d.pid;
348
+ foundNodeData.state = -1 === d.pid ? 'stopped' : 'started';
349
+ }
350
+ });
351
+ this._saveStatus((err) => {
352
+ this.cbStatus();
353
+ });
354
+ });
355
+ });
356
+ }
357
+ }
358
+
359
+ _stoppedState() {
360
+
361
+ }
362
+
363
+ _calculateNodes(nodesStatus, nodesFound, cb) {
364
+ this.nodeDatas = [];
365
+ try {
366
+ this._mergeNodeDatas(nodesStatus, nodesFound);
367
+ const supervisor = this._getSupervisor();
368
+ switch(supervisor.state) {
369
+ case 'stopped':
370
+ this._stoppedState();
371
+ break;
372
+ case 'stopping':
373
+ break;
374
+ case 'started':
375
+ this._startedState();
376
+ break;
377
+ case 'starting':
378
+ break;
379
+ };
380
+ }
381
+ catch(err) {
382
+ ddb.error('err', err);
383
+ }
384
+ process.nextTick(cb);
385
+ }
386
+
387
+ _startSuperVisor(cb, cbStatus) {
388
+ try {
389
+ const supervisor = this._getSupervisor();
390
+ supervisor.state = 'starting';
391
+ cbStatus();
392
+ // ddb.writeln'START', Path.resolve(`${ActorPath.getActorPath()}${Path.sep}..${Path.sep}persistant-node-supervisor`), `zass --dev --pp ${this.port} --ph ${this.host}`);
393
+ /*this.supervisorChildProcess = ChildProcess.exec(`${supervisor.shortName} --dev --pp ${this.port} --ph ${this.host}`, {
394
+ cwd: Path.resolve(`${ActorPath.getActorPath()}${Path.sep}..${Path.sep}${supervisor.name}`)
395
+ });*/
396
+
397
+ const cwd = Path.resolve(`${ActorPath.getActorPath()}${Path.sep}..${Path.sep}${supervisor.name}`);
398
+ this.supervisorChildProcess = ChildProcess.spawn('node', [
399
+ require.resolve('.'),
400
+ '--main', Path.join(cwd, 'main.js'),
401
+ '--cwd', cwd,
402
+ '--dev',
403
+ '--pp', `${this.port}`,
404
+ '--ph', this.host
405
+ ],
406
+ {
407
+ detached: true,
408
+ stdio: 'ignore',
409
+ cwd: cwd
410
+ });
411
+ this.supervisorChildProcess.unref();
412
+ cbStatus();
413
+ this.supervisorChildProcess.on('exit', (number, signal) => {
414
+ this.supervisorChildProcess = null;
415
+ });
416
+ process.nextTick(cb);
417
+ }
418
+ catch(a) {
419
+ ddb.error('a');
420
+ }
421
+ }
422
+
423
+ _jsonParse(s) {
424
+ try {
425
+ return JSON.parse(s, null, 2);
426
+ }
427
+ catch(err) {
428
+ ddb.error(ddb.red('\r\r\r\rDROPPED incomming message. JSON.parse Error:'), err);
429
+ }
430
+ }
431
+
432
+ startListen(cb) {
433
+ try {
434
+ if(null !== this.server) {
435
+ return process.nextTick(cb);
436
+ }
437
+ this.server = Net.createServer({allowHalfOpen: true}, (socket) => {
438
+ const socketData = {
439
+ name: 'unknown'
440
+ };
441
+ socket.on('data', (data) => {
442
+ const fromChild = this._jsonParse(data);
443
+ if(undefined === fromChild) {
444
+ return;
445
+ }
446
+ if(this.initialized) {
447
+ if(CoreProtocolConst.RESPONSE === fromChild.type) {
448
+ this.messageChannel = this._getMessageChannel(socketData.name);
449
+ if(this.messageChannel) {
450
+ this.messageChannel.response(fromChild);
451
+ }
452
+ }
453
+ else {
454
+ ddb.warning(ddb.yellow('Messages is not iplemented yet.'));
455
+ }
456
+ }
457
+ else {
458
+ if('initialize' === fromChild.type) {
459
+ this.serverStatus.connected = true;
460
+ this.serverStatus.connectedName = fromChild.name;
461
+ socketData.name = fromChild.name;
462
+ this.messageChannels.set(socketData.name, new MessageChannel(socket));
463
+ const supervisor = this._getSupervisor();
464
+ supervisor.state = 'started';
465
+ supervisor.pid = fromChild.pid;
466
+ supervisor.ping = 0;
467
+ socket.write(JSON.stringify({type: 'initialize', result: true}));
468
+ this.initialized = true;
469
+ this._saveStatus((err) => {
470
+ this.cbStatus();
471
+ });
472
+ }
473
+ }
474
+ });
475
+ socket.on('error', (err) => {
476
+ });
477
+ socket.on('close', () => {
478
+ this.initialized = false;
479
+ this.messageChannels.delete(socketData.name);
480
+ this.serverStatus.connected = false;
481
+ this.serverStatus.connectedName = '';
482
+ const supervisor = this._getSupervisor();
483
+ supervisor.pid = -1;
484
+ this._saveStatus((err) => {
485
+ this.cbStatus();
486
+ });
487
+ });
488
+ });
489
+ this.server.on('error', (err) => {
490
+ this.serverUpDate = null;
491
+ this.serverDownReason = err.message;
492
+ this.server.close();
493
+ this.server = null;
494
+ cb();
495
+ });
496
+ this.server.listen({
497
+ host: this.host,
498
+ port: this.port,
499
+ exclusive: true
500
+ }, () => {
501
+ this.serverUpDate = new Date();
502
+ cb();
503
+ });
504
+ }
505
+ catch(err) {
506
+ ddb.error(err);
507
+ cb(err);
508
+ }
509
+ }
510
+ }
511
+
512
+
513
+ module.exports = NodeAdmin;
@@ -0,0 +1,25 @@
1
+
2
+ 'use strict';
3
+
4
+
5
+ class NodeData {
6
+ constructor(name, shortName, type, status='off', state='stopped', pid=-1, ping=0, statusTicks=0, servers='0 - 0', clients='0 - 0') {
7
+ this.name = name;
8
+ this.shortName = shortName;
9
+ this.type = type;
10
+ this.state = state;
11
+ this.pid = pid,
12
+ this.servers = servers;
13
+ this.clients = clients;
14
+ this.status = status;
15
+ this.ping = ping;
16
+ this.statusTicks = statusTicks;
17
+ }
18
+
19
+ static from(nodeData) {
20
+ return new NodeData(nodeData.name, nodeData.shortName, nodeData.type, nodeData.status, nodeData.state, nodeData.pid, nodeData.ping, nodeData.statusTicks, nodeData.servers, nodeData.clients);
21
+ }
22
+ }
23
+
24
+
25
+ module.exports = NodeData;