1<?php
2/*
3** Zabbix
4** Copyright (C) 2001-2021 Zabbix SIA
5**
6** This program is free software; you can redistribute it and/or modify
7** it under the terms of the GNU General Public License as published by
8** the Free Software Foundation; either version 2 of the License, or
9** (at your option) any later version.
10**
11** This program is distributed in the hope that it will be useful,
12** but WITHOUT ANY WARRANTY; without even the implied warranty of
13** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14** GNU General Public License for more details.
15**
16** You should have received a copy of the GNU General Public License
17** along with this program; if not, write to the Free Software
18** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
19**/
20
21
22class CControllerPopupTriggerExpr extends CController {
23	private $metrics = [];
24	private $param1SecCount = [];
25	private $param1Sec = [];
26	private $param1Str = [];
27	private $param2SecCount = [];
28	private $param3SecVal = [];
29	private $param3SecPercent = [];
30	private $paramSecIntCount = [];
31	private $paramForecast = [];
32	private $paramTimeleft = [];
33	private $allowedTypesAny = [];
34	private $allowedTypesNumeric = [];
35	private $allowedTypesStr = [];
36	private $allowedTypesLog = [];
37	private $allowedTypesInt = [];
38	private $functions = [];
39	private $operators = [];
40
41	protected function init() {
42		$this->disableSIDvalidation();
43
44		$this->metrics = [
45			PARAM_TYPE_TIME => _('Time'),
46			PARAM_TYPE_COUNTS => _('Count')
47		];
48
49		/*
50		 * C - caption
51		 * T - type
52		 * M - metrics
53		 * A - asterisk
54		 */
55		$this->param1SecCount = [
56			'last' => [
57				'C' => _('Last of').' (T)',
58				'T' => T_ZBX_INT,
59				'M' => $this->metrics,
60				'A' => true
61			],
62			'shift' => [
63				'C' => _('Time shift'),
64				'T' => T_ZBX_INT,
65				'A' => false
66			]
67		];
68
69		$this->param1Sec = [
70			'last' => [
71				'C' => _('Last of').' (T)',
72				'T' => T_ZBX_INT,
73				'A' => true
74			]
75		];
76
77		$this->param1Str = [
78			'pattern' => [
79				'C' => 'T',
80				'T' => T_ZBX_STR,
81				'A' => false
82			]
83		];
84
85		$this->param2SecCount = [
86			'pattern' => [
87				'C' => 'V',
88				'T' => T_ZBX_STR,
89				'A' => false
90			],
91			'last' => [
92				'C' => _('Last of').' (T)',
93				'T' => T_ZBX_INT,
94				'M' => $this->metrics,
95				'A' => false
96			]
97		];
98
99		$this->param3SecVal = [
100			'last' => [
101				'C' => _('Last of').' (T)',
102				'T' => T_ZBX_INT,
103				'M' => $this->metrics,
104				'A' => true
105			],
106			'v' => [
107				'C' => 'V',
108				'T' => T_ZBX_STR,
109				'A' => false
110			],
111			'o' => [
112				'C' => 'O',
113				'T' => T_ZBX_STR,
114				'A' => false
115			],
116			'shift' => [
117				'C' => _('Time shift'),
118				'T' => T_ZBX_INT,
119				'A' => false
120			]
121		];
122
123		$this->param3SecPercent = [
124			'last' => [
125				'C' => _('Last of').' (T)',
126				'T' => T_ZBX_INT,
127				'M' => $this->metrics,
128				'A' => true
129			],
130			'shift' => [
131				'C' => _('Time shift'),
132				'T' => T_ZBX_INT,
133				'A' => false
134			],
135			'p' => [
136				'C' => _('Percentage').' (P)',
137				'T' => T_ZBX_DBL,
138				'A' => true
139			]
140		];
141
142		$this->paramSecIntCount = [
143			'last' => [
144				'C' => _('Last of').' (T)',
145				'T' => T_ZBX_INT,
146				'M' => $this->metrics,
147				'A' => true
148			],
149			'mask' => [
150				'C' => _('Mask'),
151				'T' => T_ZBX_STR,
152				'A' => true
153			],
154			'shift' => [
155				'C' => _('Time shift'),
156				'T' => T_ZBX_INT,
157				'A' => false
158			]
159		];
160
161		$this->paramForecast = [
162			'last' => [
163				'C' => _('Last of').' (T)',
164				'T' => T_ZBX_INT,
165				'M' => $this->metrics,
166				'A' => true
167			],
168			'shift' => [
169				'C' => _('Time shift'),
170				'T' => T_ZBX_INT,
171				'A' => false
172			],
173			'time' => [
174				'C' => _('Time').' (t)',
175				'T' => T_ZBX_INT,
176				'A' => true
177			],
178			'fit' => [
179				'C' => _('Fit'),
180				'T' => T_ZBX_STR,
181				'A' => false
182			],
183			'mode' => [
184				'C' => _('Mode'),
185				'T' => T_ZBX_STR,
186				'A' => false
187			]
188		];
189
190		$this->paramTimeleft = [
191			'last' => [
192				'C' => _('Last of').' (T)',
193				'T' => T_ZBX_INT,
194				'M' => $this->metrics,
195				'A' => true
196			],
197			'shift' => [
198				'C' => _('Time shift'),
199				'T' => T_ZBX_INT,
200				'A' => false
201			],
202			't' => [
203				'C' => _('Threshold'),
204				'T' => T_ZBX_DBL,
205				'A' => true
206			],
207			'fit' => [
208				'C' => _('Fit'),
209				'T' => T_ZBX_STR,
210				'A' => false
211			]
212		];
213
214		$this->allowedTypesAny = [
215			ITEM_VALUE_TYPE_FLOAT => 1,
216			ITEM_VALUE_TYPE_STR => 1,
217			ITEM_VALUE_TYPE_LOG => 1,
218			ITEM_VALUE_TYPE_UINT64 => 1,
219			ITEM_VALUE_TYPE_TEXT => 1
220		];
221
222		$this->allowedTypesNumeric = [
223			ITEM_VALUE_TYPE_FLOAT => 1,
224			ITEM_VALUE_TYPE_UINT64 => 1
225		];
226
227		$this->allowedTypesStr = [
228			ITEM_VALUE_TYPE_STR => 1,
229			ITEM_VALUE_TYPE_LOG => 1,
230			ITEM_VALUE_TYPE_TEXT => 1
231		];
232
233		$this->allowedTypesLog = [
234			ITEM_VALUE_TYPE_LOG => 1
235		];
236
237		$this->allowedTypesInt = [
238			ITEM_VALUE_TYPE_UINT64 => 1
239		];
240
241		$this->functions = [
242			'abschange' => [
243				'description' => _('abschange() - Absolute difference between last and previous value'),
244				'allowed_types' => $this->allowedTypesAny,
245				'operators' => ['=', '<>', '>', '<', '>=', '<=']
246			],
247			'avg' => [
248				'description' => _('avg() - Average value of a period T'),
249				'params' => $this->param1SecCount,
250				'allowed_types' => $this->allowedTypesNumeric,
251				'operators' => ['=', '<>', '>', '<', '>=', '<=']
252			],
253			'delta' => [
254				'description' => _('delta() - Difference between MAX and MIN value of a period T'),
255				'params' => $this->param1SecCount,
256				'allowed_types' => $this->allowedTypesNumeric,
257				'operators' => ['=', '<>', '>', '<', '>=', '<=']
258			],
259			'change' => [
260				'description' => _('change() - Difference between last and previous value'),
261				'allowed_types' => $this->allowedTypesAny,
262				'operators' => ['=', '<>', '>', '<', '>=', '<=']
263			],
264			'count' => [
265				'description' => _('count() - Number of successfully retrieved values V (which fulfill operator O) for period T'),
266				'params' => $this->param3SecVal,
267				'allowed_types' => $this->allowedTypesAny,
268				'operators' => ['=', '<>', '>', '<', '>=', '<=']
269			],
270			'diff' => [
271				'description' => _('diff() - Difference between last and preceding values (1 - true, 0 - false)'),
272				'allowed_types' => $this->allowedTypesAny,
273				'operators' => ['=', '<>']
274			],
275			'last' => [
276				'description' => _('last() - Last (most recent) T value'),
277				'params' => $this->param1SecCount,
278				'allowed_types' => $this->allowedTypesAny,
279				'operators' => ['=', '<>', '>', '<', '>=', '<=']
280			],
281			'max' => [
282				'description' => _('max() - Maximum value for period T'),
283				'params' => $this->param1SecCount,
284				'allowed_types' => $this->allowedTypesNumeric,
285				'operators' => ['=', '<>', '>', '<', '>=', '<=']
286			],
287			'min' => [
288				'description' => _('min() - Minimum value for period T'),
289				'params' => $this->param1SecCount,
290				'allowed_types' => $this->allowedTypesNumeric,
291				'operators' => ['=', '<>', '>', '<', '>=', '<=']
292			],
293			'percentile' => [
294				'description' => _('percentile() - Percentile P of a period T'),
295				'params' => $this->param3SecPercent,
296				'allowed_types' => $this->allowedTypesNumeric,
297				'operators' => ['=', '<>', '>', '<', '>=', '<=']
298			],
299			'prev' => [
300				'description' => _('prev() - Previous value'),
301				'allowed_types' => $this->allowedTypesAny,
302				'operators' => ['=', '<>', '>', '<', '>=', '<=']
303			],
304			'str' => [
305				'description' => _('str() - Find string V in last (most recent) value (1 - found, 0 - not found)'),
306				'params' => $this->param2SecCount,
307				'allowed_types' => $this->allowedTypesStr,
308				'operators' => ['=', '<>']
309			],
310			'strlen' => [
311				'description' => _('strlen() - Length of last (most recent) T value in characters'),
312				'params' => $this->param1SecCount,
313				'allowed_types' => $this->allowedTypesStr,
314				'operators' => ['=', '<>', '>', '<', '>=', '<=']
315			],
316			'sum' => [
317				'description' => _('sum() - Sum of values of a period T'),
318				'params' => $this->param1SecCount,
319				'allowed_types' => $this->allowedTypesNumeric,
320				'operators' => ['=', '<>', '>', '<', '>=', '<=']
321			],
322			'date' => [
323				'description' => _('date() - Current date'),
324				'allowed_types' => $this->allowedTypesAny,
325				'operators' => ['=', '<>', '>', '<', '>=', '<=']
326			],
327			'dayofweek' => [
328				'description' => _('dayofweek() - Day of week'),
329				'allowed_types' => $this->allowedTypesAny,
330				'operators' => ['=', '<>', '>', '<', '>=', '<=']
331			],
332			'dayofmonth' => [
333				'description' => _('dayofmonth() - Day of month'),
334				'allowed_types' => $this->allowedTypesAny,
335				'operators' => ['=', '<>', '>', '<', '>=', '<=']
336			],
337			'fuzzytime' => [
338				'description' => _('fuzzytime() - Difference between item value (as timestamp) and Zabbix server timestamp is less than or equal to T seconds (1 - true, 0 - false)'),
339				'params' => $this->param1Sec,
340				'allowed_types' => $this->allowedTypesNumeric,
341				'operators' => ['=', '<>']
342			],
343			'regexp' => [
344				'description' => _('regexp() - Regular expression V matching last value in period T (1 - match, 0 - no match)'),
345				'params' => $this->param2SecCount,
346				'allowed_types' => $this->allowedTypesStr,
347				'operators' => ['=', '<>']
348			],
349			'iregexp' => [
350				'description' => _('iregexp() - Regular expression V matching last value in period T (non case-sensitive; 1 - match, 0 - no match)'),
351				'params' => $this->param2SecCount,
352				'allowed_types' => $this->allowedTypesStr,
353				'operators' => ['=', '<>']
354			],
355			'logeventid' => [
356				'description' => _('logeventid() - Event ID of last log entry matching regular expression T (1 - match, 0 - no match)'),
357				'params' => $this->param1Str,
358				'allowed_types' => $this->allowedTypesLog,
359				'operators' => ['=', '<>']
360			],
361			'logseverity' => [
362				'description' => _('logseverity() - Log severity of the last log entry'),
363				'allowed_types' => $this->allowedTypesLog,
364				'operators' => ['=', '<>', '>', '<', '>=', '<=']
365			],
366			'logsource' => [
367				'description' => _('logsource() - Log source of the last log entry matching parameter T (1 - match, 0 - no match)'),
368				'params' => $this->param1Str,
369				'allowed_types' => $this->allowedTypesLog,
370				'operators' => ['=', '<>']
371			],
372			'now' => [
373				'description' => _('now() - Number of seconds since the Epoch'),
374				'allowed_types' => $this->allowedTypesAny,
375				'operators' => ['=', '<>', '>', '<', '>=', '<=']
376			],
377			'time' => [
378				'description' => _('time() - Current time'),
379				'allowed_types' => $this->allowedTypesAny,
380				'operators' => ['=', '<>', '>', '<', '>=', '<=']
381			],
382			'nodata' => [
383				'description' => _('nodata() - No data received during period of time T (1 - true, 0 - false)'),
384				'params' => $this->param1Sec,
385				'allowed_types' => $this->allowedTypesAny,
386				'operators' => ['=', '<>']
387			],
388			'band' => [
389				'description' => _('band() - Bitwise AND of last (most recent) T value and mask'),
390				'params' => $this->paramSecIntCount,
391				'allowed_types' => $this->allowedTypesInt,
392				'operators' => ['=', '<>']
393			],
394			'forecast' => [
395				'description' => _('forecast() - Forecast for next t seconds based on period T'),
396				'params' => $this->paramForecast,
397				'allowed_types' => $this->allowedTypesNumeric,
398				'operators' => ['=', '<>', '>', '<', '>=', '<=']
399			],
400			'timeleft' => [
401				'description' => _('timeleft() - Time to reach threshold estimated based on period T'),
402				'params' => $this->paramTimeleft,
403				'allowed_types' => $this->allowedTypesNumeric,
404				'operators' => ['=', '<>', '>', '<', '>=', '<=']
405			]
406		];
407
408		CArrayHelper::sort($this->functions, ['description']);
409
410		foreach ($this->functions as $function) {
411			foreach ($function['operators'] as $operator) {
412				$this->operators[$operator] = true;
413			}
414		}
415	}
416
417	protected function checkInput() {
418		$fields = [
419			'dstfrm' =>				'string|fatal',
420			'dstfld1' =>			'string|not_empty',
421			'expression' =>			'string',
422			'itemid' =>				'db items.itemid',
423			'parent_discoveryid' =>	'db items.itemid',
424			'function' =>			'in '.implode(',', array_keys($this->functions)),
425			'operator' =>			'in '.implode(',', array_keys($this->operators)),
426			'params' =>				'',
427			'paramtype' =>			'in '.implode(',', [PARAM_TYPE_TIME, PARAM_TYPE_COUNTS]),
428			'value' =>				'string|not_empty',
429			'hostid' =>				'db hosts.hostid',
430			'groupid' =>			'db hosts_groups.hostgroupid',
431			'add' =>				'in 1'
432		];
433
434		$ret = $this->validateInput($fields);
435
436		if (!$ret) {
437			$output = [];
438			if (($messages = getMessages()) !== null) {
439				$output['errors'] = $messages->toString();
440			}
441
442			if ($this->hasInput('add')) {
443				$this->setResponse(
444					(new CControllerResponseData(['main_block' => CJs::encodeJson($output)]))->disableView()
445				);
446			}
447			else {
448				$ret = true;
449			}
450		}
451
452		return $ret;
453	}
454
455	protected function checkPermissions() {
456		return true;
457	}
458
459	protected function doAction() {
460		$itemid = $this->getInput('itemid', 0);
461		$function = $this->getInput('function', 'last');
462		$operator = $this->getInput('operator', '=');
463		$param_type = $this->getInput('paramtype', PARAM_TYPE_TIME);
464		$dstfld1 = $this->getInput('dstfld1');
465		$expression = $this->getInput('expression', '');
466		$params = $this->getInput('params', []);
467		$value = $this->getInput('value', 0);
468
469		// Opening the popup when editing an expression in the trigger constructor.
470		if (($dstfld1 === 'expr_temp' || $dstfld1 === 'recovery_expr_temp') && $expression !== '') {
471			$expression = utf8RawUrlDecode($expression);
472
473			$expression_data = new CTriggerExpression();
474			$result = $expression_data->parse($expression);
475
476			if ($result) {
477				$function_macro_tokens = $result->getTokensByType(
478					CTriggerExprParserResult::TOKEN_TYPE_FUNCTION_MACRO
479				);
480
481				if ($function_macro_tokens) {
482					$function_macro_token = $function_macro_tokens[0];
483					$function = $function_macro_token['data']['functionName'];
484
485					// Determine param type.
486					$params = $function_macro_token['data']['functionParams'];
487					$param_number = in_array($function, ['regexp', 'iregexp', 'str']) ? 1 : 0;
488					if (array_key_exists($param_number, $params) && is_string($params[$param_number])
489							&& $params[$param_number] !== '' && $params[$param_number][0] === '#'
490							&& !in_array($function, ['fuzzytime', 'nodata'])) {
491						$param_type = PARAM_TYPE_COUNTS;
492						$params[$param_number] = substr($params[$param_number], 1);
493					}
494					else {
495						$param_type = PARAM_TYPE_TIME;
496					}
497
498					/*
499					 * Try to find an operator and a value.
500					 * The value and operator can be extracted only if they immediately follow the item function macro.
501					 */
502					$tokens = $result->getTokens();
503					foreach ($tokens as $key => $token) {
504						if ($token['type'] == CTriggerExprParserResult::TOKEN_TYPE_FUNCTION_MACRO) {
505							if (array_key_exists($key + 2, $tokens)
506									&& $tokens[$key + 1]['type'] == CTriggerExprParserResult::TOKEN_TYPE_OPERATOR
507									&& array_key_exists($function, $this->functions)
508									&& in_array($tokens[$key + 1]['value'],
509										$this->functions[$function]['operators'])) {
510								$operator = $tokens[$key + 1]['value'];
511
512								if (array_key_exists($key + 3, $tokens)
513										&& $tokens[$key + 2]['type'] == CTriggerExprParserResult::TOKEN_TYPE_OPERATOR) {
514									$value = $tokens[$key + 2]['value'].$tokens[$key + 3]['value'];
515								}
516								else {
517									$value = $tokens[$key + 2]['value'];
518								}
519							}
520							else {
521								break;
522							}
523						}
524					}
525
526					// Find the item.
527					$item = API::Item()->get([
528						'output' => ['itemid', 'hostid', 'name', 'key_', 'value_type'],
529						'selectHosts' => ['name'],
530						'webitems' => true,
531						'filter' => [
532							'host' => $function_macro_token['data']['host'],
533							'key_' => $function_macro_token['data']['item'],
534							'flags' => null
535						]
536					]);
537
538					if (($item = reset($item)) !== false) {
539						$itemid = $item['itemid'];
540					}
541					else {
542						error(_('Unknown host item, no such item in selected host'));
543					}
544				}
545			}
546		}
547		// Opening an empty form or switching a function.
548		else {
549			$item = API::Item()->get([
550				'output' => ['itemid', 'hostid', 'name', 'key_', 'value_type'],
551				'selectHosts' => ['host', 'name'],
552				'itemids' => $itemid,
553				'webitems' => true,
554				'filter' => ['flags' => null]
555			]);
556
557			$item = reset($item);
558		}
559
560		if ($itemid) {
561			$items = CMacrosResolverHelper::resolveItemNames([$item]);
562			$item = $items[0];
563
564			$item_value_type = $item['value_type'];
565			$item_key = $item['key_'];
566			$item_host_data = reset($item['hosts']);
567			$description = $item_host_data['name'].NAME_DELIMITER.$item['name_expanded'];
568		}
569		else {
570			$item_key = '';
571			$description = '';
572			$item_value_type = null;
573		}
574
575		if ($param_type === null && array_key_exists($function, $this->functions)
576				&& array_key_exists('params', $this->functions[$function])
577				&& array_key_exists('M', $this->functions[$function]['params'])) {
578			$param_type = is_array($this->functions[$function]['params']['M'])
579				? reset($this->functions[$function]['params']['M'])
580				: $this->functions[$function]['params']['M'];
581		}
582		elseif ($param_type === null) {
583			$param_type = PARAM_TYPE_TIME;
584		}
585
586		$data = [
587			'parent_discoveryid' => $this->getInput('parent_discoveryid', ''),
588			'dstfrm' => $this->getInput('dstfrm'),
589			'dstfld1' => $dstfld1,
590			'itemid' => $itemid,
591			'value' => $value,
592			'params' => $params,
593			'paramtype' => $param_type,
594			'item_description' => $description,
595			'functions' => $this->functions,
596			'function' => $function,
597			'operator' => $operator,
598			'item_key' => $item_key,
599			'itemValueType' => $item_value_type,
600			'selectedFunction' => null,
601			'groupid' => $this->getInput('groupid', 0),
602			'hostid' => $this->getInput('hostid', 0)
603		];
604
605		// Check if submitted function is usable with selected item.
606		foreach ($data['functions'] as $id => $f) {
607			if (($data['itemValueType'] === null || array_key_exists($item_value_type, $f['allowed_types']))
608					&& $id === $function) {
609				$data['selectedFunction'] = $id;
610				break;
611			}
612		}
613
614		if ($data['selectedFunction'] === null) {
615			$data['selectedFunction'] = 'last';
616			$data['function'] = 'last';
617		}
618
619		// Remove functions that not correspond to chosen item.
620		foreach ($data['functions'] as $id => $f) {
621			if ($data['itemValueType'] !== null && !array_key_exists($data['itemValueType'], $f['allowed_types'])) {
622				unset($data['functions'][$id]);
623
624				// Take first available function from list and change to first available operator for that function.
625				if ($id === $data['function']) {
626					$data['function'] = key($data['functions']);
627					$data['operator'] = reset($data['functions'][$data['function']]['operators']);
628				}
629			}
630		}
631
632		// Create and validate trigger expression before inserting it into textarea field.
633		if ($this->getInput('add', false)) {
634			try {
635				if ($data['item_description']) {
636					if ($data['paramtype'] == PARAM_TYPE_COUNTS
637							&& array_key_exists('last', $data['params'])
638							&& $data['params']['last'] !== '') {
639						$data['params']['last'] = zbx_is_int($data['params']['last'])
640							? '#'.$data['params']['last']
641							: $data['params']['last'];
642					}
643					elseif ($data['paramtype'] == PARAM_TYPE_TIME && in_array($function, ['last', 'band', 'strlen'])) {
644						$data['params']['last'] = '';
645					}
646
647					// Quote function param.
648					$quoted_params = [];
649					foreach ($data['params'] as $param) {
650						$quoted_params[] = quoteFunctionParam($param);
651					}
652
653					$data['expression'] = sprintf('{%s:%s.%s(%s)}%s%s',
654						$item_host_data['host'],
655						$data['item_key'],
656						$function,
657						rtrim(implode(',', $quoted_params), ','),
658						$operator,
659						$data['value']
660					);
661
662					// Validate trigger expression.
663					$trigger_expression = new CTriggerExpression();
664
665					if ($trigger_expression->parse($data['expression'])) {
666						$expression_data = reset($trigger_expression->expressions);
667
668						// Validate trigger function.
669						$trigger_function_validator = new CFunctionValidator();
670						$is_valid = $trigger_function_validator->validate([
671							'function' => $expression_data['function'],
672							'functionName' => $expression_data['functionName'],
673							'functionParamList' => $expression_data['functionParamList'],
674							'valueType' => $data['itemValueType']
675						]);
676
677						if ($is_valid === false) {
678							error($trigger_function_validator->getError());
679						}
680					}
681					else {
682						error($trigger_expression->error);
683					}
684
685					// Quote function param.
686					if (array_key_exists('insert', $data)) {
687						foreach ($data['params'] as $pnum => $param) {
688							$data['params'][$pnum] = quoteFunctionParam($param);
689						}
690					}
691				}
692				else {
693					error(_('Item not selected'));
694				}
695			}
696			catch (Exception $e) {
697				error($e->getMessage());
698				error(_('Cannot insert trigger expression'));
699			}
700
701			if (($messages = getMessages()) !== null) {
702				$output = [
703					'errors' => $messages->toString()
704				];
705			}
706			else {
707				$output = [
708					'expression' => $data['expression'],
709					'dstfld1' => $data['dstfld1'],
710					'dstfrm' => $data['dstfrm']
711				];
712			}
713
714			$this->setResponse(
715				(new CControllerResponseData(['main_block' => CJs::encodeJson($output)]))->disableView()
716			);
717		}
718		else {
719			$this->setResponse(new CControllerResponseData(
720				$data + [
721					'title' => _('Condition'),
722					'errors' => hasErrorMesssages() ? getMessages() : null,
723					'user' => [
724						'debug_mode' => $this->getDebugMode()
725					]
726				]
727			));
728		}
729	}
730}
731