";
echo "
";
echo html_print_image(
diff --git a/pandora_console/include/functions_html.php b/pandora_console/include/functions_html.php
index 30b86478f8..ef7debe089 100644
--- a/pandora_console/include/functions_html.php
+++ b/pandora_console/include/functions_html.php
@@ -436,7 +436,9 @@ function html_print_select_groups(
$keys_field='id_grupo',
$strict_user=false,
$delete_groups=false,
- $include_groups=false
+ $include_groups=false,
+ $size=false,
+ $simple_multiple_options=false
) {
global $config;
@@ -481,7 +483,12 @@ function html_print_select_groups(
$class,
$disabled,
$style,
- $option_style
+ $option_style,
+ $size,
+ false,
+ '',
+ false,
+ $simple_multiple_options
);
if ($return) {
@@ -529,7 +536,8 @@ function html_print_select(
$size=false,
$modal=false,
$message='',
- $select_all=false
+ $select_all=false,
+ $simple_multiple_options=false
) {
$output = "\n";
@@ -557,6 +565,14 @@ function html_print_select(
}
}
+ if ($simple_multiple_options === true) {
+ if ($size !== false) {
+ $attributes .= ' size="'.$size.'"';
+ } else {
+ $attributes .= ' size="10"';
+ }
+ }
+
if (!empty($class)) {
$attributes .= ' class="'.$class.'"';
}
@@ -1774,7 +1790,8 @@ function html_print_button($label='OK', $name='', $disabled=false, $script='', $
*/
function html_print_textarea($name, $rows, $columns, $value='', $attributes='', $return=false, $class='')
{
- $output = ' ';
}
+
// Leave.
else {
if ($depth == 0 && $count == 0) {
if ($count == $total) {
- echo '
';
+ $output .= '
';
} else {
- echo '
';
+ $output .= '
';
}
} else if ($count == $total) {
- echo '
';
+ $output .= '
';
} else {
- echo '
';
+ $output .= '
';
}
}
// Branch or leave with branches!
if (isset($sub_level['__OID__'])) {
- echo "
";
- echo ' ';
- echo ' ';
+ $output .= "
";
+ $output .= ' ';
+ $output .= ' ';
}
$checkbox_name_sufix = ($sufix === true) ? '_'.$level : '';
- $checkbox_name = 'create_'.$sub_id.$checkbox_name_sufix;
- $status = (!empty($checked) && isset($checked[$level]));
- echo html_print_checkbox($checkbox_name, 0, $status, true, false, '').'
'.$level.' ';
- if (isset($sub_level['__VALUE__'])) {
- echo '
= '.$sub_level['__VALUE__'].' ';
+ if ($descriptive_ids === true) {
+ $checkbox_name = 'create_'.$sub_id.$previous_id.$checkbox_name_sufix;
+ } else {
+ $checkbox_name = 'create_'.$sub_id.$checkbox_name_sufix;
}
- echo '';
+ $previous_id = $checkbox_name_sufix;
+ $status = (!empty($checked) && isset($checked[$level]));
+ $output .= html_print_checkbox($checkbox_name, 0, $status, true, false, '').'
'.$level.' ';
+ if (isset($sub_level['__VALUE__'])) {
+ $output .= '
= '.$sub_level['__VALUE__'].' ';
+ }
+
+ $output .= '';
// Recursively print sub levels.
- snmp_browser_print_tree($sub_level, $sub_id, ($depth + 1), ($count == $total ? 1 : 0), $last_array, $sufix, $checked);
+ $output .= snmp_browser_print_tree(
+ $sub_level,
+ $sub_id,
+ ($depth + 1),
+ ($count == $total ? 1 : 0),
+ $last_array,
+ $sufix,
+ $checked,
+ $return,
+ $descriptive_ids,
+ $previous_id
+ );
$count++;
}
- echo '';
+ $output .= '';
+
+ if ($return == false) {
+ echo $output;
+ }
+
+ return $output;
}
diff --git a/pandora_console/include/functions_ui.php b/pandora_console/include/functions_ui.php
index 82b85bb0ad..eac317863b 100755
--- a/pandora_console/include/functions_ui.php
+++ b/pandora_console/include/functions_ui.php
@@ -1988,10 +1988,10 @@ function ui_pagination(
$script_modified
);
- $output .= "
10) {
return VISUAL_MAP_STATUS_UNKNOWN;
}
- $layout_items = db_get_all_rows_filter('tlayout_data', ['id_layout' => $layout_id]);
+ $layout_items = db_get_all_rows_filter(
+ 'tlayout_data',
+ ['id_layout' => $layout_id]
+ );
if ($layout_items === false) {
return VISUAL_MAP_STATUS_UNKNOWN;
}
- // Check for valid items to retrieve the status for
+ // Check for valid items to retrieve the status for.
$valid_layout_items = [];
foreach ($layout_items as $layout_item_data) {
if (($layout_item_data['type'] == GROUP_ITEM
&& !empty($layout_item_data['id_group'])
- && check_acl($config['id_user'], $layout_item_data['id_group'], 'VR')
- && check_acl($config['id_user'], $layout_item_data['element_group'], 'VR'))
+ && check_acl(
+ $config['id_user'],
+ $layout_item_data['id_group'],
+ 'VR'
+ )
+ && check_acl(
+ $config['id_user'],
+ $layout_item_data['element_group'],
+ 'VR'
+ ))
|| ((!empty($layout_item_data['id_layout_linked'])
|| !empty($layout_item_data['id_agente_modulo'])
|| !empty($layout_item_data['id_agent']))
- && check_acl($config['id_user'], $layout_item_data['element_group'], 'VR'))
+ && check_acl(
+ $config['id_user'],
+ $layout_item_data['element_group'],
+ 'VR'
+ ))
) {
$valid_layout_items[] = $layout_item_data;
}
@@ -4002,7 +4018,7 @@ function visual_map_get_layout_status($layout_id, $status_data=[], $depth=0)
return VISUAL_MAP_STATUS_UNKNOWN;
}
- // Sort by node id to reduce the number of connections
+ // Sort by node id to reduce the number of connections.
if (is_metaconsole()) {
sort_by_column($valid_layout_items, 'id_metaconsole');
}
@@ -4021,14 +4037,14 @@ function visual_map_get_layout_status($layout_id, $status_data=[], $depth=0)
if (empty($node_id) && $meta_connected_to) {
metaconsole_restore_db();
- // Restore db connection
+ // Restore db connection.
$meta_connected_to = null;
- } else if (!empty($node_id) && ( empty($meta_connected_to)
- || $meta_connected_to != $node_id)
+ } else if (!empty($node_id)
+ && (empty($meta_connected_to) || $meta_connected_to != $node_id)
) {
if (!empty($meta_connected_to)) {
metaconsole_restore_db();
- // Restore db connection
+ // Restore db connection.
}
$connection = metaconsole_get_connection_by_id($node_id);
@@ -4042,64 +4058,80 @@ function visual_map_get_layout_status($layout_id, $status_data=[], $depth=0)
$status = VISUAL_MAP_STATUS_NORMAL;
- $ent_element_status = enterprise_hook('enterprise_visual_map_get_status_element', [$layoutData]);
+ $ent_element_status = enterprise_hook(
+ 'enterprise_visual_map_get_status_element',
+ [$layoutData]
+ );
if ($ent_element_status === ENTERPRISE_NOT_HOOK) {
$ent_element_status = false;
}
- // Enterprise element
if ($ent_element_status !== false) {
+ // Enterprise element.
$status = $ent_element_status;
- }
- // Other
- else {
+ } else {
+ // Other.
switch ($layout_item_data['type']) {
case STATIC_GRAPH:
case PERCENTILE_BAR:
case PERCENTILE_BUBBLE:
case CIRCULAR_PROGRESS_BAR:
case CIRCULAR_INTERIOR_PROGRESS_BAR:
- // Linked layout
if (!empty($layout_item_data['id_layout_linked'])) {
- $status = visual_map_get_layout_status($layout_item_data['id_layout_linked'], $layout_item_data, ($depth + 1));
- }
- // Module
- else if (!empty($layout_item_data['id_agente_modulo'])) {
- $module_status = modules_get_agentmodule_status($layout_item_data['id_agente_modulo']);
- $status = visual_map_translate_module_status($module_status);
- }
- // Agent
- else if (!empty($layout_item_data['id_agent'])) {
- $agent_status = agents_get_status($layout_item_data['id_agent'], true);
- $status = visual_map_translate_agent_status($agent_status);
- }
- // Unknown
- else {
+ // Linked layout.
+ $status = visual_map_get_layout_status(
+ $layout_item_data['id_layout_linked'],
+ $layout_item_data,
+ ($depth + 1)
+ );
+ } else if (!empty($layout_item_data['id_agente_modulo'])) {
+ // Module.
+ $module_status = modules_get_agentmodule_status(
+ $layout_item_data['id_agente_modulo']
+ );
+ $status = visual_map_translate_module_status(
+ $module_status
+ );
+ } else if (!empty($layout_item_data['id_agent'])) {
+ // Agent.
+ $agent_status = agents_get_status(
+ $layout_item_data['id_agent'],
+ true
+ );
+ $status = visual_map_translate_agent_status(
+ $agent_status
+ );
+ } else {
+ // Unknown.
$status = VISUAL_MAP_STATUS_UNKNOWN;
}
break;
case GROUP_ITEM:
- $group_status = groups_get_status($layout_item_data['id_group']);
+ $group_status = groups_get_status(
+ $layout_item_data['id_group']
+ );
$status = visual_map_translate_agent_status($group_status);
break;
default:
- // If it's a graph, a progress bar or a data tag, ALWAYS report status OK
- // (=0) to avoid confussions here.
+ // If it's a graph, a progress bar or a data tag,
+ // ALWAYS report status OK (=0) to avoid confussions here.
$status = VISUAL_MAP_STATUS_NORMAL;
break;
}
}
- // When the status calculation type is 'default', only one critical element is required to
- // set the layout status as critical, so we can return the critical status right now.
- if ($status_data['linked_layout_status_type'] === 'default' && ( $status == VISUAL_MAP_STATUS_CRITICAL_BAD
+ // When the status calculation type is 'default', only one critical
+ // element is required to set the layout status as critical, so we can
+ // return the critical status right now.
+ if ($status_data['linked_layout_status_type'] === 'default'
+ && ($status == VISUAL_MAP_STATUS_CRITICAL_BAD
|| $status == VISUAL_MAP_STATUS_CRITICAL_ALERT)
) {
if (is_metaconsole() && $meta_connected_to) {
+ // Restore db connection.
metaconsole_restore_db();
- // Restore db connection
}
return $status;
@@ -4113,11 +4145,11 @@ function visual_map_get_layout_status($layout_id, $status_data=[], $depth=0)
}
if (is_metaconsole() && $meta_connected_to) {
+ // Restore db connection.
metaconsole_restore_db();
- // Restore db connection
}
- // Status calculation
+ // Status calculation.
switch ($status_data['linked_layout_status_type']) {
default:
case 'default':
@@ -4149,7 +4181,7 @@ function visual_map_get_layout_status($layout_id, $status_data=[], $depth=0)
if ($num_items_critical > 0
&& ((($num_items_critical_alert + $num_items_critical) * 100) / $num_items) >= $weight
) {
- return $num_items_critical_alert > 0 ? VISUAL_MAP_STATUS_CRITICAL_ALERT : VISUAL_MAP_STATUS_CRITICAL_BAD;
+ return ($num_items_critical_alert > 0) ? VISUAL_MAP_STATUS_CRITICAL_ALERT : VISUAL_MAP_STATUS_CRITICAL_BAD;
} else if ($num_items_warning > 0
&& (($num_items_warning * 100) / $num_items) >= $weight
) {
@@ -4525,3 +4557,43 @@ function visual_map_get_color_cloud_element($data)
';
+ continue;
+ }
+
+ preg_match('/.*.css$/', $file, $match, PREG_OFFSET_CAPTURE);
+ if (empty($match) === false) {
+ $url = $baseUrl.$vcClientPath.'/'.$match[0][0];
+ echo ' ';
+ }
+ }
+
+ closedir($dh);
+ }
+ }
+}
diff --git a/pandora_console/include/functions_visual_map_editor.php b/pandora_console/include/functions_visual_map_editor.php
index 151014cd01..90da456ae1 100755
--- a/pandora_console/include/functions_visual_map_editor.php
+++ b/pandora_console/include/functions_visual_map_editor.php
@@ -688,7 +688,7 @@ function visual_map_editor_print_item_palette($visualConsole_id, $background)
'percentile_item',
'datos',
];
- $form_items['percentile_item_row_6']['html'] = ' '.__('Label color').'
+ $form_items['percentile_item_row_6']['html'] = '
'.__('Value color').'
'.html_print_input_text_extended(
'percentile_label_color',
'#ffffff',
diff --git a/pandora_console/include/graphs/flot/pandora.flot.js b/pandora_console/include/graphs/flot/pandora.flot.js
index dd6fb0645e..8fc7073365 100644
--- a/pandora_console/include/graphs/flot/pandora.flot.js
+++ b/pandora_console/include/graphs/flot/pandora.flot.js
@@ -2133,7 +2133,7 @@ function pandoraFlotArea(
var plot = $.plot($("#" + graph_id), datas, options);
// Re-calculate the graph height with the legend height
- if (dashboard || vconsole) {
+ if (dashboard) {
$acum = 0;
if (dashboard) $acum = 35;
var hDiff =
diff --git a/pandora_console/include/graphs/functions_d3.php b/pandora_console/include/graphs/functions_d3.php
index 83e622e171..2ad669308f 100644
--- a/pandora_console/include/graphs/functions_d3.php
+++ b/pandora_console/include/graphs/functions_d3.php
@@ -415,7 +415,7 @@ function d3_progress_bubble($id, $percentile, $width, $height, $color, $unit='%'
}
-function progress_circular_bar($id, $percentile, $width, $height, $color, $unit='%', $text='', $fill_color='#FFFFFF')
+function progress_circular_bar($id, $percentile, $width, $height, $color, $unit='%', $text='', $fill_color='#FFFFFF', $transition=1)
{
global $config;
@@ -427,7 +427,7 @@ function progress_circular_bar($id, $percentile, $width, $height, $color, $unit=
$output .= '
";
$output .= include_javascript_d3(true);
$output .= "";
return $output;
diff --git a/pandora_console/include/graphs/pandora.d3.js b/pandora_console/include/graphs/pandora.d3.js
index d34f9b41cd..6bc3d72d66 100644
--- a/pandora_console/include/graphs/pandora.d3.js
+++ b/pandora_console/include/graphs/pandora.d3.js
@@ -1980,7 +1980,8 @@ function print_circular_progress_bar(
color,
unit,
label,
- label_color
+ label_color,
+ transition
) {
var twoPi = Math.PI * 2;
var radius = width / 2;
@@ -2112,15 +2113,19 @@ function print_circular_progress_bar(
var progress = startPercent;
- (function loops() {
- updateProgress(progress);
+ if (transition == 0)
+ updateProgress(endPercent);
+ else {
+ (function loops() {
+ updateProgress(progress);
- if (count > 0) {
- count--;
- progress += step;
- setTimeout(loops, 30);
- }
- })();
+ if (count > 0) {
+ count--;
+ progress += step;
+ setTimeout(loops, 30);
+ }
+ })();
+ }
}
function print_interior_circular_progress_bar(
diff --git a/pandora_console/include/javascript/pandora.js b/pandora_console/include/javascript/pandora.js
index c30736cd8b..b7dd0dc48e 100644
--- a/pandora_console/include/javascript/pandora.js
+++ b/pandora_console/include/javascript/pandora.js
@@ -1748,7 +1748,9 @@ function round_with_decimals(value, multiplier) {
if (typeof multiplier === "undefined") multiplier = 1;
// Return non numeric types without modification
- if (typeof value !== "number") return value;
+ if (typeof value !== "number" || Number.isNaN(value)) {
+ return value;
+ }
if (value * multiplier == 0) return 0;
if (Math.abs(value) * multiplier >= 1) {
diff --git a/pandora_console/include/javascript/pandora_visual_console.js b/pandora_console/include/javascript/pandora_visual_console.js
index 06209e092f..1df990db10 100755
--- a/pandora_console/include/javascript/pandora_visual_console.js
+++ b/pandora_console/include/javascript/pandora_visual_console.js
@@ -1,3 +1,268 @@
+// TODO: Add Artica ST header.
+/* globals jQuery, VisualConsole */
+
+/*
+ * *********************
+ * * New VC functions. *
+ * *********************
+ */
+
+/**
+ * Generate a Visual Console client.
+ * @param {HTMLElement} container Node which will be used to contain the VC.
+ * @param {object} props VC container properties.
+ * @param {object[]} items List of item definitions.
+ * @param {string | null} baseUrl Base URL to perform API requests.
+ * @param {number | null} updateInterval Time in milliseconds between VC updates.
+ * @param {function | null} onUpdate Callback which will be execuded when the Visual Console.
+ * is updated. It will receive two arguments with the old and the new Visual Console's
+ * data structure.
+ * @return {VisualConsole | null} The Visual Console instance or a null value.
+ */
+// eslint-disable-next-line no-unused-vars
+function createVisualConsole(
+ container,
+ props,
+ items,
+ baseUrl,
+ updateInterval,
+ onUpdate
+) {
+ var visualConsole = null;
+ var linkedVCRequest = null;
+ var updateVCRequest = null;
+
+ if (container == null || props == null || items == null) return null;
+ if (baseUrl == null) baseUrl = "";
+
+ // Code which will be executed between intervals.
+ var intervalRef = null;
+ var stopInterval = function() {
+ if (intervalRef !== null) window.clearInterval(intervalRef);
+ };
+ var startInterval = function() {
+ if (updateInterval == null || updateInterval <= 0) return;
+ stopInterval();
+
+ intervalRef = window.setInterval(function() {
+ if (updateVCRequest !== null) updateVCRequest.abort();
+ updateVCRequest = loadVisualConsoleData(
+ baseUrl,
+ visualConsole.props.id,
+ function(error, data) {
+ if (error) {
+ console.log(
+ "[ERROR]",
+ "[VISUAL-CONSOLE-CLIENT]",
+ "[API]",
+ error.message
+ );
+ return;
+ }
+
+ // Replace Visual Console.
+ if (data != null && data.props != null && data.items != null) {
+ try {
+ var props =
+ typeof data.props === "string"
+ ? JSON.parse(data.props)
+ : data.props;
+ var items =
+ typeof data.items === "string"
+ ? JSON.parse(data.items)
+ : data.items;
+
+ var prevProps = visualConsole.props;
+ // Update the data structure.
+ visualConsole.props = props;
+ // Update the items.
+ visualConsole.updateElements(items);
+ // Emit the VC update event.
+ if (onUpdate) onUpdate(prevProps, visualConsole.props);
+ } catch (ignored) {} // eslint-disable-line no-empty
+ }
+ }
+ );
+ }, updateInterval);
+ };
+
+ // Initialize the Visual Console.
+ try {
+ visualConsole = new VisualConsole(container, props, items);
+ // VC Item clicked.
+ visualConsole.onClick(function(e) {
+ // Override the link to another VC if it isn't on remote console.
+ if (
+ e.data &&
+ e.data.linkedLayoutId != null &&
+ e.data.linkedLayoutId > 0 &&
+ e.data.link != null &&
+ e.data.link.length > 0 &&
+ (e.data.linkedLayoutAgentId == null || e.data.linkedLayoutAgentId === 0)
+ ) {
+ // Stop the current link behavior.
+ e.nativeEvent.preventDefault();
+
+ // Fetch and update the old VC with the new.
+ if (linkedVCRequest !== null) linkedVCRequest.abort();
+ linkedVCRequest = loadVisualConsoleData(
+ baseUrl,
+ e.data.linkedLayoutId,
+ function(error, data) {
+ if (error) {
+ console.log(
+ "[ERROR]",
+ "[VISUAL-CONSOLE-CLIENT]",
+ "[API]",
+ error.message
+ );
+ return;
+ }
+
+ // Replace Visual Console.
+ if (data != null && data.props != null && data.items != null) {
+ // Cancel the old VC updates.
+ stopInterval();
+
+ try {
+ var props =
+ typeof data.props === "string"
+ ? JSON.parse(data.props)
+ : data.props;
+ var items =
+ typeof data.items === "string"
+ ? JSON.parse(data.items)
+ : data.items;
+
+ if (updateVCRequest !== null) updateVCRequest.abort();
+ // Save the old props.
+ var prevProps = visualConsole.props;
+ // Update the data structure.
+ visualConsole.props = props;
+ // Update the items.
+ visualConsole.updateElements(items);
+ // Emit the VC update event.
+ if (onUpdate) onUpdate(prevProps, visualConsole.props);
+ } catch (ignored) {} // eslint-disable-line no-empty
+
+ // Restart the updates.
+ startInterval();
+ }
+ }
+ );
+ }
+ });
+
+ // Start an interval to update the Visual Console.
+ startInterval();
+ } catch (error) {
+ console.log("[ERROR]", "[VISUAL-CONSOLE-CLIENT]", error.message);
+ }
+
+ return visualConsole;
+}
+
+/**
+ * Fetch a Visual Console's structure and its items.
+ * @param {string} baseUrl Base URL to build the API path.
+ * @param {number} vcId Identifier of the Visual Console.
+ * @param {function} callback Function to be executed on request success or fail.
+ * On success, the function will receive an object with the next properties:
+ * - `props`: object with the Visual Console's data structure.
+ * - `items`: array of data structures of the Visual Console's items.
+ * @return {Object} Cancellable. Object which include and .abort([statusText]) function.
+ */
+// eslint-disable-next-line no-unused-vars
+function loadVisualConsoleData(baseUrl, vcId, callback) {
+ // var apiPath = baseUrl + "/include/rest-api";
+ var apiPath = baseUrl + "/ajax.php";
+ var vcJqXHR = null;
+ var itemsJqXHR = null;
+
+ // Initialize the final result.
+ var result = {
+ props: null,
+ items: null
+ };
+
+ // Cancel the ajax requests.
+ var abort = function(textStatus) {
+ if (textStatus == null) textStatus = "abort";
+
+ // -- XMLHttpRequest.readyState --
+ // Value State Description
+ // 0 UNSENT Client has been created. open() not called yet.
+ // 4 DONE The operation is complete.
+
+ if (vcJqXHR.readyState !== 0 && vcJqXHR.readyState !== 4)
+ vcJqXHR.abort(textStatus);
+ if (itemsJqXHR.readyState !== 0 && itemsJqXHR.readyState !== 4)
+ itemsJqXHR.abort(textStatus);
+ };
+
+ // Check if the required data is complete.
+ var checkResult = function() {
+ return result.props !== null && result.items !== null;
+ };
+
+ // Failed request handler.
+ var handleFail = function(jqXHR, textStatus, errorThrown) {
+ abort();
+ // Manually aborted or not.
+ if (textStatus === "abort") {
+ callback();
+ } else {
+ var error = new Error(errorThrown);
+ error.request = jqXHR;
+ callback(error);
+ }
+ };
+
+ // Curried function which handle success.
+ var handleSuccess = function(key) {
+ // Actual request handler.
+ return function(data) {
+ result[key] = data;
+ if (checkResult()) callback(null, result);
+ };
+ };
+
+ // Visual Console container request.
+ vcJqXHR = jQuery
+ // .get(apiPath + "/visual-consoles/" + vcId, null, "json")
+ .get(
+ apiPath,
+ {
+ page: "include/rest-api/index",
+ getVisualConsole: 1,
+ visualConsoleId: vcId
+ },
+ "json"
+ )
+ .done(handleSuccess("props"))
+ .fail(handleFail);
+ // Visual Console items request.
+ itemsJqXHR = jQuery
+ // .get(apiPath + "/visual-consoles/" + vcId + "/items", null, "json")
+ .get(
+ apiPath,
+ {
+ page: "include/rest-api/index",
+ getVisualConsoleItems: 1,
+ visualConsoleId: vcId
+ },
+ "json"
+ )
+ .done(handleSuccess("items"))
+ .fail(handleFail);
+
+ // Abortable.
+ return {
+ abort: abort
+ };
+}
+
+// TODO: Delete the functions below when you can.
/**************************************
These functions require jQuery library
**************************************/
diff --git a/pandora_console/include/languages/en_GB.po b/pandora_console/include/languages/en_GB.po
index 193705f89d..c6e833bc32 100644
--- a/pandora_console/include/languages/en_GB.po
+++ b/pandora_console/include/languages/en_GB.po
@@ -36481,8 +36481,8 @@ msgstr ""
#: ../../enterprise/load_enterprise.php:584
#, php-format
msgid ""
-"License out of limits "
-"This node has a metaconsole license and it allows %d agents and you have %d "
+"Out of license limits "
+"This node has a Metaconsole license that allows %d agents, and you have %d "
"agents cached."
msgstr ""
"License expired This "
@@ -36492,20 +36492,21 @@ msgstr ""
#: ../../enterprise/load_enterprise.php:592
#, php-format
msgid ""
-"License out of limits "
-"This license allows %d agents and you have %d agents configured."
+"Out of license limits "
+"This node has a Metaconsole license that allows %d agents, and you have %d "
+"agents configured."
msgstr ""
"License expired This "
-"license allows %d agents and you have %d agents configured."
+"license allows %d agents, and you have %d agents configured."
#: ../../enterprise/load_enterprise.php:597
#, php-format
msgid ""
-"License out of limits "
+"Out of license limits "
"This license allows %d modules and you have %d modules configured."
msgstr ""
-"License expired This "
-"license allows %d modules and you have %d modules configured."
+"Out of license limits This "
+"license allows %d modules, and you have %d modules configured."
#: ../../enterprise/load_enterprise.php:604
msgid ""
diff --git a/pandora_console/include/rest-api/index.php b/pandora_console/include/rest-api/index.php
new file mode 100644
index 0000000000..10f87488c7
--- /dev/null
+++ b/pandora_console/include/rest-api/index.php
@@ -0,0 +1,49 @@
+ $visualConsoleId]);
+ $visualConsoleData = $visualConsole->toArray();
+ $groupId = $visualConsoleData['groupId'];
+
+ // ACL.
+ $aclRead = check_acl($config['id_user'], $groupId, 'VR');
+ $aclWrite = check_acl($config['id_user'], $groupId, 'VW');
+ $aclManage = check_acl($config['id_user'], $groupId, 'VM');
+
+ if (!$aclRead && !$aclWrite && !$aclManage) {
+ db_pandora_audit(
+ 'ACL Violation',
+ 'Trying to access visual console without group access'
+ );
+ exit;
+ }
+
+ echo $visualConsole;
+} else if ($getVisualConsoleItems === true) {
+ $vcItems = VisualConsole::getItemsFromDB($visualConsoleId, $aclUserGroups);
+ echo '['.implode($vcItems, ',').']';
+}
+
+exit;
diff --git a/pandora_console/include/rest-api/models/Model.php b/pandora_console/include/rest-api/models/Model.php
new file mode 100644
index 0000000000..78ef90468e
--- /dev/null
+++ b/pandora_console/include/rest-api/models/Model.php
@@ -0,0 +1,231 @@
+validateData($unknownData);
+ $this->data = $this->decode($unknownData);
+ // Sort alphabetically.
+ ksort($this->data, (SORT_NATURAL | SORT_FLAG_CASE));
+ }
+
+
+ /**
+ * Instance the class with the unknown input data.
+ *
+ * @param array $data Unknown data structure.
+ *
+ * @return self Instance of the model.
+ */
+ public static function fromArray(array $data)
+ {
+ // The reserved word static refers to the invoked class at runtime.
+ return new static($data);
+ }
+
+
+ /**
+ * Obtain a data structure from the database using a filter.
+ *
+ * @param array $filter Filter to retrieve the modeled element.
+ *
+ * @return array The modeled element data structure stored into the DB.
+ * @throws \Exception When the data cannot be retrieved from the DB.
+ *
+ * @abstract
+ */
+ abstract protected static function fetchDataFromDB(array $filter);
+
+
+ /**
+ * Obtain a model's instance from the database using a filter.
+ *
+ * @param array $filter Filter to retrieve the modeled element.
+ *
+ * @return self A modeled element's instance.
+ */
+ public static function fromDB(array $filter): self
+ {
+ // The reserved word static refers to the invoked class at runtime.
+ return static::fromArray(static::fetchDataFromDB($filter));
+ }
+
+
+ /**
+ * JSON representation of the model.
+ *
+ * @return string
+ */
+ public function toArray(): array
+ {
+ return $this->data;
+ }
+
+
+ /**
+ * JSON representation of the model.
+ *
+ * @return string
+ */
+ public function toJson(): string
+ {
+ return \json_encode($this->data);
+ }
+
+
+ /**
+ * Text representation of the model.
+ *
+ * @return string
+ */
+ public function __toString(): string
+ {
+ return $this->toJson();
+ }
+
+
+ /*
+ * -------------
+ * - UTILITIES -
+ * -------------
+ */
+
+
+ /**
+ * From a unknown value, it will try to extract a valid boolean value.
+ *
+ * @param mixed $value Unknown input.
+ *
+ * @return boolean Valid boolean value.
+ */
+ protected static function parseBool($value): bool
+ {
+ if (\is_bool($value) === true) {
+ return $value;
+ } else if (\is_numeric($value) === true) {
+ return $value > 0;
+ } else if (\is_string($value) === true) {
+ return $value === '1' || $value === 'true';
+ } else {
+ return false;
+ }
+ }
+
+
+ /**
+ * Return a not empty string or a default value from a unknown value.
+ *
+ * @param mixed $val Input value.
+ * @param mixed $def Default value.
+ *
+ * @return mixed A valid string (not empty) extracted from the input
+ * or the default value.
+ */
+ protected static function notEmptyStringOr($val, $def)
+ {
+ return (\is_string($val) === true && strlen($val) > 0) ? $val : $def;
+ }
+
+
+ /**
+ * Return a valid integer or a default value from a unknown value.
+ *
+ * @param mixed $val Input value.
+ * @param mixed $def Default value.
+ *
+ * @return mixed A valid int extracted from the input or the default value.
+ */
+ protected static function parseIntOr($val, $def)
+ {
+ return (is_numeric($val) === true) ? (int) $val : $def;
+ }
+
+
+ /**
+ * Return a valid float or a default value from a unknown value.
+ *
+ * @param mixed $val Input value.
+ * @param mixed $def Default value.
+ *
+ * @return mixed A valid float extracted from the input or the
+ * default value.
+ */
+ protected static function parseFloatOr($val, $def)
+ {
+ return (is_numeric($val) === true) ? (float) $val : $def;
+ }
+
+
+ /**
+ * Get a value from a dictionary from a possible pool of keys.
+ *
+ * @param array $dict Input array.
+ * @param array $keys Possible keys.
+ *
+ * @return mixed The first value found with the pool of keys or null.
+ */
+ protected static function issetInArray(array $dict, array $keys)
+ {
+ foreach ($keys as $key => $value) {
+ if (isset($dict[$value]) === true) {
+ return $dict[$value];
+ }
+ }
+
+ return null;
+ }
+
+
+}
diff --git a/pandora_console/include/rest-api/models/VisualConsole/Container.php b/pandora_console/include/rest-api/models/VisualConsole/Container.php
new file mode 100644
index 0000000000..b8f7762615
--- /dev/null
+++ b/pandora_console/include/rest-api/models/VisualConsole/Container.php
@@ -0,0 +1,376 @@
+ (int) $data['id'],
+ 'name' => $data['name'],
+ 'groupId' => static::extractGroupId($data),
+ 'backgroundImage' => static::extractBackgroundImage($data),
+ 'backgroundColor' => static::extractBackgroundColor($data),
+ 'isFavorite' => static::extractFavorite($data),
+ 'width' => (int) $data['width'],
+ 'height' => (int) $data['height'],
+ 'backgroundURL' => static::extractBackgroundUrl($data),
+ 'relationLineWidth' => (int) $data['relationLineWidth'],
+ ];
+ }
+
+
+ /**
+ * Extract a group Id value.
+ *
+ * @param array $data Unknown input data structure.
+ *
+ * @return integer Valid identifier of a group.
+ *
+ * @throws \InvalidArgumentException When a valid group Id can't be found.
+ */
+ private static function extractGroupId(array $data): int
+ {
+ $groupId = static::parseIntOr(
+ static::issetInArray($data, ['id_group', 'groupId']),
+ null
+ );
+
+ if ($groupId === null || $groupId < 0) {
+ throw new \InvalidArgumentException(
+ 'the group Id property is required and should be integer'
+ );
+ }
+
+ return $groupId;
+ }
+
+
+ /**
+ * Extract a image name value.
+ *
+ * @param array $data Unknown input data structure.
+ *
+ * @return mixed String representing the image name (not empty) or null.
+ */
+ private static function extractBackgroundImage(array $data)
+ {
+ $backgroundImage = static::notEmptyStringOr(
+ static::issetInArray($data, ['background', 'backgroundURL']),
+ null
+ );
+
+ return ($backgroundImage === 'None.png') ? null : $backgroundImage;
+ }
+
+
+ /**
+ * Extract a image url value.
+ *
+ * @param array $data Unknown input data structure.
+ *
+ * @return mixed String representing the image url (not empty) or null.
+ */
+ private static function extractBackgroundUrl(array $data)
+ {
+ return static::notEmptyStringOr(
+ static::issetInArray($data, ['backgroundURL']),
+ null
+ );
+ }
+
+
+ /**
+ * Extract a background color value.
+ *
+ * @param array $data Unknown input data structure.
+ *
+ * @return mixed String representing the color (not empty) or null.
+ */
+ private static function extractBackgroundColor(array $data)
+ {
+ return static::notEmptyStringOr(
+ static::issetInArray(
+ $data,
+ [
+ 'backgroundColor',
+ 'background_color',
+ ]
+ ),
+ null
+ );
+ }
+
+
+ /**
+ * Extract the "is favorite" switch value.
+ *
+ * @param array $data Unknown input data structure.
+ *
+ * @return boolean If the item is favorite or not.
+ */
+ private static function extractFavorite(array $data): bool
+ {
+ return static::parseBool(
+ static::issetInArray($data, ['is_favourite', 'isFavorite'])
+ );
+ }
+
+
+ /**
+ * Obtain a container data structure from the database using a filter.
+ *
+ * @param array $filter Filter of the Visual Console.
+ *
+ * @return self A Visual Console Container instance.
+ * @throws \Exception When the data cannot be retrieved from the DB.
+ *
+ * @override Model::fetchDataFromDB.
+ */
+ protected static function fetchDataFromDB(array $filter)
+ {
+ // Due to this DB call, this function cannot be unit tested without
+ // a proper mock.
+ $row = \db_get_row_filter('tlayout', $filter);
+
+ if ($row === false) {
+ throw new \Exception('error fetching the data from the DB');
+ }
+
+ // Load side libraries.
+ global $config;
+ include_once $config['homedir'].'/include/functions_io.php';
+ include_once $config['homedir'].'/include/functions_ui.php';
+
+ // Clean HTML entities.
+ $row = \io_safe_output($row);
+
+ $row['relationLineWidth'] = (int) $config['vc_line_thickness'];
+
+ $backgroundUrl = static::extractBackgroundUrl($row);
+ $backgroundImage = static::extractBackgroundImage($row);
+
+ if ($backgroundUrl === null && $backgroundImage !== null) {
+ $row['backgroundURL'] = ui_get_full_url(
+ 'images/console/background/'.$backgroundImage,
+ false,
+ false,
+ false
+ );
+ }
+
+ return \io_safe_output($row);
+ }
+
+
+ /**
+ * Obtain a item's class.
+ *
+ * @param integer $type Type of the item of the Visual Console.
+ *
+ * @return mixed A reference to the item's class.
+ */
+ public static function getItemClass(int $type)
+ {
+ switch ($type) {
+ case STATIC_GRAPH:
+ return Items\StaticGraph::class;
+
+ case MODULE_GRAPH:
+ return Items\ModuleGraph::class;
+
+ case SIMPLE_VALUE:
+ case SIMPLE_VALUE_MAX:
+ case SIMPLE_VALUE_MIN:
+ case SIMPLE_VALUE_AVG:
+ return Items\SimpleValue::class;
+
+ case PERCENTILE_BAR:
+ case PERCENTILE_BUBBLE:
+ case CIRCULAR_PROGRESS_BAR:
+ case CIRCULAR_INTERIOR_PROGRESS_BAR:
+ return Items\Percentile::class;
+
+ case LABEL:
+ return Items\Label::class;
+
+ case ICON:
+ return Items\Icon::class;
+
+ // Enterprise item. It may not exist.
+ case SERVICE:
+ return \class_exists('\Enterprise\Models\VisualConsole\Items\Service') ? \Enterprise\Models\VisualConsole\Items\Service::class : Item::class;
+
+ case GROUP_ITEM:
+ return Items\Group::class;
+
+ case BOX_ITEM:
+ return Items\Box::class;
+
+ case LINE_ITEM:
+ return Items\Line::class;
+
+ case AUTO_SLA_GRAPH:
+ return Items\EventsHistory::class;
+
+ case DONUT_GRAPH:
+ return Items\DonutGraph::class;
+
+ case BARS_GRAPH:
+ return Items\BarsGraph::class;
+
+ case CLOCK:
+ return Items\Clock::class;
+
+ case COLOR_CLOUD:
+ return Items\ColorCloud::class;
+
+ default:
+ return Item::class;
+ }
+ }
+
+
+ /**
+ * Obtain a list of items which belong to the Visual Console.
+ *
+ * @param integer $layoutId Identifier of the Visual Console.
+ * @param array $groupsFilter Groups can access user.
+ *
+ * @return array A list of items.
+ * @throws \Exception When the data cannot be retrieved from the DB.
+ */
+ public static function getItemsFromDB(
+ int $layoutId,
+ array $groupsFilter=[]
+ ): array {
+ // Default filter.
+ $filter = ['id_layout' => $layoutId];
+ $fields = [
+ 'id',
+ 'type',
+ ];
+
+ // Override the filter if the groups filter is not empty.
+ if (count($groupsFilter) > 0) {
+ // Filter group for elements groups.
+ $filter = [];
+ $filter[] = \db_format_array_where_clause_sql(
+ [
+ 'id_layout' => $layoutId,
+ 'element_group' => $groupsFilter,
+ ]
+ );
+
+ // Filter groups for type groups.
+ // Only true condition if type is GROUP_ITEM.
+ $filter[] = '('.\db_format_array_where_clause_sql(
+ [
+ 'type' => GROUP_ITEM,
+ 'id_group' => $groupsFilter,
+ ]
+ ).')';
+ }
+
+ $rows = \db_get_all_rows_filter(
+ 'tlayout_data',
+ $filter,
+ $fields,
+ 'OR'
+ );
+
+ if ($rows === false) {
+ $rows = [];
+ }
+
+ $items = [];
+
+ foreach ($rows as $data) {
+ $itemId = (int) $data['id'];
+ $itemType = (int) $data['type'];
+ $class = static::getItemClass($itemType);
+
+ try {
+ array_push($items, $class::fromDB(['id' => $itemId]));
+ } catch (\Throwable $e) {
+ // TODO: Log this?
+ }
+ }
+
+ return $items;
+ }
+
+
+}
diff --git a/pandora_console/include/rest-api/models/VisualConsole/Item.php b/pandora_console/include/rest-api/models/VisualConsole/Item.php
new file mode 100644
index 0000000000..d29e3e645d
--- /dev/null
+++ b/pandora_console/include/rest-api/models/VisualConsole/Item.php
@@ -0,0 +1,1111 @@
+ (int) $data['id'],
+ 'type' => (int) $data['type'],
+ 'label' => static::extractLabel($data),
+ 'labelPosition' => static::extractLabelPosition($data),
+ 'isLinkEnabled' => static::extractIsLinkEnabled($data),
+ 'isOnTop' => static::extractIsOnTop($data),
+ 'parentId' => static::extractParentId($data),
+ 'aclGroupId' => static::extractAclGroupId($data),
+ 'width' => (int) $data['width'],
+ 'height' => (int) $data['height'],
+ 'x' => static::extractX($data),
+ 'y' => static::extractY($data),
+ ];
+
+ if (static::$useLinkedModule === true) {
+ $decodedData = array_merge(
+ $decodedData,
+ static::extractLinkedModule($data)
+ );
+ } else if (static::$useLinkedAgent === true) {
+ $decodedData = array_merge(
+ $decodedData,
+ static::extractLinkedAgent($data)
+ );
+ }
+
+ if (static::$useLinkedVisualConsole === true) {
+ $decodedData = array_merge(
+ $decodedData,
+ static::extractLinkedVisualConsole($data)
+ );
+ }
+
+ if (static::$useHtmlOutput === true) {
+ $decodedData['encodedHtml'] = static::extractEncodedHtml($data);
+ }
+
+ // Conditionally add the item link.
+ if ($decodedData['isLinkEnabled'] === true) {
+ $decodedData['link'] = static::notEmptyStringOr(
+ static::issetInArray($data, ['link']),
+ null
+ );
+ }
+
+ return $decodedData;
+ }
+
+
+ /**
+ * Extract x y axis value.
+ *
+ * @param array $data Unknown input data structure.
+ *
+ * @return integer Valid x axis position of the item.
+ */
+ private static function extractX(array $data): int
+ {
+ return static::parseIntOr(
+ static::issetInArray($data, ['x', 'pos_x']),
+ 0
+ );
+ }
+
+
+ /**
+ * Extract a y axis value.
+ *
+ * @param array $data Unknown input data structure.
+ *
+ * @return integer Valid y axis position of the item.
+ */
+ private static function extractY(array $data): int
+ {
+ return static::parseIntOr(
+ static::issetInArray($data, ['y', 'pos_y']),
+ 0
+ );
+ }
+
+
+ /**
+ * Extract a group Id (for ACL) value.
+ *
+ * @param array $data Unknown input data structure.
+ *
+ * @return integer Valid identifier of a group.
+ */
+ private static function extractAclGroupId(array $data)
+ {
+ return static::parseIntOr(
+ static::issetInArray($data, ['id_group', 'aclGroupId']),
+ null
+ );
+ }
+
+
+ /**
+ * Extract a parent Id value.
+ *
+ * @param array $data Unknown input data structure.
+ *
+ * @return integer Valid identifier of the item's parent.
+ */
+ private static function extractParentId(array $data)
+ {
+ return static::parseIntOr(
+ static::issetInArray($data, ['parentId', 'parent_item']),
+ null
+ );
+ }
+
+
+ /**
+ * Extract the "is on top" switch value.
+ *
+ * @param array $data Unknown input data structure.
+ *
+ * @return boolean If the item is on top or not.
+ */
+ private static function extractIsOnTop(array $data): bool
+ {
+ return static::parseBool(
+ static::issetInArray($data, ['isOnTop', 'show_on_top'])
+ );
+ }
+
+
+ /**
+ * Extract the "is link enabled" switch value.
+ *
+ * @param array $data Unknown input data structure.
+ *
+ * @return boolean If the item has the link enabled or not.
+ */
+ private static function extractIsLinkEnabled(array $data): bool
+ {
+ return static::parseBool(
+ static::issetInArray($data, ['isLinkEnabled', 'enable_link'])
+ );
+ }
+
+
+ /**
+ * Extract a label value.
+ *
+ * @param array $data Unknown input data structure.
+ *
+ * @return mixed String representing the label (not empty) or null.
+ */
+ private static function extractLabel(array $data)
+ {
+ return static::notEmptyStringOr(
+ static::issetInArray($data, ['label']),
+ null
+ );
+ }
+
+
+ /**
+ * Extract a label position value.
+ *
+ * @param array $data Unknown input data structure.
+ *
+ * @return mixed One string of up|right|left|down. down by default.
+ */
+ private static function extractLabelPosition(array $data): string
+ {
+ $labelPosition = static::notEmptyStringOr(
+ static::issetInArray($data, ['labelPosition', 'label_position']),
+ null
+ );
+
+ switch ($labelPosition) {
+ case 'up':
+ case 'right':
+ case 'left':
+ return $labelPosition;
+
+ default:
+ return 'down';
+ }
+ }
+
+
+ /**
+ * Extract an agent Id value.
+ *
+ * @param array $data Unknown input data structure.
+ *
+ * @return integer Valid identifier of an agent.
+ */
+ private static function extractAgentId(array $data)
+ {
+ return static::parseIntOr(
+ static::issetInArray($data, ['agentId', 'id_agent', 'id_agente']),
+ null
+ );
+ }
+
+
+ /**
+ * Extract an module Id value.
+ *
+ * @param array $data Unknown input data structure.
+ *
+ * @return integer Valid identifier of a module.
+ */
+ private static function extractModuleId(array $data)
+ {
+ return static::parseIntOr(
+ static::issetInArray(
+ $data,
+ [
+ 'moduleId',
+ 'id_agente_modulo',
+ 'id_modulo',
+ ]
+ ),
+ null
+ );
+ }
+
+
+ /**
+ * Extract an metaconsole node Id value.
+ *
+ * @param array $data Unknown input data structure.
+ *
+ * @return integer Valid identifier of a metaconsole node.
+ */
+ private static function extractMetaconsoleId(array $data)
+ {
+ return static::parseIntOr(
+ static::issetInArray($data, ['metaconsoleId', 'id_metaconsole']),
+ null
+ );
+ }
+
+
+ /**
+ * Extract the values of a linked agent.
+ *
+ * @param array $data Unknown input data structure.
+ *
+ * @return array Data structure of the linked agent info.
+ *
+ * @example [
+ * 'metaconsoleId' => 1,
+ * 'agentId' => 2,
+ * 'agentName' => 'Foo',
+ * ]
+ * @example [
+ * 'agentId' => 20,
+ * 'agentName' => 'Bar',
+ * ]
+ * @example [
+ * 'agentId' => null,
+ * 'agentName' => null,
+ * ]
+ */
+ protected static function extractLinkedAgent(array $data): array
+ {
+ $agentData = [];
+
+ // We should add the metaconsole Id if we can.
+ $metaconsoleId = static::extractMetaconsoleId($data);
+ if ($metaconsoleId !== null && $metaconsoleId <= 0) {
+ $agentData['metaconsoleId'] = null;
+ } else {
+ $agentData['metaconsoleId'] = $metaconsoleId;
+ }
+
+ // The agent Id should be a valid int or a null value.
+ $agentData['agentId'] = static::extractAgentId($data);
+
+ // The agent name should be a valid string or a null value.
+ $agentData['agentName'] = static::notEmptyStringOr(
+ static::issetInArray($data, ['agentName', 'agent_name']),
+ null
+ );
+
+ // The agent alias should be a valid string or a null value.
+ $agentData['agentAlias'] = static::notEmptyStringOr(
+ static::issetInArray($data, ['agentAlias', 'agent_alias']),
+ null
+ );
+
+ // The agent description should be a valid string or a null value.
+ $agentData['agentDescription'] = static::notEmptyStringOr(
+ static::issetInArray($data, ['agentDescription', 'agent_description']),
+ null
+ );
+
+ // The agent address should be a valid string or a null value.
+ $agentData['agentAddress'] = static::notEmptyStringOr(
+ static::issetInArray($data, ['agentAddress', 'agent_address']),
+ null
+ );
+
+ return $agentData;
+ }
+
+
+ /**
+ * Extract the values of a linked module.
+ *
+ * @param array $data Unknown input data structure.
+ *
+ * @return array Data structure of the linked module info.
+ *
+ * @example [
+ * 'metaconsoleId' => 1,
+ * 'agentId' => 2,
+ * 'agentName' => 'Foo',
+ * 'moduleId' => 1,
+ * 'moduleName' => 'cpu',
+ * ]
+ * @example [
+ * 'agentId' => 4,
+ * 'agentName' => 'Bar',
+ * 'moduleId' => null,
+ * 'moduleName' => null,
+ * ]
+ * @example [
+ * 'agentId' => null,
+ * 'agentName' => null,
+ * 'moduleId' => null,
+ * 'moduleName' => null,
+ * ]
+ */
+ protected static function extractLinkedModule(array $data): array
+ {
+ // Initialize the data with the agent data and then expand it.
+ $moduleData = static::extractLinkedAgent($data);
+
+ // The module Id should be a valid int or a null value.
+ $moduleData['moduleId'] = static::extractModuleId($data);
+
+ // The module name should be a valid string or a null value.
+ $moduleData['moduleName'] = static::notEmptyStringOr(
+ static::issetInArray($data, ['moduleName', 'module_name']),
+ null
+ );
+
+ // The module description should be a valid string or a null value.
+ $moduleData['moduleDescription'] = static::notEmptyStringOr(
+ static::issetInArray($data, ['moduleDescription', 'module_description']),
+ null
+ );
+
+ return $moduleData;
+ }
+
+
+ /**
+ * Extract the values of a linked visual console.
+ *
+ * @param array $data Unknown input data structure.
+ *
+ * @return array Data structure of the linked visual console info.
+ *
+ * @example [
+ * 'metaconsoleId' => 2,
+ * 'linkedLayoutId' => 12,
+ * 'linkedLayoutAgentId' => 48,
+ * 'linkedLayoutStatusType' => 'default',
+ * ]
+ * @example [
+ * 'linkedLayoutId' => 11,
+ * 'linkedLayoutAgentId' => null,
+ * 'linkedLayoutStatusType' => 'weight',
+ * 'linkedLayoutStatusTypeWeight' => 80,
+ * ]
+ * @example [
+ * 'metaconsoleId' => 2,
+ * 'linkedLayoutId' => 10,
+ * 'linkedLayoutAgentId' => 48,
+ * 'linkedLayoutStatusType' => 'service',
+ * 'linkedLayoutStatusTypeWarningThreshold' => 50,
+ * 'linkedLayoutStatusTypeCriticalThreshold' => 80,
+ * ]
+ */
+ private static function extractLinkedVisualConsole(array $data): array
+ {
+ $vcData = [];
+
+ // We should add the metaconsole Id if we can. If not,
+ // it doesn't have to be into the structure.
+ $metaconsoleId = static::extractMetaconsoleId($data);
+ if ($metaconsoleId !== null) {
+ $vcData['metaconsoleId'] = $metaconsoleId;
+ }
+
+ // The linked vc Id should be a valid int or a null value.
+ $vcData['linkedLayoutId'] = static::parseIntOr(
+ static::issetInArray($data, ['linkedLayoutId', 'id_layout_linked']),
+ null
+ );
+
+ // The linked vc agent Id should be a valid int or a null value.
+ $vcData['linkedLayoutAgentId'] = static::parseIntOr(
+ static::issetInArray(
+ $data,
+ [
+ 'linkedLayoutAgentId',
+ 'linked_layout_node_id',
+ ]
+ ),
+ null
+ );
+
+ // The linked vc status type should be a enum value.
+ $linkedLayoutStatusType = static::notEmptyStringOr(
+ static::issetInArray(
+ $data,
+ [
+ 'linkedLayoutStatusType',
+ 'linked_layout_status_type',
+ ]
+ ),
+ null
+ );
+
+ // Extract data for the calculation of the linked visual console status.
+ switch ($linkedLayoutStatusType) {
+ case 'default':
+ default:
+ $vcData['linkedLayoutStatusType'] = 'default';
+ break;
+
+ case 'weight':
+ $vcData['linkedLayoutStatusType'] = 'weight';
+ $vcData['linkedLayoutStatusTypeWeight'] = static::parseIntOr(
+ static::issetInArray(
+ $data,
+ [
+ 'linkedLayoutStatusTypeWeight',
+ 'id_layout_linked_weight',
+ ]
+ ),
+ 0
+ );
+ break;
+
+ case 'service':
+ $vcData['linkedLayoutStatusType'] = 'service';
+ $vcData['linkedLayoutStatusTypeWarningThreshold'] = static::parseIntOr(
+ static::issetInArray(
+ $data,
+ [
+ 'linkedLayoutStatusTypeWarningThreshold',
+ 'linked_layout_status_as_service_warning',
+ ]
+ ),
+ 0
+ );
+ $vcData['linkedLayoutStatusTypeCriticalThreshold'] = static::parseIntOr(
+ static::issetInArray(
+ $data,
+ [
+ 'linkedLayoutStatusTypeCriticalThreshold',
+ 'linked_layout_status_as_service_critical',
+ ]
+ ),
+ 0
+ );
+ break;
+ }
+
+ return $vcData;
+ }
+
+
+ /**
+ * Extract a encoded HTML representation of the item.
+ *
+ * @param array $data Unknown input data structure.
+ *
+ * @return string The HTML representation in base64 encoding.
+ */
+ private static function extractEncodedHtml(array $data): string
+ {
+ if (isset($data['encodedHtml']) === true) {
+ return $data['encodedHtml'];
+ } else if (isset($data['html']) === true) {
+ return base64_encode($data['html']);
+ }
+
+ return '';
+ }
+
+
+ /**
+ * Fetch a vc item data structure from the database using a filter.
+ *
+ * @param array $filter Filter of the Visual Console Item.
+ *
+ * @return array The Visual Console Item data structure stored into the DB.
+ * @throws \Exception When the data cannot be retrieved from the DB.
+ *
+ * @override Model::fetchDataFromDB.
+ */
+ protected static function fetchDataFromDB(array $filter): array
+ {
+ // Load side libraries.
+ global $config;
+ include_once $config['homedir'].'/include/functions_io.php';
+
+ // Due to this DB call, this function cannot be unit tested without
+ // a proper mock.
+ $row = \db_get_row_filter('tlayout_data', $filter);
+
+ if ($row === false) {
+ throw new \Exception('error fetching the data from the DB');
+ }
+
+ // Load side libraries.
+ global $config;
+ include_once $config['homedir'].'/include/functions_io.php';
+
+ // Clean up to two levels of HTML entities.
+ $row = \io_safe_output(\io_safe_output($row));
+
+ /*
+ * Retrieve extra data.
+ */
+
+ // The linked module includes the agent data.
+ if (static::$useLinkedModule === true) {
+ $row = array_merge($row, static::fetchModuleDataFromDB($row));
+ } else if (static::$useLinkedAgent === true) {
+ $row = array_merge($row, static::fetchAgentDataFromDB($row));
+ }
+
+ // Build the item link if needed.
+ if (static::extractIsLinkEnabled($row) === true) {
+ $row['link'] = static::buildLink($row);
+ }
+
+ return $row;
+ }
+
+
+ /**
+ * Fetch a data structure of an agent from the database using the
+ * vs item's data.
+ *
+ * @param array $itemData Visual Console Item's data structure.
+ *
+ * @return array The agent data structure stored into the DB.
+ *
+ * @throws \InvalidArgumentException When the input agent Id is invalid.
+ * @throws \Exception When the data cannot be retrieved from the DB.
+ */
+ protected static function fetchAgentDataFromDB(array $itemData): array
+ {
+ $agentData = [];
+
+ // We should add the metaconsole Id if we can.
+ $metaconsoleId = static::extractMetaconsoleId($itemData);
+
+ // Can't fetch an agent with an invalid Id.
+ $agentId = static::extractAgentId($itemData);
+ if ($agentId === null) {
+ throw new \InvalidArgumentException('invalid agent Id');
+ }
+
+ // Staticgraph don't need to have an agent.
+ if ($agentId === 0) {
+ return $agentData;
+ }
+
+ if (\is_metaconsole() && $metaconsoleId === null) {
+ throw new \InvalidArgumentException('missing metaconsole node Id');
+ }
+
+ $agent = false;
+
+ if (\is_metaconsole()) {
+ $sql = sprintf(
+ 'SELECT nombre, alias, direccion, comentarios
+ FROM tmetaconsole_agent
+ WHERE id_tagente = %s and id_tmetaconsole_setup = %s',
+ $agentId,
+ $metaconsoleId
+ );
+ } else {
+ $sql = sprintf(
+ 'SELECT nombre, alias, direccion, comentarios
+ FROM tagente
+ WHERE id_agente = %s',
+ $agentId
+ );
+ }
+
+ $agent = \db_get_row_sql($sql);
+
+ if ($agent === false) {
+ throw new \Exception('error fetching the data from the DB');
+ }
+
+ // The agent name should be a valid string or a null value.
+ $agentData['agentName'] = $agent['nombre'];
+ $agentData['agentAlias'] = $agent['alias'];
+ $agentData['agentDescription'] = $agent['comentarios'];
+ $agentData['agentAddress'] = $agent['direccion'];
+
+ return $agentData;
+ }
+
+
+ /**
+ * Fetch a data structure of an module from the database using the
+ * vs item's data.
+ *
+ * @param array $itemData Visual Console Item's data structure.
+ *
+ * @return array The module data structure stored into the DB.
+ * @throws \InvalidArgumentException When the input module Id is invalid.
+ * @throws \Exception When the data cannot be retrieved from the DB.
+ */
+ protected static function fetchModuleDataFromDB(array $itemData): array
+ {
+ // Load side libraries.
+ if (\is_metaconsole()) {
+ \enterprise_include_once('include/functions_metaconsole.php');
+ }
+
+ // Initialize with the agent data.
+ $moduleData = static::fetchAgentDataFromDB($itemData);
+
+ // Can't fetch an module with a invalid Id.
+ $moduleId = static::extractModuleId($itemData);
+ if ($moduleId === null) {
+ throw new \InvalidArgumentException('invalid module Id');
+ }
+
+ // Staticgraph don't need to have a module.
+ if ($moduleId === 0) {
+ return $moduleData;
+ }
+
+ // We should add the metaconsole Id if we can.
+ $metaconsoleId = static::extractMetaconsoleId($itemData);
+
+ if (\is_metaconsole() && $metaconsoleId === null) {
+ throw new \InvalidArgumentException('missing metaconsole node Id');
+ }
+
+ $moduleName = false;
+
+ // Connect to node.
+ if (\is_metaconsole()
+ && \metaconsole_connect(null, $metaconsoleId) !== NOERR
+ ) {
+ throw new \InvalidArgumentException(
+ 'error connecting to the node'
+ );
+ }
+
+ $sql = sprintf(
+ 'SELECT nombre, descripcion
+ FROM tagente_modulo
+ WHERE id_agente_modulo = %s',
+ $moduleId
+ );
+
+ $moduleName = \db_get_row_sql($sql);
+
+ // Restore connection.
+ if (\is_metaconsole()) {
+ \metaconsole_restore_db();
+ }
+
+ if ($moduleName === false) {
+ throw new \Exception('error fetching the data from the DB');
+ }
+
+ $moduleData['moduleName'] = $moduleName['nombre'];
+ $moduleData['moduleDescription'] = $moduleName['descripcion'];
+
+ return $moduleData;
+ }
+
+
+ /**
+ * Generate a link to something related with the item.
+ *
+ * @param array $data Visual Console Item's data structure.
+ *
+ * @return mixed The link or a null value.
+ * @throws \Exception Not really. It's controlled.
+ */
+ protected static function buildLink(array $data)
+ {
+ global $config;
+
+ // Load side libraries.
+ include_once $config['homedir'].'/include/functions_ui.php';
+ if (\is_metaconsole()) {
+ \enterprise_include_once('include/functions_metaconsole.php');
+ \enterprise_include_once('meta/include/functions_ui_meta.php');
+ }
+
+ $linkedVisualConsole = static::extractLinkedVisualConsole($data);
+ $linkedModule = static::extractLinkedModule($data);
+ $linkedAgent = static::extractLinkedAgent($data);
+
+ $baseUrl = \ui_get_full_url('index.php');
+
+ // TODO: There's a feature to get the link from the label.
+ if (static::$useLinkedVisualConsole === true
+ && $linkedVisualConsole['linkedLayoutId'] !== null
+ && $linkedVisualConsole['linkedLayoutId'] > 0
+ ) {
+ // Linked Visual Console.
+ $vcId = $linkedVisualConsole['linkedLayoutId'];
+ // The layout can be from another node.
+ $linkedLayoutAgentId = $linkedVisualConsole['linkedLayoutAgentId'];
+
+ if (empty($linkedLayoutAgentId) === true && \is_metaconsole()) {
+ /*
+ * A Visual Console from this console.
+ * We are in a metaconsole.
+ */
+
+ return $baseUrl.'?'.http_build_query(
+ [
+ 'sec' => 'screen',
+ 'sec2' => 'screens/screens',
+ 'action' => 'visualmap',
+ 'id_visualmap' => $vcId,
+ 'pure' => (int) $config['pure'],
+ ]
+ );
+ } else if (empty($linkedLayoutAgentId) === true
+ && !\is_metaconsole()
+ ) {
+ /*
+ * A Visual Console from this console.
+ * We are in a regular console.
+ */
+
+ return $baseUrl.'?'.http_build_query(
+ [
+ 'sec' => 'network',
+ 'sec2' => 'operation/visual_console/view',
+ 'id' => $vcId,
+ 'pure' => (int) $config['pure'],
+ ]
+ );
+ } else if (\is_metaconsole() && \can_user_access_node()) {
+ /*
+ * A Visual Console from a meta node.
+ * We are in a metaconsole.
+ */
+
+ try {
+ $node = \metaconsole_get_connection_by_id(
+ $linkedLayoutAgentId
+ );
+ return \ui_meta_get_node_url(
+ $node,
+ 'network',
+ // TODO: Link to a public view.
+ 'operation/visual_console/view',
+ [],
+ // No autologin from the public view.
+ !$config['public_view']
+ );
+ } catch (\Throwable $ignored) {
+ return null;
+ }
+ }
+ } else {
+ if (static::$useLinkedModule === true
+ && $linkedModule['moduleId'] !== null
+ && $linkedModule['moduleId'] > 0
+ ) {
+ // Module Id.
+ $moduleId = $linkedModule['moduleId'];
+ // The module can be from another node.
+ $metaconsoleId = $linkedModule['metaconsoleId'];
+
+ if (empty($metaconsoleId) === true) {
+ /*
+ * A module from this console.
+ */
+
+ // Check if the module is from a service.
+ $serviceId = (int) \db_get_value_filter(
+ 'custom_integer_1',
+ 'tagente_modulo',
+ [
+ 'id_agente_modulo' => $moduleId,
+ 'prediction_module' => 1,
+ ]
+ );
+
+ if (empty($serviceId) === false) {
+ // A service.
+ $queryParams = [
+ 'sec' => 'services',
+ 'sec2' => 'enterprise/operation/services/services',
+ 'id_service' => $serviceId,
+ ];
+ } else {
+ // A regular module.
+ $queryParams = [
+ 'sec' => 'view',
+ 'sec2' => 'operation/agentes/status_monitor',
+ 'id_module' => $moduleId,
+ ];
+ }
+
+ return $baseUrl.'?'.http_build_query($queryParams);
+ } else if (\is_metaconsole() && \can_user_access_node()) {
+ /*
+ * A module from a meta node.
+ * We are in a metaconsole.
+ */
+
+ try {
+ $node = \metaconsole_get_connection_by_id(
+ $metaconsoleId
+ );
+
+ // Connect to node.
+ if (\metaconsole_connect($node) !== NOERR) {
+ // Will be catched below.
+ throw new \Exception(
+ 'error connecting to the node'
+ );
+ }
+
+ // Check if the module is a service.
+ $serviceId = (int) \db_get_value_filter(
+ 'custom_integer_1',
+ 'tagente_modulo',
+ [
+ 'id_agente_modulo' => $moduleId,
+ 'prediction_module' => 1,
+ ]
+ );
+
+ // Restore connection.
+ \metaconsole_restore_db();
+
+ if (empty($serviceId) === false) {
+ // A service.
+ return \ui_meta_get_node_url(
+ $node,
+ 'services',
+ 'enterprise/operation/services/services',
+ ['id_service' => $serviceId],
+ // No autologin from the public view.
+ !$config['public_view']
+ );
+ } else {
+ // A regular module.
+ return \ui_meta_get_node_url(
+ $node,
+ 'view',
+ 'operation/agentes/status_monitor',
+ ['id_module' => $moduleId],
+ // No autologin from the public view.
+ !$config['public_view']
+ );
+ }
+ } catch (\Throwable $ignored) {
+ return null;
+ }
+ }
+ } else if ((static::$useLinkedAgent === true
+ || static::$useLinkedModule === true)
+ && $linkedAgent['agentId'] !== null
+ && $linkedAgent['agentId'] > 0
+ ) {
+ // Linked agent.
+ // Agent Id.
+ $agentId = $linkedAgent['agentId'];
+ // The agent can be from another node.
+ $metaconsoleId = $linkedAgent['metaconsoleId'];
+
+ if (empty($metaconsoleId) === true) {
+ /*
+ * An agent from this console.
+ * We are in a regular console.
+ */
+
+ return $baseUrl.'?'.http_build_query(
+ [
+ 'sec' => 'estado',
+ 'sec2' => 'operation/agentes/ver_agente',
+ 'id_agente' => $agentId,
+ ]
+ );
+ } else if (\is_metaconsole() && \can_user_access_node()) {
+ /*
+ * An agent from a meta node.
+ * We are in a metaconsole.
+ */
+
+ try {
+ $node = \metaconsole_get_connection_by_id(
+ $metaconsoleId
+ );
+ return \ui_meta_get_node_url(
+ $node,
+ 'estado',
+ 'operation/agentes/ver_agente',
+ ['id_agente' => $moduleId],
+ // No autologin from the public view.
+ !$config['public_view']
+ );
+ } catch (\Throwable $ignored) {
+ return null;
+ }
+ }
+ }
+ }
+
+ return null;
+ }
+
+
+}
diff --git a/pandora_console/include/rest-api/models/VisualConsole/Items/BarsGraph.php b/pandora_console/include/rest-api/models/VisualConsole/Items/BarsGraph.php
new file mode 100644
index 0000000000..4482b4d53d
--- /dev/null
+++ b/pandora_console/include/rest-api/models/VisualConsole/Items/BarsGraph.php
@@ -0,0 +1,346 @@
+extractGridColor($data);
+ $return['backgroundColor'] = $this->extractBackgroundColor($data);
+ $return['typeGraph'] = $this->extractTypeGraph($data);
+ return $return;
+ }
+
+
+ /**
+ * Extract a grid color value.
+ *
+ * @param array $data Unknown input data structure.
+ *
+ * @return mixed String representing the grid color (not empty) or null.
+ */
+ private function extractGridColor(array $data): string
+ {
+ return static::notEmptyStringOr(
+ static::issetInArray($data, ['gridColor', 'border_color']),
+ '#000000'
+ );
+ }
+
+
+ /**
+ * Extract a background color value.
+ *
+ * @param array $data Unknown input data structure.
+ *
+ * @return string One of 'white', 'black' or 'transparent'.
+ * 'white' by default.
+ */
+ private function extractBackgroundColor(array $data): string
+ {
+ $backgroundColor = static::notEmptyStringOr(
+ static::issetInArray($data, ['backgroundColor', 'image']),
+ null
+ );
+
+ switch ($backgroundColor) {
+ case 'black':
+ case 'transparent':
+ return $backgroundColor;
+
+ default:
+ return 'white';
+ }
+ }
+
+
+ /**
+ * Extract a type graph value.
+ *
+ * @param array $data Unknown input data structure.
+ *
+ * @return string One of 'vertical' or 'horizontal'. 'vertical' by default.
+ */
+ private function extractTypeGraph(array $data): string
+ {
+ $typeGraph = static::notEmptyStringOr(
+ static::issetInArray($data, ['typeGraph', 'type_graph']),
+ null
+ );
+
+ switch ($typeGraph) {
+ case 'horizontal':
+ return 'horizontal';
+
+ default:
+ return 'vertical';
+ }
+ }
+
+
+ /**
+ * Fetch a vc item data structure from the database using a filter.
+ *
+ * @param array $filter Filter of the Visual Console Item.
+ *
+ * @return array The Visual Console Item data structure stored into the DB.
+ * @throws \InvalidArgumentException When an agent Id cannot be found.
+ *
+ * @override Item::fetchDataFromDB.
+ */
+ protected static function fetchDataFromDB(array $filter): array
+ {
+ // Due to this DB call, this function cannot be unit tested without
+ // a proper mock.
+ $data = parent::fetchDataFromDB($filter);
+
+ /*
+ * Retrieve extra data.
+ */
+
+ // Load config.
+ global $config;
+
+ // Load side libraries.
+ include_once $config['homedir'].'/include/functions_ui.php';
+ include_once $config['homedir'].'/include/functions_visual_map.php';
+ include_once $config['homedir'].'/include/graphs/fgraph.php';
+
+ if (is_metaconsole()) {
+ \enterprise_include_once('include/functions_metaconsole.php');
+ }
+
+ // Extract needed properties.
+ $gridColor = static::extractGridColor($data);
+ $backGroundColor = static::extractBackgroundColor($data);
+ $typeGraph = static::extractTypeGraph($data);
+
+ // Get the linked agent and module Ids.
+ $linkedModule = static::extractLinkedModule($data);
+ $agentId = $linkedModule['agentId'];
+ $moduleId = $linkedModule['moduleId'];
+ $metaconsoleId = $linkedModule['metaconsoleId'];
+
+ if ($agentId === null) {
+ throw new \InvalidArgumentException('missing agent Id');
+ }
+
+ if ($moduleId === null) {
+ throw new \InvalidArgumentException('missing module Id');
+ }
+
+ // Add colors that will use the graphics.
+ $color = [];
+
+ $color[0] = [
+ 'border' => '#000000',
+ 'color' => $config['graph_color1'],
+ 'alpha' => CHART_DEFAULT_ALPHA,
+ ];
+ $color[1] = [
+ 'border' => '#000000',
+ 'color' => $config['graph_color2'],
+ 'alpha' => CHART_DEFAULT_ALPHA,
+ ];
+ $color[2] = [
+ 'border' => '#000000',
+ 'color' => $config['graph_color3'],
+ 'alpha' => CHART_DEFAULT_ALPHA,
+ ];
+ $color[3] = [
+ 'border' => '#000000',
+ 'color' => $config['graph_color4'],
+ 'alpha' => CHART_DEFAULT_ALPHA,
+ ];
+ $color[4] = [
+ 'border' => '#000000',
+ 'color' => $config['graph_color5'],
+ 'alpha' => CHART_DEFAULT_ALPHA,
+ ];
+ $color[5] = [
+ 'border' => '#000000',
+ 'color' => $config['graph_color6'],
+ 'alpha' => CHART_DEFAULT_ALPHA,
+ ];
+ $color[6] = [
+ 'border' => '#000000',
+ 'color' => $config['graph_color7'],
+ 'alpha' => CHART_DEFAULT_ALPHA,
+ ];
+ $color[7] = [
+ 'border' => '#000000',
+ 'color' => $config['graph_color8'],
+ 'alpha' => CHART_DEFAULT_ALPHA,
+ ];
+ $color[8] = [
+ 'border' => '#000000',
+ 'color' => $config['graph_color9'],
+ 'alpha' => CHART_DEFAULT_ALPHA,
+ ];
+ $color[9] = [
+ 'border' => '#000000',
+ 'color' => $config['graph_color10'],
+ 'alpha' => CHART_DEFAULT_ALPHA,
+ ];
+ $color[11] = [
+ 'border' => '#000000',
+ 'color' => COL_GRAPH9,
+ 'alpha' => CHART_DEFAULT_ALPHA,
+ ];
+ $color[12] = [
+ 'border' => '#000000',
+ 'color' => COL_GRAPH10,
+ 'alpha' => CHART_DEFAULT_ALPHA,
+ ];
+ $color[13] = [
+ 'border' => '#000000',
+ 'color' => COL_GRAPH11,
+ 'alpha' => CHART_DEFAULT_ALPHA,
+ ];
+ $color[14] = [
+ 'border' => '#000000',
+ 'color' => COL_GRAPH12,
+ 'alpha' => CHART_DEFAULT_ALPHA,
+ ];
+ $color[15] = [
+ 'border' => '#000000',
+ 'color' => COL_GRAPH13,
+ 'alpha' => CHART_DEFAULT_ALPHA,
+ ];
+
+ // Maybe connect to node.
+ $nodeConnected = false;
+ if (\is_metaconsole() === true && $metaconsoleId !== null) {
+ $nodeConnected = \metaconsole_connect(
+ null,
+ $metaconsoleId
+ ) === NOERR;
+
+ if ($nodeConnected === false) {
+ throw new \InvalidArgumentException(
+ 'error connecting to the node'
+ );
+ }
+ }
+
+ $moduleData = \get_bars_module_data($moduleId);
+
+ $waterMark = [
+ 'file' => $config['homedir'].'/images/logo_vertical_water.png',
+ 'url' => \ui_get_full_url(
+ 'images/logo_vertical_water.png',
+ false,
+ false,
+ false
+ ),
+ ];
+
+ if ((int) $data['width'] === 0 || (int) $data['height'] === 0) {
+ $width = 400;
+ $height = 400;
+ } else {
+ $width = (int) $data['width'];
+ $height = (int) $data['height'];
+ }
+
+ if ($typeGraph === 'horizontal') {
+ $graph = \hbar_graph(
+ $moduleData,
+ $width,
+ $height,
+ $color,
+ [],
+ [],
+ \ui_get_full_url(
+ 'images/image_problem_area.png',
+ false,
+ false,
+ false
+ ),
+ '',
+ '',
+ $waterMark,
+ $config['fontpath'],
+ 6,
+ '',
+ 0,
+ $config['homeurl'],
+ $backGroundColor,
+ $gridColor
+ );
+ } else {
+ $graph = \vbar_graph(
+ $moduleData,
+ $width,
+ $height,
+ $color,
+ [],
+ [],
+ \ui_get_full_url(
+ 'images/image_problem_area.png',
+ false,
+ false,
+ false
+ ),
+ '',
+ '',
+ $waterMark,
+ $config['fontpath'],
+ 6,
+ '',
+ 0,
+ $config['homeurl'],
+ $backGroundColor,
+ true,
+ false,
+ $gridColor
+ );
+ }
+
+ // Restore connection.
+ if ($nodeConnected === true) {
+ \metaconsole_restore_db();
+ }
+
+ $data['html'] = $graph;
+
+ return $data;
+ }
+
+
+}
diff --git a/pandora_console/include/rest-api/models/VisualConsole/Items/Box.php b/pandora_console/include/rest-api/models/VisualConsole/Items/Box.php
new file mode 100644
index 0000000000..144518ebb1
--- /dev/null
+++ b/pandora_console/include/rest-api/models/VisualConsole/Items/Box.php
@@ -0,0 +1,85 @@
+extractBorderWidth($data);
+ $boxData['borderColor'] = $this->extractBorderColor($data);
+ $boxData['fillColor'] = $this->extractFillColor($data);
+ return $boxData;
+ }
+
+
+ /**
+ * Extract a border width value.
+ *
+ * @param array $data Unknown input data structure.
+ *
+ * @return integer Valid border width. 0 by default.
+ */
+ private function extractBorderWidth(array $data): int
+ {
+ return static::parseIntOr(
+ static::issetInArray($data, ['borderWidth', 'border_width']),
+ 0
+ );
+ }
+
+
+ /**
+ * Extract a border color value.
+ *
+ * @param array $data Unknown input data structure.
+ *
+ * @return mixed String representing the border color (not empty) or null.
+ */
+ private function extractBorderColor(array $data)
+ {
+ return static::notEmptyStringOr(
+ static::issetInArray($data, ['borderColor', 'border_color']),
+ null
+ );
+ }
+
+
+ /**
+ * Extract a fill color value.
+ *
+ * @param array $data Unknown input data structure.
+ *
+ * @return mixed String representing the fill color (not empty) or null.
+ */
+ private function extractFillColor(array $data)
+ {
+ return static::notEmptyStringOr(
+ static::issetInArray($data, ['fillColor', 'fill_color']),
+ null
+ );
+ }
+
+
+}
diff --git a/pandora_console/include/rest-api/models/VisualConsole/Items/Clock.php b/pandora_console/include/rest-api/models/VisualConsole/Items/Clock.php
new file mode 100644
index 0000000000..ba72e0c30c
--- /dev/null
+++ b/pandora_console/include/rest-api/models/VisualConsole/Items/Clock.php
@@ -0,0 +1,154 @@
+getOffset(
+ $dateTimeUtc
+ );
+ } catch (\Throwable $e) {
+ throw new \InvalidArgumentException($e->getMessage());
+ }
+
+ // $clockData['showClockTimezone'] = static::parseBool(
+ // static::issetInArray($data, ['showClockTimezone'])
+ // );
+ // TODO: Remove the true by default when added into the editor.
+ $clockData['showClockTimezone'] = true;
+ $clockData['color'] = static::extractColor($data);
+ return $clockData;
+ }
+
+
+ /**
+ * Extract a clock type value.
+ *
+ * @param array $data Unknown input data structure.
+ *
+ * @return string One of 'digital' or 'analogic'. 'analogic' by default.
+ */
+ private static function extractClockType(array $data): string
+ {
+ $clockType = static::notEmptyStringOr(
+ static::issetInArray($data, ['clockType', 'clock_animation']),
+ null
+ );
+
+ switch ($clockType) {
+ case 'digital':
+ case 'digital_1':
+ return 'digital';
+
+ default:
+ return 'analogic';
+ }
+ }
+
+
+ /**
+ * Extract a clock format value.
+ *
+ * @param array $data Unknown input data structure.
+ *
+ * @return string One of 'time' or 'datetime'. 'datetime' by default.
+ */
+ private static function extractClockFormat(array $data): string
+ {
+ $clockFormat = static::notEmptyStringOr(
+ static::issetInArray($data, ['clockFormat', 'time_format']),
+ null
+ );
+
+ switch ($clockFormat) {
+ case 'time':
+ return 'time';
+
+ default:
+ return 'datetime';
+ }
+ }
+
+
+ /**
+ * Extract a clock timezone value.
+ *
+ * @param array $data Unknown input data structure.
+ *
+ * @return string
+ * @throws \InvalidArgumentException When a valid clock timezone cannot be
+ * extracted.
+ */
+ private static function extractClockTimezone(array $data): string
+ {
+ $clockTimezone = static::notEmptyStringOr(
+ static::issetInArray($data, ['clockTimezone', 'timezone']),
+ null
+ );
+
+ if ($clockTimezone === null) {
+ throw new \InvalidArgumentException(
+ 'the clockTimezone property is required and should be string'
+ );
+ }
+
+ return $clockTimezone;
+ }
+
+
+ /**
+ * Extract the color value.
+ *
+ * @param array $data Unknown input data structure.
+ *
+ * @return mixed returns a color or null.
+ */
+ private static function extractColor(array $data)
+ {
+ return static::notEmptyStringOr(
+ static::issetInArray($data, ['color', 'fill_color']),
+ null
+ );
+ }
+
+
+}
diff --git a/pandora_console/include/rest-api/models/VisualConsole/Items/ColorCloud.php b/pandora_console/include/rest-api/models/VisualConsole/Items/ColorCloud.php
new file mode 100644
index 0000000000..807d8fb3e9
--- /dev/null
+++ b/pandora_console/include/rest-api/models/VisualConsole/Items/ColorCloud.php
@@ -0,0 +1,281 @@
+decode.
+ */
+ protected function decode(array $data): array
+ {
+ $decodedData = parent::decode($data);
+ $decodedData['type'] = COLOR_CLOUD;
+ $decodedData['label'] = null;
+ $decodedData['defaultColor'] = static::extractDefaultColor($data);
+ $decodedData['colorRanges'] = static::extractColorRanges($data);
+ $decodedData['color'] = static::notEmptyStringOr(
+ static::issetInArray($data, ['color']),
+ null
+ );
+
+ return $decodedData;
+ }
+
+
+ /**
+ * Extract the default color value.
+ *
+ * @param array $data Unknown input data structure.
+ *
+ * @return string Default color.
+ * @throws \InvalidArgumentException If the default color cannot be
+ * extracted.
+ */
+ private static function extractDefaultColor(array $data): string
+ {
+ if (isset($data['defaultColor'])) {
+ $defaultColor = static::notEmptyStringOr(
+ $data['defaultColor'],
+ null
+ );
+
+ if ($defaultColor === null) {
+ throw new \InvalidArgumentException(
+ 'the default color property is required and should be a not empty string'
+ );
+ }
+
+ return $defaultColor;
+ } else {
+ $dynamicData = static::extractDynamicData($data);
+ return $dynamicData['defaultColor'];
+ }
+ }
+
+
+ /**
+ * Extract a list of color ranges.
+ *
+ * @param array $data Unknown input data structure.
+ *
+ * @return array Color ranges list.
+ * @throws \InvalidArgumentException If any of the color ranges is invalid.
+ */
+ private static function extractColorRanges(array $data): array
+ {
+ if (isset($data['colorRanges']) && \is_array($data['colorRanges'])) {
+ // Validate the color ranges.
+ foreach ($data['colorRanges'] as $colorRange) {
+ if (\is_numeric($colorRange['fromValue']) === false
+ || \is_numeric($colorRange['toValue']) === false
+ || static::notEmptyStringOr($colorRange['color'], null) === null
+ ) {
+ throw new \InvalidArgumentException('invalid color range');
+ }
+ }
+
+ return $data['colorRanges'];
+ } else if (isset($data['label']) === true) {
+ $dynamicData = static::extractDynamicData($data);
+ return $dynamicData['colorRanges'];
+ } else {
+ return [];
+ }
+ }
+
+
+ /**
+ * Extract a dynamic data structure from the 'label' field.
+ *
+ * @param array $data Unknown input data structure.
+ *
+ * @return array Dynamic data structure.
+ * @throws \InvalidArgumentException If the structure cannot be built.
+ *
+ * @example [
+ * 'defaultColor' => '#FFF',
+ * 'colorRanges' => [
+ * [
+ * 'fromValue' => 50.0,
+ * 'toValue' => 150.5,
+ * 'color' => '#000',
+ * ],
+ * [
+ * 'fromValue' => 200.0,
+ * 'toValue' => 300.5,
+ * 'color' => '#F0F0F0',
+ * ],
+ * ]
+ * ]
+ */
+ private static function extractDynamicData(array $data): array
+ {
+ $dynamicDataEncoded = static::notEmptyStringOr($data['label'], null);
+
+ if ($dynamicDataEncoded === null) {
+ throw new \InvalidArgumentException('dynamic data not found');
+ }
+
+ $result = [];
+
+ try {
+ $dynamicData = \json_decode($dynamicDataEncoded, true);
+
+ $result['defaultColor'] = $dynamicData['default_color'];
+ $result['colorRanges'] = [];
+
+ if (\is_array($dynamicData['color_ranges']) === true) {
+ foreach ($dynamicData['color_ranges'] as $colorRange) {
+ if (\is_numeric($colorRange['from_value']) === true
+ && \is_numeric($colorRange['to_value']) === true
+ && static::notEmptyStringOr(
+ $colorRange['color'],
+ null
+ ) !== null
+ ) {
+ $result['colorRanges'][] = [
+ 'color' => $colorRange['color'],
+ 'fromValue' => (float) $colorRange['from_value'],
+ 'toValue' => (float) $colorRange['to_value'],
+ ];
+ }
+ }
+ }
+ } catch (\Throwable $e) {
+ throw new \InvalidArgumentException('invalid dynamic data');
+ }
+
+ return $result;
+ }
+
+
+ /**
+ * Fetch a vc item data structure from the database using a filter.
+ *
+ * @param array $filter Filter of the Visual Console Item.
+ *
+ * @return array The Visual Console Item data structure stored into the DB.
+ * @throws \InvalidArgumentException When an agent Id cannot be found.
+ *
+ * @override Item::fetchDataFromDB.
+ */
+ protected static function fetchDataFromDB(array $filter): array
+ {
+ // Due to this DB call, this function cannot be unit tested without
+ // a proper mock.
+ $data = parent::fetchDataFromDB($filter);
+
+ /*
+ * Retrieve extra data.
+ */
+
+ // Load side libraries.
+ global $config;
+ include_once $config['homedir'].'/include/functions_modules.php';
+ if (is_metaconsole()) {
+ \enterprise_include_once('include/functions_metaconsole.php');
+ }
+
+ // Get the linked module Id.
+ $linkedModule = static::extractLinkedModule($data);
+ $moduleId = $linkedModule['moduleId'];
+ $metaconsoleId = $linkedModule['metaconsoleId'];
+
+ if ($moduleId === null) {
+ throw new \InvalidArgumentException('missing module Id');
+ }
+
+ $dynamicData = static::extractDynamicData($data);
+ // Set the initial color.
+ $data['color'] = $dynamicData['defaultColor'];
+
+ // Search for a matching color range.
+ if (empty($dynamicData['colorRanges']) === false) {
+ // Connect to node.
+ $nodeConnected = false;
+ if (\is_metaconsole() === true && $metaconsoleId !== null) {
+ $nodeConnected = \metaconsole_connect(
+ null,
+ $metaconsoleId
+ ) === NOERR;
+
+ if ($nodeConnected === false) {
+ throw new \InvalidArgumentException(
+ 'error connecting to the node'
+ );
+ }
+ }
+
+ // Fetch module value.
+ $value = false;
+ if ($metaconsoleId === null
+ || ($metaconsoleId !== null && $nodeConnected)
+ ) {
+ $value = \modules_get_last_value($moduleId);
+ }
+
+ // Restore connection.
+ if ($nodeConnected === true) {
+ \metaconsole_restore_db();
+ }
+
+ // Value found.
+ if ($value !== false) {
+ /*
+ * TODO: It would be ok to give support to string values in the
+ * future?
+ *
+ * It can be done by matching the range value with the value
+ * if it is a string. I think the function to retrieve the value
+ * only supports numeric values.
+ */
+
+ $value = (float) $value;
+ foreach ($dynamicData['colorRanges'] as $colorRange) {
+ if ($colorRange['fromValue'] <= $value
+ && $colorRange['toValue'] >= $value
+ ) {
+ // Range matched. Use the range color.
+ $data['color'] = $colorRange['color'];
+ break;
+ }
+ }
+ }
+ }
+
+ return $data;
+ }
+
+
+}
diff --git a/pandora_console/include/rest-api/models/VisualConsole/Items/DonutGraph.php b/pandora_console/include/rest-api/models/VisualConsole/Items/DonutGraph.php
new file mode 100644
index 0000000000..1adc948da2
--- /dev/null
+++ b/pandora_console/include/rest-api/models/VisualConsole/Items/DonutGraph.php
@@ -0,0 +1,193 @@
+';
+ }
+
+ return $data;
+ }
+
+
+}
diff --git a/pandora_console/include/rest-api/models/VisualConsole/Items/EventsHistory.php b/pandora_console/include/rest-api/models/VisualConsole/Items/EventsHistory.php
new file mode 100644
index 0000000000..fab34c26bf
--- /dev/null
+++ b/pandora_console/include/rest-api/models/VisualConsole/Items/EventsHistory.php
@@ -0,0 +1,128 @@
+ $groupId,
+ 'status' => AGENT_STATUS_CRITICAL,
+ ],
+ ['COUNT(*) AS total'],
+ 'AR',
+ false,
+ false,
+ true,
+ $isMetaconsole
+ );
+ $numCritical = $agentsCritical[0]['total'];
+ $agentsWarning = \agents_get_agents(
+ [
+ 'id_grupo' => $groupId,
+ 'status' => AGENT_STATUS_WARNING,
+ ],
+ ['COUNT(*) AS total'],
+ 'AR',
+ false,
+ false,
+ true,
+ $isMetaconsole
+ );
+ $numWarning = $agentsWarning[0]['total'];
+ $agentsUnknown = \agents_get_agents(
+ [
+ 'id_grupo' => $groupId,
+ 'status' => AGENT_STATUS_UNKNOWN,
+ ],
+ ['COUNT(*) AS total'],
+ 'AR',
+ false,
+ false,
+ true,
+ $isMetaconsole
+ );
+ $numUnknown = $agentsUnknown[0]['total'];
+ $agentsOk = \agents_get_agents(
+ [
+ 'id_grupo' => $groupId,
+ 'status' => AGENT_STATUS_OK,
+ ],
+ ['COUNT(*) AS total'],
+ 'AR',
+ false,
+ false,
+ true,
+ $isMetaconsole
+ );
+ $numNormal = $agentsOk[0]['total'];
+
+ $numTotal = ($numCritical + $numWarning + $numUnknown + $numNormal);
+ $agentStats = [
+ 'critical' => ($numCritical / $numTotal * 100),
+ 'warning' => ($numWarning / $numTotal * 100),
+ 'normal' => ($numNormal / $numTotal * 100),
+ 'unknown' => ($numUnknown / $numTotal * 100),
+ ];
+
+ $groupName = \groups_get_name($groupId, true);
+ $data['html'] = static::printStatsTable(
+ $groupName,
+ $agentStats,
+ (int) $data['width'],
+ (int) $data['height']
+ );
+ } else {
+ if (\is_metaconsole()) {
+ $groupFilter = $groupId;
+ if ($groupId === 0) {
+ $groupFilter = implode(
+ ',',
+ array_keys(\users_get_groups())
+ );
+ }
+
+ $sql = sprintf(
+ 'SELECT
+ SUM(fired_count) AS fired,
+ SUM(critical_count) AS critical,
+ SUM(warning_count) AS warning,
+ SUM(unknown_count) AS unknown
+ FROM tmetaconsole_agent
+ LEFT JOIN tmetaconsole_agent_secondary_group tasg
+ ON id_agente = tasg.id_agent
+ WHERE id_grupo IN (%s)
+ OR tasg.id_group IN (%s)',
+ $groupFilter,
+ $groupFilter
+ );
+
+ $countStatus = \db_get_row_sql($sql);
+
+ if ($countStatus['fired'] > 0) {
+ $status = AGENT_STATUS_ALERT_FIRED;
+ } else if ($countStatus['critical'] > 0) {
+ $status = AGENT_STATUS_CRITICAL;
+ } else if ($countStatus['warning'] > 0) {
+ $status = AGENT_STATUS_WARNING;
+ } else if ($countStatus['unknown'] > 0) {
+ $status = AGENT_STATUS_UNKNOWN;
+ } else {
+ $status = AGENT_STATUS_NORMAL;
+ }
+ } else {
+ // Get the status img src.
+ $status = \groups_get_status($groupId);
+ }
+
+ $imagePath = \visual_map_get_image_status_element($data, $status);
+ $data['statusImageSrc'] = \ui_get_full_url(
+ $imagePath,
+ false,
+ false,
+ false
+ );
+
+ // If the width or the height are equal to 0 we will extract them
+ // from the real image size.
+ $width = (int) $data['width'];
+ $height = (int) $data['height'];
+ if ($width === 0 || $height === 0) {
+ // TODO: This will be the default behaviour after we finish the
+ // builder. Don't delete this code.
+ // $sizeImage = getimagesize($config['homedir'].'/'.$imagePath);
+ // $data['width'] = $sizeImage[0];
+ // $data['height'] = $sizeImage[1];
+ $sizeImage = getimagesize($config['homedir'].'/'.$imagePath);
+ $imageHeight = $sizeImage[1];
+
+ if ($width === 0) {
+ $data['width'] = 70;
+ }
+
+ if ($height === 0) {
+ $data['height'] = ($imageHeight > 70) ? 70 : $imageHeight;
+ }
+ }
+
+ $data['html'] = ' ';
+ }
+
+ return $data;
+ }
+
+
+ /**
+ * HTML representation for the agent stats of a group.
+ *
+ * @param string $groupName Group name.
+ * @param array $agentStats Data structure with the agent statistics.
+ * @param integer $width Width.
+ * @param integer $height Height.
+ *
+ * @return string HTML representation.
+ */
+ private static function printStatsTable(
+ string $groupName,
+ array $agentStats,
+ int $width=520,
+ int $height=80
+ ): string {
+ $width = ($width > 0) ? $width : 520;
+ $height = ($height > 0) ? $height : 80;
+
+ $tableStyle = \join(
+ [
+ 'width:'.$width.'px;',
+ 'height:'.$height.'px;',
+ 'text-align:center;',
+ ]
+ );
+ $headStyle = \join(
+ [
+ 'text-align:center;',
+ 'background-color:#9d9ea0;',
+ 'color:black;',
+ 'font-weight:bold;',
+ ]
+ );
+ $valueStyle = \join(
+ [
+ 'margin-left: 2%;',
+ 'color: #FFF;',
+ 'font-size: 12px;',
+ 'display: inline;',
+ 'background-color: #FC4444;',
+ 'position: relative;',
+ 'height: 80%;',
+ 'width: 9.4%;',
+ 'height: 80%;',
+ 'border-radius: 2px;',
+ 'text-align: center;',
+ 'padding: 5px;',
+ ]
+ );
+ $nameStyle = \join(
+ [
+ 'background-color: white;',
+ 'color: black;',
+ 'font-size: 12px;',
+ 'display: inline;',
+ 'display: inline;',
+ 'position:relative;',
+ 'width: 9.4%;',
+ 'height: 80%;',
+ 'border-radius: 2px;',
+ 'text-align: center;',
+ 'padding: 5px;',
+ ]
+ );
+
+ $html = '';
+ $html .= '';
+ $html .= ''.$groupName.' ';
+ $html .= ' ';
+ $html .= '';
+ $html .= '';
+
+ // Critical.
+ $html .= '';
+ $html .= \number_format($agentStats['critical']).'%';
+ $html .= '
';
+ $html .= ''.__('Critical').'
';
+ // Warning.
+ $html .= '';
+ $html .= \number_format($agentStats['warning']).'%';
+ $html .= '
';
+ $html .= ''.__('Warning').'
';
+ // Normal.
+ $html .= '';
+ $html .= \number_format($agentStats['normal']).'%';
+ $html .= '
';
+ $html .= ''.__('Normal').'
';
+ // Unknown.
+ $html .= '';
+ $html .= \number_format($agentStats['unknown']).'%';
+ $html .= '
';
+ $html .= ''.__('Unknown').'
';
+
+ $html .= ' ';
+ $html .= ' ';
+ $html .= '
';
+
+ return $html;
+ }
+
+
+ /**
+ * Generate a link to something related with the item.
+ *
+ * @param array $data Visual Console Item's data structure.
+ *
+ * @return mixed The link or a null value.
+ *
+ * @override Item::buildLink.
+ */
+ protected static function buildLink(array $data)
+ {
+ // This will return the link to a linked VC if this item has one.
+ $link = parent::buildLink($data);
+ if ($link !== null) {
+ return $link;
+ }
+
+ global $config;
+
+ $groupId = static::extractGroupId($data);
+ $baseUrl = $config['homeurl'].'index.php';
+
+ if (\is_metaconsole()) {
+ return $baseUrl.'?'.http_build_query(
+ [
+ 'sec' => 'monitoring',
+ 'sec2' => 'operation/tree',
+ 'group_id' => $groupId,
+ ]
+ );
+ }
+
+ return $baseUrl.'?'.http_build_query(
+ [
+ 'sec' => 'estado',
+ 'sec2' => 'operation/agentes/estado_agente',
+ 'group_id' => $groupId,
+ ]
+ );
+ }
+
+
+}
diff --git a/pandora_console/include/rest-api/models/VisualConsole/Items/Icon.php b/pandora_console/include/rest-api/models/VisualConsole/Items/Icon.php
new file mode 100644
index 0000000000..29605ffb4f
--- /dev/null
+++ b/pandora_console/include/rest-api/models/VisualConsole/Items/Icon.php
@@ -0,0 +1,144 @@
+ 70) ? 70 : $imageHeight;
+ }
+ }
+
+ return $data;
+ }
+
+
+}
diff --git a/pandora_console/include/rest-api/models/VisualConsole/Items/Label.php b/pandora_console/include/rest-api/models/VisualConsole/Items/Label.php
new file mode 100644
index 0000000000..41c9c6c6d1
--- /dev/null
+++ b/pandora_console/include/rest-api/models/VisualConsole/Items/Label.php
@@ -0,0 +1,64 @@
+validateData.
+ */
+ protected function validateData(array $data): void
+ {
+ parent::validateData($data);
+ if (static::notEmptyStringOr(static::issetInArray($data, ['label']), null) === null) {
+ throw new \InvalidArgumentException(
+ 'the label property is required and should be a not empty string'
+ );
+ }
+ }
+
+
+ /**
+ * Returns a valid representation of the model.
+ *
+ * @param array $data Input data.
+ *
+ * @return array Data structure representing the model.
+ *
+ * @overrides Item->decode.
+ */
+ protected function decode(array $data): array
+ {
+ $return = parent::decode($data);
+ $return['type'] = LABEL;
+ return $return;
+ }
+
+
+}
diff --git a/pandora_console/include/rest-api/models/VisualConsole/Items/Line.php b/pandora_console/include/rest-api/models/VisualConsole/Items/Line.php
new file mode 100644
index 0000000000..fd6f64b4cb
--- /dev/null
+++ b/pandora_console/include/rest-api/models/VisualConsole/Items/Line.php
@@ -0,0 +1,209 @@
+validateData.
+ */
+ protected function validateData(array $data): void
+ {
+ if (isset($data['id']) === false
+ || \is_numeric($data['id']) === false
+ ) {
+ throw new \InvalidArgumentException(
+ 'the Id property is required and should be integer'
+ );
+ }
+
+ if (isset($data['type']) === false
+ || \is_numeric($data['type']) === false
+ ) {
+ throw new \InvalidArgumentException(
+ 'the Id property is required and should be integer'
+ );
+ }
+ }
+
+
+ /**
+ * Returns a valid representation of the model.
+ *
+ * @param array $data Input data.
+ *
+ * @return array Data structure representing the model.
+ *
+ * @overrides Model->decode.
+ */
+ protected function decode(array $data): array
+ {
+ return [
+ 'id' => (int) $data['id'],
+ 'type' => LINE_ITEM,
+ 'startX' => static::extractStartX($data),
+ 'startY' => static::extractStartY($data),
+ 'endX' => static::extractEndX($data),
+ 'endY' => static::extractEndY($data),
+ 'isOnTop' => static::extractIsOnTop($data),
+ 'borderWidth' => static::extractBorderWidth($data),
+ 'borderColor' => static::extractBorderColor($data),
+ ];
+ }
+
+
+ /**
+ * Extract a x axis value.
+ *
+ * @param array $data Unknown input data structure.
+ *
+ * @return integer Valid x axis of the start position of the line.
+ */
+ private static function extractStartX(array $data): int
+ {
+ return static::parseIntOr(
+ static::issetInArray($data, ['startX', 'pos_x']),
+ 0
+ );
+ }
+
+
+ /**
+ * Extract a y axis value.
+ *
+ * @param array $data Unknown input data structure.
+ *
+ * @return integer Valid y axis of the start position of the line.
+ */
+ private static function extractStartY(array $data): int
+ {
+ return static::parseIntOr(
+ static::issetInArray($data, ['startY', 'pos_y']),
+ 0
+ );
+ }
+
+
+ /**
+ * Extract a x axis value.
+ *
+ * @param array $data Unknown input data structure.
+ *
+ * @return integer Valid x axis of the end position of the line.
+ */
+ private static function extractEndX(array $data): int
+ {
+ return static::parseIntOr(
+ static::issetInArray($data, ['endX', 'width']),
+ 0
+ );
+ }
+
+
+ /**
+ * Extract a y axis value.
+ *
+ * @param array $data Unknown input data structure.
+ *
+ * @return integer Valid y axis of the end position of the line.
+ */
+ private static function extractEndY(array $data): int
+ {
+ return static::parseIntOr(
+ static::issetInArray($data, ['endY', 'height']),
+ 0
+ );
+ }
+
+
+ /**
+ * Extract a conditional value which tells if the item has visual priority.
+ *
+ * @param array $data Unknown input data structure.
+ *
+ * @return boolean If the item is on top or not.
+ */
+ private static function extractIsOnTop(array $data): bool
+ {
+ return static::parseBool(
+ static::issetInArray($data, ['isOnTop', 'show_on_top'])
+ );
+ }
+
+
+ /**
+ * Extract a border width value.
+ *
+ * @param array $data Unknown input data structure.
+ *
+ * @return integer Valid border width. 0 by default and minimum value.
+ */
+ private static function extractBorderWidth(array $data): int
+ {
+ $borderWidth = static::parseIntOr(
+ static::issetInArray($data, ['borderWidth', 'border_width']),
+ 0
+ );
+
+ return ($borderWidth >= 0) ? $borderWidth : 0;
+ }
+
+
+ /**
+ * Extract a border color value.
+ *
+ * @param array $data Unknown input data structure.
+ *
+ * @return mixed String representing the border color (not empty) or null.
+ */
+ private static function extractBorderColor(array $data)
+ {
+ return static::notEmptyStringOr(
+ static::issetInArray($data, ['borderColor', 'border_color']),
+ null
+ );
+ }
+
+
+ /**
+ * Obtain a vc item data structure from the database using a filter.
+ *
+ * @param array $filter Filter of the Visual Console Item.
+ *
+ * @return array The Visual Console line data structure stored into the DB.
+ * @throws \Exception When the data cannot be retrieved from the DB.
+ *
+ * @override Model::fetchDataFromDB.
+ */
+ protected static function fetchDataFromDB(array $filter): array
+ {
+ // Due to this DB call, this function cannot be unit tested without
+ // a proper mock.
+ $row = \db_get_row_filter('tlayout_data', $filter);
+
+ if ($row === false) {
+ throw new \Exception('error fetching the data from the DB');
+ }
+
+ return $row;
+ }
+
+
+}
diff --git a/pandora_console/include/rest-api/models/VisualConsole/Items/ModuleGraph.php b/pandora_console/include/rest-api/models/VisualConsole/Items/ModuleGraph.php
new file mode 100644
index 0000000000..d89a01efff
--- /dev/null
+++ b/pandora_console/include/rest-api/models/VisualConsole/Items/ModuleGraph.php
@@ -0,0 +1,274 @@
+ $period,
+ 'width' => $data['width'],
+ 'height' => ($data['height'] - 30),
+ 'title' => '',
+ 'unit_name' => null,
+ 'show_alerts' => false,
+ 'only_image' => $imageOnly,
+ 'vconsole' => true,
+ 'backgroundColor' => $backgroundType,
+ ];
+
+ $paramsCombined = [
+ 'id_graph' => $customGraphId,
+ 'stacked' => $customGraph['stacked'],
+ 'summatory' => $customGraph['summatory_series'],
+ 'average' => $customGraph['average_series'],
+ 'modules_series' => $customGraph['modules_series'],
+ ];
+
+ $data['html'] = \graphic_combined_module(
+ false,
+ $params,
+ $paramsCombined
+ );
+ } else {
+ // Module graph.
+ if ($moduleId === null) {
+ throw new \InvalidArgumentException('missing module Id');
+ }
+
+ $params = [
+ 'agent_module_id' => $moduleId,
+ 'period' => $period,
+ 'show_events' => false,
+ 'width' => $data['width'],
+ 'height' => ($data['height'] - 30),
+ 'title' => \modules_get_agentmodule_name($moduleId),
+ 'unit' => \modules_get_unit($moduleId),
+ 'only_image' => $imageOnly,
+ 'menu' => false,
+ 'backgroundColor' => $backgroundType,
+ 'type_graph' => $graphType,
+ 'vconsole' => true,
+ ];
+
+ $data['html'] = \grafico_modulo_sparse($params);
+ }
+
+ // Restore connection.
+ if ($nodeConnected === true) {
+ \metaconsole_restore_db();
+ }
+
+ return $data;
+ }
+
+
+}
diff --git a/pandora_console/include/rest-api/models/VisualConsole/Items/Percentile.php b/pandora_console/include/rest-api/models/VisualConsole/Items/Percentile.php
new file mode 100644
index 0000000000..3ce365195b
--- /dev/null
+++ b/pandora_console/include/rest-api/models/VisualConsole/Items/Percentile.php
@@ -0,0 +1,249 @@
+validateData.
+ */
+ protected function validateData(array $data): void
+ {
+ parent::validateData($data);
+ if (isset($data['value']) === false) {
+ throw new \InvalidArgumentException(
+ 'the value property is required and should be string'
+ );
+ }
+ }
+
+
+ /**
+ * Returns a valid representation of the model.
+ *
+ * @param array $data Input data.
+ *
+ * @return array Data structure representing the model.
+ *
+ * @overrides Item->decode.
+ */
+ protected function decode(array $data): array
+ {
+ $return = parent::decode($data);
+ $return['type'] = SIMPLE_VALUE;
+ $return['processValue'] = static::extractProcessValue($data);
+ $return['valueType'] = static::extractValueType($data);
+ $return['value'] = $data['value'];
+
+ if ($return['processValue'] !== 'none') {
+ $return['period'] = static::extractPeriod($data);
+ }
+
+ // Clear the size, as this element always have a dynamic size.
+ $return['width'] = 0;
+ $return['height'] = 0;
+
+ return $return;
+ }
+
+
+ /**
+ * Extract a process value.
+ *
+ * @param array $data Unknown input data structure.
+ *
+ * @return string One of 'none', 'avg', 'max' or 'min'. 'none' by default.
+ */
+ private static function extractProcessValue(array $data): string
+ {
+ if (isset($data['processValue'])) {
+ switch ($data['processValue']) {
+ case 'none':
+ case 'avg':
+ case 'max':
+ case 'min':
+ return $data['processValue'];
+
+ default:
+ return 'none';
+ }
+ } else {
+ switch ($data['type']) {
+ case SIMPLE_VALUE_MAX:
+ return 'max';
+
+ case SIMPLE_VALUE_MIN:
+ return 'min';
+
+ case SIMPLE_VALUE_AVG:
+ return 'avg';
+
+ default:
+ return 'none';
+ }
+ }
+ }
+
+
+ /**
+ * Extract the value of period.
+ *
+ * @param array $data Unknown input data structure.
+ *
+ * @return integer The period in seconds. 0 is the minimum value.
+ */
+ private static function extractPeriod(array $data): int
+ {
+ $period = static::parseIntOr(
+ static::issetInArray($data, ['period']),
+ 0
+ );
+ return ($period >= 0) ? $period : 0;
+ }
+
+
+ /**
+ * Extract a value type.
+ *
+ * @param array $data Unknown input data structure.
+ *
+ * @return string One of 'string' or 'image'. 'string' by default.
+ */
+ private static function extractValueType(array $data): string
+ {
+ switch ($data['valueType']) {
+ case 'string':
+ case 'image':
+ return $data['valueType'];
+
+ default:
+ return 'string';
+ }
+ }
+
+
+ /**
+ * Fetch a vc item data structure from the database using a filter.
+ *
+ * @param array $filter Filter of the Visual Console Item.
+ *
+ * @return array The Visual Console Item data structure stored into the DB.
+ * @throws \InvalidArgumentException When a module Id cannot be found.
+ *
+ * @override Item::fetchDataFromDB.
+ */
+ protected static function fetchDataFromDB(array $filter): array
+ {
+ // Due to this DB call, this function cannot be unit tested without
+ // a proper mock.
+ $data = parent::fetchDataFromDB($filter);
+
+ /*
+ * Retrieve extra data.
+ */
+
+ // Load side libraries.
+ global $config;
+ include_once $config['homedir'].'/include/functions_visual_map.php';
+ if (is_metaconsole()) {
+ \enterprise_include_once('include/functions_metaconsole.php');
+ }
+
+ // Get the linked module Id.
+ $linkedModule = static::extractLinkedModule($data);
+ $moduleId = static::parseIntOr($linkedModule['moduleId'], null);
+ $metaconsoleId = static::parseIntOr(
+ $linkedModule['metaconsoleId'],
+ null
+ );
+
+ if ($moduleId === null) {
+ throw new \InvalidArgumentException('missing module Id');
+ }
+
+ // Maybe connect to node.
+ $nodeConnected = false;
+ if (\is_metaconsole() === true && $metaconsoleId !== null) {
+ $nodeConnected = \metaconsole_connect(
+ null,
+ $metaconsoleId
+ ) === NOERR;
+
+ if ($nodeConnected === false) {
+ throw new \InvalidArgumentException(
+ 'error connecting to the node'
+ );
+ }
+ }
+
+ // Get the formatted value.
+ $value = \visual_map_get_simple_value(
+ $data['type'],
+ $moduleId,
+ static::extractPeriod($data)
+ );
+
+ // Restore connection.
+ if ($nodeConnected === true) {
+ \metaconsole_restore_db();
+ }
+
+ // Some modules are image based. Extract the base64 image if needed.
+ $matches = [];
+ if (\preg_match('/src=\"(data:image.*)"/', $value, $matches) === 1) {
+ $data['valueType'] = 'image';
+ $data['value'] = $matches[1];
+ } else {
+ $data['valueType'] = 'string';
+ $data['value'] = $value;
+ }
+
+ return $data;
+ }
+
+
+}
diff --git a/pandora_console/include/rest-api/models/VisualConsole/Items/StaticGraph.php b/pandora_console/include/rest-api/models/VisualConsole/Items/StaticGraph.php
new file mode 100644
index 0000000000..0f68841686
--- /dev/null
+++ b/pandora_console/include/rest-api/models/VisualConsole/Items/StaticGraph.php
@@ -0,0 +1,256 @@
+decode.
+ */
+ protected function decode(array $data): array
+ {
+ $return = parent::decode($data);
+ $return['type'] = STATIC_GRAPH;
+ $return['imageSrc'] = static::extractImageSrc($data);
+ $return['showLastValueTooltip'] = static::extractShowLastValueTooltip(
+ $data
+ );
+ $return['statusImageSrc'] = static::notEmptyStringOr(
+ static::issetInArray($data, ['statusImageSrc']),
+ null
+ );
+ $return['lastValue'] = static::notEmptyStringOr(
+ static::issetInArray($data, ['lastValue']),
+ null
+ );
+
+ return $return;
+ }
+
+
+ /**
+ * Extract a image src value.
+ *
+ * @param array $data Unknown input data structure.
+ *
+ * @return mixed String representing the image url (not empty) or null.
+ *
+ * @throws \InvalidArgumentException When a valid image src can't be found.
+ */
+ private static function extractImageSrc(array $data): string
+ {
+ $imageSrc = static::notEmptyStringOr(
+ static::issetInArray($data, ['imageSrc', 'image']),
+ null
+ );
+
+ if ($imageSrc === null) {
+ throw new \InvalidArgumentException(
+ 'the image src property is required and should be a non empty string'
+ );
+ }
+
+ return $imageSrc;
+ }
+
+
+ /**
+ * Extract the value of showLastValueTooltip and
+ * return 'default', 'enabled' or 'disabled'.
+ *
+ * @param array $data Unknown input data structure.
+ *
+ * @return string
+ */
+ private static function extractShowLastValueTooltip(array $data): string
+ {
+ $showLastValueTooltip = static::notEmptyStringOr(
+ static::issetInArray($data, ['showLastValueTooltip']),
+ null
+ );
+
+ if ($showLastValueTooltip === null) {
+ $showLastValueTooltip = static::parseIntOr(
+ static::issetInArray($data, ['show_last_value']),
+ null
+ );
+ switch ($showLastValueTooltip) {
+ case 1:
+ return 'enabled';
+
+ case 2:
+ return 'disabled';
+
+ default:
+ return 'default';
+ }
+ } else {
+ switch ($showLastValueTooltip) {
+ case 'enabled':
+ return 'enabled';
+
+ case 'disabled':
+ return 'disabled';
+
+ default:
+ return 'default';
+ }
+ }
+ }
+
+
+ /**
+ * Fetch a vc item data structure from the database using a filter.
+ *
+ * @param array $filter Filter of the Visual Console Item.
+ *
+ * @return array The Visual Console Item data structure stored into the DB.
+ * @throws \InvalidArgumentException When an agent Id cannot be found.
+ *
+ * @override Item::fetchDataFromDB.
+ */
+ protected static function fetchDataFromDB(array $filter): array
+ {
+ // Due to this DB call, this function cannot be unit tested without
+ // a proper mock.
+ $data = parent::fetchDataFromDB($filter);
+
+ /*
+ * Retrieve extra data.
+ */
+
+ // Load side libraries.
+ global $config;
+ include_once $config['homedir'].'/include/functions_ui.php';
+ include_once $config['homedir'].'/include/functions_io.php';
+ include_once $config['homedir'].'/include/functions_visual_map.php';
+ include_once $config['homedir'].'/include/functions_modules.php';
+ if (is_metaconsole()) {
+ \enterprise_include_once('include/functions_metaconsole.php');
+ }
+
+ // Get the linked module Id.
+ $linkedModule = static::extractLinkedModule($data);
+ $moduleId = $linkedModule['moduleId'];
+ $metaconsoleId = $linkedModule['metaconsoleId'];
+
+ if ($moduleId === null) {
+ throw new \InvalidArgumentException('missing module Id');
+ }
+
+ // Get the img src.
+ // There's no need to connect to the metaconsole before searching for
+ // the image status cause the function itself does that for us.
+ $imagePath = \visual_map_get_image_status_element($data);
+ $data['statusImageSrc'] = \ui_get_full_url(
+ $imagePath,
+ false,
+ false,
+ false
+ );
+
+ // If the width or the height are equal to 0 we will extract them
+ // from the real image size.
+ $width = (int) $data['width'];
+ $height = (int) $data['height'];
+ if ($width === 0 || $height === 0) {
+ // TODO: This will be the default behaviour after we finish the
+ // builder. Don't delete this code.
+ // $sizeImage = getimagesize($config['homedir'].'/'.$imagePath);
+ // $data['width'] = $sizeImage[0];
+ // $data['height'] = $sizeImage[1];
+ // Default value. Will be replaced by a dynamic image size
+ // calculation after the phase 3.
+ $sizeImage = getimagesize($config['homedir'].'/'.$imagePath);
+ $imageHeight = $sizeImage[1];
+
+ if ($width === 0) {
+ $data['width'] = 70;
+ }
+
+ if ($height === 0) {
+ $data['height'] = ($imageHeight > 70) ? 70 : $imageHeight;
+ }
+ }
+
+ // Get last value.
+ $showLastValueTooltip = static::extractShowLastValueTooltip($data);
+ if ($showLastValueTooltip !== 'disabled' && $moduleId > 0) {
+ // Maybe connect to node.
+ $nodeConnected = false;
+ if (\is_metaconsole() === true && $metaconsoleId !== null) {
+ $nodeConnected = \metaconsole_connect(
+ null,
+ $metaconsoleId
+ ) === NOERR;
+
+ if ($nodeConnected === false) {
+ throw new \InvalidArgumentException(
+ 'error connecting to the node'
+ );
+ }
+ }
+
+ $imgTitle = '';
+
+ $unit = \trim(\io_safe_output(\modules_get_unit($moduleId)));
+ $value = \modules_get_last_value($moduleId);
+
+ $isBooleanModule = \modules_is_boolean($moduleId);
+ if (!$isBooleanModule
+ || ($isBooleanModule && $showLastValueTooltip !== 'default')
+ ) {
+ if (is_numeric($value)) {
+ $imgTitle .= __('Last value: ').\remove_right_zeros($value);
+ } else {
+ $imgTitle .= __('Last value: ').$value;
+ }
+
+ if (empty($unit) === false && empty($imgTitle) === false) {
+ $imgTitle .= ' '.$unit;
+ }
+
+ $data['lastValue'] = $imgTitle;
+ }
+
+ // Restore connection.
+ if ($nodeConnected === true) {
+ \metaconsole_restore_db();
+ }
+ }
+
+ return $data;
+ }
+
+
+}
diff --git a/pandora_console/include/styles/discovery.css b/pandora_console/include/styles/discovery.css
index 34e9b98255..51b4e98c10 100644
--- a/pandora_console/include/styles/discovery.css
+++ b/pandora_console/include/styles/discovery.css
@@ -156,11 +156,118 @@ span.breadcrumb_link {
color: #95b750;
}
-.form_grid_items {
- overflow: hidden;
+/*
+ * Discovery forms structure
+ */
+
+.edit_discovery_info {
+ display: flex;
+ align-items: center;
+ padding-top: 25px;
}
-.form_grid_items .form_grid_item {
- float: left;
+
+.edit_discovery_input {
+ align-items: center;
+ margin-bottom: 25px;
+}
+
+/*
+ * Discovery text inputs
+ */
+
+.discovery_label_hint {
+ display: flex;
+}
+
+label {
+ color: #343434 !important;
+ font-size: 1.5em;
+ font-family: "lato-bolder", "Open Sans", sans-serif !important;
+ font-weight: bold;
+ margin: 0px 0px 5px 0px;
+}
+
+.discovery_full_width_input {
+ width: 100%;
+}
+
+select {
+ font-family: "lato-bolder", "Open Sans", sans-serif !important;
+ font-size: 1.6em !important;
+ color: #686868;
+}
+
+select > option {
+ font-family: "lato-bolder", "Open Sans", sans-serif !important;
+ font-size: 1em !important;
+}
+
+li > input[type=text], li > input[type=password], .discovery_text_input > input[type=password], .discovery_text_input > input[type=text], #interval_manual > input[type=text] {
+ background-color: transparent !important;
+ border: none;
+ border-radius: 0 !important;
+ border-bottom: 1px solid #343434;
+ padding: 0px 0px 2px 0px;
+ box-sizing: border-box;
+ margin-bottom: 4px;
+ font-family: "lato-bolder", "Open Sans", sans-serif !important;
+ font-size: 1.6em;
+}
+
+li > input[type=text]:focus, li > input[type=password]:focus, .discovery_text_input > input[type=password]:focus, .discovery_text_input > input[type=text]:focus, #interval_manual > input[type=text]:focus {
+ font-weight: bold;
+}
+
+#interval_manual > input[type=text] {
+ width: 50px;
+ margin-left: 10px;
+ margin-right: 10px;
+}
+
+.discovery_list_input {
+ font-family: "lato-bolder", "Open Sans", sans-serif !important;
+ font-size: 1.6em !important;
+ color: #686868;
+ width: 100%;
+ height: 240px;
+ border: 1px solid #CBCBCB;
+ overflow-y: auto;
+}
+
+.discovery_list_input option {
+ font-family: "lato-bolder", "Open Sans", sans-serif !important;
+ font-size: 1.1em !important;
+ padding-left: 30%;
+}
+
+.discovery_list_input option:checked {
+ background: #1aab8e -webkit-linear-gradient(bottom, #7db742 0%, #7db742 100%);
+ color: #fff;
+}
+
+.discovery_textarea_input {
+ background-color: #fbfbfb !important;
+ padding-left: 10px;
+ width: 100%;
+ height: 100px;
+ max-height: 100px;
+ max-width: 100%;
+ -webkit-box-sizing: border-box; /* Safari/Chrome, other WebKit */
+ -moz-box-sizing: border-box; /* Firefox, other Gecko */
box-sizing: border-box;
- padding: 10px;
+ resize: none;
+ font-family: "lato-bolder", "Open Sans", sans-serif !important;
+ font-size: 1.4em !important;
}
+
+a.tip {
+ margin-left: 8px;
+}
+
+.inline_switch > label {
+ float: right;
+}
+
+.discovery_interval_select_width {
+ width: 90%;
+}
\ No newline at end of file
diff --git a/pandora_console/include/styles/wizard.css b/pandora_console/include/styles/wizard.css
index 869ea85f2c..d7ec2e4ee5 100644
--- a/pandora_console/include/styles/wizard.css
+++ b/pandora_console/include/styles/wizard.css
@@ -16,8 +16,10 @@ ul.wizard li > label:not(.p-switch) {
}
ul.wizard li > textarea {
- width: 250px;
+ width: 600px;
+ height: 15em;
display: inline-block;
+ font-family: monospace;
}
.hidden {
diff --git a/pandora_console/include/visual-console-client/alarm-clock.ttf b/pandora_console/include/visual-console-client/alarm-clock.ttf
new file mode 100644
index 0000000000..9e9b593459
Binary files /dev/null and b/pandora_console/include/visual-console-client/alarm-clock.ttf differ
diff --git a/pandora_console/include/visual-console-client/vc.main.css b/pandora_console/include/visual-console-client/vc.main.css
new file mode 100644
index 0000000000..93c27b0e70
--- /dev/null
+++ b/pandora_console/include/visual-console-client/vc.main.css
@@ -0,0 +1,90 @@
+#visual-console-container {
+ margin: 0px auto;
+ position: relative;
+ background-repeat: no-repeat;
+ background-size: 100% 100%;
+ background-position: center;
+}
+
+.visual-console-item {
+ position: absolute;
+ display: -webkit-box;
+ display: -ms-flexbox;
+ display: flex;
+ -webkit-box-orient: initial;
+ -webkit-box-direction: initial;
+ -ms-flex-direction: initial;
+ flex-direction: initial;
+ justify-items: center;
+ -webkit-box-align: center;
+ -ms-flex-align: center;
+ align-items: center;
+ -webkit-user-select: text;
+ -moz-user-select: text;
+ -ms-user-select: text;
+ user-select: text;
+}
+
+@font-face {
+ font-family: Alarm Clock;
+ src: url(alarm-clock.ttf);
+}
+
+/* Digital clock */
+
+.visual-console-item .digital-clock {
+ display: -webkit-box;
+ display: -ms-flexbox;
+ display: flex;
+ -webkit-box-orient: vertical;
+ -webkit-box-direction: normal;
+ -ms-flex-direction: column;
+ flex-direction: column;
+ -webkit-box-pack: center;
+ -ms-flex-pack: center;
+ justify-content: center;
+ justify-items: center;
+ -ms-flex-line-pack: center;
+ align-content: center;
+ -webkit-box-align: center;
+ -ms-flex-align: center;
+ align-items: center;
+}
+
+.visual-console-item .digital-clock > span {
+ font-family: "Alarm Clock", "Courier New", Courier, monospace;
+ font-size: 50px;
+
+ /* To improve legibility */
+ -webkit-font-smoothing: antialiased;
+ -moz-osx-font-smoothing: grayscale;
+ text-rendering: optimizeLegibility;
+ text-shadow: rgba(0, 0, 0, 0.01) 0 0 1px;
+}
+
+.visual-console-item .digital-clock > span.date {
+ font-size: 25px;
+}
+
+.visual-console-item .digital-clock > span.timezone {
+ font-size: 25px;
+}
+
+/* Analog clock */
+
+.visual-console-item .analogic-clock .hour-hand {
+ -webkit-animation: rotate-hour 43200s infinite linear;
+ animation: rotate-hour 43200s infinite linear;
+}
+
+.visual-console-item .analogic-clock .minute-hand {
+ -webkit-animation: rotate-minute 3600s infinite linear;
+ animation: rotate-minute 3600s infinite linear;
+}
+
+.visual-console-item .analogic-clock .second-hand {
+ -webkit-animation: rotate-second 60s infinite linear;
+ animation: rotate-second 60s infinite linear;
+}
+
+/*# sourceMappingURL=vc.main.css.map*/
diff --git a/pandora_console/include/visual-console-client/vc.main.css.map b/pandora_console/include/visual-console-client/vc.main.css.map
new file mode 100644
index 0000000000..1d661ac652
--- /dev/null
+++ b/pandora_console/include/visual-console-client/vc.main.css.map
@@ -0,0 +1 @@
+{"version":3,"sources":["webpack:///main.css","webpack:///styles.css"],"names":[],"mappings":"AAAA;EACE,gBAAgB;EAChB,kBAAkB;EAClB,4BAA4B;EAC5B,0BAA0B;EAC1B,2BAA2B;AAC7B;;AAEA;EACE,kBAAkB;EAClB,oBAAa;EAAb,oBAAa;EAAb,aAAa;EACb,2BAAuB;EAAvB,8BAAuB;MAAvB,2BAAuB;UAAvB,uBAAuB;EACvB,qBAAqB;EACrB,yBAAmB;MAAnB,sBAAmB;UAAnB,mBAAmB;EACnB,yBAAiB;KAAjB,sBAAiB;MAAjB,qBAAiB;UAAjB,iBAAiB;AACnB;;ACfA;EACE,wBAAwB;EACxB,0BAA2B;AAC7B;;AAEA,kBAAkB;;AAElB;EACE,oBAAa;EAAb,oBAAa;EAAb,aAAa;EACb,4BAAsB;EAAtB,6BAAsB;MAAtB,0BAAsB;UAAtB,sBAAsB;EACtB,wBAAuB;MAAvB,qBAAuB;UAAvB,uBAAuB;EACvB,qBAAqB;EACrB,0BAAqB;MAArB,qBAAqB;EACrB,yBAAmB;MAAnB,sBAAmB;UAAnB,mBAAmB;AACrB;;AAEA;EACE,6DAA6D;EAC7D,eAAe;;EAEf,0BAA0B;EAC1B,mCAAmC;EACnC,kCAAkC;EAClC,kCAAkC;EAClC,wCAAwC;AAC1C;;AAEA;EACE,eAAe;AACjB;;AAEA;EACE,eAAe;AACjB;;AAEA,iBAAiB;;AAEjB;EACE,qDAA6C;UAA7C,6CAA6C;AAC/C;;AAEA;EACE,sDAA8C;UAA9C,8CAA8C;AAChD;;AAEA;EACE,oDAA4C;UAA5C,4CAA4C;AAC9C","file":"vc.main.css","sourcesContent":["#visual-console-container {\n margin: 0px auto;\n position: relative;\n background-repeat: no-repeat;\n background-size: 100% 100%;\n background-position: center;\n}\n\n.visual-console-item {\n position: absolute;\n display: flex;\n flex-direction: initial;\n justify-items: center;\n align-items: center;\n user-select: text;\n}\n","@font-face {\n font-family: Alarm Clock;\n src: url(./alarm-clock.ttf);\n}\n\n/* Digital clock */\n\n.visual-console-item .digital-clock {\n display: flex;\n flex-direction: column;\n justify-content: center;\n justify-items: center;\n align-content: center;\n align-items: center;\n}\n\n.visual-console-item .digital-clock > span {\n font-family: \"Alarm Clock\", \"Courier New\", Courier, monospace;\n font-size: 50px;\n\n /* To improve legibility */\n -webkit-font-smoothing: antialiased;\n -moz-osx-font-smoothing: grayscale;\n text-rendering: optimizeLegibility;\n text-shadow: rgba(0, 0, 0, 0.01) 0 0 1px;\n}\n\n.visual-console-item .digital-clock > span.date {\n font-size: 25px;\n}\n\n.visual-console-item .digital-clock > span.timezone {\n font-size: 25px;\n}\n\n/* Analog clock */\n\n.visual-console-item .analogic-clock .hour-hand {\n animation: rotate-hour 43200s infinite linear;\n}\n\n.visual-console-item .analogic-clock .minute-hand {\n animation: rotate-minute 3600s infinite linear;\n}\n\n.visual-console-item .analogic-clock .second-hand {\n animation: rotate-second 60s infinite linear;\n}\n"],"sourceRoot":""}
\ No newline at end of file
diff --git a/pandora_console/include/visual-console-client/vc.main.min.js b/pandora_console/include/visual-console-client/vc.main.min.js
new file mode 100644
index 0000000000..9b20e9f7fd
--- /dev/null
+++ b/pandora_console/include/visual-console-client/vc.main.min.js
@@ -0,0 +1,2 @@
+!function(t){var e={};function n(i){if(e[i])return e[i].exports;var r=e[i]={i:i,l:!1,exports:{}};return t[i].call(r.exports,r,r.exports,n),r.l=!0,r.exports}n.m=t,n.c=e,n.d=function(t,e,i){n.o(t,e)||Object.defineProperty(t,e,{enumerable:!0,get:i})},n.r=function(t){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(t,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(t,"__esModule",{value:!0})},n.t=function(t,e){if(1&e&&(t=n(t)),8&e)return t;if(4&e&&"object"==typeof t&&t&&t.__esModule)return t;var i=Object.create(null);if(n.r(i),Object.defineProperty(i,"default",{enumerable:!0,value:t}),2&e&&"string"!=typeof t)for(var r in t)n.d(i,r,function(e){return t[e]}.bind(null,r));return i},n.n=function(t){var e=t&&t.__esModule?function(){return t.default}:function(){return t};return n.d(e,"a",e),e},n.o=function(t,e){return Object.prototype.hasOwnProperty.call(t,e)},n.p="",n(n.s=9)}([function(t,e,n){"use strict";n.d(e,"i",function(){return r}),n.d(e,"h",function(){return s}),n.d(e,"n",function(){return o}),n.d(e,"f",function(){return a}),n.d(e,"g",function(){return c}),n.d(e,"j",function(){return u}),n.d(e,"m",function(){return h}),n.d(e,"e",function(){return p}),n.d(e,"d",function(){return _}),n.d(e,"k",function(){return f}),n.d(e,"a",function(){return d}),n.d(e,"b",function(){return y}),n.d(e,"c",function(){return m}),n.d(e,"l",function(){return b});var i=function(){return(i=Object.assign||function(t){for(var e,n=1,i=arguments.length;n0&&!isNaN(parseInt(t))?parseInt(t):e}function s(t,e){return"number"==typeof t?t:"string"==typeof t&&t.length>0&&!isNaN(parseFloat(t))?parseFloat(t):e}function o(t){return null==t||0===t.length}function a(t,e){return"string"==typeof t&&t.length>0?t:e}function c(t){return"boolean"==typeof t?t:"number"==typeof t?t>0:"string"==typeof t&&("1"===t||"true"===t)}function l(t,e,n){void 0===n&&(n=" "),"number"==typeof t&&(t=""+t),"number"==typeof n&&(n=""+n);var i=e-t.length;if(0===i)return t;if(i<0)return t.substr(Math.abs(i));if(i===n.length)return""+n+t;if(i0){var n=document.createElement("table"),i=document.createElement("tr"),r=document.createElement("tr"),s=document.createElement("tr"),o=document.createElement("td");switch(o.innerHTML=e,i.append(o),n.append(r,i,s),n.style.textAlign="center",this.props.labelPosition){case"up":case"down":this.props.width>0&&(n.style.width=this.props.width+"px",n.style.height=null);break;case"left":case"right":this.props.height>0&&(n.style.width=null,n.style.height=this.props.height+"px")}t.append(n)}return t},t.prototype.getLabelWithMacrosReplaced=function(){var t=this.props;return Object(i.l)([{macro:"_date_",value:Object(i.b)(new Date)},{macro:"_time_",value:Object(i.c)(new Date)},{macro:"_agent_",value:null!=t.agentAlias?t.agentAlias:""},{macro:"_agentdescription_",value:null!=t.agentDescription?t.agentDescription:""},{macro:"_address_",value:null!=t.agentAddress?t.agentAddress:""},{macro:"_module_",value:null!=t.moduleName?t.moduleName:""},{macro:"_moduledescription_",value:null!=t.moduleDescription?t.moduleDescription:""}],this.props.label||"")},t.prototype.updateDomElement=function(t){t.innerHTML=this.createDomElement().innerHTML},Object.defineProperty(t.prototype,"props",{get:function(){return s({},this.itemProps)},set:function(t){var e=this.props;this.itemProps=t,this.shouldBeUpdated(e,t)&&this.render(e)},enumerable:!0,configurable:!0}),t.prototype.shouldBeUpdated=function(t,e){return t!==e},t.prototype.render=function(t){void 0===t&&(t=null),this.updateDomElement(this.childElementRef),t&&!this.positionChanged(t,this.props)||this.moveElement(this.props.x,this.props.y),t&&!this.sizeChanged(t,this.props)||this.resizeElement(this.props.width,this.props.height);var e=this.labelElementRef.innerHTML,n=this.createLabelDomElement().innerHTML;if(e!==n&&(this.labelElementRef.innerHTML=n),t&&t.labelPosition===this.props.labelPosition||this.changeLabelPosition(this.props.labelPosition),t&&(t.isLinkEnabled!==this.props.isLinkEnabled||this.props.isLinkEnabled&&t.link!==this.props.link)){var i=this.createContainerDomElement();i.innerHTML=this.elementRef.innerHTML;for(var r=this.elementRef.attributes,s=0;s0?e.item(0):null;if(n)switch(this.props.labelPosition){case"up":case"down":this.props.width>0&&(n.style.width=this.props.width+"px",n.style.height=null);break;case"left":case"right":this.props.height>0&&(n.style.width=null,n.style.height=this.props.height+"px")}},t.prototype.moveElement=function(t,e){this.elementRef.style.left=t+"px",this.elementRef.style.top=e+"px"},t.prototype.move=function(t,e){this.moveElement(t,e),this.itemProps=s({},this.props,{x:t,y:e})},t.prototype.sizeChanged=function(t,e){return t.width!==e.width||t.height!==e.height},t.prototype.resizeElement=function(t,e){this.childElementRef.style.width=t>0?t+"px":null,this.childElementRef.style.height=e>0?e+"px":null},t.prototype.resize=function(t,e){this.resizeElement(t,e),this.itemProps=s({},this.props,{width:t,height:e})},t.prototype.onClick=function(t){var e=this.clickEventManager.on(t);return this.disposables.push(e),e},t.prototype.onRemove=function(t){var e=this.removeEventManager.on(t);return this.disposables.push(e),e},t}();e.a=c},function(t,e,n){"use strict";var i=function(){return function(){var t=this;this.listeners=[],this.listenersOncer=[],this.on=function(e){return t.listeners.push(e),{dispose:function(){return t.off(e)}}},this.once=function(e){t.listenersOncer.push(e)},this.off=function(e){var n=t.listeners.indexOf(e);n>-1&&t.listeners.splice(n,1)},this.emit=function(e){t.listeners.forEach(function(t){return t(e)}),t.listenersOncer.forEach(function(t){return t(e)}),t.listenersOncer=[]},this.pipe=function(e){return t.on(function(t){return e.emit(t)})}}}();e.a=i},function(module,__webpack_exports__,__webpack_require__){"use strict";__webpack_require__.d(__webpack_exports__,"b",function(){return eventsHistoryPropsDecoder});var _lib__WEBPACK_IMPORTED_MODULE_0__=__webpack_require__(0),_Item__WEBPACK_IMPORTED_MODULE_1__=__webpack_require__(1),__extends=(extendStatics=function(t,e){return(extendStatics=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(t,e){t.__proto__=e}||function(t,e){for(var n in e)e.hasOwnProperty(n)&&(t[n]=e[n])})(t,e)},function(t,e){function n(){this.constructor=t}extendStatics(t,e),t.prototype=null===e?Object.create(e):(n.prototype=e.prototype,new n)}),extendStatics,__assign=function(){return(__assign=Object.assign||function(t){for(var e,n=1,i=arguments.length;n0){var y=document.createElementNS(t,"text");y.setAttribute("text-anchor","middle"),y.setAttribute("font-size","8"),y.setAttribute("transform","translate(30 50) rotate(90)"),y.setAttribute("fill",i),y.textContent=d,_.append(y)}var m=document.createElementNS(t,"g");m.setAttribute("class","marks");var b=document.createElementNS(t,"g");b.setAttribute("class","mark"),b.setAttribute("transform","translate(50 50)");var v=document.createElementNS(t,"line");v.setAttribute("x1","36"),v.setAttribute("y1","0"),v.setAttribute("x2","46"),v.setAttribute("y2","0"),v.setAttribute("stroke",i),v.setAttribute("stroke-width","5");var x=document.createElementNS(t,"line");x.setAttribute("x1","36"),x.setAttribute("y1","0"),x.setAttribute("x2","46"),x.setAttribute("y2","0"),x.setAttribute("stroke",e),x.setAttribute("stroke-width","1"),b.append(v,x),m.append(b);for(var g=1;g<60;g++){var E=document.createElementNS(t,"line");E.setAttribute("y1","0"),E.setAttribute("y2","0"),E.setAttribute("stroke",i),E.setAttribute("transform","translate(50 50) rotate("+6*g+")"),g%5==0?(E.setAttribute("x1","38"),E.setAttribute("x2","46"),E.setAttribute("stroke-width",g%15==0?"2":"1")):(E.setAttribute("x1","42"),E.setAttribute("x2","46"),E.setAttribute("stroke-width","0.5")),m.append(E)}var O=document.createElementNS(t,"g");O.setAttribute("class","hour-hand"),O.setAttribute("transform","translate(50 50)");var w=document.createElementNS(t,"line");w.setAttribute("class","hour-hand-a"),w.setAttribute("x1","0"),w.setAttribute("y1","0"),w.setAttribute("x2","30"),w.setAttribute("y2","0"),w.setAttribute("stroke",o),w.setAttribute("stroke-width","4"),w.setAttribute("stroke-linecap","round");var T=document.createElementNS(t,"line");T.setAttribute("class","hour-hand-b"),T.setAttribute("x1","0"),T.setAttribute("y1","0"),T.setAttribute("x2","29.9"),T.setAttribute("y2","0"),T.setAttribute("stroke",s),T.setAttribute("stroke-width","3.1"),T.setAttribute("stroke-linecap","round"),O.append(w,T);var A=document.createElementNS(t,"g");A.setAttribute("class","minute-hand"),A.setAttribute("transform","translate(50 50)");var k=document.createElementNS(t,"line");k.setAttribute("class","minute-hand-a"),k.setAttribute("x1","0"),k.setAttribute("y1","0"),k.setAttribute("x2","40"),k.setAttribute("y2","0"),k.setAttribute("stroke",o),k.setAttribute("stroke-width","2"),k.setAttribute("stroke-linecap","round");var P=document.createElementNS(t,"line");P.setAttribute("class","minute-hand-b"),P.setAttribute("x1","0"),P.setAttribute("y1","0"),P.setAttribute("x2","39.9"),P.setAttribute("y2","0"),P.setAttribute("stroke",s),P.setAttribute("stroke-width","1.5"),P.setAttribute("stroke-linecap","round");var j=document.createElementNS(t,"circle");j.setAttribute("r","3"),j.setAttribute("fill",s),A.append(k,P,j);var M=document.createElementNS(t,"g");M.setAttribute("class","second-hand"),M.setAttribute("transform","translate(50 50)");var S=document.createElementNS(t,"line");S.setAttribute("x1","0"),S.setAttribute("y1","0"),S.setAttribute("x2","46"),S.setAttribute("y2","0"),S.setAttribute("stroke",a),S.setAttribute("stroke-width","1"),S.setAttribute("stroke-linecap","round");var I=document.createElementNS(t,"circle");I.setAttribute("r","2"),I.setAttribute("fill",a),M.append(S,I);var N=document.createElementNS(t,"circle");N.setAttribute("cx","50"),N.setAttribute("cy","50"),N.setAttribute("r","0.3"),N.setAttribute("fill",s);var D=this.getOriginDate(),L=D.getSeconds(),R=D.getMinutes(),C=6*L,B=6*R+L/60*6,W=30*D.getHours()+R/60*30;return O.setAttribute("transform","translate(50 50) rotate("+W+")"),A.setAttribute("transform","translate(50 50) rotate("+B+")"),M.setAttribute("transform","translate(50 50) rotate("+C+")"),p.append(_,m,O,A,M,N),p.setAttribute("transform","rotate(-90)"),h.innerHTML="\n \n ",h.append(p),h},e.prototype.createDigitalClock=function(){var t=document.createElement("div");t.className="digital-clock";var e=this.getElementSize().width,n=6/this.props.clockTimezone.length,i=20*e/100,s=10*e/100,o=Math.min(20*n*e/100,e/100*10),a=this.getOriginDate();if("datetime"===this.props.clockFormat){var c=document.createElement("span");c.className="date",c.textContent=Object(r.b)(a,"default"),c.style.fontSize=s+"px",this.props.color&&(c.style.color=this.props.color),t.append(c)}var l=document.createElement("span");l.className="time",l.textContent=Object(r.c)(a),l.style.fontSize=i+"px",this.props.color&&(l.style.color=this.props.color),t.append(l);var u=this.getHumanTimezone();if(u.length>0){var h=document.createElement("span");h.className="timezone",h.textContent=u,h.style.fontSize=o+"px",this.props.color&&(h.style.color=this.props.color),t.append(h)}return t},e.prototype.getOriginDate=function(t){void 0===t&&(t=null);var e=t||new Date,n=1e3*this.props.clockTimezoneOffset,i=60*e.getTimezoneOffset()*1e3,r=e.getTime()+n+i;return new Date(r)},e.prototype.getHumanTimezone=function(t){void 0===t&&(t=this.props.clockTimezone);var e=t.split("/")[1];return(void 0===e?"":e).replace("_"," ")},e.prototype.getElementSize=function(t,e){switch(void 0===t&&(t=this.props.width),void 0===e&&(e=this.props.height),this.props.clockType){case"analogic":var n=100;return t>0&&e>0?n=Math.min(t,e):t>0?n=t:e>0&&(n=e),{width:n,height:n};case"digital":return t>0&&e>0?e=t/20?e=t/2:e>0?t=2*e:(t=100,e=50),{width:t,height:e};default:throw new Error("invalid clock type.")}},e.TICK_INTERVAL=1e3,e}(s.a),M=function(){var t=function(e,n){return(t=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(t,e){t.__proto__=e}||function(t,e){for(var n in e)e.hasOwnProperty(n)&&(t[n]=e[n])})(e,n)};return function(e,n){function i(){this.constructor=e}t(e,n),e.prototype=null===n?Object.create(n):(i.prototype=n.prototype,new i)}}(),S=function(){return(S=Object.assign||function(t){for(var e,n=1,i=arguments.length;n0){t.style.borderStyle="solid";var e=Math.min(this.props.width,this.props.height)/2,n=Math.min(this.props.borderWidth,e);t.style.borderWidth=n+"px",this.props.borderColor&&(t.style.borderColor=this.props.borderColor)}return t},e}(s.a),D=function(){var t=function(e,n){return(t=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(t,e){t.__proto__=e}||function(t,e){for(var n in e)e.hasOwnProperty(n)&&(t[n]=e[n])})(e,n)};return function(e,n){function i(){this.constructor=e}t(e,n),e.prototype=null===n?Object.create(n):(i.prototype=n.prototype,new i)}}(),L=function(){return(L=Object.assign||function(t){for(var e,n=1,i=arguments.length;n0&&(n=Object(r.l)([{macro:/\(?_VALUE_\)?/i,value:n}],i)),t.innerHTML=n}return t},e.prototype.createLabelDomElement=function(){var t=document.createElement("div");return t.className="visual-console-item-label",t},e}(s.a),X=n(3),Z=Math.PI,Q=2*Z,J=Q-1e-6;function $(){this._x0=this._y0=this._x1=this._y1=null,this._=""}function tt(){return new $}$.prototype=tt.prototype={constructor:$,moveTo:function(t,e){this._+="M"+(this._x0=this._x1=+t)+","+(this._y0=this._y1=+e)},closePath:function(){null!==this._x1&&(this._x1=this._x0,this._y1=this._y0,this._+="Z")},lineTo:function(t,e){this._+="L"+(this._x1=+t)+","+(this._y1=+e)},quadraticCurveTo:function(t,e,n,i){this._+="Q"+ +t+","+ +e+","+(this._x1=+n)+","+(this._y1=+i)},bezierCurveTo:function(t,e,n,i,r,s){this._+="C"+ +t+","+ +e+","+ +n+","+ +i+","+(this._x1=+r)+","+(this._y1=+s)},arcTo:function(t,e,n,i,r){t=+t,e=+e,n=+n,i=+i,r=+r;var s=this._x1,o=this._y1,a=n-t,c=i-e,l=s-t,u=o-e,h=l*l+u*u;if(r<0)throw new Error("negative radius: "+r);if(null===this._x1)this._+="M"+(this._x1=t)+","+(this._y1=e);else if(h>1e-6)if(Math.abs(u*a-c*l)>1e-6&&r){var p=n-s,_=i-o,f=a*a+c*c,d=p*p+_*_,y=Math.sqrt(f),m=Math.sqrt(h),b=r*Math.tan((Z-Math.acos((f+h-d)/(2*y*m)))/2),v=b/m,x=b/y;Math.abs(v-1)>1e-6&&(this._+="L"+(t+v*l)+","+(e+v*u)),this._+="A"+r+","+r+",0,0,"+ +(u*p>l*_)+","+(this._x1=t+x*a)+","+(this._y1=e+x*c)}else this._+="L"+(this._x1=t)+","+(this._y1=e);else;},arc:function(t,e,n,i,r,s){t=+t,e=+e;var o=(n=+n)*Math.cos(i),a=n*Math.sin(i),c=t+o,l=e+a,u=1^s,h=s?i-r:r-i;if(n<0)throw new Error("negative radius: "+n);null===this._x1?this._+="M"+c+","+l:(Math.abs(this._x1-c)>1e-6||Math.abs(this._y1-l)>1e-6)&&(this._+="L"+c+","+l),n&&(h<0&&(h=h%Q+Q),h>J?this._+="A"+n+","+n+",0,1,"+u+","+(t-o)+","+(e-a)+"A"+n+","+n+",0,1,"+u+","+(this._x1=c)+","+(this._y1=l):h>1e-6&&(this._+="A"+n+","+n+",0,"+ +(h>=Z)+","+u+","+(this._x1=t+n*Math.cos(r))+","+(this._y1=e+n*Math.sin(r))))},rect:function(t,e,n,i){this._+="M"+(this._x0=this._x1=+t)+","+(this._y0=this._y1=+e)+"h"+ +n+"v"+ +i+"h"+-n+"Z"},toString:function(){return this._}};var et=tt,nt=function(t){return function(){return t}},it=Math.abs,rt=Math.atan2,st=Math.cos,ot=Math.max,at=Math.min,ct=Math.sin,lt=Math.sqrt,ut=1e-12,ht=Math.PI,pt=ht/2,_t=2*ht;function ft(t){return t>=1?pt:t<=-1?-pt:Math.asin(t)}function dt(t){return t.innerRadius}function yt(t){return t.outerRadius}function mt(t){return t.startAngle}function bt(t){return t.endAngle}function vt(t){return t&&t.padAngle}function xt(t,e,n,i,r,s,o){var a=t-n,c=e-i,l=(o?s:-s)/lt(a*a+c*c),u=l*c,h=-l*a,p=t+u,_=e+h,f=n+u,d=i+h,y=(p+f)/2,m=(_+d)/2,b=f-p,v=d-_,x=b*b+v*v,g=r-s,E=p*d-f*_,O=(v<0?-1:1)*lt(ot(0,g*g*x-E*E)),w=(E*v-b*O)/x,T=(-E*b-v*O)/x,A=(E*v+b*O)/x,k=(-E*b+v*O)/x,P=w-y,j=T-m,M=A-y,S=k-m;return P*P+j*j>M*M+S*S&&(w=A,T=k),{cx:w,cy:T,x01:-u,y01:-h,x11:w*(r/g-1),y11:T*(r/g-1)}}var gt=function(){var t=dt,e=yt,n=nt(0),i=null,r=mt,s=bt,o=vt,a=null;function c(){var c,l,u,h=+t.apply(this,arguments),p=+e.apply(this,arguments),_=r.apply(this,arguments)-pt,f=s.apply(this,arguments)-pt,d=it(f-_),y=f>_;if(a||(a=c=et()),put)if(d>_t-ut)a.moveTo(p*st(_),p*ct(_)),a.arc(0,0,p,_,f,!y),h>ut&&(a.moveTo(h*st(f),h*ct(f)),a.arc(0,0,h,f,_,y));else{var m,b,v=_,x=f,g=_,E=f,O=d,w=d,T=o.apply(this,arguments)/2,A=T>ut&&(i?+i.apply(this,arguments):lt(h*h+p*p)),k=at(it(p-h)/2,+n.apply(this,arguments)),P=k,j=k;if(A>ut){var M=ft(A/h*ct(T)),S=ft(A/p*ct(T));(O-=2*M)>ut?(g+=M*=y?1:-1,E-=M):(O=0,g=E=(_+f)/2),(w-=2*S)>ut?(v+=S*=y?1:-1,x-=S):(w=0,v=x=(_+f)/2)}var I=p*st(v),N=p*ct(v),D=h*st(E),L=h*ct(E);if(k>ut){var R,C=p*st(x),B=p*ct(x),W=h*st(g),H=h*ct(g);if(d1?0:u<-1?ht:Math.acos(u))/2),V=lt(R[0]*R[0]+R[1]*R[1]);P=at(k,(h-V)/(q-1)),j=at(k,(p-V)/(q+1))}}w>ut?j>ut?(m=xt(W,H,I,N,p,j,y),b=xt(C,B,D,L,p,j,y),a.moveTo(m.cx+m.x01,m.cy+m.y01),jut&&O>ut?P>ut?(m=xt(D,L,C,B,h,-P,y),b=xt(I,N,W,H,h,-P,y),a.lineTo(m.cx+m.x01,m.cy+m.y01),P0)for(var i,r=t[0],s=e[0],o=t[n]-r,a=e[n]-s,c=-1;++c<=n;)i=c/n,this._basis.point(this._beta*t[c]+(1-this._beta)*(r+i*o),this._beta*e[c]+(1-this._beta)*(s+i*a));this._x=this._y=null,this._basis.lineEnd()},point:function(t,e){this._x.push(+t),this._y.push(+e)}};(function t(e){function n(t){return 1===e?new jt(t):new It(t,e)}return n.beta=function(e){return t(+e)},n})(.85);function Nt(t,e,n){t._context.bezierCurveTo(t._x1+t._k*(t._x2-t._x0),t._y1+t._k*(t._y2-t._y0),t._x2+t._k*(t._x1-e),t._y2+t._k*(t._y1-n),t._x2,t._y2)}function Dt(t,e){this._context=t,this._k=(1-e)/6}Dt.prototype={areaStart:function(){this._line=0},areaEnd:function(){this._line=NaN},lineStart:function(){this._x0=this._x1=this._x2=this._y0=this._y1=this._y2=NaN,this._point=0},lineEnd:function(){switch(this._point){case 2:this._context.lineTo(this._x2,this._y2);break;case 3:Nt(this,this._x1,this._y1)}(this._line||0!==this._line&&1===this._point)&&this._context.closePath(),this._line=1-this._line},point:function(t,e){switch(t=+t,e=+e,this._point){case 0:this._point=1,this._line?this._context.lineTo(t,e):this._context.moveTo(t,e);break;case 1:this._point=2,this._x1=t,this._y1=e;break;case 2:this._point=3;default:Nt(this,t,e)}this._x0=this._x1,this._x1=this._x2,this._x2=t,this._y0=this._y1,this._y1=this._y2,this._y2=e}};(function t(e){function n(t){return new Dt(t,e)}return n.tension=function(e){return t(+e)},n})(0);function Lt(t,e){this._context=t,this._k=(1-e)/6}Lt.prototype={areaStart:kt,areaEnd:kt,lineStart:function(){this._x0=this._x1=this._x2=this._x3=this._x4=this._x5=this._y0=this._y1=this._y2=this._y3=this._y4=this._y5=NaN,this._point=0},lineEnd:function(){switch(this._point){case 1:this._context.moveTo(this._x3,this._y3),this._context.closePath();break;case 2:this._context.lineTo(this._x3,this._y3),this._context.closePath();break;case 3:this.point(this._x3,this._y3),this.point(this._x4,this._y4),this.point(this._x5,this._y5)}},point:function(t,e){switch(t=+t,e=+e,this._point){case 0:this._point=1,this._x3=t,this._y3=e;break;case 1:this._point=2,this._context.moveTo(this._x4=t,this._y4=e);break;case 2:this._point=3,this._x5=t,this._y5=e;break;default:Nt(this,t,e)}this._x0=this._x1,this._x1=this._x2,this._x2=t,this._y0=this._y1,this._y1=this._y2,this._y2=e}};(function t(e){function n(t){return new Lt(t,e)}return n.tension=function(e){return t(+e)},n})(0);function Rt(t,e){this._context=t,this._k=(1-e)/6}Rt.prototype={areaStart:function(){this._line=0},areaEnd:function(){this._line=NaN},lineStart:function(){this._x0=this._x1=this._x2=this._y0=this._y1=this._y2=NaN,this._point=0},lineEnd:function(){(this._line||0!==this._line&&3===this._point)&&this._context.closePath(),this._line=1-this._line},point:function(t,e){switch(t=+t,e=+e,this._point){case 0:this._point=1;break;case 1:this._point=2;break;case 2:this._point=3,this._line?this._context.lineTo(this._x2,this._y2):this._context.moveTo(this._x2,this._y2);break;case 3:this._point=4;default:Nt(this,t,e)}this._x0=this._x1,this._x1=this._x2,this._x2=t,this._y0=this._y1,this._y1=this._y2,this._y2=e}};(function t(e){function n(t){return new Rt(t,e)}return n.tension=function(e){return t(+e)},n})(0);function Ct(t,e,n){var i=t._x1,r=t._y1,s=t._x2,o=t._y2;if(t._l01_a>ut){var a=2*t._l01_2a+3*t._l01_a*t._l12_a+t._l12_2a,c=3*t._l01_a*(t._l01_a+t._l12_a);i=(i*a-t._x0*t._l12_2a+t._x2*t._l01_2a)/c,r=(r*a-t._y0*t._l12_2a+t._y2*t._l01_2a)/c}if(t._l23_a>ut){var l=2*t._l23_2a+3*t._l23_a*t._l12_a+t._l12_2a,u=3*t._l23_a*(t._l23_a+t._l12_a);s=(s*l+t._x1*t._l23_2a-e*t._l12_2a)/u,o=(o*l+t._y1*t._l23_2a-n*t._l12_2a)/u}t._context.bezierCurveTo(i,r,s,o,t._x2,t._y2)}function Bt(t,e){this._context=t,this._alpha=e}Bt.prototype={areaStart:function(){this._line=0},areaEnd:function(){this._line=NaN},lineStart:function(){this._x0=this._x1=this._x2=this._y0=this._y1=this._y2=NaN,this._l01_a=this._l12_a=this._l23_a=this._l01_2a=this._l12_2a=this._l23_2a=this._point=0},lineEnd:function(){switch(this._point){case 2:this._context.lineTo(this._x2,this._y2);break;case 3:this.point(this._x2,this._y2)}(this._line||0!==this._line&&1===this._point)&&this._context.closePath(),this._line=1-this._line},point:function(t,e){if(t=+t,e=+e,this._point){var n=this._x2-t,i=this._y2-e;this._l23_a=Math.sqrt(this._l23_2a=Math.pow(n*n+i*i,this._alpha))}switch(this._point){case 0:this._point=1,this._line?this._context.lineTo(t,e):this._context.moveTo(t,e);break;case 1:this._point=2;break;case 2:this._point=3;default:Ct(this,t,e)}this._l01_a=this._l12_a,this._l12_a=this._l23_a,this._l01_2a=this._l12_2a,this._l12_2a=this._l23_2a,this._x0=this._x1,this._x1=this._x2,this._x2=t,this._y0=this._y1,this._y1=this._y2,this._y2=e}};(function t(e){function n(t){return e?new Bt(t,e):new Dt(t,0)}return n.alpha=function(e){return t(+e)},n})(.5);function Wt(t,e){this._context=t,this._alpha=e}Wt.prototype={areaStart:kt,areaEnd:kt,lineStart:function(){this._x0=this._x1=this._x2=this._x3=this._x4=this._x5=this._y0=this._y1=this._y2=this._y3=this._y4=this._y5=NaN,this._l01_a=this._l12_a=this._l23_a=this._l01_2a=this._l12_2a=this._l23_2a=this._point=0},lineEnd:function(){switch(this._point){case 1:this._context.moveTo(this._x3,this._y3),this._context.closePath();break;case 2:this._context.lineTo(this._x3,this._y3),this._context.closePath();break;case 3:this.point(this._x3,this._y3),this.point(this._x4,this._y4),this.point(this._x5,this._y5)}},point:function(t,e){if(t=+t,e=+e,this._point){var n=this._x2-t,i=this._y2-e;this._l23_a=Math.sqrt(this._l23_2a=Math.pow(n*n+i*i,this._alpha))}switch(this._point){case 0:this._point=1,this._x3=t,this._y3=e;break;case 1:this._point=2,this._context.moveTo(this._x4=t,this._y4=e);break;case 2:this._point=3,this._x5=t,this._y5=e;break;default:Ct(this,t,e)}this._l01_a=this._l12_a,this._l12_a=this._l23_a,this._l01_2a=this._l12_2a,this._l12_2a=this._l23_2a,this._x0=this._x1,this._x1=this._x2,this._x2=t,this._y0=this._y1,this._y1=this._y2,this._y2=e}};(function t(e){function n(t){return e?new Wt(t,e):new Lt(t,0)}return n.alpha=function(e){return t(+e)},n})(.5);function Ht(t,e){this._context=t,this._alpha=e}Ht.prototype={areaStart:function(){this._line=0},areaEnd:function(){this._line=NaN},lineStart:function(){this._x0=this._x1=this._x2=this._y0=this._y1=this._y2=NaN,this._l01_a=this._l12_a=this._l23_a=this._l01_2a=this._l12_2a=this._l23_2a=this._point=0},lineEnd:function(){(this._line||0!==this._line&&3===this._point)&&this._context.closePath(),this._line=1-this._line},point:function(t,e){if(t=+t,e=+e,this._point){var n=this._x2-t,i=this._y2-e;this._l23_a=Math.sqrt(this._l23_2a=Math.pow(n*n+i*i,this._alpha))}switch(this._point){case 0:this._point=1;break;case 1:this._point=2;break;case 2:this._point=3,this._line?this._context.lineTo(this._x2,this._y2):this._context.moveTo(this._x2,this._y2);break;case 3:this._point=4;default:Ct(this,t,e)}this._l01_a=this._l12_a,this._l12_a=this._l23_a,this._l01_2a=this._l12_2a,this._l12_2a=this._l23_2a,this._x0=this._x1,this._x1=this._x2,this._x2=t,this._y0=this._y1,this._y1=this._y2,this._y2=e}};(function t(e){function n(t){return e?new Ht(t,e):new Rt(t,0)}return n.alpha=function(e){return t(+e)},n})(.5);function zt(t){this._context=t}zt.prototype={areaStart:kt,areaEnd:kt,lineStart:function(){this._point=0},lineEnd:function(){this._point&&this._context.closePath()},point:function(t,e){t=+t,e=+e,this._point?this._context.lineTo(t,e):(this._point=1,this._context.moveTo(t,e))}};function Ut(t){return t<0?-1:1}function Kt(t,e,n){var i=t._x1-t._x0,r=e-t._x1,s=(t._y1-t._y0)/(i||r<0&&-0),o=(n-t._y1)/(r||i<0&&-0),a=(s*r+o*i)/(i+r);return(Ut(s)+Ut(o))*Math.min(Math.abs(s),Math.abs(o),.5*Math.abs(a))||0}function Gt(t,e){var n=t._x1-t._x0;return n?(3*(t._y1-t._y0)/n-e)/2:e}function qt(t,e,n){var i=t._x0,r=t._y0,s=t._x1,o=t._y1,a=(s-i)/3;t._context.bezierCurveTo(i+a,r+a*e,s-a,o-a*n,s,o)}function Vt(t){this._context=t}function Ft(t){this._context=new Yt(t)}function Yt(t){this._context=t}function Xt(t){this._context=t}function Zt(t){var e,n,i=t.length-1,r=new Array(i),s=new Array(i),o=new Array(i);for(r[0]=0,s[0]=2,o[0]=t[0]+2*t[1],e=1;e=0;--e)r[e]=(o[e]-r[e+1])/s[e];for(s[i-1]=(t[i]+r[i-1])/2,e=0;e=0&&(this._t=1-this._t,this._line=1-this._line)},point:function(t,e){switch(t=+t,e=+e,this._point){case 0:this._point=1,this._line?this._context.lineTo(t,e):this._context.moveTo(t,e);break;case 1:this._point=2;default:if(this._t<=0)this._context.lineTo(this._x,e),this._context.lineTo(t,e);else{var n=this._x*(1-this._t)+t*this._t;this._context.lineTo(n,this._y),this._context.lineTo(n,e)}}this._x=t,this._y=e}};var Jt=function(){var t=function(e,n){return(t=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(t,e){t.__proto__=e}||function(t,e){for(var n in e)e.hasOwnProperty(n)&&(t[n]=e[n])})(e,n)};return function(e,n){function i(){this.constructor=e}t(e,n),e.prototype=null===n?Object.create(n):(i.prototype=n.prototype,new i)}}(),$t=function(){return($t=Object.assign||function(t){for(var e,n=1,i=arguments.length;n0){var h=document.createElementNS(ie,"tspan");h.setAttribute("x","0"),h.setAttribute("dy","1em"),h.textContent=""+this.props.value;var p=document.createElementNS(ie,"tspan");p.setAttribute("x","0"),p.setAttribute("dy","1em"),p.textContent=""+this.props.unit,u.append(h,p),u.setAttribute("transform","translate(50 33)")}else u.textContent=""+this.props.value,u.setAttribute("transform","translate(50 50)");else u.textContent=e+"%",u.setAttribute("transform","translate(50 50)");i.append(u)}return n.append(i),n},e.prototype.getProgress=function(){var t=this.props.minValue||0,e=this.props.maxValue||100,n=null==this.props.value?0:this.props.value;return n<=t?0:n>=e?100:Math.trunc((n-t)/(e-t)*100)},e}(s.a),se=n(2),oe=n(4),ae=n(5),ce=n(6),le=function(){var t=function(e,n){return(t=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(t,e){t.__proto__=e}||function(t,e){for(var n in e)e.hasOwnProperty(n)&&(t[n]=e[n])})(e,n)};return function(e,n){function i(){this.constructor=e}t(e,n),e.prototype=null===n?Object.create(n):(i.prototype=n.prototype,new i)}}(),ue=function(){return(ue=Object.assign||function(t){for(var e,n=1,i=arguments.length;ne.id?1:-1})).forEach(function(t){try{var e=fe(t);i.elementsById[e.props.id]=e,i.elementIds.push(e.props.id),e.onClick(i.handleElementClick),e.onRemove(i.handleElementRemove),i.containerRef.append(e.elementRef)}catch(t){console.log("Error creating a new element:",t.message)}}),this.buildRelations()}return Object.defineProperty(t.prototype,"elements",{get:function(){var t=this;return this.elementIds.map(function(e){return t.elementsById[e]}).filter(function(t){return null!=t})},enumerable:!0,configurable:!0}),t.prototype.updateElements=function(t){var e=this,n=t.map(function(t){return t.id||null}).filter(function(t){return null!=t});this.elementIds.filter(function(t){return n.indexOf(t)<0}).forEach(function(t){null!=e.elementsById[t]&&(e.elementsById[t].remove(),delete e.elementsById[t])}),this.elementIds=n,t.forEach(function(t){if(t.id)if(null==e.elementsById[t.id])try{var n=fe(t);e.elementsById[n.props.id]=n,n.onClick(e.handleElementClick),n.onRemove(e.handleElementRemove),e.containerRef.append(n.elementRef)}catch(t){console.log("Error creating a new element:",t.message)}else try{e.elementsById[t.id].props=function(t){var e=Object(r.i)(t.type,null);if(null==e)throw new TypeError("missing item type.");switch(e){case 0:return l(t);case 1:return Object(ce.b)(t);case 2:case 6:case 7:case 8:return F(t);case 3:case 9:case 15:case 16:return ne(t);case 4:return z(t);case 5:return _(t);case 10:return he(t);case 11:return E(t);case 12:return I(t);case 13:return R(t);case 14:return Object(X.b)(t);case 17:return Object(oe.b)(t);case 18:return Object(ae.a)(t);case 19:return P(t);case 20:return m(t);default:throw new TypeError("decoder not found")}}(t)}catch(t){console.log("Error updating an element:",t.message)}}),this.buildRelations()},Object.defineProperty(t.prototype,"props",{get:function(){return _e({},this._props)},set:function(t){var e=this.props;this._props=t,this.render(e)},enumerable:!0,configurable:!0}),t.prototype.render=function(t){void 0===t&&(t=null),t?(t.backgroundURL!==this.props.backgroundURL&&(this.containerRef.style.backgroundImage=null!==this.props.backgroundURL?"url("+this.props.backgroundURL+")":null),t.backgroundColor!==this.props.backgroundColor&&(this.containerRef.style.backgroundColor=this.props.backgroundColor),this.sizeChanged(t,this.props)&&this.resizeElement(this.props.width,this.props.height)):(this.containerRef.style.backgroundImage=null!==this.props.backgroundURL?"url("+this.props.backgroundURL+")":null,this.containerRef.style.backgroundColor=this.props.backgroundColor,this.resizeElement(this.props.width,this.props.height))},t.prototype.sizeChanged=function(t,e){return t.width!==e.width||t.height!==e.height},t.prototype.resizeElement=function(t,e){this.containerRef.style.width=t+"px",this.containerRef.style.height=e+"px"},t.prototype.resize=function(t,e){this.props=_e({},this.props,{width:t,height:e})},t.prototype.remove=function(){this.disposables.forEach(function(t){return t.dispose()}),this.elements.forEach(function(t){return t.remove()}),this.elementsById={},this.elementIds=[],this.clearRelations(),this.containerRef.innerHTML=""},t.prototype.buildRelations=function(){var t=this;this.clearRelations(),this.elements.forEach(function(e){if(null!==e.props.parentId){var n=t.elementsById[e.props.parentId],i=t.elementsById[e.props.id];n&&i&&t.addRelationLine(n,i)}})},t.prototype.clearRelations=function(t){if(null!=t)for(var e in this.relations){var n=e.split("|"),i=Number.parseInt(n[0]),r=Number.parseInt(n[1]);t!==i&&t!==r||(this.relations[e].remove(),delete this.relations[e])}else for(var e in this.relations)this.relations[e].remove(),delete this.relations[e]},t.prototype.getRelationLine=function(t,e){var n=t+"|"+e;return this.relations[n]||null},t.prototype.addRelationLine=function(t,e){var n=t.props.id+"|"+e.props.id;null!=this.relations[n]&&this.relations[n].remove();var i=t.props.x+t.elementRef.clientWidth/2,r=t.props.y+(t.elementRef.clientHeight-t.labelElementRef.clientHeight)/2,s=e.props.x+e.elementRef.clientWidth/2,o=e.props.y+(e.elementRef.clientHeight-e.labelElementRef.clientHeight)/2,a=new B(R({id:0,type:13,startX:i,startY:r,endX:s,endY:o,width:0,height:0,lineWidth:this.props.relationLineWidth,color:"#CCCCCC"}));return this.relations[n]=a,a.elementRef.style.zIndex="0",this.containerRef.append(a.elementRef),a},t.prototype.onClick=function(t){var e=this.clickEventManager.on(t);return this.disposables.push(e),e},t}();window.VisualConsole=de}]);
+//# sourceMappingURL=vc.main.min.js.map
\ No newline at end of file
diff --git a/pandora_console/include/visual-console-client/vc.main.min.js.map b/pandora_console/include/visual-console-client/vc.main.min.js.map
new file mode 100644
index 0000000000..f8a9dc46b8
--- /dev/null
+++ b/pandora_console/include/visual-console-client/vc.main.min.js.map
@@ -0,0 +1 @@
+{"version":3,"sources":["webpack:///webpack/bootstrap","webpack:///./src/lib.ts","webpack:///./src/Item.ts","webpack:///./src/TypedEvent.ts","webpack:///./src/items/EventsHistory.ts","webpack:///./src/items/DonutGraph.ts","webpack:///./src/items/BarsGraph.ts","webpack:///./src/items/ModuleGraph.ts","webpack:///./src/items/StaticGraph.ts","webpack:///./src/items/Icon.ts","webpack:///./src/items/ColorCloud.ts","webpack:///./src/items/Group.ts","webpack:///./src/items/Clock/index.ts","webpack:///./src/items/Box.ts","webpack:///./src/items/Line.ts","webpack:///./src/items/Label.ts","webpack:///./src/items/SimpleValue.ts","webpack:///./node_modules/d3-path/src/path.js","webpack:///./node_modules/d3-shape/src/constant.js","webpack:///./node_modules/d3-shape/src/math.js","webpack:///./node_modules/d3-shape/src/arc.js","webpack:///./node_modules/d3-shape/src/curve/linear.js","webpack:///./node_modules/d3-shape/src/curve/radial.js","webpack:///./node_modules/d3-shape/src/array.js","webpack:///./node_modules/d3-shape/src/symbol/diamond.js","webpack:///./node_modules/d3-shape/src/symbol/circle.js","webpack:///./node_modules/d3-shape/src/symbol/star.js","webpack:///./node_modules/d3-shape/src/noop.js","webpack:///./node_modules/d3-shape/src/symbol/triangle.js","webpack:///./node_modules/d3-shape/src/symbol/wye.js","webpack:///./node_modules/d3-shape/src/curve/basis.js","webpack:///./node_modules/d3-shape/src/curve/basisClosed.js","webpack:///./node_modules/d3-shape/src/curve/basisOpen.js","webpack:///./node_modules/d3-shape/src/curve/bundle.js","webpack:///./node_modules/d3-shape/src/curve/cardinal.js","webpack:///./node_modules/d3-shape/src/curve/cardinalClosed.js","webpack:///./node_modules/d3-shape/src/curve/cardinalOpen.js","webpack:///./node_modules/d3-shape/src/curve/catmullRom.js","webpack:///./node_modules/d3-shape/src/curve/catmullRomClosed.js","webpack:///./node_modules/d3-shape/src/curve/catmullRomOpen.js","webpack:///./node_modules/d3-shape/src/curve/linearClosed.js","webpack:///./node_modules/d3-shape/src/curve/monotone.js","webpack:///./node_modules/d3-shape/src/curve/natural.js","webpack:///./node_modules/d3-shape/src/curve/step.js","webpack:///./node_modules/d3-shape/src/order/descending.js","webpack:///./src/items/Percentile.ts","webpack:///./src/items/Service.ts","webpack:///./src/VisualConsole.ts","webpack:///./src/index.ts"],"names":["installedModules","__webpack_require__","moduleId","exports","module","i","l","modules","call","m","c","d","name","getter","o","Object","defineProperty","enumerable","get","r","Symbol","toStringTag","value","t","mode","__esModule","ns","create","key","bind","n","object","property","prototype","hasOwnProperty","p","s","parseIntOr","defaultValue","length","isNaN","parseInt","parseFloatOr","parseFloat","stringIsEmpty","notEmptyStringOr","parseBoolean","leftPad","pad","diffLength","substr","Math","abs","substring","repeatTimes","floor","restLength","newPad","positionPropsDecoder","data","x","y","sizePropsDecoder","width","height","TypeError","modulePropsDecoder","__assign","moduleName","moduleDescription","agentProps","agentId","agent","agentName","agentAlias","agentDescription","agentAddress","metaconsoleId","agentPropsDecoder","linkedVCPropsDecoder","id","linkedLayoutId","linkedLayoutAgentId","linkedLayoutStatusProps","linkedLayoutStatusType","weight","linkedLayoutStatusTypeWeight","warningThreshold","linkedLayoutStatusTypeWarningThreshold","criticalThreshold","linkedLayoutStatusTypeCriticalThreshold","linkedLayoutBaseProps","prefixedCssRules","ruleName","ruleValue","rule","decodeBase64","input","decodeURIComponent","escape","window","atob","humanDate","date","locale","Intl","DateTimeFormat","day","month","year","format","getDate","getMonth","getFullYear","humanTime","getHours","getMinutes","getSeconds","replaceMacros","macros","text","reduce","acc","_a","macro","replace","parseLabelPosition","labelPosition","itemBasePropsDecoder","type","label","_lib__WEBPACK_IMPORTED_MODULE_0__","isLinkEnabled","link","isOnTop","parentId","aclGroupId","VisualConsoleItem","props","this","clickEventManager","_TypedEvent__WEBPACK_IMPORTED_MODULE_1__","removeEventManager","disposables","itemProps","elementRef","createContainerDomElement","labelElementRef","createLabelDomElement","childElementRef","createDomElement","append","resizeElement","changeLabelPosition","box","_this","document","createElement","href","className","style","zIndex","left","top","onclick","e","emit","nativeEvent","element","getLabelWithMacrosReplaced","table","row","emptyRow1","emptyRow2","cell","innerHTML","textAlign","Date","updateDomElement","newProps","prevProps","shouldBeUpdated","render","positionChanged","moveElement","sizeChanged","oldLabelHtml","newLabelHtml","container","attrs","attributes","nodeName","setAttributeNode","parentNode","replaceChild","remove","forEach","disposable","dispose","ignored","prevPosition","newPosition","position","flexDirection","tables","getElementsByTagName","item","move","prevSize","newSize","resize","onClick","listener","on","push","onRemove","__webpack_exports__","TypedEvent","listeners","listenersOncer","off","once","callbackIndex","indexOf","splice","event","pipe","te","eventsHistoryPropsDecoder","html","encodedHtml","_Item__WEBPACK_IMPORTED_MODULE_1__","maxTime","EventsHistory","_super","__extends","scripts","src","setTimeout","eval","trim","aux","donutGraphPropsDecoder","DonutGraph","barsGraphPropsDecoder","BarsGraph","moduleGraphPropsDecoder","ModuleGraph","legendP","margin","overviewGraphs","getElementsByClassName","parseShowLastValueTooltip","showLastValueTooltip","staticGraphPropsDecoder","imageSrc","Item","statusImageSrc","lib","lastValue","StaticGraph","imgSrc","background","backgroundSize","backgroundPosition","setAttribute","iconPropsDecoder","Icon_assign","Icon","Icon_extends","colorCloudPropsDecoder","color","ColorCloud_assign","ColorCloud_svgNS","ColorCloud","ColorCloud_extends","createSvgElement","gradientId","svg","createElementNS","defs","radialGradient","stop0","stop100","circle","groupPropsDecoder","groupId","showStatistics","extractHtml","Group_assign","Group","Group_extends","parseClockType","clockType","parseClockFormat","clockFormat","clockPropsDecoder","clockTimezone","Clock_assign","clockTimezoneOffset","showClockTimezone","items_Clock","Clock","intervalRef","startTick","createClock","TICK_INTERVAL","Clock_extends","stopTick","clearInterval","handler","interval","setInterval","getElementSize","newWidth","newHeight","createAnalogicClock","createDigitalClock","Error","svgNS","colors","div","clockFace","clockFaceBackground","city","getHumanTimezone","timezoneComplication","textContent","marksGroup","mainMarkGroup","mark1a","mark1b","mark","hourHand","hourHandA","hourHandB","minuteHand","minuteHandA","minuteHandB","minuteHandPin","secondHand","secondHandBar","secondHandPin","pin","getOriginDate","seconds","minutes","secAngle","minuteAngle","hourAngle","join","tzFontSizeMultiplier","timeFontSize","dateFontSize","baseTimeFontSize","tzFontSize","min","dateElem","fontSize","timeElem","tzElem","initialDate","targetTZOffset","localTZOffset","getTimezoneOffset","utimestamp","getTime","timezone","_b","split","diameter","boxPropsDecoder","Box_assign","borderWidth","borderColor","fillColor","Box","Box_extends","boxSizing","backgroundColor","borderStyle","maxBorderWidth","linePropsDecoder","Line_assign","startPosition","startX","startY","endPosition","endX","endY","lineWidth","Line","extractBoxSizeAndPosition","Line_extends","toString","line","labelPropsDecoder","Label_assign","Label","Label_extends","parseValueType","valueType","parseProcessValue","processValue","simpleValuePropsDecoder","SimpleValue_assign","period","SimpleValue","SimpleValue_extends","img","pi","PI","tau","tauEpsilon","Path","_x0","_y0","_x1","_y1","_","path","constructor","moveTo","closePath","lineTo","quadraticCurveTo","x1","y1","bezierCurveTo","x2","y2","arcTo","x0","y0","x21","y21","x01","y01","l01_2","x20","y20","l21_2","l20_2","l21","sqrt","l01","tan","acos","t01","t21","arc","a0","a1","ccw","dx","cos","dy","sin","cw","da","rect","w","h","src_path","constant","atan2","max","math_epsilon","math_pi","halfPi","math_tau","asin","arcInnerRadius","innerRadius","arcOuterRadius","outerRadius","arcStartAngle","startAngle","arcEndAngle","endAngle","arcPadAngle","padAngle","cornerTangents","r1","rc","lo","ox","oy","x11","y11","x10","y10","x00","y00","d2","D","cx0","cy0","cx1","cy1","dx0","dy0","dx1","dy1","cx","cy","src_arc","cornerRadius","padRadius","context","buffer","r0","apply","arguments","t0","t1","a01","a11","a00","a10","da0","da1","ap","rp","rc0","rc1","p0","p1","oc","x3","y3","x32","y32","intersect","ax","ay","bx","by","kc","lc","centroid","a","Linear","_context","areaStart","_line","areaEnd","NaN","lineStart","_point","lineEnd","point","linear","curveRadial","Radial","curve","_curve","radial","Array","slice","kr","noop","that","Basis","BasisClosed","_x2","_x3","_x4","_y2","_y3","_y4","BasisOpen","Bundle","beta","_basis","_beta","_x","_y","j","custom","bundle","cardinal_point","_k","Cardinal","tension","cardinal","CardinalClosed","_x5","_y5","CardinalOpen","catmullRom_point","_l01_a","_l01_2a","_l12_a","_l12_2a","_l23_a","b","_l23_2a","CatmullRom","alpha","_alpha","x23","y23","pow","catmullRom","CatmullRomClosed","CatmullRomOpen","LinearClosed","sign","slope3","h0","h1","s0","s1","slope2","monotone_point","MonotoneX","MonotoneY","ReflectContext","Natural","controlPoints","_t0","px","py","i0","i1","Step","_t","extractPercentileType","extractValueType","percentilePropsDecoder","Percentile_assign","percentileType","minValue","maxValue","labelColor","unit","Percentile_svgNS","Percentile","Percentile_extends","progress","getProgress","backgroundRect","progressRect","backgroundCircle","progressCircle","arcProps","trunc","servicePropsDecoder","encodedTitle","serviceId","Service_assign","Service","Service_extends","itemInstanceFrom","items_StaticGraph","items_SimpleValue","items_Percentile","items_Label","items_Icon","items_Service","items_Group","items_Box","items_Line","items_ColorCloud","VisualConsole","items","elementsById","elementIds","relations","handleElementClick","handleElementRemove","filter","clearRelations","containerRef","_props","backgroundURL","isFavorite","relationLineWidth","VisualConsole_assign","visualConsolePropsDecoder","sort","itemInstance","error","console","log","message","buildRelations","map","updateElements","itemIds","decodeProps","backgroundImage","elements","parent_1","child","addRelationLine","itemId","ids","Number","childId","getRelationLine","identifier","parent","clientWidth","clientHeight","src_VisualConsole"],"mappings":"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","file":"vc.main.min.js","sourcesContent":[" \t// The module cache\n \tvar installedModules = {};\n\n \t// The require function\n \tfunction __webpack_require__(moduleId) {\n\n \t\t// Check if module is in cache\n \t\tif(installedModules[moduleId]) {\n \t\t\treturn installedModules[moduleId].exports;\n \t\t}\n \t\t// Create a new module (and put it into the cache)\n \t\tvar module = installedModules[moduleId] = {\n \t\t\ti: moduleId,\n \t\t\tl: false,\n \t\t\texports: {}\n \t\t};\n\n \t\t// Execute the module function\n \t\tmodules[moduleId].call(module.exports, module, module.exports, __webpack_require__);\n\n \t\t// Flag the module as loaded\n \t\tmodule.l = true;\n\n \t\t// Return the exports of the module\n \t\treturn module.exports;\n \t}\n\n\n \t// expose the modules object (__webpack_modules__)\n \t__webpack_require__.m = modules;\n\n \t// expose the module cache\n \t__webpack_require__.c = installedModules;\n\n \t// define getter function for harmony exports\n \t__webpack_require__.d = function(exports, name, getter) {\n \t\tif(!__webpack_require__.o(exports, name)) {\n \t\t\tObject.defineProperty(exports, name, { enumerable: true, get: getter });\n \t\t}\n \t};\n\n \t// define __esModule on exports\n \t__webpack_require__.r = function(exports) {\n \t\tif(typeof Symbol !== 'undefined' && Symbol.toStringTag) {\n \t\t\tObject.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });\n \t\t}\n \t\tObject.defineProperty(exports, '__esModule', { value: true });\n \t};\n\n \t// create a fake namespace object\n \t// mode & 1: value is a module id, require it\n \t// mode & 2: merge all properties of value into the ns\n \t// mode & 4: return value when already ns object\n \t// mode & 8|1: behave like require\n \t__webpack_require__.t = function(value, mode) {\n \t\tif(mode & 1) value = __webpack_require__(value);\n \t\tif(mode & 8) return value;\n \t\tif((mode & 4) && typeof value === 'object' && value && value.__esModule) return value;\n \t\tvar ns = Object.create(null);\n \t\t__webpack_require__.r(ns);\n \t\tObject.defineProperty(ns, 'default', { enumerable: true, value: value });\n \t\tif(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key));\n \t\treturn ns;\n \t};\n\n \t// getDefaultExport function for compatibility with non-harmony modules\n \t__webpack_require__.n = function(module) {\n \t\tvar getter = module && module.__esModule ?\n \t\t\tfunction getDefault() { return module['default']; } :\n \t\t\tfunction getModuleExports() { return module; };\n \t\t__webpack_require__.d(getter, 'a', getter);\n \t\treturn getter;\n \t};\n\n \t// Object.prototype.hasOwnProperty.call\n \t__webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };\n\n \t// __webpack_public_path__\n \t__webpack_require__.p = \"\";\n\n\n \t// Load entry module and return exports\n \treturn __webpack_require__(__webpack_require__.s = 9);\n","import {\n UnknownObject,\n Position,\n Size,\n WithAgentProps,\n WithModuleProps,\n LinkedVisualConsoleProps,\n LinkedVisualConsolePropsStatus\n} from \"./types\";\n\n/**\n * Return a number or a default value from a raw value.\n * @param value Raw value from which we will try to extract a valid number.\n * @param defaultValue Default value to use if we cannot extract a valid number.\n * @return A valid number or the default value.\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport function parseIntOr(value: any, defaultValue: T): number | T {\n if (typeof value === \"number\") return value;\n if (typeof value === \"string\" && value.length > 0 && !isNaN(parseInt(value)))\n return parseInt(value);\n else return defaultValue;\n}\n\n/**\n * Return a number or a default value from a raw value.\n * @param value Raw value from which we will try to extract a valid number.\n * @param defaultValue Default value to use if we cannot extract a valid number.\n * @return A valid number or the default value.\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport function parseFloatOr(value: any, defaultValue: T): number | T {\n if (typeof value === \"number\") return value;\n if (\n typeof value === \"string\" &&\n value.length > 0 &&\n !isNaN(parseFloat(value))\n )\n return parseFloat(value);\n else return defaultValue;\n}\n\n/**\n * Check if a string exists and it's not empty.\n * @param value Value to check.\n * @return The check result.\n */\nexport function stringIsEmpty(value?: string | null): boolean {\n return value == null || value.length === 0;\n}\n\n/**\n * Return a not empty string or a default value from a raw value.\n * @param value Raw value from which we will try to extract a non empty string.\n * @param defaultValue Default value to use if we cannot extract a non empty string.\n * @return A non empty string or the default value.\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport function notEmptyStringOr(value: any, defaultValue: T): string | T {\n return typeof value === \"string\" && value.length > 0 ? value : defaultValue;\n}\n\n/**\n * Return a boolean from a raw value.\n * @param value Raw value from which we will try to extract the boolean.\n * @return A valid boolean value. false by default.\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport function parseBoolean(value: any): boolean {\n if (typeof value === \"boolean\") return value;\n else if (typeof value === \"number\") return value > 0;\n else if (typeof value === \"string\") return value === \"1\" || value === \"true\";\n else return false;\n}\n\n/**\n * Pad the current string with another string (multiple times, if needed)\n * until the resulting string reaches the given length.\n * The padding is applied from the start (left) of the current string.\n * @param value Text that needs to be padded.\n * @param length Length of the returned text.\n * @param pad Text to add.\n * @return Padded text.\n */\nexport function leftPad(\n value: string | number,\n length: number,\n pad: string | number = \" \"\n): string {\n if (typeof value === \"number\") value = `${value}`;\n if (typeof pad === \"number\") pad = `${pad}`;\n\n const diffLength = length - value.length;\n if (diffLength === 0) return value;\n if (diffLength < 0) return value.substr(Math.abs(diffLength));\n\n if (diffLength === pad.length) return `${pad}${value}`;\n if (diffLength < pad.length) return `${pad.substring(0, diffLength)}${value}`;\n\n const repeatTimes = Math.floor(diffLength / pad.length);\n const restLength = diffLength - pad.length * repeatTimes;\n\n let newPad = \"\";\n for (let i = 0; i < repeatTimes; i++) newPad += pad;\n\n if (restLength === 0) return `${newPad}${value}`;\n return `${newPad}${pad.substring(0, restLength)}${value}`;\n}\n\n/* Decoders */\n\n/**\n * Build a valid typed object from a raw object.\n * @param data Raw object.\n * @return An object representing the position.\n */\nexport function positionPropsDecoder(data: UnknownObject): Position {\n return {\n x: parseIntOr(data.x, 0),\n y: parseIntOr(data.y, 0)\n };\n}\n\n/**\n * Build a valid typed object from a raw object.\n * @param data Raw object.\n * @return An object representing the size.\n * @throws Will throw a TypeError if the width and height are not valid numbers.\n */\nexport function sizePropsDecoder(data: UnknownObject): Size | never {\n if (\n data.width == null ||\n isNaN(parseInt(data.width)) ||\n data.height == null ||\n isNaN(parseInt(data.height))\n ) {\n throw new TypeError(\"invalid size.\");\n }\n\n return {\n width: parseInt(data.width),\n height: parseInt(data.height)\n };\n}\n\n/**\n * Build a valid typed object from a raw object.\n * @param data Raw object.\n * @return An object representing the agent properties.\n */\nexport function agentPropsDecoder(data: UnknownObject): WithAgentProps {\n const agentProps: WithAgentProps = {\n agentId: parseIntOr(data.agent, null),\n agentName: notEmptyStringOr(data.agentName, null),\n agentAlias: notEmptyStringOr(data.agentAlias, null),\n agentDescription: notEmptyStringOr(data.agentDescription, null),\n agentAddress: notEmptyStringOr(data.agentAddress, null)\n };\n\n return data.metaconsoleId != null\n ? {\n metaconsoleId: data.metaconsoleId,\n ...agentProps // Object spread: http://es6-features.org/#SpreadOperator\n }\n : agentProps;\n}\n\n/**\n * Build a valid typed object from a raw object.\n * @param data Raw object.\n * @return An object representing the module and agent properties.\n */\nexport function modulePropsDecoder(data: UnknownObject): WithModuleProps {\n return {\n moduleId: parseIntOr(data.moduleId, null),\n moduleName: notEmptyStringOr(data.moduleName, null),\n moduleDescription: notEmptyStringOr(data.moduleDescription, null),\n ...agentPropsDecoder(data) // Object spread: http://es6-features.org/#SpreadOperator\n };\n}\n\n/**\n * Build a valid typed object from a raw object.\n * @param data Raw object.\n * @return An object representing the linked visual console properties.\n * @throws Will throw a TypeError if the status calculation properties are invalid.\n */\nexport function linkedVCPropsDecoder(\n data: UnknownObject\n): LinkedVisualConsoleProps | never {\n // Object destructuring: http://es6-features.org/#ObjectMatchingShorthandNotation\n const {\n metaconsoleId,\n linkedLayoutId: id,\n linkedLayoutAgentId: agentId\n } = data;\n\n let linkedLayoutStatusProps: LinkedVisualConsolePropsStatus = {\n linkedLayoutStatusType: \"default\"\n };\n switch (data.linkedLayoutStatusType) {\n case \"weight\": {\n const weight = parseIntOr(data.linkedLayoutStatusTypeWeight, null);\n if (weight == null)\n throw new TypeError(\"invalid status calculation properties.\");\n\n if (data.linkedLayoutStatusTypeWeight)\n linkedLayoutStatusProps = {\n linkedLayoutStatusType: \"weight\",\n linkedLayoutStatusTypeWeight: weight\n };\n break;\n }\n case \"service\": {\n const warningThreshold = parseIntOr(\n data.linkedLayoutStatusTypeWarningThreshold,\n null\n );\n const criticalThreshold = parseIntOr(\n data.linkedLayoutStatusTypeCriticalThreshold,\n null\n );\n if (warningThreshold == null || criticalThreshold == null) {\n throw new TypeError(\"invalid status calculation properties.\");\n }\n\n linkedLayoutStatusProps = {\n linkedLayoutStatusType: \"service\",\n linkedLayoutStatusTypeWarningThreshold: warningThreshold,\n linkedLayoutStatusTypeCriticalThreshold: criticalThreshold\n };\n break;\n }\n }\n\n const linkedLayoutBaseProps = {\n linkedLayoutId: parseIntOr(id, null),\n linkedLayoutAgentId: parseIntOr(agentId, null),\n ...linkedLayoutStatusProps // Object spread: http://es6-features.org/#SpreadOperator\n };\n\n return metaconsoleId != null\n ? {\n metaconsoleId,\n ...linkedLayoutBaseProps // Object spread: http://es6-features.org/#SpreadOperator\n }\n : linkedLayoutBaseProps;\n}\n\n/**\n * To get a CSS rule with the most used prefixes.\n * @param ruleName Name of the CSS rule.\n * @param ruleValue Value of the CSS rule.\n * @return An array of rules with the prefixes applied.\n */\nexport function prefixedCssRules(\n ruleName: string,\n ruleValue: string\n): string[] {\n const rule = `${ruleName}: ${ruleValue};`;\n return [\n `-webkit-${rule}`,\n `-moz-${rule}`,\n `-ms-${rule}`,\n `-o-${rule}`,\n `${rule}`\n ];\n}\n\n/**\n * Decode a base64 string.\n * @param input Data encoded using base64.\n * @return Decoded data.\n */\nexport function decodeBase64(input: string): string {\n return decodeURIComponent(escape(window.atob(input)));\n}\n\n/**\n * Generate a date representation with the format 'd/m/Y'.\n * @param initialDate Date to be used instead of a generated one.\n * @param locale Locale to use if localization is required and available.\n * @example 24/02/2020.\n * @return Date representation.\n */\nexport function humanDate(date: Date, locale: string | null = null): string {\n if (locale && Intl && Intl.DateTimeFormat) {\n // Format using the user locale.\n const options: Intl.DateTimeFormatOptions = {\n day: \"2-digit\",\n month: \"2-digit\",\n year: \"numeric\"\n };\n return Intl.DateTimeFormat(locale, options).format(date);\n } else {\n // Use getDate, getDay returns the week day.\n const day = leftPad(date.getDate(), 2, 0);\n // The getMonth function returns the month starting by 0.\n const month = leftPad(date.getMonth() + 1, 2, 0);\n const year = leftPad(date.getFullYear(), 4, 0);\n\n // Format: 'd/m/Y'.\n return `${day}/${month}/${year}`;\n }\n}\n\n/**\n * Generate a time representation with the format 'hh:mm:ss'.\n * @param initialDate Date to be used instead of a generated one.\n * @example 01:34:09.\n * @return Time representation.\n */\nexport function humanTime(date: Date): string {\n const hours = leftPad(date.getHours(), 2, 0);\n const minutes = leftPad(date.getMinutes(), 2, 0);\n const seconds = leftPad(date.getSeconds(), 2, 0);\n\n return `${hours}:${minutes}:${seconds}`;\n}\n\ninterface Macro {\n macro: string | RegExp;\n value: string;\n}\n/**\n * Replace the macros of a text.\n * @param macros List of macros and their replacements.\n * @param text Text in which we need to replace the macros.\n */\nexport function replaceMacros(macros: Macro[], text: string): string {\n return macros.reduce(\n (acc, { macro, value }) => acc.replace(macro, value),\n text\n );\n}\n","import { Position, Size, UnknownObject, WithModuleProps } from \"./types\";\nimport {\n sizePropsDecoder,\n positionPropsDecoder,\n parseIntOr,\n parseBoolean,\n notEmptyStringOr,\n replaceMacros,\n humanDate,\n humanTime\n} from \"./lib\";\nimport TypedEvent, { Listener, Disposable } from \"./TypedEvent\";\n\n// Enum: https://www.typescriptlang.org/docs/handbook/enums.html.\nexport const enum ItemType {\n STATIC_GRAPH = 0,\n MODULE_GRAPH = 1,\n SIMPLE_VALUE = 2,\n PERCENTILE_BAR = 3,\n LABEL = 4,\n ICON = 5,\n SIMPLE_VALUE_MAX = 6,\n SIMPLE_VALUE_MIN = 7,\n SIMPLE_VALUE_AVG = 8,\n PERCENTILE_BUBBLE = 9,\n SERVICE = 10,\n GROUP_ITEM = 11,\n BOX_ITEM = 12,\n LINE_ITEM = 13,\n AUTO_SLA_GRAPH = 14,\n CIRCULAR_PROGRESS_BAR = 15,\n CIRCULAR_INTERIOR_PROGRESS_BAR = 16,\n DONUT_GRAPH = 17,\n BARS_GRAPH = 18,\n CLOCK = 19,\n COLOR_CLOUD = 20\n}\n\n// Base item properties. This interface should be extended by the item implementations.\nexport interface ItemProps extends Position, Size {\n readonly id: number;\n readonly type: ItemType;\n label: string | null;\n labelPosition: \"up\" | \"right\" | \"down\" | \"left\";\n isLinkEnabled: boolean;\n link: string | null;\n isOnTop: boolean;\n parentId: number | null;\n aclGroupId: number | null;\n}\n\n// FIXME: Fix type compatibility.\nexport interface ItemClickEvent {\n // data: Props;\n data: UnknownObject;\n nativeEvent: Event;\n}\n\n// FIXME: Fix type compatibility.\nexport interface ItemRemoveEvent {\n // data: Props;\n data: UnknownObject;\n}\n\n/**\n * Extract a valid enum value from a raw label positi9on value.\n * @param labelPosition Raw value.\n */\nconst parseLabelPosition = (\n labelPosition: any // eslint-disable-line @typescript-eslint/no-explicit-any\n): ItemProps[\"labelPosition\"] => {\n switch (labelPosition) {\n case \"up\":\n case \"right\":\n case \"down\":\n case \"left\":\n return labelPosition;\n default:\n return \"down\";\n }\n};\n\n/**\n * Build a valid typed object from a raw object.\n * This will allow us to ensure the type safety.\n *\n * @param data Raw object.\n * @return An object representing the item props.\n * @throws Will throw a TypeError if some property\n * is missing from the raw object or have an invalid type.\n */\nexport function itemBasePropsDecoder(data: UnknownObject): ItemProps | never {\n if (data.id == null || isNaN(parseInt(data.id))) {\n throw new TypeError(\"invalid id.\");\n }\n if (data.type == null || isNaN(parseInt(data.type))) {\n throw new TypeError(\"invalid type.\");\n }\n\n return {\n id: parseInt(data.id),\n type: parseInt(data.type),\n label: notEmptyStringOr(data.label, null),\n labelPosition: parseLabelPosition(data.labelPosition),\n isLinkEnabled: parseBoolean(data.isLinkEnabled),\n link: notEmptyStringOr(data.link, null),\n isOnTop: parseBoolean(data.isOnTop),\n parentId: parseIntOr(data.parentId, null),\n aclGroupId: parseIntOr(data.aclGroupId, null),\n ...sizePropsDecoder(data), // Object spread. It will merge the properties of the two objects.\n ...positionPropsDecoder(data) // Object spread. It will merge the properties of the two objects.\n };\n}\n\n/**\n * Base class of the visual console items. Should be extended to use its capabilities.\n */\nabstract class VisualConsoleItem {\n // Properties of the item.\n private itemProps: Props;\n // Reference to the DOM element which will contain the item.\n public elementRef: HTMLElement;\n public readonly labelElementRef: HTMLElement;\n // Reference to the DOM element which will contain the view of the item which extends this class.\n protected readonly childElementRef: HTMLElement;\n // Event manager for click events.\n private readonly clickEventManager = new TypedEvent>();\n // Event manager for remove events.\n private readonly removeEventManager = new TypedEvent<\n ItemRemoveEvent\n >();\n // List of references to clean the event listeners.\n private readonly disposables: Disposable[] = [];\n\n /**\n * To create a new element which will be inside the item box.\n * @return Item.\n */\n protected abstract createDomElement(): HTMLElement;\n\n public constructor(props: Props) {\n this.itemProps = props;\n\n /*\n * Get a HTMLElement which represents the container box\n * of the Visual Console item. This element will manage\n * all the common things like click events, show a border\n * when hovered, etc.\n */\n this.elementRef = this.createContainerDomElement();\n this.labelElementRef = this.createLabelDomElement();\n\n /*\n * Get a HTMLElement which represents the custom view\n * of the Visual Console item. This element will be\n * different depending on the item implementation.\n */\n this.childElementRef = this.createDomElement();\n\n // Insert the elements into the container.\n this.elementRef.append(this.childElementRef, this.labelElementRef);\n\n // Resize element.\n this.resizeElement(props.width, props.height);\n // Set label position.\n this.changeLabelPosition(props.labelPosition);\n }\n\n /**\n * To create a new box for the visual console item.\n * @return Item box.\n */\n private createContainerDomElement(): HTMLElement {\n let box;\n if (this.props.isLinkEnabled) {\n box = document.createElement(\"a\");\n box as HTMLAnchorElement;\n if (this.props.link) box.href = this.props.link;\n } else {\n box = document.createElement(\"div\");\n box as HTMLDivElement;\n }\n\n box.className = \"visual-console-item\";\n box.style.zIndex = this.props.isOnTop ? \"2\" : \"1\";\n box.style.left = `${this.props.x}px`;\n box.style.top = `${this.props.y}px`;\n box.onclick = e =>\n this.clickEventManager.emit({ data: this.props, nativeEvent: e });\n\n return box;\n }\n\n /**\n * To create a new label for the visual console item.\n * @return Item label.\n */\n protected createLabelDomElement(): HTMLElement {\n const element = document.createElement(\"div\");\n element.className = \"visual-console-item-label\";\n // Add the label if it exists.\n const label = this.getLabelWithMacrosReplaced();\n if (label.length > 0) {\n // Ugly table we need to use to replicate the legacy style.\n const table = document.createElement(\"table\");\n const row = document.createElement(\"tr\");\n const emptyRow1 = document.createElement(\"tr\");\n const emptyRow2 = document.createElement(\"tr\");\n const cell = document.createElement(\"td\");\n\n cell.innerHTML = label;\n row.append(cell);\n table.append(emptyRow1, row, emptyRow2);\n table.style.textAlign = \"center\";\n\n // Change the table size depending on its position.\n switch (this.props.labelPosition) {\n case \"up\":\n case \"down\":\n if (this.props.width > 0) {\n table.style.width = `${this.props.width}px`;\n table.style.height = null;\n }\n break;\n case \"left\":\n case \"right\":\n if (this.props.height > 0) {\n table.style.width = null;\n table.style.height = `${this.props.height}px`;\n }\n break;\n }\n\n // element.innerHTML = this.props.label;\n element.append(table);\n }\n\n return element;\n }\n\n /**\n * Return the label stored into the props with some macros replaced.\n */\n protected getLabelWithMacrosReplaced(): string {\n // We assert that the props may have some needed properties.\n const props = this.props as Partial;\n\n return replaceMacros(\n [\n {\n macro: \"_date_\",\n value: humanDate(new Date())\n },\n {\n macro: \"_time_\",\n value: humanTime(new Date())\n },\n {\n macro: \"_agent_\",\n value: props.agentAlias != null ? props.agentAlias : \"\"\n },\n {\n macro: \"_agentdescription_\",\n value: props.agentDescription != null ? props.agentDescription : \"\"\n },\n {\n macro: \"_address_\",\n value: props.agentAddress != null ? props.agentAddress : \"\"\n },\n {\n macro: \"_module_\",\n value: props.moduleName != null ? props.moduleName : \"\"\n },\n {\n macro: \"_moduledescription_\",\n value: props.moduleDescription != null ? props.moduleDescription : \"\"\n }\n ],\n this.props.label || \"\"\n );\n }\n\n /**\n * To update the content element.\n * @return Item.\n */\n protected updateDomElement(element: HTMLElement): void {\n element.innerHTML = this.createDomElement().innerHTML;\n }\n\n /**\n * Public accessor of the `props` property.\n * @return Properties.\n */\n public get props(): Props {\n return { ...this.itemProps }; // Return a copy.\n }\n\n /**\n * Public setter of the `props` property.\n * If the new props are different enough than the\n * stored props, a render would be fired.\n * @param newProps\n */\n public set props(newProps: Props) {\n const prevProps = this.props;\n // Update the internal props.\n this.itemProps = newProps;\n\n // From this point, things which rely on this.props can access to the changes.\n\n // Check if we should re-render.\n if (this.shouldBeUpdated(prevProps, newProps)) this.render(prevProps);\n }\n\n /**\n * To compare the previous and the new props and returns a boolean value\n * in case the difference is meaningfull enough to perform DOM changes.\n *\n * Here, the only comparision is done by reference.\n *\n * Override this function to perform a different comparision depending on the item needs.\n *\n * @param prevProps\n * @param newProps\n * @return Whether the difference is meaningful enough to perform DOM changes or not.\n */\n protected shouldBeUpdated(prevProps: Props, newProps: Props): boolean {\n return prevProps !== newProps;\n }\n\n /**\n * To recreate or update the HTMLElement which represents the item into the DOM.\n * @param prevProps If exists it will be used to only perform DOM updates instead of a full replace.\n */\n public render(prevProps: Props | null = null): void {\n this.updateDomElement(this.childElementRef);\n\n // Move box.\n if (!prevProps || this.positionChanged(prevProps, this.props)) {\n this.moveElement(this.props.x, this.props.y);\n }\n // Resize box.\n if (!prevProps || this.sizeChanged(prevProps, this.props)) {\n this.resizeElement(this.props.width, this.props.height);\n }\n // Change label.\n const oldLabelHtml = this.labelElementRef.innerHTML;\n const newLabelHtml = this.createLabelDomElement().innerHTML;\n if (oldLabelHtml !== newLabelHtml) {\n this.labelElementRef.innerHTML = newLabelHtml;\n }\n // Change label position.\n if (!prevProps || prevProps.labelPosition !== this.props.labelPosition) {\n this.changeLabelPosition(this.props.labelPosition);\n }\n // Change link.\n if (\n prevProps &&\n (prevProps.isLinkEnabled !== this.props.isLinkEnabled ||\n (this.props.isLinkEnabled && prevProps.link !== this.props.link))\n ) {\n const container = this.createContainerDomElement();\n // Add the children of the old element.\n container.innerHTML = this.elementRef.innerHTML;\n // Copy the attributes.\n const attrs = this.elementRef.attributes;\n for (let i = 0; i < attrs.length; i++) {\n if (attrs[i].nodeName !== \"id\") {\n container.setAttributeNode(attrs[i]);\n }\n }\n // Replace the reference.\n if (this.elementRef.parentNode !== null) {\n this.elementRef.parentNode.replaceChild(container, this.elementRef);\n }\n\n // Changed the reference to the main element. It's ugly, but needed.\n this.elementRef = container;\n }\n }\n\n /**\n * To remove the event listeners and the elements from the DOM.\n */\n public remove(): void {\n // Call the remove event.\n this.removeEventManager.emit({ data: this.props });\n // Event listeners.\n this.disposables.forEach(disposable => {\n try {\n disposable.dispose();\n } catch (ignored) {} // eslint-disable-line no-empty\n });\n // VisualConsoleItem DOM element.\n this.elementRef.remove();\n }\n\n /**\n * Compare the previous and the new position and return\n * a boolean value in case the position changed.\n * @param prevPosition\n * @param newPosition\n * @return Whether the position changed or not.\n */\n protected positionChanged(\n prevPosition: Position,\n newPosition: Position\n ): boolean {\n return prevPosition.x !== newPosition.x || prevPosition.y !== newPosition.y;\n }\n\n /**\n * Move the label around the item content.\n * @param position Label position.\n */\n protected changeLabelPosition(position: Props[\"labelPosition\"]): void {\n switch (position) {\n case \"up\":\n this.elementRef.style.flexDirection = \"column-reverse\";\n break;\n case \"left\":\n this.elementRef.style.flexDirection = \"row-reverse\";\n break;\n case \"right\":\n this.elementRef.style.flexDirection = \"row\";\n break;\n case \"down\":\n default:\n this.elementRef.style.flexDirection = \"column\";\n break;\n }\n\n // Ugly table to show the label as its legacy counterpart.\n const tables = this.labelElementRef.getElementsByTagName(\"table\");\n const table = tables.length > 0 ? tables.item(0) : null;\n // Change the table size depending on its position.\n if (table) {\n switch (this.props.labelPosition) {\n case \"up\":\n case \"down\":\n if (this.props.width > 0) {\n table.style.width = `${this.props.width}px`;\n table.style.height = null;\n }\n break;\n case \"left\":\n case \"right\":\n if (this.props.height > 0) {\n table.style.width = null;\n table.style.height = `${this.props.height}px`;\n }\n break;\n }\n }\n }\n\n /**\n * Move the DOM container.\n * @param x Horizontal axis position.\n * @param y Vertical axis position.\n */\n protected moveElement(x: number, y: number): void {\n this.elementRef.style.left = `${x}px`;\n this.elementRef.style.top = `${y}px`;\n }\n\n /**\n * Update the position into the properties and move the DOM container.\n * @param x Horizontal axis position.\n * @param y Vertical axis position.\n */\n public move(x: number, y: number): void {\n this.moveElement(x, y);\n this.itemProps = {\n ...this.props, // Object spread: http://es6-features.org/#SpreadOperator\n x,\n y\n };\n }\n\n /**\n * Compare the previous and the new size and return\n * a boolean value in case the size changed.\n * @param prevSize\n * @param newSize\n * @return Whether the size changed or not.\n */\n protected sizeChanged(prevSize: Size, newSize: Size): boolean {\n return (\n prevSize.width !== newSize.width || prevSize.height !== newSize.height\n );\n }\n\n /**\n * Resize the DOM content container.\n * @param width\n * @param height\n */\n protected resizeElement(width: number, height: number): void {\n // The most valuable size is the content size.\n this.childElementRef.style.width = width > 0 ? `${width}px` : null;\n this.childElementRef.style.height = height > 0 ? `${height}px` : null;\n }\n\n /**\n * Update the size into the properties and resize the DOM container.\n * @param width\n * @param height\n */\n public resize(width: number, height: number): void {\n this.resizeElement(width, height);\n this.itemProps = {\n ...this.props, // Object spread: http://es6-features.org/#SpreadOperator\n width,\n height\n };\n }\n\n /**\n * To add an event handler to the click of the linked visual console elements.\n * @param listener Function which is going to be executed when a linked console is clicked.\n */\n public onClick(listener: Listener>): Disposable {\n /*\n * The '.on' function returns a function which will clean the event\n * listener when executed. We store all the 'dispose' functions to\n * call them when the item should be cleared.\n */\n const disposable = this.clickEventManager.on(listener);\n this.disposables.push(disposable);\n\n return disposable;\n }\n\n /**\n * To add an event handler to the removal of the item.\n * @param listener Function which is going to be executed when a item is removed.\n */\n public onRemove(listener: Listener>): Disposable {\n /*\n * The '.on' function returns a function which will clean the event\n * listener when executed. We store all the 'dispose' functions to\n * call them when the item should be cleared.\n */\n const disposable = this.removeEventManager.on(listener);\n this.disposables.push(disposable);\n\n return disposable;\n }\n}\n\nexport default VisualConsoleItem;\n","export interface Listener {\n (event: T): void;\n}\n\nexport interface Disposable {\n dispose: () => void;\n}\n\n/** passes through events as they happen. You will not get events from before you start listening */\nexport default class TypedEvent {\n private listeners: Listener[] = [];\n private listenersOncer: Listener[] = [];\n\n public on = (listener: Listener): Disposable => {\n this.listeners.push(listener);\n return {\n dispose: () => this.off(listener)\n };\n };\n\n public once = (listener: Listener): void => {\n this.listenersOncer.push(listener);\n };\n\n public off = (listener: Listener): void => {\n const callbackIndex = this.listeners.indexOf(listener);\n if (callbackIndex > -1) this.listeners.splice(callbackIndex, 1);\n };\n\n public emit = (event: T): void => {\n /** Update any general listeners */\n this.listeners.forEach(listener => listener(event));\n\n /** Clear the `once` queue */\n this.listenersOncer.forEach(listener => listener(event));\n this.listenersOncer = [];\n };\n\n public pipe = (te: TypedEvent): Disposable => this.on(e => te.emit(e));\n}\n","import { UnknownObject, WithModuleProps } from \"../types\";\nimport {\n modulePropsDecoder,\n parseIntOr,\n decodeBase64,\n stringIsEmpty\n} from \"../lib\";\nimport Item, { ItemType, ItemProps, itemBasePropsDecoder } from \"../Item\";\n\nexport type EventsHistoryProps = {\n type: ItemType.AUTO_SLA_GRAPH;\n maxTime: number | null;\n html: string;\n} & ItemProps &\n WithModuleProps;\n\n/**\n * Build a valid typed object from a raw object.\n * This will allow us to ensure the type safety.\n *\n * @param data Raw object.\n * @return An object representing the events history props.\n * @throws Will throw a TypeError if some property\n * is missing from the raw object or have an invalid type.\n */\nexport function eventsHistoryPropsDecoder(\n data: UnknownObject\n): EventsHistoryProps | never {\n if (stringIsEmpty(data.html) && stringIsEmpty(data.encodedHtml)) {\n throw new TypeError(\"missing html content.\");\n }\n\n return {\n ...itemBasePropsDecoder(data), // Object spread. It will merge the properties of the two objects.\n type: ItemType.AUTO_SLA_GRAPH,\n maxTime: parseIntOr(data.maxTime, null),\n html: !stringIsEmpty(data.html)\n ? data.html\n : decodeBase64(data.encodedHtml),\n ...modulePropsDecoder(data) // Object spread. It will merge the properties of the two objects.\n };\n}\n\nexport default class EventsHistory extends Item {\n protected createDomElement(): HTMLElement {\n const element = document.createElement(\"div\");\n element.className = \"events-history\";\n element.innerHTML = this.props.html;\n\n // Hack to execute the JS after the HTML is added to the DOM.\n const scripts = element.getElementsByTagName(\"script\");\n for (let i = 0; i < scripts.length; i++) {\n if (scripts[i].src.length === 0) {\n setTimeout(() => {\n try {\n eval(scripts[i].innerHTML.trim());\n } catch (ignored) {} // eslint-disable-line no-empty\n }, 0);\n }\n }\n\n return element;\n }\n\n protected updateDomElement(element: HTMLElement): void {\n element.innerHTML = this.props.html;\n\n // Hack to execute the JS after the HTML is added to the DOM.\n const aux = document.createElement(\"div\");\n aux.innerHTML = this.props.html;\n const scripts = aux.getElementsByTagName(\"script\");\n for (let i = 0; i < scripts.length; i++) {\n if (scripts[i].src.length === 0) {\n eval(scripts[i].innerHTML.trim());\n }\n }\n }\n}\n","import {\n LinkedVisualConsoleProps,\n UnknownObject,\n WithModuleProps\n} from \"../types\";\nimport {\n linkedVCPropsDecoder,\n modulePropsDecoder,\n decodeBase64,\n stringIsEmpty\n} from \"../lib\";\nimport Item, { ItemType, ItemProps, itemBasePropsDecoder } from \"../Item\";\n\nexport type DonutGraphProps = {\n type: ItemType.DONUT_GRAPH;\n html: string;\n} & ItemProps &\n WithModuleProps &\n LinkedVisualConsoleProps;\n\n/**\n * Build a valid typed object from a raw object.\n * This will allow us to ensure the type safety.\n *\n * @param data Raw object.\n * @return An object representing the donut graph props.\n * @throws Will throw a TypeError if some property\n * is missing from the raw object or have an invalid type.\n */\nexport function donutGraphPropsDecoder(\n data: UnknownObject\n): DonutGraphProps | never {\n if (stringIsEmpty(data.html) && stringIsEmpty(data.encodedHtml)) {\n throw new TypeError(\"missing html content.\");\n }\n\n return {\n ...itemBasePropsDecoder(data), // Object spread. It will merge the properties of the two objects.\n type: ItemType.DONUT_GRAPH,\n html: !stringIsEmpty(data.html)\n ? data.html\n : decodeBase64(data.encodedHtml),\n ...modulePropsDecoder(data), // Object spread. It will merge the properties of the two objects.\n ...linkedVCPropsDecoder(data) // Object spread. It will merge the properties of the two objects.\n };\n}\n\nexport default class DonutGraph extends Item {\n protected createDomElement(): HTMLElement {\n const element = document.createElement(\"div\");\n element.className = \"donut-graph\";\n element.innerHTML = this.props.html;\n\n // Hack to execute the JS after the HTML is added to the DOM.\n const scripts = element.getElementsByTagName(\"script\");\n for (let i = 0; i < scripts.length; i++) {\n setTimeout(() => {\n if (scripts[i].src.length === 0) eval(scripts[i].innerHTML.trim());\n }, 0);\n }\n\n return element;\n }\n\n protected updateDomElement(element: HTMLElement): void {\n element.innerHTML = this.props.html;\n\n // Hack to execute the JS after the HTML is added to the DOM.\n const aux = document.createElement(\"div\");\n aux.innerHTML = this.props.html;\n const scripts = aux.getElementsByTagName(\"script\");\n for (let i = 0; i < scripts.length; i++) {\n if (scripts[i].src.length === 0) {\n eval(scripts[i].innerHTML.trim());\n }\n }\n }\n}\n","import { UnknownObject, WithModuleProps } from \"../types\";\nimport { modulePropsDecoder, decodeBase64, stringIsEmpty } from \"../lib\";\nimport Item, { ItemType, ItemProps, itemBasePropsDecoder } from \"../Item\";\n\nexport type BarsGraphProps = {\n type: ItemType.BARS_GRAPH;\n html: string;\n} & ItemProps &\n WithModuleProps;\n\n/**\n * Build a valid typed object from a raw object.\n * This will allow us to ensure the type safety.\n *\n * @param data Raw object.\n * @return An object representing the bars graph props.\n * @throws Will throw a TypeError if some property\n * is missing from the raw object or have an invalid type.\n */\nexport function barsGraphPropsDecoder(\n data: UnknownObject\n): BarsGraphProps | never {\n if (stringIsEmpty(data.html) && stringIsEmpty(data.encodedHtml)) {\n throw new TypeError(\"missing html content.\");\n }\n\n return {\n ...itemBasePropsDecoder(data), // Object spread. It will merge the properties of the two objects.\n type: ItemType.BARS_GRAPH,\n html: !stringIsEmpty(data.html)\n ? data.html\n : decodeBase64(data.encodedHtml),\n ...modulePropsDecoder(data) // Object spread. It will merge the properties of the two objects.\n };\n}\n\nexport default class BarsGraph extends Item {\n protected createDomElement(): HTMLElement {\n const element = document.createElement(\"div\");\n element.className = \"bars-graph\";\n element.innerHTML = this.props.html;\n\n // Hack to execute the JS after the HTML is added to the DOM.\n const scripts = element.getElementsByTagName(\"script\");\n for (let i = 0; i < scripts.length; i++) {\n setTimeout(() => {\n if (scripts[i].src.length === 0) eval(scripts[i].innerHTML.trim());\n }, 0);\n }\n\n return element;\n }\n\n protected updateDomElement(element: HTMLElement): void {\n element.innerHTML = this.props.html;\n\n // Hack to execute the JS after the HTML is added to the DOM.\n const aux = document.createElement(\"div\");\n aux.innerHTML = this.props.html;\n const scripts = aux.getElementsByTagName(\"script\");\n for (let i = 0; i < scripts.length; i++) {\n if (scripts[i].src.length === 0) {\n eval(scripts[i].innerHTML.trim());\n }\n }\n }\n}\n","import {\n LinkedVisualConsoleProps,\n UnknownObject,\n WithModuleProps\n} from \"../types\";\nimport {\n linkedVCPropsDecoder,\n modulePropsDecoder,\n decodeBase64,\n stringIsEmpty\n} from \"../lib\";\nimport Item, { ItemType, ItemProps, itemBasePropsDecoder } from \"../Item\";\n\nexport type ModuleGraphProps = {\n type: ItemType.MODULE_GRAPH;\n html: string;\n} & ItemProps &\n WithModuleProps &\n LinkedVisualConsoleProps;\n\n/**\n * Build a valid typed object from a raw object.\n * This will allow us to ensure the type safety.\n *\n * @param data Raw object.\n * @return An object representing the module graph props.\n * @throws Will throw a TypeError if some property\n * is missing from the raw object or have an invalid type.\n */\nexport function moduleGraphPropsDecoder(\n data: UnknownObject\n): ModuleGraphProps | never {\n if (stringIsEmpty(data.html) && stringIsEmpty(data.encodedHtml)) {\n throw new TypeError(\"missing html content.\");\n }\n\n return {\n ...itemBasePropsDecoder(data), // Object spread. It will merge the properties of the two objects.\n type: ItemType.MODULE_GRAPH,\n html: !stringIsEmpty(data.html)\n ? data.html\n : decodeBase64(data.encodedHtml),\n ...modulePropsDecoder(data), // Object spread. It will merge the properties of the two objects.\n ...linkedVCPropsDecoder(data) // Object spread. It will merge the properties of the two objects.\n };\n}\n\nexport default class ModuleGraph extends Item {\n /**\n * @override Item.resizeElement.\n * Resize the DOM content container.\n * We need to override the resize function cause this item's height\n * is larger than the configured and the graph is over the label.\n * @param width\n * @param height\n */\n protected resizeElement(width: number): void {\n super.resizeElement(width, 0);\n }\n\n protected createDomElement(): HTMLElement {\n const element = document.createElement(\"div\");\n element.className = \"module-graph\";\n element.innerHTML = this.props.html;\n\n // Remove the overview graph.\n const legendP = element.getElementsByTagName(\"p\");\n for (let i = 0; i < legendP.length; i++) {\n legendP[i].style.margin = \"0px\";\n }\n\n // Remove the overview graph.\n const overviewGraphs = element.getElementsByClassName(\"overview_graph\");\n for (let i = 0; i < overviewGraphs.length; i++) {\n overviewGraphs[i].remove();\n }\n\n // Hack to execute the JS after the HTML is added to the DOM.\n const scripts = element.getElementsByTagName(\"script\");\n for (let i = 0; i < scripts.length; i++) {\n if (scripts[i].src.length === 0) {\n setTimeout(() => {\n try {\n eval(scripts[i].innerHTML.trim());\n } catch (ignored) {} // eslint-disable-line no-empty\n }, 0);\n }\n }\n\n return element;\n }\n\n protected updateDomElement(element: HTMLElement): void {\n element.innerHTML = this.props.html;\n\n // Remove the overview graph.\n const legendP = element.getElementsByTagName(\"p\");\n for (let i = 0; i < legendP.length; i++) {\n legendP[i].style.margin = \"0px\";\n }\n\n // Remove the overview graph.\n const overviewGraphs = element.getElementsByClassName(\"overview_graph\");\n for (let i = 0; i < overviewGraphs.length; i++) {\n overviewGraphs[i].remove();\n }\n\n // Hack to execute the JS after the HTML is added to the DOM.\n const aux = document.createElement(\"div\");\n aux.innerHTML = this.props.html;\n const scripts = aux.getElementsByTagName(\"script\");\n for (let i = 0; i < scripts.length; i++) {\n if (scripts[i].src.length === 0) {\n eval(scripts[i].innerHTML.trim());\n }\n }\n }\n}\n","import {\n WithModuleProps,\n LinkedVisualConsoleProps,\n UnknownObject\n} from \"../types\";\n\nimport {\n modulePropsDecoder,\n linkedVCPropsDecoder,\n notEmptyStringOr\n} from \"../lib\";\nimport Item, { ItemType, ItemProps, itemBasePropsDecoder } from \"../Item\";\n\nexport type StaticGraphProps = {\n type: ItemType.STATIC_GRAPH;\n imageSrc: string; // URL?\n showLastValueTooltip: \"default\" | \"enabled\" | \"disabled\";\n statusImageSrc: string | null; // URL?\n lastValue: string | null;\n} & ItemProps &\n (WithModuleProps | LinkedVisualConsoleProps);\n\n/**\n * Extract a valid enum value from a raw unknown value.\n * @param showLastValueTooltip Raw value.\n */\nconst parseShowLastValueTooltip = (\n showLastValueTooltip: any // eslint-disable-line @typescript-eslint/no-explicit-any\n): StaticGraphProps[\"showLastValueTooltip\"] => {\n switch (showLastValueTooltip) {\n case \"default\":\n case \"enabled\":\n case \"disabled\":\n return showLastValueTooltip;\n default:\n return \"default\";\n }\n};\n\n/**\n * Build a valid typed object from a raw object.\n * This will allow us to ensure the type safety.\n *\n * @param data Raw object.\n * @return An object representing the static graph props.\n * @throws Will throw a TypeError if some property\n * is missing from the raw object or have an invalid type.\n */\nexport function staticGraphPropsDecoder(\n data: UnknownObject\n): StaticGraphProps | never {\n if (typeof data.imageSrc !== \"string\" || data.imageSrc.length === 0) {\n throw new TypeError(\"invalid image src.\");\n }\n\n return {\n ...itemBasePropsDecoder(data), // Object spread. It will merge the properties of the two objects.\n type: ItemType.STATIC_GRAPH,\n imageSrc: data.imageSrc,\n showLastValueTooltip: parseShowLastValueTooltip(data.showLastValueTooltip),\n statusImageSrc: notEmptyStringOr(data.statusImageSrc, null),\n lastValue: notEmptyStringOr(data.lastValue, null),\n ...modulePropsDecoder(data), // Object spread. It will merge the properties of the two objects.\n ...linkedVCPropsDecoder(data) // Object spread. It will merge the properties of the two objects.\n };\n}\n\nexport default class StaticGraph extends Item {\n protected createDomElement(): HTMLElement {\n const imgSrc = this.props.statusImageSrc || this.props.imageSrc;\n const element = document.createElement(\"div\");\n element.className = \"static-graph\";\n element.style.background = `url(${imgSrc}) no-repeat`;\n element.style.backgroundSize = \"contain\";\n element.style.backgroundPosition = \"center\";\n\n // Show last value in a tooltip.\n if (\n this.props.lastValue !== null &&\n this.props.showLastValueTooltip !== \"disabled\"\n ) {\n element.className = \"static-graph image forced_title\";\n element.setAttribute(\"data-use_title_for_force_title\", \"1\");\n element.setAttribute(\"data-title\", this.props.lastValue);\n }\n\n return element;\n }\n}\n","import { LinkedVisualConsoleProps, UnknownObject } from \"../types\";\nimport { linkedVCPropsDecoder } from \"../lib\";\nimport Item, { ItemType, ItemProps, itemBasePropsDecoder } from \"../Item\";\n\nexport type IconProps = {\n type: ItemType.ICON;\n imageSrc: string; // URL?\n} & ItemProps &\n LinkedVisualConsoleProps;\n\n/**\n * Build a valid typed object from a raw object.\n * This will allow us to ensure the type safety.\n *\n * @param data Raw object.\n * @return An object representing the icon props.\n * @throws Will throw a TypeError if some property\n * is missing from the raw object or have an invalid type.\n */\nexport function iconPropsDecoder(data: UnknownObject): IconProps | never {\n if (typeof data.imageSrc !== \"string\" || data.imageSrc.length === 0) {\n throw new TypeError(\"invalid image src.\");\n }\n\n return {\n ...itemBasePropsDecoder(data), // Object spread. It will merge the properties of the two objects.\n type: ItemType.ICON,\n imageSrc: data.imageSrc,\n ...linkedVCPropsDecoder(data) // Object spread. It will merge the properties of the two objects.\n };\n}\n\nexport default class Icon extends Item {\n protected createDomElement(): HTMLElement {\n const element = document.createElement(\"div\");\n element.className = \"icon\";\n element.style.background = `url(${this.props.imageSrc}) no-repeat`;\n element.style.backgroundSize = \"contain\";\n element.style.backgroundPosition = \"center\";\n\n return element;\n }\n}\n","import {\n WithModuleProps,\n LinkedVisualConsoleProps,\n UnknownObject\n} from \"../types\";\nimport { modulePropsDecoder, linkedVCPropsDecoder } from \"../lib\";\nimport Item, { itemBasePropsDecoder, ItemType, ItemProps } from \"../Item\";\n\nexport type ColorCloudProps = {\n type: ItemType.COLOR_CLOUD;\n color: string;\n // TODO: Add the rest of the color cloud values?\n} & ItemProps &\n WithModuleProps &\n LinkedVisualConsoleProps;\n\n/**\n * Build a valid typed object from a raw object.\n * This will allow us to ensure the type safety.\n *\n * @param data Raw object.\n * @return An object representing the static graph props.\n * @throws Will throw a TypeError if some property\n * is missing from the raw object or have an invalid type.\n */\nexport function colorCloudPropsDecoder(\n data: UnknownObject\n): ColorCloudProps | never {\n // TODO: Validate the color.\n if (typeof data.color !== \"string\" || data.color.length === 0) {\n throw new TypeError(\"invalid color.\");\n }\n\n return {\n ...itemBasePropsDecoder(data), // Object spread. It will merge the properties of the two objects.\n type: ItemType.COLOR_CLOUD,\n color: data.color,\n ...modulePropsDecoder(data), // Object spread. It will merge the properties of the two objects.\n ...linkedVCPropsDecoder(data) // Object spread. It will merge the properties of the two objects.\n };\n}\n\nconst svgNS = \"http://www.w3.org/2000/svg\";\n\nexport default class ColorCloud extends Item {\n protected createDomElement(): HTMLElement {\n const container: HTMLDivElement = document.createElement(\"div\");\n container.className = \"color-cloud\";\n\n // Add the SVG.\n container.append(this.createSvgElement());\n\n return container;\n }\n\n public createSvgElement(): SVGSVGElement {\n const gradientId = `grad_${this.props.id}`;\n // SVG container.\n const svg = document.createElementNS(svgNS, \"svg\");\n // Auto resize SVG using the view box magic: https://css-tricks.com/scale-svg/\n svg.setAttribute(\"viewBox\", \"0 0 100 100\");\n\n // Defs.\n const defs = document.createElementNS(svgNS, \"defs\");\n // Radial gradient.\n const radialGradient = document.createElementNS(svgNS, \"radialGradient\");\n radialGradient.setAttribute(\"id\", gradientId);\n radialGradient.setAttribute(\"cx\", \"50%\");\n radialGradient.setAttribute(\"cy\", \"50%\");\n radialGradient.setAttribute(\"r\", \"50%\");\n radialGradient.setAttribute(\"fx\", \"50%\");\n radialGradient.setAttribute(\"fy\", \"50%\");\n // Stops.\n const stop0 = document.createElementNS(svgNS, \"stop\");\n stop0.setAttribute(\"offset\", \"0%\");\n stop0.setAttribute(\n \"style\",\n `stop-color:${this.props.color};stop-opacity:0.9`\n );\n const stop100 = document.createElementNS(svgNS, \"stop\");\n stop100.setAttribute(\"offset\", \"100%\");\n stop100.setAttribute(\n \"style\",\n `stop-color:${this.props.color};stop-opacity:0`\n );\n // Circle.\n const circle = document.createElementNS(svgNS, \"circle\");\n circle.setAttribute(\"fill\", `url(#${gradientId})`);\n circle.setAttribute(\"cx\", \"50%\");\n circle.setAttribute(\"cy\", \"50%\");\n circle.setAttribute(\"r\", \"50%\");\n\n // Append elements.\n radialGradient.append(stop0, stop100);\n defs.append(radialGradient);\n svg.append(defs, circle);\n\n return svg;\n }\n}\n","import { LinkedVisualConsoleProps, UnknownObject } from \"../types\";\nimport {\n linkedVCPropsDecoder,\n parseIntOr,\n notEmptyStringOr,\n stringIsEmpty,\n decodeBase64,\n parseBoolean\n} from \"../lib\";\nimport Item, { ItemProps, itemBasePropsDecoder, ItemType } from \"../Item\";\n\nexport type GroupProps = {\n type: ItemType.GROUP_ITEM;\n groupId: number;\n imageSrc: string | null; // URL?\n statusImageSrc: string | null;\n showStatistics: boolean;\n html?: string | null;\n} & ItemProps &\n LinkedVisualConsoleProps;\n\nfunction extractHtml(data: UnknownObject): string | null {\n if (!stringIsEmpty(data.html)) return data.html;\n if (!stringIsEmpty(data.encodedHtml)) return decodeBase64(data.encodedHtml);\n return null;\n}\n\n/**\n * Build a valid typed object from a raw object.\n * This will allow us to ensure the type safety.\n *\n * @param data Raw object.\n * @return An object representing the group props.\n * @throws Will throw a TypeError if some property\n * is missing from the raw object or have an invalid type.\n */\nexport function groupPropsDecoder(data: UnknownObject): GroupProps | never {\n if (\n (typeof data.imageSrc !== \"string\" || data.imageSrc.length === 0) &&\n data.encodedHtml === null\n ) {\n throw new TypeError(\"invalid image src.\");\n }\n if (parseIntOr(data.groupId, null) === null) {\n throw new TypeError(\"invalid group Id.\");\n }\n\n const showStatistics = parseBoolean(data.showStatistics);\n const html = showStatistics ? extractHtml(data) : null;\n\n return {\n ...itemBasePropsDecoder(data), // Object spread. It will merge the properties of the two objects.\n type: ItemType.GROUP_ITEM,\n groupId: parseInt(data.groupId),\n imageSrc: notEmptyStringOr(data.imageSrc, null),\n statusImageSrc: notEmptyStringOr(data.statusImageSrc, null),\n showStatistics,\n html,\n ...linkedVCPropsDecoder(data) // Object spread. It will merge the properties of the two objects.\n };\n}\n\nexport default class Group extends Item {\n protected createDomElement(): HTMLElement {\n const element = document.createElement(\"div\");\n element.className = \"group\";\n\n if (!this.props.showStatistics && this.props.statusImageSrc !== null) {\n // Icon with status.\n element.style.background = `url(${this.props.statusImageSrc}) no-repeat`;\n element.style.backgroundSize = \"contain\";\n element.style.backgroundPosition = \"center\";\n } else if (this.props.showStatistics && this.props.html != null) {\n // Stats table.\n element.innerHTML = this.props.html;\n }\n\n return element;\n }\n}\n","import \"./styles.css\";\n\nimport { LinkedVisualConsoleProps, UnknownObject, Size } from \"../../types\";\nimport {\n linkedVCPropsDecoder,\n parseIntOr,\n parseBoolean,\n prefixedCssRules,\n notEmptyStringOr,\n humanDate,\n humanTime\n} from \"../../lib\";\nimport Item, { ItemProps, itemBasePropsDecoder, ItemType } from \"../../Item\";\n\nexport type ClockProps = {\n type: ItemType.CLOCK;\n clockType: \"analogic\" | \"digital\";\n clockFormat: \"datetime\" | \"time\";\n clockTimezone: string;\n clockTimezoneOffset: number; // Offset of the timezone to UTC in seconds.\n showClockTimezone: boolean;\n color?: string | null;\n} & ItemProps &\n LinkedVisualConsoleProps;\n\n/**\n * Extract a valid enum value from a raw unknown value.\n * @param clockType Raw value.\n */\nconst parseClockType = (\n clockType: any // eslint-disable-line @typescript-eslint/no-explicit-any\n): ClockProps[\"clockType\"] => {\n switch (clockType) {\n case \"analogic\":\n case \"digital\":\n return clockType;\n default:\n return \"analogic\";\n }\n};\n\n/**\n * Extract a valid enum value from a raw unknown value.\n * @param clockFormat Raw value.\n */\nconst parseClockFormat = (\n clockFormat: any // eslint-disable-line @typescript-eslint/no-explicit-any\n): ClockProps[\"clockFormat\"] => {\n switch (clockFormat) {\n case \"datetime\":\n case \"date\":\n case \"time\":\n return clockFormat;\n default:\n return \"datetime\";\n }\n};\n\n/**\n * Build a valid typed object from a raw object.\n * This will allow us to ensure the type safety.\n *\n * @param data Raw object.\n * @return An object representing the clock props.\n * @throws Will throw a TypeError if some property\n * is missing from the raw object or have an invalid type.\n */\nexport function clockPropsDecoder(data: UnknownObject): ClockProps | never {\n if (\n typeof data.clockTimezone !== \"string\" ||\n data.clockTimezone.length === 0\n ) {\n throw new TypeError(\"invalid timezone.\");\n }\n\n return {\n ...itemBasePropsDecoder(data), // Object spread. It will merge the properties of the two objects.\n type: ItemType.CLOCK,\n clockType: parseClockType(data.clockType),\n clockFormat: parseClockFormat(data.clockFormat),\n clockTimezone: data.clockTimezone,\n clockTimezoneOffset: parseIntOr(data.clockTimezoneOffset, 0),\n showClockTimezone: parseBoolean(data.showClockTimezone),\n color: notEmptyStringOr(data.color, null),\n ...linkedVCPropsDecoder(data) // Object spread. It will merge the properties of the two objects.\n };\n}\n\nexport default class Clock extends Item {\n public static readonly TICK_INTERVAL = 1000; // In ms.\n private intervalRef: number | null = null;\n\n public constructor(props: ClockProps) {\n // Call the superclass constructor.\n super(props);\n\n /* The item is already loaded and inserted into the DOM.\n * The class properties are now initialized.\n * Now you can modify the item, add event handlers, timers, etc.\n */\n\n /* The use of the arrow function is important here. startTick will\n * use the function passed as an argument to call the global setInterval\n * function. The interval, timeout or event functions, among other, are\n * called into another execution loop and using a different context.\n * The arrow functions, unlike the classic functions, doesn't create\n * their own context (this), so their context at execution time will be\n * use the current context at the declaration time.\n * http://es6-features.org/#Lexicalthis\n */\n this.startTick(\n () => {\n // Replace the old element with the updated date.\n this.childElementRef.innerHTML = this.createClock().innerHTML;\n },\n /* The analogic clock doesn't need to tick,\n * but it will be refreshed every 20 seconds\n * to avoid a desync caused by page freezes.\n */\n this.props.clockType === \"analogic\" ? 20000 : Clock.TICK_INTERVAL\n );\n }\n\n /**\n * Wrap a window.clearInterval call.\n */\n private stopTick(): void {\n if (this.intervalRef !== null) {\n window.clearInterval(this.intervalRef);\n this.intervalRef = null;\n }\n }\n\n /**\n * Wrap a window.setInterval call.\n * @param handler Function to be called every time the interval\n * timer is reached.\n * @param interval Number in milliseconds for the interval timer.\n */\n private startTick(\n handler: TimerHandler,\n interval: number = Clock.TICK_INTERVAL\n ): void {\n this.stopTick();\n this.intervalRef = window.setInterval(handler, interval);\n }\n\n /**\n * Create a element which contains the DOM representation of the item.\n * @return DOM Element.\n * @override\n */\n protected createDomElement(): HTMLElement | never {\n return this.createClock();\n }\n\n /**\n * To remove the event listeners and the elements from the DOM.\n * @override\n */\n public remove(): void {\n // Clear the interval.\n this.stopTick();\n // Call to the parent clean function.\n super.remove();\n }\n\n /**\n * @override Item.resizeElement\n * Resize the DOM content container.\n * @param width\n * @param height\n */\n protected resizeElement(width: number, height: number): void {\n const { width: newWidth, height: newHeight } = this.getElementSize(\n width,\n height\n ); // Destructuring assigment: http://es6-features.org/#ObjectMatchingShorthandNotation\n super.resizeElement(newWidth, newHeight);\n // Re-render the item to force it calculate a new font size.\n if (this.props.clockType === \"digital\") {\n // Replace the old element with the updated date.\n this.childElementRef.innerHTML = this.createClock().innerHTML;\n }\n }\n\n /**\n * Create a element which contains a representation of a clock.\n * It choose between the clock types.\n * @return DOM Element.\n * @throws Error.\n */\n private createClock(): HTMLElement | never {\n switch (this.props.clockType) {\n case \"analogic\":\n return this.createAnalogicClock();\n case \"digital\":\n return this.createDigitalClock();\n default:\n throw new Error(\"invalid clock type.\");\n }\n }\n\n /**\n * Create a element which contains a representation of an analogic clock.\n * @return DOM Element.\n */\n private createAnalogicClock(): HTMLElement {\n const svgNS = \"http://www.w3.org/2000/svg\";\n const colors = {\n watchFace: \"#FFFFF0\",\n watchFaceBorder: \"#242124\",\n mark: \"#242124\",\n handDark: \"#242124\",\n handLight: \"#525252\",\n secondHand: \"#DC143C\"\n };\n\n const { width, height } = this.getElementSize(); // Destructuring assigment: http://es6-features.org/#ObjectMatchingShorthandNotation\n\n const div = document.createElement(\"div\");\n div.className = \"analogic-clock\";\n div.style.width = `${width}px`;\n div.style.height = `${height}px`;\n\n // SVG container.\n const svg = document.createElementNS(svgNS, \"svg\");\n // Auto resize SVG using the view box magic: https://css-tricks.com/scale-svg/\n svg.setAttribute(\"viewBox\", \"0 0 100 100\");\n\n // Clock face.\n const clockFace = document.createElementNS(svgNS, \"g\");\n clockFace.setAttribute(\"class\", \"clockface\");\n const clockFaceBackground = document.createElementNS(svgNS, \"circle\");\n clockFaceBackground.setAttribute(\"cx\", \"50\");\n clockFaceBackground.setAttribute(\"cy\", \"50\");\n clockFaceBackground.setAttribute(\"r\", \"48\");\n clockFaceBackground.setAttribute(\"fill\", colors.watchFace);\n clockFaceBackground.setAttribute(\"stroke\", colors.watchFaceBorder);\n clockFaceBackground.setAttribute(\"stroke-width\", \"2\");\n clockFaceBackground.setAttribute(\"stroke-linecap\", \"round\");\n // Insert the clockface background into the clockface group.\n clockFace.append(clockFaceBackground);\n\n // Timezone complication.\n const city = this.getHumanTimezone();\n if (city.length > 0) {\n const timezoneComplication = document.createElementNS(svgNS, \"text\");\n timezoneComplication.setAttribute(\"text-anchor\", \"middle\");\n timezoneComplication.setAttribute(\"font-size\", \"8\");\n timezoneComplication.setAttribute(\n \"transform\",\n \"translate(30 50) rotate(90)\" // Rotate to counter the clock rotation.\n );\n timezoneComplication.setAttribute(\"fill\", colors.mark);\n timezoneComplication.textContent = city;\n clockFace.append(timezoneComplication);\n }\n\n // Marks group.\n const marksGroup = document.createElementNS(svgNS, \"g\");\n marksGroup.setAttribute(\"class\", \"marks\");\n // Build the 12 hours mark.\n const mainMarkGroup = document.createElementNS(svgNS, \"g\");\n mainMarkGroup.setAttribute(\"class\", \"mark\");\n mainMarkGroup.setAttribute(\"transform\", \"translate(50 50)\");\n const mark1a = document.createElementNS(svgNS, \"line\");\n mark1a.setAttribute(\"x1\", \"36\");\n mark1a.setAttribute(\"y1\", \"0\");\n mark1a.setAttribute(\"x2\", \"46\");\n mark1a.setAttribute(\"y2\", \"0\");\n mark1a.setAttribute(\"stroke\", colors.mark);\n mark1a.setAttribute(\"stroke-width\", \"5\");\n const mark1b = document.createElementNS(svgNS, \"line\");\n mark1b.setAttribute(\"x1\", \"36\");\n mark1b.setAttribute(\"y1\", \"0\");\n mark1b.setAttribute(\"x2\", \"46\");\n mark1b.setAttribute(\"y2\", \"0\");\n mark1b.setAttribute(\"stroke\", colors.watchFace);\n mark1b.setAttribute(\"stroke-width\", \"1\");\n // Insert the 12 mark lines into their group.\n mainMarkGroup.append(mark1a, mark1b);\n // Insert the main mark into the marks group.\n marksGroup.append(mainMarkGroup);\n // Build the rest of the marks.\n for (let i = 1; i < 60; i++) {\n const mark = document.createElementNS(svgNS, \"line\");\n mark.setAttribute(\"y1\", \"0\");\n mark.setAttribute(\"y2\", \"0\");\n mark.setAttribute(\"stroke\", colors.mark);\n mark.setAttribute(\"transform\", `translate(50 50) rotate(${i * 6})`);\n\n if (i % 5 === 0) {\n mark.setAttribute(\"x1\", \"38\");\n mark.setAttribute(\"x2\", \"46\");\n mark.setAttribute(\"stroke-width\", i % 15 === 0 ? \"2\" : \"1\");\n } else {\n mark.setAttribute(\"x1\", \"42\");\n mark.setAttribute(\"x2\", \"46\");\n mark.setAttribute(\"stroke-width\", \"0.5\");\n }\n\n // Insert the mark into the marks group.\n marksGroup.append(mark);\n }\n\n /* Clock hands */\n\n // Hour hand.\n const hourHand = document.createElementNS(svgNS, \"g\");\n hourHand.setAttribute(\"class\", \"hour-hand\");\n hourHand.setAttribute(\"transform\", \"translate(50 50)\");\n // This will go back and will act like a border.\n const hourHandA = document.createElementNS(svgNS, \"line\");\n hourHandA.setAttribute(\"class\", \"hour-hand-a\");\n hourHandA.setAttribute(\"x1\", \"0\");\n hourHandA.setAttribute(\"y1\", \"0\");\n hourHandA.setAttribute(\"x2\", \"30\");\n hourHandA.setAttribute(\"y2\", \"0\");\n hourHandA.setAttribute(\"stroke\", colors.handLight);\n hourHandA.setAttribute(\"stroke-width\", \"4\");\n hourHandA.setAttribute(\"stroke-linecap\", \"round\");\n // This will go in front of the previous line.\n const hourHandB = document.createElementNS(svgNS, \"line\");\n hourHandB.setAttribute(\"class\", \"hour-hand-b\");\n hourHandB.setAttribute(\"x1\", \"0\");\n hourHandB.setAttribute(\"y1\", \"0\");\n hourHandB.setAttribute(\"x2\", \"29.9\");\n hourHandB.setAttribute(\"y2\", \"0\");\n hourHandB.setAttribute(\"stroke\", colors.handDark);\n hourHandB.setAttribute(\"stroke-width\", \"3.1\");\n hourHandB.setAttribute(\"stroke-linecap\", \"round\");\n // Append the elements to finish the hour hand.\n hourHand.append(hourHandA, hourHandB);\n\n // Minute hand.\n const minuteHand = document.createElementNS(svgNS, \"g\");\n minuteHand.setAttribute(\"class\", \"minute-hand\");\n minuteHand.setAttribute(\"transform\", \"translate(50 50)\");\n // This will go back and will act like a border.\n const minuteHandA = document.createElementNS(svgNS, \"line\");\n minuteHandA.setAttribute(\"class\", \"minute-hand-a\");\n minuteHandA.setAttribute(\"x1\", \"0\");\n minuteHandA.setAttribute(\"y1\", \"0\");\n minuteHandA.setAttribute(\"x2\", \"40\");\n minuteHandA.setAttribute(\"y2\", \"0\");\n minuteHandA.setAttribute(\"stroke\", colors.handLight);\n minuteHandA.setAttribute(\"stroke-width\", \"2\");\n minuteHandA.setAttribute(\"stroke-linecap\", \"round\");\n // This will go in front of the previous line.\n const minuteHandB = document.createElementNS(svgNS, \"line\");\n minuteHandB.setAttribute(\"class\", \"minute-hand-b\");\n minuteHandB.setAttribute(\"x1\", \"0\");\n minuteHandB.setAttribute(\"y1\", \"0\");\n minuteHandB.setAttribute(\"x2\", \"39.9\");\n minuteHandB.setAttribute(\"y2\", \"0\");\n minuteHandB.setAttribute(\"stroke\", colors.handDark);\n minuteHandB.setAttribute(\"stroke-width\", \"1.5\");\n minuteHandB.setAttribute(\"stroke-linecap\", \"round\");\n const minuteHandPin = document.createElementNS(svgNS, \"circle\");\n minuteHandPin.setAttribute(\"r\", \"3\");\n minuteHandPin.setAttribute(\"fill\", colors.handDark);\n // Append the elements to finish the minute hand.\n minuteHand.append(minuteHandA, minuteHandB, minuteHandPin);\n\n // Second hand.\n const secondHand = document.createElementNS(svgNS, \"g\");\n secondHand.setAttribute(\"class\", \"second-hand\");\n secondHand.setAttribute(\"transform\", \"translate(50 50)\");\n const secondHandBar = document.createElementNS(svgNS, \"line\");\n secondHandBar.setAttribute(\"x1\", \"0\");\n secondHandBar.setAttribute(\"y1\", \"0\");\n secondHandBar.setAttribute(\"x2\", \"46\");\n secondHandBar.setAttribute(\"y2\", \"0\");\n secondHandBar.setAttribute(\"stroke\", colors.secondHand);\n secondHandBar.setAttribute(\"stroke-width\", \"1\");\n secondHandBar.setAttribute(\"stroke-linecap\", \"round\");\n const secondHandPin = document.createElementNS(svgNS, \"circle\");\n secondHandPin.setAttribute(\"r\", \"2\");\n secondHandPin.setAttribute(\"fill\", colors.secondHand);\n // Append the elements to finish the second hand.\n secondHand.append(secondHandBar, secondHandPin);\n\n // Pin.\n const pin = document.createElementNS(svgNS, \"circle\");\n pin.setAttribute(\"cx\", \"50\");\n pin.setAttribute(\"cy\", \"50\");\n pin.setAttribute(\"r\", \"0.3\");\n pin.setAttribute(\"fill\", colors.handDark);\n\n // Get the hand angles.\n const date = this.getOriginDate();\n const seconds = date.getSeconds();\n const minutes = date.getMinutes();\n const hours = date.getHours();\n const secAngle = (360 / 60) * seconds;\n const minuteAngle = (360 / 60) * minutes + (360 / 60) * (seconds / 60);\n const hourAngle = (360 / 12) * hours + (360 / 12) * (minutes / 60);\n // Set the clock time by moving the hands.\n hourHand.setAttribute(\"transform\", `translate(50 50) rotate(${hourAngle})`);\n minuteHand.setAttribute(\n \"transform\",\n `translate(50 50) rotate(${minuteAngle})`\n );\n secondHand.setAttribute(\n \"transform\",\n `translate(50 50) rotate(${secAngle})`\n );\n\n // Build the clock\n svg.append(clockFace, marksGroup, hourHand, minuteHand, secondHand, pin);\n // Rotate the clock to its normal position.\n svg.setAttribute(\"transform\", \"rotate(-90)\");\n\n /* Add the animation declaration to the container.\n * Since the animation keyframes need to know the\n * start angle, this angle is dynamic (current time),\n * and we can't edit keyframes through javascript\n * safely and with backwards compatibility, we need\n * to inject it.\n */\n div.innerHTML = `\n \n `;\n // Add the clock to the container\n div.append(svg);\n\n return div;\n }\n\n /**\n * Create a element which contains a representation of a digital clock.\n * @return DOM Element.\n */\n private createDigitalClock(): HTMLElement {\n const element: HTMLDivElement = document.createElement(\"div\");\n element.className = \"digital-clock\";\n\n const { width } = this.getElementSize(); // Destructuring assigment: http://es6-features.org/#ObjectMatchingShorthandNotation\n\n // Calculate font size to adapt the font to the item size.\n const baseTimeFontSize = 20; // Per 100px of width.\n const dateFontSizeMultiplier = 0.5;\n const tzFontSizeMultiplier = 6 / this.props.clockTimezone.length;\n const timeFontSize = (baseTimeFontSize * width) / 100;\n const dateFontSize =\n (baseTimeFontSize * dateFontSizeMultiplier * width) / 100;\n const tzFontSize = Math.min(\n (baseTimeFontSize * tzFontSizeMultiplier * width) / 100,\n (width / 100) * 10\n );\n\n // Date calculated using the original timezone.\n const date = this.getOriginDate();\n\n // Date.\n if (this.props.clockFormat === \"datetime\") {\n const dateElem: HTMLSpanElement = document.createElement(\"span\");\n dateElem.className = \"date\";\n dateElem.textContent = humanDate(date, \"default\");\n dateElem.style.fontSize = `${dateFontSize}px`;\n if (this.props.color) dateElem.style.color = this.props.color;\n element.append(dateElem);\n }\n\n // Time.\n const timeElem: HTMLSpanElement = document.createElement(\"span\");\n timeElem.className = \"time\";\n timeElem.textContent = humanTime(date);\n timeElem.style.fontSize = `${timeFontSize}px`;\n if (this.props.color) timeElem.style.color = this.props.color;\n element.append(timeElem);\n\n // City name.\n const city = this.getHumanTimezone();\n if (city.length > 0) {\n const tzElem: HTMLSpanElement = document.createElement(\"span\");\n tzElem.className = \"timezone\";\n tzElem.textContent = city;\n tzElem.style.fontSize = `${tzFontSize}px`;\n if (this.props.color) tzElem.style.color = this.props.color;\n element.append(tzElem);\n }\n\n return element;\n }\n\n /**\n * Generate the current date using the timezone offset stored into the properties.\n * @return The current date.\n */\n private getOriginDate(initialDate: Date | null = null): Date {\n const d = initialDate ? initialDate : new Date();\n const targetTZOffset = this.props.clockTimezoneOffset * 1000; // In ms.\n const localTZOffset = d.getTimezoneOffset() * 60 * 1000; // In ms.\n const utimestamp = d.getTime() + targetTZOffset + localTZOffset;\n\n return new Date(utimestamp);\n }\n\n /**\n * Extract a human readable city name from the timezone text.\n * @param timezone Timezone text.\n */\n public getHumanTimezone(timezone: string = this.props.clockTimezone): string {\n const [, city = \"\"] = timezone.split(\"/\");\n return city.replace(\"_\", \" \");\n }\n\n /**\n * Generate a element size using the current size and the default values.\n * @return The size.\n */\n private getElementSize(\n width: number = this.props.width,\n height: number = this.props.height\n ): Size {\n switch (this.props.clockType) {\n case \"analogic\": {\n let diameter = 100; // Default value.\n\n if (width > 0 && height > 0) {\n diameter = Math.min(width, height);\n } else if (width > 0) {\n diameter = width;\n } else if (height > 0) {\n diameter = height;\n }\n\n return {\n width: diameter,\n height: diameter\n };\n }\n case \"digital\": {\n if (width > 0 && height > 0) {\n // The proportion of the clock should be (width = height / 2) aproximately.\n height = width / 2 < height ? width / 2 : height;\n } else if (width > 0) {\n height = width / 2;\n } else if (height > 0) {\n // The proportion of the clock should be (height * 2 = width) aproximately.\n width = height * 2;\n } else {\n width = 100; // Default value.\n height = 50; // Default value.\n }\n\n return {\n width,\n height\n };\n }\n default:\n throw new Error(\"invalid clock type.\");\n }\n }\n}\n","import { UnknownObject } from \"../types\";\nimport { parseIntOr, notEmptyStringOr } from \"../lib\";\nimport Item, { ItemType, ItemProps, itemBasePropsDecoder } from \"../Item\";\n\ninterface BoxProps extends ItemProps {\n // Overrided properties.\n readonly type: ItemType.BOX_ITEM;\n label: null;\n isLinkEnabled: false;\n parentId: null;\n aclGroupId: null;\n // Custom properties.\n borderWidth: number;\n borderColor: string | null;\n fillColor: string | null;\n}\n\n/**\n * Build a valid typed object from a raw object.\n * This will allow us to ensure the type safety.\n *\n * @param data Raw object.\n * @return An object representing the item props.\n * @throws Will throw a TypeError if some property\n * is missing from the raw object or have an invalid type.\n */\nexport function boxPropsDecoder(data: UnknownObject): BoxProps | never {\n return {\n ...itemBasePropsDecoder(data), // Object spread. It will merge the properties of the two objects.\n type: ItemType.BOX_ITEM,\n label: null,\n isLinkEnabled: false,\n parentId: null,\n aclGroupId: null,\n // Custom properties.\n borderWidth: parseIntOr(data.borderWidth, 0),\n borderColor: notEmptyStringOr(data.borderColor, null),\n fillColor: notEmptyStringOr(data.fillColor, null)\n };\n}\n\nexport default class Box extends Item {\n protected createDomElement(): HTMLElement {\n const box: HTMLDivElement = document.createElement(\"div\");\n box.className = \"box\";\n // To prevent this item to expand beyond its parent.\n box.style.boxSizing = \"border-box\";\n\n if (this.props.fillColor) {\n box.style.backgroundColor = this.props.fillColor;\n }\n\n // Border.\n if (this.props.borderWidth > 0) {\n box.style.borderStyle = \"solid\";\n // Control the max width to prevent this item to expand beyond its parent.\n const maxBorderWidth = Math.min(this.props.width, this.props.height) / 2;\n const borderWidth = Math.min(this.props.borderWidth, maxBorderWidth);\n box.style.borderWidth = `${borderWidth}px`;\n\n if (this.props.borderColor) {\n box.style.borderColor = this.props.borderColor;\n }\n }\n\n return box;\n }\n}\n","import { UnknownObject, Position, Size } from \"../types\";\nimport { parseIntOr, notEmptyStringOr } from \"../lib\";\nimport Item, { ItemType, ItemProps, itemBasePropsDecoder } from \"../Item\";\n\ninterface LineProps extends ItemProps {\n // Overrided properties.\n readonly type: ItemType.LINE_ITEM;\n label: null;\n isLinkEnabled: false;\n parentId: null;\n aclGroupId: null;\n // Custom properties.\n startPosition: Position;\n endPosition: Position;\n lineWidth: number;\n color: string | null;\n}\n\n/**\n * Build a valid typed object from a raw object.\n * This will allow us to ensure the type safety.\n *\n * @param data Raw object.\n * @return An object representing the item props.\n * @throws Will throw a TypeError if some property\n * is missing from the raw object or have an invalid type.\n */\nexport function linePropsDecoder(data: UnknownObject): LineProps | never {\n const props: LineProps = {\n ...itemBasePropsDecoder({ ...data, width: 1, height: 1 }), // Object spread. It will merge the properties of the two objects.\n type: ItemType.LINE_ITEM,\n label: null,\n isLinkEnabled: false,\n parentId: null,\n aclGroupId: null,\n // Initialize Position & Size.\n x: 0,\n y: 0,\n width: 0,\n height: 0,\n // Custom properties.\n startPosition: {\n x: parseIntOr(data.startX, 0),\n y: parseIntOr(data.startY, 0)\n },\n endPosition: {\n x: parseIntOr(data.endX, 0),\n y: parseIntOr(data.endY, 0)\n },\n lineWidth: parseIntOr(data.lineWidth || data.borderWidth, 1),\n color: notEmptyStringOr(data.borderColor || data.color, null)\n };\n\n /*\n * We need to enhance the props with the extracted size and position\n * of the box cause there are missing at the props update. A better\n * solution would be overriding the props setter to do it there, but\n * the language doesn't allow it while targetting ES5.\n * TODO: We need to figure out a more consistent solution.\n */\n\n return {\n ...props,\n // Enhance the props extracting the box size and position.\n // eslint-disable-next-line @typescript-eslint/no-use-before-define\n ...Line.extractBoxSizeAndPosition(props)\n };\n}\n\nexport default class Line extends Item {\n /**\n * @override\n */\n public constructor(props: LineProps) {\n /*\n * We need to override the constructor cause we need to obtain\n * the\n * box size and position from the start and finish points\n * of the line.\n */\n super({\n ...props,\n ...Line.extractBoxSizeAndPosition(props)\n });\n }\n\n /**\n * @override\n * To create the item's DOM representation.\n * @return Item.\n */\n protected createDomElement(): HTMLElement {\n const element: HTMLDivElement = document.createElement(\"div\");\n element.className = \"line\";\n\n const svgNS = \"http://www.w3.org/2000/svg\";\n // SVG container.\n const svg = document.createElementNS(svgNS, \"svg\");\n // Set SVG size.\n svg.setAttribute(\n \"width\",\n (this.props.width + this.props.lineWidth).toString()\n );\n svg.setAttribute(\n \"height\",\n (this.props.height + this.props.lineWidth).toString()\n );\n const line = document.createElementNS(svgNS, \"line\");\n line.setAttribute(\n \"x1\",\n `${this.props.startPosition.x - this.props.x + this.props.lineWidth / 2}`\n );\n line.setAttribute(\n \"y1\",\n `${this.props.startPosition.y - this.props.y + this.props.lineWidth / 2}`\n );\n line.setAttribute(\n \"x2\",\n `${this.props.endPosition.x - this.props.x + this.props.lineWidth / 2}`\n );\n line.setAttribute(\n \"y2\",\n `${this.props.endPosition.y - this.props.y + this.props.lineWidth / 2}`\n );\n line.setAttribute(\"stroke\", this.props.color || \"black\");\n line.setAttribute(\"stroke-width\", this.props.lineWidth.toString());\n\n svg.append(line);\n element.append(svg);\n\n return element;\n }\n\n /**\n * Extract the size and position of the box from\n * the start and the finish of the line.\n * @param props Item properties.\n */\n public static extractBoxSizeAndPosition(props: LineProps): Size & Position {\n return {\n width: Math.abs(props.startPosition.x - props.endPosition.x),\n height: Math.abs(props.startPosition.y - props.endPosition.y),\n x: Math.min(props.startPosition.x, props.endPosition.x),\n y: Math.min(props.startPosition.y, props.endPosition.y)\n };\n }\n}\n","import { LinkedVisualConsoleProps, UnknownObject } from \"../types\";\nimport { linkedVCPropsDecoder } from \"../lib\";\nimport Item, { ItemType, ItemProps, itemBasePropsDecoder } from \"../Item\";\n\nexport type LabelProps = {\n type: ItemType.LABEL;\n} & ItemProps &\n LinkedVisualConsoleProps;\n\n/**\n * Build a valid typed object from a raw object.\n * This will allow us to ensure the type safety.\n *\n * @param data Raw object.\n * @return An object representing the label props.\n * @throws Will throw a TypeError if some property\n * is missing from the raw object or have an invalid type.\n */\nexport function labelPropsDecoder(data: UnknownObject): LabelProps | never {\n return {\n ...itemBasePropsDecoder(data), // Object spread. It will merge the properties of the two objects.\n type: ItemType.LABEL,\n ...linkedVCPropsDecoder(data) // Object spread. It will merge the properties of the two objects.\n };\n}\n\nexport default class Label extends Item {\n protected createDomElement(): HTMLElement {\n const element = document.createElement(\"div\");\n element.className = \"label\";\n element.innerHTML = this.getLabelWithMacrosReplaced();\n\n return element;\n }\n\n /**\n * @override Item.createLabelDomElement\n * Create a new label for the visual console item.\n * @return Item label.\n */\n public createLabelDomElement(): HTMLElement {\n const element = document.createElement(\"div\");\n element.className = \"visual-console-item-label\";\n // Always return an empty label.\n return element;\n }\n}\n","import {\n LinkedVisualConsoleProps,\n UnknownObject,\n WithModuleProps\n} from \"../types\";\nimport {\n linkedVCPropsDecoder,\n parseIntOr,\n modulePropsDecoder,\n replaceMacros\n} from \"../lib\";\nimport Item, { ItemType, ItemProps, itemBasePropsDecoder } from \"../Item\";\n\nexport type SimpleValueProps = {\n type: ItemType.SIMPLE_VALUE;\n valueType: \"string\" | \"image\";\n value: string;\n} & (\n | {\n processValue: \"none\";\n }\n | {\n processValue: \"avg\" | \"max\" | \"min\";\n period: number;\n }) &\n ItemProps &\n WithModuleProps &\n LinkedVisualConsoleProps;\n\n/**\n * Extract a valid enum value from a raw value type.\n * @param valueType Raw value.\n */\nconst parseValueType = (\n valueType: any // eslint-disable-line @typescript-eslint/no-explicit-any\n): SimpleValueProps[\"valueType\"] => {\n switch (valueType) {\n case \"string\":\n case \"image\":\n return valueType;\n default:\n return \"string\";\n }\n};\n\n/**\n * Extract a valid enum value from a raw process value.\n * @param processValue Raw value.\n */\nconst parseProcessValue = (\n processValue: any // eslint-disable-line @typescript-eslint/no-explicit-any\n): SimpleValueProps[\"processValue\"] => {\n switch (processValue) {\n case \"none\":\n case \"avg\":\n case \"max\":\n case \"min\":\n return processValue;\n default:\n return \"none\";\n }\n};\n\n/**\n * Build a valid typed object from a raw object.\n * This will allow us to ensure the type safety.\n *\n * @param data Raw object.\n * @return An object representing the simple value props.\n * @throws Will throw a TypeError if some property\n * is missing from the raw object or have an invalid type.\n */\nexport function simpleValuePropsDecoder(\n data: UnknownObject\n): SimpleValueProps | never {\n if (typeof data.value !== \"string\" || data.value.length === 0) {\n throw new TypeError(\"invalid value\");\n }\n\n const processValue = parseProcessValue(data.processValue);\n\n return {\n ...itemBasePropsDecoder(data), // Object spread. It will merge the properties of the two objects.\n type: ItemType.SIMPLE_VALUE,\n valueType: parseValueType(data.valueType),\n value: data.value,\n ...(processValue === \"none\"\n ? { processValue }\n : { processValue, period: parseIntOr(data.period, 0) }), // Object spread. It will merge the properties of the two objects.\n ...modulePropsDecoder(data), // Object spread. It will merge the properties of the two objects.\n ...linkedVCPropsDecoder(data) // Object spread. It will merge the properties of the two objects.\n };\n}\n\nexport default class SimpleValue extends Item {\n protected createDomElement(): HTMLElement {\n const element = document.createElement(\"div\");\n element.className = \"simple-value\";\n\n if (this.props.valueType === \"image\") {\n const img = document.createElement(\"img\");\n img.src = this.props.value;\n element.append(img);\n } else {\n // Add the value to the label and show it.\n let text = this.props.value;\n let label = this.getLabelWithMacrosReplaced();\n if (label.length > 0) {\n text = replaceMacros([{ macro: /\\(?_VALUE_\\)?/i, value: text }], label);\n }\n\n element.innerHTML = text;\n }\n\n return element;\n }\n\n /**\n * @override Item.createLabelDomElement\n * Create a new label for the visual console item.\n * @return Item label.\n */\n protected createLabelDomElement(): HTMLElement {\n const element = document.createElement(\"div\");\n element.className = \"visual-console-item-label\";\n // Always return an empty label.\n return element;\n }\n}\n","var pi = Math.PI,\n tau = 2 * pi,\n epsilon = 1e-6,\n tauEpsilon = tau - epsilon;\n\nfunction Path() {\n this._x0 = this._y0 = // start of current subpath\n this._x1 = this._y1 = null; // end of current subpath\n this._ = \"\";\n}\n\nfunction path() {\n return new Path;\n}\n\nPath.prototype = path.prototype = {\n constructor: Path,\n moveTo: function(x, y) {\n this._ += \"M\" + (this._x0 = this._x1 = +x) + \",\" + (this._y0 = this._y1 = +y);\n },\n closePath: function() {\n if (this._x1 !== null) {\n this._x1 = this._x0, this._y1 = this._y0;\n this._ += \"Z\";\n }\n },\n lineTo: function(x, y) {\n this._ += \"L\" + (this._x1 = +x) + \",\" + (this._y1 = +y);\n },\n quadraticCurveTo: function(x1, y1, x, y) {\n this._ += \"Q\" + (+x1) + \",\" + (+y1) + \",\" + (this._x1 = +x) + \",\" + (this._y1 = +y);\n },\n bezierCurveTo: function(x1, y1, x2, y2, x, y) {\n this._ += \"C\" + (+x1) + \",\" + (+y1) + \",\" + (+x2) + \",\" + (+y2) + \",\" + (this._x1 = +x) + \",\" + (this._y1 = +y);\n },\n arcTo: function(x1, y1, x2, y2, r) {\n x1 = +x1, y1 = +y1, x2 = +x2, y2 = +y2, r = +r;\n var x0 = this._x1,\n y0 = this._y1,\n x21 = x2 - x1,\n y21 = y2 - y1,\n x01 = x0 - x1,\n y01 = y0 - y1,\n l01_2 = x01 * x01 + y01 * y01;\n\n // Is the radius negative? Error.\n if (r < 0) throw new Error(\"negative radius: \" + r);\n\n // Is this path empty? Move to (x1,y1).\n if (this._x1 === null) {\n this._ += \"M\" + (this._x1 = x1) + \",\" + (this._y1 = y1);\n }\n\n // Or, is (x1,y1) coincident with (x0,y0)? Do nothing.\n else if (!(l01_2 > epsilon));\n\n // Or, are (x0,y0), (x1,y1) and (x2,y2) collinear?\n // Equivalently, is (x1,y1) coincident with (x2,y2)?\n // Or, is the radius zero? Line to (x1,y1).\n else if (!(Math.abs(y01 * x21 - y21 * x01) > epsilon) || !r) {\n this._ += \"L\" + (this._x1 = x1) + \",\" + (this._y1 = y1);\n }\n\n // Otherwise, draw an arc!\n else {\n var x20 = x2 - x0,\n y20 = y2 - y0,\n l21_2 = x21 * x21 + y21 * y21,\n l20_2 = x20 * x20 + y20 * y20,\n l21 = Math.sqrt(l21_2),\n l01 = Math.sqrt(l01_2),\n l = r * Math.tan((pi - Math.acos((l21_2 + l01_2 - l20_2) / (2 * l21 * l01))) / 2),\n t01 = l / l01,\n t21 = l / l21;\n\n // If the start tangent is not coincident with (x0,y0), line to.\n if (Math.abs(t01 - 1) > epsilon) {\n this._ += \"L\" + (x1 + t01 * x01) + \",\" + (y1 + t01 * y01);\n }\n\n this._ += \"A\" + r + \",\" + r + \",0,0,\" + (+(y01 * x20 > x01 * y20)) + \",\" + (this._x1 = x1 + t21 * x21) + \",\" + (this._y1 = y1 + t21 * y21);\n }\n },\n arc: function(x, y, r, a0, a1, ccw) {\n x = +x, y = +y, r = +r;\n var dx = r * Math.cos(a0),\n dy = r * Math.sin(a0),\n x0 = x + dx,\n y0 = y + dy,\n cw = 1 ^ ccw,\n da = ccw ? a0 - a1 : a1 - a0;\n\n // Is the radius negative? Error.\n if (r < 0) throw new Error(\"negative radius: \" + r);\n\n // Is this path empty? Move to (x0,y0).\n if (this._x1 === null) {\n this._ += \"M\" + x0 + \",\" + y0;\n }\n\n // Or, is (x0,y0) not coincident with the previous point? Line to (x0,y0).\n else if (Math.abs(this._x1 - x0) > epsilon || Math.abs(this._y1 - y0) > epsilon) {\n this._ += \"L\" + x0 + \",\" + y0;\n }\n\n // Is this arc empty? We’re done.\n if (!r) return;\n\n // Does the angle go the wrong way? Flip the direction.\n if (da < 0) da = da % tau + tau;\n\n // Is this a complete circle? Draw two arcs to complete the circle.\n if (da > tauEpsilon) {\n this._ += \"A\" + r + \",\" + r + \",0,1,\" + cw + \",\" + (x - dx) + \",\" + (y - dy) + \"A\" + r + \",\" + r + \",0,1,\" + cw + \",\" + (this._x1 = x0) + \",\" + (this._y1 = y0);\n }\n\n // Is this arc non-empty? Draw an arc!\n else if (da > epsilon) {\n this._ += \"A\" + r + \",\" + r + \",0,\" + (+(da >= pi)) + \",\" + cw + \",\" + (this._x1 = x + r * Math.cos(a1)) + \",\" + (this._y1 = y + r * Math.sin(a1));\n }\n },\n rect: function(x, y, w, h) {\n this._ += \"M\" + (this._x0 = this._x1 = +x) + \",\" + (this._y0 = this._y1 = +y) + \"h\" + (+w) + \"v\" + (+h) + \"h\" + (-w) + \"Z\";\n },\n toString: function() {\n return this._;\n }\n};\n\nexport default path;\n","export default function(x) {\n return function constant() {\n return x;\n };\n}\n","export var abs = Math.abs;\nexport var atan2 = Math.atan2;\nexport var cos = Math.cos;\nexport var max = Math.max;\nexport var min = Math.min;\nexport var sin = Math.sin;\nexport var sqrt = Math.sqrt;\n\nexport var epsilon = 1e-12;\nexport var pi = Math.PI;\nexport var halfPi = pi / 2;\nexport var tau = 2 * pi;\n\nexport function acos(x) {\n return x > 1 ? 0 : x < -1 ? pi : Math.acos(x);\n}\n\nexport function asin(x) {\n return x >= 1 ? halfPi : x <= -1 ? -halfPi : Math.asin(x);\n}\n","import {path} from \"d3-path\";\nimport constant from \"./constant\";\nimport {abs, acos, asin, atan2, cos, epsilon, halfPi, max, min, pi, sin, sqrt, tau} from \"./math\";\n\nfunction arcInnerRadius(d) {\n return d.innerRadius;\n}\n\nfunction arcOuterRadius(d) {\n return d.outerRadius;\n}\n\nfunction arcStartAngle(d) {\n return d.startAngle;\n}\n\nfunction arcEndAngle(d) {\n return d.endAngle;\n}\n\nfunction arcPadAngle(d) {\n return d && d.padAngle; // Note: optional!\n}\n\nfunction intersect(x0, y0, x1, y1, x2, y2, x3, y3) {\n var x10 = x1 - x0, y10 = y1 - y0,\n x32 = x3 - x2, y32 = y3 - y2,\n t = y32 * x10 - x32 * y10;\n if (t * t < epsilon) return;\n t = (x32 * (y0 - y2) - y32 * (x0 - x2)) / t;\n return [x0 + t * x10, y0 + t * y10];\n}\n\n// Compute perpendicular offset line of length rc.\n// http://mathworld.wolfram.com/Circle-LineIntersection.html\nfunction cornerTangents(x0, y0, x1, y1, r1, rc, cw) {\n var x01 = x0 - x1,\n y01 = y0 - y1,\n lo = (cw ? rc : -rc) / sqrt(x01 * x01 + y01 * y01),\n ox = lo * y01,\n oy = -lo * x01,\n x11 = x0 + ox,\n y11 = y0 + oy,\n x10 = x1 + ox,\n y10 = y1 + oy,\n x00 = (x11 + x10) / 2,\n y00 = (y11 + y10) / 2,\n dx = x10 - x11,\n dy = y10 - y11,\n d2 = dx * dx + dy * dy,\n r = r1 - rc,\n D = x11 * y10 - x10 * y11,\n d = (dy < 0 ? -1 : 1) * sqrt(max(0, r * r * d2 - D * D)),\n cx0 = (D * dy - dx * d) / d2,\n cy0 = (-D * dx - dy * d) / d2,\n cx1 = (D * dy + dx * d) / d2,\n cy1 = (-D * dx + dy * d) / d2,\n dx0 = cx0 - x00,\n dy0 = cy0 - y00,\n dx1 = cx1 - x00,\n dy1 = cy1 - y00;\n\n // Pick the closer of the two intersection points.\n // TODO Is there a faster way to determine which intersection to use?\n if (dx0 * dx0 + dy0 * dy0 > dx1 * dx1 + dy1 * dy1) cx0 = cx1, cy0 = cy1;\n\n return {\n cx: cx0,\n cy: cy0,\n x01: -ox,\n y01: -oy,\n x11: cx0 * (r1 / r - 1),\n y11: cy0 * (r1 / r - 1)\n };\n}\n\nexport default function() {\n var innerRadius = arcInnerRadius,\n outerRadius = arcOuterRadius,\n cornerRadius = constant(0),\n padRadius = null,\n startAngle = arcStartAngle,\n endAngle = arcEndAngle,\n padAngle = arcPadAngle,\n context = null;\n\n function arc() {\n var buffer,\n r,\n r0 = +innerRadius.apply(this, arguments),\n r1 = +outerRadius.apply(this, arguments),\n a0 = startAngle.apply(this, arguments) - halfPi,\n a1 = endAngle.apply(this, arguments) - halfPi,\n da = abs(a1 - a0),\n cw = a1 > a0;\n\n if (!context) context = buffer = path();\n\n // Ensure that the outer radius is always larger than the inner radius.\n if (r1 < r0) r = r1, r1 = r0, r0 = r;\n\n // Is it a point?\n if (!(r1 > epsilon)) context.moveTo(0, 0);\n\n // Or is it a circle or annulus?\n else if (da > tau - epsilon) {\n context.moveTo(r1 * cos(a0), r1 * sin(a0));\n context.arc(0, 0, r1, a0, a1, !cw);\n if (r0 > epsilon) {\n context.moveTo(r0 * cos(a1), r0 * sin(a1));\n context.arc(0, 0, r0, a1, a0, cw);\n }\n }\n\n // Or is it a circular or annular sector?\n else {\n var a01 = a0,\n a11 = a1,\n a00 = a0,\n a10 = a1,\n da0 = da,\n da1 = da,\n ap = padAngle.apply(this, arguments) / 2,\n rp = (ap > epsilon) && (padRadius ? +padRadius.apply(this, arguments) : sqrt(r0 * r0 + r1 * r1)),\n rc = min(abs(r1 - r0) / 2, +cornerRadius.apply(this, arguments)),\n rc0 = rc,\n rc1 = rc,\n t0,\n t1;\n\n // Apply padding? Note that since r1 ≥ r0, da1 ≥ da0.\n if (rp > epsilon) {\n var p0 = asin(rp / r0 * sin(ap)),\n p1 = asin(rp / r1 * sin(ap));\n if ((da0 -= p0 * 2) > epsilon) p0 *= (cw ? 1 : -1), a00 += p0, a10 -= p0;\n else da0 = 0, a00 = a10 = (a0 + a1) / 2;\n if ((da1 -= p1 * 2) > epsilon) p1 *= (cw ? 1 : -1), a01 += p1, a11 -= p1;\n else da1 = 0, a01 = a11 = (a0 + a1) / 2;\n }\n\n var x01 = r1 * cos(a01),\n y01 = r1 * sin(a01),\n x10 = r0 * cos(a10),\n y10 = r0 * sin(a10);\n\n // Apply rounded corners?\n if (rc > epsilon) {\n var x11 = r1 * cos(a11),\n y11 = r1 * sin(a11),\n x00 = r0 * cos(a00),\n y00 = r0 * sin(a00),\n oc;\n\n // Restrict the corner radius according to the sector angle.\n if (da < pi && (oc = intersect(x01, y01, x00, y00, x11, y11, x10, y10))) {\n var ax = x01 - oc[0],\n ay = y01 - oc[1],\n bx = x11 - oc[0],\n by = y11 - oc[1],\n kc = 1 / sin(acos((ax * bx + ay * by) / (sqrt(ax * ax + ay * ay) * sqrt(bx * bx + by * by))) / 2),\n lc = sqrt(oc[0] * oc[0] + oc[1] * oc[1]);\n rc0 = min(rc, (r0 - lc) / (kc - 1));\n rc1 = min(rc, (r1 - lc) / (kc + 1));\n }\n }\n\n // Is the sector collapsed to a line?\n if (!(da1 > epsilon)) context.moveTo(x01, y01);\n\n // Does the sector’s outer ring have rounded corners?\n else if (rc1 > epsilon) {\n t0 = cornerTangents(x00, y00, x01, y01, r1, rc1, cw);\n t1 = cornerTangents(x11, y11, x10, y10, r1, rc1, cw);\n\n context.moveTo(t0.cx + t0.x01, t0.cy + t0.y01);\n\n // Have the corners merged?\n if (rc1 < rc) context.arc(t0.cx, t0.cy, rc1, atan2(t0.y01, t0.x01), atan2(t1.y01, t1.x01), !cw);\n\n // Otherwise, draw the two corners and the ring.\n else {\n context.arc(t0.cx, t0.cy, rc1, atan2(t0.y01, t0.x01), atan2(t0.y11, t0.x11), !cw);\n context.arc(0, 0, r1, atan2(t0.cy + t0.y11, t0.cx + t0.x11), atan2(t1.cy + t1.y11, t1.cx + t1.x11), !cw);\n context.arc(t1.cx, t1.cy, rc1, atan2(t1.y11, t1.x11), atan2(t1.y01, t1.x01), !cw);\n }\n }\n\n // Or is the outer ring just a circular arc?\n else context.moveTo(x01, y01), context.arc(0, 0, r1, a01, a11, !cw);\n\n // Is there no inner ring, and it’s a circular sector?\n // Or perhaps it’s an annular sector collapsed due to padding?\n if (!(r0 > epsilon) || !(da0 > epsilon)) context.lineTo(x10, y10);\n\n // Does the sector’s inner ring (or point) have rounded corners?\n else if (rc0 > epsilon) {\n t0 = cornerTangents(x10, y10, x11, y11, r0, -rc0, cw);\n t1 = cornerTangents(x01, y01, x00, y00, r0, -rc0, cw);\n\n context.lineTo(t0.cx + t0.x01, t0.cy + t0.y01);\n\n // Have the corners merged?\n if (rc0 < rc) context.arc(t0.cx, t0.cy, rc0, atan2(t0.y01, t0.x01), atan2(t1.y01, t1.x01), !cw);\n\n // Otherwise, draw the two corners and the ring.\n else {\n context.arc(t0.cx, t0.cy, rc0, atan2(t0.y01, t0.x01), atan2(t0.y11, t0.x11), !cw);\n context.arc(0, 0, r0, atan2(t0.cy + t0.y11, t0.cx + t0.x11), atan2(t1.cy + t1.y11, t1.cx + t1.x11), cw);\n context.arc(t1.cx, t1.cy, rc0, atan2(t1.y11, t1.x11), atan2(t1.y01, t1.x01), !cw);\n }\n }\n\n // Or is the inner ring just a circular arc?\n else context.arc(0, 0, r0, a10, a00, cw);\n }\n\n context.closePath();\n\n if (buffer) return context = null, buffer + \"\" || null;\n }\n\n arc.centroid = function() {\n var r = (+innerRadius.apply(this, arguments) + +outerRadius.apply(this, arguments)) / 2,\n a = (+startAngle.apply(this, arguments) + +endAngle.apply(this, arguments)) / 2 - pi / 2;\n return [cos(a) * r, sin(a) * r];\n };\n\n arc.innerRadius = function(_) {\n return arguments.length ? (innerRadius = typeof _ === \"function\" ? _ : constant(+_), arc) : innerRadius;\n };\n\n arc.outerRadius = function(_) {\n return arguments.length ? (outerRadius = typeof _ === \"function\" ? _ : constant(+_), arc) : outerRadius;\n };\n\n arc.cornerRadius = function(_) {\n return arguments.length ? (cornerRadius = typeof _ === \"function\" ? _ : constant(+_), arc) : cornerRadius;\n };\n\n arc.padRadius = function(_) {\n return arguments.length ? (padRadius = _ == null ? null : typeof _ === \"function\" ? _ : constant(+_), arc) : padRadius;\n };\n\n arc.startAngle = function(_) {\n return arguments.length ? (startAngle = typeof _ === \"function\" ? _ : constant(+_), arc) : startAngle;\n };\n\n arc.endAngle = function(_) {\n return arguments.length ? (endAngle = typeof _ === \"function\" ? _ : constant(+_), arc) : endAngle;\n };\n\n arc.padAngle = function(_) {\n return arguments.length ? (padAngle = typeof _ === \"function\" ? _ : constant(+_), arc) : padAngle;\n };\n\n arc.context = function(_) {\n return arguments.length ? ((context = _ == null ? null : _), arc) : context;\n };\n\n return arc;\n}\n","function Linear(context) {\n this._context = context;\n}\n\nLinear.prototype = {\n areaStart: function() {\n this._line = 0;\n },\n areaEnd: function() {\n this._line = NaN;\n },\n lineStart: function() {\n this._point = 0;\n },\n lineEnd: function() {\n if (this._line || (this._line !== 0 && this._point === 1)) this._context.closePath();\n this._line = 1 - this._line;\n },\n point: function(x, y) {\n x = +x, y = +y;\n switch (this._point) {\n case 0: this._point = 1; this._line ? this._context.lineTo(x, y) : this._context.moveTo(x, y); break;\n case 1: this._point = 2; // proceed\n default: this._context.lineTo(x, y); break;\n }\n }\n};\n\nexport default function(context) {\n return new Linear(context);\n}\n","import curveLinear from \"./linear\";\n\nexport var curveRadialLinear = curveRadial(curveLinear);\n\nfunction Radial(curve) {\n this._curve = curve;\n}\n\nRadial.prototype = {\n areaStart: function() {\n this._curve.areaStart();\n },\n areaEnd: function() {\n this._curve.areaEnd();\n },\n lineStart: function() {\n this._curve.lineStart();\n },\n lineEnd: function() {\n this._curve.lineEnd();\n },\n point: function(a, r) {\n this._curve.point(r * Math.sin(a), r * -Math.cos(a));\n }\n};\n\nexport default function curveRadial(curve) {\n\n function radial(context) {\n return new Radial(curve(context));\n }\n\n radial._curve = curve;\n\n return radial;\n}\n","export var slice = Array.prototype.slice;\n","var tan30 = Math.sqrt(1 / 3),\n tan30_2 = tan30 * 2;\n\nexport default {\n draw: function(context, size) {\n var y = Math.sqrt(size / tan30_2),\n x = y * tan30;\n context.moveTo(0, -y);\n context.lineTo(x, 0);\n context.lineTo(0, y);\n context.lineTo(-x, 0);\n context.closePath();\n }\n};\n","import {pi, tau} from \"../math\";\n\nexport default {\n draw: function(context, size) {\n var r = Math.sqrt(size / pi);\n context.moveTo(r, 0);\n context.arc(0, 0, r, 0, tau);\n }\n};\n","import {pi, tau} from \"../math\";\n\nvar ka = 0.89081309152928522810,\n kr = Math.sin(pi / 10) / Math.sin(7 * pi / 10),\n kx = Math.sin(tau / 10) * kr,\n ky = -Math.cos(tau / 10) * kr;\n\nexport default {\n draw: function(context, size) {\n var r = Math.sqrt(size * ka),\n x = kx * r,\n y = ky * r;\n context.moveTo(0, -r);\n context.lineTo(x, y);\n for (var i = 1; i < 5; ++i) {\n var a = tau * i / 5,\n c = Math.cos(a),\n s = Math.sin(a);\n context.lineTo(s * r, -c * r);\n context.lineTo(c * x - s * y, s * x + c * y);\n }\n context.closePath();\n }\n};\n","export default function() {}\n","var sqrt3 = Math.sqrt(3);\n\nexport default {\n draw: function(context, size) {\n var y = -Math.sqrt(size / (sqrt3 * 3));\n context.moveTo(0, y * 2);\n context.lineTo(-sqrt3 * y, -y);\n context.lineTo(sqrt3 * y, -y);\n context.closePath();\n }\n};\n","var c = -0.5,\n s = Math.sqrt(3) / 2,\n k = 1 / Math.sqrt(12),\n a = (k / 2 + 1) * 3;\n\nexport default {\n draw: function(context, size) {\n var r = Math.sqrt(size / a),\n x0 = r / 2,\n y0 = r * k,\n x1 = x0,\n y1 = r * k + r,\n x2 = -x1,\n y2 = y1;\n context.moveTo(x0, y0);\n context.lineTo(x1, y1);\n context.lineTo(x2, y2);\n context.lineTo(c * x0 - s * y0, s * x0 + c * y0);\n context.lineTo(c * x1 - s * y1, s * x1 + c * y1);\n context.lineTo(c * x2 - s * y2, s * x2 + c * y2);\n context.lineTo(c * x0 + s * y0, c * y0 - s * x0);\n context.lineTo(c * x1 + s * y1, c * y1 - s * x1);\n context.lineTo(c * x2 + s * y2, c * y2 - s * x2);\n context.closePath();\n }\n};\n","export function point(that, x, y) {\n that._context.bezierCurveTo(\n (2 * that._x0 + that._x1) / 3,\n (2 * that._y0 + that._y1) / 3,\n (that._x0 + 2 * that._x1) / 3,\n (that._y0 + 2 * that._y1) / 3,\n (that._x0 + 4 * that._x1 + x) / 6,\n (that._y0 + 4 * that._y1 + y) / 6\n );\n}\n\nexport function Basis(context) {\n this._context = context;\n}\n\nBasis.prototype = {\n areaStart: function() {\n this._line = 0;\n },\n areaEnd: function() {\n this._line = NaN;\n },\n lineStart: function() {\n this._x0 = this._x1 =\n this._y0 = this._y1 = NaN;\n this._point = 0;\n },\n lineEnd: function() {\n switch (this._point) {\n case 3: point(this, this._x1, this._y1); // proceed\n case 2: this._context.lineTo(this._x1, this._y1); break;\n }\n if (this._line || (this._line !== 0 && this._point === 1)) this._context.closePath();\n this._line = 1 - this._line;\n },\n point: function(x, y) {\n x = +x, y = +y;\n switch (this._point) {\n case 0: this._point = 1; this._line ? this._context.lineTo(x, y) : this._context.moveTo(x, y); break;\n case 1: this._point = 2; break;\n case 2: this._point = 3; this._context.lineTo((5 * this._x0 + this._x1) / 6, (5 * this._y0 + this._y1) / 6); // proceed\n default: point(this, x, y); break;\n }\n this._x0 = this._x1, this._x1 = x;\n this._y0 = this._y1, this._y1 = y;\n }\n};\n\nexport default function(context) {\n return new Basis(context);\n}\n","import noop from \"../noop\";\nimport {point} from \"./basis\";\n\nfunction BasisClosed(context) {\n this._context = context;\n}\n\nBasisClosed.prototype = {\n areaStart: noop,\n areaEnd: noop,\n lineStart: function() {\n this._x0 = this._x1 = this._x2 = this._x3 = this._x4 =\n this._y0 = this._y1 = this._y2 = this._y3 = this._y4 = NaN;\n this._point = 0;\n },\n lineEnd: function() {\n switch (this._point) {\n case 1: {\n this._context.moveTo(this._x2, this._y2);\n this._context.closePath();\n break;\n }\n case 2: {\n this._context.moveTo((this._x2 + 2 * this._x3) / 3, (this._y2 + 2 * this._y3) / 3);\n this._context.lineTo((this._x3 + 2 * this._x2) / 3, (this._y3 + 2 * this._y2) / 3);\n this._context.closePath();\n break;\n }\n case 3: {\n this.point(this._x2, this._y2);\n this.point(this._x3, this._y3);\n this.point(this._x4, this._y4);\n break;\n }\n }\n },\n point: function(x, y) {\n x = +x, y = +y;\n switch (this._point) {\n case 0: this._point = 1; this._x2 = x, this._y2 = y; break;\n case 1: this._point = 2; this._x3 = x, this._y3 = y; break;\n case 2: this._point = 3; this._x4 = x, this._y4 = y; this._context.moveTo((this._x0 + 4 * this._x1 + x) / 6, (this._y0 + 4 * this._y1 + y) / 6); break;\n default: point(this, x, y); break;\n }\n this._x0 = this._x1, this._x1 = x;\n this._y0 = this._y1, this._y1 = y;\n }\n};\n\nexport default function(context) {\n return new BasisClosed(context);\n}\n","import {point} from \"./basis\";\n\nfunction BasisOpen(context) {\n this._context = context;\n}\n\nBasisOpen.prototype = {\n areaStart: function() {\n this._line = 0;\n },\n areaEnd: function() {\n this._line = NaN;\n },\n lineStart: function() {\n this._x0 = this._x1 =\n this._y0 = this._y1 = NaN;\n this._point = 0;\n },\n lineEnd: function() {\n if (this._line || (this._line !== 0 && this._point === 3)) this._context.closePath();\n this._line = 1 - this._line;\n },\n point: function(x, y) {\n x = +x, y = +y;\n switch (this._point) {\n case 0: this._point = 1; break;\n case 1: this._point = 2; break;\n case 2: this._point = 3; var x0 = (this._x0 + 4 * this._x1 + x) / 6, y0 = (this._y0 + 4 * this._y1 + y) / 6; this._line ? this._context.lineTo(x0, y0) : this._context.moveTo(x0, y0); break;\n case 3: this._point = 4; // proceed\n default: point(this, x, y); break;\n }\n this._x0 = this._x1, this._x1 = x;\n this._y0 = this._y1, this._y1 = y;\n }\n};\n\nexport default function(context) {\n return new BasisOpen(context);\n}\n","import {Basis} from \"./basis\";\n\nfunction Bundle(context, beta) {\n this._basis = new Basis(context);\n this._beta = beta;\n}\n\nBundle.prototype = {\n lineStart: function() {\n this._x = [];\n this._y = [];\n this._basis.lineStart();\n },\n lineEnd: function() {\n var x = this._x,\n y = this._y,\n j = x.length - 1;\n\n if (j > 0) {\n var x0 = x[0],\n y0 = y[0],\n dx = x[j] - x0,\n dy = y[j] - y0,\n i = -1,\n t;\n\n while (++i <= j) {\n t = i / j;\n this._basis.point(\n this._beta * x[i] + (1 - this._beta) * (x0 + t * dx),\n this._beta * y[i] + (1 - this._beta) * (y0 + t * dy)\n );\n }\n }\n\n this._x = this._y = null;\n this._basis.lineEnd();\n },\n point: function(x, y) {\n this._x.push(+x);\n this._y.push(+y);\n }\n};\n\nexport default (function custom(beta) {\n\n function bundle(context) {\n return beta === 1 ? new Basis(context) : new Bundle(context, beta);\n }\n\n bundle.beta = function(beta) {\n return custom(+beta);\n };\n\n return bundle;\n})(0.85);\n","export function point(that, x, y) {\n that._context.bezierCurveTo(\n that._x1 + that._k * (that._x2 - that._x0),\n that._y1 + that._k * (that._y2 - that._y0),\n that._x2 + that._k * (that._x1 - x),\n that._y2 + that._k * (that._y1 - y),\n that._x2,\n that._y2\n );\n}\n\nexport function Cardinal(context, tension) {\n this._context = context;\n this._k = (1 - tension) / 6;\n}\n\nCardinal.prototype = {\n areaStart: function() {\n this._line = 0;\n },\n areaEnd: function() {\n this._line = NaN;\n },\n lineStart: function() {\n this._x0 = this._x1 = this._x2 =\n this._y0 = this._y1 = this._y2 = NaN;\n this._point = 0;\n },\n lineEnd: function() {\n switch (this._point) {\n case 2: this._context.lineTo(this._x2, this._y2); break;\n case 3: point(this, this._x1, this._y1); break;\n }\n if (this._line || (this._line !== 0 && this._point === 1)) this._context.closePath();\n this._line = 1 - this._line;\n },\n point: function(x, y) {\n x = +x, y = +y;\n switch (this._point) {\n case 0: this._point = 1; this._line ? this._context.lineTo(x, y) : this._context.moveTo(x, y); break;\n case 1: this._point = 2; this._x1 = x, this._y1 = y; break;\n case 2: this._point = 3; // proceed\n default: point(this, x, y); break;\n }\n this._x0 = this._x1, this._x1 = this._x2, this._x2 = x;\n this._y0 = this._y1, this._y1 = this._y2, this._y2 = y;\n }\n};\n\nexport default (function custom(tension) {\n\n function cardinal(context) {\n return new Cardinal(context, tension);\n }\n\n cardinal.tension = function(tension) {\n return custom(+tension);\n };\n\n return cardinal;\n})(0);\n","import noop from \"../noop\";\nimport {point} from \"./cardinal\";\n\nexport function CardinalClosed(context, tension) {\n this._context = context;\n this._k = (1 - tension) / 6;\n}\n\nCardinalClosed.prototype = {\n areaStart: noop,\n areaEnd: noop,\n lineStart: function() {\n this._x0 = this._x1 = this._x2 = this._x3 = this._x4 = this._x5 =\n this._y0 = this._y1 = this._y2 = this._y3 = this._y4 = this._y5 = NaN;\n this._point = 0;\n },\n lineEnd: function() {\n switch (this._point) {\n case 1: {\n this._context.moveTo(this._x3, this._y3);\n this._context.closePath();\n break;\n }\n case 2: {\n this._context.lineTo(this._x3, this._y3);\n this._context.closePath();\n break;\n }\n case 3: {\n this.point(this._x3, this._y3);\n this.point(this._x4, this._y4);\n this.point(this._x5, this._y5);\n break;\n }\n }\n },\n point: function(x, y) {\n x = +x, y = +y;\n switch (this._point) {\n case 0: this._point = 1; this._x3 = x, this._y3 = y; break;\n case 1: this._point = 2; this._context.moveTo(this._x4 = x, this._y4 = y); break;\n case 2: this._point = 3; this._x5 = x, this._y5 = y; break;\n default: point(this, x, y); break;\n }\n this._x0 = this._x1, this._x1 = this._x2, this._x2 = x;\n this._y0 = this._y1, this._y1 = this._y2, this._y2 = y;\n }\n};\n\nexport default (function custom(tension) {\n\n function cardinal(context) {\n return new CardinalClosed(context, tension);\n }\n\n cardinal.tension = function(tension) {\n return custom(+tension);\n };\n\n return cardinal;\n})(0);\n","import {point} from \"./cardinal\";\n\nexport function CardinalOpen(context, tension) {\n this._context = context;\n this._k = (1 - tension) / 6;\n}\n\nCardinalOpen.prototype = {\n areaStart: function() {\n this._line = 0;\n },\n areaEnd: function() {\n this._line = NaN;\n },\n lineStart: function() {\n this._x0 = this._x1 = this._x2 =\n this._y0 = this._y1 = this._y2 = NaN;\n this._point = 0;\n },\n lineEnd: function() {\n if (this._line || (this._line !== 0 && this._point === 3)) this._context.closePath();\n this._line = 1 - this._line;\n },\n point: function(x, y) {\n x = +x, y = +y;\n switch (this._point) {\n case 0: this._point = 1; break;\n case 1: this._point = 2; break;\n case 2: this._point = 3; this._line ? this._context.lineTo(this._x2, this._y2) : this._context.moveTo(this._x2, this._y2); break;\n case 3: this._point = 4; // proceed\n default: point(this, x, y); break;\n }\n this._x0 = this._x1, this._x1 = this._x2, this._x2 = x;\n this._y0 = this._y1, this._y1 = this._y2, this._y2 = y;\n }\n};\n\nexport default (function custom(tension) {\n\n function cardinal(context) {\n return new CardinalOpen(context, tension);\n }\n\n cardinal.tension = function(tension) {\n return custom(+tension);\n };\n\n return cardinal;\n})(0);\n","import {epsilon} from \"../math\";\nimport {Cardinal} from \"./cardinal\";\n\nexport function point(that, x, y) {\n var x1 = that._x1,\n y1 = that._y1,\n x2 = that._x2,\n y2 = that._y2;\n\n if (that._l01_a > epsilon) {\n var a = 2 * that._l01_2a + 3 * that._l01_a * that._l12_a + that._l12_2a,\n n = 3 * that._l01_a * (that._l01_a + that._l12_a);\n x1 = (x1 * a - that._x0 * that._l12_2a + that._x2 * that._l01_2a) / n;\n y1 = (y1 * a - that._y0 * that._l12_2a + that._y2 * that._l01_2a) / n;\n }\n\n if (that._l23_a > epsilon) {\n var b = 2 * that._l23_2a + 3 * that._l23_a * that._l12_a + that._l12_2a,\n m = 3 * that._l23_a * (that._l23_a + that._l12_a);\n x2 = (x2 * b + that._x1 * that._l23_2a - x * that._l12_2a) / m;\n y2 = (y2 * b + that._y1 * that._l23_2a - y * that._l12_2a) / m;\n }\n\n that._context.bezierCurveTo(x1, y1, x2, y2, that._x2, that._y2);\n}\n\nfunction CatmullRom(context, alpha) {\n this._context = context;\n this._alpha = alpha;\n}\n\nCatmullRom.prototype = {\n areaStart: function() {\n this._line = 0;\n },\n areaEnd: function() {\n this._line = NaN;\n },\n lineStart: function() {\n this._x0 = this._x1 = this._x2 =\n this._y0 = this._y1 = this._y2 = NaN;\n this._l01_a = this._l12_a = this._l23_a =\n this._l01_2a = this._l12_2a = this._l23_2a =\n this._point = 0;\n },\n lineEnd: function() {\n switch (this._point) {\n case 2: this._context.lineTo(this._x2, this._y2); break;\n case 3: this.point(this._x2, this._y2); break;\n }\n if (this._line || (this._line !== 0 && this._point === 1)) this._context.closePath();\n this._line = 1 - this._line;\n },\n point: function(x, y) {\n x = +x, y = +y;\n\n if (this._point) {\n var x23 = this._x2 - x,\n y23 = this._y2 - y;\n this._l23_a = Math.sqrt(this._l23_2a = Math.pow(x23 * x23 + y23 * y23, this._alpha));\n }\n\n switch (this._point) {\n case 0: this._point = 1; this._line ? this._context.lineTo(x, y) : this._context.moveTo(x, y); break;\n case 1: this._point = 2; break;\n case 2: this._point = 3; // proceed\n default: point(this, x, y); break;\n }\n\n this._l01_a = this._l12_a, this._l12_a = this._l23_a;\n this._l01_2a = this._l12_2a, this._l12_2a = this._l23_2a;\n this._x0 = this._x1, this._x1 = this._x2, this._x2 = x;\n this._y0 = this._y1, this._y1 = this._y2, this._y2 = y;\n }\n};\n\nexport default (function custom(alpha) {\n\n function catmullRom(context) {\n return alpha ? new CatmullRom(context, alpha) : new Cardinal(context, 0);\n }\n\n catmullRom.alpha = function(alpha) {\n return custom(+alpha);\n };\n\n return catmullRom;\n})(0.5);\n","import {CardinalClosed} from \"./cardinalClosed\";\nimport noop from \"../noop\";\nimport {point} from \"./catmullRom\";\n\nfunction CatmullRomClosed(context, alpha) {\n this._context = context;\n this._alpha = alpha;\n}\n\nCatmullRomClosed.prototype = {\n areaStart: noop,\n areaEnd: noop,\n lineStart: function() {\n this._x0 = this._x1 = this._x2 = this._x3 = this._x4 = this._x5 =\n this._y0 = this._y1 = this._y2 = this._y3 = this._y4 = this._y5 = NaN;\n this._l01_a = this._l12_a = this._l23_a =\n this._l01_2a = this._l12_2a = this._l23_2a =\n this._point = 0;\n },\n lineEnd: function() {\n switch (this._point) {\n case 1: {\n this._context.moveTo(this._x3, this._y3);\n this._context.closePath();\n break;\n }\n case 2: {\n this._context.lineTo(this._x3, this._y3);\n this._context.closePath();\n break;\n }\n case 3: {\n this.point(this._x3, this._y3);\n this.point(this._x4, this._y4);\n this.point(this._x5, this._y5);\n break;\n }\n }\n },\n point: function(x, y) {\n x = +x, y = +y;\n\n if (this._point) {\n var x23 = this._x2 - x,\n y23 = this._y2 - y;\n this._l23_a = Math.sqrt(this._l23_2a = Math.pow(x23 * x23 + y23 * y23, this._alpha));\n }\n\n switch (this._point) {\n case 0: this._point = 1; this._x3 = x, this._y3 = y; break;\n case 1: this._point = 2; this._context.moveTo(this._x4 = x, this._y4 = y); break;\n case 2: this._point = 3; this._x5 = x, this._y5 = y; break;\n default: point(this, x, y); break;\n }\n\n this._l01_a = this._l12_a, this._l12_a = this._l23_a;\n this._l01_2a = this._l12_2a, this._l12_2a = this._l23_2a;\n this._x0 = this._x1, this._x1 = this._x2, this._x2 = x;\n this._y0 = this._y1, this._y1 = this._y2, this._y2 = y;\n }\n};\n\nexport default (function custom(alpha) {\n\n function catmullRom(context) {\n return alpha ? new CatmullRomClosed(context, alpha) : new CardinalClosed(context, 0);\n }\n\n catmullRom.alpha = function(alpha) {\n return custom(+alpha);\n };\n\n return catmullRom;\n})(0.5);\n","import {CardinalOpen} from \"./cardinalOpen\";\nimport {point} from \"./catmullRom\";\n\nfunction CatmullRomOpen(context, alpha) {\n this._context = context;\n this._alpha = alpha;\n}\n\nCatmullRomOpen.prototype = {\n areaStart: function() {\n this._line = 0;\n },\n areaEnd: function() {\n this._line = NaN;\n },\n lineStart: function() {\n this._x0 = this._x1 = this._x2 =\n this._y0 = this._y1 = this._y2 = NaN;\n this._l01_a = this._l12_a = this._l23_a =\n this._l01_2a = this._l12_2a = this._l23_2a =\n this._point = 0;\n },\n lineEnd: function() {\n if (this._line || (this._line !== 0 && this._point === 3)) this._context.closePath();\n this._line = 1 - this._line;\n },\n point: function(x, y) {\n x = +x, y = +y;\n\n if (this._point) {\n var x23 = this._x2 - x,\n y23 = this._y2 - y;\n this._l23_a = Math.sqrt(this._l23_2a = Math.pow(x23 * x23 + y23 * y23, this._alpha));\n }\n\n switch (this._point) {\n case 0: this._point = 1; break;\n case 1: this._point = 2; break;\n case 2: this._point = 3; this._line ? this._context.lineTo(this._x2, this._y2) : this._context.moveTo(this._x2, this._y2); break;\n case 3: this._point = 4; // proceed\n default: point(this, x, y); break;\n }\n\n this._l01_a = this._l12_a, this._l12_a = this._l23_a;\n this._l01_2a = this._l12_2a, this._l12_2a = this._l23_2a;\n this._x0 = this._x1, this._x1 = this._x2, this._x2 = x;\n this._y0 = this._y1, this._y1 = this._y2, this._y2 = y;\n }\n};\n\nexport default (function custom(alpha) {\n\n function catmullRom(context) {\n return alpha ? new CatmullRomOpen(context, alpha) : new CardinalOpen(context, 0);\n }\n\n catmullRom.alpha = function(alpha) {\n return custom(+alpha);\n };\n\n return catmullRom;\n})(0.5);\n","import noop from \"../noop\";\n\nfunction LinearClosed(context) {\n this._context = context;\n}\n\nLinearClosed.prototype = {\n areaStart: noop,\n areaEnd: noop,\n lineStart: function() {\n this._point = 0;\n },\n lineEnd: function() {\n if (this._point) this._context.closePath();\n },\n point: function(x, y) {\n x = +x, y = +y;\n if (this._point) this._context.lineTo(x, y);\n else this._point = 1, this._context.moveTo(x, y);\n }\n};\n\nexport default function(context) {\n return new LinearClosed(context);\n}\n","function sign(x) {\n return x < 0 ? -1 : 1;\n}\n\n// Calculate the slopes of the tangents (Hermite-type interpolation) based on\n// the following paper: Steffen, M. 1990. A Simple Method for Monotonic\n// Interpolation in One Dimension. Astronomy and Astrophysics, Vol. 239, NO.\n// NOV(II), P. 443, 1990.\nfunction slope3(that, x2, y2) {\n var h0 = that._x1 - that._x0,\n h1 = x2 - that._x1,\n s0 = (that._y1 - that._y0) / (h0 || h1 < 0 && -0),\n s1 = (y2 - that._y1) / (h1 || h0 < 0 && -0),\n p = (s0 * h1 + s1 * h0) / (h0 + h1);\n return (sign(s0) + sign(s1)) * Math.min(Math.abs(s0), Math.abs(s1), 0.5 * Math.abs(p)) || 0;\n}\n\n// Calculate a one-sided slope.\nfunction slope2(that, t) {\n var h = that._x1 - that._x0;\n return h ? (3 * (that._y1 - that._y0) / h - t) / 2 : t;\n}\n\n// According to https://en.wikipedia.org/wiki/Cubic_Hermite_spline#Representations\n// \"you can express cubic Hermite interpolation in terms of cubic Bézier curves\n// with respect to the four values p0, p0 + m0 / 3, p1 - m1 / 3, p1\".\nfunction point(that, t0, t1) {\n var x0 = that._x0,\n y0 = that._y0,\n x1 = that._x1,\n y1 = that._y1,\n dx = (x1 - x0) / 3;\n that._context.bezierCurveTo(x0 + dx, y0 + dx * t0, x1 - dx, y1 - dx * t1, x1, y1);\n}\n\nfunction MonotoneX(context) {\n this._context = context;\n}\n\nMonotoneX.prototype = {\n areaStart: function() {\n this._line = 0;\n },\n areaEnd: function() {\n this._line = NaN;\n },\n lineStart: function() {\n this._x0 = this._x1 =\n this._y0 = this._y1 =\n this._t0 = NaN;\n this._point = 0;\n },\n lineEnd: function() {\n switch (this._point) {\n case 2: this._context.lineTo(this._x1, this._y1); break;\n case 3: point(this, this._t0, slope2(this, this._t0)); break;\n }\n if (this._line || (this._line !== 0 && this._point === 1)) this._context.closePath();\n this._line = 1 - this._line;\n },\n point: function(x, y) {\n var t1 = NaN;\n\n x = +x, y = +y;\n if (x === this._x1 && y === this._y1) return; // Ignore coincident points.\n switch (this._point) {\n case 0: this._point = 1; this._line ? this._context.lineTo(x, y) : this._context.moveTo(x, y); break;\n case 1: this._point = 2; break;\n case 2: this._point = 3; point(this, slope2(this, t1 = slope3(this, x, y)), t1); break;\n default: point(this, this._t0, t1 = slope3(this, x, y)); break;\n }\n\n this._x0 = this._x1, this._x1 = x;\n this._y0 = this._y1, this._y1 = y;\n this._t0 = t1;\n }\n}\n\nfunction MonotoneY(context) {\n this._context = new ReflectContext(context);\n}\n\n(MonotoneY.prototype = Object.create(MonotoneX.prototype)).point = function(x, y) {\n MonotoneX.prototype.point.call(this, y, x);\n};\n\nfunction ReflectContext(context) {\n this._context = context;\n}\n\nReflectContext.prototype = {\n moveTo: function(x, y) { this._context.moveTo(y, x); },\n closePath: function() { this._context.closePath(); },\n lineTo: function(x, y) { this._context.lineTo(y, x); },\n bezierCurveTo: function(x1, y1, x2, y2, x, y) { this._context.bezierCurveTo(y1, x1, y2, x2, y, x); }\n};\n\nexport function monotoneX(context) {\n return new MonotoneX(context);\n}\n\nexport function monotoneY(context) {\n return new MonotoneY(context);\n}\n","function Natural(context) {\n this._context = context;\n}\n\nNatural.prototype = {\n areaStart: function() {\n this._line = 0;\n },\n areaEnd: function() {\n this._line = NaN;\n },\n lineStart: function() {\n this._x = [];\n this._y = [];\n },\n lineEnd: function() {\n var x = this._x,\n y = this._y,\n n = x.length;\n\n if (n) {\n this._line ? this._context.lineTo(x[0], y[0]) : this._context.moveTo(x[0], y[0]);\n if (n === 2) {\n this._context.lineTo(x[1], y[1]);\n } else {\n var px = controlPoints(x),\n py = controlPoints(y);\n for (var i0 = 0, i1 = 1; i1 < n; ++i0, ++i1) {\n this._context.bezierCurveTo(px[0][i0], py[0][i0], px[1][i0], py[1][i0], x[i1], y[i1]);\n }\n }\n }\n\n if (this._line || (this._line !== 0 && n === 1)) this._context.closePath();\n this._line = 1 - this._line;\n this._x = this._y = null;\n },\n point: function(x, y) {\n this._x.push(+x);\n this._y.push(+y);\n }\n};\n\n// See https://www.particleincell.com/2012/bezier-splines/ for derivation.\nfunction controlPoints(x) {\n var i,\n n = x.length - 1,\n m,\n a = new Array(n),\n b = new Array(n),\n r = new Array(n);\n a[0] = 0, b[0] = 2, r[0] = x[0] + 2 * x[1];\n for (i = 1; i < n - 1; ++i) a[i] = 1, b[i] = 4, r[i] = 4 * x[i] + 2 * x[i + 1];\n a[n - 1] = 2, b[n - 1] = 7, r[n - 1] = 8 * x[n - 1] + x[n];\n for (i = 1; i < n; ++i) m = a[i] / b[i - 1], b[i] -= m, r[i] -= m * r[i - 1];\n a[n - 1] = r[n - 1] / b[n - 1];\n for (i = n - 2; i >= 0; --i) a[i] = (r[i] - a[i + 1]) / b[i];\n b[n - 1] = (x[n] + a[n - 1]) / 2;\n for (i = 0; i < n - 1; ++i) b[i] = 2 * x[i + 1] - a[i + 1];\n return [a, b];\n}\n\nexport default function(context) {\n return new Natural(context);\n}\n","function Step(context, t) {\n this._context = context;\n this._t = t;\n}\n\nStep.prototype = {\n areaStart: function() {\n this._line = 0;\n },\n areaEnd: function() {\n this._line = NaN;\n },\n lineStart: function() {\n this._x = this._y = NaN;\n this._point = 0;\n },\n lineEnd: function() {\n if (0 < this._t && this._t < 1 && this._point === 2) this._context.lineTo(this._x, this._y);\n if (this._line || (this._line !== 0 && this._point === 1)) this._context.closePath();\n if (this._line >= 0) this._t = 1 - this._t, this._line = 1 - this._line;\n },\n point: function(x, y) {\n x = +x, y = +y;\n switch (this._point) {\n case 0: this._point = 1; this._line ? this._context.lineTo(x, y) : this._context.moveTo(x, y); break;\n case 1: this._point = 2; // proceed\n default: {\n if (this._t <= 0) {\n this._context.lineTo(this._x, y);\n this._context.lineTo(x, y);\n } else {\n var x1 = this._x * (1 - this._t) + x * this._t;\n this._context.lineTo(x1, this._y);\n this._context.lineTo(x1, y);\n }\n break;\n }\n }\n this._x = x, this._y = y;\n }\n};\n\nexport default function(context) {\n return new Step(context, 0.5);\n}\n\nexport function stepBefore(context) {\n return new Step(context, 0);\n}\n\nexport function stepAfter(context) {\n return new Step(context, 1);\n}\n","import ascending from \"./ascending\";\n\nexport default function(series) {\n return ascending(series).reverse();\n}\n","import { arc as arcFactory } from \"d3-shape\";\n\nimport {\n LinkedVisualConsoleProps,\n UnknownObject,\n WithModuleProps\n} from \"../types\";\nimport {\n linkedVCPropsDecoder,\n modulePropsDecoder,\n notEmptyStringOr,\n parseIntOr,\n parseFloatOr\n} from \"../lib\";\nimport Item, { ItemType, ItemProps, itemBasePropsDecoder } from \"../Item\";\n\nexport type PercentileProps = {\n type: ItemType.PERCENTILE_BAR;\n percentileType:\n | \"progress-bar\"\n | \"bubble\"\n | \"circular-progress-bar\"\n | \"circular-progress-bar-alt\";\n valueType: \"percent\" | \"value\";\n minValue: number | null;\n maxValue: number | null;\n color: string | null;\n labelColor: string | null;\n value: number | null;\n unit: string | null;\n} & ItemProps &\n WithModuleProps &\n LinkedVisualConsoleProps;\n\n/**\n * Extract a valid enum value from a raw type value.\n * @param type Raw value.\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nfunction extractPercentileType(type: any): PercentileProps[\"percentileType\"] {\n switch (type) {\n case \"progress-bar\":\n case \"bubble\":\n case \"circular-progress-bar\":\n case \"circular-progress-bar-alt\":\n return type;\n default:\n case ItemType.PERCENTILE_BAR:\n return \"progress-bar\";\n case ItemType.PERCENTILE_BUBBLE:\n return \"bubble\";\n case ItemType.CIRCULAR_PROGRESS_BAR:\n return \"circular-progress-bar\";\n case ItemType.CIRCULAR_INTERIOR_PROGRESS_BAR:\n return \"circular-progress-bar-alt\";\n }\n}\n\n/**\n * Extract a valid enum value from a raw value type value.\n * @param type Raw value.\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nfunction extractValueType(valueType: any): PercentileProps[\"valueType\"] {\n switch (valueType) {\n case \"percent\":\n case \"value\":\n return valueType;\n default:\n return \"percent\";\n }\n}\n\n/**\n * Build a valid typed object from a raw object.\n * This will allow us to ensure the type safety.\n *\n * @param data Raw object.\n * @return An object representing the percentile props.\n * @throws Will throw a TypeError if some property\n * is missing from the raw object or have an invalid type.\n */\nexport function percentilePropsDecoder(\n data: UnknownObject\n): PercentileProps | never {\n return {\n ...itemBasePropsDecoder(data), // Object spread. It will merge the properties of the two objects.\n type: ItemType.PERCENTILE_BAR,\n percentileType: extractPercentileType(data.percentileType || data.type),\n valueType: extractValueType(data.valueType),\n minValue: parseIntOr(data.minValue, null),\n maxValue: parseIntOr(data.maxValue, null),\n color: notEmptyStringOr(data.color, null),\n labelColor: notEmptyStringOr(data.labelColor, null),\n value: parseFloatOr(data.value, null),\n unit: notEmptyStringOr(data.unit, null),\n ...modulePropsDecoder(data), // Object spread. It will merge the properties of the two objects.\n ...linkedVCPropsDecoder(data) // Object spread. It will merge the properties of the two objects.\n };\n}\n\nconst svgNS = \"http://www.w3.org/2000/svg\";\n\nexport default class Percentile extends Item {\n protected createDomElement(): HTMLElement {\n const colors = {\n background: \"#000000\",\n progress: this.props.color || \"#F0F0F0\",\n text: this.props.labelColor || \"#444444\"\n };\n // Progress.\n const progress = this.getProgress();\n // Main element.\n const element = document.createElement(\"div\");\n // SVG container.\n const svg = document.createElementNS(svgNS, \"svg\");\n\n switch (this.props.percentileType) {\n case \"progress-bar\":\n {\n const backgroundRect = document.createElementNS(svgNS, \"rect\");\n backgroundRect.setAttribute(\"fill\", colors.background);\n backgroundRect.setAttribute(\"fill-opacity\", \"0.5\");\n backgroundRect.setAttribute(\"width\", \"100\");\n backgroundRect.setAttribute(\"height\", \"20\");\n backgroundRect.setAttribute(\"rx\", \"5\");\n backgroundRect.setAttribute(\"ry\", \"5\");\n const progressRect = document.createElementNS(svgNS, \"rect\");\n progressRect.setAttribute(\"fill\", colors.progress);\n progressRect.setAttribute(\"fill-opacity\", \"1\");\n progressRect.setAttribute(\"width\", `${progress}`);\n progressRect.setAttribute(\"height\", \"20\");\n progressRect.setAttribute(\"rx\", \"5\");\n progressRect.setAttribute(\"ry\", \"5\");\n const text = document.createElementNS(svgNS, \"text\");\n text.setAttribute(\"text-anchor\", \"middle\");\n text.setAttribute(\"alignment-baseline\", \"middle\");\n text.setAttribute(\"font-size\", \"12\");\n text.setAttribute(\"font-family\", \"arial\");\n text.setAttribute(\"font-weight\", \"bold\");\n text.setAttribute(\"transform\", \"translate(50 11)\");\n text.setAttribute(\"fill\", colors.text);\n\n if (this.props.valueType === \"value\") {\n text.textContent = this.props.unit\n ? `${this.props.value} ${this.props.unit}`\n : `${this.props.value}`;\n } else {\n text.textContent = `${progress}%`;\n }\n\n // Auto resize SVG using the view box magic: https://css-tricks.com/scale-svg/\n svg.setAttribute(\"viewBox\", \"0 0 100 20\");\n svg.append(backgroundRect, progressRect, text);\n }\n break;\n case \"bubble\":\n case \"circular-progress-bar\":\n case \"circular-progress-bar-alt\":\n {\n // Auto resize SVG using the view box magic: https://css-tricks.com/scale-svg/\n svg.setAttribute(\"viewBox\", \"0 0 100 100\");\n\n if (this.props.percentileType === \"bubble\") {\n // Create and append the circles.\n const backgroundCircle = document.createElementNS(svgNS, \"circle\");\n backgroundCircle.setAttribute(\"transform\", \"translate(50 50)\");\n backgroundCircle.setAttribute(\"fill\", colors.background);\n backgroundCircle.setAttribute(\"fill-opacity\", \"0.5\");\n backgroundCircle.setAttribute(\"r\", \"50\");\n const progressCircle = document.createElementNS(svgNS, \"circle\");\n progressCircle.setAttribute(\"transform\", \"translate(50 50)\");\n progressCircle.setAttribute(\"fill\", colors.progress);\n progressCircle.setAttribute(\"fill-opacity\", \"1\");\n progressCircle.setAttribute(\"r\", `${progress / 2}`);\n\n svg.append(backgroundCircle, progressCircle);\n } else {\n // Create and append the circles.\n const arcProps = {\n innerRadius:\n this.props.percentileType === \"circular-progress-bar\" ? 30 : 0,\n outerRadius: 50,\n startAngle: 0,\n endAngle: Math.PI * 2\n };\n const arc = arcFactory();\n\n const backgroundCircle = document.createElementNS(svgNS, \"path\");\n backgroundCircle.setAttribute(\"transform\", \"translate(50 50)\");\n backgroundCircle.setAttribute(\"fill\", colors.background);\n backgroundCircle.setAttribute(\"fill-opacity\", \"0.5\");\n backgroundCircle.setAttribute(\"d\", `${arc(arcProps)}`);\n const progressCircle = document.createElementNS(svgNS, \"path\");\n progressCircle.setAttribute(\"transform\", \"translate(50 50)\");\n progressCircle.setAttribute(\"fill\", colors.progress);\n progressCircle.setAttribute(\"fill-opacity\", \"1\");\n progressCircle.setAttribute(\n \"d\",\n `${arc({\n ...arcProps,\n endAngle: arcProps.endAngle * (progress / 100)\n })}`\n );\n\n svg.append(backgroundCircle, progressCircle);\n }\n\n // Create and append the text.\n const text = document.createElementNS(svgNS, \"text\");\n text.setAttribute(\"text-anchor\", \"middle\");\n text.setAttribute(\"alignment-baseline\", \"middle\");\n text.setAttribute(\"font-size\", \"16\");\n text.setAttribute(\"font-family\", \"arial\");\n text.setAttribute(\"font-weight\", \"bold\");\n text.setAttribute(\"fill\", colors.text);\n\n if (this.props.valueType === \"value\") {\n // Show value and unit in 1 (no unit) or 2 lines.\n if (this.props.unit && this.props.unit.length > 0) {\n const value = document.createElementNS(svgNS, \"tspan\");\n value.setAttribute(\"x\", \"0\");\n value.setAttribute(\"dy\", \"1em\");\n value.textContent = `${this.props.value}`;\n const unit = document.createElementNS(svgNS, \"tspan\");\n unit.setAttribute(\"x\", \"0\");\n unit.setAttribute(\"dy\", \"1em\");\n unit.textContent = `${this.props.unit}`;\n text.append(value, unit);\n text.setAttribute(\"transform\", \"translate(50 33)\");\n } else {\n text.textContent = `${this.props.value}`;\n text.setAttribute(\"transform\", \"translate(50 50)\");\n }\n } else {\n // Percentage.\n text.textContent = `${progress}%`;\n text.setAttribute(\"transform\", \"translate(50 50)\");\n }\n\n svg.append(text);\n }\n break;\n }\n\n element.append(svg);\n\n return element;\n }\n\n private getProgress(): number {\n const minValue = this.props.minValue || 0;\n const maxValue = this.props.maxValue || 100;\n const value = this.props.value == null ? 0 : this.props.value;\n\n if (value <= minValue) return 0;\n else if (value >= maxValue) return 100;\n else return Math.trunc(((value - minValue) / (maxValue - minValue)) * 100);\n }\n}\n","import { UnknownObject } from \"../types\";\nimport {\n stringIsEmpty,\n notEmptyStringOr,\n decodeBase64,\n parseIntOr\n} from \"../lib\";\nimport Item, { ItemType, ItemProps, itemBasePropsDecoder } from \"../Item\";\n\nexport type ServiceProps = {\n type: ItemType.SERVICE;\n serviceId: number;\n imageSrc: string | null;\n statusImageSrc: string | null;\n encodedTitle: string | null;\n} & ItemProps;\n\n/**\n * Build a valid typed object from a raw object.\n * This will allow us to ensure the type safety.\n *\n * @param data Raw object.\n * @return An object representing the service props.\n * @throws Will throw a TypeError if some property\n * is missing from the raw object or have an invalid type.\n */\nexport function servicePropsDecoder(data: UnknownObject): ServiceProps | never {\n if (data.imageSrc !== null) {\n if (\n typeof data.statusImageSrc !== \"string\" ||\n data.imageSrc.statusImageSrc === 0\n ) {\n throw new TypeError(\"invalid status image src.\");\n }\n } else {\n if (stringIsEmpty(data.encodedTitle)) {\n throw new TypeError(\"missing encode tittle content.\");\n }\n }\n\n if (parseIntOr(data.serviceId, null) === null) {\n throw new TypeError(\"invalid service id.\");\n }\n\n return {\n ...itemBasePropsDecoder(data), // Object spread. It will merge the properties of the two objects.\n type: ItemType.SERVICE,\n serviceId: data.serviceId,\n imageSrc: notEmptyStringOr(data.imageSrc, null),\n statusImageSrc: notEmptyStringOr(data.statusImageSrc, null),\n encodedTitle: notEmptyStringOr(data.encodedTitle, null)\n };\n}\n\nexport default class Service extends Item {\n public createDomElement(): HTMLElement {\n const element = document.createElement(\"div\");\n element.className = \"service\";\n\n if (this.props.statusImageSrc !== null) {\n element.style.background = `url(${this.props.statusImageSrc}) no-repeat`;\n element.style.backgroundSize = \"contain\";\n element.style.backgroundPosition = \"center\";\n } else if (this.props.encodedTitle !== null) {\n element.innerHTML = decodeBase64(this.props.encodedTitle);\n }\n\n return element;\n }\n}\n","import { UnknownObject, Size } from \"./types\";\nimport {\n parseBoolean,\n sizePropsDecoder,\n parseIntOr,\n notEmptyStringOr\n} from \"./lib\";\nimport Item, {\n ItemType,\n ItemProps,\n ItemClickEvent,\n ItemRemoveEvent\n} from \"./Item\";\nimport StaticGraph, { staticGraphPropsDecoder } from \"./items/StaticGraph\";\nimport Icon, { iconPropsDecoder } from \"./items/Icon\";\nimport ColorCloud, { colorCloudPropsDecoder } from \"./items/ColorCloud\";\nimport Group, { groupPropsDecoder } from \"./items/Group\";\nimport Clock, { clockPropsDecoder } from \"./items/Clock\";\nimport Box, { boxPropsDecoder } from \"./items/Box\";\nimport Line, { linePropsDecoder } from \"./items/Line\";\nimport Label, { labelPropsDecoder } from \"./items/Label\";\nimport SimpleValue, { simpleValuePropsDecoder } from \"./items/SimpleValue\";\nimport EventsHistory, {\n eventsHistoryPropsDecoder\n} from \"./items/EventsHistory\";\nimport Percentile, { percentilePropsDecoder } from \"./items/Percentile\";\nimport TypedEvent, { Disposable, Listener } from \"./TypedEvent\";\nimport DonutGraph, { donutGraphPropsDecoder } from \"./items/DonutGraph\";\nimport BarsGraph, { barsGraphPropsDecoder } from \"./items/BarsGraph\";\nimport ModuleGraph, { moduleGraphPropsDecoder } from \"./items/ModuleGraph\";\nimport Service, { servicePropsDecoder } from \"./items/Service\";\n\n// TODO: Document.\n// eslint-disable-next-line @typescript-eslint/explicit-function-return-type\nfunction itemInstanceFrom(data: UnknownObject) {\n const type = parseIntOr(data.type, null);\n if (type == null) throw new TypeError(\"missing item type.\");\n\n switch (type as ItemType) {\n case ItemType.STATIC_GRAPH:\n return new StaticGraph(staticGraphPropsDecoder(data));\n case ItemType.MODULE_GRAPH:\n return new ModuleGraph(moduleGraphPropsDecoder(data));\n case ItemType.SIMPLE_VALUE:\n case ItemType.SIMPLE_VALUE_MAX:\n case ItemType.SIMPLE_VALUE_MIN:\n case ItemType.SIMPLE_VALUE_AVG:\n return new SimpleValue(simpleValuePropsDecoder(data));\n case ItemType.PERCENTILE_BAR:\n case ItemType.PERCENTILE_BUBBLE:\n case ItemType.CIRCULAR_PROGRESS_BAR:\n case ItemType.CIRCULAR_INTERIOR_PROGRESS_BAR:\n return new Percentile(percentilePropsDecoder(data));\n case ItemType.LABEL:\n return new Label(labelPropsDecoder(data));\n case ItemType.ICON:\n return new Icon(iconPropsDecoder(data));\n case ItemType.SERVICE:\n return new Service(servicePropsDecoder(data));\n case ItemType.GROUP_ITEM:\n return new Group(groupPropsDecoder(data));\n case ItemType.BOX_ITEM:\n return new Box(boxPropsDecoder(data));\n case ItemType.LINE_ITEM:\n return new Line(linePropsDecoder(data));\n case ItemType.AUTO_SLA_GRAPH:\n return new EventsHistory(eventsHistoryPropsDecoder(data));\n case ItemType.DONUT_GRAPH:\n return new DonutGraph(donutGraphPropsDecoder(data));\n case ItemType.BARS_GRAPH:\n return new BarsGraph(barsGraphPropsDecoder(data));\n case ItemType.CLOCK:\n return new Clock(clockPropsDecoder(data));\n case ItemType.COLOR_CLOUD:\n return new ColorCloud(colorCloudPropsDecoder(data));\n default:\n throw new TypeError(\"item not found\");\n }\n}\n\n// TODO: Document.\n// eslint-disable-next-line @typescript-eslint/explicit-function-return-type\nfunction decodeProps(data: UnknownObject) {\n const type = parseIntOr(data.type, null);\n if (type == null) throw new TypeError(\"missing item type.\");\n\n switch (type as ItemType) {\n case ItemType.STATIC_GRAPH:\n return staticGraphPropsDecoder(data);\n case ItemType.MODULE_GRAPH:\n return moduleGraphPropsDecoder(data);\n case ItemType.SIMPLE_VALUE:\n case ItemType.SIMPLE_VALUE_MAX:\n case ItemType.SIMPLE_VALUE_MIN:\n case ItemType.SIMPLE_VALUE_AVG:\n return simpleValuePropsDecoder(data);\n case ItemType.PERCENTILE_BAR:\n case ItemType.PERCENTILE_BUBBLE:\n case ItemType.CIRCULAR_PROGRESS_BAR:\n case ItemType.CIRCULAR_INTERIOR_PROGRESS_BAR:\n return percentilePropsDecoder(data);\n case ItemType.LABEL:\n return labelPropsDecoder(data);\n case ItemType.ICON:\n return iconPropsDecoder(data);\n case ItemType.SERVICE:\n return servicePropsDecoder(data);\n case ItemType.GROUP_ITEM:\n return groupPropsDecoder(data);\n case ItemType.BOX_ITEM:\n return boxPropsDecoder(data);\n case ItemType.LINE_ITEM:\n return linePropsDecoder(data);\n case ItemType.AUTO_SLA_GRAPH:\n return eventsHistoryPropsDecoder(data);\n case ItemType.DONUT_GRAPH:\n return donutGraphPropsDecoder(data);\n case ItemType.BARS_GRAPH:\n return barsGraphPropsDecoder(data);\n case ItemType.CLOCK:\n return clockPropsDecoder(data);\n case ItemType.COLOR_CLOUD:\n return colorCloudPropsDecoder(data);\n default:\n throw new TypeError(\"decoder not found\");\n }\n}\n\n// Base properties.\nexport interface VisualConsoleProps extends Size {\n readonly id: number;\n name: string;\n groupId: number;\n backgroundURL: string | null; // URL?\n backgroundColor: string | null;\n isFavorite: boolean;\n relationLineWidth: number;\n}\n\n/**\n * Build a valid typed object from a raw object.\n * This will allow us to ensure the type safety.\n *\n * @param data Raw object.\n * @return An object representing the Visual Console props.\n * @throws Will throw a TypeError if some property\n * is missing from the raw object or have an invalid type.\n */\nexport function visualConsolePropsDecoder(\n data: UnknownObject\n): VisualConsoleProps | never {\n // Object destructuring: http://es6-features.org/#ObjectMatchingShorthandNotation\n const {\n id,\n name,\n groupId,\n backgroundURL,\n backgroundColor,\n isFavorite,\n relationLineWidth\n } = data;\n\n if (id == null || isNaN(parseInt(id))) {\n throw new TypeError(\"invalid Id.\");\n }\n if (typeof name !== \"string\" || name.length === 0) {\n throw new TypeError(\"invalid name.\");\n }\n if (groupId == null || isNaN(parseInt(groupId))) {\n throw new TypeError(\"invalid group Id.\");\n }\n\n return {\n id: parseInt(id),\n name,\n groupId: parseInt(groupId),\n backgroundURL: notEmptyStringOr(backgroundURL, null),\n backgroundColor: notEmptyStringOr(backgroundColor, null),\n isFavorite: parseBoolean(isFavorite),\n relationLineWidth: parseIntOr(relationLineWidth, 0),\n ...sizePropsDecoder(data)\n };\n}\n\nexport default class VisualConsole {\n // Reference to the DOM element which will contain the items.\n private readonly containerRef: HTMLElement;\n // Properties.\n private _props: VisualConsoleProps;\n // Visual Console Item instances by their Id.\n private elementsById: {\n [key: number]: Item;\n } = {};\n // Visual Console Item Ids.\n private elementIds: ItemProps[\"id\"][] = [];\n // Dictionary which store the created lines.\n private relations: {\n [key: string]: Line;\n } = {};\n // Event manager for click events.\n private readonly clickEventManager = new TypedEvent<\n ItemClickEvent\n >();\n // List of references to clean the event listeners.\n private readonly disposables: Disposable[] = [];\n\n /**\n * React to a click on an element.\n * @param e Event object.\n */\n private handleElementClick: (e: ItemClickEvent) => void = e => {\n this.clickEventManager.emit(e);\n // console.log(`Clicked element #${e.data.id}`, e);\n };\n\n /**\n * Clear some element references.\n * @param e Event object.\n */\n private handleElementRemove: (e: ItemRemoveEvent) => void = e => {\n // Remove the element from the list and its relations.\n this.elementIds = this.elementIds.filter(id => id !== e.data.id);\n delete this.elementsById[e.data.id];\n this.clearRelations(e.data.id);\n };\n\n public constructor(\n container: HTMLElement,\n props: UnknownObject,\n items: UnknownObject[]\n ) {\n this.containerRef = container;\n this._props = visualConsolePropsDecoder(props);\n\n // Force the first render.\n this.render();\n\n // Sort by isOnTop, id ASC\n items = items.sort(function(a, b) {\n if (\n a.isOnTop == null ||\n b.isOnTop == null ||\n a.id == null ||\n b.id == null\n ) {\n return 0;\n }\n\n if (a.isOnTop && !b.isOnTop) return 1;\n else if (!a.isOnTop && b.isOnTop) return -1;\n else if (a.id > b.id) return 1;\n else return -1;\n });\n\n // Initialize the items.\n items.forEach(item => {\n try {\n const itemInstance = itemInstanceFrom(item);\n // Add the item to the list.\n this.elementsById[itemInstance.props.id] = itemInstance;\n this.elementIds.push(itemInstance.props.id);\n // Item event handlers.\n itemInstance.onClick(this.handleElementClick);\n itemInstance.onRemove(this.handleElementRemove);\n // Add the item to the DOM.\n this.containerRef.append(itemInstance.elementRef);\n } catch (error) {\n console.log(\"Error creating a new element:\", error.message);\n }\n });\n\n // Create lines.\n this.buildRelations();\n }\n\n /**\n * Public accessor of the `elements` property.\n * @return Properties.\n */\n public get elements(): Item[] {\n // Ensure the type cause Typescript doesn't know the filter removes null items.\n return this.elementIds\n .map(id => this.elementsById[id])\n .filter(_ => _ != null) as Item[];\n }\n\n /**\n * Public setter of the `elements` property.\n * @param items.\n */\n public updateElements(items: UnknownObject[]): void {\n const itemIds = items.map(item => item.id || null).filter(id => id != null);\n itemIds as number[]; // Tell the type system to rely on us.\n // Get the elements we should delete.\n const deletedIds: number[] = this.elementIds.filter(\n id => itemIds.indexOf(id) < 0\n );\n // Delete the elements.\n deletedIds.forEach(id => {\n if (this.elementsById[id] != null) {\n this.elementsById[id].remove();\n delete this.elementsById[id];\n }\n });\n // Replace the element ids.\n this.elementIds = itemIds;\n\n // Initialize the items.\n items.forEach(item => {\n if (item.id) {\n if (this.elementsById[item.id] == null) {\n // New item.\n try {\n const itemInstance = itemInstanceFrom(item);\n // Add the item to the list.\n this.elementsById[itemInstance.props.id] = itemInstance;\n // Item event handlers.\n itemInstance.onClick(this.handleElementClick);\n itemInstance.onRemove(this.handleElementRemove);\n // Add the item to the DOM.\n this.containerRef.append(itemInstance.elementRef);\n } catch (error) {\n console.log(\"Error creating a new element:\", error.message);\n }\n } else {\n // Update item.\n try {\n this.elementsById[item.id].props = decodeProps(item);\n } catch (error) {\n console.log(\"Error updating an element:\", error.message);\n }\n }\n }\n });\n\n // Re-build relations.\n this.buildRelations();\n }\n\n /**\n * Public accessor of the `props` property.\n * @return Properties.\n */\n public get props(): VisualConsoleProps {\n return { ...this._props }; // Return a copy.\n }\n\n /**\n * Public setter of the `props` property.\n * If the new props are different enough than the\n * stored props, a render would be fired.\n * @param newProps\n */\n public set props(newProps: VisualConsoleProps) {\n const prevProps = this.props;\n // Update the internal props.\n this._props = newProps;\n\n // From this point, things which rely on this.props can access to the changes.\n\n // Re-render.\n this.render(prevProps);\n }\n\n /**\n * Recreate or update the HTMLElement which represents the Visual Console into the DOM.\n * @param prevProps If exists it will be used to only DOM updates instead of a full replace.\n */\n public render(prevProps: VisualConsoleProps | null = null): void {\n if (prevProps) {\n if (prevProps.backgroundURL !== this.props.backgroundURL) {\n this.containerRef.style.backgroundImage =\n this.props.backgroundURL !== null\n ? `url(${this.props.backgroundURL})`\n : null;\n }\n if (prevProps.backgroundColor !== this.props.backgroundColor) {\n this.containerRef.style.backgroundColor = this.props.backgroundColor;\n }\n if (this.sizeChanged(prevProps, this.props)) {\n this.resizeElement(this.props.width, this.props.height);\n }\n } else {\n this.containerRef.style.backgroundImage =\n this.props.backgroundURL !== null\n ? `url(${this.props.backgroundURL})`\n : null;\n\n this.containerRef.style.backgroundColor = this.props.backgroundColor;\n this.resizeElement(this.props.width, this.props.height);\n }\n }\n\n /**\n * Compare the previous and the new size and return\n * a boolean value in case the size changed.\n * @param prevSize\n * @param newSize\n * @return Whether the size changed or not.\n */\n public sizeChanged(prevSize: Size, newSize: Size): boolean {\n return (\n prevSize.width !== newSize.width || prevSize.height !== newSize.height\n );\n }\n\n /**\n * Resize the DOM container.\n * @param width\n * @param height\n */\n public resizeElement(width: number, height: number): void {\n this.containerRef.style.width = `${width}px`;\n this.containerRef.style.height = `${height}px`;\n }\n\n /**\n * Update the size into the properties and resize the DOM container.\n * @param width\n * @param height\n */\n public resize(width: number, height: number): void {\n this.props = {\n ...this.props, // Object spread: http://es6-features.org/#SpreadOperator\n width,\n height\n };\n }\n\n /**\n * To remove the event listeners and the elements from the DOM.\n */\n public remove(): void {\n this.disposables.forEach(d => d.dispose()); // Arrow function.\n this.elements.forEach(e => e.remove()); // Arrow function.\n this.elementsById = {};\n this.elementIds = [];\n // Clear relations.\n this.clearRelations();\n // Clean container.\n this.containerRef.innerHTML = \"\";\n }\n\n /**\n * Create line elements which connect the elements with their parents.\n */\n private buildRelations(): void {\n // Clear relations.\n this.clearRelations();\n // Add relations.\n this.elements.forEach(item => {\n if (item.props.parentId !== null) {\n const parent = this.elementsById[item.props.parentId];\n const child = this.elementsById[item.props.id];\n if (parent && child) this.addRelationLine(parent, child);\n }\n });\n }\n\n /**\n * @param itemId Optional identifier of a parent or child item.\n * Remove the line elements which connect the elements with their parents.\n */\n private clearRelations(itemId?: number): void {\n if (itemId != null) {\n for (let key in this.relations) {\n const ids = key.split(\"|\");\n const parentId = Number.parseInt(ids[0]);\n const childId = Number.parseInt(ids[1]);\n\n if (itemId === parentId || itemId === childId) {\n this.relations[key].remove();\n delete this.relations[key];\n }\n }\n } else {\n for (let key in this.relations) {\n this.relations[key].remove();\n delete this.relations[key];\n }\n }\n }\n\n /**\n * Retrieve the line element which represent the relation between items.\n * @param parentId Identifier of the parent item.\n * @param childId Itentifier of the child item.\n * @return The line element or nothing.\n */\n private getRelationLine(parentId: number, childId: number): Line | null {\n const identifier = `${parentId}|${childId}`;\n return this.relations[identifier] || null;\n }\n\n /**\n * Add a new line item to represent a relation between the items.\n * @param parent Parent item.\n * @param child Child item.\n * @return Whether the line was added or not.\n */\n private addRelationLine(\n parent: Item,\n child: Item\n ): Line {\n const identifier = `${parent.props.id}|${child.props.id}`;\n if (this.relations[identifier] != null) {\n this.relations[identifier].remove();\n }\n\n // Get the items center.\n const startX = parent.props.x + parent.elementRef.clientWidth / 2;\n const startY =\n parent.props.y +\n (parent.elementRef.clientHeight - parent.labelElementRef.clientHeight) /\n 2;\n const endX = child.props.x + child.elementRef.clientWidth / 2;\n const endY =\n child.props.y +\n (child.elementRef.clientHeight - child.labelElementRef.clientHeight) / 2;\n\n const line = new Line(\n linePropsDecoder({\n id: 0,\n type: ItemType.LINE_ITEM,\n startX,\n startY,\n endX,\n endY,\n width: 0,\n height: 0,\n lineWidth: this.props.relationLineWidth,\n color: \"#CCCCCC\"\n })\n );\n // Save a reference to the line item.\n this.relations[identifier] = line;\n\n // Add the line to the DOM.\n line.elementRef.style.zIndex = \"0\";\n this.containerRef.append(line.elementRef);\n\n return line;\n }\n\n /**\n * Add an event handler to the click of the linked visual console elements.\n * @param listener Function which is going to be executed when a linked console is clicked.\n */\n public onClick(listener: Listener>): Disposable {\n /*\n * The '.on' function returns a function which will clean the event\n * listener when executed. We store all the 'dispose' functions to\n * call them when the item should be cleared.\n */\n const disposable = this.clickEventManager.on(listener);\n this.disposables.push(disposable);\n\n return disposable;\n }\n}\n","/*\n * Useful resources.\n * http://es6-features.org/\n * http://exploringjs.com/es6\n * https://www.typescriptlang.org/\n */\n\nimport \"./main.css\"; // CSS import.\nimport VisualConsole from \"./VisualConsole\";\n\n// Export the VisualConsole class to the global object.\n\n// eslint-disable-next-line\n(window as any).VisualConsole = VisualConsole;\n"],"sourceRoot":""}
\ No newline at end of file
diff --git a/pandora_console/install.php b/pandora_console/install.php
index 21bd9994c3..d984e41a98 100644
--- a/pandora_console/install.php
+++ b/pandora_console/install.php
@@ -128,8 +128,8 @@
size[7] = '5%';
if (check_acl_one_of_groups($config['id_user'], $all_groups, 'LW') || check_acl_one_of_groups($config['id_user'], $all_groups, 'LM')) {
+ $table->head[8] = __('Validate');
$table->align[8] = 'left';
$table->size[8] = '5%';
}
@@ -532,6 +533,7 @@ if ($isFunctionPolicies !== ENTERPRISE_NOT_HOOK) {
if (!is_metaconsole()) {
$table->size[7] = '5%';
if (check_acl($config['id_user'], $id_group, 'LW') || check_acl($config['id_user'], $id_group, 'LM')) {
+ $table->head[8] = __('Validate');
$table->align[8] = 'left';
$table->size[8] = '5%';
}
@@ -563,6 +565,7 @@ if ($isFunctionPolicies !== ENTERPRISE_NOT_HOOK) {
if (!is_metaconsole()) {
$table->size[6] = '5%';
if (check_acl($config['id_user'], $id_group, 'LW') || check_acl($config['id_user'], $id_group, 'LM')) {
+ $table->head[7] = __('Validate');
$table->align[7] = 'left';
$table->size[7] = '5%';
}
diff --git a/pandora_console/operation/events/events.build_query.php b/pandora_console/operation/events/events.build_query.php
index 2d335ff7e7..f915a5093b 100755
--- a/pandora_console/operation/events/events.build_query.php
+++ b/pandora_console/operation/events/events.build_query.php
@@ -91,18 +91,20 @@ if ($id_group > 0 && in_array($id_group, array_keys($groups))) {
$childrens_str = implode(',', $childrens_ids);
$sql_post .= " AND (id_grupo IN ($childrens_str)";
- if ($is_using_secondary_group === 1)
+ if ($is_using_secondary_group === 1) {
$sql_post .= " OR id_group IN ($childrens_str)";
+ }
- $sql_post .= ")";
+ $sql_post .= ')';
} else {
// If a group is selected and it's in the groups allowed.
$sql_post .= " AND (id_grupo = $id_group";
- if ($is_using_secondary_group === 1)
+ if ($is_using_secondary_group === 1) {
$sql_post .= " OR id_group = $id_group";
+ }
- $sql_post .= ")";
+ $sql_post .= ')';
}
} else {
if (!users_is_admin() && !users_can_manage_group_all('ER')) {
@@ -112,13 +114,12 @@ if ($id_group > 0 && in_array($id_group, array_keys($groups))) {
implode(',', array_keys($groups)),
implode(',', array_keys($groups))
);
- }
- else {
+ } else {
$sql_post .= sprintf(
' AND (id_grupo IN (%s)) ',
implode(',', array_keys($groups))
);
- }
+ }
}
}
diff --git a/pandora_console/operation/menu.php b/pandora_console/operation/menu.php
index e22769cd8a..f52d830d14 100644
--- a/pandora_console/operation/menu.php
+++ b/pandora_console/operation/menu.php
@@ -492,12 +492,6 @@ if (is_array($config['extensions'])) {
$sub['godmode/agentes/planned_downtime.list']['id'] = 'Scheduled downtime';
}
- if (check_acl($config['id_user'], 0, 'AW')) {
- $sub['operation/servers/recon_view']['text'] = __('Recon view');
- $sub['operation/servers/recon_view']['id'] = 'Recon view';
- $sub['operation/servers/recon_view']['refr'] = 0;
- }
-
foreach ($config['extensions'] as $extension) {
// If no operation_menu is a godmode extension.
if ($extension['operation_menu'] == '') {
diff --git a/pandora_console/operation/visual_console/legacy_public_view.php b/pandora_console/operation/visual_console/legacy_public_view.php
new file mode 100644
index 0000000000..18d8e2ca55
--- /dev/null
+++ b/pandora_console/operation/visual_console/legacy_public_view.php
@@ -0,0 +1,265 @@
+'."\n";
+echo ''."\n";
+echo '';
+
+global $vc_public_view;
+$vc_public_view = true;
+// This starts the page head. In the call back function,
+// things from $page['head'] array will be processed into the head
+ob_start('ui_process_page_head');
+// Enterprise main
+enterprise_include('index.php');
+
+require_once 'include/functions_visual_map.php';
+
+$hash = get_parameter('hash');
+$id_layout = (int) get_parameter('id_layout');
+$graph_javascript = (bool) get_parameter('graph_javascript');
+$config['id_user'] = get_parameter('id_user');
+
+$myhash = md5($config['dbpass'].$id_layout.$config['id_user']);
+
+// Check input hash
+if ($myhash != $hash) {
+ exit;
+}
+
+$refr = (int) get_parameter('refr', 0);
+$layout = db_get_row('tlayout', 'id', $id_layout);
+
+if (! $layout) {
+ db_pandora_audit('ACL Violation', 'Trying to access visual console without id layout');
+ include $config['homedir'].'/general/noaccess.php';
+ exit;
+}
+
+if (!isset($config['pure'])) {
+ $config['pure'] = 0;
+}
+
+// ~ $xhr = (bool) get_parameter('xhr');
+if ($layout) {
+ $id_group = $layout['id_group'];
+ $layout_name = $layout['name'];
+ $background = $layout['background'];
+ $bwidth = $layout['width'];
+ $bheight = $layout['height'];
+ // ~ $width = (int) get_parameter('width');
+ // ~ if ($width <= 0) $width = null;
+ // ~ $height = (int) get_parameter('height');
+ // ~ if ($height <= 0) $height = null;
+ // ~ ob_start();
+ // ~ // Render map
+ visual_map_print_visual_map(
+ $id_layout,
+ true,
+ true,
+ $width,
+ $height,
+ '../../',
+ true,
+ true,
+ true
+ );
+ // ~ return;
+} else {
+ echo '
';
+}
+
+// Floating menu - Start
+echo '
';
+
+echo '';
+
+echo '
';
+// Floating menu - End
+// QR code dialog
+echo '
';
+
+ui_require_jquery_file('countdown');
+ui_require_javascript_file('wz_jsgraphics');
+ui_require_javascript_file('pandora_visual_console');
+$ignored_params['refr'] = '';
+?>
+
+
+
+
diff --git a/pandora_console/operation/visual_console/legacy_view.php b/pandora_console/operation/visual_console/legacy_view.php
new file mode 100644
index 0000000000..f5eec24096
--- /dev/null
+++ b/pandora_console/operation/visual_console/legacy_view.php
@@ -0,0 +1,386 @@
+'.html_print_image(
+ 'images/visual_console.png',
+ true,
+ ['title' => __('Visual consoles list')]
+).'';
+
+if ($vconsole_write || $vconsole_manage) {
+ $url_base = 'index.php?sec=network&sec2=godmode/reporting/visual_console_builder&action=';
+
+ $hash = md5($config['dbpass'].$id_layout.$config['id_user']);
+
+ $options['public_link']['text'] = '
'.html_print_image(
+ 'images/camera_mc.png',
+ true,
+ ['title' => __('Show link to public Visual Console')]
+ ).' ';
+ $options['public_link']['active'] = false;
+
+ $options['data']['text'] = '
'.html_print_image(
+ 'images/op_reporting.png',
+ true,
+ ['title' => __('Main data')]
+ ).' ';
+ $options['list_elements']['text'] = '
'.html_print_image(
+ 'images/list.png',
+ true,
+ ['title' => __('List elements')]
+ ).' ';
+
+ if (enterprise_installed()) {
+ $options['wizard_services']['text'] = '
'.html_print_image(
+ 'images/wand_services.png',
+ true,
+ ['title' => __('Services wizard')]
+ ).' ';
+ }
+
+ $options['wizard']['text'] = '
'.html_print_image(
+ 'images/wand.png',
+ true,
+ ['title' => __('Wizard')]
+ ).' ';
+ $options['editor']['text'] = '
'.html_print_image(
+ 'images/builder.png',
+ true,
+ ['title' => __('Builder')]
+ ).' ';
+}
+
+$options['view']['text'] = '
'.html_print_image('images/operation.png', true, ['title' => __('View')]).' ';
+$options['view']['active'] = true;
+
+if (!is_metaconsole()) {
+ if (!$config['pure']) {
+ $options['pure']['text'] = '
'.html_print_image('images/full_screen.png', true, ['title' => __('Full screen mode')]).' ';
+ ui_print_page_header($layout_name, 'images/visual_console.png', false, '', false, $options);
+ }
+
+ // Set the hidden value for the javascript
+ html_print_input_hidden('metaconsole', 0);
+} else {
+ // Set the hidden value for the javascript
+ html_print_input_hidden('metaconsole', 1);
+}
+
+if ($config['pure']) {
+ // Container of the visual map (ajax loaded)
+ echo '
'.visual_map_print_visual_map(
+ $id_layout,
+ true,
+ true,
+ null,
+ null,
+ '',
+ false,
+ true
+ ).'
';
+
+ // Floating menu - Start
+ echo '
';
+
+ echo '';
+
+ echo '
';
+ // Floating menu - End
+ ui_require_jquery_file('countdown');
+
+ ?>
+
+
+
+
+
+
\ No newline at end of file
diff --git a/pandora_console/operation/visual_console/public_console.php b/pandora_console/operation/visual_console/public_console.php
index bc5b3d2a20..8a6ff462fc 100755
--- a/pandora_console/operation/visual_console/public_console.php
+++ b/pandora_console/operation/visual_console/public_console.php
@@ -15,245 +15,9 @@
// The session is configured and started inside the config process.
require_once '../../include/config.php';
-// Set root on homedir, as defined in setup
-chdir($config['homedir']);
-
-ob_start();
-// Enterprise support
-if (file_exists(ENTERPRISE_DIR.'/load_enterprise.php')) {
- include_once ENTERPRISE_DIR.'/load_enterprise.php';
-}
-
-if (file_exists(ENTERPRISE_DIR.'/include/functions_login.php')) {
- include_once ENTERPRISE_DIR.'/include/functions_login.php';
-}
-
-echo ''."\n";
-echo ''."\n";
-echo '';
-
-global $vc_public_view;
-$vc_public_view = true;
-// This starts the page head. In the call back function,
-// things from $page['head'] array will be processed into the head
-ob_start('ui_process_page_head');
-// Enterprise main
-enterprise_include('index.php');
-
-require_once 'include/functions_visual_map.php';
-
-$hash = get_parameter('hash');
-$id_layout = (int) get_parameter('id_layout');
-$graph_javascript = (bool) get_parameter('graph_javascript');
-$config['id_user'] = get_parameter('id_user');
-
-$myhash = md5($config['dbpass'].$id_layout.$config['id_user']);
-
-// Check input hash
-if ($myhash != $hash) {
- exit;
-}
-
-$refr = (int) get_parameter('refr', 0);
-$layout = db_get_row('tlayout', 'id', $id_layout);
-
-if (! $layout) {
- db_pandora_audit('ACL Violation', 'Trying to access visual console without id layout');
- include $config['homedir'].'/general/noaccess.php';
- exit;
-}
-
-if (!isset($config['pure'])) {
- $config['pure'] = 0;
-}
-
-// ~ $xhr = (bool) get_parameter('xhr');
-if ($layout) {
- $id_group = $layout['id_group'];
- $layout_name = $layout['name'];
- $background = $layout['background'];
- $bwidth = $layout['width'];
- $bheight = $layout['height'];
- // ~ $width = (int) get_parameter('width');
- // ~ if ($width <= 0) $width = null;
- // ~ $height = (int) get_parameter('height');
- // ~ if ($height <= 0) $height = null;
- // ~ ob_start();
- // ~ // Render map
- visual_map_print_visual_map(
- $id_layout,
- true,
- true,
- $width,
- $height,
- '../../',
- true,
- true,
- true
- );
- // ~ return;
+$legacy = (bool) get_parameter('legacy', $config['legacy_vc']);
+if ($legacy === false) {
+ include_once $config['homedir'].'/operation/visual_console/public_view.php';
} else {
- echo '
';
+ include_once $config['homedir'].'/operation/visual_console/legacy_public_view.php';
}
-
-// Floating menu - Start
-echo '
';
-
-echo '';
-
-echo '
';
-// Floating menu - End
-// QR code dialog
-echo '
';
-
-ui_require_jquery_file('countdown');
-ui_require_javascript_file('wz_jsgraphics');
-ui_require_javascript_file('pandora_visual_console');
-$ignored_params['refr'] = '';
-?>
-
-
diff --git a/pandora_console/operation/visual_console/public_view.php b/pandora_console/operation/visual_console/public_view.php
new file mode 100644
index 0000000000..0a23c5f216
--- /dev/null
+++ b/pandora_console/operation/visual_console/public_view.php
@@ -0,0 +1,209 @@
+'."\n";
+echo ''."\n";
+echo '';
+
+global $vc_public_view;
+$vc_public_view = true;
+$config['public_view'] = true;
+
+// This starts the page head. In the call back function,
+// things from $page['head'] array will be processed into the head.
+ob_start('ui_process_page_head');
+// Enterprise main.
+enterprise_include('index.php');
+
+require_once 'include/functions_visual_map.php';
+
+$hash = (string) get_parameter('hash');
+$visualConsoleId = (int) get_parameter('id_layout');
+$config['id_user'] = (string) get_parameter('id_user');
+$refr = (int) get_parameter('refr', $config['refr']);
+
+if (!isset($config['pure'])) {
+ $config['pure'] = 0;
+}
+
+$myhash = md5($config['dbpass'].$visualConsoleId.$config['id_user']);
+
+// Check input hash.
+if ($myhash != $hash) {
+ exit;
+}
+
+// Load Visual Console.
+use Models\VisualConsole\Container as VisualConsole;
+$visualConsole = null;
+try {
+ $visualConsole = VisualConsole::fromDB(['id' => $visualConsoleId]);
+} catch (Throwable $e) {
+ db_pandora_audit(
+ 'ACL Violation',
+ 'Trying to access visual console without Id'
+ );
+ include $config['homedir'].'/general/noaccess.php';
+ exit;
+}
+
+$visualConsoleData = $visualConsole->toArray();
+$visualConsoleName = $visualConsoleData['name'];
+
+echo '
';
+
+// Floating menu - Start.
+echo '
';
+
+echo '';
+
+echo '
';
+
+// QR code dialog.
+echo '
';
+
+// Check groups can access user.
+$aclUserGroups = [];
+if (!users_can_manage_group_all('AR')) {
+ $aclUserGroups = array_keys(users_get_groups(false, 'AR'));
+}
+
+$ignored_params['refr'] = '';
+ui_require_javascript_file('pandora_visual_console');
+include_javascript_d3();
+visual_map_load_client_resources();
+
+// Load Visual Console Items.
+$visualConsoleItems = VisualConsole::getItemsFromDB(
+ $visualConsoleId,
+ $aclUserGroups
+);
+
+?>
+
+
+
+
diff --git a/pandora_console/operation/visual_console/render_view.php b/pandora_console/operation/visual_console/render_view.php
index 4799932e2c..00cdc2d113 100755
--- a/pandora_console/operation/visual_console/render_view.php
+++ b/pandora_console/operation/visual_console/render_view.php
@@ -13,368 +13,9 @@
// GNU General Public License for more details.
global $config;
-// Login check
-require_once $config['homedir'].'/include/functions_visual_map.php';
-
-check_login();
-
-if (!defined('METACONSOLE')) {
- $id_layout = (int) get_parameter('id');
+$legacy = (bool) get_parameter('legacy', $config['legacy_vc']);
+if ($legacy === false) {
+ include_once $config['homedir'].'/operation/visual_console/view.php';
} else {
- $id_layout = (int) get_parameter('id_visualmap');
+ include_once $config['homedir'].'/operation/visual_console/legacy_view.php';
}
-
-if ($id_layout) {
- $default_action = 'edit';
-} else {
- $default_action = 'new';
-}
-
-if (!defined('METACONSOLE')) {
- $action = get_parameterBetweenListValues(
- 'action',
- [
- 'new',
- 'save',
- 'edit',
- 'update',
- 'delete',
- ],
- $default_action
- );
-} else {
- $action = get_parameterBetweenListValues(
- 'action2',
- [
- 'new',
- 'save',
- 'edit',
- 'update',
- 'delete',
- ],
- $default_action
- );
-}
-
-$refr = (int) get_parameter('refr', $config['vc_refr']);
-$graph_javascript = (bool) get_parameter('graph_javascript', true);
-$vc_refr = false;
-
-if (isset($config['vc_refr']) and $config['vc_refr'] != 0) {
- $view_refresh = $config['vc_refr'];
-} else {
- $view_refresh = '300';
-}
-
-// Get input parameter for layout id
-if (! $id_layout) {
- db_pandora_audit(
- 'ACL Violation',
- 'Trying to access visual console without id layout'
- );
- include 'general/noaccess.php';
- exit;
-}
-
-$layout = db_get_row('tlayout', 'id', $id_layout);
-
-if (! $layout) {
- db_pandora_audit(
- 'ACL Violation',
- 'Trying to access visual console without id layout'
- );
- include 'general/noaccess.php';
- exit;
-}
-
-$id_group = $layout['id_group'];
-$layout_name = $layout['name'];
-$background = $layout['background'];
-$bwidth = $layout['width'];
-$bheight = $layout['height'];
-
-$pure_url = '&pure='.$config['pure'];
-
-// ACL
-$vconsole_read = check_acl($config['id_user'], $id_group, 'VR');
-$vconsole_write = check_acl($config['id_user'], $id_group, 'VW');
-$vconsole_manage = check_acl($config['id_user'], $id_group, 'VM');
-
-if (! $vconsole_read && !$vconsole_write && !$vconsole_manage) {
- db_pandora_audit(
- 'ACL Violation',
- 'Trying to access visual console without group access'
- );
- include 'general/noaccess.php';
- exit;
-}
-
-// Render map
-$options = [];
-
-$options['consoles_list']['text'] = '
'.html_print_image(
- 'images/visual_console.png',
- true,
- ['title' => __('Visual consoles list')]
-).' ';
-
-if ($vconsole_write || $vconsole_manage) {
- $url_base = 'index.php?sec=network&sec2=godmode/reporting/visual_console_builder&action=';
-
- $hash = md5($config['dbpass'].$id_layout.$config['id_user']);
-
- $options['public_link']['text'] = '
'.html_print_image(
- 'images/camera_mc.png',
- true,
- ['title' => __('Show link to public Visual Console')]
- ).' ';
- $options['public_link']['active'] = false;
-
- $options['data']['text'] = '
'.html_print_image(
- 'images/op_reporting.png',
- true,
- ['title' => __('Main data')]
- ).' ';
- $options['list_elements']['text'] = '
'.html_print_image(
- 'images/list.png',
- true,
- ['title' => __('List elements')]
- ).' ';
-
- if (enterprise_installed()) {
- $options['wizard_services']['text'] = '
'.html_print_image(
- 'images/wand_services.png',
- true,
- ['title' => __('Services wizard')]
- ).' ';
- }
-
- $options['wizard']['text'] = '
'.html_print_image(
- 'images/wand.png',
- true,
- ['title' => __('Wizard')]
- ).' ';
- $options['editor']['text'] = '
'.html_print_image(
- 'images/builder.png',
- true,
- ['title' => __('Builder')]
- ).' ';
-}
-
-$options['view']['text'] = '
'.html_print_image('images/operation.png', true, ['title' => __('View')]).' ';
-$options['view']['active'] = true;
-
-if (!is_metaconsole()) {
- if (!$config['pure']) {
- $options['pure']['text'] = '
'.html_print_image('images/full_screen.png', true, ['title' => __('Full screen mode')]).' ';
- ui_print_page_header($layout_name, 'images/visual_console.png', false, '', false, $options);
- }
-
- // Set the hidden value for the javascript
- html_print_input_hidden('metaconsole', 0);
-} else {
- // Set the hidden value for the javascript
- html_print_input_hidden('metaconsole', 1);
-}
-
-if ($config['pure']) {
- // Container of the visual map (ajax loaded)
- echo '
'.visual_map_print_visual_map(
- $id_layout,
- true,
- true,
- null,
- null,
- '',
- false,
- true
- ).'
';
-
- // Floating menu - Start
- echo '
';
-
- echo '';
-
- echo '
';
- // Floating menu - End
- ui_require_jquery_file('countdown');
-
- ?>
-
-
-
-
\ No newline at end of file
diff --git a/pandora_console/operation/visual_console/view.php b/pandora_console/operation/visual_console/view.php
new file mode 100644
index 0000000000..5134c0d98d
--- /dev/null
+++ b/pandora_console/operation/visual_console/view.php
@@ -0,0 +1,320 @@
+ $visualConsoleId]);
+} catch (Throwable $e) {
+ db_pandora_audit(
+ 'ACL Violation',
+ 'Trying to access visual console without Id'
+ );
+ include 'general/noaccess.php';
+ exit;
+}
+
+$visualConsoleData = $visualConsole->toArray();
+$groupId = $visualConsoleData['groupId'];
+$visualConsoleName = $visualConsoleData['name'];
+
+// ACL.
+$aclRead = check_acl($config['id_user'], $groupId, 'VR');
+$aclWrite = check_acl($config['id_user'], $groupId, 'VW');
+$aclManage = check_acl($config['id_user'], $groupId, 'VM');
+
+if (!$aclRead && !$aclWrite && !$aclManage) {
+ db_pandora_audit(
+ 'ACL Violation',
+ 'Trying to access visual console without group access'
+ );
+ include 'general/noaccess.php';
+ exit;
+}
+
+// Render map.
+$options = [];
+
+$options['consoles_list']['text'] = '
'.html_print_image(
+ 'images/visual_console.png',
+ true,
+ ['title' => __('Visual consoles list')]
+).' ';
+
+if ($aclWrite || $aclManage) {
+ $action = get_parameterBetweenListValues(
+ is_metaconsole() ? 'action2' : 'action',
+ [
+ 'new',
+ 'save',
+ 'edit',
+ 'update',
+ 'delete',
+ ],
+ 'edit'
+ );
+
+ $baseUrl = 'index.php?sec=network&sec2=godmode/reporting/visual_console_builder&action='.$action;
+
+ $hash = md5($config['dbpass'].$visualConsoleId.$config['id_user']);
+
+ $options['public_link']['text'] = '
'.html_print_image(
+ 'images/camera_mc.png',
+ true,
+ ['title' => __('Show link to public Visual Console')]
+ ).' ';
+ $options['public_link']['active'] = false;
+
+ $options['data']['text'] = '
'.html_print_image(
+ 'images/op_reporting.png',
+ true,
+ ['title' => __('Main data')]
+ ).' ';
+ $options['list_elements']['text'] = '
'.html_print_image(
+ 'images/list.png',
+ true,
+ ['title' => __('List elements')]
+ ).' ';
+
+ if (enterprise_installed()) {
+ $options['wizard_services']['text'] = '
'.html_print_image(
+ 'images/wand_services.png',
+ true,
+ ['title' => __('Services wizard')]
+ ).' ';
+ }
+
+ $options['wizard']['text'] = '
'.html_print_image(
+ 'images/wand.png',
+ true,
+ ['title' => __('Wizard')]
+ ).' ';
+ $options['editor']['text'] = '
'.html_print_image(
+ 'images/builder.png',
+ true,
+ ['title' => __('Builder')]
+ ).' ';
+}
+
+$options['view']['text'] = '
'.html_print_image(
+ 'images/operation.png',
+ true,
+ ['title' => __('View')]
+).' ';
+$options['view']['active'] = true;
+
+if (!is_metaconsole()) {
+ if (!$config['pure']) {
+ $options['pure']['text'] = '
'.html_print_image(
+ 'images/full_screen.png',
+ true,
+ ['title' => __('Full screen mode')]
+ ).' ';
+ ui_print_page_header(
+ $visualConsoleName,
+ 'images/visual_console.png',
+ false,
+ '',
+ false,
+ $options
+ );
+ }
+
+ // Set the hidden value for the javascript.
+ html_print_input_hidden('metaconsole', 0);
+} else {
+ // Set the hidden value for the javascript.
+ html_print_input_hidden('metaconsole', 1);
+}
+
+echo '
';
+
+if ($pure === true) {
+ // Floating menu - Start.
+ echo '
';
+
+ echo '';
+
+ echo '
';
+ // Floating menu - End.
+ ?>
+
+
+
+
diff --git a/pandora_console/pandora_console.redhat.spec b/pandora_console/pandora_console.redhat.spec
index bb1712e4f6..3eb4b1ea5c 100644
--- a/pandora_console/pandora_console.redhat.spec
+++ b/pandora_console/pandora_console.redhat.spec
@@ -2,8 +2,8 @@
# Pandora FMS Console
#
%define name pandorafms_console
-%define version 7.0NG.733
-%define release 190417
+%define version 7.0NG.734
+%define release 190503
# User and Group under which Apache is running
%define httpd_name httpd
diff --git a/pandora_console/pandora_console.rhel7.spec b/pandora_console/pandora_console.rhel7.spec
index 57f47a8558..037db29731 100644
--- a/pandora_console/pandora_console.rhel7.spec
+++ b/pandora_console/pandora_console.rhel7.spec
@@ -2,8 +2,8 @@
# Pandora FMS Console
#
%define name pandorafms_console
-%define version 7.0NG.733
-%define release 190417
+%define version 7.0NG.734
+%define release 190503
# User and Group under which Apache is running
%define httpd_name httpd
diff --git a/pandora_console/pandora_console.spec b/pandora_console/pandora_console.spec
index 7234025e42..9f2a29603a 100644
--- a/pandora_console/pandora_console.spec
+++ b/pandora_console/pandora_console.spec
@@ -2,8 +2,8 @@
# Pandora FMS Console
#
%define name pandorafms_console
-%define version 7.0NG.733
-%define release 190417
+%define version 7.0NG.734
+%define release 190503
%define httpd_name httpd
# User and Group under which Apache is running
%define httpd_name apache2
diff --git a/pandora_console/pandora_console_install b/pandora_console/pandora_console_install
index d81843bc2f..707098d231 100644
--- a/pandora_console/pandora_console_install
+++ b/pandora_console/pandora_console_install
@@ -9,7 +9,7 @@
# This code is licensed under GPL 2.0 license.
# **********************************************************************
-PI_VERSION="7.0NG.733"
+PI_VERSION="7.0NG.734"
FORCE=0
DESTDIR=""
LOG_TIMESTAMP=`date +"%Y/%m/%d %H:%M:%S"`
diff --git a/pandora_console/pandoradb.sql b/pandora_console/pandoradb.sql
index 34d1d9f83a..33d58d948b 100644
--- a/pandora_console/pandoradb.sql
+++ b/pandora_console/pandoradb.sql
@@ -790,6 +790,7 @@ CREATE TABLE IF NOT EXISTS `trecon_task` (
`auth_strings` text,
`autoconfiguration_enabled` tinyint(1) unsigned default '0',
`summary` text,
+ `type` int NOT NULL default 0,
PRIMARY KEY (`id_rt`),
KEY `recon_task_daemon` (`id_recon_server`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
@@ -967,6 +968,7 @@ CREATE TABLE IF NOT EXISTS `trecon_script` (
`description` TEXT,
`script` varchar(250) default '',
`macros` TEXT,
+ `type` int NOT NULL default 0,
PRIMARY KEY (`id_recon_script`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
@@ -1419,6 +1421,18 @@ CREATE TABLE IF NOT EXISTS `treport_content` (
`hide_no_data` tinyint(1) default 0,
`recursion` tinyint(1) default NULL,
`show_extended_events` tinyint(1) default '0',
+ `total_time` TINYINT(1) DEFAULT '1',
+ `time_failed` TINYINT(1) DEFAULT '1',
+ `time_in_ok_status` TINYINT(1) DEFAULT '1',
+ `time_in_unknown_status` TINYINT(1) DEFAULT '1',
+ `time_of_not_initialized_module` TINYINT(1) DEFAULT '1',
+ `time_of_downtime` TINYINT(1) DEFAULT '1',
+ `total_checks` TINYINT(1) DEFAULT '1',
+ `checks_failed` TINYINT(1) DEFAULT '1',
+ `checks_in_ok_status` TINYINT(1) DEFAULT '1',
+ `unknown_checks` TINYINT(1) DEFAULT '1',
+ `agent_max_value` TINYINT(1) DEFAULT '1',
+ `agent_min_value` TINYINT(1) DEFAULT '1',
PRIMARY KEY(`id_rc`),
FOREIGN KEY (`id_report`) REFERENCES treport(`id_report`)
ON UPDATE CASCADE ON DELETE CASCADE
@@ -2946,6 +2960,18 @@ CREATE TABLE IF NOT EXISTS `treport_content_template` (
`lapse` int(11) UNSIGNED NOT NULL default '300',
`visual_format` tinyint(1) UNSIGNED NOT NULL default '0',
`hide_no_data` tinyint(1) default 0,
+ `total_time` TINYINT(1) DEFAULT '1',
+ `time_failed` TINYINT(1) DEFAULT '1',
+ `time_in_ok_status` TINYINT(1) DEFAULT '1',
+ `time_in_unknown_status` TINYINT(1) DEFAULT '1',
+ `time_of_not_initialized_module` TINYINT(1) DEFAULT '1',
+ `time_of_downtime` TINYINT(1) DEFAULT '1',
+ `total_checks` TINYINT(1) DEFAULT '1',
+ `checks_failed` TINYINT(1) DEFAULT '1',
+ `checks_in_ok_status` TINYINT(1) DEFAULT '1',
+ `unknown_checks` TINYINT(1) DEFAULT '1',
+ `agent_max_value` TINYINT(1) DEFAULT '1',
+ `agent_min_value` TINYINT(1) DEFAULT '1',
PRIMARY KEY(`id_rc`)
) ENGINE = InnoDB DEFAULT CHARSET=utf8;
diff --git a/pandora_console/pandoradb_data.sql b/pandora_console/pandoradb_data.sql
index f98cc3b511..7b9517f661 100644
--- a/pandora_console/pandoradb_data.sql
+++ b/pandora_console/pandoradb_data.sql
@@ -1135,10 +1135,10 @@ INSERT INTO `treport_custom_sql` (`id`, `name`, `sql`) VALUES (3, 'Monitoring
INSERT INTO `treport_custom_sql` (`id`, `name`, `sql`) VALUES (4, 'Group view', 'select t1.nombre, (select count(t3.id_agente) from tagente as t3 where t1.id_grupo = t3.id_grupo) as agents, (SELECT COUNT(t4.id_agente) FROM tagente as t4 WHERE t4.id_grupo = t1.id_grupo AND t4.disabled = 0 AND t4.ultimo_contacto < NOW() - (intervalo / (1/2))) as agent_unknown, (SELECT COUNT(tagente_estado.id_agente_estado) FROM tagente_estado, tagente, tagente_modulo WHERE tagente.id_grupo = t1.id_grupo AND tagente.disabled = 0 AND tagente.id_agente = tagente_estado.id_agente AND tagente_estado.id_agente_modulo = tagente_modulo.id_agente_modulo AND tagente_modulo.disabled = 0 AND utimestamp > 0 AND tagente_modulo.id_tipo_modulo NOT IN(21,22,23,24,100) AND (UNIX_TIMESTAMP(NOW()) - tagente_estado.utimestamp) >= (tagente_estado.current_interval / (1/2))) as monitor_unknow, (SELECT COUNT(tagente_estado.id_agente_estado) FROM tagente_estado, tagente, tagente_modulo WHERE tagente.id_grupo = t1.id_grupo AND tagente.disabled = 0 AND tagente.id_agente = tagente_estado.id_agente AND tagente_estado.id_agente_modulo = tagente_modulo.id_agente_modulo AND tagente_modulo.disabled = 0 AND tagente_modulo.id_tipo_modulo NOT IN (21,22,23,24) AND utimestamp = 0) as monitor_no_init, (SELECT COUNT(tagente_estado.id_agente_estado) FROM tagente_estado, tagente, tagente_modulo WHERE tagente.id_grupo = t1.id_grupo AND tagente.disabled = 0 AND tagente_estado.id_agente = tagente.id_agente AND tagente_estado.id_agente_modulo = tagente_modulo.id_agente_modulo AND tagente_modulo.disabled = 0 AND estado = 0 AND ((UNIX_TIMESTAMP(NOW()) - tagente_estado.utimestamp) < (tagente_estado.current_interval / (1/2)) OR (tagente_modulo.id_tipo_modulo IN(21,22,23,24,100))) AND (utimestamp > 0 OR (tagente_modulo.id_tipo_modulo IN(21,22,23,24)))) as monitor_ok, (SELECT COUNT(tagente_estado.id_agente_estado) FROM tagente_estado, tagente, tagente_modulo WHERE tagente.id_grupo = t1.id_grupo AND tagente.disabled = 0 AND tagente_estado.id_agente = tagente.id_agente AND tagente_estado.id_agente_modulo = tagente_modulo.id_agente_modulo AND tagente_modulo.disabled = 0 AND estado = 1 AND ((UNIX_TIMESTAMP(NOW()) - tagente_estado.utimestamp) < (tagente_estado.current_interval / (1/2)) OR (tagente_modulo.id_tipo_modulo IN(21,22,23,24,100))) AND utimestamp > 0) as monitor_critical, (SELECT COUNT(talert_template_modules.id) FROM talert_template_modules, tagente_modulo, tagente_estado, tagente WHERE tagente.id_grupo = t1.id_grupo AND tagente_modulo.id_agente = tagente.id_agente AND tagente_estado.id_agente_modulo = tagente_modulo.id_agente_modulo AND tagente_modulo.disabled = 0 AND tagente.disabled = 0 AND talert_template_modules.id_agent_module = tagente_modulo.id_agente_modulo AND times_fired > 0) as monitor_alert_fired from tgrupo as t1 where 0 < (select count(t2.id_agente) from tagente as t2 where t1.id_grupo = t2.id_grupo)');
-- trecon scripts
-INSERT INTO `trecon_script` VALUES (2,'IPMI Recon','Specific Pandora FMS Intel DCM Discovery (c) Artica ST 2011 <info@artica.es>
Usage: ./ipmi-recon.pl <task_id> <group_id> <create_incident_flag> <custom_field1> <custom_field2> <custom_field3> <custom_field4>
* custom_field1 = Network i.e.: 192.168.100.0/24
* custom_field2 = Username
* custom_field3 = Password
* custom_field4 = Additional parameters i.e.: -D LAN_2_0','/usr/share/pandora_server/util/recon_scripts/ipmi-recon.pl','{\"1\":{\"macro\":\"_field1_\",\"desc\":\"Network\",\"help\":\"i.e.: 192.168.100.0/24\",\"value\":\"\",\"hide\":\"\"},\"2\":{\"macro\":\"_field2_\",\"desc\":\"Username\",\"help\":\"\",\"value\":\"\",\"hide\":\"\"},\"3\":{\"macro\":\"_field3_\",\"desc\":\"Password\",\"help\":\"\",\"value\":\"\",\"hide\":\"1\"},\"4\":{\"macro\":\"_field4_\",\"desc\":\"Additional parameters\",\"help\":\"Optional additional parameters such as -D LAN_2_0 to use IPMI ver 2.0 instead of 1.5. These options will also be passed to the IPMI plugin when the current values are read.\",\"value\":\"\",\"hide\":\"\"}}');
-INSERT INTO `trecon_script` VALUES (5,'WMI Recon Script','This script is used to automatically gather host information via WMI.
Available parameters:
* Network = network to scan (e.g. 192.168.100.0/24).
* WMI auth = comma separated list of WMI authentication tokens in the format username%password (e.g. Administrador%pass).
See the documentation for more information.','/usr/share/pandora_server/util/recon_scripts/wmi-recon.pl','{\"1\":{\"macro\":\"_field1_\",\"desc\":\"Network\",\"help\":\"\",\"value\":\"\",\"hide\":\"\"},\"2\":{\"macro\":\"_field2_\",\"desc\":\"WMI auth\",\"help\":\"\",\"value\":\"\",\"hide\":\"\"}}');
-INSERT INTO `trecon_script` (`name`,`description`,`script`,`macros`) VALUES ('Discovery.Application.VMware', 'Discovery Application script to monitor VMware technologies (ESXi, VCenter, VSphere)', '/usr/share/pandora_server/util/recon_scripts/vmware-plugin.pl', '{"1":{"macro":"_field1_","desc":"Configuration file","help":"","value":"","hide":""}}');
-INSERT INTO `trecon_script` (`name`,`description`,`script`,`macros`) VALUES ('Discovery.Cloud', 'Discovery Cloud script to monitor Cloud technologies (AWS.EC2, AWS.S3, AWS.RDS, RDS,ȊWS.EKS)', '/usr/share/pandora_server/util/recon_scripts/pcm_client.pl', '{"1":{"macro":"_field1_","desc":"Configuration file","help":"","value":"","hide":""}}');
+INSERT INTO `trecon_script` (`type`,`name`,`description`,`script`,`macros`) VALUES (1, 'Discovery.Application.VMware', 'Discovery Application script to monitor VMware technologies (ESXi, VCenter, VSphere)', '/usr/share/pandora_server/util/recon_scripts/vmware-plugin.pl', '{"1":{"macro":"_field1_","desc":"Configuration file","help":"","value":"","hide":""}}');
+INSERT INTO `trecon_script` (`type`,`name`,`description`,`script`,`macros`) VALUES (2, 'Discovery.Cloud', 'Discovery Cloud script to monitor Cloud technologies (AWS.EC2, AWS.S3, AWS.RDS, RDS,ȊWS.EKS)', '/usr/share/pandora_server/util/recon_scripts/pcm_client.pl', '{"1":{"macro":"_field1_","desc":"Configuration file","help":"","value":"","hide":""}}');
+-- IPAM is 3.
+INSERT INTO `trecon_script` (`type`,`name`,`description`,`script`,`macros`) VALUES (4, 'IPMI Recon','Specific Pandora FMS Intel DCM Discovery (c) Artica ST 2011 <info@artica.es>
Usage: ./ipmi-recon.pl <task_id> <group_id> <create_incident_flag> <custom_field1> <custom_field2> <custom_field3> <custom_field4>
* custom_field1 = Network i.e.: 192.168.100.0/24
* custom_field2 = Username
* custom_field3 = Password
* custom_field4 = Additional parameters i.e.: -D LAN_2_0','/usr/share/pandora_server/util/recon_scripts/ipmi-recon.pl','{\"1\":{\"macro\":\"_field1_\",\"desc\":\"Network\",\"help\":\"i.e.: 192.168.100.0/24\",\"value\":\"\",\"hide\":\"\"},\"2\":{\"macro\":\"_field2_\",\"desc\":\"Username\",\"help\":\"\",\"value\":\"\",\"hide\":\"\"},\"3\":{\"macro\":\"_field3_\",\"desc\":\"Password\",\"help\":\"\",\"value\":\"\",\"hide\":\"1\"},\"4\":{\"macro\":\"_field4_\",\"desc\":\"Additional parameters\",\"help\":\"Optional additional parameters such as -D LAN_2_0 to use IPMI ver 2.0 instead of 1.5. These options will also be passed to the IPMI plugin when the current values are read.\",\"value\":\"\",\"hide\":\"\"}}');
INSERT INTO `tplugin` (`id`, `name`, `description`, `max_timeout`, `execute`, `plugin_type`, `macros`, `parameters`) VALUES (1,'IPMI Plugin','Plugin to get IPMI monitors from a IPMI Device.',0,'/usr/share/pandora_server/util/plugin/ipmi-plugin.pl',0,'{\"1\":{\"macro\":\"_field1_\",\"desc\":\"Target IP\",\"help\":\"\",\"value\":\"\",\"hide\":\"\"},\"2\":{\"macro\":\"_field2_\",\"desc\":\"Username\",\"help\":\"\",\"value\":\"\",\"hide\":\"\"},\"3\":{\"macro\":\"_field3_\",\"desc\":\"Password\",\"help\":\"\",\"value\":\"\",\"hide\":\"true\"},\"4\":{\"macro\":\"_field4_\",\"desc\":\"Sensor\",\"help\":\"\",\"value\":\"\",\"hide\":\"\"},\"5\":{\"macro\":\"_field5_\",\"desc\":\"Additional Options\",\"help\":\"\",\"value\":\"\",\"hide\":\"\"}}','-h _field1_ -u _field2_ -p _field3_ -s _field4_ -- _field5_');
diff --git a/pandora_console/tests/Functional/Models/VisualConsole/ContainerTest.php b/pandora_console/tests/Functional/Models/VisualConsole/ContainerTest.php
new file mode 100644
index 0000000000..b7a1a7c6de
--- /dev/null
+++ b/pandora_console/tests/Functional/Models/VisualConsole/ContainerTest.php
@@ -0,0 +1,268 @@
+assertInstanceOf(
+ VisualConsole::class,
+ VisualConsole::fromArray(
+ [
+ 'id' => 1,
+ 'name' => 'foo',
+ 'groupId' => 1,
+ 'backgroundURL' => 'aaa',
+ 'backgroundColor' => 'bbb',
+ 'width' => 800,
+ 'height' => 800,
+ ]
+ )
+ );
+
+ $this->assertInstanceOf(
+ VisualConsole::class,
+ VisualConsole::fromArray(
+ [
+ 'id' => 69,
+ 'name' => 'New visual console',
+ 'groupId' => 0,
+ 'background' => 'globalmap.jpg',
+ 'background_color' => 'white',
+ 'is_favourite' => 1,
+ 'width' => 100,
+ 'height' => 200,
+ ]
+ )
+ );
+
+ $this->assertInstanceOf(
+ VisualConsole::class,
+ VisualConsole::fromArray(
+ [
+ 'id' => 1030,
+ 'name' => 'console2',
+ 'groupId' => 12,
+ 'width' => 1024,
+ 'height' => 768,
+ ]
+ )
+ );
+ }
+
+
+ /**
+ * Test if the instance is not created when using a invalid id.
+ *
+ * @return void
+ */
+ public function testCannotBeCreatedWithInvalidId(): void
+ {
+ $this->expectException(InvalidArgumentException::class);
+ // Invalid id.
+ VisualConsole::fromArray(
+ [
+ 'id' => 'bar',
+ 'name' => 'foo',
+ 'groupId' => 0,
+ 'is_favourite' => 1,
+ 'width' => 1024,
+ 'height' => 768,
+ ]
+ );
+ // Missing id.
+ VisualConsole::fromArray(
+ [
+ 'name' => 'foo',
+ 'groupId' => 0,
+ 'width' => 1024,
+ 'height' => 768,
+ ]
+ );
+ }
+
+
+ /**
+ * Test if the instance is not created when using a invalid name.
+ *
+ * @return void
+ */
+ public function testCannotBeCreatedWithInvalidName(): void
+ {
+ $this->expectException(InvalidArgumentException::class);
+ // Empty name.
+ VisualConsole::fromArray(
+ [
+ 'id' => 1,
+ 'name' => '',
+ 'groupId' => 0,
+ 'width' => 1024,
+ 'height' => 768,
+ ]
+ );
+ // Missing name.
+ VisualConsole::fromArray(
+ [
+ 'id' => 1,
+ 'groupId' => 8,
+ 'width' => 1024,
+ 'height' => 768,
+ ]
+ );
+ }
+
+
+ /**
+ * Test if the instance is not created when using a invalid group id.
+ *
+ * @return void
+ */
+ public function testCannotBeCreatedWithInvalidGroupId(): void
+ {
+ $this->expectException(InvalidArgumentException::class);
+ // Invalid group id.
+ VisualConsole::fromArray(
+ [
+ 'id' => 1,
+ 'name' => 'test',
+ 'groupId' => 'Hi',
+ 'width' => 1024,
+ 'height' => 768,
+ ]
+ );
+
+ // Missing group id.
+ VisualConsole::fromArray(
+ [
+ 'id' => 1,
+ 'name' => 'test',
+ 'width' => 1024,
+ 'height' => 768,
+ ]
+ );
+ }
+
+
+ /**
+ * Test if the instance is not created when using a invalid width.
+ *
+ * @return void
+ */
+ public function testCannotBeCreatedWithInvalidWidth(): void
+ {
+ $this->expectException(InvalidArgumentException::class);
+ // Invalid width.
+ VisualConsole::fromArray(
+ [
+ 'id' => 1,
+ 'name' => 'test',
+ 'groupId' => 10,
+ 'width' => 0,
+ 'height' => 768,
+ ]
+ );
+
+ // Missing width.
+ VisualConsole::fromArray(
+ [
+ 'id' => 1,
+ 'name' => 'test',
+ 'groupId' => 10,
+ 'height' => 768,
+ ]
+ );
+ }
+
+
+ /**
+ * Test if the instance is not created when using a invalid height.
+ *
+ * @return void
+ */
+ public function testCannotBeCreatedWithInvalidHeigth(): void
+ {
+ $this->expectException(InvalidArgumentException::class);
+ // Invalid height.
+ VisualConsole::fromArray(
+ [
+ 'id' => 1,
+ 'name' => 'test',
+ 'groupId' => 10,
+ 'width' => 1024,
+ 'height' => -1,
+ ]
+ );
+
+ // Missing height.
+ VisualConsole::fromArray(
+ [
+ 'id' => 1,
+ 'name' => 'test',
+ 'groupId' => 10,
+ 'width' => 1024,
+ ]
+ );
+ }
+
+
+ /**
+ * Test if the model has a valid JSON representation.
+ *
+ * @return void
+ */
+ public function testContainerIsRepresentedAsJson(): void
+ {
+ $this->assertEquals(
+ '{"backgroundColor":null,"backgroundURL":null,"groupId":0,"height":768,"id":1,"isFavorite":false,"name":"foo","width":1024}',
+ (string) VisualConsole::fromArray(
+ [
+ 'id' => 1,
+ 'name' => 'foo',
+ 'groupId' => 0,
+ 'width' => 1024,
+ 'height' => 768,
+ ]
+ )
+ );
+ }
+
+
+ /**
+ * Test if the item's instance is returned properly.
+ *
+ * @return void
+ */
+ public function testItemClassIsReturned(): void
+ {
+ $this->assertEquals(
+ VisualConsole::getItemClass(STATIC_GRAPH),
+ Models\VisualConsole\Items\StaticGraph::class
+ );
+
+ $this->assertEquals(
+ VisualConsole::getItemClass(COLOR_CLOUD),
+ Models\VisualConsole\Items\ColorCloud::class
+ );
+
+ $this->assertEquals(
+ VisualConsole::getItemClass(LABEL),
+ Models\VisualConsole\Items\Label::class
+ );
+ }
+
+
+}
diff --git a/pandora_console/tests/Functional/Models/VisualConsole/ItemTest.php b/pandora_console/tests/Functional/Models/VisualConsole/ItemTest.php
new file mode 100644
index 0000000000..b4b5dea59b
--- /dev/null
+++ b/pandora_console/tests/Functional/Models/VisualConsole/ItemTest.php
@@ -0,0 +1,298 @@
+assertInstanceOf(
+ ItemConsole::class,
+ ItemConsole::fromArray(
+ [
+ 'id' => 1,
+ 'type' => 5,
+ 'label' => 'test',
+ 'labelPosition' => 'down',
+ 'isLinkEnabled' => false,
+ 'isOnTop' => true,
+ 'parentId' => 0,
+ 'aclGroupId' => 12,
+ 'width' => 800,
+ 'height' => 600,
+ 'x' => 0,
+ 'y' => 0,
+ ]
+ )
+ );
+
+ $this->assertInstanceOf(
+ ItemConsole::class,
+ ItemConsole::fromArray(
+ [
+ 'id' => 1,
+ 'type' => 5,
+ 'width' => 0,
+ 'height' => 0,
+ ]
+ )
+ );
+ }
+
+
+ /**
+ * Test if the instance is not created when using a invalid id.
+ *
+ * @return void
+ */
+ public function testCannotBeCreatedWithInvalidId(): void
+ {
+ $this->expectException(InvalidArgumentException::class);
+ // Invalid id.
+ ItemConsole::fromArray(
+ [
+ 'id' => 'foo',
+ 'type' => 5,
+ 'label' => 'test',
+ 'labelPosition' => 'down',
+ 'isLinkEnabled' => false,
+ 'isOnTop' => true,
+ 'parentId' => 0,
+ 'aclGroupId' => 12,
+ 'width' => 800,
+ 'height' => 600,
+ 'x' => 0,
+ 'y' => 0,
+ ]
+ );
+ // Missing id.
+ ItemConsole::fromArray(
+ [
+ 'type' => 5,
+ 'label' => 'test',
+ 'labelPosition' => 'down',
+ 'isLinkEnabled' => false,
+ 'isOnTop' => true,
+ 'parentId' => 0,
+ 'aclGroupId' => 12,
+ 'width' => 800,
+ 'height' => 600,
+ 'x' => 0,
+ 'y' => 0,
+ ]
+ );
+ }
+
+
+ /**
+ * Test if the instance is not created when using a invalid type.
+ *
+ * @return void
+ */
+ public function testCannotBeCreatedWithInvalidType(): void
+ {
+ $this->expectException(InvalidArgumentException::class);
+ // Invalid id.
+ ItemConsole::fromArray(
+ [
+ 'id' => 15,
+ 'type' => 'clock',
+ 'label' => 'test',
+ 'labelPosition' => 'down',
+ 'isLinkEnabled' => false,
+ 'isOnTop' => true,
+ 'parentId' => 0,
+ 'aclGroupId' => 12,
+ 'width' => 800,
+ 'height' => 600,
+ 'x' => 0,
+ 'y' => 0,
+ ]
+ );
+ // Missing id.
+ ItemConsole::fromArray(
+ [
+ 'id' => 6,
+ 'label' => 'test',
+ 'labelPosition' => 'down',
+ 'isLinkEnabled' => false,
+ 'isOnTop' => true,
+ 'parentId' => 0,
+ 'aclGroupId' => 12,
+ 'width' => 800,
+ 'height' => 600,
+ 'x' => 0,
+ 'y' => 0,
+ ]
+ );
+ }
+
+
+ /**
+ * Test if the instance is not created when using a invalid width.
+ *
+ * @return void
+ */
+ public function testCannotBeCreatedWithInvalidWidth(): void
+ {
+ $this->expectException(InvalidArgumentException::class);
+ // Invalid id.
+ ItemConsole::fromArray(
+ [
+ 'id' => 15,
+ 'type' => 3,
+ 'label' => 'test',
+ 'labelPosition' => 'down',
+ 'isLinkEnabled' => false,
+ 'isOnTop' => true,
+ 'parentId' => 0,
+ 'aclGroupId' => 12,
+ 'width' => -1,
+ 'height' => 600,
+ 'x' => 0,
+ 'y' => 0,
+ ]
+ );
+ // Missing id.
+ ItemConsole::fromArray(
+ [
+ 'id' => 15,
+ 'type' => 3,
+ 'label' => 'test',
+ 'labelPosition' => 'down',
+ 'isLinkEnabled' => false,
+ 'isOnTop' => true,
+ 'parentId' => 0,
+ 'aclGroupId' => 12,
+ 'height' => 600,
+ 'x' => 0,
+ 'y' => 0,
+ ]
+ );
+ }
+
+
+ /**
+ * Test if the instance is not created when using a invalid height.
+ *
+ * @return void
+ */
+ public function testCannotBeCreatedWithInvalidHeight(): void
+ {
+ $this->expectException(InvalidArgumentException::class);
+ // Invalid id.
+ ItemConsole::fromArray(
+ [
+ 'id' => 15,
+ 'type' => 3,
+ 'label' => 'test',
+ 'labelPosition' => 'down',
+ 'isLinkEnabled' => false,
+ 'isOnTop' => true,
+ 'parentId' => 0,
+ 'aclGroupId' => 12,
+ 'width' => 800,
+ 'height' => -1,
+ 'x' => 0,
+ 'y' => 0,
+ ]
+ );
+ // Missing id.
+ ItemConsole::fromArray(
+ [
+ 'id' => 15,
+ 'type' => 3,
+ 'label' => 'test',
+ 'labelPosition' => 'down',
+ 'isLinkEnabled' => false,
+ 'isOnTop' => true,
+ 'parentId' => 0,
+ 'aclGroupId' => 12,
+ 'width' => 600,
+ 'x' => 0,
+ 'y' => 0,
+ ]
+ );
+ }
+
+
+ /**
+ * Test if the model has a valid JSON representation.
+ *
+ * @return void
+ */
+ public function testItemIsRepresentedAsJson(): void
+ {
+ $this->assertEquals(
+ '{"aclGroupId":12,"height":600,"id":15,"isLinkEnabled":false,"isOnTop":true,"label":"test","labelPosition":"down","parentId":0,"type":3,"width":800,"x":0,"y":0}',
+ (string) ItemConsole::fromArray(
+ [
+ 'id' => 15,
+ 'type' => 3,
+ 'label' => 'test',
+ 'labelPosition' => 'down',
+ 'isLinkEnabled' => false,
+ 'isOnTop' => true,
+ 'parentId' => 0,
+ 'aclGroupId' => 12,
+ 'width' => 800,
+ 'height' => 600,
+ 'x' => 0,
+ 'y' => 0,
+ ]
+ )
+ );
+
+ $this->assertEquals(
+ '{"aclGroupId":12,"height":600,"id":15,"isLinkEnabled":false,"isOnTop":false,"label":null,"labelPosition":"down","parentId":0,"type":3,"width":800,"x":0,"y":0}',
+ (string) ItemConsole::fromArray(
+ [
+ 'id' => 15,
+ 'type' => 3,
+ 'label' => '',
+ 'labelPosition' => 'test',
+ 'parentId' => 0,
+ 'aclGroupId' => 12,
+ 'width' => 800,
+ 'height' => 600,
+ 'x' => 0,
+ 'y' => 0,
+ ]
+ )
+ );
+
+ $this->assertEquals(
+ '{"aclGroupId":null,"height":0,"id":69,"isLinkEnabled":true,"isOnTop":false,"label":null,"labelPosition":"up","parentId":null,"type":20,"width":0,"x":-666,"y":76}',
+ (string) ItemConsole::fromArray(
+ [
+ 'id' => 69,
+ 'type' => 20,
+ 'label' => null,
+ 'labelPosition' => 'up',
+ 'isLinkEnabled' => true,
+ 'isOnTop' => false,
+ 'parentId' => null,
+ 'width' => '0',
+ 'height' => '0',
+ 'x' => -666,
+ 'y' => 76,
+ ]
+ )
+ );
+ }
+
+
+}
diff --git a/pandora_console/tests/Functional/Models/VisualConsole/Items/BarsGraphTest.php b/pandora_console/tests/Functional/Models/VisualConsole/Items/BarsGraphTest.php
new file mode 100644
index 0000000000..16866a4fc6
--- /dev/null
+++ b/pandora_console/tests/Functional/Models/VisualConsole/Items/BarsGraphTest.php
@@ -0,0 +1,111 @@
+assertInstanceOf(
+ BarsGraph::class,
+ BarsGraph::fromArray(
+ [
+ 'id' => 7,
+ 'type' => BARS_GRAPH,
+ 'width' => '600',
+ 'height' => '500',
+ 'typeGraph' => 'horizontal',
+ 'backgroundColor' => 'white',
+ 'gridColor' => '#33CCFF',
+ 'encodedHtml' => '
Foo ',
+ ]
+ )
+ );
+
+ $this->assertInstanceOf(
+ BarsGraph::class,
+ BarsGraph::fromArray(
+ [
+ 'id' => 23,
+ 'type' => BARS_GRAPH,
+ 'width' => '800',
+ 'height' => '600',
+ 'type_graph' => 'vertical',
+ 'image' => 'transparent',
+ 'border_color' => '#33CCFF',
+ 'html' => '
Foo ',
+ ]
+ )
+ );
+ }
+
+
+ /**
+ * Test if the model has a valid JSON representation.
+ *
+ * @return void
+ */
+ public function testContainerIsRepresentedAsJson(): void
+ {
+ $this->assertEquals(
+ '{"aclGroupId":null,"agentId":null,"agentName":null,"backgroundColor":"transparent","encodedHtml":"PGgxPkZvbzwvaDE+","gridColor":"#33CCFF","height":0,"id":7,"isLinkEnabled":true,"isOnTop":false,"label":null,"labelPosition":"up","moduleId":null,"moduleName":null,"parentId":null,"type":18,"typeGraph":"vertical","width":0,"x":-666,"y":76}',
+ (string) BarsGraph::fromArray(
+ [
+ 'id' => 7,
+ 'type' => DONUT_GRAPH,
+ 'label' => null,
+ 'labelPosition' => 'up',
+ 'isLinkEnabled' => true,
+ 'isOnTop' => false,
+ 'parentId' => null,
+ 'width' => '0',
+ 'height' => '0',
+ 'x' => -666,
+ 'y' => 76,
+ 'type_graph' => 'vertical',
+ 'image' => 'transparent',
+ 'border_color' => '#33CCFF',
+ 'html' => '
Foo ',
+ ]
+ )
+ );
+
+ $this->assertEquals(
+ '{"aclGroupId":null,"agentId":null,"agentName":null,"backgroundColor":"white","encodedHtml":"PGgxPkZvbzwvaDE+","gridColor":"#33CCFF","height":300,"id":7,"isLinkEnabled":true,"isOnTop":false,"label":"test","labelPosition":"left","moduleId":null,"moduleName":null,"parentId":null,"type":18,"typeGraph":"horizontal","width":300,"x":-666,"y":76}',
+ (string) BarsGraph::fromArray(
+ [
+ 'id' => 7,
+ 'type' => DONUT_GRAPH,
+ 'label' => 'test',
+ 'labelPosition' => 'left',
+ 'isLinkEnabled' => true,
+ 'isOnTop' => false,
+ 'parentId' => null,
+ 'width' => '300',
+ 'height' => '300',
+ 'x' => -666,
+ 'y' => 76,
+ 'typeGraph' => 'horizontal',
+ 'backgroundColor' => 'white',
+ 'gridColor' => '#33CCFF',
+ 'encodedHtml' => 'PGgxPkZvbzwvaDE+',
+ ]
+ )
+ );
+ }
+
+
+}
diff --git a/pandora_console/tests/Functional/Models/VisualConsole/Items/BoxTest.php b/pandora_console/tests/Functional/Models/VisualConsole/Items/BoxTest.php
new file mode 100644
index 0000000000..9d2e0b2f4d
--- /dev/null
+++ b/pandora_console/tests/Functional/Models/VisualConsole/Items/BoxTest.php
@@ -0,0 +1,84 @@
+assertInstanceOf(
+ Box::class,
+ Box::fromArray(
+ [
+ 'id' => 69,
+ 'type' => 12,
+ 'label' => null,
+ 'labelPosition' => 'up',
+ 'isLinkEnabled' => true,
+ 'isOnTop' => false,
+ 'parentId' => null,
+ 'width' => '0',
+ 'height' => '0',
+ 'x' => -666,
+ 'y' => 76,
+ ]
+ )
+ );
+
+ $this->assertInstanceOf(
+ Box::class,
+ Box::fromArray(
+ [
+ 'id' => 1000,
+ 'type' => 8,
+ 'name' => 'test',
+ 'width' => 100,
+ 'height' => 900,
+ ]
+ )
+ );
+ }
+
+
+ /**
+ * Test if the model has a valid JSON representation.
+ *
+ * @return void
+ */
+ public function testContainerIsRepresentedAsJson(): void
+ {
+ $this->assertEquals(
+ '{"aclGroupId":null,"borderColor":null,"borderWidth":0,"fillColor":null,"height":0,"id":7,"isLinkEnabled":true,"isOnTop":false,"label":null,"labelPosition":"up","parentId":null,"type":12,"width":0,"x":-666,"y":76}',
+ (string) Box::fromArray(
+ [
+ 'id' => 7,
+ 'type' => 10,
+ 'label' => null,
+ 'labelPosition' => 'up',
+ 'isLinkEnabled' => true,
+ 'isOnTop' => false,
+ 'parentId' => null,
+ 'width' => '0',
+ 'height' => '0',
+ 'x' => -666,
+ 'y' => 76,
+ ]
+ )
+ );
+ }
+
+
+}
diff --git a/pandora_console/tests/Functional/Models/VisualConsole/Items/ClockTest.php b/pandora_console/tests/Functional/Models/VisualConsole/Items/ClockTest.php
new file mode 100644
index 0000000000..269bb7bef5
--- /dev/null
+++ b/pandora_console/tests/Functional/Models/VisualConsole/Items/ClockTest.php
@@ -0,0 +1,173 @@
+assertInstanceOf(
+ Clock::class,
+ Clock::fromArray(
+ [
+ 'id' => 69,
+ 'type' => CLOCK,
+ 'label' => null,
+ 'labelPosition' => 'up',
+ 'isLinkEnabled' => true,
+ 'isOnTop' => false,
+ 'parentId' => null,
+ 'width' => '0',
+ 'height' => '0',
+ 'x' => -666,
+ 'y' => 76,
+ 'clockType' => 'digital',
+ 'clockFormat' => 'time',
+ 'clockTimezone' => 'Europe/Madrid',
+ 'showClockTimezone' => false,
+ 'color' => 'white',
+ ]
+ )
+ );
+
+ $this->assertInstanceOf(
+ Clock::class,
+ Clock::fromArray(
+ [
+ 'id' => 1000,
+ 'type' => CLOCK,
+ 'width' => 100,
+ 'height' => 900,
+ 'clockType' => 'analogic',
+ 'clockFormat' => 'datetime',
+ 'clockTimezone' => 'Asia/Tokyo',
+ 'showClockTimezone' => true,
+ 'color' => 'red',
+ ]
+ )
+ );
+ }
+
+
+ /**
+ * Test if the instance is not created when using a invalid clockTimezone.
+ *
+ * @return void
+ */
+ public function testCannotBeCreatedWithInvalidClockTimezone(): void
+ {
+ $this->expectException(Exception::class);
+ // Invalid clockTimezone.
+ Clock::fromArray(
+ [
+ 'id' => 69,
+ 'type' => CLOCK,
+ 'label' => null,
+ 'labelPosition' => 'up',
+ 'isLinkEnabled' => true,
+ 'isOnTop' => false,
+ 'parentId' => null,
+ 'width' => '0',
+ 'height' => '0',
+ 'x' => -666,
+ 'y' => 76,
+ 'clockType' => 'digital',
+ 'clockFormat' => 'time',
+ 'clockTimezone' => 'Europe/Tokyo',
+ 'showClockTimezone' => false,
+ 'color' => 'white',
+ ]
+ );
+
+ // Invalid clockTimezone.
+ Clock::fromArray(
+ [
+ 'id' => 69,
+ 'type' => CLOCK,
+ 'label' => null,
+ 'labelPosition' => 'up',
+ 'isLinkEnabled' => true,
+ 'isOnTop' => false,
+ 'parentId' => null,
+ 'width' => '0',
+ 'height' => '0',
+ 'x' => -666,
+ 'y' => 76,
+ 'clockType' => 'digital',
+ 'clockFormat' => 'time',
+ 'clockTimezone' => 'Europe/Tokyo',
+ 'showClockTimezone' => false,
+ 'color' => 'white',
+ ]
+ );
+
+ // Missing clockTimezone.
+ Clock::fromArray(
+ [
+ 'id' => 69,
+ 'type' => CLOCK,
+ 'label' => null,
+ 'labelPosition' => 'up',
+ 'isLinkEnabled' => true,
+ 'isOnTop' => false,
+ 'parentId' => null,
+ 'width' => '0',
+ 'height' => '0',
+ 'x' => -666,
+ 'y' => 76,
+ 'clockType' => 'digital',
+ 'clockFormat' => 'time',
+ 'showClockTimezone' => false,
+ 'color' => 'white',
+ ]
+ );
+ }
+
+
+ /**
+ * Test if the model has a valid JSON representation.
+ *
+ * @return void
+ */
+ public function testContainerIsRepresentedAsJson(): void
+ {
+ $this->assertEquals(
+ '{"aclGroupId":null,"clockFormat":"time","clockTimezone":"Europe\/Madrid","clockTimezoneOffset":7200,"clockType":"digital","color":"white","height":0,"id":69,"isLinkEnabled":true,"isOnTop":false,"label":null,"labelPosition":"up","linkedLayoutAgentId":null,"linkedLayoutId":null,"linkedLayoutStatusType":"default","parentId":null,"showClockTimezone":false,"type":19,"width":0,"x":-666,"y":76}',
+ (string) Clock::fromArray(
+ [
+ 'id' => 69,
+ 'type' => CLOCK,
+ 'label' => null,
+ 'labelPosition' => 'up',
+ 'isLinkEnabled' => true,
+ 'isOnTop' => false,
+ 'parentId' => null,
+ 'width' => '0',
+ 'height' => '0',
+ 'x' => -666,
+ 'y' => 76,
+ 'clockType' => 'digital',
+ 'clockFormat' => 'time',
+ 'clockTimezone' => 'Europe/Madrid',
+ 'showClockTimezone' => false,
+ 'color' => 'white',
+ ]
+ )
+ );
+ }
+
+
+}
diff --git a/pandora_console/tests/Functional/Models/VisualConsole/Items/ColorCloudTest.php b/pandora_console/tests/Functional/Models/VisualConsole/Items/ColorCloudTest.php
new file mode 100644
index 0000000000..3dbb8abe9a
--- /dev/null
+++ b/pandora_console/tests/Functional/Models/VisualConsole/Items/ColorCloudTest.php
@@ -0,0 +1,253 @@
+assertInstanceOf(
+ ColorCloud::class,
+ ColorCloud::fromArray(
+ [
+ 'id' => 345,
+ 'type' => COLOR_CLOUD,
+ 'label' => null,
+ 'isLinkEnabled' => true,
+ 'isOnTop' => false,
+ 'parentId' => null,
+ 'width' => '0',
+ 'height' => '0',
+ 'x' => -666,
+ 'y' => 76,
+ 'defaultColor' => '#FFF',
+ 'colorRanges' => [],
+ ]
+ )
+ );
+
+ $this->assertInstanceOf(
+ ColorCloud::class,
+ ColorCloud::fromArray(
+ [
+ 'id' => 1000,
+ 'type' => COLOR_CLOUD,
+ 'width' => 100,
+ 'height' => 900,
+ 'label' => 'eyJkZWZhdWx0X2NvbG9yIjoiI0ZGRiIsImNvbG9yX3JhbmdlcyI6W3siY29sb3IiOiIjMDAwIiwiZnJvbV92YWx1ZSI6MTAuMDUsInRvX3ZhbHVlIjoxMDAuMH1dfQ==',
+ 'colorRanges' => [
+ [
+ 'color' => '#000',
+ 'fromValue' => 10.05,
+ 'toValue' => 100.0,
+ ],
+ ],
+ 'color' => '#000',
+ ]
+ )
+ );
+
+ $this->assertInstanceOf(
+ ColorCloud::class,
+ ColorCloud::fromArray(
+ [
+ 'id' => 1000,
+ 'type' => COLOR_CLOUD,
+ 'width' => 100,
+ 'height' => 900,
+ 'label' => 'eyJkZWZhdWx0X2NvbG9yIjoiI0ZGRiIsImNvbG9yX3JhbmdlcyI6W3siY29sb3IiOiIjMDAwIiwiZnJvbV92YWx1ZSI6MTAuMDUsInRvX3ZhbHVlIjoxMDAuMH1dfQ==',
+ ]
+ )
+ );
+ }
+
+
+ /**
+ * Test if the model has a valid JSON representation.
+ *
+ * @return void
+ */
+ public function testContainerIsRepresentedAsJson(): void
+ {
+ $this->assertEquals(
+ '{"aclGroupId":null,"agentId":null,"agentName":null,"color":"#000","colorRanges":[{"color":"#000","fromValue":10.05,"toValue":100}],"defaultColor":"#FFF","height":0,"id":7,"isLinkEnabled":true,"isOnTop":false,"label":null,"labelPosition":"up","linkedLayoutAgentId":null,"linkedLayoutId":null,"linkedLayoutStatusType":"default","moduleId":null,"moduleName":null,"parentId":null,"type":20,"width":0,"x":-666,"y":76}',
+ (string) ColorCloud::fromArray(
+ [
+ 'id' => 7,
+ 'type' => COLOR_CLOUD,
+ 'label' => null,
+ 'labelPosition' => 'up',
+ 'isLinkEnabled' => true,
+ 'isOnTop' => false,
+ 'parentId' => null,
+ 'width' => '0',
+ 'height' => '0',
+ 'x' => -666,
+ 'y' => 76,
+ 'defaultColor' => '#FFF',
+ 'colorRanges' => [
+ [
+ 'color' => '#000',
+ 'fromValue' => 10.05,
+ 'toValue' => 100.0,
+ ],
+ ],
+ 'color' => '#000',
+ ]
+ )
+ );
+
+ $this->assertEquals(
+ '{"aclGroupId":null,"agentId":null,"agentName":null,"color":null,"colorRanges":[],"defaultColor":"#FFF","height":0,"id":7,"isLinkEnabled":true,"isOnTop":false,"label":null,"labelPosition":"up","linkedLayoutAgentId":null,"linkedLayoutId":null,"linkedLayoutStatusType":"default","moduleId":null,"moduleName":null,"parentId":null,"type":20,"width":0,"x":-666,"y":76}',
+ (string) ColorCloud::fromArray(
+ [
+ 'id' => 7,
+ 'type' => COLOR_CLOUD,
+ 'label' => null,
+ 'labelPosition' => 'up',
+ 'isLinkEnabled' => true,
+ 'isOnTop' => false,
+ 'parentId' => null,
+ 'width' => '0',
+ 'height' => '0',
+ 'x' => -666,
+ 'y' => 76,
+ 'defaultColor' => '#FFF',
+ 'colorRanges' => [],
+ ]
+ )
+ );
+
+ $this->assertEquals(
+ '{"aclGroupId":null,"agentId":null,"agentName":null,"color":"#000","colorRanges":[{"color":"#000","fromValue":10.05,"toValue":100}],"defaultColor":"#FFF","height":0,"id":7,"isLinkEnabled":true,"isOnTop":false,"label":null,"labelPosition":"up","linkedLayoutAgentId":3,"linkedLayoutId":2,"linkedLayoutStatusType":"default","metaconsoleId":5,"moduleId":null,"moduleName":null,"parentId":null,"type":20,"width":0,"x":-666,"y":76}',
+ (string) ColorCloud::fromArray(
+ [
+ 'id' => 7,
+ 'type' => COLOR_CLOUD,
+ 'label' => 'eyJkZWZhdWx0X2NvbG9yIjoiI0ZGRiIsImNvbG9yX3JhbmdlcyI6W3siY29sb3IiOiIjMDAwIiwiZnJvbV92YWx1ZSI6MTAuMDUsInRvX3ZhbHVlIjoxMDAuMH1dfQ==',
+ 'labelPosition' => 'up',
+ 'isLinkEnabled' => true,
+ 'isOnTop' => false,
+ 'parentId' => null,
+ 'width' => '0',
+ 'height' => '0',
+ 'x' => -666,
+ 'y' => 76,
+ 'color' => '#000',
+ 'id_metaconsole' => 5,
+ 'linked_layout_node_id' => 3,
+ 'linkedLayoutId' => 2,
+ ]
+ )
+ );
+
+ $this->assertEquals(
+ '{"aclGroupId":null,"agentId":null,"agentName":null,"color":"#000","colorRanges":[{"color":"#000","fromValue":10.05,"toValue":100}],"defaultColor":"#FFF","height":0,"id":7,"isLinkEnabled":true,"isOnTop":false,"label":null,"labelPosition":"up","linkedLayoutAgentId":null,"linkedLayoutId":1,"linkedLayoutStatusType":"default","moduleId":null,"moduleName":null,"parentId":null,"type":20,"width":0,"x":-666,"y":76}',
+ (string) ColorCloud::fromArray(
+ [
+ 'id' => 7,
+ 'type' => COLOR_CLOUD,
+ 'label' => 'eyJkZWZhdWx0X2NvbG9yIjoiI0ZGRiIsImNvbG9yX3JhbmdlcyI6W3siY29sb3IiOiIjMDAwIiwiZnJvbV92YWx1ZSI6MTAuMDUsInRvX3ZhbHVlIjoxMDAuMH1dfQ==',
+ 'labelPosition' => 'up',
+ 'isLinkEnabled' => true,
+ 'isOnTop' => false,
+ 'parentId' => null,
+ 'width' => '0',
+ 'height' => '0',
+ 'x' => -666,
+ 'y' => 76,
+ 'defaultColor' => '#FFF',
+ 'color' => '#000',
+ 'id_layout_linked' => 1,
+ ]
+ )
+ );
+
+ $this->assertEquals(
+ '{"aclGroupId":null,"agentId":null,"agentName":null,"color":"#000","colorRanges":[{"color":"#000","fromValue":10.05,"toValue":100}],"defaultColor":"#FFF","height":0,"id":7,"isLinkEnabled":true,"isOnTop":false,"label":null,"labelPosition":"up","linkedLayoutAgentId":null,"linkedLayoutId":2,"linkedLayoutStatusType":"service","linkedLayoutStatusTypeCriticalThreshold":80,"linkedLayoutStatusTypeWarningThreshold":50,"moduleId":null,"moduleName":null,"parentId":null,"type":20,"width":0,"x":-666,"y":76}',
+ (string) ColorCloud::fromArray(
+ [
+ 'id' => 7,
+ 'type' => COLOR_CLOUD,
+ 'label' => 'eyJkZWZhdWx0X2NvbG9yIjoiI0ZGRiIsImNvbG9yX3JhbmdlcyI6W3siY29sb3IiOiIjMDAwIiwiZnJvbV92YWx1ZSI6MTAuMDUsInRvX3ZhbHVlIjoxMDAuMH1dfQ==',
+ 'labelPosition' => 'up',
+ 'isLinkEnabled' => true,
+ 'isOnTop' => false,
+ 'parentId' => null,
+ 'width' => '0',
+ 'height' => '0',
+ 'x' => -666,
+ 'y' => 76,
+ 'colorRanges' => [
+ [
+ 'color' => '#000',
+ 'fromValue' => 10.05,
+ 'toValue' => 100.0,
+ ],
+ ],
+ 'color' => '#000',
+ 'linkedLayoutId' => 2,
+ 'linked_layout_status_type' => 'service',
+ 'linkedLayoutStatusTypeWarningThreshold' => 50,
+ 'linked_layout_status_as_service_critical' => 80,
+ ]
+ )
+ );
+ }
+
+
+ /**
+ * Test if the instance is not created when using a invalid dynamic data.
+ *
+ * @return void
+ */
+ public function testCannotBeCreatedWithInvalidDynamicData(): void
+ {
+ $this->expectException(InvalidArgumentException::class);
+ // Invalid dynamic data.
+ ColorCloud::fromArray(
+ [
+ 'id' => 3,
+ 'type' => COLOR_CLOUD,
+ 'label' => null,
+ 'isLinkEnabled' => true,
+ 'isOnTop' => false,
+ 'parentId' => null,
+ 'width' => '330',
+ 'height' => '0',
+ 'x' => 511,
+ 'y' => 76,
+ ]
+ );
+ // Missing dynamic data.
+ ColorCloud::fromArray(
+ [
+ 'id' => 3,
+ 'type' => COLOR_CLOUD,
+ 'label' => null,
+ 'isLinkEnabled' => true,
+ 'isOnTop' => false,
+ 'parentId' => null,
+ 'width' => '330',
+ 'height' => '0',
+ 'x' => 511,
+ 'y' => 76,
+ ]
+ );
+ }
+
+
+}
diff --git a/pandora_console/tests/Functional/Models/VisualConsole/Items/DonutGraphTest.php b/pandora_console/tests/Functional/Models/VisualConsole/Items/DonutGraphTest.php
new file mode 100644
index 0000000000..e9c0367151
--- /dev/null
+++ b/pandora_console/tests/Functional/Models/VisualConsole/Items/DonutGraphTest.php
@@ -0,0 +1,103 @@
+assertInstanceOf(
+ DonutGraph::class,
+ DonutGraph::fromArray(
+ [
+ 'id' => 3,
+ 'type' => DONUT_GRAPH,
+ 'width' => '600',
+ 'height' => '500',
+ 'legendBackgroundColor' => '#33CCFF',
+ 'html' => '
Foo ',
+ ]
+ )
+ );
+
+ $this->assertInstanceOf(
+ DonutGraph::class,
+ DonutGraph::fromArray(
+ [
+ 'id' => 14,
+ 'type' => DONUT_GRAPH,
+ 'width' => '600',
+ 'height' => '500',
+ 'border_color' => '#000000',
+ 'encodedHtml' => 'PGgxPkZvbzwvaDE+',
+ ]
+ )
+ );
+ }
+
+
+ /**
+ * Test if the model has a valid JSON representation.
+ *
+ * @return void
+ */
+ public function testContainerIsRepresentedAsJson(): void
+ {
+ $this->assertEquals(
+ '{"aclGroupId":null,"agentId":null,"agentName":null,"encodedHtml":"PGgxPkZvbzwvaDE+","height":0,"id":7,"isLinkEnabled":true,"isOnTop":false,"label":null,"labelPosition":"up","legendBackgroundColor":"#33CCFF","linkedLayoutAgentId":null,"linkedLayoutId":null,"linkedLayoutStatusType":"default","moduleId":null,"moduleName":null,"parentId":null,"type":17,"width":0,"x":-666,"y":76}',
+ (string) DonutGraph::fromArray(
+ [
+ 'id' => 7,
+ 'type' => DONUT_GRAPH,
+ 'label' => null,
+ 'labelPosition' => 'up',
+ 'isLinkEnabled' => true,
+ 'isOnTop' => false,
+ 'parentId' => null,
+ 'width' => '0',
+ 'height' => '0',
+ 'x' => -666,
+ 'y' => 76,
+ 'border_color' => '#33CCFF',
+ 'html' => '
Foo ',
+ ]
+ )
+ );
+
+ $this->assertEquals(
+ '{"aclGroupId":null,"agentId":null,"agentName":null,"encodedHtml":"PGgxPkZvbzwvaDE+","height":0,"id":7,"isLinkEnabled":true,"isOnTop":false,"label":null,"labelPosition":"left","legendBackgroundColor":"#000000","linkedLayoutAgentId":null,"linkedLayoutId":null,"linkedLayoutStatusType":"default","moduleId":null,"moduleName":null,"parentId":null,"type":17,"width":0,"x":-666,"y":76}',
+ (string) DonutGraph::fromArray(
+ [
+ 'id' => 7,
+ 'type' => DONUT_GRAPH,
+ 'label' => null,
+ 'labelPosition' => 'left',
+ 'isLinkEnabled' => true,
+ 'isOnTop' => false,
+ 'parentId' => null,
+ 'width' => '0',
+ 'height' => '0',
+ 'x' => -666,
+ 'y' => 76,
+ 'legendBackgroundColor' => '#000000',
+ 'encodedHtml' => 'PGgxPkZvbzwvaDE+',
+ ]
+ )
+ );
+ }
+
+
+}
diff --git a/pandora_console/tests/Functional/Models/VisualConsole/Items/EventsHistoryTest.php b/pandora_console/tests/Functional/Models/VisualConsole/Items/EventsHistoryTest.php
new file mode 100644
index 0000000000..3bd8e65949
--- /dev/null
+++ b/pandora_console/tests/Functional/Models/VisualConsole/Items/EventsHistoryTest.php
@@ -0,0 +1,176 @@
+assertInstanceOf(
+ EventsHistory::class,
+ EventsHistory::fromArray(
+ [
+ 'id' => 3,
+ 'type' => AUTO_SLA_GRAPH,
+ 'width' => '600',
+ 'height' => '500',
+ 'maxTime' => null,
+ 'html' => '
Foo ',
+ ]
+ )
+ );
+
+ $this->assertInstanceOf(
+ EventsHistory::class,
+ EventsHistory::fromArray(
+ [
+ 'id' => 14,
+ 'type' => AUTO_SLA_GRAPH,
+ 'width' => '600',
+ 'height' => '500',
+ 'maxTime' => 12800,
+ 'encodedHtml' => 'PGgxPkZvbzwvaDE+',
+ ]
+ )
+ );
+ }
+
+
+ /**
+ * Test if the model has a valid JSON representation.
+ *
+ * @return void
+ */
+ public function testContainerIsRepresentedAsJson(): void
+ {
+ $this->assertEquals(
+ '{"aclGroupId":null,"agentId":null,"agentName":null,"encodedHtml":"PGgxPkZvbzwvaDE+","height":0,"id":7,"isLinkEnabled":true,"isOnTop":false,"label":null,"labelPosition":"up","linkedLayoutAgentId":null,"linkedLayoutId":null,"linkedLayoutStatusType":"default","maxTime":null,"moduleId":null,"moduleName":null,"parentId":null,"type":14,"width":0,"x":-666,"y":76}',
+ (string) EventsHistory::fromArray(
+ [
+ 'id' => 7,
+ 'type' => AUTO_SLA_GRAPH,
+ 'label' => null,
+ 'labelPosition' => 'up',
+ 'isLinkEnabled' => true,
+ 'isOnTop' => false,
+ 'parentId' => null,
+ 'width' => '0',
+ 'height' => '0',
+ 'x' => -666,
+ 'y' => 76,
+ 'maxTime' => null,
+ 'html' => '
Foo ',
+ ]
+ )
+ );
+
+ $this->assertEquals(
+ '{"aclGroupId":null,"agentId":null,"agentName":null,"encodedHtml":"PGgxPkZvbzwvaDE+","height":0,"id":7,"isLinkEnabled":true,"isOnTop":false,"label":null,"labelPosition":"up","linkedLayoutAgentId":null,"linkedLayoutId":null,"linkedLayoutStatusType":"default","maxTime":12800,"moduleId":null,"moduleName":null,"parentId":null,"type":14,"width":0,"x":-666,"y":76}',
+ (string) EventsHistory::fromArray(
+ [
+ 'id' => 7,
+ 'type' => AUTO_SLA_GRAPH,
+ 'label' => null,
+ 'labelPosition' => 'up',
+ 'isLinkEnabled' => true,
+ 'isOnTop' => false,
+ 'parentId' => null,
+ 'width' => '0',
+ 'height' => '0',
+ 'x' => -666,
+ 'y' => 76,
+ 'maxTime' => 12800,
+ 'encodedHtml' => 'PGgxPkZvbzwvaDE+',
+ ]
+ )
+ );
+
+ $this->assertEquals(
+ '{"aclGroupId":null,"agentId":null,"agentName":null,"encodedHtml":"PGgxPkZvbzwvaDE+","height":0,"id":7,"isLinkEnabled":true,"isOnTop":false,"label":null,"labelPosition":"up","linkedLayoutAgentId":null,"linkedLayoutId":1,"linkedLayoutStatusType":"default","maxTime":null,"moduleId":null,"moduleName":null,"parentId":null,"type":14,"width":0,"x":-666,"y":76}',
+ (string) EventsHistory::fromArray(
+ [
+ 'id' => 7,
+ 'type' => AUTO_SLA_GRAPH,
+ 'label' => null,
+ 'labelPosition' => 'up',
+ 'isLinkEnabled' => true,
+ 'isOnTop' => false,
+ 'parentId' => null,
+ 'width' => '0',
+ 'height' => '0',
+ 'x' => -666,
+ 'y' => 76,
+ 'maxTime' => null,
+ 'encodedHtml' => 'PGgxPkZvbzwvaDE+',
+ 'id_layout_linked' => 1,
+ ]
+ )
+ );
+
+ $this->assertEquals(
+ '{"aclGroupId":null,"agentId":null,"agentName":null,"encodedHtml":"PGgxPkZvbzwvaDE+","height":0,"id":7,"isLinkEnabled":true,"isOnTop":false,"label":null,"labelPosition":"up","linkedLayoutAgentId":3,"linkedLayoutId":2,"linkedLayoutStatusType":"default","maxTime":12800,"metaconsoleId":5,"moduleId":null,"moduleName":null,"parentId":null,"type":14,"width":0,"x":-666,"y":76}',
+ (string) EventsHistory::fromArray(
+ [
+ 'id' => 7,
+ 'type' => AUTO_SLA_GRAPH,
+ 'label' => null,
+ 'labelPosition' => 'up',
+ 'isLinkEnabled' => true,
+ 'isOnTop' => false,
+ 'parentId' => null,
+ 'width' => '0',
+ 'height' => '0',
+ 'x' => -666,
+ 'y' => 76,
+ 'maxTime' => 12800,
+ 'encodedHtml' => 'PGgxPkZvbzwvaDE+',
+ 'id_metaconsole' => 5,
+ 'linked_layout_node_id' => 3,
+ 'linkedLayoutId' => 2,
+ ]
+ )
+ );
+
+ $this->assertEquals(
+ '{"aclGroupId":null,"agentId":21,"agentName":null,"encodedHtml":"PGgxPkZvbzwvaDE+","height":0,"id":7,"isLinkEnabled":true,"isOnTop":false,"label":null,"labelPosition":"up","linkedLayoutAgentId":15,"linkedLayoutId":3,"linkedLayoutStatusType":"default","maxTime":12800,"metaconsoleId":2,"moduleId":385,"moduleName":"module_test","parentId":null,"type":14,"width":0,"x":-666,"y":76}',
+ (string) EventsHistory::fromArray(
+ [
+ 'id' => 7,
+ 'type' => AUTO_SLA_GRAPH,
+ 'label' => null,
+ 'labelPosition' => 'up',
+ 'isLinkEnabled' => true,
+ 'isOnTop' => false,
+ 'parentId' => null,
+ 'width' => '0',
+ 'height' => '0',
+ 'x' => -666,
+ 'y' => 76,
+ 'maxTime' => 12800,
+ 'encodedHtml' => 'PGgxPkZvbzwvaDE+',
+ 'id_metaconsole' => 2,
+ 'linked_layout_node_id' => 15,
+ 'linkedLayoutId' => 3,
+ 'agentId' => 21,
+ 'moduleId' => 385,
+ 'moduleName' => 'module_test',
+ ]
+ )
+ );
+ }
+
+
+}
diff --git a/pandora_console/tests/Functional/Models/VisualConsole/Items/GroupTest.php b/pandora_console/tests/Functional/Models/VisualConsole/Items/GroupTest.php
new file mode 100644
index 0000000000..00e3a90620
--- /dev/null
+++ b/pandora_console/tests/Functional/Models/VisualConsole/Items/GroupTest.php
@@ -0,0 +1,279 @@
+assertInstanceOf(
+ Group::class,
+ Group::fromArray(
+ [
+ 'id' => 13,
+ 'type' => GROUP_ITEM,
+ 'width' => '600',
+ 'height' => '500',
+ 'imageSrc' => 'image.jpg',
+ 'groupId' => 12,
+ 'statusImageSrc' => 'image.bad.jpg',
+ ]
+ )
+ );
+
+ $this->assertInstanceOf(
+ Group::class,
+ Group::fromArray(
+ [
+ 'id' => 1004,
+ 'type' => GROUP_ITEM,
+ 'width' => '600',
+ 'height' => '500',
+ 'image' => 'test_image.png',
+ 'id_group' => 0,
+ 'statusImageSrc' => 'test_image.bad.jpg',
+ ]
+ )
+ );
+ }
+
+
+ /**
+ * Test if the instance is not created when using a invalid image src.
+ *
+ * @return void
+ */
+ public function testCannotBeCreatedWithInvalidImageSrc(): void
+ {
+ $this->expectException(InvalidArgumentException::class);
+ // Invalid imageSrc.
+ Group::fromArray(
+ [
+ 'id' => 7,
+ 'type' => GROUP_ITEM,
+ 'label' => null,
+ 'labelPosition' => 'up',
+ 'isLinkEnabled' => true,
+ 'isOnTop' => false,
+ 'parentId' => null,
+ 'width' => '0',
+ 'height' => '0',
+ 'x' => -666,
+ 'y' => 76,
+ 'imageSrc' => '',
+ 'groupId' => 0,
+ ]
+ );
+ // Missing imageSrc.
+ Group::fromArray(
+ [
+ 'id' => 7,
+ 'type' => GROUP_ITEM,
+ 'label' => null,
+ 'labelPosition' => 'up',
+ 'isLinkEnabled' => true,
+ 'isOnTop' => false,
+ 'parentId' => null,
+ 'width' => '0',
+ 'height' => '0',
+ 'x' => -666,
+ 'y' => 76,
+ 'id_group' => 11,
+ ]
+ );
+ }
+
+
+ /**
+ * Test if the instance is not created when using a invalid group Id.
+ *
+ * @return void
+ */
+ public function testCannotBeCreatedWithInvalidGroupId(): void
+ {
+ $this->expectException(InvalidArgumentException::class);
+ // Invalid groupId.
+ Group::fromArray(
+ [
+ 'id' => 7,
+ 'type' => GROUP_ITEM,
+ 'label' => null,
+ 'labelPosition' => 'up',
+ 'isLinkEnabled' => true,
+ 'isOnTop' => false,
+ 'parentId' => null,
+ 'width' => '0',
+ 'height' => '0',
+ 'x' => -666,
+ 'y' => 76,
+ 'imageSrc' => 'test.jpg',
+ 'groupId' => 'bar',
+ 'statusImageSrc' => 'image.bad.jpg',
+ ]
+ );
+ // Missing groupId.
+ Group::fromArray(
+ [
+ 'id' => 7,
+ 'type' => GROUP_ITEM,
+ 'label' => null,
+ 'labelPosition' => 'up',
+ 'isLinkEnabled' => true,
+ 'isOnTop' => false,
+ 'parentId' => null,
+ 'width' => '0',
+ 'height' => '0',
+ 'x' => -666,
+ 'y' => 76,
+ 'imageSrc' => 'test.jpg',
+ 'statusImageSrc' => 'image.bad.jpg',
+ ]
+ );
+ }
+
+
+ /**
+ * Test if the model has a valid JSON representation.
+ *
+ * @return void
+ */
+ public function testContainerIsRepresentedAsJson(): void
+ {
+ $this->assertEquals(
+ '{"aclGroupId":null,"groupId":12,"height":0,"id":7,"imageSrc":"image.jpg","isLinkEnabled":true,"isOnTop":false,"label":null,"labelPosition":"up","linkedLayoutAgentId":null,"linkedLayoutId":null,"linkedLayoutStatusType":"default","parentId":null,"statusImageSrc":"image.bad.jpg","type":11,"width":0,"x":-666,"y":76}',
+ (string) Group::fromArray(
+ [
+ 'id' => 7,
+ 'type' => GROUP_ITEM,
+ 'label' => null,
+ 'labelPosition' => 'up',
+ 'isLinkEnabled' => true,
+ 'isOnTop' => false,
+ 'parentId' => null,
+ 'width' => '0',
+ 'height' => '0',
+ 'x' => -666,
+ 'y' => 76,
+ 'imageSrc' => 'image.jpg',
+ 'groupId' => 12,
+ 'statusImageSrc' => 'image.bad.jpg',
+ ]
+ )
+ );
+
+ // With a linked layout.
+ $this->assertEquals(
+ '{"aclGroupId":null,"groupId":12,"height":0,"id":7,"imageSrc":"image.jpg","isLinkEnabled":true,"isOnTop":false,"label":null,"labelPosition":"up","linkedLayoutAgentId":null,"linkedLayoutId":1,"linkedLayoutStatusType":"default","parentId":null,"statusImageSrc":"image.bad.jpg","type":11,"width":0,"x":-666,"y":76}',
+ (string) Group::fromArray(
+ [
+ 'id' => 7,
+ 'type' => GROUP_ITEM,
+ 'label' => null,
+ 'labelPosition' => 'up',
+ 'isLinkEnabled' => true,
+ 'isOnTop' => false,
+ 'parentId' => null,
+ 'width' => '0',
+ 'height' => '0',
+ 'x' => -666,
+ 'y' => 76,
+ 'imageSrc' => 'image.jpg',
+ 'groupId' => 12,
+ 'statusImageSrc' => 'image.bad.jpg',
+ 'id_layout_linked' => 1,
+ ]
+ )
+ );
+
+ $this->assertEquals(
+ '{"aclGroupId":null,"groupId":12,"height":0,"id":7,"imageSrc":"image.jpg","isLinkEnabled":true,"isOnTop":false,"label":null,"labelPosition":"up","linkedLayoutAgentId":3,"linkedLayoutId":2,"linkedLayoutStatusType":"default","metaconsoleId":5,"parentId":null,"statusImageSrc":"image.bad.jpg","type":11,"width":0,"x":-666,"y":76}',
+ (string) Group::fromArray(
+ [
+ 'id' => 7,
+ 'type' => GROUP_ITEM,
+ 'label' => null,
+ 'labelPosition' => 'up',
+ 'isLinkEnabled' => true,
+ 'isOnTop' => false,
+ 'parentId' => null,
+ 'width' => '0',
+ 'height' => '0',
+ 'x' => -666,
+ 'y' => 76,
+ 'imageSrc' => 'image.jpg',
+ 'groupId' => 12,
+ 'statusImageSrc' => 'image.bad.jpg',
+ 'id_metaconsole' => 5,
+ 'linked_layout_node_id' => 3,
+ 'linkedLayoutId' => 2,
+ ]
+ )
+ );
+ $this->assertEquals(
+ '{"aclGroupId":null,"groupId":12,"height":0,"id":7,"imageSrc":"image.jpg","isLinkEnabled":true,"isOnTop":false,"label":null,"labelPosition":"up","linkedLayoutAgentId":3,"linkedLayoutId":2,"linkedLayoutStatusType":"weight","linkedLayoutStatusTypeWeight":80,"metaconsoleId":5,"parentId":null,"statusImageSrc":"image.bad.jpg","type":11,"width":0,"x":-666,"y":76}',
+ (string) Group::fromArray(
+ [
+ 'id' => 7,
+ 'type' => GROUP_ITEM,
+ 'label' => null,
+ 'labelPosition' => 'up',
+ 'isLinkEnabled' => true,
+ 'isOnTop' => false,
+ 'parentId' => null,
+ 'width' => '0',
+ 'height' => '0',
+ 'x' => -666,
+ 'y' => 76,
+ 'imageSrc' => 'image.jpg',
+ 'groupId' => 12,
+ 'statusImageSrc' => 'image.bad.jpg',
+ 'id_metaconsole' => 5,
+ 'linked_layout_node_id' => 3,
+ 'linkedLayoutId' => 2,
+ 'linkedLayoutStatusType' => 'weight',
+ 'linkedLayoutStatusTypeWeight' => 80,
+ ]
+ )
+ );
+ $this->assertEquals(
+ '{"aclGroupId":null,"groupId":12,"height":0,"id":7,"imageSrc":"image.jpg","isLinkEnabled":true,"isOnTop":false,"label":null,"labelPosition":"up","linkedLayoutAgentId":null,"linkedLayoutId":2,"linkedLayoutStatusType":"service","linkedLayoutStatusTypeCriticalThreshold":80,"linkedLayoutStatusTypeWarningThreshold":50,"parentId":null,"statusImageSrc":"image.bad.jpg","type":11,"width":0,"x":-666,"y":76}',
+ (string) Group::fromArray(
+ [
+ 'id' => 7,
+ 'type' => GROUP_ITEM,
+ 'label' => null,
+ 'labelPosition' => 'up',
+ 'isLinkEnabled' => true,
+ 'isOnTop' => false,
+ 'parentId' => null,
+ 'width' => '0',
+ 'height' => '0',
+ 'x' => -666,
+ 'y' => 76,
+ 'imageSrc' => 'image.jpg',
+ 'groupId' => 12,
+ 'statusImageSrc' => 'image.bad.jpg',
+ 'linkedLayoutId' => 2,
+ 'linked_layout_status_type' => 'service',
+ 'linkedLayoutStatusTypeWarningThreshold' => 50,
+ 'linked_layout_status_as_service_critical' => 80,
+ ]
+ )
+ );
+ }
+
+
+}
diff --git a/pandora_console/tests/Functional/Models/VisualConsole/Items/IconTest.php b/pandora_console/tests/Functional/Models/VisualConsole/Items/IconTest.php
new file mode 100644
index 0000000000..44fa077959
--- /dev/null
+++ b/pandora_console/tests/Functional/Models/VisualConsole/Items/IconTest.php
@@ -0,0 +1,207 @@
+assertInstanceOf(
+ Icon::class,
+ Icon::fromArray(
+ [
+ 'id' => 69,
+ 'type' => ICON,
+ 'width' => '0',
+ 'height' => '0',
+ 'imageSrc' => 'image.jpg',
+ ]
+ )
+ );
+ }
+
+
+ /**
+ * Test if the instance is not created when using a invalid image src.
+ *
+ * @return void
+ */
+ public function testCannotBeCreatedWithInvalidImageSrc(): void
+ {
+ $this->expectException(InvalidArgumentException::class);
+ // Invalid imageSrc.
+ Icon::fromArray(
+ [
+ 'id' => 7,
+ 'type' => ICON,
+ 'label' => null,
+ 'labelPosition' => 'up',
+ 'isLinkEnabled' => true,
+ 'isOnTop' => false,
+ 'parentId' => null,
+ 'width' => '0',
+ 'height' => '0',
+ 'x' => -666,
+ 'y' => 76,
+ 'imageSrc' => '',
+ ]
+ );
+ // Missing imageSrc.
+ Icon::fromArray(
+ [
+ 'id' => 7,
+ 'type' => ICON,
+ 'label' => null,
+ 'labelPosition' => 'up',
+ 'isLinkEnabled' => true,
+ 'isOnTop' => false,
+ 'parentId' => null,
+ 'width' => '0',
+ 'height' => '0',
+ 'x' => -666,
+ 'y' => 76,
+ ]
+ );
+ }
+
+
+ /**
+ * Test if the model has a valid JSON representation.
+ *
+ * @return void
+ */
+ public function testContainerIsRepresentedAsJson(): void
+ {
+ $this->assertEquals(
+ '{"aclGroupId":null,"height":0,"id":7,"imageSrc":"image.jpg","isLinkEnabled":true,"isOnTop":false,"label":null,"labelPosition":"up","linkedLayoutAgentId":null,"linkedLayoutId":null,"linkedLayoutStatusType":"default","parentId":null,"type":5,"width":0,"x":-666,"y":76}',
+ (string) Icon::fromArray(
+ [
+ 'id' => 7,
+ 'type' => ICON,
+ 'label' => null,
+ 'labelPosition' => 'up',
+ 'isLinkEnabled' => true,
+ 'isOnTop' => false,
+ 'parentId' => null,
+ 'width' => '0',
+ 'height' => '0',
+ 'x' => -666,
+ 'y' => 76,
+ 'imageSrc' => 'image.jpg',
+ ]
+ )
+ );
+
+ // With a linked layout.
+ $this->assertEquals(
+ '{"aclGroupId":null,"height":0,"id":7,"imageSrc":"image.jpg","isLinkEnabled":true,"isOnTop":false,"label":null,"labelPosition":"up","linkedLayoutAgentId":null,"linkedLayoutId":1,"linkedLayoutStatusType":"default","parentId":null,"type":5,"width":0,"x":-666,"y":76}',
+ (string) Icon::fromArray(
+ [
+ 'id' => 7,
+ 'type' => ICON,
+ 'label' => null,
+ 'labelPosition' => 'up',
+ 'isLinkEnabled' => true,
+ 'isOnTop' => false,
+ 'parentId' => null,
+ 'width' => '0',
+ 'height' => '0',
+ 'x' => -666,
+ 'y' => 76,
+ 'imageSrc' => 'image.jpg',
+ 'id_layout_linked' => 1,
+ ]
+ )
+ );
+
+ $this->assertEquals(
+ '{"aclGroupId":null,"height":0,"id":7,"imageSrc":"image.jpg","isLinkEnabled":true,"isOnTop":false,"label":null,"labelPosition":"up","linkedLayoutAgentId":3,"linkedLayoutId":2,"linkedLayoutStatusType":"default","metaconsoleId":5,"parentId":null,"type":5,"width":0,"x":-666,"y":76}',
+ (string) Icon::fromArray(
+ [
+ 'id' => 7,
+ 'type' => ICON,
+ 'label' => null,
+ 'labelPosition' => 'up',
+ 'isLinkEnabled' => true,
+ 'isOnTop' => false,
+ 'parentId' => null,
+ 'width' => '0',
+ 'height' => '0',
+ 'x' => -666,
+ 'y' => 76,
+ 'imageSrc' => 'image.jpg',
+ 'id_metaconsole' => 5,
+ 'linked_layout_node_id' => 3,
+ 'linkedLayoutId' => 2,
+ ]
+ )
+ );
+
+ $this->assertEquals(
+ '{"aclGroupId":null,"height":0,"id":7,"imageSrc":"image.jpg","isLinkEnabled":true,"isOnTop":false,"label":null,"labelPosition":"up","linkedLayoutAgentId":3,"linkedLayoutId":2,"linkedLayoutStatusType":"weight","linkedLayoutStatusTypeWeight":80,"metaconsoleId":5,"parentId":null,"type":5,"width":0,"x":-666,"y":76}',
+ (string) Icon::fromArray(
+ [
+ 'id' => 7,
+ 'type' => ICON,
+ 'label' => null,
+ 'labelPosition' => 'up',
+ 'isLinkEnabled' => true,
+ 'isOnTop' => false,
+ 'parentId' => null,
+ 'width' => '0',
+ 'height' => '0',
+ 'x' => -666,
+ 'y' => 76,
+ 'imageSrc' => 'image.jpg',
+ 'id_metaconsole' => 5,
+ 'linked_layout_node_id' => 3,
+ 'linkedLayoutId' => 2,
+ 'linkedLayoutStatusType' => 'weight',
+ 'linkedLayoutStatusTypeWeight' => 80,
+ ]
+ )
+ );
+
+ $this->assertEquals(
+ '{"aclGroupId":null,"height":0,"id":7,"imageSrc":"image.jpg","isLinkEnabled":true,"isOnTop":false,"label":null,"labelPosition":"up","linkedLayoutAgentId":3,"linkedLayoutId":2,"linkedLayoutStatusType":"service","linkedLayoutStatusTypeCriticalThreshold":80,"linkedLayoutStatusTypeWarningThreshold":50,"metaconsoleId":5,"parentId":null,"type":5,"width":0,"x":-666,"y":76}',
+ (string) Icon::fromArray(
+ [
+ 'id' => 7,
+ 'type' => ICON,
+ 'label' => null,
+ 'labelPosition' => 'up',
+ 'isLinkEnabled' => true,
+ 'isOnTop' => false,
+ 'parentId' => null,
+ 'width' => '0',
+ 'height' => '0',
+ 'x' => -666,
+ 'y' => 76,
+ 'imageSrc' => 'image.jpg',
+ 'id_metaconsole' => 5,
+ 'linked_layout_node_id' => 3,
+ 'linkedLayoutId' => 2,
+ 'linked_layout_status_type' => 'service',
+ 'linkedLayoutStatusTypeWarningThreshold' => 50,
+ 'linked_layout_status_as_service_critical' => 80,
+ ]
+ )
+ );
+
+ }
+
+
+}
diff --git a/pandora_console/tests/Functional/Models/VisualConsole/Items/LabelTest.php b/pandora_console/tests/Functional/Models/VisualConsole/Items/LabelTest.php
new file mode 100644
index 0000000000..2c1fd963cd
--- /dev/null
+++ b/pandora_console/tests/Functional/Models/VisualConsole/Items/LabelTest.php
@@ -0,0 +1,129 @@
+assertInstanceOf(
+ Label::class,
+ Label::fromArray(
+ [
+ 'id' => 69,
+ 'type' => LABEL,
+ 'width' => '0',
+ 'height' => '0',
+ 'label' => 'Label',
+ ]
+ )
+ );
+ }
+
+
+ /**
+ * Test if the instance is not created when using a invalid label.
+ *
+ * @return void
+ */
+ public function testCannotBeCreatedWithInvalidLabel(): void
+ {
+ $this->expectException(InvalidArgumentException::class);
+ // Missing label.
+ Label::fromArray(
+ [
+ 'id' => 7,
+ 'type' => LABEL,
+ 'labelPosition' => 'up',
+ 'isLinkEnabled' => true,
+ 'isOnTop' => false,
+ 'parentId' => null,
+ 'width' => '0',
+ 'height' => '0',
+ 'x' => -666,
+ 'y' => 76,
+ ]
+ );
+ // Empty label.
+ Label::fromArray(
+ [
+ 'id' => 7,
+ 'type' => LABEL,
+ 'label' => '',
+ 'labelPosition' => 'up',
+ 'isLinkEnabled' => true,
+ 'isOnTop' => false,
+ 'parentId' => null,
+ 'width' => '0',
+ 'height' => '0',
+ 'x' => -666,
+ 'y' => 76,
+ ]
+ );
+ }
+
+
+ /**
+ * Test if the model has a valid JSON representation.
+ *
+ * @return void
+ */
+ public function testContainerIsRepresentedAsJson(): void
+ {
+ $this->assertEquals(
+ '{"aclGroupId":null,"height":0,"id":7,"isLinkEnabled":true,"isOnTop":false,"label":"Label","labelPosition":"up","linkedLayoutAgentId":null,"linkedLayoutId":null,"linkedLayoutStatusType":"default","parentId":null,"type":4,"width":0,"x":-666,"y":76}',
+ (string) Label::fromArray(
+ [
+ 'id' => 7,
+ 'type' => LABEL,
+ 'label' => 'Label',
+ 'labelPosition' => 'up',
+ 'isLinkEnabled' => true,
+ 'isOnTop' => false,
+ 'parentId' => null,
+ 'width' => '0',
+ 'height' => '0',
+ 'x' => -666,
+ 'y' => 76,
+ ]
+ )
+ );
+
+ // With a linked layout.
+ $this->assertEquals(
+ '{"aclGroupId":null,"height":0,"id":7,"isLinkEnabled":true,"isOnTop":false,"label":"Label","labelPosition":"up","linkedLayoutAgentId":null,"linkedLayoutId":1,"linkedLayoutStatusType":"default","parentId":null,"type":4,"width":0,"x":-666,"y":76}',
+ (string) Label::fromArray(
+ [
+ 'id' => 7,
+ 'type' => LABEL,
+ 'label' => 'Label',
+ 'labelPosition' => 'up',
+ 'isLinkEnabled' => true,
+ 'isOnTop' => false,
+ 'parentId' => null,
+ 'width' => '0',
+ 'height' => '0',
+ 'x' => -666,
+ 'y' => 76,
+ 'id_layout_linked' => 1,
+ ]
+ )
+ );
+
+ }
+
+
+}
diff --git a/pandora_console/tests/Functional/Models/VisualConsole/Items/LineTest.php b/pandora_console/tests/Functional/Models/VisualConsole/Items/LineTest.php
new file mode 100644
index 0000000000..b70b1699a6
--- /dev/null
+++ b/pandora_console/tests/Functional/Models/VisualConsole/Items/LineTest.php
@@ -0,0 +1,156 @@
+assertInstanceOf(
+ Line::class,
+ Line::fromArray(
+ [
+ 'id' => 10,
+ 'type' => LINE_ITEM,
+ 'startX' => 50,
+ 'startY' => 100,
+ 'endX' => 0,
+ 'endY' => 10,
+ 'isOnTop' => false,
+ 'borderWidth' => 0,
+ 'borderColor' => 'white',
+ ]
+ )
+ );
+
+ $this->assertInstanceOf(
+ Line::class,
+ Line::fromArray(
+ [
+ 'id' => 10,
+ 'type' => LINE_ITEM,
+ 'startX' => 50,
+ 'endY' => 10,
+ 'borderColor' => 'black',
+ ]
+ )
+ );
+ }
+
+
+ /**
+ * Test if the instance is not created when using a invalid Id.
+ *
+ * @return void
+ */
+ public function testCannotBeCreatedWithInvalidId(): void
+ {
+ $this->expectException(InvalidArgumentException::class);
+ // Invalid id.
+ Line::fromArray(
+ [
+ 'id' => 'foo',
+ 'type' => LINE_ITEM,
+ 'startX' => 50,
+ 'startY' => 100,
+ 'endX' => 0,
+ 'endY' => 10,
+ 'isOnTop' => false,
+ 'borderWidth' => 0,
+ 'borderColor' => 'white',
+ ]
+ );
+ // Missing id.
+ Line::fromArray(
+ [
+ 'type' => LINE_ITEM,
+ 'startX' => 50,
+ 'startY' => 100,
+ 'endX' => 0,
+ 'endY' => 10,
+ 'isOnTop' => false,
+ 'borderWidth' => 0,
+ 'borderColor' => 'white',
+ ]
+ );
+ }
+
+
+ /**
+ * Test if the instance is not created when using a invalid type.
+ *
+ * @return void
+ */
+ public function testCannotBeCreatedWithInvalidtype(): void
+ {
+ $this->expectException(InvalidArgumentException::class);
+ // Invalid type.
+ Line::fromArray(
+ [
+ 'id' => 13,
+ 'type' => 'test',
+ 'startX' => 50,
+ 'startY' => 100,
+ 'endX' => 0,
+ 'endY' => 10,
+ 'isOnTop' => false,
+ 'borderWidth' => 0,
+ 'borderColor' => 'white',
+ ]
+ );
+ // Missing type.
+ Line::fromArray(
+ [
+ 'id' => 13,
+ 'startX' => 50,
+ 'startY' => 100,
+ 'endX' => 0,
+ 'endY' => 10,
+ 'isOnTop' => true,
+ 'borderWidth' => 0,
+ 'borderColor' => 'white',
+ ]
+ );
+ }
+
+
+ /**
+ * Test if the model has a valid JSON representation.
+ *
+ * @return void
+ */
+ public function testContainerIsRepresentedAsJson(): void
+ {
+ $this->assertEquals(
+ '{"borderColor":"white","borderWidth":0,"endX":0,"endY":10,"id":1,"isOnTop":false,"startX":50,"startY":100,"type":13}',
+ (string) Line::fromArray(
+ [
+ 'id' => 1,
+ 'type' => LINE_ITEM,
+ 'startX' => 50,
+ 'startY' => 100,
+ 'endX' => 0,
+ 'endY' => 10,
+ 'isOnTop' => false,
+ 'borderWidth' => 0,
+ 'borderColor' => 'white',
+ ]
+ )
+ );
+ }
+
+
+}
diff --git a/pandora_console/tests/Functional/Models/VisualConsole/Items/PercentileTest.php b/pandora_console/tests/Functional/Models/VisualConsole/Items/PercentileTest.php
new file mode 100644
index 0000000000..ebe80f6b8c
--- /dev/null
+++ b/pandora_console/tests/Functional/Models/VisualConsole/Items/PercentileTest.php
@@ -0,0 +1,149 @@
+assertInstanceOf(
+ Percentile::class,
+ Percentile::fromArray(
+ [
+ 'id' => 3,
+ 'type' => PERCENTILE_BAR,
+ 'width' => '600',
+ 'height' => '500',
+ 'maxTime' => null,
+ 'valueType' => 'value',
+ 'value' => '123ms',
+ ]
+ )
+ );
+
+ $this->assertInstanceOf(
+ Percentile::class,
+ Percentile::fromArray(
+ [
+ 'id' => 14,
+ 'type' => PERCENTILE_BUBBLE,
+ 'width' => '600',
+ 'height' => '500',
+ 'maxTime' => 12800,
+ 'valueType' => 'image',
+ 'value' => 'data:image;asdasoih==',
+ ]
+ )
+ );
+ }
+
+
+ /**
+ * Test if the model has a valid JSON representation.
+ *
+ * @return void
+ */
+ public function testContainerIsRepresentedAsJson(): void
+ {
+ $this->assertEquals(
+ '{"aclGroupId":null,"agentId":null,"agentName":null,"color":null,"height":0,"id":7,"isLinkEnabled":true,"isOnTop":false,"label":null,"labelColor":null,"labelPosition":"up","linkedLayoutAgentId":null,"linkedLayoutId":null,"linkedLayoutStatusType":"default","maxValue":0,"minValue":null,"moduleId":null,"moduleName":null,"parentId":null,"percentileType":"progress-bar","type":3,"unit":null,"value":null,"valueType":"percent","width":0,"x":-666,"y":76}',
+ (string) Percentile::fromArray(
+ [
+ 'id' => 7,
+ 'type' => PERCENTILE_BAR,
+ 'label' => null,
+ 'labelPosition' => 'up',
+ 'isLinkEnabled' => true,
+ 'isOnTop' => false,
+ 'parentId' => null,
+ 'width' => '0',
+ 'height' => '0',
+ 'x' => -666,
+ 'y' => 76,
+ 'maxTime' => null,
+ ]
+ )
+ );
+
+ $this->assertEquals(
+ '{"aclGroupId":null,"agentId":null,"agentName":null,"color":null,"height":0,"id":7,"isLinkEnabled":true,"isOnTop":false,"label":null,"labelColor":null,"labelPosition":"up","linkedLayoutAgentId":null,"linkedLayoutId":null,"linkedLayoutStatusType":"default","maxValue":0,"minValue":null,"moduleId":null,"moduleName":null,"parentId":null,"percentileType":"bubble","type":3,"unit":null,"value":null,"valueType":"percent","width":0,"x":-666,"y":76}',
+ (string) Percentile::fromArray(
+ [
+ 'id' => 7,
+ 'type' => PERCENTILE_BUBBLE,
+ 'label' => null,
+ 'labelPosition' => 'up',
+ 'isLinkEnabled' => true,
+ 'isOnTop' => false,
+ 'parentId' => null,
+ 'width' => '0',
+ 'height' => '0',
+ 'x' => -666,
+ 'y' => 76,
+ 'maxTime' => 12800,
+ ]
+ )
+ );
+
+ $this->assertEquals(
+ '{"aclGroupId":null,"agentId":null,"agentName":null,"color":null,"height":0,"id":7,"isLinkEnabled":true,"isOnTop":false,"label":null,"labelColor":null,"labelPosition":"up","linkedLayoutAgentId":null,"linkedLayoutId":null,"linkedLayoutStatusType":"default","maxValue":0,"minValue":null,"moduleId":null,"moduleName":null,"parentId":null,"percentileType":"circular-progress-bar","type":3,"unit":null,"value":1,"valueType":"value","width":0,"x":-666,"y":76}',
+ (string) Percentile::fromArray(
+ [
+ 'id' => 7,
+ 'type' => CIRCULAR_PROGRESS_BAR,
+ 'label' => null,
+ 'labelPosition' => 'up',
+ 'isLinkEnabled' => true,
+ 'isOnTop' => false,
+ 'parentId' => null,
+ 'width' => '0',
+ 'height' => '0',
+ 'x' => -666,
+ 'y' => 76,
+ 'maxTime' => 12800,
+ 'valueType' => 'value',
+ 'value' => '1',
+ ]
+ )
+ );
+
+ $this->assertEquals(
+ '{"aclGroupId":null,"agentId":null,"agentName":null,"color":"#FFF","height":0,"id":7,"isLinkEnabled":true,"isOnTop":false,"label":null,"labelColor":"#000","labelPosition":"up","linkedLayoutAgentId":null,"linkedLayoutId":null,"linkedLayoutStatusType":"default","maxValue":0,"minValue":null,"moduleId":null,"moduleName":null,"parentId":null,"percentileType":"circular-progress-bar","type":3,"unit":null,"value":80,"valueType":"percent","width":0,"x":-666,"y":76}',
+ (string) Percentile::fromArray(
+ [
+ 'id' => 7,
+ 'type' => CIRCULAR_PROGRESS_BAR,
+ 'label' => null,
+ 'labelPosition' => 'up',
+ 'isLinkEnabled' => true,
+ 'isOnTop' => false,
+ 'parentId' => null,
+ 'width' => '0',
+ 'height' => '0',
+ 'x' => -666,
+ 'y' => 76,
+ 'maxTime' => 12800,
+ 'valueType' => 'percent',
+ 'value' => '80',
+ 'color' => '#FFF',
+ 'labelColor' => '#000',
+ ]
+ )
+ );
+ }
+
+
+}
diff --git a/pandora_console/tests/Functional/Models/VisualConsole/Items/SimpleValueTest.php b/pandora_console/tests/Functional/Models/VisualConsole/Items/SimpleValueTest.php
new file mode 100644
index 0000000000..a417699fe0
--- /dev/null
+++ b/pandora_console/tests/Functional/Models/VisualConsole/Items/SimpleValueTest.php
@@ -0,0 +1,148 @@
+assertInstanceOf(
+ SimpleValue::class,
+ SimpleValue::fromArray(
+ [
+ 'id' => 3,
+ 'type' => SIMPLE_VALUE,
+ 'width' => '600',
+ 'height' => '500',
+ 'valueType' => 'string',
+ 'value' => 57,
+ 'processValue' => 'avg',
+ 'period' => 12800,
+ ]
+ )
+ );
+
+ $this->assertInstanceOf(
+ SimpleValue::class,
+ SimpleValue::fromArray(
+ [
+ 'id' => 14,
+ 'type' => SIMPLE_VALUE,
+ 'width' => '600',
+ 'height' => '500',
+ 'valueType' => 'image',
+ 'value' => 3598,
+ 'processValue' => 'max',
+ 'period' => 9000,
+ ]
+ )
+ );
+ }
+
+
+ /**
+ * Test if the model has a valid JSON representation.
+ *
+ * @return void
+ */
+ public function testContainerIsRepresentedAsJson(): void
+ {
+ $this->assertEquals(
+ '{"aclGroupId":null,"agentId":null,"agentName":null,"height":500,"id":3,"isLinkEnabled":false,"isOnTop":false,"label":null,"labelPosition":"down","linkedLayoutAgentId":null,"linkedLayoutId":null,"linkedLayoutStatusType":"default","moduleId":null,"moduleName":null,"parentId":null,"period":12800,"processValue":"avg","type":2,"value":57,"valueType":"string","width":600,"x":0,"y":0}',
+ (string) SimpleValue::fromArray(
+ [
+ 'id' => 3,
+ 'type' => SIMPLE_VALUE,
+ 'width' => '600',
+ 'height' => '500',
+ 'valueType' => 'string',
+ 'value' => 57,
+ 'processValue' => 'avg',
+ 'period' => 12800,
+ ]
+ )
+ );
+
+ $this->assertEquals(
+ '{"aclGroupId":null,"agentId":null,"agentName":null,"height":500,"id":3,"isLinkEnabled":false,"isOnTop":false,"label":null,"labelPosition":"down","linkedLayoutAgentId":null,"linkedLayoutId":null,"linkedLayoutStatusType":"default","moduleId":null,"moduleName":null,"parentId":null,"processValue":"none","type":2,"value":57,"valueType":"string","width":600,"x":0,"y":0}',
+ (string) SimpleValue::fromArray(
+ [
+ 'id' => 3,
+ 'type' => SIMPLE_VALUE,
+ 'width' => '600',
+ 'height' => '500',
+ 'valueType' => 'string',
+ 'value' => 57,
+ ]
+ )
+ );
+
+ $this->assertEquals(
+ '{"aclGroupId":null,"agentId":null,"agentName":null,"height":500,"id":3,"isLinkEnabled":false,"isOnTop":false,"label":null,"labelPosition":"down","linkedLayoutAgentId":null,"linkedLayoutId":1,"linkedLayoutStatusType":"default","moduleId":null,"moduleName":null,"parentId":null,"processValue":"none","type":2,"value":57,"valueType":"string","width":600,"x":0,"y":0}',
+ (string) SimpleValue::fromArray(
+ [
+ 'id' => 3,
+ 'type' => SIMPLE_VALUE,
+ 'width' => '600',
+ 'height' => '500',
+ 'valueType' => 'string',
+ 'value' => 57,
+ 'id_layout_linked' => 1,
+ ]
+ )
+ );
+
+ $this->assertEquals(
+ '{"aclGroupId":null,"agentId":null,"agentName":null,"height":500,"id":3,"isLinkEnabled":false,"isOnTop":false,"label":null,"labelPosition":"down","linkedLayoutAgentId":3,"linkedLayoutId":2,"linkedLayoutStatusType":"default","metaconsoleId":5,"moduleId":null,"moduleName":null,"parentId":null,"processValue":"none","type":2,"value":57,"valueType":"string","width":600,"x":0,"y":0}',
+ (string) SimpleValue::fromArray(
+ [
+ 'id' => 3,
+ 'type' => SIMPLE_VALUE,
+ 'width' => '600',
+ 'height' => '500',
+ 'valueType' => 'string',
+ 'value' => 57,
+ 'id_metaconsole' => 5,
+ 'linked_layout_node_id' => 3,
+ 'linkedLayoutId' => 2,
+ ]
+ )
+ );
+
+ $this->assertEquals(
+ '{"aclGroupId":null,"agentId":21,"agentName":null,"height":500,"id":3,"isLinkEnabled":false,"isOnTop":false,"label":null,"labelPosition":"down","linkedLayoutAgentId":15,"linkedLayoutId":3,"linkedLayoutStatusType":"default","metaconsoleId":2,"moduleId":385,"moduleName":"module_test","parentId":null,"processValue":"none","type":2,"value":57,"valueType":"string","width":600,"x":0,"y":0}',
+ (string) SimpleValue::fromArray(
+ [
+ 'id' => 3,
+ 'type' => SIMPLE_VALUE,
+ 'width' => '600',
+ 'height' => '500',
+ 'valueType' => 'string',
+ 'value' => 57,
+ 'id_metaconsole' => 2,
+ 'linked_layout_node_id' => 15,
+ 'linkedLayoutId' => 3,
+ 'agentId' => 21,
+ 'moduleId' => 385,
+ 'moduleName' => 'module_test',
+ ]
+ )
+ );
+
+ }
+
+
+}
diff --git a/pandora_console/tests/Functional/Models/VisualConsole/Items/StaticGraphTest.php b/pandora_console/tests/Functional/Models/VisualConsole/Items/StaticGraphTest.php
new file mode 100644
index 0000000000..9b77fc7540
--- /dev/null
+++ b/pandora_console/tests/Functional/Models/VisualConsole/Items/StaticGraphTest.php
@@ -0,0 +1,224 @@
+assertInstanceOf(
+ StaticGraph::class,
+ StaticGraph::fromArray(
+ [
+ 'id' => 345,
+ 'type' => STATIC_GRAPH,
+ 'label' => null,
+ 'labelPosition' => 'up',
+ 'isLinkEnabled' => true,
+ 'isOnTop' => false,
+ 'parentId' => null,
+ 'width' => '0',
+ 'height' => '0',
+ 'x' => -666,
+ 'y' => 76,
+ 'imageSrc' => 'aaaaa',
+ 'showLastValueTooltip' => 'enabled',
+ ]
+ )
+ );
+
+ $this->assertInstanceOf(
+ StaticGraph::class,
+ StaticGraph::fromArray(
+ [
+ 'id' => 1000,
+ 'type' => STATIC_GRAPH,
+ 'width' => 100,
+ 'height' => 900,
+ 'image' => 'test.jpg',
+ 'show_last_value' => 2,
+ ]
+ )
+ );
+ }
+
+
+ /**
+ * Test if the model has a valid JSON representation.
+ *
+ * @return void
+ */
+ public function testContainerIsRepresentedAsJson(): void
+ {
+ $this->assertEquals(
+ '{"aclGroupId":null,"agentId":null,"agentName":null,"height":0,"id":7,"imageSrc":"image.jpg","isLinkEnabled":true,"isOnTop":false,"label":null,"labelPosition":"up","linkedLayoutAgentId":null,"linkedLayoutId":null,"linkedLayoutStatusType":"default","moduleId":null,"moduleName":null,"parentId":null,"showLastValueTooltip":"default","statusImageSrc":null,"type":0,"width":0,"x":-666,"y":76}',
+ (string) StaticGraph::fromArray(
+ [
+ 'id' => 7,
+ 'type' => STATIC_GRAPH,
+ 'label' => null,
+ 'labelPosition' => 'up',
+ 'isLinkEnabled' => true,
+ 'isOnTop' => false,
+ 'parentId' => null,
+ 'width' => '0',
+ 'height' => '0',
+ 'x' => -666,
+ 'y' => 76,
+ 'imageSrc' => 'image.jpg',
+ ]
+ )
+ );
+
+ $this->assertEquals(
+ '{"aclGroupId":null,"agentId":null,"agentName":null,"height":0,"id":7,"imageSrc":"image.jpg","isLinkEnabled":true,"isOnTop":false,"label":null,"labelPosition":"up","linkedLayoutAgentId":null,"linkedLayoutId":null,"linkedLayoutStatusType":"default","moduleId":null,"moduleName":null,"parentId":null,"showLastValueTooltip":"disabled","statusImageSrc":null,"type":0,"width":0,"x":-666,"y":76}',
+ (string) StaticGraph::fromArray(
+ [
+ 'id' => 7,
+ 'type' => STATIC_GRAPH,
+ 'label' => null,
+ 'labelPosition' => 'up',
+ 'isLinkEnabled' => true,
+ 'isOnTop' => false,
+ 'parentId' => null,
+ 'width' => '0',
+ 'height' => '0',
+ 'x' => -666,
+ 'y' => 76,
+ 'image' => 'image.jpg',
+ 'showLastValueTooltip' => 'disabled',
+ ]
+ )
+ );
+
+ $this->assertEquals(
+ '{"aclGroupId":null,"agentId":null,"agentName":null,"height":0,"id":7,"imageSrc":"image.jpg","isLinkEnabled":true,"isOnTop":false,"label":null,"labelPosition":"up","linkedLayoutAgentId":3,"linkedLayoutId":2,"linkedLayoutStatusType":"default","metaconsoleId":5,"moduleId":null,"moduleName":null,"parentId":null,"showLastValueTooltip":"default","statusImageSrc":"image.bad.jpg","type":0,"width":0,"x":-666,"y":76}',
+ (string) StaticGraph::fromArray(
+ [
+ 'id' => 7,
+ 'type' => STATIC_GRAPH,
+ 'label' => null,
+ 'labelPosition' => 'up',
+ 'isLinkEnabled' => true,
+ 'isOnTop' => false,
+ 'parentId' => null,
+ 'width' => '0',
+ 'height' => '0',
+ 'x' => -666,
+ 'y' => 76,
+ 'imageSrc' => 'image.jpg',
+ 'id_metaconsole' => 5,
+ 'linked_layout_node_id' => 3,
+ 'linkedLayoutId' => 2,
+ 'statusImageSrc' => 'image.bad.jpg',
+ ]
+ )
+ );
+
+ $this->assertEquals(
+ '{"aclGroupId":null,"agentId":null,"agentName":null,"height":0,"id":7,"imageSrc":"image.jpg","isLinkEnabled":true,"isOnTop":false,"label":null,"labelPosition":"up","linkedLayoutAgentId":null,"linkedLayoutId":1,"linkedLayoutStatusType":"default","moduleId":null,"moduleName":null,"parentId":null,"showLastValueTooltip":"default","statusImageSrc":null,"type":0,"width":0,"x":-666,"y":76}',
+ (string) StaticGraph::fromArray(
+ [
+ 'id' => 7,
+ 'type' => STATIC_GRAPH,
+ 'label' => null,
+ 'labelPosition' => 'up',
+ 'isLinkEnabled' => true,
+ 'isOnTop' => false,
+ 'parentId' => null,
+ 'width' => '0',
+ 'height' => '0',
+ 'x' => -666,
+ 'y' => 76,
+ 'image' => 'image.jpg',
+ 'id_layout_linked' => 1,
+ ]
+ )
+ );
+
+ $this->assertEquals(
+ '{"aclGroupId":null,"agentId":null,"agentName":null,"height":0,"id":7,"imageSrc":"image.jpg","isLinkEnabled":true,"isOnTop":false,"label":null,"labelPosition":"up","linkedLayoutAgentId":null,"linkedLayoutId":2,"linkedLayoutStatusType":"service","linkedLayoutStatusTypeCriticalThreshold":80,"linkedLayoutStatusTypeWarningThreshold":50,"moduleId":null,"moduleName":null,"parentId":null,"showLastValueTooltip":"default","statusImageSrc":"image.bad.jpg","type":0,"width":0,"x":-666,"y":76}',
+ (string) StaticGraph::fromArray(
+ [
+ 'id' => 7,
+ 'type' => STATIC_GRAPH,
+ 'label' => null,
+ 'labelPosition' => 'up',
+ 'isLinkEnabled' => true,
+ 'isOnTop' => false,
+ 'parentId' => null,
+ 'width' => '0',
+ 'height' => '0',
+ 'x' => -666,
+ 'y' => 76,
+ 'image' => 'image.jpg',
+ 'linkedLayoutId' => 2,
+ 'linked_layout_status_type' => 'service',
+ 'linkedLayoutStatusTypeWarningThreshold' => 50,
+ 'linked_layout_status_as_service_critical' => 80,
+ 'statusImageSrc' => 'image.bad.jpg',
+ ]
+ )
+ );
+ }
+
+
+ /**
+ * Test if the instance is not created when using a invalid image src.
+ *
+ * @return void
+ */
+ public function testCannotBeCreatedWithInvalidImageSrc(): void
+ {
+ $this->expectException(InvalidArgumentException::class);
+ // Invalid imageSrc.
+ StaticGraph::fromArray(
+ [
+ 'id' => 3,
+ 'type' => STATIC_GRAPH,
+ 'label' => null,
+ 'isLinkEnabled' => true,
+ 'isOnTop' => false,
+ 'parentId' => null,
+ 'width' => '330',
+ 'height' => '0',
+ 'x' => 511,
+ 'y' => 76,
+ 'imageSrc' => 45,
+ 'showLastValueTooltip' => 'disabled',
+ ]
+ );
+
+ // Missing imageSrc.
+ StaticGraph::fromArray(
+ [
+ 'id' => 3,
+ 'type' => STATIC_GRAPH,
+ 'label' => null,
+ 'isLinkEnabled' => true,
+ 'isOnTop' => false,
+ 'parentId' => null,
+ 'width' => '330',
+ 'height' => '0',
+ 'x' => 511,
+ 'y' => 76,
+ 'showLastValueTooltip' => 'enabled',
+ ]
+ );
+ }
+
+
+}
diff --git a/pandora_console/tests/bootstrap.php b/pandora_console/tests/bootstrap.php
new file mode 100644
index 0000000000..c2d6c31bf2
--- /dev/null
+++ b/pandora_console/tests/bootstrap.php
@@ -0,0 +1,4 @@
+apcuPrefix = function_exists('apcu_fetch') && ini_get('apc.enabled') ? $apcuPrefix : null;
+ $this->apcuPrefix = function_exists('apcu_fetch') && filter_var(ini_get('apc.enabled'), FILTER_VALIDATE_BOOLEAN) ? $apcuPrefix : null;
}
/**
diff --git a/pandora_console/vendor/composer/autoload_psr4.php b/pandora_console/vendor/composer/autoload_psr4.php
index cd3de7c147..57404185e1 100644
--- a/pandora_console/vendor/composer/autoload_psr4.php
+++ b/pandora_console/vendor/composer/autoload_psr4.php
@@ -6,8 +6,11 @@ $vendorDir = dirname(dirname(__FILE__));
$baseDir = dirname($vendorDir);
return array(
+ 'Tests\\' => array($baseDir . '/tests'),
'Psr\\Log\\' => array($vendorDir . '/psr/log/Psr/Log'),
'Mpdf\\' => array($vendorDir . '/mpdf/mpdf/src'),
+ 'Models\\' => array($baseDir . '/include/rest-api/models'),
+ 'Enterprise\\Models\\' => array($baseDir . '/enterprise/include/rest-api/models'),
'Egulias\\EmailValidator\\' => array($vendorDir . '/egulias/email-validator/EmailValidator'),
'DeepCopy\\' => array($vendorDir . '/myclabs/deep-copy/src/DeepCopy'),
);
diff --git a/pandora_console/vendor/composer/autoload_static.php b/pandora_console/vendor/composer/autoload_static.php
index 2e8ac5a72e..f6d8bc0456 100644
--- a/pandora_console/vendor/composer/autoload_static.php
+++ b/pandora_console/vendor/composer/autoload_static.php
@@ -12,6 +12,10 @@ class ComposerStaticInitfdecadadce22e6dde51e9535fe4ad7aa
);
public static $prefixLengthsPsr4 = array (
+ 'T' =>
+ array (
+ 'Tests\\' => 6,
+ ),
'P' =>
array (
'Psr\\Log\\' => 8,
@@ -19,9 +23,11 @@ class ComposerStaticInitfdecadadce22e6dde51e9535fe4ad7aa
'M' =>
array (
'Mpdf\\' => 5,
+ 'Models\\' => 7,
),
'E' =>
array (
+ 'Enterprise\\Models\\' => 18,
'Egulias\\EmailValidator\\' => 23,
),
'D' =>
@@ -31,6 +37,10 @@ class ComposerStaticInitfdecadadce22e6dde51e9535fe4ad7aa
);
public static $prefixDirsPsr4 = array (
+ 'Tests\\' =>
+ array (
+ 0 => __DIR__ . '/../..' . '/tests',
+ ),
'Psr\\Log\\' =>
array (
0 => __DIR__ . '/..' . '/psr/log/Psr/Log',
@@ -39,6 +49,14 @@ class ComposerStaticInitfdecadadce22e6dde51e9535fe4ad7aa
array (
0 => __DIR__ . '/..' . '/mpdf/mpdf/src',
),
+ 'Models\\' =>
+ array (
+ 0 => __DIR__ . '/../..' . '/include/rest-api/models',
+ ),
+ 'Enterprise\\Models\\' =>
+ array (
+ 0 => __DIR__ . '/../..' . '/enterprise/include/rest-api/models',
+ ),
'Egulias\\EmailValidator\\' =>
array (
0 => __DIR__ . '/..' . '/egulias/email-validator/EmailValidator',
diff --git a/pandora_server/DEBIAN/control b/pandora_server/DEBIAN/control
index 68041401d6..56042b8fcc 100644
--- a/pandora_server/DEBIAN/control
+++ b/pandora_server/DEBIAN/control
@@ -1,5 +1,5 @@
package: pandorafms-server
-Version: 7.0NG.733-190417
+Version: 7.0NG.734-190503
Architecture: all
Priority: optional
Section: admin
diff --git a/pandora_server/DEBIAN/make_deb_package.sh b/pandora_server/DEBIAN/make_deb_package.sh
index c2b7cafe72..407d642ea4 100644
--- a/pandora_server/DEBIAN/make_deb_package.sh
+++ b/pandora_server/DEBIAN/make_deb_package.sh
@@ -14,7 +14,7 @@
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
-pandora_version="7.0NG.733-190417"
+pandora_version="7.0NG.734-190503"
package_cpan=0
package_pandora=1
diff --git a/pandora_server/conf/pandora_server.conf.new b/pandora_server/conf/pandora_server.conf.new
index 3dad8a139f..625113b7c1 100644
--- a/pandora_server/conf/pandora_server.conf.new
+++ b/pandora_server/conf/pandora_server.conf.new
@@ -1,7 +1,7 @@
#############################################################################
# Pandora FMS Server Parameters
# Pandora FMS, the Flexible Monitoring System.
-# Version 7.0NG.733
+# Version 7.0NG.734
# Licensed under GPL license v2,
# (c) 2003-2017 Artica Soluciones Tecnologicas
# http://www.pandorafms.com
diff --git a/pandora_server/lib/PandoraFMS/Config.pm b/pandora_server/lib/PandoraFMS/Config.pm
index 61578042f0..aecf535334 100644
--- a/pandora_server/lib/PandoraFMS/Config.pm
+++ b/pandora_server/lib/PandoraFMS/Config.pm
@@ -44,8 +44,8 @@ our @EXPORT = qw(
);
# version: Defines actual version of Pandora Server for this module only
-my $pandora_version = "7.0NG.733";
-my $pandora_build = "190417";
+my $pandora_version = "7.0NG.734";
+my $pandora_build = "190503";
our $VERSION = $pandora_version." ".$pandora_build;
# Setup hash
@@ -1200,7 +1200,7 @@ sub pandora_get_tconfig_token ($$$) {
my ($dbh, $token, $default_value) = @_;
my $token_value = get_db_value ($dbh, "SELECT value FROM tconfig WHERE token = ?", $token);
- if (defined ($token_value)) {
+ if (defined ($token_value) && $token_value ne '') {
return safe_output ($token_value);
}
diff --git a/pandora_server/lib/PandoraFMS/DiscoveryServer.pm b/pandora_server/lib/PandoraFMS/DiscoveryServer.pm
index 918f0bcc4a..c92b56ed0d 100644
--- a/pandora_server/lib/PandoraFMS/DiscoveryServer.pm
+++ b/pandora_server/lib/PandoraFMS/DiscoveryServer.pm
@@ -53,798 +53,975 @@ my $Sem :shared;
my $TaskSem :shared;
# IDs from tconfig_os.
-use constant OS_OTHER => 10;
-use constant OS_ROUTER => 17;
-use constant OS_SWITCH => 18;
+use constant {
+ OS_OTHER => 10,
+ OS_ROUTER => 17,
+ OS_SWITCH => 18,
+ DISCOVERY_HOSTDEVICES => 0,
+ DISCOVERY_HOSTDEVICES_CUSTOM => 1,
+ DISCOVERY_CLOUD_AWS => 2,
+ DISCOVERY_APP_VMWARE => 3,
+ DISCOVERY_APP_MYSQL => 4,
+ DISCOVERY_APP_ORACLE => 5,
+ DISCOVERY_CLOUD_AWS_EC2 => 6,
+ DISCOVERY_CLOUD_AWS_RDS => 7
+};
########################################################################################
# Discovery Server class constructor.
########################################################################################
sub new ($$$$$$) {
- my ($class, $config, $dbh) = @_;
-
- return undef unless $config->{'reconserver'} == 1 || $config->{'discoveryserver'} == 1;
-
- if (! -e $config->{'nmap'}) {
- logger ($config, ' [E] ' . $config->{'nmap'} . " needed by " . $config->{'rb_product_name'} . " Discovery Server not found.", 1);
- print_message ($config, ' [E] ' . $config->{'nmap'} . " needed by " . $config->{'rb_product_name'} . " Discovery Server not found.", 1);
- return undef;
- }
+ my ($class, $config, $dbh) = @_;
+
+ return undef unless $config->{'reconserver'} == 1 || $config->{'discoveryserver'} == 1;
+
+ if (! -e $config->{'nmap'}) {
+ logger ($config, ' [E] ' . $config->{'nmap'} . " needed by " . $config->{'rb_product_name'} . " Discovery Server not found.", 1);
+ print_message ($config, ' [E] ' . $config->{'nmap'} . " needed by " . $config->{'rb_product_name'} . " Discovery Server not found.", 1);
+ return undef;
+ }
- # Initialize semaphores and queues
- @TaskQueue = ();
- %PendingTasks = ();
- $Sem = Thread::Semaphore->new;
- $TaskSem = Thread::Semaphore->new (0);
-
- # Restart automatic recon tasks.
- db_do ($dbh, 'UPDATE trecon_task SET utimestamp = 0 WHERE id_recon_server = ? AND status <> -1 AND interval_sweep > 0',
- get_server_id ($dbh, $config->{'servername'}, DISCOVERYSERVER));
+ # Initialize semaphores and queues
+ @TaskQueue = ();
+ %PendingTasks = ();
+ $Sem = Thread::Semaphore->new;
+ $TaskSem = Thread::Semaphore->new (0);
+
+ # Restart automatic recon tasks.
+ db_do ($dbh, 'UPDATE trecon_task SET utimestamp = 0 WHERE id_recon_server = ? AND status <> -1 AND interval_sweep > 0',
+ get_server_id ($dbh, $config->{'servername'}, DISCOVERYSERVER));
- # Reset (but do not restart) manual recon tasks.
- db_do ($dbh, 'UPDATE trecon_task SET status = -1 WHERE id_recon_server = ? AND status <> -1 AND interval_sweep = 0',
- get_server_id ($dbh, $config->{'servername'}, DISCOVERYSERVER));
+ # Reset (but do not restart) manual recon tasks.
+ db_do ($dbh, 'UPDATE trecon_task SET status = -1 WHERE id_recon_server = ? AND status <> -1 AND interval_sweep = 0',
+ get_server_id ($dbh, $config->{'servername'}, DISCOVERYSERVER));
- # Call the constructor of the parent class
- my $self = $class->SUPER::new($config, DISCOVERYSERVER, \&PandoraFMS::DiscoveryServer::data_producer, \&PandoraFMS::DiscoveryServer::data_consumer, $dbh);
-
- bless $self, $class;
- return $self;
+ # Call the constructor of the parent class
+ my $self = $class->SUPER::new($config, DISCOVERYSERVER, \&PandoraFMS::DiscoveryServer::data_producer, \&PandoraFMS::DiscoveryServer::data_consumer, $dbh);
+
+ bless $self, $class;
+ return $self;
}
###############################################################################
# Run.
###############################################################################
sub run ($) {
- my $self = shift;
- my $pa_config = $self->getConfig ();
-
- print_message ($pa_config, " [*] Starting " . $pa_config->{'rb_product_name'} . " Discovery Server.", 1);
- my $threads = $pa_config->{'recon_threads'};
+ my $self = shift;
+ my $pa_config = $self->getConfig ();
+ my $dbh = $self->getDBH();
+
+ print_message ($pa_config, " [*] Starting " . $pa_config->{'rb_product_name'} . " Discovery Server.", 1);
+ my $threads = $pa_config->{'recon_threads'};
- # Use hightest value
- if ($pa_config->{'discovery_threads'} > $pa_config->{'recon_threads'}) {
- $threads = $pa_config->{'discovery_threads'};
- }
- $self->setNumThreads($threads);
- $self->SUPER::run (\@TaskQueue, \%PendingTasks, $Sem, $TaskSem);
+ # Prepare some environmental variables.
+ $ENV{'AWS_ACCESS_KEY_ID'} = pandora_get_config_value($dbh, 'aws_access_key_id');
+ $ENV{'AWS_SECRET_ACCESS_KEY'} = pandora_get_config_value($dbh, 'aws_secret_access_key');
+
+ # Use hightest value
+ if ($pa_config->{'discovery_threads'} > $pa_config->{'recon_threads'}) {
+ $threads = $pa_config->{'discovery_threads'};
+ }
+ $self->setNumThreads($threads);
+ $self->SUPER::run (\@TaskQueue, \%PendingTasks, $Sem, $TaskSem);
}
###############################################################################
# Data producer.
###############################################################################
sub data_producer ($) {
- my $self = shift;
- my ($pa_config, $dbh) = ($self->getConfig (), $self->getDBH ());
-
- my @tasks;
-
- my $server_id = get_server_id ($dbh, $pa_config->{'servername'}, $self->getServerType ());
- return @tasks unless defined ($server_id);
-
- # Manual tasks have interval_sweep = 0
- # Manual tasks are "forced" like the other, setting the utimestamp to 1
- # By default, after create a tasks it takes the utimestamp to 0
- # Status -1 means "done".
-
- my @rows = get_db_rows ($dbh, 'SELECT * FROM trecon_task
- WHERE id_recon_server = ?
- AND disabled = 0
- AND ((utimestamp = 0 AND interval_sweep != 0 OR status = 1)
- OR (status = -1 AND interval_sweep > 0 AND (utimestamp + interval_sweep) < UNIX_TIMESTAMP()))', $server_id);
- foreach my $row (@rows) {
-
- # Update task status
- update_recon_task ($dbh, $row->{'id_rt'}, 1);
-
- push (@tasks, $row->{'id_rt'});
- }
-
- return @tasks;
+ my $self = shift;
+ my ($pa_config, $dbh) = ($self->getConfig (), $self->getDBH ());
+
+ my @tasks;
+
+ my $server_id = get_server_id ($dbh, $pa_config->{'servername'}, $self->getServerType ());
+ return @tasks unless defined ($server_id);
+
+ # Manual tasks have interval_sweep = 0
+ # Manual tasks are "forced" like the other, setting the utimestamp to 1
+ # By default, after create a tasks it takes the utimestamp to 0
+ # Status -1 means "done".
+
+ my @rows = get_db_rows ($dbh, 'SELECT * FROM trecon_task
+ WHERE id_recon_server = ?
+ AND disabled = 0
+ AND ((utimestamp = 0 AND interval_sweep != 0 OR status = 1)
+ OR (status = -1 AND interval_sweep > 0 AND (utimestamp + interval_sweep) < UNIX_TIMESTAMP()))', $server_id);
+ foreach my $row (@rows) {
+
+ # Update task status
+ update_recon_task ($dbh, $row->{'id_rt'}, 1);
+
+ push (@tasks, $row->{'id_rt'});
+ }
+
+ return @tasks;
}
###############################################################################
# Data consumer.
###############################################################################
sub data_consumer ($$) {
- my ($self, $task_id) = @_;
- my ($pa_config, $dbh) = ($self->getConfig (), $self->getDBH ());
+ my ($self, $task_id) = @_;
+ my ($pa_config, $dbh) = ($self->getConfig (), $self->getDBH ());
- # Get recon task data
- my $task = get_db_single_row ($dbh, 'SELECT * FROM trecon_task WHERE id_rt = ?', $task_id);
- return -1 unless defined ($task);
+ # Get server id.
+ my $server_id = get_server_id($dbh, $pa_config->{'servername'}, $self->getServerType());
- # Is it a recon script?
- if (defined ($task->{'id_recon_script'}) && ($task->{'id_recon_script'} != 0)) {
- exec_recon_script ($pa_config, $dbh, $task);
- return;
- } else {
- logger($pa_config, 'Starting recon task for net ' . $task->{'subnet'} . '.', 10);
- }
+ # Get recon task data
+ my $task = get_db_single_row ($dbh, 'SELECT * FROM trecon_task WHERE id_rt = ?', $task_id);
+ return -1 unless defined ($task);
- eval {
- my @subnets = split(/,/, safe_output($task->{'subnet'}));
- my @communities = split(/,/, safe_output($task->{'snmp_community'}));
- my @auth_strings = ();
- if(defined($task->{'auth_strings'})) {
- @auth_strings = split(/,/, safe_output($task->{'auth_strings'}));
+ # Is it a recon script?
+ if (defined ($task->{'id_recon_script'}) && ($task->{'id_recon_script'} != 0)) {
+ exec_recon_script ($pa_config, $dbh, $task);
+ return;
+ } else {
+ logger($pa_config, 'Starting recon task for net ' . $task->{'subnet'} . '.', 10);
+ }
+
+ eval {
+ my @subnets = split(/,/, safe_output($task->{'subnet'}));
+ my @communities = split(/,/, safe_output($task->{'snmp_community'}));
+ my @auth_strings = ();
+ if(defined($task->{'auth_strings'})) {
+ @auth_strings = split(/,/, safe_output($task->{'auth_strings'}));
+ }
+
+ my $main_event = pandora_event($pa_config, "[Discovery] Execution summary",$task->{'id_group'}, 0, 0, 0, 0, 'system', 0, $dbh);
+
+ my %cnf_extra;
+ if ($task->{'type'} == DISCOVERY_CLOUD_AWS_EC2
+ || $task->{'type'} == DISCOVERY_CLOUD_AWS_RDS) {
+ $cnf_extra{'aws_access_key_id'} = pandora_get_config_value($dbh, 'aws_access_key_id');
+ $cnf_extra{'aws_secret_access_key'} = pandora_get_config_value($dbh, 'aws_secret_access_key');
+ $cnf_extra{'cloud_util_path'} = pandora_get_config_value($dbh, 'cloud_util_path');
+
+ if (!defined($ENV{'AWS_ACCESS_KEY_ID'}) || !defined($ENV{'AWS_SECRET_ACCESS_KEY'})
+ || $cnf_extra{'aws_secret_access_key'} ne $ENV{'AWS_ACCESS_KEY_ID'}
+ || $cnf_extra{'cloud_util_path'} ne $ENV{'AWS_SECRET_ACCESS_KEY'}) {
+ # Environmental data is out of date. Create a tmp file to manage
+ # credentials. Perl limitation. We cannot update ENV here.
+ $cnf_extra{'creds_file'} = $pa_config->{'temporal'} . '/tmp_discovery.' . md5($task->{'id_rt'} . $task->{'name'} . time());
+ eval {
+ open(my $__file_cfg, '> '. $cnf_extra{'creds_file'}) or die($!);
+ print $__file_cfg $cnf_extra{'aws_access_key_id'} . "\n";
+ print $__file_cfg $cnf_extra{'aws_secret_access_key'} . "\n";
+ close($__file_cfg);
+ set_file_permissions(
+ $pa_config,
+ $cnf_extra{'creds_file'},
+ "0600"
+ );
+ };
+ if ($@) {
+ logger(
+ $pa_config,
+ 'Cannot instantiate configuration file for task: ' . safe_output($task->{'name'}),
+ 5
+ );
+ # A server restart will override ENV definition (see run)
+ logger(
+ $pa_config,
+ 'Cannot execute Discovery task: ' . safe_output($task->{'name'}) . '. Please restart the server.',
+ 1
+ );
+ # Skip this task.
+ return;
+ }
+ }
+ }
+
+ my $recon = new PandoraFMS::Recon::Base(
+ communities => \@communities,
+ dbh => $dbh,
+ group_id => $task->{'id_group'},
+ id_os => $task->{'id_os'},
+ id_network_profile => $task->{'id_network_profile'},
+ os_detection => $task->{'os_detect'},
+ parent_detection => $task->{'parent_detection'},
+ parent_recursion => $task->{'parent_recursion'},
+ pa_config => $pa_config,
+ recon_ports => $task->{'recon_ports'},
+ resolve_names => $task->{'resolve_names'},
+ snmp_auth_user => $task->{'snmp_auth_user'},
+ snmp_auth_pass => $task->{'snmp_auth_pass'},
+ snmp_auth_method => $task->{'snmp_auth_method'},
+ snmp_checks => $task->{'snmp_checks'},
+ snmp_enabled => $task->{'snmp_enabled'},
+ snmp_privacy_method => $task->{'snmp_privacy_method'},
+ snmp_privacy_pass => $task->{'snmp_privacy_pass'},
+ snmp_security_level => $task->{'snmp_security_level'},
+ snmp_timeout => $task->{'snmp_timeout'},
+ snmp_version => $task->{'snmp_version'},
+ subnets => \@subnets,
+ task_id => $task->{'id_rt'},
+ vlan_cache_enabled => $task->{'vlan_enabled'},
+ wmi_enabled => $task->{'wmi_enabled'},
+ auth_strings_array => \@auth_strings,
+ autoconfiguration_enabled => $task->{'autoconfiguration_enabled'},
+ main_event_id => $main_event,
+ server_id => $server_id,
+ %{$pa_config},
+ task_data => $task,
+ %cnf_extra
+ );
+
+ $recon->scan();
+
+ # Clean tmp file.
+ if (defined($cnf_extra{'creds_file'})
+ && -f $cnf_extra{'creds_file'}) {
+ unlink($cnf_extra{'creds_file'});
}
-
- my $main_event = pandora_event($pa_config, "[Discovery] Execution summary",$task->{'id_group'}, 0, 0, 0, 0, 'system', 0, $dbh);
-
- my $recon = new PandoraFMS::Recon::Base(
- communities => \@communities,
- dbh => $dbh,
- group_id => $task->{'id_group'},
- id_os => $task->{'id_os'},
- id_network_profile => $task->{'id_network_profile'},
- os_detection => $task->{'os_detect'},
- parent_detection => $task->{'parent_detection'},
- parent_recursion => $task->{'parent_recursion'},
- pa_config => $pa_config,
- recon_ports => $task->{'recon_ports'},
- resolve_names => $task->{'resolve_names'},
- snmp_auth_user => $task->{'snmp_auth_user'},
- snmp_auth_pass => $task->{'snmp_auth_pass'},
- snmp_auth_method => $task->{'snmp_auth_method'},
- snmp_checks => $task->{'snmp_checks'},
- snmp_enabled => $task->{'snmp_enabled'},
- snmp_privacy_method => $task->{'snmp_privacy_method'},
- snmp_privacy_pass => $task->{'snmp_privacy_pass'},
- snmp_security_level => $task->{'snmp_security_level'},
- snmp_timeout => $task->{'snmp_timeout'},
- snmp_version => $task->{'snmp_version'},
- subnets => \@subnets,
- task_id => $task->{'id_rt'},
- vlan_cache_enabled => $task->{'vlan_enabled'},
- wmi_enabled => $task->{'wmi_enabled'},
- auth_strings_array => \@auth_strings,
- autoconfiguration_enabled => $task->{'autoconfiguration_enabled'},
- main_event_id => $main_event,
- %{$pa_config}
- );
-
- $recon->scan();
- };
- if ($@) {
- update_recon_task ($dbh, $task_id, -1);
- return;
- }
+ };
+ if ($@) {
+ logger(
+ $pa_config,
+ 'Cannot execute Discovery task: ' . safe_output($task->{'name'}) . $@,
+ 10
+ );
+ update_recon_task ($dbh, $task_id, -1);
+ return;
+ }
}
##########################################################################
# Update recon task status.
##########################################################################
sub update_recon_task ($$$) {
- my ($dbh, $id_task, $status) = @_;
-
- db_do ($dbh, 'UPDATE trecon_task SET utimestamp = ?, status = ? WHERE id_rt = ?', time (), $status, $id_task);
+ my ($dbh, $id_task, $status) = @_;
+
+ db_do ($dbh, 'UPDATE trecon_task SET utimestamp = ?, status = ? WHERE id_rt = ?', time (), $status, $id_task);
}
##########################################################################
# Executes recon scripts
##########################################################################
sub exec_recon_script ($$$) {
- my ($pa_config, $dbh, $task) = @_;
-
- # Get recon plugin data
- my $script = get_db_single_row ($dbh, 'SELECT * FROM trecon_script WHERE id_recon_script = ?', $task->{'id_recon_script'});
- return -1 unless defined ($script);
-
- logger($pa_config, 'Executing recon script ' . safe_output($script->{'name'}), 10);
-
- my $command = safe_output($script->{'script'});
-
- my $macros = safe_output($task->{'macros'});
+ my ($pa_config, $dbh, $task) = @_;
+
+ # Get recon plugin data
+ my $script = get_db_single_row ($dbh, 'SELECT * FROM trecon_script WHERE id_recon_script = ?', $task->{'id_recon_script'});
+ return -1 unless defined ($script);
+
+ logger($pa_config, 'Executing recon script ' . safe_output($script->{'name'}), 10);
+
+ my $command = safe_output($script->{'script'});
+
+ my $macros = safe_output($task->{'macros'});
- # \r and \n should be escaped for decode_json().
- $macros =~ s/\n/\\n/g;
- $macros =~ s/\r/\\r/g;
- my $decoded_macros;
-
- if ($macros) {
- eval {
- $decoded_macros = decode_json(encode_utf8($macros));
- };
- }
-
- my $macros_parameters = '';
-
- # Add module macros as parameter
- if(ref($decoded_macros) eq "HASH") {
- # Convert the hash to a sorted array
- my @sorted_macros;
- while (my ($i, $m) = each (%{$decoded_macros})) {
- $sorted_macros[$i] = $m;
- }
+ # \r and \n should be escaped for decode_json().
+ $macros =~ s/\n/\\n/g;
+ $macros =~ s/\r/\\r/g;
+ my $decoded_macros;
+
+ if ($macros) {
+ eval {
+ $decoded_macros = decode_json(encode_utf8($macros));
+ };
+ }
+
+ my $macros_parameters = '';
+
+ # Add module macros as parameter
+ if(ref($decoded_macros) eq "HASH") {
+ # Convert the hash to a sorted array
+ my @sorted_macros;
+ while (my ($i, $m) = each (%{$decoded_macros})) {
+ $sorted_macros[$i] = $m;
+ }
- # Remove the 0 position
- shift @sorted_macros;
+ # Remove the 0 position
+ shift @sorted_macros;
- foreach my $m (@sorted_macros) {
- $macros_parameters = $macros_parameters . ' "' . $m->{"value"} . '"';
- }
- }
+ foreach my $m (@sorted_macros) {
+ $macros_parameters = $macros_parameters . ' "' . $m->{"value"} . '"';
+ }
+ }
- my $ent_script = 0;
- my $args = enterprise_hook('discovery_custom_recon_scripts',[$pa_config, $dbh, $task, $script]);
- if (!$args) {
- $args = "$task->{'id_rt'} $task->{'id_group'} $task->{'create_incident'} $macros_parameters";
- } else {
- $ent_script = 1;
- }
-
- if (-x $command) {
- my $exec_output = `$command $args`;
- logger($pa_config, "Execution output: \n". $exec_output, 10);
- } else {
- logger($pa_config, "Cannot execute recon task command $command.", 10);
- }
-
- # Only update the timestamp in case something went wrong. The script should set the status.
- db_do ($dbh, 'UPDATE trecon_task SET utimestamp = ? WHERE id_rt = ?', time (), $task->{'id_rt'});
+ my $ent_script = 0;
+ my $args = enterprise_hook('discovery_custom_recon_scripts',[$pa_config, $dbh, $task, $script]);
+ if (!$args) {
+ $args = "$task->{'id_rt'} $task->{'id_group'} $task->{'create_incident'} $macros_parameters";
+ } else {
+ $ent_script = 1;
+ }
+
+ if (-x $command) {
+ my $exec_output = `$command $args`;
+ logger($pa_config, "Execution output: \n". $exec_output, 10);
+ } else {
+ logger($pa_config, "Cannot execute recon task command $command.", 10);
+ }
+
+ # Only update the timestamp in case something went wrong. The script should set the status.
+ db_do ($dbh, 'UPDATE trecon_task SET utimestamp = ? WHERE id_rt = ?', time (), $task->{'id_rt'});
- if ($ent_script == 1) {
- enterprise_hook('discovery_clean_custom_recon',[$pa_config, $dbh, $task, $script]);
- }
-
- logger($pa_config, 'Done executing recon script ' . safe_output($script->{'name'}), 10);
- return 0;
+ if ($ent_script == 1) {
+ enterprise_hook('discovery_clean_custom_recon',[$pa_config, $dbh, $task, $script]);
+ }
+
+ logger($pa_config, 'Done executing recon script ' . safe_output($script->{'name'}), 10);
+ return 0;
}
##########################################################################
# Guess the OS using xprobe2 or nmap.
##########################################################################
sub PandoraFMS::Recon::Base::guess_os($$) {
- my ($self, $device) = @_;
+ my ($self, $device) = @_;
- # OS detection disabled. Use the device type.
- if ($self->{'os_detection'} == 0) {
- my $device_type = $self->get_device_type($device);
- return OS_OTHER unless defined($device_type);
+ # OS detection disabled. Use the device type.
+ if ($self->{'os_detection'} == 0) {
+ my $device_type = $self->get_device_type($device);
+ return OS_OTHER unless defined($device_type);
- return OS_ROUTER if ($device_type eq 'router');
- return OS_SWITCH if ($device_type eq 'switch');
- return OS_OTHER;
- }
+ return OS_ROUTER if ($device_type eq 'router');
+ return OS_SWITCH if ($device_type eq 'switch');
+ return OS_OTHER;
+ }
- # Use xprobe2 if available
- if (-e $self->{pa_config}->{xprobe2}) {
- my $output = `"$self->{pa_config}->{xprobe2}" $device 2>$DEVNULL | grep 'Running OS' | head -1`;
- return OS_OTHER if ($? != 0);
- return pandora_get_os($self->{'dbh'}, $output);
- }
-
- # Use nmap by default
- if (-e $self->{pa_config}->{nmap}) {
- my $output = `"$self->{pa_config}->{nmap}" -F -O $device 2>$DEVNULL | grep 'Aggressive OS guesses'`;
- return OS_OTHER if ($? != 0);
- return pandora_get_os($self->{'dbh'}, $output);
- }
+ # Use xprobe2 if available
+ if (-e $self->{pa_config}->{xprobe2}) {
+ my $output = `"$self->{pa_config}->{xprobe2}" $device 2>$DEVNULL | grep 'Running OS' | head -1`;
+ return OS_OTHER if ($? != 0);
+ return pandora_get_os($self->{'dbh'}, $output);
+ }
+
+ # Use nmap by default
+ if (-e $self->{pa_config}->{nmap}) {
+ my $output = `"$self->{pa_config}->{nmap}" -F -O $device 2>$DEVNULL | grep 'Aggressive OS guesses'`;
+ return OS_OTHER if ($? != 0);
+ return pandora_get_os($self->{'dbh'}, $output);
+ }
- return OS_OTHER;
+ return OS_OTHER;
}
##############################################################################
# Returns the number of open ports from the given list.
##############################################################################
sub PandoraFMS::Recon::Base::tcp_scan ($$) {
- my ($self, $host) = @_;
+ my ($self, $host) = @_;
- my $open_ports = `"$self->{pa_config}->{nmap}" -p$self->{recon_ports} $host | grep open | wc -l`;
- return $open_ports;
+ my $open_ports = `"$self->{pa_config}->{nmap}" -p$self->{recon_ports} $host | grep open | wc -l`;
+ return $open_ports;
}
##########################################################################
# Create network profile modules for the given agent.
##########################################################################
sub PandoraFMS::Recon::Base::create_network_profile_modules($$$) {
- my ($self, $agent_id, $device) = @_;
-
- return unless ($self->{'id_network_profile'} > 0);
-
- # Get network components associated to the network profile.
- my @np_components = get_db_rows($self->{'dbh'}, 'SELECT * FROM tnetwork_profile_component WHERE id_np = ?', $self->{'id_network_profile'});
- foreach my $np_component (@np_components) {
+ my ($self, $agent_id, $device) = @_;
+
+ return unless ($self->{'id_network_profile'} > 0);
+
+ # Get network components associated to the network profile.
+ my @np_components = get_db_rows($self->{'dbh'}, 'SELECT * FROM tnetwork_profile_component WHERE id_np = ?', $self->{'id_network_profile'});
+ foreach my $np_component (@np_components) {
- # Get network component data
- my $component = get_db_single_row($self->{'dbh'}, 'SELECT * FROM tnetwork_component WHERE id_nc = ?', $np_component->{'id_nc'});
- if (!defined ($component)) {
- $self->call('message', "Network component ID " . $np_component->{'id_nc'} . " not found.", 5);
- next;
- }
+ # Get network component data
+ my $component = get_db_single_row($self->{'dbh'}, 'SELECT * FROM tnetwork_component WHERE id_nc = ?', $np_component->{'id_nc'});
+ if (!defined ($component)) {
+ $self->call('message', "Network component ID " . $np_component->{'id_nc'} . " not found.", 5);
+ next;
+ }
- # Use snmp_community from network task instead the component snmp_community
- $component->{'snmp_community'} = safe_output($self->get_community($device));
- $component->{'tcp_send'} = $self->{'snmp_version'};
- $component->{'custom_string_1'} = $self->{'snmp_privacy_method'};
- $component->{'custom_string_2'} = $self->{'snmp_privacy_pass'};
- $component->{'custom_string_3'} = $self->{'snmp_security_level'};
- $component->{'plugin_parameter'} = $self->{'snmp_auth_method'};
- $component->{'plugin_user'} = $self->{'snmp_auth_user'};
- $component->{'plugin_pass'} = $self->{'snmp_auth_pass'};
+ # Use snmp_community from network task instead the component snmp_community
+ $component->{'snmp_community'} = safe_output($self->get_community($device));
+ $component->{'tcp_send'} = $self->{'snmp_version'};
+ $component->{'custom_string_1'} = $self->{'snmp_privacy_method'};
+ $component->{'custom_string_2'} = $self->{'snmp_privacy_pass'};
+ $component->{'custom_string_3'} = $self->{'snmp_security_level'};
+ $component->{'plugin_parameter'} = $self->{'snmp_auth_method'};
+ $component->{'plugin_user'} = $self->{'snmp_auth_user'};
+ $component->{'plugin_pass'} = $self->{'snmp_auth_pass'};
- pandora_create_module_from_network_component($self->{'pa_config'}, $component, $agent_id, $self->{'dbh'});
- }
+ pandora_create_module_from_network_component($self->{'pa_config'}, $component, $agent_id, $self->{'dbh'});
+ }
}
##########################################################################
# Connect the given devices in the Pandora FMS database.
##########################################################################
sub PandoraFMS::Recon::Base::connect_agents($$$$$) {
- my ($self, $dev_1, $if_1, $dev_2, $if_2) = @_;
+ my ($self, $dev_1, $if_1, $dev_2, $if_2) = @_;
- # Get the agent for the first device.
- my $agent_1 = get_agent_from_addr($self->{'dbh'}, $dev_1);
- if (!defined($agent_1)) {
- $agent_1 = get_agent_from_name($self->{'dbh'}, $dev_1);
- }
- return unless defined($agent_1);
+ # Get the agent for the first device.
+ my $agent_1 = get_agent_from_addr($self->{'dbh'}, $dev_1);
+ if (!defined($agent_1)) {
+ $agent_1 = get_agent_from_name($self->{'dbh'}, $dev_1);
+ }
+ return unless defined($agent_1);
- # Get the agent for the second device.
- my $agent_2 = get_agent_from_addr($self->{'dbh'}, $dev_2);
- if (!defined($agent_2)) {
- $agent_2 = get_agent_from_name($self->{'dbh'}, $dev_2);
- }
- return unless defined($agent_2);
+ # Get the agent for the second device.
+ my $agent_2 = get_agent_from_addr($self->{'dbh'}, $dev_2);
+ if (!defined($agent_2)) {
+ $agent_2 = get_agent_from_name($self->{'dbh'}, $dev_2);
+ }
+ return unless defined($agent_2);
- # Use ping modules by default.
- $if_1 = 'ping' if ($if_1 eq '');
- $if_2 = 'ping' if ($if_2 eq '');
+ # Use ping modules by default.
+ $if_1 = 'ping' if ($if_1 eq '');
+ $if_2 = 'ping' if ($if_2 eq '');
- # Check whether the modules exists.
- my $module_name_1 = $if_1 eq 'ping' ? 'ping' : "${if_1}_ifOperStatus";
- my $module_name_2 = $if_2 eq 'ping' ? 'ping' : "${if_2}_ifOperStatus";
- my $module_id_1 = get_agent_module_id($self->{'dbh'}, $module_name_1, $agent_1->{'id_agente'});
- if ($module_id_1 <= 0) {
- $self->call('message', "ERROR: Module " . safe_output($module_name_1) . " does not exist for agent $dev_1.", 5);
- return;
- }
- my $module_id_2 = get_agent_module_id($self->{'dbh'}, $module_name_2, $agent_2->{'id_agente'});
- if ($module_id_2 <= 0) {
- $self->call('message', "ERROR: Module " . safe_output($module_name_2) . " does not exist for agent $dev_2.", 5);
- return;
- }
+ # Check whether the modules exists.
+ my $module_name_1 = $if_1 eq 'ping' ? 'ping' : "${if_1}_ifOperStatus";
+ my $module_name_2 = $if_2 eq 'ping' ? 'ping' : "${if_2}_ifOperStatus";
+ my $module_id_1 = get_agent_module_id($self->{'dbh'}, $module_name_1, $agent_1->{'id_agente'});
+ if ($module_id_1 <= 0) {
+ $self->call('message', "ERROR: Module " . safe_output($module_name_1) . " does not exist for agent $dev_1.", 5);
+ return;
+ }
+ my $module_id_2 = get_agent_module_id($self->{'dbh'}, $module_name_2, $agent_2->{'id_agente'});
+ if ($module_id_2 <= 0) {
+ $self->call('message', "ERROR: Module " . safe_output($module_name_2) . " does not exist for agent $dev_2.", 5);
+ return;
+ }
- # Connect the modules if they are not already connected.
- my $connection_id = get_db_value($self->{'dbh'}, 'SELECT id FROM tmodule_relationship WHERE (module_a = ? AND module_b = ?) OR (module_b = ? AND module_a = ?)', $module_id_1, $module_id_2, $module_id_1, $module_id_2);
- if (! defined($connection_id)) {
- db_do($self->{'dbh'}, 'INSERT INTO tmodule_relationship (`module_a`, `module_b`, `id_rt`) VALUES(?, ?, ?)', $module_id_1, $module_id_2, $self->{'task_id'});
- }
+ # Connect the modules if they are not already connected.
+ my $connection_id = get_db_value($self->{'dbh'}, 'SELECT id FROM tmodule_relationship WHERE (module_a = ? AND module_b = ?) OR (module_b = ? AND module_a = ?)', $module_id_1, $module_id_2, $module_id_1, $module_id_2);
+ if (! defined($connection_id)) {
+ db_do($self->{'dbh'}, 'INSERT INTO tmodule_relationship (`module_a`, `module_b`, `id_rt`) VALUES(?, ?, ?)', $module_id_1, $module_id_2, $self->{'task_id'});
+ }
}
+
+##########################################################################
+# Create agents from db_scan. Uses DataServer methods.
+# data = [
+# 'agent_data' => {},
+# 'module_data' => []
+# ]
+##########################################################################
+sub PandoraFMS::Recon::Base::create_agents($$) {
+ my ($self, $data) = @_;
+
+ my $pa_config = $self->{'pa_config'};
+ my $dbh = $self->{'dbh'};
+ my $server_id = $self->{'server_id'};
+
+ return undef if (ref($data) ne "ARRAY");
+
+ foreach my $information (@{$data}) {
+ my $agent = $information->{'agent_data'};
+ my $modules = $information->{'module_data'};
+ my $force_processing = 0;
+
+ # Search agent
+ my $current_agent = PandoraFMS::Core::locate_agent(
+ $pa_config, $dbh, $agent->{'agent_name'}
+ );
+
+ my $parent_id;
+ if (defined($agent->{'parent_agent_name'})) {
+ $parent_id = PandoraFMS::Core::locate_agent(
+ $pa_config, $dbh, $agent->{'parent_agent_name'}
+ );
+ if ($parent_id) {
+ $parent_id = $parent_id->{'id_agente'};
+ }
+ }
+
+ my $agent_id;
+ my $os_id = get_os_id($dbh, $agent->{'os'});
+
+ if ($os_id < 0) {
+ $os_id = get_os_id($dbh, 'Other');
+ }
+
+ if (!$current_agent) {
+ # Create agent.
+ $agent_id = pandora_create_agent(
+ $pa_config, $pa_config->{'servername'}, $agent->{'agent_name'},
+ $agent->{'address'}, $agent->{'id_group'}, $parent_id,
+ $os_id, $agent->{'description'},
+ $agent->{'interval'}, $dbh, $agent->{'timezone_offset'}
+ );
+
+ $current_agent = $parent_id = PandoraFMS::Core::locate_agent(
+ $pa_config, $dbh, $agent->{'agent_name'}
+ );
+
+ $force_processing = 1;
+
+ } else {
+ $agent_id = $current_agent->{'id_agente'};
+ }
+
+ if (!defined($agent_id)) {
+ return undef;
+ }
+
+ if ($agent->{'address'} ne '') {
+ pandora_add_agent_address(
+ $pa_config, $agent_id, $agent->{'agent_name'},
+ $agent->{'address'}, $dbh
+ );
+ }
+
+ # Update agent information
+ pandora_update_agent(
+ $pa_config, strftime("%Y-%m-%d %H:%M:%S", localtime()), $agent_id,
+ $agent->{'os_version'}, $agent->{'agent_version'},
+ $agent->{'interval'}, $dbh, undef, $parent_id
+ );
+
+ # Add modules.
+ if (ref($modules) eq "ARRAY") {
+ foreach my $module (@{$modules}) {
+ # Translate data structure to simulate XML parser return.
+ my %data_translated = map { $_ => [ $module->{$_} ] } keys %{$module};
+
+ # Process modules.
+ PandoraFMS::DataServer::process_module_data (
+ $pa_config, \%data_translated,
+ $server_id, $current_agent,
+ $module->{'name'}, $module->{'type'},
+ $agent->{'interval'},
+ strftime ("%Y/%m/%d %H:%M:%S", localtime()),
+ $dbh, $force_processing
+ );
+ }
+ }
+ }
+
+}
+
+
##########################################################################
# Create an agent for the given device. Returns the ID of the new (or
# existing) agent, undef on error.
##########################################################################
sub PandoraFMS::Recon::Base::create_agent($$) {
- my ($self, $device) = @_;
+ my ($self, $device) = @_;
- my @agents = get_db_rows($self->{'dbh'},
- 'SELECT * FROM taddress, taddress_agent, tagente
- WHERE tagente.id_agente = taddress_agent.id_agent
- AND taddress_agent.id_a = taddress.id_a
- AND ip = ?', $device
- );
+ my @agents = get_db_rows($self->{'dbh'},
+ 'SELECT * FROM taddress, taddress_agent, tagente
+ WHERE tagente.id_agente = taddress_agent.id_agent
+ AND taddress_agent.id_a = taddress.id_a
+ AND ip = ?', $device
+ );
- # Does the host already exist?
- my $agent;
- foreach my $candidate (@agents) {
- $agent = {map {$_} %$candidate}; # copy contents, do not use shallow copy
- # exclude $device itself, because it handle corner case when target includes NAT
- my @registered = map {$_->{ip}} get_db_rows($self->{'dbh'},
- 'SELECT ip FROM taddress, taddress_agent, tagente
- WHERE tagente.id_agente = taddress_agent.id_agent
- AND taddress_agent.id_a = taddress.id_a
- AND tagente.id_agente = ?
- AND taddress.ip != ?', $agent->{id_agente}, $device
- );
- foreach my $ip_addr (@registered) {
- my @matched = grep { $_ =~ /^$ip_addr$/ } $self->get_addresses($device);
- if (scalar(@matched) == 0) {
- $agent = undef;
- last;
- }
- }
- last if(defined($agent)); # exit loop if match all ip_addr
- }
+ # Does the host already exist?
+ my $agent;
+ foreach my $candidate (@agents) {
+ $agent = {map {$_} %$candidate}; # copy contents, do not use shallow copy
+ # exclude $device itself, because it handle corner case when target includes NAT
+ my @registered = map {$_->{ip}} get_db_rows($self->{'dbh'},
+ 'SELECT ip FROM taddress, taddress_agent, tagente
+ WHERE tagente.id_agente = taddress_agent.id_agent
+ AND taddress_agent.id_a = taddress.id_a
+ AND tagente.id_agente = ?
+ AND taddress.ip != ?', $agent->{id_agente}, $device
+ );
+ foreach my $ip_addr (@registered) {
+ my @matched = grep { $_ =~ /^$ip_addr$/ } $self->get_addresses($device);
+ if (scalar(@matched) == 0) {
+ $agent = undef;
+ last;
+ }
+ }
+ last if(defined($agent)); # exit loop if match all ip_addr
+ }
- if (!defined($agent)) {
- $agent = get_agent_from_name($self->{'dbh'}, $device);
- }
+ if (!defined($agent)) {
+ $agent = get_agent_from_name($self->{'dbh'}, $device);
+ }
- my ($agent_id, $agent_learning);
- if (!defined($agent)) {
+ my ($agent_id, $agent_learning);
+ if (!defined($agent)) {
- # Resolve hostnames.
- my $host_name = $self->{'resolve_names'} == 1 ? gethostbyaddr (inet_aton($device), AF_INET) : $device;
- $host_name = $device unless defined ($host_name);
+ # Resolve hostnames.
+ my $host_name = $self->{'resolve_names'} == 1 ? gethostbyaddr (inet_aton($device), AF_INET) : $device;
+ $host_name = $device unless defined ($host_name);
- # Guess the OS.
- my $id_os = $self->guess_os($device);
+ # Guess the OS.
+ my $id_os = $self->guess_os($device);
- # Are we filtering hosts by OS?
- return if ($self->{'id_os'} > 0 && $id_os != $self->{'id_os'});
+ # Are we filtering hosts by OS?
+ return if ($self->{'id_os'} > 0 && $id_os != $self->{'id_os'});
- # Are we filtering hosts by TCP port?
- return if ($self->{'recon_ports'} ne '' && $self->tcp_scan($device) == 0);
- my $location = get_geoip_info($self->{'pa_config'}, $device);
- $agent_id = pandora_create_agent(
- $self->{'pa_config'}, $self->{'pa_config'}->{'servername'},
- $host_name, $device, $self->{'group_id'}, 0, $id_os,
- '', 300, $self->{'dbh'}, undef, $location->{'longitude'},
- $location->{'latitude'}
- );
- return undef unless defined ($agent_id) and ($agent_id > 0);
+ # Are we filtering hosts by TCP port?
+ return if ($self->{'recon_ports'} ne '' && $self->tcp_scan($device) == 0);
+ my $location = get_geoip_info($self->{'pa_config'}, $device);
+ $agent_id = pandora_create_agent(
+ $self->{'pa_config'}, $self->{'pa_config'}->{'servername'},
+ $host_name, $device, $self->{'group_id'}, 0, $id_os,
+ '', 300, $self->{'dbh'}, undef, $location->{'longitude'},
+ $location->{'latitude'}
+ );
+ return undef unless defined ($agent_id) and ($agent_id > 0);
- # Autoconfigure agent
- if (defined($self->{'autoconfiguration_enabled'}) && $self->{'autoconfiguration_enabled'} == 1) {
- my $agent_data = PandoraFMS::DB::get_db_single_row($self->{'dbh'}, 'SELECT * FROM tagente WHERE id_agente = ?', $agent_id);
- # Update agent configuration once, after create agent.
- enterprise_hook('autoconfigure_agent', [$self->{'pa_config'}, $host_name, $agent_id, $agent_data, $self->{'dbh'}, 1]);
- }
-
- if (defined($self->{'main_event_id'})) {
- my $addresses_str = join(',', safe_output($self->get_addresses($device)));
- pandora_extended_event(
- $self->{'pa_config'}, $self->{'dbh'}, $self->{'main_event_id'},
- "[Discovery] New " . safe_output($self->get_device_type($device)) . " found " . $host_name . " (" . $addresses_str . ") Agent $agent_id."
- );
+ # Autoconfigure agent
+ if (defined($self->{'autoconfiguration_enabled'}) && $self->{'autoconfiguration_enabled'} == 1) {
+ my $agent_data = PandoraFMS::DB::get_db_single_row($self->{'dbh'}, 'SELECT * FROM tagente WHERE id_agente = ?', $agent_id);
+ # Update agent configuration once, after create agent.
+ enterprise_hook('autoconfigure_agent', [$self->{'pa_config'}, $host_name, $agent_id, $agent_data, $self->{'dbh'}, 1]);
+ }
+
+ if (defined($self->{'main_event_id'})) {
+ my $addresses_str = join(',', safe_output($self->get_addresses($device)));
+ pandora_extended_event(
+ $self->{'pa_config'}, $self->{'dbh'}, $self->{'main_event_id'},
+ "[Discovery] New " . safe_output($self->get_device_type($device)) . " found " . $host_name . " (" . $addresses_str . ") Agent $agent_id."
+ );
- }
-
- $agent_learning = 1;
+ }
+
+ $agent_learning = 1;
- # Create network profile modules for the agent
- $self->create_network_profile_modules($agent_id, $device);
- }
- else {
- $agent_id = $agent->{'id_agente'};
- $agent_learning = $agent->{'modo'};
- }
+ # Create network profile modules for the agent
+ $self->create_network_profile_modules($agent_id, $device);
+ }
+ else {
+ $agent_id = $agent->{'id_agente'};
+ $agent_learning = $agent->{'modo'};
+ }
- # Do not create any modules if the agent is not in learning mode.
- return unless ($agent_learning == 1);
+ # Do not create any modules if the agent is not in learning mode.
+ return unless ($agent_learning == 1);
- # Add found IP addresses to the agent.
- foreach my $ip_addr ($self->get_addresses($device)) {
- my $addr_id = get_addr_id($self->{'dbh'}, $ip_addr);
- $addr_id = add_address($self->{'dbh'}, $ip_addr) unless ($addr_id > 0);
- next unless ($addr_id > 0);
+ # Add found IP addresses to the agent.
+ foreach my $ip_addr ($self->get_addresses($device)) {
+ my $addr_id = get_addr_id($self->{'dbh'}, $ip_addr);
+ $addr_id = add_address($self->{'dbh'}, $ip_addr) unless ($addr_id > 0);
+ next unless ($addr_id > 0);
- # Assign the new address to the agent
- my $agent_addr_id = get_agent_addr_id($self->{'dbh'}, $addr_id, $agent_id);
- if ($agent_addr_id <= 0) {
- db_do($self->{'dbh'}, 'INSERT INTO taddress_agent (`id_a`, `id_agent`)
- VALUES (?, ?)', $addr_id, $agent_id);
- }
- }
+ # Assign the new address to the agent
+ my $agent_addr_id = get_agent_addr_id($self->{'dbh'}, $addr_id, $agent_id);
+ if ($agent_addr_id <= 0) {
+ db_do($self->{'dbh'}, 'INSERT INTO taddress_agent (`id_a`, `id_agent`)
+ VALUES (?, ?)', $addr_id, $agent_id);
+ }
+ }
- # Create a ping module.
- my $module_id = get_agent_module_id($self->{'dbh'}, "ping", $agent_id);
- if ($module_id <= 0) {
- my %module = ('id_tipo_modulo' => 6,
- 'id_modulo' => 2,
- 'nombre' => "ping",
- 'descripcion' => '',
- 'id_agente' => $agent_id,
- 'ip_target' => $device);
- pandora_create_module_from_hash ($self->{'pa_config'}, \%module, $self->{'dbh'});
- }
+ # Create a ping module.
+ my $module_id = get_agent_module_id($self->{'dbh'}, "ping", $agent_id);
+ if ($module_id <= 0) {
+ my %module = ('id_tipo_modulo' => 6,
+ 'id_modulo' => 2,
+ 'nombre' => "ping",
+ 'descripcion' => '',
+ 'id_agente' => $agent_id,
+ 'ip_target' => $device);
+ pandora_create_module_from_hash ($self->{'pa_config'}, \%module, $self->{'dbh'});
+ }
- # Add interfaces to the agent if it responds to SNMP.
- return $agent_id unless ($self->is_snmp_discovered($device));
- my $community = $self->get_community($device);
+ # Add interfaces to the agent if it responds to SNMP.
+ return $agent_id unless ($self->is_snmp_discovered($device));
+ my $community = $self->get_community($device);
- my @output = $self->snmp_get_value_array($device, $PandoraFMS::Recon::Base::IFINDEX);
- foreach my $if_index (@output) {
- next unless ($if_index =~ /^[0-9]+$/);
+ my @output = $self->snmp_get_value_array($device, $PandoraFMS::Recon::Base::IFINDEX);
+ foreach my $if_index (@output) {
+ next unless ($if_index =~ /^[0-9]+$/);
- # Check the status of the interface.
- if ($self->{'all_ifaces'} == 0) {
- my $if_status = $self->snmp_get_value($device, "$PandoraFMS::Recon::Base::IFOPERSTATUS.$if_index");
- next unless $if_status == 1;
- }
+ # Check the status of the interface.
+ if ($self->{'all_ifaces'} == 0) {
+ my $if_status = $self->snmp_get_value($device, "$PandoraFMS::Recon::Base::IFOPERSTATUS.$if_index");
+ next unless $if_status == 1;
+ }
- # Fill the module description with the IP and MAC addresses.
- my $mac = $self->get_if_mac($device, $if_index);
- my $ip = $self->get_if_ip($device, $if_index);
- my $if_desc = ($mac ne '' ? "MAC $mac " : '') . ($ip ne '' ? "IP $ip" : '');
+ # Fill the module description with the IP and MAC addresses.
+ my $mac = $self->get_if_mac($device, $if_index);
+ my $ip = $self->get_if_ip($device, $if_index);
+ my $if_desc = ($mac ne '' ? "MAC $mac " : '') . ($ip ne '' ? "IP $ip" : '');
- # Get the name of the network interface.
- my $if_name = $self->snmp_get_value($device, "$PandoraFMS::Recon::Base::IFNAME.$if_index");
- $if_name = "if$if_index" unless defined ($if_name);
- $if_name =~ s/"//g;
+ # Get the name of the network interface.
+ my $if_name = $self->snmp_get_value($device, "$PandoraFMS::Recon::Base::IFNAME.$if_index");
+ $if_name = "if$if_index" unless defined ($if_name);
+ $if_name =~ s/"//g;
- # Check whether the module already exists.
- my $module_id = get_agent_module_id($self->{'dbh'}, "${if_name}_ifOperStatus", $agent_id);
- next if ($module_id > 0 && !$agent_learning);
-
- # Encode problematic characters.
- $if_name = safe_input($if_name);
- $if_desc = safe_input($if_desc);
+ # Check whether the module already exists.
+ my $module_id = get_agent_module_id($self->{'dbh'}, "${if_name}_ifOperStatus", $agent_id);
+ next if ($module_id > 0 && !$agent_learning);
+
+ # Encode problematic characters.
+ $if_name = safe_input($if_name);
+ $if_desc = safe_input($if_desc);
- # Interface status module.
- $module_id = get_agent_module_id($self->{'dbh'}, "${if_name}_ifOperStatus", $agent_id);
- if ($module_id <= 0) {
- my %module = ('id_tipo_modulo' => 18,
- 'id_modulo' => 2,
- 'nombre' => "${if_name}_ifOperStatus",
- 'descripcion' => $if_desc,
- 'id_agente' => $agent_id,
- 'ip_target' => $device,
- 'tcp_send' => $self->{'snmp_version'},
- 'custom_string_1' => $self->{'snmp_privacy_method'},
- 'custom_string_2' => $self->{'snmp_privacy_pass'},
- 'custom_string_3' => $self->{'snmp_security_level'},
- 'plugin_parameter' => $self->{'snmp_auth_method'},
- 'plugin_user' => $self->{'snmp_auth_user'},
- 'plugin_pass' => $self->{'snmp_auth_pass'},
- 'snmp_community' => $community,
- 'snmp_oid' => "$PandoraFMS::Recon::Base::IFOPERSTATUS.$if_index"
- );
- pandora_create_module_from_hash ($self->{'pa_config'}, \%module, $self->{'dbh'});
- } else {
- my %module = (
- 'descripcion' => $if_desc,
- 'ip_target' => $device,
- 'snmp_community' => $community,
- 'tcp_send' => $self->{'snmp_version'},
- 'custom_string_1' => $self->{'snmp_privacy_method'},
- 'custom_string_2' => $self->{'snmp_privacy_pass'},
- 'custom_string_3' => $self->{'snmp_security_level'},
- 'plugin_parameter' => $self->{'snmp_auth_method'},
- 'plugin_user' => $self->{'snmp_auth_user'},
- 'plugin_pass' => $self->{'snmp_auth_pass'},
- 'tcp_send' => $self->{'snmp_version'},
- );
- pandora_update_module_from_hash ($self->{'pa_config'}, \%module, 'id_agente_modulo', $module_id, $self->{'dbh'});
- }
+ # Interface status module.
+ $module_id = get_agent_module_id($self->{'dbh'}, "${if_name}_ifOperStatus", $agent_id);
+ if ($module_id <= 0) {
+ my %module = ('id_tipo_modulo' => 18,
+ 'id_modulo' => 2,
+ 'nombre' => "${if_name}_ifOperStatus",
+ 'descripcion' => $if_desc,
+ 'id_agente' => $agent_id,
+ 'ip_target' => $device,
+ 'tcp_send' => $self->{'snmp_version'},
+ 'custom_string_1' => $self->{'snmp_privacy_method'},
+ 'custom_string_2' => $self->{'snmp_privacy_pass'},
+ 'custom_string_3' => $self->{'snmp_security_level'},
+ 'plugin_parameter' => $self->{'snmp_auth_method'},
+ 'plugin_user' => $self->{'snmp_auth_user'},
+ 'plugin_pass' => $self->{'snmp_auth_pass'},
+ 'snmp_community' => $community,
+ 'snmp_oid' => "$PandoraFMS::Recon::Base::IFOPERSTATUS.$if_index"
+ );
+ pandora_create_module_from_hash ($self->{'pa_config'}, \%module, $self->{'dbh'});
+ } else {
+ my %module = (
+ 'descripcion' => $if_desc,
+ 'ip_target' => $device,
+ 'snmp_community' => $community,
+ 'tcp_send' => $self->{'snmp_version'},
+ 'custom_string_1' => $self->{'snmp_privacy_method'},
+ 'custom_string_2' => $self->{'snmp_privacy_pass'},
+ 'custom_string_3' => $self->{'snmp_security_level'},
+ 'plugin_parameter' => $self->{'snmp_auth_method'},
+ 'plugin_user' => $self->{'snmp_auth_user'},
+ 'plugin_pass' => $self->{'snmp_auth_pass'},
+ 'tcp_send' => $self->{'snmp_version'},
+ );
+ pandora_update_module_from_hash ($self->{'pa_config'}, \%module, 'id_agente_modulo', $module_id, $self->{'dbh'});
+ }
- # Incoming traffic module.
- my $if_hc_in_octets = $self->snmp_get_value($device, "$PandoraFMS::Recon::Base::IFHCINOCTECTS.$if_index");
- if (defined($if_hc_in_octets)) {
- $module_id = get_agent_module_id($self->{'dbh'}, "${if_name}_ifHCInOctets", $agent_id);
- if ($module_id <= 0) {
- my %module = ('id_tipo_modulo' => 16,
- 'id_modulo' => 2,
- 'nombre' => "${if_name}_ifHCInOctets",
- 'descripcion' => 'The total number of octets received on the interface, including framing characters. This object is a 64-bit version of ifInOctets.',
- 'id_agente' => $agent_id,
- 'ip_target' => $device,
- 'tcp_send' => $self->{'snmp_version'},
- 'custom_string_1' => $self->{'snmp_privacy_method'},
- 'custom_string_2' => $self->{'snmp_privacy_pass'},
- 'custom_string_3' => $self->{'snmp_security_level'},
- 'plugin_parameter' => $self->{'snmp_auth_method'},
- 'plugin_user' => $self->{'snmp_auth_user'},
- 'plugin_pass' => $self->{'snmp_auth_pass'},
- 'snmp_community' => $community,
- 'snmp_oid' => "$PandoraFMS::Recon::Base::IFHCINOCTECTS.$if_index");
- pandora_create_module_from_hash ($self->{'pa_config'}, \%module, $self->{'dbh'});
- } else {
- my %module = (
- 'ip_target' => $device,
- 'snmp_community' => $community,
- 'tcp_send' => $self->{'snmp_version'},
- 'custom_string_1' => $self->{'snmp_privacy_method'},
- 'custom_string_2' => $self->{'snmp_privacy_pass'},
- 'custom_string_3' => $self->{'snmp_security_level'},
- 'plugin_parameter' => $self->{'snmp_auth_method'},
- 'plugin_user' => $self->{'snmp_auth_user'},
- 'plugin_pass' => $self->{'snmp_auth_pass'},
- );
- pandora_update_module_from_hash ($self->{'pa_config'}, \%module, 'id_agente_modulo', $module_id, $self->{'dbh'});
- }
- }
- # ifInOctets
- elsif (defined($self->snmp_get_value($device, "$PandoraFMS::Recon::Base::IFINOCTECTS.$if_index"))) {
- $module_id = get_agent_module_id($self->{'dbh'}, "${if_name}_ifInOctets", $agent_id);
- if ($module_id <= 0) {
- my %module = ('id_tipo_modulo' => 16,
- 'id_modulo' => 2,
- 'nombre' => "${if_name}_ifInOctets",
- 'descripcion' => 'The total number of octets received on the interface, including framing characters.',
- 'id_agente' => $agent_id,
- 'ip_target' => $device,
- 'tcp_send' => $self->{'snmp_version'},
- 'custom_string_1' => $self->{'snmp_privacy_method'},
- 'custom_string_2' => $self->{'snmp_privacy_pass'},
- 'custom_string_3' => $self->{'snmp_security_level'},
- 'plugin_parameter' => $self->{'snmp_auth_method'},
- 'plugin_user' => $self->{'snmp_auth_user'},
- 'plugin_pass' => $self->{'snmp_auth_pass'},
- 'snmp_community' => $community,
- 'snmp_oid' => "$PandoraFMS::Recon::Base::IFINOCTECTS.$if_index");
- pandora_create_module_from_hash ($self->{'pa_config'}, \%module, $self->{'dbh'});
- } else {
- my %module = (
- 'ip_target' => $device,
- 'snmp_community' => $community,
- 'tcp_send' => $self->{'snmp_version'},
- 'custom_string_1' => $self->{'snmp_privacy_method'},
- 'custom_string_2' => $self->{'snmp_privacy_pass'},
- 'custom_string_3' => $self->{'snmp_security_level'},
- 'plugin_parameter' => $self->{'snmp_auth_method'},
- 'plugin_user' => $self->{'snmp_auth_user'},
- 'plugin_pass' => $self->{'snmp_auth_pass'},
- );
- pandora_update_module_from_hash ($self->{'pa_config'}, \%module, 'id_agente_modulo', $module_id, $self->{'dbh'});
- }
- }
+ # Incoming traffic module.
+ my $if_hc_in_octets = $self->snmp_get_value($device, "$PandoraFMS::Recon::Base::IFHCINOCTECTS.$if_index");
+ if (defined($if_hc_in_octets)) {
+ $module_id = get_agent_module_id($self->{'dbh'}, "${if_name}_ifHCInOctets", $agent_id);
+ if ($module_id <= 0) {
+ my %module = ('id_tipo_modulo' => 16,
+ 'id_modulo' => 2,
+ 'nombre' => "${if_name}_ifHCInOctets",
+ 'descripcion' => 'The total number of octets received on the interface, including framing characters. This object is a 64-bit version of ifInOctets.',
+ 'id_agente' => $agent_id,
+ 'ip_target' => $device,
+ 'tcp_send' => $self->{'snmp_version'},
+ 'custom_string_1' => $self->{'snmp_privacy_method'},
+ 'custom_string_2' => $self->{'snmp_privacy_pass'},
+ 'custom_string_3' => $self->{'snmp_security_level'},
+ 'plugin_parameter' => $self->{'snmp_auth_method'},
+ 'plugin_user' => $self->{'snmp_auth_user'},
+ 'plugin_pass' => $self->{'snmp_auth_pass'},
+ 'snmp_community' => $community,
+ 'snmp_oid' => "$PandoraFMS::Recon::Base::IFHCINOCTECTS.$if_index");
+ pandora_create_module_from_hash ($self->{'pa_config'}, \%module, $self->{'dbh'});
+ } else {
+ my %module = (
+ 'ip_target' => $device,
+ 'snmp_community' => $community,
+ 'tcp_send' => $self->{'snmp_version'},
+ 'custom_string_1' => $self->{'snmp_privacy_method'},
+ 'custom_string_2' => $self->{'snmp_privacy_pass'},
+ 'custom_string_3' => $self->{'snmp_security_level'},
+ 'plugin_parameter' => $self->{'snmp_auth_method'},
+ 'plugin_user' => $self->{'snmp_auth_user'},
+ 'plugin_pass' => $self->{'snmp_auth_pass'},
+ );
+ pandora_update_module_from_hash ($self->{'pa_config'}, \%module, 'id_agente_modulo', $module_id, $self->{'dbh'});
+ }
+ }
+ # ifInOctets
+ elsif (defined($self->snmp_get_value($device, "$PandoraFMS::Recon::Base::IFINOCTECTS.$if_index"))) {
+ $module_id = get_agent_module_id($self->{'dbh'}, "${if_name}_ifInOctets", $agent_id);
+ if ($module_id <= 0) {
+ my %module = ('id_tipo_modulo' => 16,
+ 'id_modulo' => 2,
+ 'nombre' => "${if_name}_ifInOctets",
+ 'descripcion' => 'The total number of octets received on the interface, including framing characters.',
+ 'id_agente' => $agent_id,
+ 'ip_target' => $device,
+ 'tcp_send' => $self->{'snmp_version'},
+ 'custom_string_1' => $self->{'snmp_privacy_method'},
+ 'custom_string_2' => $self->{'snmp_privacy_pass'},
+ 'custom_string_3' => $self->{'snmp_security_level'},
+ 'plugin_parameter' => $self->{'snmp_auth_method'},
+ 'plugin_user' => $self->{'snmp_auth_user'},
+ 'plugin_pass' => $self->{'snmp_auth_pass'},
+ 'snmp_community' => $community,
+ 'snmp_oid' => "$PandoraFMS::Recon::Base::IFINOCTECTS.$if_index");
+ pandora_create_module_from_hash ($self->{'pa_config'}, \%module, $self->{'dbh'});
+ } else {
+ my %module = (
+ 'ip_target' => $device,
+ 'snmp_community' => $community,
+ 'tcp_send' => $self->{'snmp_version'},
+ 'custom_string_1' => $self->{'snmp_privacy_method'},
+ 'custom_string_2' => $self->{'snmp_privacy_pass'},
+ 'custom_string_3' => $self->{'snmp_security_level'},
+ 'plugin_parameter' => $self->{'snmp_auth_method'},
+ 'plugin_user' => $self->{'snmp_auth_user'},
+ 'plugin_pass' => $self->{'snmp_auth_pass'},
+ );
+ pandora_update_module_from_hash ($self->{'pa_config'}, \%module, 'id_agente_modulo', $module_id, $self->{'dbh'});
+ }
+ }
- # Outgoing traffic module.
- my $if_hc_out_octets = $self->snmp_get_value($device, "$PandoraFMS::Recon::Base::IFHCOUTOCTECTS.$if_index");
- if (defined($if_hc_out_octets)) {
- $module_id = get_agent_module_id($self->{'dbh'}, "${if_name}_ifHCOutOctets", $agent_id);
- if ($module_id <= 0) {
- my %module = ('id_tipo_modulo' => 16,
- 'id_modulo' => 2,
- 'nombre' => "${if_name}_ifHCOutOctets",
- 'descripcion' => 'The total number of octets received on the interface, including framing characters. This object is a 64-bit version of ifOutOctets.',
- 'id_agente' => $agent_id,
- 'ip_target' => $device,
- 'tcp_send' => $self->{'snmp_version'},
- 'custom_string_1' => $self->{'snmp_privacy_method'},
- 'custom_string_2' => $self->{'snmp_privacy_pass'},
- 'custom_string_3' => $self->{'snmp_security_level'},
- 'plugin_parameter' => $self->{'snmp_auth_method'},
- 'plugin_user' => $self->{'snmp_auth_user'},
- 'plugin_pass' => $self->{'snmp_auth_pass'},
- 'snmp_community' => $community,
- 'snmp_oid' => "$PandoraFMS::Recon::Base::IFHCOUTOCTECTS.$if_index");
- pandora_create_module_from_hash ($self->{'pa_config'}, \%module, $self->{'dbh'});
- } else {
- my %module = (
- 'ip_target' => $device,
- 'snmp_community' => $community,
- 'tcp_send' => $self->{'snmp_version'},
- 'tcp_send' => $self->{'snmp_version'},
- 'custom_string_1' => $self->{'snmp_privacy_method'},
- 'custom_string_2' => $self->{'snmp_privacy_pass'},
- 'custom_string_3' => $self->{'snmp_security_level'},
- 'plugin_parameter' => $self->{'snmp_auth_method'},
- 'plugin_user' => $self->{'snmp_auth_user'},
- 'plugin_pass' => $self->{'snmp_auth_pass'},
- );
- pandora_update_module_from_hash ($self->{'pa_config'}, \%module, 'id_agente_modulo', $module_id, $self->{'dbh'});
- }
- }
- # ifOutOctets
- elsif (defined($self->snmp_get_value($device, "$PandoraFMS::Recon::Base::IFOUTOCTECTS.$if_index"))) {
- $module_id = get_agent_module_id($self->{'dbh'}, "${if_name}_ifOutOctets", $agent_id);
- if ($module_id <= 0) {
- my %module = ('id_tipo_modulo' => 16,
- 'id_modulo' => 2,
- 'nombre' => "${if_name}_ifOutOctets",
- 'descripcion' => 'The total number of octets received on the interface, including framing characters.',
- 'id_agente' => $agent_id,
- 'ip_target' => $device,
- 'tcp_send' => $self->{'snmp_version'},
- 'custom_string_1' => $self->{'snmp_privacy_method'},
- 'custom_string_2' => $self->{'snmp_privacy_pass'},
- 'custom_string_3' => $self->{'snmp_security_level'},
- 'plugin_parameter' => $self->{'snmp_auth_method'},
- 'plugin_user' => $self->{'snmp_auth_user'},
- 'plugin_pass' => $self->{'snmp_auth_pass'},
- 'snmp_community' => $community,
- 'snmp_oid' => "$PandoraFMS::Recon::Base::IFOUTOCTECTS.$if_index");
- pandora_create_module_from_hash ($self->{'pa_config'}, \%module, $self->{'dbh'});
- } else {
- my %module = (
- 'ip_target' => $device,
- 'snmp_community' => $community,
- 'tcp_send' => $self->{'snmp_version'},
- 'tcp_send' => $self->{'snmp_version'},
- 'custom_string_1' => $self->{'snmp_privacy_method'},
- 'custom_string_2' => $self->{'snmp_privacy_pass'},
- 'custom_string_3' => $self->{'snmp_security_level'},
- 'plugin_parameter' => $self->{'snmp_auth_method'},
- 'plugin_user' => $self->{'snmp_auth_user'},
- 'plugin_pass' => $self->{'snmp_auth_pass'},
- );
- pandora_update_module_from_hash ($self->{'pa_config'}, \%module, 'id_agente_modulo', $module_id, $self->{'dbh'});
- }
- }
- }
+ # Outgoing traffic module.
+ my $if_hc_out_octets = $self->snmp_get_value($device, "$PandoraFMS::Recon::Base::IFHCOUTOCTECTS.$if_index");
+ if (defined($if_hc_out_octets)) {
+ $module_id = get_agent_module_id($self->{'dbh'}, "${if_name}_ifHCOutOctets", $agent_id);
+ if ($module_id <= 0) {
+ my %module = ('id_tipo_modulo' => 16,
+ 'id_modulo' => 2,
+ 'nombre' => "${if_name}_ifHCOutOctets",
+ 'descripcion' => 'The total number of octets received on the interface, including framing characters. This object is a 64-bit version of ifOutOctets.',
+ 'id_agente' => $agent_id,
+ 'ip_target' => $device,
+ 'tcp_send' => $self->{'snmp_version'},
+ 'custom_string_1' => $self->{'snmp_privacy_method'},
+ 'custom_string_2' => $self->{'snmp_privacy_pass'},
+ 'custom_string_3' => $self->{'snmp_security_level'},
+ 'plugin_parameter' => $self->{'snmp_auth_method'},
+ 'plugin_user' => $self->{'snmp_auth_user'},
+ 'plugin_pass' => $self->{'snmp_auth_pass'},
+ 'snmp_community' => $community,
+ 'snmp_oid' => "$PandoraFMS::Recon::Base::IFHCOUTOCTECTS.$if_index");
+ pandora_create_module_from_hash ($self->{'pa_config'}, \%module, $self->{'dbh'});
+ } else {
+ my %module = (
+ 'ip_target' => $device,
+ 'snmp_community' => $community,
+ 'tcp_send' => $self->{'snmp_version'},
+ 'tcp_send' => $self->{'snmp_version'},
+ 'custom_string_1' => $self->{'snmp_privacy_method'},
+ 'custom_string_2' => $self->{'snmp_privacy_pass'},
+ 'custom_string_3' => $self->{'snmp_security_level'},
+ 'plugin_parameter' => $self->{'snmp_auth_method'},
+ 'plugin_user' => $self->{'snmp_auth_user'},
+ 'plugin_pass' => $self->{'snmp_auth_pass'},
+ );
+ pandora_update_module_from_hash ($self->{'pa_config'}, \%module, 'id_agente_modulo', $module_id, $self->{'dbh'});
+ }
+ }
+ # ifOutOctets
+ elsif (defined($self->snmp_get_value($device, "$PandoraFMS::Recon::Base::IFOUTOCTECTS.$if_index"))) {
+ $module_id = get_agent_module_id($self->{'dbh'}, "${if_name}_ifOutOctets", $agent_id);
+ if ($module_id <= 0) {
+ my %module = ('id_tipo_modulo' => 16,
+ 'id_modulo' => 2,
+ 'nombre' => "${if_name}_ifOutOctets",
+ 'descripcion' => 'The total number of octets received on the interface, including framing characters.',
+ 'id_agente' => $agent_id,
+ 'ip_target' => $device,
+ 'tcp_send' => $self->{'snmp_version'},
+ 'custom_string_1' => $self->{'snmp_privacy_method'},
+ 'custom_string_2' => $self->{'snmp_privacy_pass'},
+ 'custom_string_3' => $self->{'snmp_security_level'},
+ 'plugin_parameter' => $self->{'snmp_auth_method'},
+ 'plugin_user' => $self->{'snmp_auth_user'},
+ 'plugin_pass' => $self->{'snmp_auth_pass'},
+ 'snmp_community' => $community,
+ 'snmp_oid' => "$PandoraFMS::Recon::Base::IFOUTOCTECTS.$if_index");
+ pandora_create_module_from_hash ($self->{'pa_config'}, \%module, $self->{'dbh'});
+ } else {
+ my %module = (
+ 'ip_target' => $device,
+ 'snmp_community' => $community,
+ 'tcp_send' => $self->{'snmp_version'},
+ 'tcp_send' => $self->{'snmp_version'},
+ 'custom_string_1' => $self->{'snmp_privacy_method'},
+ 'custom_string_2' => $self->{'snmp_privacy_pass'},
+ 'custom_string_3' => $self->{'snmp_security_level'},
+ 'plugin_parameter' => $self->{'snmp_auth_method'},
+ 'plugin_user' => $self->{'snmp_auth_user'},
+ 'plugin_pass' => $self->{'snmp_auth_pass'},
+ );
+ pandora_update_module_from_hash ($self->{'pa_config'}, \%module, 'id_agente_modulo', $module_id, $self->{'dbh'});
+ }
+ }
+ }
- return $agent_id;
+ return $agent_id;
}
##########################################################################
# Delete already existing connections.
##########################################################################
sub PandoraFMS::Recon::Base::delete_connections($) {
- my ($self) = @_;
+ my ($self) = @_;
- $self->call('message', "Deleting connections...", 10);
- db_do($self->{'dbh'}, 'DELETE FROM tmodule_relationship WHERE id_rt=?', $self->{'task_id'});
+ $self->call('message', "Deleting connections...", 10);
+ db_do($self->{'dbh'}, 'DELETE FROM tmodule_relationship WHERE id_rt=?', $self->{'task_id'});
}
#######################################################################
# Print log messages.
#######################################################################
sub PandoraFMS::Recon::Base::message($$$) {
- my ($self, $message, $verbosity) = @_;
-
- logger($self->{'pa_config'}, "[Recon task " . $self->{'task_id'} . "] $message", $verbosity);
+ my ($self, $message, $verbosity) = @_;
+
+ logger($self->{'pa_config'}, "[Recon task " . $self->{'task_id'} . "] $message", $verbosity);
}
##########################################################################
# Connect the given hosts to its parent.
##########################################################################
sub PandoraFMS::Recon::Base::set_parent($$$) {
- my ($self, $host, $parent) = @_;
+ my ($self, $host, $parent) = @_;
- return unless ($self->{'parent_detection'} == 1);
+ return unless ($self->{'parent_detection'} == 1);
- # Get the agent for the host.
- my $agent = get_agent_from_addr($self->{'dbh'}, $host);
- if (!defined($agent)) {
- $agent = get_agent_from_name($self->{'dbh'}, $host);
- }
- return unless defined($agent);
+ # Get the agent for the host.
+ my $agent = get_agent_from_addr($self->{'dbh'}, $host);
+ if (!defined($agent)) {
+ $agent = get_agent_from_name($self->{'dbh'}, $host);
+ }
+ return unless defined($agent);
- # Check if the parent agent exists.
- my $agent_parent = get_agent_from_addr($self->{'dbh'}, $parent);
- if (!defined($agent_parent)) {
- $agent_parent = get_agent_from_name($self->{'dbh'}, $parent);
- }
- return unless (defined ($agent_parent));
+ # Check if the parent agent exists.
+ my $agent_parent = get_agent_from_addr($self->{'dbh'}, $parent);
+ if (!defined($agent_parent)) {
+ $agent_parent = get_agent_from_name($self->{'dbh'}, $parent);
+ }
+ return unless (defined ($agent_parent));
- # Is the agent in learning mode?
- return unless ($agent_parent->{'modo'} == 1);
+ # Is the agent in learning mode?
+ return unless ($agent_parent->{'modo'} == 1);
- # Connect the host to its parent.
- db_do($self->{'dbh'}, 'UPDATE tagente SET id_parent=? WHERE id_agente=?', $agent_parent->{'id_agente'}, $agent->{'id_agente'});
+ # Connect the host to its parent.
+ db_do($self->{'dbh'}, 'UPDATE tagente SET id_parent=? WHERE id_agente=?', $agent_parent->{'id_agente'}, $agent->{'id_agente'});
}
##########################################################################
# Create a WMI module for the given agent.
##########################################################################
sub PandoraFMS::Recon::Base::wmi_module {
- my ($self, $agent_id, $target, $wmi_query, $wmi_auth, $column,
+ my ($self, $agent_id, $target, $wmi_query, $wmi_auth, $column,
$module_name, $module_description, $module_type, $unit) = @_;
- # Check whether the module already exists.
- my $module_id = get_agent_module_id($self->{'dbh'}, $module_name, $agent_id);
- return if ($module_id > 0);
+ # Check whether the module already exists.
+ my $module_id = get_agent_module_id($self->{'dbh'}, $module_name, $agent_id);
+ return if ($module_id > 0);
- my ($user, $pass) = ($wmi_auth ne '') ? split('%', $wmi_auth) : (undef, undef);
- my %module = (
- 'descripcion' => safe_input($module_description),
- 'id_agente' => $agent_id,
- 'id_modulo' => 6,
- 'id_tipo_modulo' => get_module_id($self->{'dbh'}, $module_type),
- 'ip_target' => $target,
- 'nombre' => safe_input($module_name),
- 'plugin_pass' => defined($pass) ? $pass : '',
- 'plugin_user' => defined($user) ? $user : '',
- 'snmp_oid' => $wmi_query,
- 'tcp_port' => $column,
- 'unit' => defined($unit) ? $unit : ''
- );
-
- pandora_create_module_from_hash($self->{'pa_config'}, \%module, $self->{'dbh'});
+ my ($user, $pass) = ($wmi_auth ne '') ? split('%', $wmi_auth) : (undef, undef);
+ my %module = (
+ 'descripcion' => safe_input($module_description),
+ 'id_agente' => $agent_id,
+ 'id_modulo' => 6,
+ 'id_tipo_modulo' => get_module_id($self->{'dbh'}, $module_type),
+ 'ip_target' => $target,
+ 'nombre' => safe_input($module_name),
+ 'plugin_pass' => defined($pass) ? $pass : '',
+ 'plugin_user' => defined($user) ? $user : '',
+ 'snmp_oid' => $wmi_query,
+ 'tcp_port' => $column,
+ 'unit' => defined($unit) ? $unit : ''
+ );
+
+ pandora_create_module_from_hash($self->{'pa_config'}, \%module, $self->{'dbh'});
}
##########################################################################
# Update recon task status.
##########################################################################
sub PandoraFMS::Recon::Base::update_progress ($$) {
- my ($self, $progress) = @_;
+ my ($self, $progress) = @_;
- my $stats = {};
- if (defined($self->{'summary'}) && $self->{'summary'} ne '') {
- $stats->{'summary'} = $self->{'summary'};
- }
- $stats->{'step'} = $self->{'step'};
- $stats->{'c_network_name'} = $self->{'c_network_name'};
- $stats->{'c_network_percent'} = $self->{'c_network_percent'};
+ my $stats = {};
+ if (defined($self->{'summary'}) && $self->{'summary'} ne '') {
+ $stats->{'summary'} = $self->{'summary'};
+ }
+ $stats->{'step'} = $self->{'step'};
+ $stats->{'c_network_name'} = $self->{'c_network_name'};
+ $stats->{'c_network_percent'} = $self->{'c_network_percent'};
- # Store progress, last contact and overall status.
- db_do ($self->{'dbh'}, 'UPDATE trecon_task SET utimestamp = ?, status = ?, summary = ? WHERE id_rt = ?',
- time (), $progress, encode_json($stats), $self->{'task_id'});
+ # Store progress, last contact and overall status.
+ db_do ($self->{'dbh'}, 'UPDATE trecon_task SET utimestamp = ?, status = ?, summary = ? WHERE id_rt = ?',
+ time (), $progress, encode_json($stats), $self->{'task_id'});
}
1;
diff --git a/pandora_server/lib/PandoraFMS/PluginTools.pm b/pandora_server/lib/PandoraFMS/PluginTools.pm
index 057dbc7bef..0b5956a50d 100644
--- a/pandora_server/lib/PandoraFMS/PluginTools.pm
+++ b/pandora_server/lib/PandoraFMS/PluginTools.pm
@@ -31,8 +31,8 @@ use base 'Exporter';
our @ISA = qw(Exporter);
# version: Defines actual version of Pandora Server for this module only
-my $pandora_version = "7.0NG.733";
-my $pandora_build = "190417";
+my $pandora_version = "7.0NG.734";
+my $pandora_build = "190503";
our $VERSION = $pandora_version." ".$pandora_build;
our %EXPORT_TAGS = ( 'all' => [ qw() ] );
diff --git a/pandora_server/lib/PandoraFMS/Recon/Base.pm b/pandora_server/lib/PandoraFMS/Recon/Base.pm
index 393734bc85..23532d843b 100644
--- a/pandora_server/lib/PandoraFMS/Recon/Base.pm
+++ b/pandora_server/lib/PandoraFMS/Recon/Base.pm
@@ -20,7 +20,18 @@ use constant {
STEP_SCANNING => 1,
STEP_AFT => 2,
STEP_TRACEROUTE => 3,
- STEP_GATEWAY => 4
+ STEP_GATEWAY => 4,
+ STEP_STATISTICS => 1,
+ STEP_DATABASE_SCAN => 2,
+ STEP_CUSTOM_QUERIES => 3,
+ DISCOVERY_HOSTDEVICES => 0,
+ DISCOVERY_HOSTDEVICES_CUSTOM => 1,
+ DISCOVERY_CLOUD_AWS => 2,
+ DISCOVERY_APP_VMWARE => 3,
+ DISCOVERY_APP_MYSQL => 4,
+ DISCOVERY_APP_ORACLE => 5,
+ DISCOVERY_CLOUD_AWS_EC2 => 6,
+ DISCOVERY_CLOUD_AWS_RDS => 7
};
# /dev/null
@@ -194,6 +205,8 @@ sub new {
# Perform some sanity checks.
die("No subnet was specified.") unless defined($self->{'subnets'});
+ $self = bless($self, $class);
+
# Check SNMP params id SNMP is enabled
if ($self->{'snmp_enabled'}) {
@@ -240,7 +253,7 @@ sub new {
# Disable SNMP scans if no community was given.
if (ref($self->{'communities'}) ne "ARRAY" || scalar(@{$self->{'communities'}}) == 0) {
$self->{'snmp_enabled'} = 0;
- $self->call('message', "There is not any SNMP community configured.", 5);
+ $self->call('message', "There is no SNMP community configured.", 5);
}
}
@@ -270,7 +283,7 @@ sub new {
$self->{'snmp_security_level'} = '';
}
- return bless($self, $class);
+ return $self;
}
########################################################################################
@@ -1415,6 +1428,210 @@ sub scan_subnet($) {
}
}
+
+##########################################################################
+# Perform a Cloud scan
+##########################################################################
+sub cloud_scan($) {
+ my $self = shift;
+ my ($progress, $step);
+
+ my $type = '';
+
+ if ($self->{'task_data'}->{'type'} == DISCOVERY_CLOUD_AWS_EC2
+ || $self->{'task_data'}->{'type'} == DISCOVERY_CLOUD_AWS_RDS) {
+ $type = 'Aws';
+ } else {
+ # Unrecognized task type.
+ call('message', 'Unrecognized task type', 1);
+ $self->call('update_progress', -1);
+ return;
+ }
+
+ # Initialize cloud object.
+ my $cloudObj = PandoraFMS::Recon::Util::enterprise_new(
+ 'PandoraFMS::Recon::Cloud::'.$type,
+ [
+ task_data => $self->{'task_data'},
+ aws_access_key_id => $self->{'aws_access_key_id'},
+ aws_secret_access_key => $self->{'aws_secret_access_key'},
+ cloud_util_path => $self->{'cloud_util_path'},
+ creds_file => $self->{'creds_file'},
+ parent => $self
+ ]
+
+ );
+
+ if (!$cloudObj) {
+ # Failed to initialize, check Cloud credentials or anything.
+ call('message', 'Unable to initialize PandoraFMS::Recon::Cloud::'.$type, 3);
+ } else {
+ # Let Cloud object manage scan.
+ $cloudObj->scan();
+ }
+
+ # Update progress.
+ # Done!
+ $self->{'step'} = '';
+ $self->call('update_progress', -1);
+}
+
+
+##########################################################################
+# Perform an Application scan.
+##########################################################################
+sub app_scan($) {
+ my ($self) = @_;
+ my ($progress, $step);
+
+ my $type = '';
+
+ if ($self->{'task_data'}->{'type'} == DISCOVERY_APP_MYSQL) {
+ $type = 'MySQL';
+ } elsif ($self->{'task_data'}->{'type'} == DISCOVERY_APP_ORACLE) {
+ $type = 'Oracle';
+ } else {
+ # Unrecognized task type.
+ call('message', 'Unrecognized task type', 1);
+ $self->call('update_progress', -1);
+ return;
+ }
+
+ my @targets = split /,/, $self->{'task_data'}->{'subnet'};
+
+ my $global_step = 100 / (scalar @targets);
+ my $global_percent = 0;
+ my $i = 0;
+ foreach my $target (@targets) {
+ my @data;
+ my @modules;
+
+ $self->{'step'} = STEP_DATABASE_SCAN;
+ $self->{'c_network_name'} = $target;
+ $self->{'c_network_percent'} = 0;
+
+ # Send message
+ call('message', 'Checking target ' . $target, 10);
+
+ # Force target acquirement.
+ $self->{'task_data'}->{'dbhost'} = $target;
+ $self->{'task_data'}->{'target_index'} = $i++;
+
+ # Update progress
+ $self->{'c_network_percent'} = 10;
+ $self->call('update_progress', $global_percent + (10 / (scalar @targets)));
+
+ # Connect to target.
+ my $dbObj = PandoraFMS::Recon::Util::enterprise_new(
+ 'PandoraFMS::Recon::Applications::'.$type,
+ $self->{'task_data'}
+ );
+
+ if (!$dbObj->is_connected()) {
+ call('message', 'Cannot connect to target ' . $target, 3);
+ $global_percent += $global_step;
+ $self->{'c_network_percent'} = 90;
+ # Update progress
+ $self->call('update_progress', $global_percent + (90 / (scalar @targets)));
+ $self->{'summary'}->{'not_alive'} += 1;
+ push @modules, {
+ name => $type . ' connection',
+ type => 'generic_proc',
+ data => 0,
+ description => $type . ' availability'
+ };
+
+ } else {
+ my $dbObjCfg = $dbObj->get_config();
+
+ $self->{'summary'}->{'discovered'} += 1;
+ $self->{'summary'}->{'alive'} += 1;
+
+ push @modules, {
+ name => $type . ' connection',
+ type => 'generic_proc',
+ data => 1,
+ description => $type . ' availability'
+ };
+
+ # Analyze.
+ $self->{'step'} = STEP_STATISTICS;
+ $self->{'c_network_percent'} = 30;
+ $self->call('update_progress', $global_percent + (30 / (scalar @targets)));
+ $self->{'c_network_name'} = $dbObj->get_host();
+
+ # Retrieve connection statistics.
+ # Retrieve uptime statistics
+ # Retrieve query stats
+ # Retrieve connections
+ # Retrieve innodb
+ # Retrieve cache
+ $self->{'c_network_percent'} = 50;
+ $self->call('update_progress', $global_percent + (50 / (scalar @targets)));
+ push @modules, $dbObj->get_statistics();
+
+ # Custom queries.
+ $self->{'step'} = STEP_CUSTOM_QUERIES;
+ $self->{'c_network_percent'} = 80;
+ $self->call('update_progress', $global_percent + (80 / (scalar @targets)));
+ push @modules, $dbObj->execute_custom_queries();
+
+ if (defined($dbObjCfg->{'scan_databases'})
+ && $dbObjCfg->{'scan_databases'} == 1) {
+ # Skip database scan in Oracle tasks
+ next if $self->{'type'} == DISCOVERY_APP_ORACLE;
+
+ my $__data = $dbObj->scan_databases();
+
+ if (ref($__data) eq "ARRAY") {
+ if (defined($dbObjCfg->{'agent_per_database'})
+ && $dbObjCfg->{'agent_per_database'} == 1) {
+ # Agent per database detected.
+ push @data, @{$__data};
+ } else {
+ # Merge modules into engine agent.
+ my @_modules = map {
+ map { $_ } @{$_->{'module_data'}}
+ } @{$__data};
+
+ push @modules, @_modules;
+ }
+ }
+ }
+ }
+
+ # Put engine agent at the beginning of the list.
+ my $version = $dbObj->get_version();
+ unshift @data,{
+ 'agent_data' => {
+ 'agent_name' => $dbObj->get_agent_name(),
+ 'os' => $type,
+ 'os_version' => (defined($version) ? $version : 'Discovery'),
+ 'interval' => $self->{'task_data'}->{'interval_sweep'},
+ 'id_group' => $self->{'task_data'}->{'id_group'},
+ 'address' => $dbObj->get_host(),
+ 'description' => '',
+ },
+ 'module_data' => \@modules,
+ };
+
+ $self->call('create_agents', \@data);
+
+ # Destroy item.
+ undef($dbObj);
+
+ $global_percent += $global_step;
+ $self->{'c_network_percent'} = 100;
+ $self->call('update_progress', $global_percent);
+ }
+
+ # Update progress.
+ # Done!
+ $self->{'step'} = '';
+ $self->call('update_progress', -1);
+
+}
+
##########################################################################
# Perform a network scan.
##########################################################################
@@ -1425,6 +1642,19 @@ sub scan($) {
# 1%
$self->call('update_progress', 1);
+ if (defined($self->{'task_data'})) {
+ if ($self->{'task_data'}->{'type'} == DISCOVERY_APP_MYSQL
+ || $self->{'task_data'}->{'type'} == DISCOVERY_APP_ORACLE) {
+ # Database scan.
+ return $self->app_scan();
+ }
+
+ if ($self->{'task_data'}->{'type'} == DISCOVERY_CLOUD_AWS_RDS) {
+ # Cloud scan.
+ return $self->cloud_scan();
+ }
+ }
+
# Find devices.
$self->call('message', "[1/5] Scanning the network...", 3);
$self->{'step'} = STEP_SCANNING;
@@ -1540,7 +1770,7 @@ sub snmp_get($$$) {
my %output_hash;
foreach my $vlan (@vlans) {
my $command = $self->snmp_get_command($device, $oid, $community, $vlan);
- foreach my $line (`$vlan`) {
+ foreach my $line (`$command`) {
$output_hash{$line} = 1;
}
}
diff --git a/pandora_server/lib/PandoraFMS/Recon/Util.pm b/pandora_server/lib/PandoraFMS/Recon/Util.pm
index 85d251ff1b..64cc7b28e6 100644
--- a/pandora_server/lib/PandoraFMS/Recon/Util.pm
+++ b/pandora_server/lib/PandoraFMS/Recon/Util.pm
@@ -12,16 +12,47 @@ use lib '/usr/lib/perl5';
use Socket qw/inet_aton/;
our @ISA = ("Exporter");
-our %EXPORT_TAGS = ( 'all' => [ qw( ) ] );
+our %EXPORT_TAGS = ( 'all' => [qw( )] );
our @EXPORT_OK = ( @{ $EXPORT_TAGS{'all'} } );
our @EXPORT = qw(
- ip_to_long
- mac_matches
- mac_to_dec
- parse_mac
- subnet_matches
+ enterprise_new
+ ip_to_long
+ mac_matches
+ mac_to_dec
+ parse_mac
+ subnet_matches
);
+########################################################################################
+# Return an Enterprise Recon object.
+########################################################################################
+sub enterprise_new($$) {
+ my ($class, $arguments) = @_;
+
+ my @args;
+ if (ref($arguments) eq "HASH") {
+ @args = %{$arguments};
+ }
+ if (ref($arguments) eq "ARRAY") {
+ @args = @{$arguments};
+ }
+
+ # Try to load the module
+ if ($^O eq 'MSWin32') {
+ # If the Windows service dies the service is stopped, even inside an eval ($RUN is set to 0)!
+ eval 'local $SIG{__DIE__}; require '.$class.';';
+ }else {
+ eval 'require '.$class.';';
+ }
+ if ($@) {
+ # Not loaded.
+ return undef;
+ }
+
+ return new $class(@args);
+}
+
+
########################################################################################
# Return the numeric representation of the given IP address.
########################################################################################
@@ -35,13 +66,13 @@ sub ip_to_long($) {
# Returns 1 if the two given MAC addresses are the same.
########################################################################################
sub mac_matches($$) {
- my ($mac_1, $mac_2) = @_;
+ my ($mac_1, $mac_2) = @_;
- if (parse_mac($mac_1) eq parse_mac($mac_2)) {
- return 1;
- }
+ if (parse_mac($mac_1) eq parse_mac($mac_2)) {
+ return 1;
+ }
- return 0;
+ return 0;
}
########################################################################################
@@ -53,7 +84,7 @@ sub mac_to_dec($) {
my $dec_mac = '';
my @elements = split(/:/, $mac);
foreach my $element (@elements) {
- $dec_mac .= unpack('s', pack 's', hex($element)) . '.'
+ $dec_mac .= unpack('s', pack 's', hex($element)) . '.';
}
chop($dec_mac);
@@ -64,23 +95,23 @@ sub mac_to_dec($) {
# Make sure all MAC addresses are in the same format (00 11 22 33 44 55 66).
########################################################################################
sub parse_mac($) {
- my ($mac) = @_;
+ my ($mac) = @_;
- # Remove leading and trailing whitespaces.
- $mac =~ s/(^\s+)|(\s+$)//g;
+ # Remove leading and trailing whitespaces.
+ $mac =~ s/(^\s+)|(\s+$)//g;
- # Replace whitespaces and dots with colons.
- $mac =~ s/\s+|\./:/g;
+ # Replace whitespaces and dots with colons.
+ $mac =~ s/\s+|\./:/g;
- # Convert hex digits to uppercase.
- $mac =~ s/([a-f])/\U$1/g;
+ # Convert hex digits to uppercase.
+ $mac =~ s/([a-f])/\U$1/g;
- # Add a leading 0 to single digits.
- $mac =~ s/^([0-9A-F]):/0$1:/g;
- $mac =~ s/:([0-9A-F]):/:0$1:/g;
- $mac =~ s/:([0-9A-F])$/:0$1/g;
+ # Add a leading 0 to single digits.
+ $mac =~ s/^([0-9A-F]):/0$1:/g;
+ $mac =~ s/:([0-9A-F]):/:0$1:/g;
+ $mac =~ s/:([0-9A-F])$/:0$1/g;
- return $mac;
+ return $mac;
}
########################################################################################
@@ -95,6 +126,7 @@ sub subnet_matches($$;$) {
$netaddr = $subnet;
$netmask = ip_to_long($mask);
}
+
# CIDR notation.
else {
($netaddr, $netmask) = split('/', $subnet);
diff --git a/pandora_server/lib/PandoraFMS/Tools.pm b/pandora_server/lib/PandoraFMS/Tools.pm
index a03ebb83d5..02bb9f05ea 100755
--- a/pandora_server/lib/PandoraFMS/Tools.pm
+++ b/pandora_server/lib/PandoraFMS/Tools.pm
@@ -120,6 +120,7 @@ our @EXPORT = qw(
month_have_days
translate_obj
valid_regex
+ read_file
set_file_permissions
uri_encode
check_server_threads
@@ -330,6 +331,28 @@ my @ServerThreads;
# Keep threads running.
our $THRRUN :shared = 1;
+##########################################################################
+## Reads a file and returns entire content or undef if error.
+##########################################################################
+sub read_file {
+ my $path = shift;
+
+ my $_FILE;
+ if( !open($_FILE, "<", $path) ) {
+ # failed to open, return undef
+ return undef;
+ }
+
+ # Slurp configuration file content.
+ my $content = do { local $/; <$_FILE> };
+
+ # Close file
+ close($_FILE);
+
+ return $content;
+}
+
+
###############################################################################
# Sets user:group owner for the given file
###############################################################################
diff --git a/pandora_server/pandora_server.redhat.spec b/pandora_server/pandora_server.redhat.spec
index 3aa67e3058..db17b7ef0a 100644
--- a/pandora_server/pandora_server.redhat.spec
+++ b/pandora_server/pandora_server.redhat.spec
@@ -2,8 +2,8 @@
# Pandora FMS Server
#
%define name pandorafms_server
-%define version 7.0NG.733
-%define release 190417
+%define version 7.0NG.734
+%define release 190503
Summary: Pandora FMS Server
Name: %{name}
diff --git a/pandora_server/pandora_server.spec b/pandora_server/pandora_server.spec
index ac82abc7d3..aecb3cf80c 100644
--- a/pandora_server/pandora_server.spec
+++ b/pandora_server/pandora_server.spec
@@ -2,8 +2,8 @@
# Pandora FMS Server
#
%define name pandorafms_server
-%define version 7.0NG.733
-%define release 190417
+%define version 7.0NG.734
+%define release 190503
Summary: Pandora FMS Server
Name: %{name}
diff --git a/pandora_server/pandora_server_installer b/pandora_server/pandora_server_installer
index ffd57d7ed4..10a0a45a09 100755
--- a/pandora_server/pandora_server_installer
+++ b/pandora_server/pandora_server_installer
@@ -8,8 +8,8 @@
# This code is licensed under GPL 2.0 license.
# **********************************************************************
-PI_VERSION="7.0NG.733"
-PI_BUILD="190417"
+PI_VERSION="7.0NG.734"
+PI_BUILD="190503"
MODE=$1
if [ $# -gt 1 ]; then
diff --git a/pandora_server/util/pandora_db.pl b/pandora_server/util/pandora_db.pl
index 7721c3c13b..66d39969da 100644
--- a/pandora_server/util/pandora_db.pl
+++ b/pandora_server/util/pandora_db.pl
@@ -34,7 +34,7 @@ use PandoraFMS::Config;
use PandoraFMS::DB;
# version: define current version
-my $version = "7.0NG.733 PS190417";
+my $version = "7.0NG.734 PS190503";
# Pandora server configuration
my %conf;
diff --git a/pandora_server/util/pandora_manage.pl b/pandora_server/util/pandora_manage.pl
index 1a7f1f72de..0eab6f5039 100644
--- a/pandora_server/util/pandora_manage.pl
+++ b/pandora_server/util/pandora_manage.pl
@@ -36,7 +36,7 @@ use Encode::Locale;
Encode::Locale::decode_argv;
# version: define current version
-my $version = "7.0NG.733 PS190417";
+my $version = "7.0NG.734 PS190503";
# save program name for logging
my $progname = basename($0);
@@ -155,6 +155,7 @@ sub help_screen{
help_screen_line('--update_module', '
', 'Update a module field');
help_screen_line('--get_agents_module_current_data', '', "Get the agent and current data \n\t of all the modules with a given name");
help_screen_line('--create_network_module_from_component', ' ', "Create a new network \n\t module from a network component");
+ help_screen_line('--create_network_component', " \n\t [ \n\t \n\t \n\t \n\t \n\t \n\t ]", "Create a new network component");
help_screen_line('--create_synthetic', " ,,|, \n\t [ , | ,, ]", "Create a new Synthetic module");
print "\nALERTS:\n\n" unless $param ne '';
help_screen_line('--create_template_module', ' ', 'Add alert template to module');
@@ -1685,6 +1686,23 @@ sub cli_create_network_module_from_component() {
pandora_create_module_from_network_component ($conf, $component, $agent_id, $dbh);
}
+##############################################################################
+# Create a network component.
+# Related option: --create_network_component
+##############################################################################
+sub cli_create_network_component() {
+ my ($c_name, $c_group, $c_type) = @ARGV[2..4];
+ my @todo = @ARGV[5..20];
+ my $other = join('|', @todo);
+ my @todo2 = @ARGV[22..26];
+ my $other2 = join('|', @todo2);
+
+ # Call the API.
+ my $result = api_call( $conf, 'set', 'new_network_component', $c_name, undef, "$c_type|$other|$c_group|$other2");
+
+ print "$result \n\n ";
+}
+
##############################################################################
# Create netflow filter
# Related option: --create_netflow_filter
@@ -6204,6 +6222,10 @@ sub pandora_manage_main ($$$) {
param_check($ltotal, 2);
cli_create_network_module_from_component();
}
+ elsif ($param eq '--create_network_component') {
+ param_check($ltotal, 24, 21);
+ cli_create_network_component();
+ }
elsif ($param eq '--create_netflow_filter') {
param_check($ltotal, 5);
cli_create_netflow_filter();
diff --git a/visual_console_client/.eslintrc b/visual_console_client/.eslintrc
new file mode 100644
index 0000000000..af67551834
--- /dev/null
+++ b/visual_console_client/.eslintrc
@@ -0,0 +1,19 @@
+{
+ "env": {
+ "browser": true,
+ "node": true,
+ "jest": true
+ },
+ "parser": "@typescript-eslint/parser",
+ "plugins": ["@typescript-eslint", "prettier"],
+ "extends": [
+ "eslint:recommended",
+ "plugin:prettier/recommended",
+ "plugin:@typescript-eslint/recommended"
+ ],
+ "rules": {
+ "no-console": "off",
+ "@typescript-eslint/indent": "off",
+ "@typescript-eslint/explicit-function-return-type": "off"
+ }
+}
diff --git a/visual_console_client/.gitignore b/visual_console_client/.gitignore
new file mode 100644
index 0000000000..46091fbe36
--- /dev/null
+++ b/visual_console_client/.gitignore
@@ -0,0 +1,27 @@
+# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
+
+# dependencies
+/node_modules
+/.pnp
+.pnp.js
+
+# testing
+/coverage
+
+# production
+/build
+/dist
+
+# editor
+# .vscode
+
+# misc
+.DS_Store
+.env.local
+.env.development.local
+.env.test.local
+.env.production.local
+
+npm-debug.log*
+yarn-debug.log*
+yarn-error.log*
diff --git a/visual_console_client/.vscode/launch.json b/visual_console_client/.vscode/launch.json
new file mode 100644
index 0000000000..115b2f51b6
--- /dev/null
+++ b/visual_console_client/.vscode/launch.json
@@ -0,0 +1,15 @@
+{
+ // Use IntelliSense para saber los atributos posibles.
+ // Mantenga el puntero para ver las descripciones de los existentes atributos
+ // Para más información, visite: https://go.microsoft.com/fwlink/?linkid=830387
+ "version": "0.2.0",
+ "configurations": [
+ {
+ "type": "chrome",
+ "request": "launch",
+ "name": "Debug",
+ "url": "http://localhost:8080",
+ "webRoot": "${workspaceFolder}"
+ }
+ ]
+}
diff --git a/visual_console_client/.vscode/settings.json b/visual_console_client/.vscode/settings.json
new file mode 100644
index 0000000000..024b36878e
--- /dev/null
+++ b/visual_console_client/.vscode/settings.json
@@ -0,0 +1,10 @@
+{
+ "typescript.tsdk": "node_modules/typescript/lib",
+ "editor.formatOnSave": true,
+ "eslint.validate": [
+ "javascript",
+ "javascriptreact",
+ "typescript",
+ "typescriptreact"
+ ]
+}
diff --git a/visual_console_client/README.md b/visual_console_client/README.md
new file mode 100644
index 0000000000..b480fac939
--- /dev/null
+++ b/visual_console_client/README.md
@@ -0,0 +1 @@
+# Visual Console Client
diff --git a/visual_console_client/__mocks__/fileMock.js b/visual_console_client/__mocks__/fileMock.js
new file mode 100644
index 0000000000..0a445d0600
--- /dev/null
+++ b/visual_console_client/__mocks__/fileMock.js
@@ -0,0 +1 @@
+module.exports = "test-file-stub";
diff --git a/visual_console_client/__mocks__/styleMock.js b/visual_console_client/__mocks__/styleMock.js
new file mode 100644
index 0000000000..f053ebf797
--- /dev/null
+++ b/visual_console_client/__mocks__/styleMock.js
@@ -0,0 +1 @@
+module.exports = {};
diff --git a/visual_console_client/jest.config.js b/visual_console_client/jest.config.js
new file mode 100644
index 0000000000..ec2b954ec2
--- /dev/null
+++ b/visual_console_client/jest.config.js
@@ -0,0 +1,14 @@
+module.exports = {
+ roots: ["/src"],
+ transform: {
+ "^.+\\.tsx?$": "ts-jest"
+ },
+ moduleFileExtensions: ["ts", "tsx", "js", "jsx", "json", "node"],
+ // This configuration is used to mock the css and file imports used by Webpack.
+ // https://jestjs.io/docs/en/webpack.html
+ moduleNameMapper: {
+ "\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$":
+ "/__mocks__/fileMock.js",
+ "\\.(css|less)$": "/__mocks__/styleMock.js"
+ }
+};
diff --git a/visual_console_client/package-lock.json b/visual_console_client/package-lock.json
new file mode 100644
index 0000000000..c5a4da6f7a
--- /dev/null
+++ b/visual_console_client/package-lock.json
@@ -0,0 +1,7957 @@
+{
+ "name": "pandora-fms-visual-console",
+ "version": "1.0.0",
+ "lockfileVersion": 1,
+ "requires": true,
+ "dependencies": {
+ "@babel/code-frame": {
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.0.0.tgz",
+ "integrity": "sha512-OfC2uemaknXr87bdLUkWog7nYuliM9Ij5HUcajsVcMCpQrcLmtxRbVFTIqmcSkSeYRBFBRxs2FiUqFJDLdiebA==",
+ "requires": {
+ "@babel/highlight": "^7.0.0"
+ }
+ },
+ "@babel/core": {
+ "version": "7.4.3",
+ "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.4.3.tgz",
+ "integrity": "sha512-oDpASqKFlbspQfzAE7yaeTmdljSH2ADIvBlb0RwbStltTuWa0+7CCI1fYVINNv9saHPa1W7oaKeuNuKj+RQCvA==",
+ "requires": {
+ "@babel/code-frame": "^7.0.0",
+ "@babel/generator": "^7.4.0",
+ "@babel/helpers": "^7.4.3",
+ "@babel/parser": "^7.4.3",
+ "@babel/template": "^7.4.0",
+ "@babel/traverse": "^7.4.3",
+ "@babel/types": "^7.4.0",
+ "convert-source-map": "^1.1.0",
+ "debug": "^4.1.0",
+ "json5": "^2.1.0",
+ "lodash": "^4.17.11",
+ "resolve": "^1.3.2",
+ "semver": "^5.4.1",
+ "source-map": "^0.5.0"
+ },
+ "dependencies": {
+ "debug": {
+ "version": "4.1.1",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz",
+ "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==",
+ "requires": {
+ "ms": "^2.1.1"
+ }
+ },
+ "json5": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/json5/-/json5-2.1.0.tgz",
+ "integrity": "sha512-8Mh9h6xViijj36g7Dxi+Y4S6hNGV96vcJZr/SrlHh1LR/pEn/8j/+qIBbs44YKl69Lrfctp4QD+AdWLTMqEZAQ==",
+ "requires": {
+ "minimist": "^1.2.0"
+ }
+ },
+ "ms": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz",
+ "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg=="
+ }
+ }
+ },
+ "@babel/generator": {
+ "version": "7.4.0",
+ "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.4.0.tgz",
+ "integrity": "sha512-/v5I+a1jhGSKLgZDcmAUZ4K/VePi43eRkUs3yePW1HB1iANOD5tqJXwGSG4BZhSksP8J9ejSlwGeTiiOFZOrXQ==",
+ "requires": {
+ "@babel/types": "^7.4.0",
+ "jsesc": "^2.5.1",
+ "lodash": "^4.17.11",
+ "source-map": "^0.5.0",
+ "trim-right": "^1.0.1"
+ }
+ },
+ "@babel/helper-function-name": {
+ "version": "7.1.0",
+ "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.1.0.tgz",
+ "integrity": "sha512-A95XEoCpb3TO+KZzJ4S/5uW5fNe26DjBGqf1o9ucyLyCmi1dXq/B3c8iaWTfBk3VvetUxl16e8tIrd5teOCfGw==",
+ "requires": {
+ "@babel/helper-get-function-arity": "^7.0.0",
+ "@babel/template": "^7.1.0",
+ "@babel/types": "^7.0.0"
+ }
+ },
+ "@babel/helper-get-function-arity": {
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.0.0.tgz",
+ "integrity": "sha512-r2DbJeg4svYvt3HOS74U4eWKsUAMRH01Z1ds1zx8KNTPtpTL5JAsdFv8BNyOpVqdFhHkkRDIg5B4AsxmkjAlmQ==",
+ "requires": {
+ "@babel/types": "^7.0.0"
+ }
+ },
+ "@babel/helper-plugin-utils": {
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.0.0.tgz",
+ "integrity": "sha512-CYAOUCARwExnEixLdB6sDm2dIJ/YgEAKDM1MOeMeZu9Ld/bDgVo8aiWrXwcY7OBh+1Ea2uUcVRcxKk0GJvW7QA=="
+ },
+ "@babel/helper-split-export-declaration": {
+ "version": "7.4.0",
+ "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.4.0.tgz",
+ "integrity": "sha512-7Cuc6JZiYShaZnybDmfwhY4UYHzI6rlqhWjaIqbsJGsIqPimEYy5uh3akSRLMg65LSdSEnJ8a8/bWQN6u2oMGw==",
+ "requires": {
+ "@babel/types": "^7.4.0"
+ }
+ },
+ "@babel/helpers": {
+ "version": "7.4.3",
+ "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.4.3.tgz",
+ "integrity": "sha512-BMh7X0oZqb36CfyhvtbSmcWc3GXocfxv3yNsAEuM0l+fAqSO22rQrUpijr3oE/10jCTrB6/0b9kzmG4VetCj8Q==",
+ "requires": {
+ "@babel/template": "^7.4.0",
+ "@babel/traverse": "^7.4.3",
+ "@babel/types": "^7.4.0"
+ }
+ },
+ "@babel/highlight": {
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.0.0.tgz",
+ "integrity": "sha512-UFMC4ZeFC48Tpvj7C8UgLvtkaUuovQX+5xNWrsIoMG8o2z+XFKjKaN9iVmS84dPwVN00W4wPmqvYoZF3EGAsfw==",
+ "requires": {
+ "chalk": "^2.0.0",
+ "esutils": "^2.0.2",
+ "js-tokens": "^4.0.0"
+ }
+ },
+ "@babel/parser": {
+ "version": "7.4.3",
+ "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.4.3.tgz",
+ "integrity": "sha512-gxpEUhTS1sGA63EGQGuA+WESPR/6tz6ng7tSHFCmaTJK/cGK8y37cBTspX+U2xCAue2IQVvF6Z0oigmjwD8YGQ=="
+ },
+ "@babel/plugin-syntax-object-rest-spread": {
+ "version": "7.2.0",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.2.0.tgz",
+ "integrity": "sha512-t0JKGgqk2We+9may3t0xDdmneaXmyxq0xieYcKHxIsrJO64n1OiMWNUtc5gQK1PA0NpdCRrtZp4z+IUaKugrSA==",
+ "requires": {
+ "@babel/helper-plugin-utils": "^7.0.0"
+ }
+ },
+ "@babel/template": {
+ "version": "7.4.0",
+ "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.4.0.tgz",
+ "integrity": "sha512-SOWwxxClTTh5NdbbYZ0BmaBVzxzTh2tO/TeLTbF6MO6EzVhHTnff8CdBXx3mEtazFBoysmEM6GU/wF+SuSx4Fw==",
+ "requires": {
+ "@babel/code-frame": "^7.0.0",
+ "@babel/parser": "^7.4.0",
+ "@babel/types": "^7.4.0"
+ }
+ },
+ "@babel/traverse": {
+ "version": "7.4.3",
+ "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.4.3.tgz",
+ "integrity": "sha512-HmA01qrtaCwwJWpSKpA948cBvU5BrmviAief/b3AVw936DtcdsTexlbyzNuDnthwhOQ37xshn7hvQaEQk7ISYQ==",
+ "requires": {
+ "@babel/code-frame": "^7.0.0",
+ "@babel/generator": "^7.4.0",
+ "@babel/helper-function-name": "^7.1.0",
+ "@babel/helper-split-export-declaration": "^7.4.0",
+ "@babel/parser": "^7.4.3",
+ "@babel/types": "^7.4.0",
+ "debug": "^4.1.0",
+ "globals": "^11.1.0",
+ "lodash": "^4.17.11"
+ },
+ "dependencies": {
+ "debug": {
+ "version": "4.1.1",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz",
+ "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==",
+ "requires": {
+ "ms": "^2.1.1"
+ }
+ },
+ "ms": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz",
+ "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg=="
+ }
+ }
+ },
+ "@babel/types": {
+ "version": "7.4.0",
+ "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.4.0.tgz",
+ "integrity": "sha512-aPvkXyU2SPOnztlgo8n9cEiXW755mgyvueUPcpStqdzoSPm0fjO0vQBjLkt3JKJW7ufikfcnMTTPsN1xaTsBPA==",
+ "requires": {
+ "esutils": "^2.0.2",
+ "lodash": "^4.17.11",
+ "to-fast-properties": "^2.0.0"
+ }
+ },
+ "@cnakazawa/watch": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/@cnakazawa/watch/-/watch-1.0.3.tgz",
+ "integrity": "sha512-r5160ogAvGyHsal38Kux7YYtodEKOj89RGb28ht1jh3SJb08VwRwAKKJL0bGb04Zd/3r9FL3BFIc3bBidYffCA==",
+ "requires": {
+ "exec-sh": "^0.3.2",
+ "minimist": "^1.2.0"
+ }
+ },
+ "@jest/console": {
+ "version": "24.7.1",
+ "resolved": "https://registry.npmjs.org/@jest/console/-/console-24.7.1.tgz",
+ "integrity": "sha512-iNhtIy2M8bXlAOULWVTUxmnelTLFneTNEkHCgPmgd+zNwy9zVddJ6oS5rZ9iwoscNdT5mMwUd0C51v/fSlzItg==",
+ "requires": {
+ "@jest/source-map": "^24.3.0",
+ "chalk": "^2.0.1",
+ "slash": "^2.0.0"
+ }
+ },
+ "@jest/core": {
+ "version": "24.7.1",
+ "resolved": "https://registry.npmjs.org/@jest/core/-/core-24.7.1.tgz",
+ "integrity": "sha512-ivlZ8HX/FOASfHcb5DJpSPFps8ydfUYzLZfgFFqjkLijYysnIEOieg72YRhO4ZUB32xu40hsSMmaw+IGYeKONA==",
+ "requires": {
+ "@jest/console": "^24.7.1",
+ "@jest/reporters": "^24.7.1",
+ "@jest/test-result": "^24.7.1",
+ "@jest/transform": "^24.7.1",
+ "@jest/types": "^24.7.0",
+ "ansi-escapes": "^3.0.0",
+ "chalk": "^2.0.1",
+ "exit": "^0.1.2",
+ "graceful-fs": "^4.1.15",
+ "jest-changed-files": "^24.7.0",
+ "jest-config": "^24.7.1",
+ "jest-haste-map": "^24.7.1",
+ "jest-message-util": "^24.7.1",
+ "jest-regex-util": "^24.3.0",
+ "jest-resolve-dependencies": "^24.7.1",
+ "jest-runner": "^24.7.1",
+ "jest-runtime": "^24.7.1",
+ "jest-snapshot": "^24.7.1",
+ "jest-util": "^24.7.1",
+ "jest-validate": "^24.7.0",
+ "jest-watcher": "^24.7.1",
+ "micromatch": "^3.1.10",
+ "p-each-series": "^1.0.0",
+ "pirates": "^4.0.1",
+ "realpath-native": "^1.1.0",
+ "rimraf": "^2.5.4",
+ "strip-ansi": "^5.0.0"
+ },
+ "dependencies": {
+ "ansi-regex": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz",
+ "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg=="
+ },
+ "strip-ansi": {
+ "version": "5.2.0",
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz",
+ "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==",
+ "requires": {
+ "ansi-regex": "^4.1.0"
+ }
+ }
+ }
+ },
+ "@jest/environment": {
+ "version": "24.7.1",
+ "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-24.7.1.tgz",
+ "integrity": "sha512-wmcTTYc4/KqA+U5h1zQd5FXXynfa7VGP2NfF+c6QeGJ7c+2nStgh65RQWNX62SC716dTtqheTRrZl0j+54oGHw==",
+ "requires": {
+ "@jest/fake-timers": "^24.7.1",
+ "@jest/transform": "^24.7.1",
+ "@jest/types": "^24.7.0",
+ "jest-mock": "^24.7.0"
+ }
+ },
+ "@jest/fake-timers": {
+ "version": "24.7.1",
+ "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-24.7.1.tgz",
+ "integrity": "sha512-4vSQJDKfR2jScOe12L9282uiwuwQv9Lk7mgrCSZHA9evB9efB/qx8i0KJxsAKtp8fgJYBJdYY7ZU6u3F4/pyjA==",
+ "requires": {
+ "@jest/types": "^24.7.0",
+ "jest-message-util": "^24.7.1",
+ "jest-mock": "^24.7.0"
+ }
+ },
+ "@jest/reporters": {
+ "version": "24.7.1",
+ "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-24.7.1.tgz",
+ "integrity": "sha512-bO+WYNwHLNhrjB9EbPL4kX/mCCG4ZhhfWmO3m4FSpbgr7N83MFejayz30kKjgqr7smLyeaRFCBQMbXpUgnhAJw==",
+ "requires": {
+ "@jest/environment": "^24.7.1",
+ "@jest/test-result": "^24.7.1",
+ "@jest/transform": "^24.7.1",
+ "@jest/types": "^24.7.0",
+ "chalk": "^2.0.1",
+ "exit": "^0.1.2",
+ "glob": "^7.1.2",
+ "istanbul-api": "^2.1.1",
+ "istanbul-lib-coverage": "^2.0.2",
+ "istanbul-lib-instrument": "^3.0.1",
+ "istanbul-lib-source-maps": "^3.0.1",
+ "jest-haste-map": "^24.7.1",
+ "jest-resolve": "^24.7.1",
+ "jest-runtime": "^24.7.1",
+ "jest-util": "^24.7.1",
+ "jest-worker": "^24.6.0",
+ "node-notifier": "^5.2.1",
+ "slash": "^2.0.0",
+ "source-map": "^0.6.0",
+ "string-length": "^2.0.0"
+ },
+ "dependencies": {
+ "source-map": {
+ "version": "0.6.1",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
+ "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="
+ }
+ }
+ },
+ "@jest/source-map": {
+ "version": "24.3.0",
+ "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-24.3.0.tgz",
+ "integrity": "sha512-zALZt1t2ou8le/crCeeiRYzvdnTzaIlpOWaet45lNSqNJUnXbppUUFR4ZUAlzgDmKee4Q5P/tKXypI1RiHwgag==",
+ "requires": {
+ "callsites": "^3.0.0",
+ "graceful-fs": "^4.1.15",
+ "source-map": "^0.6.0"
+ },
+ "dependencies": {
+ "source-map": {
+ "version": "0.6.1",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
+ "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="
+ }
+ }
+ },
+ "@jest/test-result": {
+ "version": "24.7.1",
+ "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-24.7.1.tgz",
+ "integrity": "sha512-3U7wITxstdEc2HMfBX7Yx3JZgiNBubwDqQMh+BXmZXHa3G13YWF3p6cK+5g0hGkN3iufg/vGPl3hLxQXD74Npg==",
+ "requires": {
+ "@jest/console": "^24.7.1",
+ "@jest/types": "^24.7.0",
+ "@types/istanbul-lib-coverage": "^2.0.0"
+ }
+ },
+ "@jest/test-sequencer": {
+ "version": "24.7.1",
+ "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-24.7.1.tgz",
+ "integrity": "sha512-84HQkCpVZI/G1zq53gHJvSmhUer4aMYp9tTaffW28Ih5OxfCg8hGr3nTSbL1OhVDRrFZwvF+/R9gY6JRkDUpUA==",
+ "requires": {
+ "@jest/test-result": "^24.7.1",
+ "jest-haste-map": "^24.7.1",
+ "jest-runner": "^24.7.1",
+ "jest-runtime": "^24.7.1"
+ }
+ },
+ "@jest/transform": {
+ "version": "24.7.1",
+ "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-24.7.1.tgz",
+ "integrity": "sha512-EsOUqP9ULuJ66IkZQhI5LufCHlTbi7hrcllRMUEV/tOgqBVQi93+9qEvkX0n8mYpVXQ8VjwmICeRgg58mrtIEw==",
+ "requires": {
+ "@babel/core": "^7.1.0",
+ "@jest/types": "^24.7.0",
+ "babel-plugin-istanbul": "^5.1.0",
+ "chalk": "^2.0.1",
+ "convert-source-map": "^1.4.0",
+ "fast-json-stable-stringify": "^2.0.0",
+ "graceful-fs": "^4.1.15",
+ "jest-haste-map": "^24.7.1",
+ "jest-regex-util": "^24.3.0",
+ "jest-util": "^24.7.1",
+ "micromatch": "^3.1.10",
+ "realpath-native": "^1.1.0",
+ "slash": "^2.0.0",
+ "source-map": "^0.6.1",
+ "write-file-atomic": "2.4.1"
+ },
+ "dependencies": {
+ "source-map": {
+ "version": "0.6.1",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
+ "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="
+ }
+ }
+ },
+ "@jest/types": {
+ "version": "24.7.0",
+ "resolved": "https://registry.npmjs.org/@jest/types/-/types-24.7.0.tgz",
+ "integrity": "sha512-ipJUa2rFWiKoBqMKP63Myb6h9+iT3FHRTF2M8OR6irxWzItisa8i4dcSg14IbvmXUnBlHBlUQPYUHWyX3UPpYA==",
+ "requires": {
+ "@types/istanbul-lib-coverage": "^2.0.0",
+ "@types/yargs": "^12.0.9"
+ }
+ },
+ "@types/babel__core": {
+ "version": "7.1.1",
+ "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.1.1.tgz",
+ "integrity": "sha512-+hjBtgcFPYyCTo0A15+nxrCVJL7aC6Acg87TXd5OW3QhHswdrOLoles+ldL2Uk8q++7yIfl4tURtztccdeeyOw==",
+ "requires": {
+ "@babel/parser": "^7.1.0",
+ "@babel/types": "^7.0.0",
+ "@types/babel__generator": "*",
+ "@types/babel__template": "*",
+ "@types/babel__traverse": "*"
+ }
+ },
+ "@types/babel__generator": {
+ "version": "7.0.2",
+ "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.0.2.tgz",
+ "integrity": "sha512-NHcOfab3Zw4q5sEE2COkpfXjoE7o+PmqD9DQW4koUT3roNxwziUdXGnRndMat/LJNUtePwn1TlP4do3uoe3KZQ==",
+ "requires": {
+ "@babel/types": "^7.0.0"
+ }
+ },
+ "@types/babel__template": {
+ "version": "7.0.2",
+ "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.0.2.tgz",
+ "integrity": "sha512-/K6zCpeW7Imzgab2bLkLEbz0+1JlFSrUMdw7KoIIu+IUdu51GWaBZpd3y1VXGVXzynvGa4DaIaxNZHiON3GXUg==",
+ "requires": {
+ "@babel/parser": "^7.1.0",
+ "@babel/types": "^7.0.0"
+ }
+ },
+ "@types/babel__traverse": {
+ "version": "7.0.6",
+ "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.0.6.tgz",
+ "integrity": "sha512-XYVgHF2sQ0YblLRMLNPB3CkFMewzFmlDsH/TneZFHUXDlABQgh88uOxuez7ZcXxayLFrqLwtDH1t+FmlFwNZxw==",
+ "requires": {
+ "@babel/types": "^7.3.0"
+ }
+ },
+ "@types/d3-path": {
+ "version": "1.0.8",
+ "resolved": "https://registry.npmjs.org/@types/d3-path/-/d3-path-1.0.8.tgz",
+ "integrity": "sha512-AZGHWslq/oApTAHu9+yH/Bnk63y9oFOMROtqPAtxl5uB6qm1x2lueWdVEjsjjV3Qc2+QfuzKIwIR5MvVBakfzA=="
+ },
+ "@types/d3-shape": {
+ "version": "1.3.1",
+ "resolved": "https://registry.npmjs.org/@types/d3-shape/-/d3-shape-1.3.1.tgz",
+ "integrity": "sha512-usqdvUvPJ7AJNwpd2drOzRKs1ELie53p2m2GnPKr076/ADM579jVTJ5dPsoZ5E/CMNWk8lvPWYQSvilpp6jjwg==",
+ "requires": {
+ "@types/d3-path": "*"
+ }
+ },
+ "@types/istanbul-lib-coverage": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.0.tgz",
+ "integrity": "sha512-eAtOAFZefEnfJiRFQBGw1eYqa5GTLCZ1y86N0XSI/D6EB+E8z6VPV/UL7Gi5UEclFqoQk+6NRqEDsfmDLXn8sg=="
+ },
+ "@types/jest": {
+ "version": "24.0.11",
+ "resolved": "https://registry.npmjs.org/@types/jest/-/jest-24.0.11.tgz",
+ "integrity": "sha512-2kLuPC5FDnWIDvaJBzsGTBQaBbnDweznicvK7UGYzlIJP4RJR2a4A/ByLUXEyEgag6jz8eHdlWExGDtH3EYUXQ==",
+ "requires": {
+ "@types/jest-diff": "*"
+ }
+ },
+ "@types/jest-diff": {
+ "version": "20.0.1",
+ "resolved": "https://registry.npmjs.org/@types/jest-diff/-/jest-diff-20.0.1.tgz",
+ "integrity": "sha512-yALhelO3i0hqZwhjtcr6dYyaLoCHbAMshwtj6cGxTvHZAKXHsYGdff6E8EPw3xLKY0ELUTQ69Q1rQiJENnccMA=="
+ },
+ "@types/stack-utils": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-1.0.1.tgz",
+ "integrity": "sha512-l42BggppR6zLmpfU6fq9HEa2oGPEI8yrSPL3GITjfRInppYFahObbIQOQK3UGxEnyQpltZLaPe75046NOZQikw=="
+ },
+ "@types/yargs": {
+ "version": "12.0.12",
+ "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-12.0.12.tgz",
+ "integrity": "sha512-SOhuU4wNBxhhTHxYaiG5NY4HBhDIDnJF60GU+2LqHAdKKer86//e4yg69aENCtQ04n0ovz+tq2YPME5t5yp4pw=="
+ },
+ "@typescript-eslint/eslint-plugin": {
+ "version": "1.6.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-1.6.0.tgz",
+ "integrity": "sha512-U224c29E2lo861TQZs6GSmyC0OYeRNg6bE9UVIiFBxN2MlA0nq2dCrgIVyyRbC05UOcrgf2Wk/CF2gGOPQKUSQ==",
+ "requires": {
+ "@typescript-eslint/parser": "1.6.0",
+ "@typescript-eslint/typescript-estree": "1.6.0",
+ "requireindex": "^1.2.0",
+ "tsutils": "^3.7.0"
+ }
+ },
+ "@typescript-eslint/parser": {
+ "version": "1.6.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-1.6.0.tgz",
+ "integrity": "sha512-VB9xmSbfafI+/kI4gUK3PfrkGmrJQfh0N4EScT1gZXSZyUxpsBirPL99EWZg9MmPG0pzq/gMtgkk7/rAHj4aQw==",
+ "requires": {
+ "@typescript-eslint/typescript-estree": "1.6.0",
+ "eslint-scope": "^4.0.0",
+ "eslint-visitor-keys": "^1.0.0"
+ }
+ },
+ "@typescript-eslint/typescript-estree": {
+ "version": "1.6.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-1.6.0.tgz",
+ "integrity": "sha512-A4CanUwfaG4oXobD5y7EXbsOHjCwn8tj1RDd820etpPAjH+Icjc2K9e/DQM1Hac5zH2BSy+u6bjvvF2wwREvYA==",
+ "requires": {
+ "lodash.unescape": "4.0.1",
+ "semver": "5.5.0"
+ }
+ },
+ "@webassemblyjs/ast": {
+ "version": "1.8.5",
+ "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.8.5.tgz",
+ "integrity": "sha512-aJMfngIZ65+t71C3y2nBBg5FFG0Okt9m0XEgWZ7Ywgn1oMAT8cNwx00Uv1cQyHtidq0Xn94R4TAywO+LCQ+ZAQ==",
+ "requires": {
+ "@webassemblyjs/helper-module-context": "1.8.5",
+ "@webassemblyjs/helper-wasm-bytecode": "1.8.5",
+ "@webassemblyjs/wast-parser": "1.8.5"
+ }
+ },
+ "@webassemblyjs/floating-point-hex-parser": {
+ "version": "1.8.5",
+ "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.8.5.tgz",
+ "integrity": "sha512-9p+79WHru1oqBh9ewP9zW95E3XAo+90oth7S5Re3eQnECGq59ly1Ri5tsIipKGpiStHsUYmY3zMLqtk3gTcOtQ=="
+ },
+ "@webassemblyjs/helper-api-error": {
+ "version": "1.8.5",
+ "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.8.5.tgz",
+ "integrity": "sha512-Za/tnzsvnqdaSPOUXHyKJ2XI7PDX64kWtURyGiJJZKVEdFOsdKUCPTNEVFZq3zJ2R0G5wc2PZ5gvdTRFgm81zA=="
+ },
+ "@webassemblyjs/helper-buffer": {
+ "version": "1.8.5",
+ "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.8.5.tgz",
+ "integrity": "sha512-Ri2R8nOS0U6G49Q86goFIPNgjyl6+oE1abW1pS84BuhP1Qcr5JqMwRFT3Ah3ADDDYGEgGs1iyb1DGX+kAi/c/Q=="
+ },
+ "@webassemblyjs/helper-code-frame": {
+ "version": "1.8.5",
+ "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-code-frame/-/helper-code-frame-1.8.5.tgz",
+ "integrity": "sha512-VQAadSubZIhNpH46IR3yWO4kZZjMxN1opDrzePLdVKAZ+DFjkGD/rf4v1jap744uPVU6yjL/smZbRIIJTOUnKQ==",
+ "requires": {
+ "@webassemblyjs/wast-printer": "1.8.5"
+ }
+ },
+ "@webassemblyjs/helper-fsm": {
+ "version": "1.8.5",
+ "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-fsm/-/helper-fsm-1.8.5.tgz",
+ "integrity": "sha512-kRuX/saORcg8se/ft6Q2UbRpZwP4y7YrWsLXPbbmtepKr22i8Z4O3V5QE9DbZK908dh5Xya4Un57SDIKwB9eow=="
+ },
+ "@webassemblyjs/helper-module-context": {
+ "version": "1.8.5",
+ "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-module-context/-/helper-module-context-1.8.5.tgz",
+ "integrity": "sha512-/O1B236mN7UNEU4t9X7Pj38i4VoU8CcMHyy3l2cV/kIF4U5KoHXDVqcDuOs1ltkac90IM4vZdHc52t1x8Yfs3g==",
+ "requires": {
+ "@webassemblyjs/ast": "1.8.5",
+ "mamacro": "^0.0.3"
+ }
+ },
+ "@webassemblyjs/helper-wasm-bytecode": {
+ "version": "1.8.5",
+ "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.8.5.tgz",
+ "integrity": "sha512-Cu4YMYG3Ddl72CbmpjU/wbP6SACcOPVbHN1dI4VJNJVgFwaKf1ppeFJrwydOG3NDHxVGuCfPlLZNyEdIYlQ6QQ=="
+ },
+ "@webassemblyjs/helper-wasm-section": {
+ "version": "1.8.5",
+ "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.8.5.tgz",
+ "integrity": "sha512-VV083zwR+VTrIWWtgIUpqfvVdK4ff38loRmrdDBgBT8ADXYsEZ5mPQ4Nde90N3UYatHdYoDIFb7oHzMncI02tA==",
+ "requires": {
+ "@webassemblyjs/ast": "1.8.5",
+ "@webassemblyjs/helper-buffer": "1.8.5",
+ "@webassemblyjs/helper-wasm-bytecode": "1.8.5",
+ "@webassemblyjs/wasm-gen": "1.8.5"
+ }
+ },
+ "@webassemblyjs/ieee754": {
+ "version": "1.8.5",
+ "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.8.5.tgz",
+ "integrity": "sha512-aaCvQYrvKbY/n6wKHb/ylAJr27GglahUO89CcGXMItrOBqRarUMxWLJgxm9PJNuKULwN5n1csT9bYoMeZOGF3g==",
+ "requires": {
+ "@xtuc/ieee754": "^1.2.0"
+ }
+ },
+ "@webassemblyjs/leb128": {
+ "version": "1.8.5",
+ "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.8.5.tgz",
+ "integrity": "sha512-plYUuUwleLIziknvlP8VpTgO4kqNaH57Y3JnNa6DLpu/sGcP6hbVdfdX5aHAV716pQBKrfuU26BJK29qY37J7A==",
+ "requires": {
+ "@xtuc/long": "4.2.2"
+ }
+ },
+ "@webassemblyjs/utf8": {
+ "version": "1.8.5",
+ "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.8.5.tgz",
+ "integrity": "sha512-U7zgftmQriw37tfD934UNInokz6yTmn29inT2cAetAsaU9YeVCveWEwhKL1Mg4yS7q//NGdzy79nlXh3bT8Kjw=="
+ },
+ "@webassemblyjs/wasm-edit": {
+ "version": "1.8.5",
+ "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.8.5.tgz",
+ "integrity": "sha512-A41EMy8MWw5yvqj7MQzkDjU29K7UJq1VrX2vWLzfpRHt3ISftOXqrtojn7nlPsZ9Ijhp5NwuODuycSvfAO/26Q==",
+ "requires": {
+ "@webassemblyjs/ast": "1.8.5",
+ "@webassemblyjs/helper-buffer": "1.8.5",
+ "@webassemblyjs/helper-wasm-bytecode": "1.8.5",
+ "@webassemblyjs/helper-wasm-section": "1.8.5",
+ "@webassemblyjs/wasm-gen": "1.8.5",
+ "@webassemblyjs/wasm-opt": "1.8.5",
+ "@webassemblyjs/wasm-parser": "1.8.5",
+ "@webassemblyjs/wast-printer": "1.8.5"
+ }
+ },
+ "@webassemblyjs/wasm-gen": {
+ "version": "1.8.5",
+ "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.8.5.tgz",
+ "integrity": "sha512-BCZBT0LURC0CXDzj5FXSc2FPTsxwp3nWcqXQdOZE4U7h7i8FqtFK5Egia6f9raQLpEKT1VL7zr4r3+QX6zArWg==",
+ "requires": {
+ "@webassemblyjs/ast": "1.8.5",
+ "@webassemblyjs/helper-wasm-bytecode": "1.8.5",
+ "@webassemblyjs/ieee754": "1.8.5",
+ "@webassemblyjs/leb128": "1.8.5",
+ "@webassemblyjs/utf8": "1.8.5"
+ }
+ },
+ "@webassemblyjs/wasm-opt": {
+ "version": "1.8.5",
+ "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.8.5.tgz",
+ "integrity": "sha512-HKo2mO/Uh9A6ojzu7cjslGaHaUU14LdLbGEKqTR7PBKwT6LdPtLLh9fPY33rmr5wcOMrsWDbbdCHq4hQUdd37Q==",
+ "requires": {
+ "@webassemblyjs/ast": "1.8.5",
+ "@webassemblyjs/helper-buffer": "1.8.5",
+ "@webassemblyjs/wasm-gen": "1.8.5",
+ "@webassemblyjs/wasm-parser": "1.8.5"
+ }
+ },
+ "@webassemblyjs/wasm-parser": {
+ "version": "1.8.5",
+ "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.8.5.tgz",
+ "integrity": "sha512-pi0SYE9T6tfcMkthwcgCpL0cM9nRYr6/6fjgDtL6q/ZqKHdMWvxitRi5JcZ7RI4SNJJYnYNaWy5UUrHQy998lw==",
+ "requires": {
+ "@webassemblyjs/ast": "1.8.5",
+ "@webassemblyjs/helper-api-error": "1.8.5",
+ "@webassemblyjs/helper-wasm-bytecode": "1.8.5",
+ "@webassemblyjs/ieee754": "1.8.5",
+ "@webassemblyjs/leb128": "1.8.5",
+ "@webassemblyjs/utf8": "1.8.5"
+ }
+ },
+ "@webassemblyjs/wast-parser": {
+ "version": "1.8.5",
+ "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-parser/-/wast-parser-1.8.5.tgz",
+ "integrity": "sha512-daXC1FyKWHF1i11obK086QRlsMsY4+tIOKgBqI1lxAnkp9xe9YMcgOxm9kLe+ttjs5aWV2KKE1TWJCN57/Btsg==",
+ "requires": {
+ "@webassemblyjs/ast": "1.8.5",
+ "@webassemblyjs/floating-point-hex-parser": "1.8.5",
+ "@webassemblyjs/helper-api-error": "1.8.5",
+ "@webassemblyjs/helper-code-frame": "1.8.5",
+ "@webassemblyjs/helper-fsm": "1.8.5",
+ "@xtuc/long": "4.2.2"
+ }
+ },
+ "@webassemblyjs/wast-printer": {
+ "version": "1.8.5",
+ "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.8.5.tgz",
+ "integrity": "sha512-w0U0pD4EhlnvRyeJzBqaVSJAo9w/ce7/WPogeXLzGkO6hzhr4GnQIZ4W4uUt5b9ooAaXPtnXlj0gzsXEOUNYMg==",
+ "requires": {
+ "@webassemblyjs/ast": "1.8.5",
+ "@webassemblyjs/wast-parser": "1.8.5",
+ "@xtuc/long": "4.2.2"
+ }
+ },
+ "@xtuc/ieee754": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz",
+ "integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA=="
+ },
+ "@xtuc/long": {
+ "version": "4.2.2",
+ "resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz",
+ "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ=="
+ },
+ "abab": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.0.tgz",
+ "integrity": "sha512-sY5AXXVZv4Y1VACTtR11UJCPHHudgY5i26Qj5TypE6DKlIApbwb5uqhXcJ5UUGbvZNRh7EeIoW+LrJumBsKp7w=="
+ },
+ "accepts": {
+ "version": "1.3.5",
+ "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.5.tgz",
+ "integrity": "sha1-63d99gEXI6OxTopywIBcjoZ0a9I=",
+ "requires": {
+ "mime-types": "~2.1.18",
+ "negotiator": "0.6.1"
+ }
+ },
+ "acorn": {
+ "version": "6.1.1",
+ "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.1.1.tgz",
+ "integrity": "sha512-jPTiwtOxaHNaAPg/dmrJ/beuzLRnXtB0kQPQ8JpotKJgTB6rX6c8mlf315941pyjBSaPg8NHXS9fhP4u17DpGA=="
+ },
+ "acorn-dynamic-import": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/acorn-dynamic-import/-/acorn-dynamic-import-4.0.0.tgz",
+ "integrity": "sha512-d3OEjQV4ROpoflsnUA8HozoIR504TFxNivYEUi6uwz0IYhBkTDXGuWlNdMtybRt3nqVx/L6XqMt0FxkXuWKZhw=="
+ },
+ "acorn-globals": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/acorn-globals/-/acorn-globals-4.3.0.tgz",
+ "integrity": "sha512-hMtHj3s5RnuhvHPowpBYvJVj3rAar82JiDQHvGs1zO0l10ocX/xEdBShNHTJaboucJUsScghp74pH3s7EnHHQw==",
+ "requires": {
+ "acorn": "^6.0.1",
+ "acorn-walk": "^6.0.1"
+ }
+ },
+ "acorn-jsx": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.0.1.tgz",
+ "integrity": "sha512-HJ7CfNHrfJLlNTzIEUTj43LNWGkqpRLxm3YjAlcD0ACydk9XynzYsCBHxut+iqt+1aBXkx9UP/w/ZqMr13XIzg=="
+ },
+ "acorn-walk": {
+ "version": "6.1.1",
+ "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-6.1.1.tgz",
+ "integrity": "sha512-OtUw6JUTgxA2QoqqmrmQ7F2NYqiBPi/L2jqHyFtllhOUvXYQXf0Z1CYUinIfyT4bTCGmrA7gX9FvHA81uzCoVw=="
+ },
+ "ajv": {
+ "version": "6.9.1",
+ "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.9.1.tgz",
+ "integrity": "sha512-XDN92U311aINL77ieWHmqCcNlwjoP5cHXDxIxbf2MaPYuCXOHS7gHH8jktxeK5omgd52XbSTX6a4Piwd1pQmzA==",
+ "requires": {
+ "fast-deep-equal": "^2.0.1",
+ "fast-json-stable-stringify": "^2.0.0",
+ "json-schema-traverse": "^0.4.1",
+ "uri-js": "^4.2.2"
+ }
+ },
+ "ajv-errors": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/ajv-errors/-/ajv-errors-1.0.1.tgz",
+ "integrity": "sha512-DCRfO/4nQ+89p/RK43i8Ezd41EqdGIU4ld7nGF8OQ14oc/we5rEntLCUa7+jrn3nn83BosfwZA0wb4pon2o8iQ=="
+ },
+ "ajv-keywords": {
+ "version": "3.4.0",
+ "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.4.0.tgz",
+ "integrity": "sha512-aUjdRFISbuFOl0EIZc+9e4FfZp0bDZgAdOOf30bJmw8VM9v84SHyVyxDfbWxpGYbdZD/9XoKxfHVNmxPkhwyGw=="
+ },
+ "ansi-colors": {
+ "version": "3.2.4",
+ "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-3.2.4.tgz",
+ "integrity": "sha512-hHUXGagefjN2iRrID63xckIvotOXOojhQKWIPUZ4mNUZ9nLZW+7FMNoE1lOkEhNWYsx/7ysGIuJYCiMAA9FnrA=="
+ },
+ "ansi-escapes": {
+ "version": "3.2.0",
+ "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.2.0.tgz",
+ "integrity": "sha512-cBhpre4ma+U0T1oM5fXg7Dy1Jw7zzwv7lt/GoCpr+hDQJoYnKVPLL4dCvSEFMmQurOQvSrwT7SL/DAlhBI97RQ=="
+ },
+ "ansi-html": {
+ "version": "0.0.7",
+ "resolved": "https://registry.npmjs.org/ansi-html/-/ansi-html-0.0.7.tgz",
+ "integrity": "sha1-gTWEAhliqenm/QOflA0S9WynhZ4="
+ },
+ "ansi-regex": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz",
+ "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg="
+ },
+ "ansi-styles": {
+ "version": "3.2.1",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
+ "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
+ "requires": {
+ "color-convert": "^1.9.0"
+ }
+ },
+ "anymatch": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-2.0.0.tgz",
+ "integrity": "sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw==",
+ "requires": {
+ "micromatch": "^3.1.4",
+ "normalize-path": "^2.1.1"
+ },
+ "dependencies": {
+ "normalize-path": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz",
+ "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=",
+ "requires": {
+ "remove-trailing-separator": "^1.0.1"
+ }
+ }
+ }
+ },
+ "append-transform": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/append-transform/-/append-transform-1.0.0.tgz",
+ "integrity": "sha512-P009oYkeHyU742iSZJzZZywj4QRJdnTWffaKuJQLablCZ1uz6/cW4yaRgcDaoQ+uwOxxnt0gRUcwfsNP2ri0gw==",
+ "requires": {
+ "default-require-extensions": "^2.0.0"
+ }
+ },
+ "aproba": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz",
+ "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw=="
+ },
+ "argparse": {
+ "version": "1.0.10",
+ "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz",
+ "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==",
+ "requires": {
+ "sprintf-js": "~1.0.2"
+ }
+ },
+ "arr-diff": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz",
+ "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA="
+ },
+ "arr-flatten": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz",
+ "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg=="
+ },
+ "arr-union": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz",
+ "integrity": "sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ="
+ },
+ "array-equal": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/array-equal/-/array-equal-1.0.0.tgz",
+ "integrity": "sha1-jCpe8kcv2ep0KwTHenUJO6J1fJM="
+ },
+ "array-flatten": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-2.1.2.tgz",
+ "integrity": "sha512-hNfzcOV8W4NdualtqBFPyVO+54DSJuZGY9qT4pRroB6S9e3iiido2ISIC5h9R2sPJ8H3FHCIiEnsv1lPXO3KtQ=="
+ },
+ "array-union": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/array-union/-/array-union-1.0.2.tgz",
+ "integrity": "sha1-mjRBDk9OPaI96jdb5b5w8kd47Dk=",
+ "requires": {
+ "array-uniq": "^1.0.1"
+ }
+ },
+ "array-uniq": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.3.tgz",
+ "integrity": "sha1-r2rId6Jcx/dOBYiUdThY39sk/bY="
+ },
+ "array-unique": {
+ "version": "0.3.2",
+ "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz",
+ "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg="
+ },
+ "arrify": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz",
+ "integrity": "sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0="
+ },
+ "asn1": {
+ "version": "0.2.4",
+ "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz",
+ "integrity": "sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==",
+ "requires": {
+ "safer-buffer": "~2.1.0"
+ }
+ },
+ "asn1.js": {
+ "version": "4.10.1",
+ "resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-4.10.1.tgz",
+ "integrity": "sha512-p32cOF5q0Zqs9uBiONKYLm6BClCoBCM5O9JfeUSlnQLBTxYdTK+pW+nXflm8UkKd2UYlEbYz5qEi0JuZR9ckSw==",
+ "requires": {
+ "bn.js": "^4.0.0",
+ "inherits": "^2.0.1",
+ "minimalistic-assert": "^1.0.0"
+ }
+ },
+ "assert": {
+ "version": "1.4.1",
+ "resolved": "https://registry.npmjs.org/assert/-/assert-1.4.1.tgz",
+ "integrity": "sha1-mZEtWRg2tab1s0XA8H7vwI/GXZE=",
+ "requires": {
+ "util": "0.10.3"
+ },
+ "dependencies": {
+ "inherits": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz",
+ "integrity": "sha1-sX0I0ya0Qj5Wjv9xn5GwscvfafE="
+ },
+ "util": {
+ "version": "0.10.3",
+ "resolved": "https://registry.npmjs.org/util/-/util-0.10.3.tgz",
+ "integrity": "sha1-evsa/lCAUkZInj23/g7TeTNqwPk=",
+ "requires": {
+ "inherits": "2.0.1"
+ }
+ }
+ }
+ },
+ "assert-plus": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz",
+ "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU="
+ },
+ "assign-symbols": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz",
+ "integrity": "sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c="
+ },
+ "astral-regex": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-1.0.0.tgz",
+ "integrity": "sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg=="
+ },
+ "async": {
+ "version": "2.6.2",
+ "resolved": "https://registry.npmjs.org/async/-/async-2.6.2.tgz",
+ "integrity": "sha512-H1qVYh1MYhEEFLsP97cVKqCGo7KfCyTt6uEWqsTBr9SO84oK9Uwbyd/yCW+6rKJLHksBNUVWZDAjfS+Ccx0Bbg==",
+ "requires": {
+ "lodash": "^4.17.11"
+ }
+ },
+ "async-each": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/async-each/-/async-each-1.0.1.tgz",
+ "integrity": "sha1-GdOGodntxufByF04iu28xW0zYC0="
+ },
+ "async-limiter": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.0.tgz",
+ "integrity": "sha512-jp/uFnooOiO+L211eZOoSyzpOITMXx1rBITauYykG3BRYPu8h0UcxsPNB04RR5vo4Tyz3+ay17tR6JVf9qzYWg=="
+ },
+ "asynckit": {
+ "version": "0.4.0",
+ "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
+ "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k="
+ },
+ "atob": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz",
+ "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg=="
+ },
+ "awesome-typescript-loader": {
+ "version": "5.2.1",
+ "resolved": "https://registry.npmjs.org/awesome-typescript-loader/-/awesome-typescript-loader-5.2.1.tgz",
+ "integrity": "sha512-slv66OAJB8orL+UUaTI3pKlLorwIvS4ARZzYR9iJJyGsEgOqueMfOMdKySWzZ73vIkEe3fcwFgsKMg4d8zyb1g==",
+ "requires": {
+ "chalk": "^2.4.1",
+ "enhanced-resolve": "^4.0.0",
+ "loader-utils": "^1.1.0",
+ "lodash": "^4.17.5",
+ "micromatch": "^3.1.9",
+ "mkdirp": "^0.5.1",
+ "source-map-support": "^0.5.3",
+ "webpack-log": "^1.2.0"
+ }
+ },
+ "aws-sign2": {
+ "version": "0.7.0",
+ "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz",
+ "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg="
+ },
+ "aws4": {
+ "version": "1.8.0",
+ "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.8.0.tgz",
+ "integrity": "sha512-ReZxvNHIOv88FlT7rxcXIIC0fPt4KZqZbOlivyWtXLt8ESx84zd3kMC6iK5jVeS2qt+g7ftS7ye4fi06X5rtRQ=="
+ },
+ "babel-jest": {
+ "version": "24.7.1",
+ "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-24.7.1.tgz",
+ "integrity": "sha512-GPnLqfk8Mtt0i4OemjWkChi73A3ALs4w2/QbG64uAj8b5mmwzxc7jbJVRZt8NJkxi6FopVHog9S3xX6UJKb2qg==",
+ "requires": {
+ "@jest/transform": "^24.7.1",
+ "@jest/types": "^24.7.0",
+ "@types/babel__core": "^7.1.0",
+ "babel-plugin-istanbul": "^5.1.0",
+ "babel-preset-jest": "^24.6.0",
+ "chalk": "^2.4.2",
+ "slash": "^2.0.0"
+ }
+ },
+ "babel-plugin-istanbul": {
+ "version": "5.1.1",
+ "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-5.1.1.tgz",
+ "integrity": "sha512-RNNVv2lsHAXJQsEJ5jonQwrJVWK8AcZpG1oxhnjCUaAjL7xahYLANhPUZbzEQHjKy1NMYUwn+0NPKQc8iSY4xQ==",
+ "requires": {
+ "find-up": "^3.0.0",
+ "istanbul-lib-instrument": "^3.0.0",
+ "test-exclude": "^5.0.0"
+ }
+ },
+ "babel-plugin-jest-hoist": {
+ "version": "24.6.0",
+ "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-24.6.0.tgz",
+ "integrity": "sha512-3pKNH6hMt9SbOv0F3WVmy5CWQ4uogS3k0GY5XLyQHJ9EGpAT9XWkFd2ZiXXtkwFHdAHa5j7w7kfxSP5lAIwu7w==",
+ "requires": {
+ "@types/babel__traverse": "^7.0.6"
+ }
+ },
+ "babel-preset-jest": {
+ "version": "24.6.0",
+ "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-24.6.0.tgz",
+ "integrity": "sha512-pdZqLEdmy1ZK5kyRUfvBb2IfTPb2BUvIJczlPspS8fWmBQslNNDBqVfh7BW5leOVJMDZKzjD8XEyABTk6gQ5yw==",
+ "requires": {
+ "@babel/plugin-syntax-object-rest-spread": "^7.0.0",
+ "babel-plugin-jest-hoist": "^24.6.0"
+ }
+ },
+ "balanced-match": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
+ "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c="
+ },
+ "base": {
+ "version": "0.11.2",
+ "resolved": "https://registry.npmjs.org/base/-/base-0.11.2.tgz",
+ "integrity": "sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==",
+ "requires": {
+ "cache-base": "^1.0.1",
+ "class-utils": "^0.3.5",
+ "component-emitter": "^1.2.1",
+ "define-property": "^1.0.0",
+ "isobject": "^3.0.1",
+ "mixin-deep": "^1.2.0",
+ "pascalcase": "^0.1.1"
+ },
+ "dependencies": {
+ "define-property": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz",
+ "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=",
+ "requires": {
+ "is-descriptor": "^1.0.0"
+ }
+ },
+ "is-accessor-descriptor": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz",
+ "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==",
+ "requires": {
+ "kind-of": "^6.0.0"
+ }
+ },
+ "is-data-descriptor": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz",
+ "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==",
+ "requires": {
+ "kind-of": "^6.0.0"
+ }
+ },
+ "is-descriptor": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz",
+ "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==",
+ "requires": {
+ "is-accessor-descriptor": "^1.0.0",
+ "is-data-descriptor": "^1.0.0",
+ "kind-of": "^6.0.2"
+ }
+ }
+ }
+ },
+ "base64-js": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.3.0.tgz",
+ "integrity": "sha512-ccav/yGvoa80BQDljCxsmmQ3Xvx60/UpBIij5QN21W3wBi/hhIC9OoO+KLpu9IJTS9j4DRVJ3aDDF9cMSoa2lw=="
+ },
+ "batch": {
+ "version": "0.6.1",
+ "resolved": "https://registry.npmjs.org/batch/-/batch-0.6.1.tgz",
+ "integrity": "sha1-3DQxT05nkxgJP8dgJyUl+UvyXBY="
+ },
+ "bcrypt-pbkdf": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz",
+ "integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=",
+ "requires": {
+ "tweetnacl": "^0.14.3"
+ }
+ },
+ "big.js": {
+ "version": "5.2.2",
+ "resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz",
+ "integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ=="
+ },
+ "binary-extensions": {
+ "version": "1.13.0",
+ "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.13.0.tgz",
+ "integrity": "sha512-EgmjVLMn22z7eGGv3kcnHwSnJXmFHjISTY9E/S5lIcTD3Oxw05QTcBLNkJFzcb3cNueUdF/IN4U+d78V0zO8Hw=="
+ },
+ "bluebird": {
+ "version": "3.5.3",
+ "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.5.3.tgz",
+ "integrity": "sha512-/qKPUQlaW1OyR51WeCPBvRnAlnZFUJkCSG5HzGnuIqhgyJtF+T94lFnn33eiazjRm2LAHVy2guNnaq48X9SJuw=="
+ },
+ "bn.js": {
+ "version": "4.11.8",
+ "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.8.tgz",
+ "integrity": "sha512-ItfYfPLkWHUjckQCk8xC+LwxgK8NYcXywGigJgSwOP8Y2iyWT4f2vsZnoOXTTbo+o5yXmIUJ4gn5538SO5S3gA=="
+ },
+ "body-parser": {
+ "version": "1.18.3",
+ "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.18.3.tgz",
+ "integrity": "sha1-WykhmP/dVTs6DyDe0FkrlWlVyLQ=",
+ "requires": {
+ "bytes": "3.0.0",
+ "content-type": "~1.0.4",
+ "debug": "2.6.9",
+ "depd": "~1.1.2",
+ "http-errors": "~1.6.3",
+ "iconv-lite": "0.4.23",
+ "on-finished": "~2.3.0",
+ "qs": "6.5.2",
+ "raw-body": "2.3.3",
+ "type-is": "~1.6.16"
+ },
+ "dependencies": {
+ "iconv-lite": {
+ "version": "0.4.23",
+ "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.23.tgz",
+ "integrity": "sha512-neyTUVFtahjf0mB3dZT77u+8O0QB89jFdnBkd5P1JgYPbPaia3gXXOVL2fq8VyU2gMMD7SaN7QukTB/pmXYvDA==",
+ "requires": {
+ "safer-buffer": ">= 2.1.2 < 3"
+ }
+ }
+ }
+ },
+ "bonjour": {
+ "version": "3.5.0",
+ "resolved": "https://registry.npmjs.org/bonjour/-/bonjour-3.5.0.tgz",
+ "integrity": "sha1-jokKGD2O6aI5OzhExpGkK897yfU=",
+ "requires": {
+ "array-flatten": "^2.1.0",
+ "deep-equal": "^1.0.1",
+ "dns-equal": "^1.0.0",
+ "dns-txt": "^2.0.2",
+ "multicast-dns": "^6.0.1",
+ "multicast-dns-service-types": "^1.1.0"
+ }
+ },
+ "brace-expansion": {
+ "version": "1.1.11",
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
+ "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
+ "requires": {
+ "balanced-match": "^1.0.0",
+ "concat-map": "0.0.1"
+ }
+ },
+ "braces": {
+ "version": "2.3.2",
+ "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz",
+ "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==",
+ "requires": {
+ "arr-flatten": "^1.1.0",
+ "array-unique": "^0.3.2",
+ "extend-shallow": "^2.0.1",
+ "fill-range": "^4.0.0",
+ "isobject": "^3.0.1",
+ "repeat-element": "^1.1.2",
+ "snapdragon": "^0.8.1",
+ "snapdragon-node": "^2.0.1",
+ "split-string": "^3.0.2",
+ "to-regex": "^3.0.1"
+ },
+ "dependencies": {
+ "extend-shallow": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
+ "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
+ "requires": {
+ "is-extendable": "^0.1.0"
+ }
+ }
+ }
+ },
+ "brorand": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz",
+ "integrity": "sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8="
+ },
+ "browser-process-hrtime": {
+ "version": "0.1.3",
+ "resolved": "https://registry.npmjs.org/browser-process-hrtime/-/browser-process-hrtime-0.1.3.tgz",
+ "integrity": "sha512-bRFnI4NnjO6cnyLmOV/7PVoDEMJChlcfN0z4s1YMBY989/SvlfMI1lgCnkFUs53e9gQF+w7qu7XdllSTiSl8Aw=="
+ },
+ "browser-resolve": {
+ "version": "1.11.3",
+ "resolved": "https://registry.npmjs.org/browser-resolve/-/browser-resolve-1.11.3.tgz",
+ "integrity": "sha512-exDi1BYWB/6raKHmDTCicQfTkqwN5fioMFV4j8BsfMU4R2DK/QfZfK7kOVkmWCNANf0snkBzqGqAJBao9gZMdQ==",
+ "requires": {
+ "resolve": "1.1.7"
+ },
+ "dependencies": {
+ "resolve": {
+ "version": "1.1.7",
+ "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.1.7.tgz",
+ "integrity": "sha1-IDEU2CrSxe2ejgQRs5ModeiJ6Xs="
+ }
+ }
+ },
+ "browserify-aes": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz",
+ "integrity": "sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==",
+ "requires": {
+ "buffer-xor": "^1.0.3",
+ "cipher-base": "^1.0.0",
+ "create-hash": "^1.1.0",
+ "evp_bytestokey": "^1.0.3",
+ "inherits": "^2.0.1",
+ "safe-buffer": "^5.0.1"
+ }
+ },
+ "browserify-cipher": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/browserify-cipher/-/browserify-cipher-1.0.1.tgz",
+ "integrity": "sha512-sPhkz0ARKbf4rRQt2hTpAHqn47X3llLkUGn+xEJzLjwY8LRs2p0v7ljvI5EyoRO/mexrNunNECisZs+gw2zz1w==",
+ "requires": {
+ "browserify-aes": "^1.0.4",
+ "browserify-des": "^1.0.0",
+ "evp_bytestokey": "^1.0.0"
+ }
+ },
+ "browserify-des": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/browserify-des/-/browserify-des-1.0.2.tgz",
+ "integrity": "sha512-BioO1xf3hFwz4kc6iBhI3ieDFompMhrMlnDFC4/0/vd5MokpuAc3R+LYbwTA9A5Yc9pq9UYPqffKpW2ObuwX5A==",
+ "requires": {
+ "cipher-base": "^1.0.1",
+ "des.js": "^1.0.0",
+ "inherits": "^2.0.1",
+ "safe-buffer": "^5.1.2"
+ }
+ },
+ "browserify-rsa": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/browserify-rsa/-/browserify-rsa-4.0.1.tgz",
+ "integrity": "sha1-IeCr+vbyApzy+vsTNWenAdQTVSQ=",
+ "requires": {
+ "bn.js": "^4.1.0",
+ "randombytes": "^2.0.1"
+ }
+ },
+ "browserify-sign": {
+ "version": "4.0.4",
+ "resolved": "https://registry.npmjs.org/browserify-sign/-/browserify-sign-4.0.4.tgz",
+ "integrity": "sha1-qk62jl17ZYuqa/alfmMMvXqT0pg=",
+ "requires": {
+ "bn.js": "^4.1.1",
+ "browserify-rsa": "^4.0.0",
+ "create-hash": "^1.1.0",
+ "create-hmac": "^1.1.2",
+ "elliptic": "^6.0.0",
+ "inherits": "^2.0.1",
+ "parse-asn1": "^5.0.0"
+ }
+ },
+ "browserify-zlib": {
+ "version": "0.2.0",
+ "resolved": "https://registry.npmjs.org/browserify-zlib/-/browserify-zlib-0.2.0.tgz",
+ "integrity": "sha512-Z942RysHXmJrhqk88FmKBVq/v5tqmSkDz7p54G/MGyjMnCFFnC79XWNbg+Vta8W6Wb2qtSZTSxIGkJrRpCFEiA==",
+ "requires": {
+ "pako": "~1.0.5"
+ }
+ },
+ "bs-logger": {
+ "version": "0.2.6",
+ "resolved": "https://registry.npmjs.org/bs-logger/-/bs-logger-0.2.6.tgz",
+ "integrity": "sha512-pd8DCoxmbgc7hyPKOvxtqNcjYoOsABPQdcCUjGp3d42VR2CX1ORhk2A87oqqu5R1kk+76nsxZupkmyd+MVtCog==",
+ "requires": {
+ "fast-json-stable-stringify": "2.x"
+ }
+ },
+ "bser": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/bser/-/bser-2.0.0.tgz",
+ "integrity": "sha1-mseNPtXZFYBP2HrLFYvHlxR6Fxk=",
+ "requires": {
+ "node-int64": "^0.4.0"
+ }
+ },
+ "buffer": {
+ "version": "4.9.1",
+ "resolved": "https://registry.npmjs.org/buffer/-/buffer-4.9.1.tgz",
+ "integrity": "sha1-bRu2AbB6TvztlwlBMgkwJ8lbwpg=",
+ "requires": {
+ "base64-js": "^1.0.2",
+ "ieee754": "^1.1.4",
+ "isarray": "^1.0.0"
+ }
+ },
+ "buffer-from": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz",
+ "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A=="
+ },
+ "buffer-indexof": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/buffer-indexof/-/buffer-indexof-1.1.1.tgz",
+ "integrity": "sha512-4/rOEg86jivtPTeOUUT61jJO1Ya1TrR/OkqCSZDyq84WJh3LuuiphBYJN+fm5xufIk4XAFcEwte/8WzC8If/1g=="
+ },
+ "buffer-xor": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/buffer-xor/-/buffer-xor-1.0.3.tgz",
+ "integrity": "sha1-JuYe0UIvtw3ULm42cp7VHYVf6Nk="
+ },
+ "builtin-status-codes": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz",
+ "integrity": "sha1-hZgoeOIbmOHGZCXgPQF0eI9Wnug="
+ },
+ "bytes": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz",
+ "integrity": "sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg="
+ },
+ "cacache": {
+ "version": "11.3.2",
+ "resolved": "https://registry.npmjs.org/cacache/-/cacache-11.3.2.tgz",
+ "integrity": "sha512-E0zP4EPGDOaT2chM08Als91eYnf8Z+eH1awwwVsngUmgppfM5jjJ8l3z5vO5p5w/I3LsiXawb1sW0VY65pQABg==",
+ "requires": {
+ "bluebird": "^3.5.3",
+ "chownr": "^1.1.1",
+ "figgy-pudding": "^3.5.1",
+ "glob": "^7.1.3",
+ "graceful-fs": "^4.1.15",
+ "lru-cache": "^5.1.1",
+ "mississippi": "^3.0.0",
+ "mkdirp": "^0.5.1",
+ "move-concurrently": "^1.0.1",
+ "promise-inflight": "^1.0.1",
+ "rimraf": "^2.6.2",
+ "ssri": "^6.0.1",
+ "unique-filename": "^1.1.1",
+ "y18n": "^4.0.0"
+ }
+ },
+ "cache-base": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/cache-base/-/cache-base-1.0.1.tgz",
+ "integrity": "sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==",
+ "requires": {
+ "collection-visit": "^1.0.0",
+ "component-emitter": "^1.2.1",
+ "get-value": "^2.0.6",
+ "has-value": "^1.0.0",
+ "isobject": "^3.0.1",
+ "set-value": "^2.0.0",
+ "to-object-path": "^0.3.0",
+ "union-value": "^1.0.0",
+ "unset-value": "^1.0.0"
+ }
+ },
+ "callsites": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.0.0.tgz",
+ "integrity": "sha512-tWnkwu9YEq2uzlBDI4RcLn8jrFvF9AOi8PxDNU3hZZjJcjkcRAq3vCI+vZcg1SuxISDYe86k9VZFwAxDiJGoAw=="
+ },
+ "camelcase": {
+ "version": "5.2.0",
+ "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.2.0.tgz",
+ "integrity": "sha512-IXFsBS2pC+X0j0N/GE7Dm7j3bsEBp+oTpb7F50dwEVX7rf3IgwO9XatnegTsDtniKCUtEJH4fSU6Asw7uoVLfQ=="
+ },
+ "capture-exit": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/capture-exit/-/capture-exit-2.0.0.tgz",
+ "integrity": "sha512-PiT/hQmTonHhl/HFGN+Lx3JJUznrVYJ3+AQsnthneZbvW7x+f08Tk7yLJTLEOUvBTbduLeeBkxEaYXUOUrRq6g==",
+ "requires": {
+ "rsvp": "^4.8.4"
+ }
+ },
+ "caseless": {
+ "version": "0.12.0",
+ "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz",
+ "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw="
+ },
+ "chalk": {
+ "version": "2.4.2",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
+ "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
+ "requires": {
+ "ansi-styles": "^3.2.1",
+ "escape-string-regexp": "^1.0.5",
+ "supports-color": "^5.3.0"
+ }
+ },
+ "chardet": {
+ "version": "0.7.0",
+ "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz",
+ "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA=="
+ },
+ "chokidar": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.1.2.tgz",
+ "integrity": "sha512-IwXUx0FXc5ibYmPC2XeEj5mpXoV66sR+t3jqu2NS2GYwCktt3KF1/Qqjws/NkegajBA4RbZ5+DDwlOiJsxDHEg==",
+ "requires": {
+ "anymatch": "^2.0.0",
+ "async-each": "^1.0.1",
+ "braces": "^2.3.2",
+ "fsevents": "^1.2.7",
+ "glob-parent": "^3.1.0",
+ "inherits": "^2.0.3",
+ "is-binary-path": "^1.0.0",
+ "is-glob": "^4.0.0",
+ "normalize-path": "^3.0.0",
+ "path-is-absolute": "^1.0.0",
+ "readdirp": "^2.2.1",
+ "upath": "^1.1.0"
+ }
+ },
+ "chownr": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.1.tgz",
+ "integrity": "sha512-j38EvO5+LHX84jlo6h4UzmOwi0UgW61WRyPtJz4qaadK5eY3BTS5TY/S1Stc3Uk2lIM6TPevAlULiEJwie860g=="
+ },
+ "chrome-trace-event": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.0.tgz",
+ "integrity": "sha512-xDbVgyfDTT2piup/h8dK/y4QZfJRSa73bw1WZ8b4XM1o7fsFubUVGYcE+1ANtOzJJELGpYoG2961z0Z6OAld9A==",
+ "requires": {
+ "tslib": "^1.9.0"
+ }
+ },
+ "ci-info": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz",
+ "integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ=="
+ },
+ "cipher-base": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.4.tgz",
+ "integrity": "sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q==",
+ "requires": {
+ "inherits": "^2.0.1",
+ "safe-buffer": "^5.0.1"
+ }
+ },
+ "class-utils": {
+ "version": "0.3.6",
+ "resolved": "https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz",
+ "integrity": "sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==",
+ "requires": {
+ "arr-union": "^3.1.0",
+ "define-property": "^0.2.5",
+ "isobject": "^3.0.0",
+ "static-extend": "^0.1.1"
+ },
+ "dependencies": {
+ "define-property": {
+ "version": "0.2.5",
+ "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz",
+ "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=",
+ "requires": {
+ "is-descriptor": "^0.1.0"
+ }
+ }
+ }
+ },
+ "clean-webpack-plugin": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/clean-webpack-plugin/-/clean-webpack-plugin-2.0.1.tgz",
+ "integrity": "sha512-vway5pXGVd91bicwjaf8j188Al6VMf9R9Ekl6q0qeiaWStRsOOXuh4qtjX1UrUvmz5XevQVCdjBuzr4Tzsnpog==",
+ "requires": {
+ "del": "^4.0.0"
+ },
+ "dependencies": {
+ "del": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/del/-/del-4.0.0.tgz",
+ "integrity": "sha512-/BnSJ+SuZyLu7xMn48kZY0nMXDi+5KNmR4g8n21Wivsl8+B9njV6/5kcTNE9juSprp0zRWBU28JuHUq0FqK1Nw==",
+ "requires": {
+ "globby": "^6.1.0",
+ "is-path-cwd": "^2.0.0",
+ "is-path-in-cwd": "^2.0.0",
+ "p-map": "^2.0.0",
+ "pify": "^4.0.1",
+ "rimraf": "^2.6.2"
+ }
+ },
+ "is-path-cwd": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-2.0.0.tgz",
+ "integrity": "sha512-m5dHHzpOXEiv18JEORttBO64UgTEypx99vCxQLjbBvGhOJxnTNglYoFXxwo6AbsQb79sqqycQEHv2hWkHZAijA=="
+ },
+ "is-path-in-cwd": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/is-path-in-cwd/-/is-path-in-cwd-2.0.0.tgz",
+ "integrity": "sha512-6Vz5Gc9s/sDA3JBVu0FzWufm8xaBsqy1zn8Q6gmvGP6nSDMw78aS4poBNeatWjaRpTpxxLn1WOndAiOlk+qY8A==",
+ "requires": {
+ "is-path-inside": "^1.0.0"
+ }
+ },
+ "p-map": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/p-map/-/p-map-2.0.0.tgz",
+ "integrity": "sha512-GO107XdrSUmtHxVoi60qc9tUl/KkNKm+X2CF4P9amalpGxv5YqVPJNfSb0wcA+syCopkZvYYIzW8OVTQW59x/w=="
+ },
+ "pify": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz",
+ "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g=="
+ }
+ }
+ },
+ "cli-cursor": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-2.1.0.tgz",
+ "integrity": "sha1-s12sN2R5+sw+lHR9QdDQ9SOP/LU=",
+ "requires": {
+ "restore-cursor": "^2.0.0"
+ }
+ },
+ "cli-width": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-2.2.0.tgz",
+ "integrity": "sha1-/xnt6Kml5XkyQUewwR8PvLq+1jk="
+ },
+ "cliui": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/cliui/-/cliui-4.1.0.tgz",
+ "integrity": "sha512-4FG+RSG9DL7uEwRUZXZn3SS34DiDPfzP0VOiEwtUWlE+AR2EIg+hSyvrIgUUfhdgR/UkAeW2QHgeP+hWrXs7jQ==",
+ "requires": {
+ "string-width": "^2.1.1",
+ "strip-ansi": "^4.0.0",
+ "wrap-ansi": "^2.0.0"
+ }
+ },
+ "co": {
+ "version": "4.6.0",
+ "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz",
+ "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ="
+ },
+ "code-point-at": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz",
+ "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c="
+ },
+ "collection-visit": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz",
+ "integrity": "sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA=",
+ "requires": {
+ "map-visit": "^1.0.0",
+ "object-visit": "^1.0.0"
+ }
+ },
+ "color-convert": {
+ "version": "1.9.3",
+ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
+ "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
+ "requires": {
+ "color-name": "1.1.3"
+ }
+ },
+ "color-name": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
+ "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU="
+ },
+ "combined-stream": {
+ "version": "1.0.7",
+ "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.7.tgz",
+ "integrity": "sha512-brWl9y6vOB1xYPZcpZde3N9zDByXTosAeMDo4p1wzo6UMOX4vumB+TP1RZ76sfE6Md68Q0NJSrE/gbezd4Ul+w==",
+ "requires": {
+ "delayed-stream": "~1.0.0"
+ }
+ },
+ "commander": {
+ "version": "2.19.0",
+ "resolved": "https://registry.npmjs.org/commander/-/commander-2.19.0.tgz",
+ "integrity": "sha512-6tvAOO+D6OENvRAh524Dh9jcfKTYDQAqvqezbCW82xj5X0pSrcpxtvRKHLG0yBY6SD7PSDrJaj+0AiOcKVd1Xg=="
+ },
+ "commondir": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz",
+ "integrity": "sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs="
+ },
+ "compare-versions": {
+ "version": "3.4.0",
+ "resolved": "https://registry.npmjs.org/compare-versions/-/compare-versions-3.4.0.tgz",
+ "integrity": "sha512-tK69D7oNXXqUW3ZNo/z7NXTEz22TCF0pTE+YF9cxvaAM9XnkLo1fV621xCLrRR6aevJlKxExkss0vWqUCUpqdg=="
+ },
+ "component-emitter": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.2.1.tgz",
+ "integrity": "sha1-E3kY1teCg/ffemt8WmPhQOaUJeY="
+ },
+ "compressible": {
+ "version": "2.0.16",
+ "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.16.tgz",
+ "integrity": "sha512-JQfEOdnI7dASwCuSPWIeVYwc/zMsu/+tRhoUvEfXz2gxOA2DNjmG5vhtFdBlhWPPGo+RdT9S3tgc/uH5qgDiiA==",
+ "requires": {
+ "mime-db": ">= 1.38.0 < 2"
+ }
+ },
+ "compression": {
+ "version": "1.7.4",
+ "resolved": "https://registry.npmjs.org/compression/-/compression-1.7.4.tgz",
+ "integrity": "sha512-jaSIDzP9pZVS4ZfQ+TzvtiWhdpFhE2RDHz8QJkpX9SIpLq88VueF5jJw6t+6CUQcAoA6t+x89MLrWAqpfDE8iQ==",
+ "requires": {
+ "accepts": "~1.3.5",
+ "bytes": "3.0.0",
+ "compressible": "~2.0.16",
+ "debug": "2.6.9",
+ "on-headers": "~1.0.2",
+ "safe-buffer": "5.1.2",
+ "vary": "~1.1.2"
+ }
+ },
+ "concat-map": {
+ "version": "0.0.1",
+ "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
+ "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s="
+ },
+ "concat-stream": {
+ "version": "1.6.2",
+ "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz",
+ "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==",
+ "requires": {
+ "buffer-from": "^1.0.0",
+ "inherits": "^2.0.3",
+ "readable-stream": "^2.2.2",
+ "typedarray": "^0.0.6"
+ }
+ },
+ "connect-history-api-fallback": {
+ "version": "1.6.0",
+ "resolved": "https://registry.npmjs.org/connect-history-api-fallback/-/connect-history-api-fallback-1.6.0.tgz",
+ "integrity": "sha512-e54B99q/OUoH64zYYRf3HBP5z24G38h5D3qXu23JGRoigpX5Ss4r9ZnDk3g0Z8uQC2x2lPaJ+UlWBc1ZWBWdLg=="
+ },
+ "console-browserify": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/console-browserify/-/console-browserify-1.1.0.tgz",
+ "integrity": "sha1-8CQcRXMKn8YyOyBtvzjtx0HQuxA=",
+ "requires": {
+ "date-now": "^0.1.4"
+ }
+ },
+ "constants-browserify": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/constants-browserify/-/constants-browserify-1.0.0.tgz",
+ "integrity": "sha1-wguW2MYXdIqvHBYCF2DNJ/y4y3U="
+ },
+ "content-disposition": {
+ "version": "0.5.2",
+ "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.2.tgz",
+ "integrity": "sha1-DPaLud318r55YcOoUXjLhdunjLQ="
+ },
+ "content-type": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz",
+ "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA=="
+ },
+ "convert-source-map": {
+ "version": "1.6.0",
+ "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.6.0.tgz",
+ "integrity": "sha512-eFu7XigvxdZ1ETfbgPBohgyQ/Z++C0eEhTor0qRwBw9unw+L0/6V8wkSuGgzdThkiS5lSpdptOQPD8Ak40a+7A==",
+ "requires": {
+ "safe-buffer": "~5.1.1"
+ }
+ },
+ "cookie": {
+ "version": "0.3.1",
+ "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.3.1.tgz",
+ "integrity": "sha1-5+Ch+e9DtMi6klxcWpboBtFoc7s="
+ },
+ "cookie-signature": {
+ "version": "1.0.6",
+ "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz",
+ "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw="
+ },
+ "copy-concurrently": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/copy-concurrently/-/copy-concurrently-1.0.5.tgz",
+ "integrity": "sha512-f2domd9fsVDFtaFcbaRZuYXwtdmnzqbADSwhSWYxYB/Q8zsdUUFMXVRwXGDMWmbEzAn1kdRrtI1T/KTFOL4X2A==",
+ "requires": {
+ "aproba": "^1.1.1",
+ "fs-write-stream-atomic": "^1.0.8",
+ "iferr": "^0.1.5",
+ "mkdirp": "^0.5.1",
+ "rimraf": "^2.5.4",
+ "run-queue": "^1.0.0"
+ }
+ },
+ "copy-descriptor": {
+ "version": "0.1.1",
+ "resolved": "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz",
+ "integrity": "sha1-Z29us8OZl8LuGsOpJP1hJHSPV40="
+ },
+ "core-util-is": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz",
+ "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac="
+ },
+ "cosmiconfig": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-4.0.0.tgz",
+ "integrity": "sha512-6e5vDdrXZD+t5v0L8CrurPeybg4Fmf+FCSYxXKYVAqLUtyCSbuyqE059d0kDthTNRzKVjL7QMgNpEUlsoYH3iQ==",
+ "requires": {
+ "is-directory": "^0.3.1",
+ "js-yaml": "^3.9.0",
+ "parse-json": "^4.0.0",
+ "require-from-string": "^2.0.1"
+ }
+ },
+ "create-ecdh": {
+ "version": "4.0.3",
+ "resolved": "https://registry.npmjs.org/create-ecdh/-/create-ecdh-4.0.3.tgz",
+ "integrity": "sha512-GbEHQPMOswGpKXM9kCWVrremUcBmjteUaQ01T9rkKCPDXfUHX0IoP9LpHYo2NPFampa4e+/pFDc3jQdxrxQLaw==",
+ "requires": {
+ "bn.js": "^4.1.0",
+ "elliptic": "^6.0.0"
+ }
+ },
+ "create-hash": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz",
+ "integrity": "sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==",
+ "requires": {
+ "cipher-base": "^1.0.1",
+ "inherits": "^2.0.1",
+ "md5.js": "^1.3.4",
+ "ripemd160": "^2.0.1",
+ "sha.js": "^2.4.0"
+ }
+ },
+ "create-hmac": {
+ "version": "1.1.7",
+ "resolved": "https://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz",
+ "integrity": "sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==",
+ "requires": {
+ "cipher-base": "^1.0.3",
+ "create-hash": "^1.1.0",
+ "inherits": "^2.0.1",
+ "ripemd160": "^2.0.0",
+ "safe-buffer": "^5.0.1",
+ "sha.js": "^2.4.8"
+ }
+ },
+ "cross-spawn": {
+ "version": "6.0.5",
+ "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz",
+ "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==",
+ "requires": {
+ "nice-try": "^1.0.4",
+ "path-key": "^2.0.1",
+ "semver": "^5.5.0",
+ "shebang-command": "^1.2.0",
+ "which": "^1.2.9"
+ }
+ },
+ "crypto-browserify": {
+ "version": "3.12.0",
+ "resolved": "https://registry.npmjs.org/crypto-browserify/-/crypto-browserify-3.12.0.tgz",
+ "integrity": "sha512-fz4spIh+znjO2VjL+IdhEpRJ3YN6sMzITSBijk6FK2UvTqruSQW+/cCZTSNsMiZNvUeq0CqurF+dAbyiGOY6Wg==",
+ "requires": {
+ "browserify-cipher": "^1.0.0",
+ "browserify-sign": "^4.0.0",
+ "create-ecdh": "^4.0.0",
+ "create-hash": "^1.1.0",
+ "create-hmac": "^1.1.0",
+ "diffie-hellman": "^5.0.0",
+ "inherits": "^2.0.1",
+ "pbkdf2": "^3.0.3",
+ "public-encrypt": "^4.0.0",
+ "randombytes": "^2.0.0",
+ "randomfill": "^1.0.3"
+ }
+ },
+ "css-loader": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-2.1.1.tgz",
+ "integrity": "sha512-OcKJU/lt232vl1P9EEDamhoO9iKY3tIjY5GU+XDLblAykTdgs6Ux9P1hTHve8nFKy5KPpOXOsVI/hIwi3841+w==",
+ "requires": {
+ "camelcase": "^5.2.0",
+ "icss-utils": "^4.1.0",
+ "loader-utils": "^1.2.3",
+ "normalize-path": "^3.0.0",
+ "postcss": "^7.0.14",
+ "postcss-modules-extract-imports": "^2.0.0",
+ "postcss-modules-local-by-default": "^2.0.6",
+ "postcss-modules-scope": "^2.1.0",
+ "postcss-modules-values": "^2.0.0",
+ "postcss-value-parser": "^3.3.0",
+ "schema-utils": "^1.0.0"
+ }
+ },
+ "cssesc": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz",
+ "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg=="
+ },
+ "cssom": {
+ "version": "0.3.6",
+ "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.3.6.tgz",
+ "integrity": "sha512-DtUeseGk9/GBW0hl0vVPpU22iHL6YB5BUX7ml1hB+GMpo0NX5G4voX3kdWiMSEguFtcW3Vh3djqNF4aIe6ne0A=="
+ },
+ "cssstyle": {
+ "version": "1.2.2",
+ "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-1.2.2.tgz",
+ "integrity": "sha512-43wY3kl1CVQSvL7wUY1qXkxVGkStjpkDmVjiIKX8R97uhajy8Bybay78uOtqvh7Q5GK75dNPfW0geWjE6qQQow==",
+ "requires": {
+ "cssom": "0.3.x"
+ }
+ },
+ "cyclist": {
+ "version": "0.2.2",
+ "resolved": "https://registry.npmjs.org/cyclist/-/cyclist-0.2.2.tgz",
+ "integrity": "sha1-GzN5LhHpFKL9bW7WRHRkRE5fpkA="
+ },
+ "d": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/d/-/d-1.0.0.tgz",
+ "integrity": "sha1-dUu1v+VUUdpppYuU1F9MWwRi1Y8=",
+ "requires": {
+ "es5-ext": "^0.10.9"
+ }
+ },
+ "d3-path": {
+ "version": "1.0.7",
+ "resolved": "https://registry.npmjs.org/d3-path/-/d3-path-1.0.7.tgz",
+ "integrity": "sha512-q0cW1RpvA5c5ma2rch62mX8AYaiLX0+bdaSM2wxSU9tXjU4DNvkx9qiUvjkuWCj3p22UO/hlPivujqMiR9PDzA=="
+ },
+ "d3-shape": {
+ "version": "1.3.5",
+ "resolved": "https://registry.npmjs.org/d3-shape/-/d3-shape-1.3.5.tgz",
+ "integrity": "sha512-VKazVR3phgD+MUCldapHD7P9kcrvPcexeX/PkMJmkUov4JM8IxsSg1DvbYoYich9AtdTsa5nNk2++ImPiDiSxg==",
+ "requires": {
+ "d3-path": "1"
+ }
+ },
+ "dashdash": {
+ "version": "1.14.1",
+ "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz",
+ "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=",
+ "requires": {
+ "assert-plus": "^1.0.0"
+ }
+ },
+ "data-urls": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-1.1.0.tgz",
+ "integrity": "sha512-YTWYI9se1P55u58gL5GkQHW4P6VJBJ5iBT+B5a7i2Tjadhv52paJG0qHX4A0OR6/t52odI64KP2YvFpkDOi3eQ==",
+ "requires": {
+ "abab": "^2.0.0",
+ "whatwg-mimetype": "^2.2.0",
+ "whatwg-url": "^7.0.0"
+ },
+ "dependencies": {
+ "whatwg-url": {
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-7.0.0.tgz",
+ "integrity": "sha512-37GeVSIJ3kn1JgKyjiYNmSLP1yzbpb29jdmwBSgkD9h40/hyrR/OifpVUndji3tmwGgD8qpw7iQu3RSbCrBpsQ==",
+ "requires": {
+ "lodash.sortby": "^4.7.0",
+ "tr46": "^1.0.1",
+ "webidl-conversions": "^4.0.2"
+ }
+ }
+ }
+ },
+ "date-now": {
+ "version": "0.1.4",
+ "resolved": "https://registry.npmjs.org/date-now/-/date-now-0.1.4.tgz",
+ "integrity": "sha1-6vQ5/U1ISK105cx9vvIAZyueNFs="
+ },
+ "debug": {
+ "version": "2.6.9",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
+ "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
+ "requires": {
+ "ms": "2.0.0"
+ }
+ },
+ "decamelize": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz",
+ "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA="
+ },
+ "decode-uri-component": {
+ "version": "0.2.0",
+ "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz",
+ "integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU="
+ },
+ "deep-equal": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-1.0.1.tgz",
+ "integrity": "sha1-9dJgKStmDghO/0zbyfCK0yR0SLU="
+ },
+ "deep-is": {
+ "version": "0.1.3",
+ "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz",
+ "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ="
+ },
+ "default-gateway": {
+ "version": "4.2.0",
+ "resolved": "https://registry.npmjs.org/default-gateway/-/default-gateway-4.2.0.tgz",
+ "integrity": "sha512-h6sMrVB1VMWVrW13mSc6ia/DwYYw5MN6+exNu1OaJeFac5aSAvwM7lZ0NVfTABuSkQelr4h5oebg3KB1XPdjgA==",
+ "requires": {
+ "execa": "^1.0.0",
+ "ip-regex": "^2.1.0"
+ }
+ },
+ "default-require-extensions": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/default-require-extensions/-/default-require-extensions-2.0.0.tgz",
+ "integrity": "sha1-9fj7sYp9bVCyH2QfZJ67Uiz+JPc=",
+ "requires": {
+ "strip-bom": "^3.0.0"
+ }
+ },
+ "define-properties": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz",
+ "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==",
+ "requires": {
+ "object-keys": "^1.0.12"
+ }
+ },
+ "define-property": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz",
+ "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==",
+ "requires": {
+ "is-descriptor": "^1.0.2",
+ "isobject": "^3.0.1"
+ },
+ "dependencies": {
+ "is-accessor-descriptor": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz",
+ "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==",
+ "requires": {
+ "kind-of": "^6.0.0"
+ }
+ },
+ "is-data-descriptor": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz",
+ "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==",
+ "requires": {
+ "kind-of": "^6.0.0"
+ }
+ },
+ "is-descriptor": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz",
+ "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==",
+ "requires": {
+ "is-accessor-descriptor": "^1.0.0",
+ "is-data-descriptor": "^1.0.0",
+ "kind-of": "^6.0.2"
+ }
+ }
+ }
+ },
+ "del": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/del/-/del-4.1.0.tgz",
+ "integrity": "sha512-C4kvKNlYrwXhKxz97BuohF8YoGgQ23Xm9lvoHmgT7JaPGprSEjk3+XFled74Yt/x0ZABUHg2D67covzAPUKx5Q==",
+ "requires": {
+ "globby": "^6.1.0",
+ "is-path-cwd": "^2.0.0",
+ "is-path-in-cwd": "^2.0.0",
+ "p-map": "^2.0.0",
+ "pify": "^4.0.1",
+ "rimraf": "^2.6.3"
+ },
+ "dependencies": {
+ "pify": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz",
+ "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g=="
+ }
+ }
+ },
+ "delayed-stream": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
+ "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk="
+ },
+ "depd": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz",
+ "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak="
+ },
+ "des.js": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/des.js/-/des.js-1.0.0.tgz",
+ "integrity": "sha1-wHTS4qpqipoH29YfmhXCzYPsjsw=",
+ "requires": {
+ "inherits": "^2.0.1",
+ "minimalistic-assert": "^1.0.0"
+ }
+ },
+ "destroy": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz",
+ "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA="
+ },
+ "detect-file": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/detect-file/-/detect-file-1.0.0.tgz",
+ "integrity": "sha1-8NZtA2cqglyxtzvbP+YjEMjlUrc="
+ },
+ "detect-newline": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-2.1.0.tgz",
+ "integrity": "sha1-9B8cEL5LAOh7XxPaaAdZ8sW/0+I="
+ },
+ "detect-node": {
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/detect-node/-/detect-node-2.0.4.tgz",
+ "integrity": "sha512-ZIzRpLJrOj7jjP2miAtgqIfmzbxa4ZOr5jJc601zklsfEx9oTzmmj2nVpIPRpNlRTIh8lc1kyViIY7BWSGNmKw=="
+ },
+ "diff-sequences": {
+ "version": "24.3.0",
+ "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-24.3.0.tgz",
+ "integrity": "sha512-xLqpez+Zj9GKSnPWS0WZw1igGocZ+uua8+y+5dDNTT934N3QuY1sp2LkHzwiaYQGz60hMq0pjAshdeXm5VUOEw=="
+ },
+ "diffie-hellman": {
+ "version": "5.0.3",
+ "resolved": "https://registry.npmjs.org/diffie-hellman/-/diffie-hellman-5.0.3.tgz",
+ "integrity": "sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg==",
+ "requires": {
+ "bn.js": "^4.1.0",
+ "miller-rabin": "^4.0.0",
+ "randombytes": "^2.0.0"
+ }
+ },
+ "dns-equal": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/dns-equal/-/dns-equal-1.0.0.tgz",
+ "integrity": "sha1-s55/HabrCnW6nBcySzR1PEfgZU0="
+ },
+ "dns-packet": {
+ "version": "1.3.1",
+ "resolved": "https://registry.npmjs.org/dns-packet/-/dns-packet-1.3.1.tgz",
+ "integrity": "sha512-0UxfQkMhYAUaZI+xrNZOz/as5KgDU0M/fQ9b6SpkyLbk3GEswDi6PADJVaYJradtRVsRIlF1zLyOodbcTCDzUg==",
+ "requires": {
+ "ip": "^1.1.0",
+ "safe-buffer": "^5.0.1"
+ }
+ },
+ "dns-txt": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/dns-txt/-/dns-txt-2.0.2.tgz",
+ "integrity": "sha1-uR2Ab10nGI5Ks+fRB9iBocxGQrY=",
+ "requires": {
+ "buffer-indexof": "^1.0.0"
+ }
+ },
+ "doctrine": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz",
+ "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==",
+ "requires": {
+ "esutils": "^2.0.2"
+ }
+ },
+ "domain-browser": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/domain-browser/-/domain-browser-1.2.0.tgz",
+ "integrity": "sha512-jnjyiM6eRyZl2H+W8Q/zLMA481hzi0eszAaBUzIVnmYVDBbnLxVNnfu1HgEBvCbL+71FrxMl3E6lpKH7Ge3OXA=="
+ },
+ "domexception": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/domexception/-/domexception-1.0.1.tgz",
+ "integrity": "sha512-raigMkn7CJNNo6Ihro1fzG7wr3fHuYVytzquZKX5n0yizGsTcYgzdIUwj1X9pK0VvjeihV+XiclP+DjwbsSKug==",
+ "requires": {
+ "webidl-conversions": "^4.0.2"
+ }
+ },
+ "duplexify": {
+ "version": "3.7.1",
+ "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-3.7.1.tgz",
+ "integrity": "sha512-07z8uv2wMyS51kKhD1KsdXJg5WQ6t93RneqRxUHnskXVtlYYkLqM0gqStQZ3pj073g687jPCHrqNfCzawLYh5g==",
+ "requires": {
+ "end-of-stream": "^1.0.0",
+ "inherits": "^2.0.1",
+ "readable-stream": "^2.0.0",
+ "stream-shift": "^1.0.0"
+ }
+ },
+ "ecc-jsbn": {
+ "version": "0.1.2",
+ "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz",
+ "integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=",
+ "requires": {
+ "jsbn": "~0.1.0",
+ "safer-buffer": "^2.1.0"
+ }
+ },
+ "ee-first": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
+ "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0="
+ },
+ "elliptic": {
+ "version": "6.4.1",
+ "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.4.1.tgz",
+ "integrity": "sha512-BsXLz5sqX8OHcsh7CqBMztyXARmGQ3LWPtGjJi6DiJHq5C/qvi9P3OqgswKSDftbu8+IoI/QDTAm2fFnQ9SZSQ==",
+ "requires": {
+ "bn.js": "^4.4.0",
+ "brorand": "^1.0.1",
+ "hash.js": "^1.0.0",
+ "hmac-drbg": "^1.0.0",
+ "inherits": "^2.0.1",
+ "minimalistic-assert": "^1.0.0",
+ "minimalistic-crypto-utils": "^1.0.0"
+ }
+ },
+ "emoji-regex": {
+ "version": "7.0.3",
+ "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz",
+ "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA=="
+ },
+ "emojis-list": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-2.1.0.tgz",
+ "integrity": "sha1-TapNnbAPmBmIDHn6RXrlsJof04k="
+ },
+ "encodeurl": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz",
+ "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k="
+ },
+ "end-of-stream": {
+ "version": "1.4.1",
+ "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.1.tgz",
+ "integrity": "sha512-1MkrZNvWTKCaigbn+W15elq2BB/L22nqrSY5DKlo3X6+vclJm8Bb5djXJBmEX6fS3+zCh/F4VBK5Z2KxJt4s2Q==",
+ "requires": {
+ "once": "^1.4.0"
+ }
+ },
+ "enhanced-resolve": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-4.1.0.tgz",
+ "integrity": "sha512-F/7vkyTtyc/llOIn8oWclcB25KdRaiPBpZYDgJHgh/UHtpgT2p2eldQgtQnLtUvfMKPKxbRaQM/hHkvLHt1Vng==",
+ "requires": {
+ "graceful-fs": "^4.1.2",
+ "memory-fs": "^0.4.0",
+ "tapable": "^1.0.0"
+ }
+ },
+ "errno": {
+ "version": "0.1.7",
+ "resolved": "https://registry.npmjs.org/errno/-/errno-0.1.7.tgz",
+ "integrity": "sha512-MfrRBDWzIWifgq6tJj60gkAwtLNb6sQPlcFrSOflcP1aFmmruKQ2wRnze/8V6kgyz7H3FF8Npzv78mZ7XLLflg==",
+ "requires": {
+ "prr": "~1.0.1"
+ }
+ },
+ "error-ex": {
+ "version": "1.3.2",
+ "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz",
+ "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==",
+ "requires": {
+ "is-arrayish": "^0.2.1"
+ }
+ },
+ "es-abstract": {
+ "version": "1.13.0",
+ "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.13.0.tgz",
+ "integrity": "sha512-vDZfg/ykNxQVwup/8E1BZhVzFfBxs9NqMzGcvIJrqg5k2/5Za2bWo40dK2J1pgLngZ7c+Shh8lwYtLGyrwPutg==",
+ "requires": {
+ "es-to-primitive": "^1.2.0",
+ "function-bind": "^1.1.1",
+ "has": "^1.0.3",
+ "is-callable": "^1.1.4",
+ "is-regex": "^1.0.4",
+ "object-keys": "^1.0.12"
+ }
+ },
+ "es-to-primitive": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.0.tgz",
+ "integrity": "sha512-qZryBOJjV//LaxLTV6UC//WewneB3LcXOL9NP++ozKVXsIIIpm/2c13UDiD9Jp2eThsecw9m3jPqDwTyobcdbg==",
+ "requires": {
+ "is-callable": "^1.1.4",
+ "is-date-object": "^1.0.1",
+ "is-symbol": "^1.0.2"
+ }
+ },
+ "es5-ext": {
+ "version": "0.10.47",
+ "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.47.tgz",
+ "integrity": "sha512-/1TItLfj+TTfWoeRcDn/0FbGV6SNo4R+On2GGVucPU/j3BWnXE2Co8h8CTo4Tu34gFJtnmwS9xiScKs4EjZhdw==",
+ "requires": {
+ "es6-iterator": "~2.0.3",
+ "es6-symbol": "~3.1.1",
+ "next-tick": "1"
+ }
+ },
+ "es6-iterator": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.3.tgz",
+ "integrity": "sha1-p96IkUGgWpSwhUQDstCg+/qY87c=",
+ "requires": {
+ "d": "1",
+ "es5-ext": "^0.10.35",
+ "es6-symbol": "^3.1.1"
+ }
+ },
+ "es6-symbol": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.1.tgz",
+ "integrity": "sha1-vwDvT9q2uhtG7Le2KbTH7VcVzHc=",
+ "requires": {
+ "d": "1",
+ "es5-ext": "~0.10.14"
+ }
+ },
+ "escape-html": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz",
+ "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg="
+ },
+ "escape-string-regexp": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
+ "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ="
+ },
+ "escodegen": {
+ "version": "1.11.1",
+ "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.11.1.tgz",
+ "integrity": "sha512-JwiqFD9KdGVVpeuRa68yU3zZnBEOcPs0nKW7wZzXky8Z7tffdYUHbe11bPCV5jYlK6DVdKLWLm0f5I/QlL0Kmw==",
+ "requires": {
+ "esprima": "^3.1.3",
+ "estraverse": "^4.2.0",
+ "esutils": "^2.0.2",
+ "optionator": "^0.8.1",
+ "source-map": "~0.6.1"
+ },
+ "dependencies": {
+ "esprima": {
+ "version": "3.1.3",
+ "resolved": "https://registry.npmjs.org/esprima/-/esprima-3.1.3.tgz",
+ "integrity": "sha1-/cpRzuYTOJXjyI1TXOSdv/YqRjM="
+ },
+ "source-map": {
+ "version": "0.6.1",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
+ "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
+ "optional": true
+ }
+ }
+ },
+ "eslint": {
+ "version": "5.16.0",
+ "resolved": "https://registry.npmjs.org/eslint/-/eslint-5.16.0.tgz",
+ "integrity": "sha512-S3Rz11i7c8AA5JPv7xAH+dOyq/Cu/VXHiHXBPOU1k/JAM5dXqQPt3qcrhpHSorXmrpu2g0gkIBVXAqCpzfoZIg==",
+ "requires": {
+ "@babel/code-frame": "^7.0.0",
+ "ajv": "^6.9.1",
+ "chalk": "^2.1.0",
+ "cross-spawn": "^6.0.5",
+ "debug": "^4.0.1",
+ "doctrine": "^3.0.0",
+ "eslint-scope": "^4.0.3",
+ "eslint-utils": "^1.3.1",
+ "eslint-visitor-keys": "^1.0.0",
+ "espree": "^5.0.1",
+ "esquery": "^1.0.1",
+ "esutils": "^2.0.2",
+ "file-entry-cache": "^5.0.1",
+ "functional-red-black-tree": "^1.0.1",
+ "glob": "^7.1.2",
+ "globals": "^11.7.0",
+ "ignore": "^4.0.6",
+ "import-fresh": "^3.0.0",
+ "imurmurhash": "^0.1.4",
+ "inquirer": "^6.2.2",
+ "js-yaml": "^3.13.0",
+ "json-stable-stringify-without-jsonify": "^1.0.1",
+ "levn": "^0.3.0",
+ "lodash": "^4.17.11",
+ "minimatch": "^3.0.4",
+ "mkdirp": "^0.5.1",
+ "natural-compare": "^1.4.0",
+ "optionator": "^0.8.2",
+ "path-is-inside": "^1.0.2",
+ "progress": "^2.0.0",
+ "regexpp": "^2.0.1",
+ "semver": "^5.5.1",
+ "strip-ansi": "^4.0.0",
+ "strip-json-comments": "^2.0.1",
+ "table": "^5.2.3",
+ "text-table": "^0.2.0"
+ },
+ "dependencies": {
+ "debug": {
+ "version": "4.1.1",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz",
+ "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==",
+ "requires": {
+ "ms": "^2.1.1"
+ }
+ },
+ "js-yaml": {
+ "version": "3.13.1",
+ "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz",
+ "integrity": "sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==",
+ "requires": {
+ "argparse": "^1.0.7",
+ "esprima": "^4.0.0"
+ }
+ },
+ "ms": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz",
+ "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg=="
+ },
+ "semver": {
+ "version": "5.7.0",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.0.tgz",
+ "integrity": "sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA=="
+ }
+ }
+ },
+ "eslint-config-prettier": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-4.1.0.tgz",
+ "integrity": "sha512-zILwX9/Ocz4SV2vX7ox85AsrAgXV3f2o2gpIicdMIOra48WYqgUnWNH/cR/iHtmD2Vb3dLSC3LiEJnS05Gkw7w==",
+ "requires": {
+ "get-stdin": "^6.0.0"
+ }
+ },
+ "eslint-plugin-prettier": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-3.0.1.tgz",
+ "integrity": "sha512-/PMttrarPAY78PLvV3xfWibMOdMDl57hmlQ2XqFeA37wd+CJ7WSxV7txqjVPHi/AAFKd2lX0ZqfsOc/i5yFCSQ==",
+ "requires": {
+ "prettier-linter-helpers": "^1.0.0"
+ }
+ },
+ "eslint-scope": {
+ "version": "4.0.3",
+ "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-4.0.3.tgz",
+ "integrity": "sha512-p7VutNr1O/QrxysMo3E45FjYDTeXBy0iTltPFNSqKAIfjDSXC+4dj+qfyuD8bfAXrW/y6lW3O76VaYNPKfpKrg==",
+ "requires": {
+ "esrecurse": "^4.1.0",
+ "estraverse": "^4.1.1"
+ }
+ },
+ "eslint-utils": {
+ "version": "1.3.1",
+ "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-1.3.1.tgz",
+ "integrity": "sha512-Z7YjnIldX+2XMcjr7ZkgEsOj/bREONV60qYeB/bjMAqqqZ4zxKyWX+BOUkdmRmA9riiIPVvo5x86m5elviOk0Q=="
+ },
+ "eslint-visitor-keys": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz",
+ "integrity": "sha512-qzm/XxIbxm/FHyH341ZrbnMUpe+5Bocte9xkmFMzPMjRaZMcXww+MpBptFvtU+79L362nqiLhekCxCxDPaUMBQ=="
+ },
+ "espree": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/espree/-/espree-5.0.1.tgz",
+ "integrity": "sha512-qWAZcWh4XE/RwzLJejfcofscgMc9CamR6Tn1+XRXNzrvUSSbiAjGOI/fggztjIi7y9VLPqnICMIPiGyr8JaZ0A==",
+ "requires": {
+ "acorn": "^6.0.7",
+ "acorn-jsx": "^5.0.0",
+ "eslint-visitor-keys": "^1.0.0"
+ }
+ },
+ "esprima": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz",
+ "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A=="
+ },
+ "esquery": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.0.1.tgz",
+ "integrity": "sha512-SmiyZ5zIWH9VM+SRUReLS5Q8a7GxtRdxEBVZpm98rJM7Sb+A9DVCndXfkeFUd3byderg+EbDkfnevfCwynWaNA==",
+ "requires": {
+ "estraverse": "^4.0.0"
+ }
+ },
+ "esrecurse": {
+ "version": "4.2.1",
+ "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.2.1.tgz",
+ "integrity": "sha512-64RBB++fIOAXPw3P9cy89qfMlvZEXZkqqJkjqqXIvzP5ezRZjW+lPWjw35UX/3EhUPFYbg5ER4JYgDw4007/DQ==",
+ "requires": {
+ "estraverse": "^4.1.0"
+ }
+ },
+ "estraverse": {
+ "version": "4.2.0",
+ "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.2.0.tgz",
+ "integrity": "sha1-De4/7TH81GlhjOc0IJn8GvoL2xM="
+ },
+ "esutils": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz",
+ "integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs="
+ },
+ "etag": {
+ "version": "1.8.1",
+ "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz",
+ "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc="
+ },
+ "eventemitter3": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-3.1.0.tgz",
+ "integrity": "sha512-ivIvhpq/Y0uSjcHDcOIccjmYjGLcP09MFGE7ysAwkAvkXfpZlC985pH2/ui64DKazbTW/4kN3yqozUxlXzI6cA=="
+ },
+ "events": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/events/-/events-3.0.0.tgz",
+ "integrity": "sha512-Dc381HFWJzEOhQ+d8pkNon++bk9h6cdAoAj4iE6Q4y6xgTzySWXlKn05/TVNpjnfRqi/X0EpJEJohPjNI3zpVA=="
+ },
+ "eventsource": {
+ "version": "1.0.7",
+ "resolved": "https://registry.npmjs.org/eventsource/-/eventsource-1.0.7.tgz",
+ "integrity": "sha512-4Ln17+vVT0k8aWq+t/bF5arcS3EpT9gYtW66EPacdj/mAFevznsnyoHLPy2BA8gbIQeIHoPsvwmfBftfcG//BQ==",
+ "requires": {
+ "original": "^1.0.0"
+ }
+ },
+ "evp_bytestokey": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz",
+ "integrity": "sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA==",
+ "requires": {
+ "md5.js": "^1.3.4",
+ "safe-buffer": "^5.1.1"
+ }
+ },
+ "exec-sh": {
+ "version": "0.3.2",
+ "resolved": "https://registry.npmjs.org/exec-sh/-/exec-sh-0.3.2.tgz",
+ "integrity": "sha512-9sLAvzhI5nc8TpuQUh4ahMdCrWT00wPWz7j47/emR5+2qEfoZP5zzUXvx+vdx+H6ohhnsYC31iX04QLYJK8zTg=="
+ },
+ "execa": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/execa/-/execa-1.0.0.tgz",
+ "integrity": "sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==",
+ "requires": {
+ "cross-spawn": "^6.0.0",
+ "get-stream": "^4.0.0",
+ "is-stream": "^1.1.0",
+ "npm-run-path": "^2.0.0",
+ "p-finally": "^1.0.0",
+ "signal-exit": "^3.0.0",
+ "strip-eof": "^1.0.0"
+ }
+ },
+ "exit": {
+ "version": "0.1.2",
+ "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz",
+ "integrity": "sha1-BjJjj42HfMghB9MKD/8aF8uhzQw="
+ },
+ "expand-brackets": {
+ "version": "2.1.4",
+ "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz",
+ "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=",
+ "requires": {
+ "debug": "^2.3.3",
+ "define-property": "^0.2.5",
+ "extend-shallow": "^2.0.1",
+ "posix-character-classes": "^0.1.0",
+ "regex-not": "^1.0.0",
+ "snapdragon": "^0.8.1",
+ "to-regex": "^3.0.1"
+ },
+ "dependencies": {
+ "define-property": {
+ "version": "0.2.5",
+ "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz",
+ "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=",
+ "requires": {
+ "is-descriptor": "^0.1.0"
+ }
+ },
+ "extend-shallow": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
+ "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
+ "requires": {
+ "is-extendable": "^0.1.0"
+ }
+ }
+ }
+ },
+ "expand-tilde": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/expand-tilde/-/expand-tilde-2.0.2.tgz",
+ "integrity": "sha1-l+gBqgUt8CRU3kawK/YhZCzchQI=",
+ "requires": {
+ "homedir-polyfill": "^1.0.1"
+ }
+ },
+ "expect": {
+ "version": "24.7.1",
+ "resolved": "https://registry.npmjs.org/expect/-/expect-24.7.1.tgz",
+ "integrity": "sha512-mGfvMTPduksV3xoI0xur56pQsg2vJjNf5+a+bXOjqCkiCBbmCayrBbHS/75y9K430cfqyocPr2ZjiNiRx4SRKw==",
+ "requires": {
+ "@jest/types": "^24.7.0",
+ "ansi-styles": "^3.2.0",
+ "jest-get-type": "^24.3.0",
+ "jest-matcher-utils": "^24.7.0",
+ "jest-message-util": "^24.7.1",
+ "jest-regex-util": "^24.3.0"
+ }
+ },
+ "express": {
+ "version": "4.16.4",
+ "resolved": "https://registry.npmjs.org/express/-/express-4.16.4.tgz",
+ "integrity": "sha512-j12Uuyb4FMrd/qQAm6uCHAkPtO8FDTRJZBDd5D2KOL2eLaz1yUNdUB/NOIyq0iU4q4cFarsUCrnFDPBcnksuOg==",
+ "requires": {
+ "accepts": "~1.3.5",
+ "array-flatten": "1.1.1",
+ "body-parser": "1.18.3",
+ "content-disposition": "0.5.2",
+ "content-type": "~1.0.4",
+ "cookie": "0.3.1",
+ "cookie-signature": "1.0.6",
+ "debug": "2.6.9",
+ "depd": "~1.1.2",
+ "encodeurl": "~1.0.2",
+ "escape-html": "~1.0.3",
+ "etag": "~1.8.1",
+ "finalhandler": "1.1.1",
+ "fresh": "0.5.2",
+ "merge-descriptors": "1.0.1",
+ "methods": "~1.1.2",
+ "on-finished": "~2.3.0",
+ "parseurl": "~1.3.2",
+ "path-to-regexp": "0.1.7",
+ "proxy-addr": "~2.0.4",
+ "qs": "6.5.2",
+ "range-parser": "~1.2.0",
+ "safe-buffer": "5.1.2",
+ "send": "0.16.2",
+ "serve-static": "1.13.2",
+ "setprototypeof": "1.1.0",
+ "statuses": "~1.4.0",
+ "type-is": "~1.6.16",
+ "utils-merge": "1.0.1",
+ "vary": "~1.1.2"
+ },
+ "dependencies": {
+ "array-flatten": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz",
+ "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI="
+ }
+ }
+ },
+ "extend": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz",
+ "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g=="
+ },
+ "extend-shallow": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz",
+ "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=",
+ "requires": {
+ "assign-symbols": "^1.0.0",
+ "is-extendable": "^1.0.1"
+ },
+ "dependencies": {
+ "is-extendable": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz",
+ "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==",
+ "requires": {
+ "is-plain-object": "^2.0.4"
+ }
+ }
+ }
+ },
+ "external-editor": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.0.3.tgz",
+ "integrity": "sha512-bn71H9+qWoOQKyZDo25mOMVpSmXROAsTJVVVYzrrtol3d4y+AsKjf4Iwl2Q+IuT0kFSQ1qo166UuIwqYq7mGnA==",
+ "requires": {
+ "chardet": "^0.7.0",
+ "iconv-lite": "^0.4.24",
+ "tmp": "^0.0.33"
+ }
+ },
+ "extglob": {
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz",
+ "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==",
+ "requires": {
+ "array-unique": "^0.3.2",
+ "define-property": "^1.0.0",
+ "expand-brackets": "^2.1.4",
+ "extend-shallow": "^2.0.1",
+ "fragment-cache": "^0.2.1",
+ "regex-not": "^1.0.0",
+ "snapdragon": "^0.8.1",
+ "to-regex": "^3.0.1"
+ },
+ "dependencies": {
+ "define-property": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz",
+ "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=",
+ "requires": {
+ "is-descriptor": "^1.0.0"
+ }
+ },
+ "extend-shallow": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
+ "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
+ "requires": {
+ "is-extendable": "^0.1.0"
+ }
+ },
+ "is-accessor-descriptor": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz",
+ "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==",
+ "requires": {
+ "kind-of": "^6.0.0"
+ }
+ },
+ "is-data-descriptor": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz",
+ "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==",
+ "requires": {
+ "kind-of": "^6.0.0"
+ }
+ },
+ "is-descriptor": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz",
+ "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==",
+ "requires": {
+ "is-accessor-descriptor": "^1.0.0",
+ "is-data-descriptor": "^1.0.0",
+ "kind-of": "^6.0.2"
+ }
+ }
+ }
+ },
+ "extsprintf": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz",
+ "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU="
+ },
+ "fast-deep-equal": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz",
+ "integrity": "sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk="
+ },
+ "fast-diff": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.2.0.tgz",
+ "integrity": "sha512-xJuoT5+L99XlZ8twedaRf6Ax2TgQVxvgZOYoPKqZufmJib0tL2tegPBOZb1pVNgIhlqDlA0eO0c3wBvQcmzx4w=="
+ },
+ "fast-json-stable-stringify": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz",
+ "integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I="
+ },
+ "fast-levenshtein": {
+ "version": "2.0.6",
+ "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz",
+ "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc="
+ },
+ "faye-websocket": {
+ "version": "0.10.0",
+ "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.10.0.tgz",
+ "integrity": "sha1-TkkvjQTftviQA1B/btvy1QHnxvQ=",
+ "requires": {
+ "websocket-driver": ">=0.5.1"
+ }
+ },
+ "fb-watchman": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.0.tgz",
+ "integrity": "sha1-VOmr99+i8mzZsWNsWIwa/AXeXVg=",
+ "requires": {
+ "bser": "^2.0.0"
+ }
+ },
+ "figgy-pudding": {
+ "version": "3.5.1",
+ "resolved": "https://registry.npmjs.org/figgy-pudding/-/figgy-pudding-3.5.1.tgz",
+ "integrity": "sha512-vNKxJHTEKNThjfrdJwHc7brvM6eVevuO5nTj6ez8ZQ1qbXTvGthucRF7S4vf2cr71QVnT70V34v0S1DyQsti0w=="
+ },
+ "figures": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/figures/-/figures-2.0.0.tgz",
+ "integrity": "sha1-OrGi0qYsi/tDGgyUy3l6L84nyWI=",
+ "requires": {
+ "escape-string-regexp": "^1.0.5"
+ }
+ },
+ "file-entry-cache": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-5.0.1.tgz",
+ "integrity": "sha512-bCg29ictuBaKUwwArK4ouCaqDgLZcysCFLmM/Yn/FDoqndh/9vNuQfXRDvTuXKLxfD/JtZQGKFT8MGcJBK644g==",
+ "requires": {
+ "flat-cache": "^2.0.1"
+ }
+ },
+ "file-loader": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/file-loader/-/file-loader-3.0.1.tgz",
+ "integrity": "sha512-4sNIOXgtH/9WZq4NvlfU3Opn5ynUsqBwSLyM+I7UOwdGigTBYfVVQEwe/msZNX/j4pCJTIM14Fsw66Svo1oVrw==",
+ "requires": {
+ "loader-utils": "^1.0.2",
+ "schema-utils": "^1.0.0"
+ }
+ },
+ "fileset": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/fileset/-/fileset-2.0.3.tgz",
+ "integrity": "sha1-jnVIqW08wjJ+5eZ0FocjozO7oqA=",
+ "requires": {
+ "glob": "^7.0.3",
+ "minimatch": "^3.0.3"
+ }
+ },
+ "fill-range": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz",
+ "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=",
+ "requires": {
+ "extend-shallow": "^2.0.1",
+ "is-number": "^3.0.0",
+ "repeat-string": "^1.6.1",
+ "to-regex-range": "^2.1.0"
+ },
+ "dependencies": {
+ "extend-shallow": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
+ "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
+ "requires": {
+ "is-extendable": "^0.1.0"
+ }
+ }
+ }
+ },
+ "finalhandler": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.1.tgz",
+ "integrity": "sha512-Y1GUDo39ez4aHAw7MysnUD5JzYX+WaIj8I57kO3aEPT1fFRL4sr7mjei97FgnwhAyyzRYmQZaTHb2+9uZ1dPtg==",
+ "requires": {
+ "debug": "2.6.9",
+ "encodeurl": "~1.0.2",
+ "escape-html": "~1.0.3",
+ "on-finished": "~2.3.0",
+ "parseurl": "~1.3.2",
+ "statuses": "~1.4.0",
+ "unpipe": "~1.0.0"
+ }
+ },
+ "find-cache-dir": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-2.1.0.tgz",
+ "integrity": "sha512-Tq6PixE0w/VMFfCgbONnkiQIVol/JJL7nRMi20fqzA4NRs9AfeqMGeRdPi3wIhYkxjeBaWh2rxwapn5Tu3IqOQ==",
+ "requires": {
+ "commondir": "^1.0.1",
+ "make-dir": "^2.0.0",
+ "pkg-dir": "^3.0.0"
+ },
+ "dependencies": {
+ "make-dir": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz",
+ "integrity": "sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==",
+ "requires": {
+ "pify": "^4.0.1",
+ "semver": "^5.6.0"
+ }
+ },
+ "pify": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz",
+ "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g=="
+ },
+ "semver": {
+ "version": "5.7.0",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.0.tgz",
+ "integrity": "sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA=="
+ }
+ }
+ },
+ "find-up": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz",
+ "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==",
+ "requires": {
+ "locate-path": "^3.0.0"
+ }
+ },
+ "findup-sync": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/findup-sync/-/findup-sync-2.0.0.tgz",
+ "integrity": "sha1-kyaxSIwi0aYIhlCoaQGy2akKLLw=",
+ "requires": {
+ "detect-file": "^1.0.0",
+ "is-glob": "^3.1.0",
+ "micromatch": "^3.0.4",
+ "resolve-dir": "^1.0.1"
+ },
+ "dependencies": {
+ "is-glob": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz",
+ "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=",
+ "requires": {
+ "is-extglob": "^2.1.0"
+ }
+ }
+ }
+ },
+ "flat-cache": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-2.0.1.tgz",
+ "integrity": "sha512-LoQe6yDuUMDzQAEH8sgmh4Md6oZnc/7PjtwjNFSzveXqSHt6ka9fPBuso7IGf9Rz4uqnSnWiFH2B/zj24a5ReA==",
+ "requires": {
+ "flatted": "^2.0.0",
+ "rimraf": "2.6.3",
+ "write": "1.0.3"
+ }
+ },
+ "flatted": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/flatted/-/flatted-2.0.0.tgz",
+ "integrity": "sha512-R+H8IZclI8AAkSBRQJLVOsxwAoHd6WC40b4QTNWIjzAa6BXOBfQcM587MXDTVPeYaopFNWHUFLx7eNmHDSxMWg=="
+ },
+ "flush-write-stream": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/flush-write-stream/-/flush-write-stream-1.1.1.tgz",
+ "integrity": "sha512-3Z4XhFZ3992uIq0XOqb9AreonueSYphE6oYbpt5+3u06JWklbsPkNv3ZKkP9Bz/r+1MWCaMoSQ28P85+1Yc77w==",
+ "requires": {
+ "inherits": "^2.0.3",
+ "readable-stream": "^2.3.6"
+ }
+ },
+ "follow-redirects": {
+ "version": "1.7.0",
+ "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.7.0.tgz",
+ "integrity": "sha512-m/pZQy4Gj287eNy94nivy5wchN3Kp+Q5WgUPNy5lJSZ3sgkVKSYV/ZChMAQVIgx1SqfZ2zBZtPA2YlXIWxxJOQ==",
+ "requires": {
+ "debug": "^3.2.6"
+ },
+ "dependencies": {
+ "debug": {
+ "version": "3.2.6",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz",
+ "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==",
+ "requires": {
+ "ms": "^2.1.1"
+ }
+ },
+ "ms": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz",
+ "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg=="
+ }
+ }
+ },
+ "for-in": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz",
+ "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA="
+ },
+ "forever-agent": {
+ "version": "0.6.1",
+ "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz",
+ "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE="
+ },
+ "form-data": {
+ "version": "2.3.3",
+ "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz",
+ "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==",
+ "requires": {
+ "asynckit": "^0.4.0",
+ "combined-stream": "^1.0.6",
+ "mime-types": "^2.1.12"
+ }
+ },
+ "forwarded": {
+ "version": "0.1.2",
+ "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz",
+ "integrity": "sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ="
+ },
+ "fragment-cache": {
+ "version": "0.2.1",
+ "resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz",
+ "integrity": "sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk=",
+ "requires": {
+ "map-cache": "^0.2.2"
+ }
+ },
+ "fresh": {
+ "version": "0.5.2",
+ "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz",
+ "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac="
+ },
+ "from2": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/from2/-/from2-2.3.0.tgz",
+ "integrity": "sha1-i/tVAr3kpNNs/e6gB/zKIdfjgq8=",
+ "requires": {
+ "inherits": "^2.0.1",
+ "readable-stream": "^2.0.0"
+ }
+ },
+ "fs-write-stream-atomic": {
+ "version": "1.0.10",
+ "resolved": "https://registry.npmjs.org/fs-write-stream-atomic/-/fs-write-stream-atomic-1.0.10.tgz",
+ "integrity": "sha1-tH31NJPvkR33VzHnCp3tAYnbQMk=",
+ "requires": {
+ "graceful-fs": "^4.1.2",
+ "iferr": "^0.1.5",
+ "imurmurhash": "^0.1.4",
+ "readable-stream": "1 || 2"
+ }
+ },
+ "fs.realpath": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
+ "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8="
+ },
+ "fsevents": {
+ "version": "1.2.7",
+ "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.7.tgz",
+ "integrity": "sha512-Pxm6sI2MeBD7RdD12RYsqaP0nMiwx8eZBXCa6z2L+mRHm2DYrOYwihmhjpkdjUHwQhslWQjRpEgNq4XvBmaAuw==",
+ "optional": true,
+ "requires": {
+ "nan": "^2.9.2",
+ "node-pre-gyp": "^0.10.0"
+ },
+ "dependencies": {
+ "abbrev": {
+ "version": "1.1.1",
+ "bundled": true,
+ "optional": true
+ },
+ "ansi-regex": {
+ "version": "2.1.1",
+ "bundled": true,
+ "optional": true
+ },
+ "aproba": {
+ "version": "1.2.0",
+ "bundled": true,
+ "optional": true
+ },
+ "are-we-there-yet": {
+ "version": "1.1.5",
+ "bundled": true,
+ "optional": true,
+ "requires": {
+ "delegates": "^1.0.0",
+ "readable-stream": "^2.0.6"
+ }
+ },
+ "balanced-match": {
+ "version": "1.0.0",
+ "bundled": true,
+ "optional": true
+ },
+ "brace-expansion": {
+ "version": "1.1.11",
+ "bundled": true,
+ "optional": true,
+ "requires": {
+ "balanced-match": "^1.0.0",
+ "concat-map": "0.0.1"
+ }
+ },
+ "chownr": {
+ "version": "1.1.1",
+ "bundled": true,
+ "optional": true
+ },
+ "code-point-at": {
+ "version": "1.1.0",
+ "bundled": true,
+ "optional": true
+ },
+ "concat-map": {
+ "version": "0.0.1",
+ "bundled": true,
+ "optional": true
+ },
+ "console-control-strings": {
+ "version": "1.1.0",
+ "bundled": true,
+ "optional": true
+ },
+ "core-util-is": {
+ "version": "1.0.2",
+ "bundled": true,
+ "optional": true
+ },
+ "debug": {
+ "version": "2.6.9",
+ "bundled": true,
+ "optional": true,
+ "requires": {
+ "ms": "2.0.0"
+ }
+ },
+ "deep-extend": {
+ "version": "0.6.0",
+ "bundled": true,
+ "optional": true
+ },
+ "delegates": {
+ "version": "1.0.0",
+ "bundled": true,
+ "optional": true
+ },
+ "detect-libc": {
+ "version": "1.0.3",
+ "bundled": true,
+ "optional": true
+ },
+ "fs-minipass": {
+ "version": "1.2.5",
+ "bundled": true,
+ "optional": true,
+ "requires": {
+ "minipass": "^2.2.1"
+ }
+ },
+ "fs.realpath": {
+ "version": "1.0.0",
+ "bundled": true,
+ "optional": true
+ },
+ "gauge": {
+ "version": "2.7.4",
+ "bundled": true,
+ "optional": true,
+ "requires": {
+ "aproba": "^1.0.3",
+ "console-control-strings": "^1.0.0",
+ "has-unicode": "^2.0.0",
+ "object-assign": "^4.1.0",
+ "signal-exit": "^3.0.0",
+ "string-width": "^1.0.1",
+ "strip-ansi": "^3.0.1",
+ "wide-align": "^1.1.0"
+ }
+ },
+ "glob": {
+ "version": "7.1.3",
+ "bundled": true,
+ "optional": true,
+ "requires": {
+ "fs.realpath": "^1.0.0",
+ "inflight": "^1.0.4",
+ "inherits": "2",
+ "minimatch": "^3.0.4",
+ "once": "^1.3.0",
+ "path-is-absolute": "^1.0.0"
+ }
+ },
+ "has-unicode": {
+ "version": "2.0.1",
+ "bundled": true,
+ "optional": true
+ },
+ "iconv-lite": {
+ "version": "0.4.24",
+ "bundled": true,
+ "optional": true,
+ "requires": {
+ "safer-buffer": ">= 2.1.2 < 3"
+ }
+ },
+ "ignore-walk": {
+ "version": "3.0.1",
+ "bundled": true,
+ "optional": true,
+ "requires": {
+ "minimatch": "^3.0.4"
+ }
+ },
+ "inflight": {
+ "version": "1.0.6",
+ "bundled": true,
+ "optional": true,
+ "requires": {
+ "once": "^1.3.0",
+ "wrappy": "1"
+ }
+ },
+ "inherits": {
+ "version": "2.0.3",
+ "bundled": true,
+ "optional": true
+ },
+ "ini": {
+ "version": "1.3.5",
+ "bundled": true,
+ "optional": true
+ },
+ "is-fullwidth-code-point": {
+ "version": "1.0.0",
+ "bundled": true,
+ "optional": true,
+ "requires": {
+ "number-is-nan": "^1.0.0"
+ }
+ },
+ "isarray": {
+ "version": "1.0.0",
+ "bundled": true,
+ "optional": true
+ },
+ "minimatch": {
+ "version": "3.0.4",
+ "bundled": true,
+ "optional": true,
+ "requires": {
+ "brace-expansion": "^1.1.7"
+ }
+ },
+ "minimist": {
+ "version": "0.0.8",
+ "bundled": true,
+ "optional": true
+ },
+ "minipass": {
+ "version": "2.3.5",
+ "bundled": true,
+ "optional": true,
+ "requires": {
+ "safe-buffer": "^5.1.2",
+ "yallist": "^3.0.0"
+ }
+ },
+ "minizlib": {
+ "version": "1.2.1",
+ "bundled": true,
+ "optional": true,
+ "requires": {
+ "minipass": "^2.2.1"
+ }
+ },
+ "mkdirp": {
+ "version": "0.5.1",
+ "bundled": true,
+ "optional": true,
+ "requires": {
+ "minimist": "0.0.8"
+ }
+ },
+ "ms": {
+ "version": "2.0.0",
+ "bundled": true,
+ "optional": true
+ },
+ "needle": {
+ "version": "2.2.4",
+ "bundled": true,
+ "optional": true,
+ "requires": {
+ "debug": "^2.1.2",
+ "iconv-lite": "^0.4.4",
+ "sax": "^1.2.4"
+ }
+ },
+ "node-pre-gyp": {
+ "version": "0.10.3",
+ "bundled": true,
+ "optional": true,
+ "requires": {
+ "detect-libc": "^1.0.2",
+ "mkdirp": "^0.5.1",
+ "needle": "^2.2.1",
+ "nopt": "^4.0.1",
+ "npm-packlist": "^1.1.6",
+ "npmlog": "^4.0.2",
+ "rc": "^1.2.7",
+ "rimraf": "^2.6.1",
+ "semver": "^5.3.0",
+ "tar": "^4"
+ }
+ },
+ "nopt": {
+ "version": "4.0.1",
+ "bundled": true,
+ "optional": true,
+ "requires": {
+ "abbrev": "1",
+ "osenv": "^0.1.4"
+ }
+ },
+ "npm-bundled": {
+ "version": "1.0.5",
+ "bundled": true,
+ "optional": true
+ },
+ "npm-packlist": {
+ "version": "1.2.0",
+ "bundled": true,
+ "optional": true,
+ "requires": {
+ "ignore-walk": "^3.0.1",
+ "npm-bundled": "^1.0.1"
+ }
+ },
+ "npmlog": {
+ "version": "4.1.2",
+ "bundled": true,
+ "optional": true,
+ "requires": {
+ "are-we-there-yet": "~1.1.2",
+ "console-control-strings": "~1.1.0",
+ "gauge": "~2.7.3",
+ "set-blocking": "~2.0.0"
+ }
+ },
+ "number-is-nan": {
+ "version": "1.0.1",
+ "bundled": true,
+ "optional": true
+ },
+ "object-assign": {
+ "version": "4.1.1",
+ "bundled": true,
+ "optional": true
+ },
+ "once": {
+ "version": "1.4.0",
+ "bundled": true,
+ "optional": true,
+ "requires": {
+ "wrappy": "1"
+ }
+ },
+ "os-homedir": {
+ "version": "1.0.2",
+ "bundled": true,
+ "optional": true
+ },
+ "os-tmpdir": {
+ "version": "1.0.2",
+ "bundled": true,
+ "optional": true
+ },
+ "osenv": {
+ "version": "0.1.5",
+ "bundled": true,
+ "optional": true,
+ "requires": {
+ "os-homedir": "^1.0.0",
+ "os-tmpdir": "^1.0.0"
+ }
+ },
+ "path-is-absolute": {
+ "version": "1.0.1",
+ "bundled": true,
+ "optional": true
+ },
+ "process-nextick-args": {
+ "version": "2.0.0",
+ "bundled": true,
+ "optional": true
+ },
+ "rc": {
+ "version": "1.2.8",
+ "bundled": true,
+ "optional": true,
+ "requires": {
+ "deep-extend": "^0.6.0",
+ "ini": "~1.3.0",
+ "minimist": "^1.2.0",
+ "strip-json-comments": "~2.0.1"
+ },
+ "dependencies": {
+ "minimist": {
+ "version": "1.2.0",
+ "bundled": true,
+ "optional": true
+ }
+ }
+ },
+ "readable-stream": {
+ "version": "2.3.6",
+ "bundled": true,
+ "optional": true,
+ "requires": {
+ "core-util-is": "~1.0.0",
+ "inherits": "~2.0.3",
+ "isarray": "~1.0.0",
+ "process-nextick-args": "~2.0.0",
+ "safe-buffer": "~5.1.1",
+ "string_decoder": "~1.1.1",
+ "util-deprecate": "~1.0.1"
+ }
+ },
+ "rimraf": {
+ "version": "2.6.3",
+ "bundled": true,
+ "optional": true,
+ "requires": {
+ "glob": "^7.1.3"
+ }
+ },
+ "safe-buffer": {
+ "version": "5.1.2",
+ "bundled": true,
+ "optional": true
+ },
+ "safer-buffer": {
+ "version": "2.1.2",
+ "bundled": true,
+ "optional": true
+ },
+ "sax": {
+ "version": "1.2.4",
+ "bundled": true,
+ "optional": true
+ },
+ "semver": {
+ "version": "5.6.0",
+ "bundled": true,
+ "optional": true
+ },
+ "set-blocking": {
+ "version": "2.0.0",
+ "bundled": true,
+ "optional": true
+ },
+ "signal-exit": {
+ "version": "3.0.2",
+ "bundled": true,
+ "optional": true
+ },
+ "string-width": {
+ "version": "1.0.2",
+ "bundled": true,
+ "optional": true,
+ "requires": {
+ "code-point-at": "^1.0.0",
+ "is-fullwidth-code-point": "^1.0.0",
+ "strip-ansi": "^3.0.0"
+ }
+ },
+ "string_decoder": {
+ "version": "1.1.1",
+ "bundled": true,
+ "optional": true,
+ "requires": {
+ "safe-buffer": "~5.1.0"
+ }
+ },
+ "strip-ansi": {
+ "version": "3.0.1",
+ "bundled": true,
+ "optional": true,
+ "requires": {
+ "ansi-regex": "^2.0.0"
+ }
+ },
+ "strip-json-comments": {
+ "version": "2.0.1",
+ "bundled": true,
+ "optional": true
+ },
+ "tar": {
+ "version": "4.4.8",
+ "bundled": true,
+ "optional": true,
+ "requires": {
+ "chownr": "^1.1.1",
+ "fs-minipass": "^1.2.5",
+ "minipass": "^2.3.4",
+ "minizlib": "^1.1.1",
+ "mkdirp": "^0.5.0",
+ "safe-buffer": "^5.1.2",
+ "yallist": "^3.0.2"
+ }
+ },
+ "util-deprecate": {
+ "version": "1.0.2",
+ "bundled": true,
+ "optional": true
+ },
+ "wide-align": {
+ "version": "1.1.3",
+ "bundled": true,
+ "optional": true,
+ "requires": {
+ "string-width": "^1.0.2 || 2"
+ }
+ },
+ "wrappy": {
+ "version": "1.0.2",
+ "bundled": true,
+ "optional": true
+ },
+ "yallist": {
+ "version": "3.0.3",
+ "bundled": true,
+ "optional": true
+ }
+ }
+ },
+ "function-bind": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz",
+ "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A=="
+ },
+ "functional-red-black-tree": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz",
+ "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc="
+ },
+ "get-caller-file": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-1.0.3.tgz",
+ "integrity": "sha512-3t6rVToeoZfYSGd8YoLFR2DJkiQrIiUrGcjvFX2mDw3bn6k2OtwHN0TNCLbBO+w8qTvimhDkv+LSscbJY1vE6w=="
+ },
+ "get-stdin": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-6.0.0.tgz",
+ "integrity": "sha512-jp4tHawyV7+fkkSKyvjuLZswblUtz+SQKzSWnBbii16BuZksJlU1wuBYXY75r+duh/llF1ur6oNwi+2ZzjKZ7g=="
+ },
+ "get-stream": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz",
+ "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==",
+ "requires": {
+ "pump": "^3.0.0"
+ }
+ },
+ "get-value": {
+ "version": "2.0.6",
+ "resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz",
+ "integrity": "sha1-3BXKHGcjh8p2vTesCjlbogQqLCg="
+ },
+ "getpass": {
+ "version": "0.1.7",
+ "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz",
+ "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=",
+ "requires": {
+ "assert-plus": "^1.0.0"
+ }
+ },
+ "glob": {
+ "version": "7.1.3",
+ "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz",
+ "integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==",
+ "requires": {
+ "fs.realpath": "^1.0.0",
+ "inflight": "^1.0.4",
+ "inherits": "2",
+ "minimatch": "^3.0.4",
+ "once": "^1.3.0",
+ "path-is-absolute": "^1.0.0"
+ }
+ },
+ "glob-parent": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz",
+ "integrity": "sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4=",
+ "requires": {
+ "is-glob": "^3.1.0",
+ "path-dirname": "^1.0.0"
+ },
+ "dependencies": {
+ "is-glob": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz",
+ "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=",
+ "requires": {
+ "is-extglob": "^2.1.0"
+ }
+ }
+ }
+ },
+ "global-modules": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-1.0.0.tgz",
+ "integrity": "sha512-sKzpEkf11GpOFuw0Zzjzmt4B4UZwjOcG757PPvrfhxcLFbq0wpsgpOqxpxtxFiCG4DtG93M6XRVbF2oGdev7bg==",
+ "requires": {
+ "global-prefix": "^1.0.1",
+ "is-windows": "^1.0.1",
+ "resolve-dir": "^1.0.0"
+ }
+ },
+ "global-prefix": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/global-prefix/-/global-prefix-1.0.2.tgz",
+ "integrity": "sha1-2/dDxsFJklk8ZVVoy2btMsASLr4=",
+ "requires": {
+ "expand-tilde": "^2.0.2",
+ "homedir-polyfill": "^1.0.1",
+ "ini": "^1.3.4",
+ "is-windows": "^1.0.1",
+ "which": "^1.2.14"
+ }
+ },
+ "globals": {
+ "version": "11.11.0",
+ "resolved": "https://registry.npmjs.org/globals/-/globals-11.11.0.tgz",
+ "integrity": "sha512-WHq43gS+6ufNOEqlrDBxVEbb8ntfXrfAUU2ZOpCxrBdGKW3gyv8mCxAfIBD0DroPKGrJ2eSsXsLtY9MPntsyTw=="
+ },
+ "globby": {
+ "version": "6.1.0",
+ "resolved": "https://registry.npmjs.org/globby/-/globby-6.1.0.tgz",
+ "integrity": "sha1-9abXDoOV4hyFj7BInWTfAkJNUGw=",
+ "requires": {
+ "array-union": "^1.0.1",
+ "glob": "^7.0.3",
+ "object-assign": "^4.0.1",
+ "pify": "^2.0.0",
+ "pinkie-promise": "^2.0.0"
+ },
+ "dependencies": {
+ "pify": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz",
+ "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw="
+ }
+ }
+ },
+ "graceful-fs": {
+ "version": "4.1.15",
+ "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.15.tgz",
+ "integrity": "sha512-6uHUhOPEBgQ24HM+r6b/QwWfZq+yiFcipKFrOFiBEnWdy5sdzYoi+pJeQaPI5qOLRFqWmAXUPQNsielzdLoecA=="
+ },
+ "growly": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/growly/-/growly-1.3.0.tgz",
+ "integrity": "sha1-8QdIy+dq+WS3yWyTxrzCivEgwIE="
+ },
+ "handle-thing": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/handle-thing/-/handle-thing-2.0.0.tgz",
+ "integrity": "sha512-d4sze1JNC454Wdo2fkuyzCr6aHcbL6PGGuFAz0Li/NcOm1tCHGnWDRmJP85dh9IhQErTc2svWFEX5xHIOo//kQ=="
+ },
+ "handlebars": {
+ "version": "4.1.2",
+ "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.1.2.tgz",
+ "integrity": "sha512-nvfrjqvt9xQ8Z/w0ijewdD/vvWDTOweBUm96NTr66Wfvo1mJenBLwcYmPs3TIBP5ruzYGD7Hx/DaM9RmhroGPw==",
+ "requires": {
+ "neo-async": "^2.6.0",
+ "optimist": "^0.6.1",
+ "source-map": "^0.6.1",
+ "uglify-js": "^3.1.4"
+ },
+ "dependencies": {
+ "source-map": {
+ "version": "0.6.1",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
+ "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="
+ }
+ }
+ },
+ "har-schema": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz",
+ "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI="
+ },
+ "har-validator": {
+ "version": "5.1.3",
+ "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.3.tgz",
+ "integrity": "sha512-sNvOCzEQNr/qrvJgc3UG/kD4QtlHycrzwS+6mfTrrSq97BvaYcPZZI1ZSqGSPR73Cxn4LKTD4PttRwfU7jWq5g==",
+ "requires": {
+ "ajv": "^6.5.5",
+ "har-schema": "^2.0.0"
+ }
+ },
+ "has": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz",
+ "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==",
+ "requires": {
+ "function-bind": "^1.1.1"
+ }
+ },
+ "has-flag": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
+ "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0="
+ },
+ "has-symbols": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.0.tgz",
+ "integrity": "sha1-uhqPGvKg/DllD1yFA2dwQSIGO0Q="
+ },
+ "has-value": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz",
+ "integrity": "sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc=",
+ "requires": {
+ "get-value": "^2.0.6",
+ "has-values": "^1.0.0",
+ "isobject": "^3.0.0"
+ }
+ },
+ "has-values": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/has-values/-/has-values-1.0.0.tgz",
+ "integrity": "sha1-lbC2P+whRmGab+V/51Yo1aOe/k8=",
+ "requires": {
+ "is-number": "^3.0.0",
+ "kind-of": "^4.0.0"
+ },
+ "dependencies": {
+ "kind-of": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz",
+ "integrity": "sha1-IIE989cSkosgc3hpGkUGb65y3Vc=",
+ "requires": {
+ "is-buffer": "^1.1.5"
+ }
+ }
+ }
+ },
+ "hash-base": {
+ "version": "3.0.4",
+ "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.0.4.tgz",
+ "integrity": "sha1-X8hoaEfs1zSZQDMZprCj8/auSRg=",
+ "requires": {
+ "inherits": "^2.0.1",
+ "safe-buffer": "^5.0.1"
+ }
+ },
+ "hash.js": {
+ "version": "1.1.7",
+ "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz",
+ "integrity": "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==",
+ "requires": {
+ "inherits": "^2.0.3",
+ "minimalistic-assert": "^1.0.1"
+ }
+ },
+ "hmac-drbg": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz",
+ "integrity": "sha1-0nRXAQJabHdabFRXk+1QL8DGSaE=",
+ "requires": {
+ "hash.js": "^1.0.3",
+ "minimalistic-assert": "^1.0.0",
+ "minimalistic-crypto-utils": "^1.0.1"
+ }
+ },
+ "homedir-polyfill": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/homedir-polyfill/-/homedir-polyfill-1.0.3.tgz",
+ "integrity": "sha512-eSmmWE5bZTK2Nou4g0AI3zZ9rswp7GRKoKXS1BLUkvPviOqs4YTN1djQIqrXy9k5gEtdLPy86JjRwsNM9tnDcA==",
+ "requires": {
+ "parse-passwd": "^1.0.0"
+ }
+ },
+ "hosted-git-info": {
+ "version": "2.7.1",
+ "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.7.1.tgz",
+ "integrity": "sha512-7T/BxH19zbcCTa8XkMlbK5lTo1WtgkFi3GvdWEyNuc4Vex7/9Dqbnpsf4JMydcfj9HCg4zUWFTL3Za6lapg5/w=="
+ },
+ "hpack.js": {
+ "version": "2.1.6",
+ "resolved": "https://registry.npmjs.org/hpack.js/-/hpack.js-2.1.6.tgz",
+ "integrity": "sha1-h3dMCUnlE/QuhFdbPEVoH63ioLI=",
+ "requires": {
+ "inherits": "^2.0.1",
+ "obuf": "^1.0.0",
+ "readable-stream": "^2.0.1",
+ "wbuf": "^1.1.0"
+ }
+ },
+ "html-encoding-sniffer": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-1.0.2.tgz",
+ "integrity": "sha512-71lZziiDnsuabfdYiUeWdCVyKuqwWi23L8YeIgV9jSSZHCtb6wB1BKWooH7L3tn4/FuZJMVWyNaIDr4RGmaSYw==",
+ "requires": {
+ "whatwg-encoding": "^1.0.1"
+ }
+ },
+ "html-entities": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/html-entities/-/html-entities-1.2.1.tgz",
+ "integrity": "sha1-DfKTUfByEWNRXfueVUPl9u7VFi8="
+ },
+ "http-deceiver": {
+ "version": "1.2.7",
+ "resolved": "https://registry.npmjs.org/http-deceiver/-/http-deceiver-1.2.7.tgz",
+ "integrity": "sha1-+nFolEq5pRnTN8sL7HKE3D5yPYc="
+ },
+ "http-errors": {
+ "version": "1.6.3",
+ "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz",
+ "integrity": "sha1-i1VoC7S+KDoLW/TqLjhYC+HZMg0=",
+ "requires": {
+ "depd": "~1.1.2",
+ "inherits": "2.0.3",
+ "setprototypeof": "1.1.0",
+ "statuses": ">= 1.4.0 < 2"
+ }
+ },
+ "http-parser-js": {
+ "version": "0.5.0",
+ "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.5.0.tgz",
+ "integrity": "sha512-cZdEF7r4gfRIq7ezX9J0T+kQmJNOub71dWbgAXVHDct80TKP4MCETtZQ31xyv38UwgzkWPYF/Xc0ge55dW9Z9w=="
+ },
+ "http-proxy": {
+ "version": "1.17.0",
+ "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.17.0.tgz",
+ "integrity": "sha512-Taqn+3nNvYRfJ3bGvKfBSRwy1v6eePlm3oc/aWVxZp57DQr5Eq3xhKJi7Z4hZpS8PC3H4qI+Yly5EmFacGuA/g==",
+ "requires": {
+ "eventemitter3": "^3.0.0",
+ "follow-redirects": "^1.0.0",
+ "requires-port": "^1.0.0"
+ }
+ },
+ "http-proxy-middleware": {
+ "version": "0.19.1",
+ "resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-0.19.1.tgz",
+ "integrity": "sha512-yHYTgWMQO8VvwNS22eLLloAkvungsKdKTLO8AJlftYIKNfJr3GK3zK0ZCfzDDGUBttdGc8xFy1mCitvNKQtC3Q==",
+ "requires": {
+ "http-proxy": "^1.17.0",
+ "is-glob": "^4.0.0",
+ "lodash": "^4.17.11",
+ "micromatch": "^3.1.10"
+ }
+ },
+ "http-signature": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz",
+ "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=",
+ "requires": {
+ "assert-plus": "^1.0.0",
+ "jsprim": "^1.2.2",
+ "sshpk": "^1.7.0"
+ }
+ },
+ "https-browserify": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/https-browserify/-/https-browserify-1.0.0.tgz",
+ "integrity": "sha1-7AbBDgo0wPL68Zn3/X/Hj//QPHM="
+ },
+ "iconv-lite": {
+ "version": "0.4.24",
+ "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
+ "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==",
+ "requires": {
+ "safer-buffer": ">= 2.1.2 < 3"
+ }
+ },
+ "icss-replace-symbols": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/icss-replace-symbols/-/icss-replace-symbols-1.1.0.tgz",
+ "integrity": "sha1-Bupvg2ead0njhs/h/oEq5dsiPe0="
+ },
+ "icss-utils": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/icss-utils/-/icss-utils-4.1.0.tgz",
+ "integrity": "sha512-3DEun4VOeMvSczifM3F2cKQrDQ5Pj6WKhkOq6HD4QTnDUAq8MQRxy5TX6Sy1iY6WPBe4gQ3p5vTECjbIkglkkQ==",
+ "requires": {
+ "postcss": "^7.0.14"
+ }
+ },
+ "ieee754": {
+ "version": "1.1.13",
+ "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.13.tgz",
+ "integrity": "sha512-4vf7I2LYV/HaWerSo3XmlMkp5eZ83i+/CDluXi/IGTs/O1sejBNhTtnxzmRZfvOUqj7lZjqHkeTvpgSFDlWZTg=="
+ },
+ "iferr": {
+ "version": "0.1.5",
+ "resolved": "https://registry.npmjs.org/iferr/-/iferr-0.1.5.tgz",
+ "integrity": "sha1-xg7taebY/bazEEofy8ocGS3FtQE="
+ },
+ "ignore": {
+ "version": "4.0.6",
+ "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz",
+ "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg=="
+ },
+ "import-cwd": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/import-cwd/-/import-cwd-2.1.0.tgz",
+ "integrity": "sha1-qmzzbnInYShcs3HsZRn1PiQ1sKk=",
+ "requires": {
+ "import-from": "^2.1.0"
+ }
+ },
+ "import-fresh": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.0.0.tgz",
+ "integrity": "sha512-pOnA9tfM3Uwics+SaBLCNyZZZbK+4PTu0OPZtLlMIrv17EdBoC15S9Kn8ckJ9TZTyKb3ywNE5y1yeDxxGA7nTQ==",
+ "requires": {
+ "parent-module": "^1.0.0",
+ "resolve-from": "^4.0.0"
+ }
+ },
+ "import-from": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/import-from/-/import-from-2.1.0.tgz",
+ "integrity": "sha1-M1238qev/VOqpHHUuAId7ja387E=",
+ "requires": {
+ "resolve-from": "^3.0.0"
+ },
+ "dependencies": {
+ "resolve-from": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-3.0.0.tgz",
+ "integrity": "sha1-six699nWiBvItuZTM17rywoYh0g="
+ }
+ }
+ },
+ "import-local": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/import-local/-/import-local-2.0.0.tgz",
+ "integrity": "sha512-b6s04m3O+s3CGSbqDIyP4R6aAwAeYlVq9+WUWep6iHa8ETRf9yei1U48C5MmfJmV9AiLYYBKPMq/W+/WRpQmCQ==",
+ "requires": {
+ "pkg-dir": "^3.0.0",
+ "resolve-cwd": "^2.0.0"
+ }
+ },
+ "imurmurhash": {
+ "version": "0.1.4",
+ "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz",
+ "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o="
+ },
+ "indexes-of": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/indexes-of/-/indexes-of-1.0.1.tgz",
+ "integrity": "sha1-8w9xbI4r00bHtn0985FVZqfAVgc="
+ },
+ "indexof": {
+ "version": "0.0.1",
+ "resolved": "https://registry.npmjs.org/indexof/-/indexof-0.0.1.tgz",
+ "integrity": "sha1-gtwzbSMrkGIXnQWrMpOmYFn9Q10="
+ },
+ "inflight": {
+ "version": "1.0.6",
+ "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
+ "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=",
+ "requires": {
+ "once": "^1.3.0",
+ "wrappy": "1"
+ }
+ },
+ "inherits": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
+ "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4="
+ },
+ "ini": {
+ "version": "1.3.5",
+ "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.5.tgz",
+ "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw=="
+ },
+ "inquirer": {
+ "version": "6.2.2",
+ "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-6.2.2.tgz",
+ "integrity": "sha512-Z2rREiXA6cHRR9KBOarR3WuLlFzlIfAEIiB45ll5SSadMg7WqOh1MKEjjndfuH5ewXdixWCxqnVfGOQzPeiztA==",
+ "requires": {
+ "ansi-escapes": "^3.2.0",
+ "chalk": "^2.4.2",
+ "cli-cursor": "^2.1.0",
+ "cli-width": "^2.0.0",
+ "external-editor": "^3.0.3",
+ "figures": "^2.0.0",
+ "lodash": "^4.17.11",
+ "mute-stream": "0.0.7",
+ "run-async": "^2.2.0",
+ "rxjs": "^6.4.0",
+ "string-width": "^2.1.0",
+ "strip-ansi": "^5.0.0",
+ "through": "^2.3.6"
+ },
+ "dependencies": {
+ "ansi-regex": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz",
+ "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg=="
+ },
+ "strip-ansi": {
+ "version": "5.2.0",
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz",
+ "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==",
+ "requires": {
+ "ansi-regex": "^4.1.0"
+ }
+ }
+ }
+ },
+ "internal-ip": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/internal-ip/-/internal-ip-4.3.0.tgz",
+ "integrity": "sha512-S1zBo1D6zcsyuC6PMmY5+55YMILQ9av8lotMx447Bq6SAgo/sDK6y6uUKmuYhW7eacnIhFfsPmCNYdDzsnnDCg==",
+ "requires": {
+ "default-gateway": "^4.2.0",
+ "ipaddr.js": "^1.9.0"
+ },
+ "dependencies": {
+ "ipaddr.js": {
+ "version": "1.9.0",
+ "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.0.tgz",
+ "integrity": "sha512-M4Sjn6N/+O6/IXSJseKqHoFc+5FdGJ22sXqnjTpdZweHK64MzEPAyQZyEU3R/KRv2GLoa7nNtg/C2Ev6m7z+eA=="
+ }
+ }
+ },
+ "interpret": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.2.0.tgz",
+ "integrity": "sha512-mT34yGKMNceBQUoVn7iCDKDntA7SC6gycMAWzGx1z/CMCTV7b2AAtXlo3nRyHZ1FelRkQbQjprHSYGwzLtkVbw=="
+ },
+ "invariant": {
+ "version": "2.2.4",
+ "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz",
+ "integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==",
+ "requires": {
+ "loose-envify": "^1.0.0"
+ }
+ },
+ "invert-kv": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-2.0.0.tgz",
+ "integrity": "sha512-wPVv/y/QQ/Uiirj/vh3oP+1Ww+AWehmi1g5fFWGPF6IpCBCDVrhgHRMvrLfdYcwDh3QJbGXDW4JAuzxElLSqKA=="
+ },
+ "ip": {
+ "version": "1.1.5",
+ "resolved": "https://registry.npmjs.org/ip/-/ip-1.1.5.tgz",
+ "integrity": "sha1-vd7XARQpCCjAoDnnLvJfWq7ENUo="
+ },
+ "ip-regex": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/ip-regex/-/ip-regex-2.1.0.tgz",
+ "integrity": "sha1-+ni/XS5pE8kRzp+BnuUUa7bYROk="
+ },
+ "ipaddr.js": {
+ "version": "1.8.0",
+ "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.8.0.tgz",
+ "integrity": "sha1-6qM9bd16zo9/b+DJygRA5wZzix4="
+ },
+ "is-accessor-descriptor": {
+ "version": "0.1.6",
+ "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz",
+ "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=",
+ "requires": {
+ "kind-of": "^3.0.2"
+ },
+ "dependencies": {
+ "kind-of": {
+ "version": "3.2.2",
+ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
+ "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
+ "requires": {
+ "is-buffer": "^1.1.5"
+ }
+ }
+ }
+ },
+ "is-arrayish": {
+ "version": "0.2.1",
+ "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz",
+ "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0="
+ },
+ "is-binary-path": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-1.0.1.tgz",
+ "integrity": "sha1-dfFmQrSA8YenEcgUFh/TpKdlWJg=",
+ "requires": {
+ "binary-extensions": "^1.0.0"
+ }
+ },
+ "is-buffer": {
+ "version": "1.1.6",
+ "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz",
+ "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w=="
+ },
+ "is-callable": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.1.4.tgz",
+ "integrity": "sha512-r5p9sxJjYnArLjObpjA4xu5EKI3CuKHkJXMhT7kwbpUyIFD1n5PMAsoPvWnvtZiNz7LjkYDRZhd7FlI0eMijEA=="
+ },
+ "is-ci": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-2.0.0.tgz",
+ "integrity": "sha512-YfJT7rkpQB0updsdHLGWrvhBJfcfzNNawYDNIyQXJz0IViGf75O8EBPKSdvw2rF+LGCsX4FZ8tcr3b19LcZq4w==",
+ "requires": {
+ "ci-info": "^2.0.0"
+ }
+ },
+ "is-data-descriptor": {
+ "version": "0.1.4",
+ "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz",
+ "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=",
+ "requires": {
+ "kind-of": "^3.0.2"
+ },
+ "dependencies": {
+ "kind-of": {
+ "version": "3.2.2",
+ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
+ "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
+ "requires": {
+ "is-buffer": "^1.1.5"
+ }
+ }
+ }
+ },
+ "is-date-object": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.1.tgz",
+ "integrity": "sha1-mqIOtq7rv/d/vTPnTKAbM1gdOhY="
+ },
+ "is-descriptor": {
+ "version": "0.1.6",
+ "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz",
+ "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==",
+ "requires": {
+ "is-accessor-descriptor": "^0.1.6",
+ "is-data-descriptor": "^0.1.4",
+ "kind-of": "^5.0.0"
+ },
+ "dependencies": {
+ "kind-of": {
+ "version": "5.1.0",
+ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz",
+ "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw=="
+ }
+ }
+ },
+ "is-directory": {
+ "version": "0.3.1",
+ "resolved": "https://registry.npmjs.org/is-directory/-/is-directory-0.3.1.tgz",
+ "integrity": "sha1-YTObbyR1/Hcv2cnYP1yFddwVSuE="
+ },
+ "is-extendable": {
+ "version": "0.1.1",
+ "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz",
+ "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik="
+ },
+ "is-extglob": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
+ "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI="
+ },
+ "is-fullwidth-code-point": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz",
+ "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8="
+ },
+ "is-generator-fn": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/is-generator-fn/-/is-generator-fn-2.1.0.tgz",
+ "integrity": "sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ=="
+ },
+ "is-glob": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.0.tgz",
+ "integrity": "sha1-lSHHaEXMJhCoUgPd8ICpWML/q8A=",
+ "requires": {
+ "is-extglob": "^2.1.1"
+ }
+ },
+ "is-number": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz",
+ "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=",
+ "requires": {
+ "kind-of": "^3.0.2"
+ },
+ "dependencies": {
+ "kind-of": {
+ "version": "3.2.2",
+ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
+ "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
+ "requires": {
+ "is-buffer": "^1.1.5"
+ }
+ }
+ }
+ },
+ "is-path-cwd": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-2.0.0.tgz",
+ "integrity": "sha512-m5dHHzpOXEiv18JEORttBO64UgTEypx99vCxQLjbBvGhOJxnTNglYoFXxwo6AbsQb79sqqycQEHv2hWkHZAijA=="
+ },
+ "is-path-in-cwd": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/is-path-in-cwd/-/is-path-in-cwd-2.0.0.tgz",
+ "integrity": "sha512-6Vz5Gc9s/sDA3JBVu0FzWufm8xaBsqy1zn8Q6gmvGP6nSDMw78aS4poBNeatWjaRpTpxxLn1WOndAiOlk+qY8A==",
+ "requires": {
+ "is-path-inside": "^1.0.0"
+ }
+ },
+ "is-path-inside": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-1.0.1.tgz",
+ "integrity": "sha1-jvW33lBDej/cprToZe96pVy0gDY=",
+ "requires": {
+ "path-is-inside": "^1.0.1"
+ }
+ },
+ "is-plain-object": {
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz",
+ "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==",
+ "requires": {
+ "isobject": "^3.0.1"
+ }
+ },
+ "is-promise": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.1.0.tgz",
+ "integrity": "sha1-eaKp7OfwlugPNtKy87wWwf9L8/o="
+ },
+ "is-regex": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.0.4.tgz",
+ "integrity": "sha1-VRdIm1RwkbCTDglWVM7SXul+lJE=",
+ "requires": {
+ "has": "^1.0.1"
+ }
+ },
+ "is-stream": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz",
+ "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ="
+ },
+ "is-symbol": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.2.tgz",
+ "integrity": "sha512-HS8bZ9ox60yCJLH9snBpIwv9pYUAkcuLhSA1oero1UB5y9aiQpRA8y2ex945AOtCZL1lJDeIk3G5LthswI46Lw==",
+ "requires": {
+ "has-symbols": "^1.0.0"
+ }
+ },
+ "is-typedarray": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz",
+ "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo="
+ },
+ "is-windows": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz",
+ "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA=="
+ },
+ "is-wsl": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-1.1.0.tgz",
+ "integrity": "sha1-HxbkqiKwTRM2tmGIpmrzxgDDpm0="
+ },
+ "isarray": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
+ "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE="
+ },
+ "isexe": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
+ "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA="
+ },
+ "isobject": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz",
+ "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8="
+ },
+ "isstream": {
+ "version": "0.1.2",
+ "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz",
+ "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo="
+ },
+ "istanbul-api": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/istanbul-api/-/istanbul-api-2.1.1.tgz",
+ "integrity": "sha512-kVmYrehiwyeBAk/wE71tW6emzLiHGjYIiDrc8sfyty4F8M02/lrgXSm+R1kXysmF20zArvmZXjlE/mg24TVPJw==",
+ "requires": {
+ "async": "^2.6.1",
+ "compare-versions": "^3.2.1",
+ "fileset": "^2.0.3",
+ "istanbul-lib-coverage": "^2.0.3",
+ "istanbul-lib-hook": "^2.0.3",
+ "istanbul-lib-instrument": "^3.1.0",
+ "istanbul-lib-report": "^2.0.4",
+ "istanbul-lib-source-maps": "^3.0.2",
+ "istanbul-reports": "^2.1.1",
+ "js-yaml": "^3.12.0",
+ "make-dir": "^1.3.0",
+ "minimatch": "^3.0.4",
+ "once": "^1.4.0"
+ }
+ },
+ "istanbul-lib-coverage": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.3.tgz",
+ "integrity": "sha512-dKWuzRGCs4G+67VfW9pBFFz2Jpi4vSp/k7zBcJ888ofV5Mi1g5CUML5GvMvV6u9Cjybftu+E8Cgp+k0dI1E5lw=="
+ },
+ "istanbul-lib-hook": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/istanbul-lib-hook/-/istanbul-lib-hook-2.0.3.tgz",
+ "integrity": "sha512-CLmEqwEhuCYtGcpNVJjLV1DQyVnIqavMLFHV/DP+np/g3qvdxu3gsPqYoJMXm15sN84xOlckFB3VNvRbf5yEgA==",
+ "requires": {
+ "append-transform": "^1.0.0"
+ }
+ },
+ "istanbul-lib-instrument": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-3.1.0.tgz",
+ "integrity": "sha512-ooVllVGT38HIk8MxDj/OIHXSYvH+1tq/Vb38s8ixt9GoJadXska4WkGY+0wkmtYCZNYtaARniH/DixUGGLZ0uA==",
+ "requires": {
+ "@babel/generator": "^7.0.0",
+ "@babel/parser": "^7.0.0",
+ "@babel/template": "^7.0.0",
+ "@babel/traverse": "^7.0.0",
+ "@babel/types": "^7.0.0",
+ "istanbul-lib-coverage": "^2.0.3",
+ "semver": "^5.5.0"
+ }
+ },
+ "istanbul-lib-report": {
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-2.0.4.tgz",
+ "integrity": "sha512-sOiLZLAWpA0+3b5w5/dq0cjm2rrNdAfHWaGhmn7XEFW6X++IV9Ohn+pnELAl9K3rfpaeBfbmH9JU5sejacdLeA==",
+ "requires": {
+ "istanbul-lib-coverage": "^2.0.3",
+ "make-dir": "^1.3.0",
+ "supports-color": "^6.0.0"
+ },
+ "dependencies": {
+ "supports-color": {
+ "version": "6.1.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz",
+ "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==",
+ "requires": {
+ "has-flag": "^3.0.0"
+ }
+ }
+ }
+ },
+ "istanbul-lib-source-maps": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-3.0.2.tgz",
+ "integrity": "sha512-JX4v0CiKTGp9fZPmoxpu9YEkPbEqCqBbO3403VabKjH+NRXo72HafD5UgnjTEqHL2SAjaZK1XDuDOkn6I5QVfQ==",
+ "requires": {
+ "debug": "^4.1.1",
+ "istanbul-lib-coverage": "^2.0.3",
+ "make-dir": "^1.3.0",
+ "rimraf": "^2.6.2",
+ "source-map": "^0.6.1"
+ },
+ "dependencies": {
+ "debug": {
+ "version": "4.1.1",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz",
+ "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==",
+ "requires": {
+ "ms": "^2.1.1"
+ }
+ },
+ "ms": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz",
+ "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg=="
+ },
+ "source-map": {
+ "version": "0.6.1",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
+ "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="
+ }
+ }
+ },
+ "istanbul-reports": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-2.1.1.tgz",
+ "integrity": "sha512-FzNahnidyEPBCI0HcufJoSEoKykesRlFcSzQqjH9x0+LC8tnnE/p/90PBLu8iZTxr8yYZNyTtiAujUqyN+CIxw==",
+ "requires": {
+ "handlebars": "^4.1.0"
+ }
+ },
+ "jest": {
+ "version": "24.7.1",
+ "resolved": "https://registry.npmjs.org/jest/-/jest-24.7.1.tgz",
+ "integrity": "sha512-AbvRar5r++izmqo5gdbAjTeA6uNRGoNRuj5vHB0OnDXo2DXWZJVuaObiGgtlvhKb+cWy2oYbQSfxv7Q7GjnAtA==",
+ "requires": {
+ "import-local": "^2.0.0",
+ "jest-cli": "^24.7.1"
+ },
+ "dependencies": {
+ "jest-cli": {
+ "version": "24.7.1",
+ "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-24.7.1.tgz",
+ "integrity": "sha512-32OBoSCVPzcTslGFl6yVCMzB2SqX3IrWwZCY5mZYkb0D2WsogmU3eV2o8z7+gRQa4o4sZPX/k7GU+II7CxM6WQ==",
+ "requires": {
+ "@jest/core": "^24.7.1",
+ "@jest/test-result": "^24.7.1",
+ "@jest/types": "^24.7.0",
+ "chalk": "^2.0.1",
+ "exit": "^0.1.2",
+ "import-local": "^2.0.0",
+ "is-ci": "^2.0.0",
+ "jest-config": "^24.7.1",
+ "jest-util": "^24.7.1",
+ "jest-validate": "^24.7.0",
+ "prompts": "^2.0.1",
+ "realpath-native": "^1.1.0",
+ "yargs": "^12.0.2"
+ }
+ }
+ }
+ },
+ "jest-changed-files": {
+ "version": "24.7.0",
+ "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-24.7.0.tgz",
+ "integrity": "sha512-33BgewurnwSfJrW7T5/ZAXGE44o7swLslwh8aUckzq2e17/2Os1V0QU506ZNik3hjs8MgnEMKNkcud442NCDTw==",
+ "requires": {
+ "@jest/types": "^24.7.0",
+ "execa": "^1.0.0",
+ "throat": "^4.0.0"
+ }
+ },
+ "jest-config": {
+ "version": "24.7.1",
+ "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-24.7.1.tgz",
+ "integrity": "sha512-8FlJNLI+X+MU37j7j8RE4DnJkvAghXmBWdArVzypW6WxfGuxiL/CCkzBg0gHtXhD2rxla3IMOSUAHylSKYJ83g==",
+ "requires": {
+ "@babel/core": "^7.1.0",
+ "@jest/test-sequencer": "^24.7.1",
+ "@jest/types": "^24.7.0",
+ "babel-jest": "^24.7.1",
+ "chalk": "^2.0.1",
+ "glob": "^7.1.1",
+ "jest-environment-jsdom": "^24.7.1",
+ "jest-environment-node": "^24.7.1",
+ "jest-get-type": "^24.3.0",
+ "jest-jasmine2": "^24.7.1",
+ "jest-regex-util": "^24.3.0",
+ "jest-resolve": "^24.7.1",
+ "jest-util": "^24.7.1",
+ "jest-validate": "^24.7.0",
+ "micromatch": "^3.1.10",
+ "pretty-format": "^24.7.0",
+ "realpath-native": "^1.1.0"
+ }
+ },
+ "jest-diff": {
+ "version": "24.7.0",
+ "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-24.7.0.tgz",
+ "integrity": "sha512-ULQZ5B1lWpH70O4xsANC4tf4Ko6RrpwhE3PtG6ERjMg1TiYTC2Wp4IntJVGro6a8HG9luYHhhmF4grF0Pltckg==",
+ "requires": {
+ "chalk": "^2.0.1",
+ "diff-sequences": "^24.3.0",
+ "jest-get-type": "^24.3.0",
+ "pretty-format": "^24.7.0"
+ }
+ },
+ "jest-docblock": {
+ "version": "24.3.0",
+ "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-24.3.0.tgz",
+ "integrity": "sha512-nlANmF9Yq1dufhFlKG9rasfQlrY7wINJbo3q01tu56Jv5eBU5jirylhF2O5ZBnLxzOVBGRDz/9NAwNyBtG4Nyg==",
+ "requires": {
+ "detect-newline": "^2.1.0"
+ }
+ },
+ "jest-each": {
+ "version": "24.7.1",
+ "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-24.7.1.tgz",
+ "integrity": "sha512-4fsS8fEfLa3lfnI1Jw6NxjhyRTgfpuOVTeUZZFyVYqeTa4hPhr2YkToUhouuLTrL2eMGOfpbdMyRx0GQ/VooKA==",
+ "requires": {
+ "@jest/types": "^24.7.0",
+ "chalk": "^2.0.1",
+ "jest-get-type": "^24.3.0",
+ "jest-util": "^24.7.1",
+ "pretty-format": "^24.7.0"
+ }
+ },
+ "jest-environment-jsdom": {
+ "version": "24.7.1",
+ "resolved": "https://registry.npmjs.org/jest-environment-jsdom/-/jest-environment-jsdom-24.7.1.tgz",
+ "integrity": "sha512-Gnhb+RqE2JuQGb3kJsLF8vfqjt3PHKSstq4Xc8ic+ax7QKo4Z0RWGucU3YV+DwKR3T9SYc+3YCUQEJs8r7+Jxg==",
+ "requires": {
+ "@jest/environment": "^24.7.1",
+ "@jest/fake-timers": "^24.7.1",
+ "@jest/types": "^24.7.0",
+ "jest-mock": "^24.7.0",
+ "jest-util": "^24.7.1",
+ "jsdom": "^11.5.1"
+ }
+ },
+ "jest-environment-node": {
+ "version": "24.7.1",
+ "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-24.7.1.tgz",
+ "integrity": "sha512-GJJQt1p9/C6aj6yNZMvovZuxTUd+BEJprETdvTKSb4kHcw4mFj8777USQV0FJoJ4V3djpOwA5eWyPwfq//PFBA==",
+ "requires": {
+ "@jest/environment": "^24.7.1",
+ "@jest/fake-timers": "^24.7.1",
+ "@jest/types": "^24.7.0",
+ "jest-mock": "^24.7.0",
+ "jest-util": "^24.7.1"
+ }
+ },
+ "jest-get-type": {
+ "version": "24.3.0",
+ "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-24.3.0.tgz",
+ "integrity": "sha512-HYF6pry72YUlVcvUx3sEpMRwXEWGEPlJ0bSPVnB3b3n++j4phUEoSPcS6GC0pPJ9rpyPSe4cb5muFo6D39cXow=="
+ },
+ "jest-haste-map": {
+ "version": "24.7.1",
+ "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-24.7.1.tgz",
+ "integrity": "sha512-g0tWkzjpHD2qa03mTKhlydbmmYiA2KdcJe762SbfFo/7NIMgBWAA0XqQlApPwkWOF7Cxoi/gUqL0i6DIoLpMBw==",
+ "requires": {
+ "@jest/types": "^24.7.0",
+ "anymatch": "^2.0.0",
+ "fb-watchman": "^2.0.0",
+ "fsevents": "^1.2.7",
+ "graceful-fs": "^4.1.15",
+ "invariant": "^2.2.4",
+ "jest-serializer": "^24.4.0",
+ "jest-util": "^24.7.1",
+ "jest-worker": "^24.6.0",
+ "micromatch": "^3.1.10",
+ "sane": "^4.0.3",
+ "walker": "^1.0.7"
+ }
+ },
+ "jest-jasmine2": {
+ "version": "24.7.1",
+ "resolved": "https://registry.npmjs.org/jest-jasmine2/-/jest-jasmine2-24.7.1.tgz",
+ "integrity": "sha512-Y/9AOJDV1XS44wNwCaThq4Pw3gBPiOv/s6NcbOAkVRRUEPu+36L2xoPsqQXsDrxoBerqeyslpn2TpCI8Zr6J2w==",
+ "requires": {
+ "@babel/traverse": "^7.1.0",
+ "@jest/environment": "^24.7.1",
+ "@jest/test-result": "^24.7.1",
+ "@jest/types": "^24.7.0",
+ "chalk": "^2.0.1",
+ "co": "^4.6.0",
+ "expect": "^24.7.1",
+ "is-generator-fn": "^2.0.0",
+ "jest-each": "^24.7.1",
+ "jest-matcher-utils": "^24.7.0",
+ "jest-message-util": "^24.7.1",
+ "jest-runtime": "^24.7.1",
+ "jest-snapshot": "^24.7.1",
+ "jest-util": "^24.7.1",
+ "pretty-format": "^24.7.0",
+ "throat": "^4.0.0"
+ }
+ },
+ "jest-leak-detector": {
+ "version": "24.7.0",
+ "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-24.7.0.tgz",
+ "integrity": "sha512-zV0qHKZGXtmPVVzT99CVEcHE9XDf+8LwiE0Ob7jjezERiGVljmqKFWpV2IkG+rkFIEUHFEkMiICu7wnoPM/RoQ==",
+ "requires": {
+ "pretty-format": "^24.7.0"
+ }
+ },
+ "jest-matcher-utils": {
+ "version": "24.7.0",
+ "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-24.7.0.tgz",
+ "integrity": "sha512-158ieSgk3LNXeUhbVJYRXyTPSCqNgVXOp/GT7O94mYd3pk/8+odKTyR1JLtNOQSPzNi8NFYVONtvSWA/e1RDXg==",
+ "requires": {
+ "chalk": "^2.0.1",
+ "jest-diff": "^24.7.0",
+ "jest-get-type": "^24.3.0",
+ "pretty-format": "^24.7.0"
+ }
+ },
+ "jest-message-util": {
+ "version": "24.7.1",
+ "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-24.7.1.tgz",
+ "integrity": "sha512-dk0gqVtyqezCHbcbk60CdIf+8UHgD+lmRHifeH3JRcnAqh4nEyPytSc9/L1+cQyxC+ceaeP696N4ATe7L+omcg==",
+ "requires": {
+ "@babel/code-frame": "^7.0.0",
+ "@jest/test-result": "^24.7.1",
+ "@jest/types": "^24.7.0",
+ "@types/stack-utils": "^1.0.1",
+ "chalk": "^2.0.1",
+ "micromatch": "^3.1.10",
+ "slash": "^2.0.0",
+ "stack-utils": "^1.0.1"
+ }
+ },
+ "jest-mock": {
+ "version": "24.7.0",
+ "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-24.7.0.tgz",
+ "integrity": "sha512-6taW4B4WUcEiT2V9BbOmwyGuwuAFT2G8yghF7nyNW1/2gq5+6aTqSPcS9lS6ArvEkX55vbPAS/Jarx5LSm4Fng==",
+ "requires": {
+ "@jest/types": "^24.7.0"
+ }
+ },
+ "jest-pnp-resolver": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.1.tgz",
+ "integrity": "sha512-pgFw2tm54fzgYvc/OHrnysABEObZCUNFnhjoRjaVOCN8NYc032/gVjPaHD4Aq6ApkSieWtfKAFQtmDKAmhupnQ=="
+ },
+ "jest-regex-util": {
+ "version": "24.3.0",
+ "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-24.3.0.tgz",
+ "integrity": "sha512-tXQR1NEOyGlfylyEjg1ImtScwMq8Oh3iJbGTjN7p0J23EuVX1MA8rwU69K4sLbCmwzgCUbVkm0FkSF9TdzOhtg=="
+ },
+ "jest-resolve": {
+ "version": "24.7.1",
+ "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-24.7.1.tgz",
+ "integrity": "sha512-Bgrc+/UUZpGJ4323sQyj85hV9d+ANyPNu6XfRDUcyFNX1QrZpSoM0kE4Mb2vZMAYTJZsBFzYe8X1UaOkOELSbw==",
+ "requires": {
+ "@jest/types": "^24.7.0",
+ "browser-resolve": "^1.11.3",
+ "chalk": "^2.0.1",
+ "jest-pnp-resolver": "^1.2.1",
+ "realpath-native": "^1.1.0"
+ }
+ },
+ "jest-resolve-dependencies": {
+ "version": "24.7.1",
+ "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-24.7.1.tgz",
+ "integrity": "sha512-2Eyh5LJB2liNzfk4eo7bD1ZyBbqEJIyyrFtZG555cSWW9xVHxII2NuOkSl1yUYTAYCAmM2f2aIT5A7HzNmubyg==",
+ "requires": {
+ "@jest/types": "^24.7.0",
+ "jest-regex-util": "^24.3.0",
+ "jest-snapshot": "^24.7.1"
+ }
+ },
+ "jest-runner": {
+ "version": "24.7.1",
+ "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-24.7.1.tgz",
+ "integrity": "sha512-aNFc9liWU/xt+G9pobdKZ4qTeG/wnJrJna3VqunziDNsWT3EBpmxXZRBMKCsNMyfy+A/XHiV+tsMLufdsNdgCw==",
+ "requires": {
+ "@jest/console": "^24.7.1",
+ "@jest/environment": "^24.7.1",
+ "@jest/test-result": "^24.7.1",
+ "@jest/types": "^24.7.0",
+ "chalk": "^2.4.2",
+ "exit": "^0.1.2",
+ "graceful-fs": "^4.1.15",
+ "jest-config": "^24.7.1",
+ "jest-docblock": "^24.3.0",
+ "jest-haste-map": "^24.7.1",
+ "jest-jasmine2": "^24.7.1",
+ "jest-leak-detector": "^24.7.0",
+ "jest-message-util": "^24.7.1",
+ "jest-resolve": "^24.7.1",
+ "jest-runtime": "^24.7.1",
+ "jest-util": "^24.7.1",
+ "jest-worker": "^24.6.0",
+ "source-map-support": "^0.5.6",
+ "throat": "^4.0.0"
+ }
+ },
+ "jest-runtime": {
+ "version": "24.7.1",
+ "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-24.7.1.tgz",
+ "integrity": "sha512-0VAbyBy7tll3R+82IPJpf6QZkokzXPIS71aDeqh+WzPRXRCNz6StQ45otFariPdJ4FmXpDiArdhZrzNAC3sj6A==",
+ "requires": {
+ "@jest/console": "^24.7.1",
+ "@jest/environment": "^24.7.1",
+ "@jest/source-map": "^24.3.0",
+ "@jest/transform": "^24.7.1",
+ "@jest/types": "^24.7.0",
+ "@types/yargs": "^12.0.2",
+ "chalk": "^2.0.1",
+ "exit": "^0.1.2",
+ "glob": "^7.1.3",
+ "graceful-fs": "^4.1.15",
+ "jest-config": "^24.7.1",
+ "jest-haste-map": "^24.7.1",
+ "jest-message-util": "^24.7.1",
+ "jest-mock": "^24.7.0",
+ "jest-regex-util": "^24.3.0",
+ "jest-resolve": "^24.7.1",
+ "jest-snapshot": "^24.7.1",
+ "jest-util": "^24.7.1",
+ "jest-validate": "^24.7.0",
+ "realpath-native": "^1.1.0",
+ "slash": "^2.0.0",
+ "strip-bom": "^3.0.0",
+ "yargs": "^12.0.2"
+ }
+ },
+ "jest-serializer": {
+ "version": "24.4.0",
+ "resolved": "https://registry.npmjs.org/jest-serializer/-/jest-serializer-24.4.0.tgz",
+ "integrity": "sha512-k//0DtglVstc1fv+GY/VHDIjrtNjdYvYjMlbLUed4kxrE92sIUewOi5Hj3vrpB8CXfkJntRPDRjCrCvUhBdL8Q=="
+ },
+ "jest-snapshot": {
+ "version": "24.7.1",
+ "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-24.7.1.tgz",
+ "integrity": "sha512-8Xk5O4p+JsZZn4RCNUS3pxA+ORKpEKepE+a5ejIKrId9CwrVN0NY+vkqEkXqlstA5NMBkNahXkR/4qEBy0t5yA==",
+ "requires": {
+ "@babel/types": "^7.0.0",
+ "@jest/types": "^24.7.0",
+ "chalk": "^2.0.1",
+ "expect": "^24.7.1",
+ "jest-diff": "^24.7.0",
+ "jest-matcher-utils": "^24.7.0",
+ "jest-message-util": "^24.7.1",
+ "jest-resolve": "^24.7.1",
+ "mkdirp": "^0.5.1",
+ "natural-compare": "^1.4.0",
+ "pretty-format": "^24.7.0",
+ "semver": "^5.5.0"
+ }
+ },
+ "jest-util": {
+ "version": "24.7.1",
+ "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-24.7.1.tgz",
+ "integrity": "sha512-/KilOue2n2rZ5AnEBYoxOXkeTu6vi7cjgQ8MXEkih0oeAXT6JkS3fr7/j8+engCjciOU1Nq5loMSKe0A1oeX0A==",
+ "requires": {
+ "@jest/console": "^24.7.1",
+ "@jest/fake-timers": "^24.7.1",
+ "@jest/source-map": "^24.3.0",
+ "@jest/test-result": "^24.7.1",
+ "@jest/types": "^24.7.0",
+ "callsites": "^3.0.0",
+ "chalk": "^2.0.1",
+ "graceful-fs": "^4.1.15",
+ "is-ci": "^2.0.0",
+ "mkdirp": "^0.5.1",
+ "slash": "^2.0.0",
+ "source-map": "^0.6.0"
+ },
+ "dependencies": {
+ "source-map": {
+ "version": "0.6.1",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
+ "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="
+ }
+ }
+ },
+ "jest-validate": {
+ "version": "24.7.0",
+ "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-24.7.0.tgz",
+ "integrity": "sha512-cgai/gts9B2chz1rqVdmLhzYxQbgQurh1PEQSvSgPZ8KGa1AqXsqC45W5wKEwzxKrWqypuQrQxnF4+G9VejJJA==",
+ "requires": {
+ "@jest/types": "^24.7.0",
+ "camelcase": "^5.0.0",
+ "chalk": "^2.0.1",
+ "jest-get-type": "^24.3.0",
+ "leven": "^2.1.0",
+ "pretty-format": "^24.7.0"
+ }
+ },
+ "jest-watcher": {
+ "version": "24.7.1",
+ "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-24.7.1.tgz",
+ "integrity": "sha512-Wd6TepHLRHVKLNPacEsBwlp9raeBIO+01xrN24Dek4ggTS8HHnOzYSFnvp+6MtkkJ3KfMzy220KTi95e2rRkrw==",
+ "requires": {
+ "@jest/test-result": "^24.7.1",
+ "@jest/types": "^24.7.0",
+ "@types/yargs": "^12.0.9",
+ "ansi-escapes": "^3.0.0",
+ "chalk": "^2.0.1",
+ "jest-util": "^24.7.1",
+ "string-length": "^2.0.0"
+ }
+ },
+ "jest-worker": {
+ "version": "24.6.0",
+ "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-24.6.0.tgz",
+ "integrity": "sha512-jDwgW5W9qGNvpI1tNnvajh0a5IE/PuGLFmHk6aR/BZFz8tSgGw17GsDPXAJ6p91IvYDjOw8GpFbvvZGAK+DPQQ==",
+ "requires": {
+ "merge-stream": "^1.0.1",
+ "supports-color": "^6.1.0"
+ },
+ "dependencies": {
+ "supports-color": {
+ "version": "6.1.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz",
+ "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==",
+ "requires": {
+ "has-flag": "^3.0.0"
+ }
+ }
+ }
+ },
+ "js-tokens": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
+ "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ=="
+ },
+ "js-yaml": {
+ "version": "3.13.1",
+ "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz",
+ "integrity": "sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==",
+ "requires": {
+ "argparse": "^1.0.7",
+ "esprima": "^4.0.0"
+ }
+ },
+ "jsbn": {
+ "version": "0.1.1",
+ "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz",
+ "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM="
+ },
+ "jsdom": {
+ "version": "11.12.0",
+ "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-11.12.0.tgz",
+ "integrity": "sha512-y8Px43oyiBM13Zc1z780FrfNLJCXTL40EWlty/LXUtcjykRBNgLlCjWXpfSPBl2iv+N7koQN+dvqszHZgT/Fjw==",
+ "requires": {
+ "abab": "^2.0.0",
+ "acorn": "^5.5.3",
+ "acorn-globals": "^4.1.0",
+ "array-equal": "^1.0.0",
+ "cssom": ">= 0.3.2 < 0.4.0",
+ "cssstyle": "^1.0.0",
+ "data-urls": "^1.0.0",
+ "domexception": "^1.0.1",
+ "escodegen": "^1.9.1",
+ "html-encoding-sniffer": "^1.0.2",
+ "left-pad": "^1.3.0",
+ "nwsapi": "^2.0.7",
+ "parse5": "4.0.0",
+ "pn": "^1.1.0",
+ "request": "^2.87.0",
+ "request-promise-native": "^1.0.5",
+ "sax": "^1.2.4",
+ "symbol-tree": "^3.2.2",
+ "tough-cookie": "^2.3.4",
+ "w3c-hr-time": "^1.0.1",
+ "webidl-conversions": "^4.0.2",
+ "whatwg-encoding": "^1.0.3",
+ "whatwg-mimetype": "^2.1.0",
+ "whatwg-url": "^6.4.1",
+ "ws": "^5.2.0",
+ "xml-name-validator": "^3.0.0"
+ },
+ "dependencies": {
+ "acorn": {
+ "version": "5.7.3",
+ "resolved": "https://registry.npmjs.org/acorn/-/acorn-5.7.3.tgz",
+ "integrity": "sha512-T/zvzYRfbVojPWahDsE5evJdHb3oJoQfFbsrKM7w5Zcs++Tr257tia3BmMP8XYVjp1S9RZXQMh7gao96BlqZOw=="
+ }
+ }
+ },
+ "jsesc": {
+ "version": "2.5.2",
+ "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz",
+ "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA=="
+ },
+ "json-parse-better-errors": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz",
+ "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw=="
+ },
+ "json-schema": {
+ "version": "0.2.3",
+ "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz",
+ "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM="
+ },
+ "json-schema-traverse": {
+ "version": "0.4.1",
+ "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
+ "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg=="
+ },
+ "json-stable-stringify-without-jsonify": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz",
+ "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE="
+ },
+ "json-stringify-safe": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz",
+ "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus="
+ },
+ "json3": {
+ "version": "3.3.2",
+ "resolved": "https://registry.npmjs.org/json3/-/json3-3.3.2.tgz",
+ "integrity": "sha1-PAQ0dD35Pi9cQq7nsZvLSDV19OE="
+ },
+ "json5": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz",
+ "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==",
+ "requires": {
+ "minimist": "^1.2.0"
+ }
+ },
+ "jsprim": {
+ "version": "1.4.1",
+ "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz",
+ "integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=",
+ "requires": {
+ "assert-plus": "1.0.0",
+ "extsprintf": "1.3.0",
+ "json-schema": "0.2.3",
+ "verror": "1.10.0"
+ }
+ },
+ "killable": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/killable/-/killable-1.0.1.tgz",
+ "integrity": "sha512-LzqtLKlUwirEUyl/nicirVmNiPvYs7l5n8wOPP7fyJVpUPkvCnW/vuiXGpylGUlnPDnB7311rARzAt3Mhswpjg=="
+ },
+ "kind-of": {
+ "version": "6.0.2",
+ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz",
+ "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA=="
+ },
+ "kleur": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz",
+ "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w=="
+ },
+ "lcid": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/lcid/-/lcid-2.0.0.tgz",
+ "integrity": "sha512-avPEb8P8EGnwXKClwsNUgryVjllcRqtMYa49NTsbQagYuT1DcXnl1915oxWjoyGrXR6zH/Y0Zc96xWsPcoDKeA==",
+ "requires": {
+ "invert-kv": "^2.0.0"
+ }
+ },
+ "left-pad": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/left-pad/-/left-pad-1.3.0.tgz",
+ "integrity": "sha512-XI5MPzVNApjAyhQzphX8BkmKsKUxD4LdyK24iZeQGinBN9yTQT3bFlCBy/aVx2HrNcqQGsdot8ghrjyrvMCoEA=="
+ },
+ "leven": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/leven/-/leven-2.1.0.tgz",
+ "integrity": "sha1-wuep93IJTe6dNCAq6KzORoeHVYA="
+ },
+ "levn": {
+ "version": "0.3.0",
+ "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz",
+ "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=",
+ "requires": {
+ "prelude-ls": "~1.1.2",
+ "type-check": "~0.3.2"
+ }
+ },
+ "load-json-file": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-4.0.0.tgz",
+ "integrity": "sha1-L19Fq5HjMhYjT9U62rZo607AmTs=",
+ "requires": {
+ "graceful-fs": "^4.1.2",
+ "parse-json": "^4.0.0",
+ "pify": "^3.0.0",
+ "strip-bom": "^3.0.0"
+ }
+ },
+ "loader-runner": {
+ "version": "2.4.0",
+ "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-2.4.0.tgz",
+ "integrity": "sha512-Jsmr89RcXGIwivFY21FcRrisYZfvLMTWx5kOLc+JTxtpBOG6xML0vzbc6SEQG2FO9/4Fc3wW4LVcB5DmGflaRw=="
+ },
+ "loader-utils": {
+ "version": "1.2.3",
+ "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.2.3.tgz",
+ "integrity": "sha512-fkpz8ejdnEMG3s37wGL07iSBDg99O9D5yflE9RGNH3hRdx9SOwYfnGYdZOUIZitN8E+E2vkq3MUMYMvPYl5ZZA==",
+ "requires": {
+ "big.js": "^5.2.2",
+ "emojis-list": "^2.0.0",
+ "json5": "^1.0.1"
+ }
+ },
+ "locate-path": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz",
+ "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==",
+ "requires": {
+ "p-locate": "^3.0.0",
+ "path-exists": "^3.0.0"
+ }
+ },
+ "lodash": {
+ "version": "4.17.11",
+ "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz",
+ "integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg=="
+ },
+ "lodash.sortby": {
+ "version": "4.7.0",
+ "resolved": "https://registry.npmjs.org/lodash.sortby/-/lodash.sortby-4.7.0.tgz",
+ "integrity": "sha1-7dFMgk4sycHgsKG0K7UhBRakJDg="
+ },
+ "lodash.unescape": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/lodash.unescape/-/lodash.unescape-4.0.1.tgz",
+ "integrity": "sha1-vyJJiGzlFM2hEvrpIYzcBlIR/Jw="
+ },
+ "log-symbols": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-2.2.0.tgz",
+ "integrity": "sha512-VeIAFslyIerEJLXHziedo2basKbMKtTw3vfn5IzG0XTjhAVEJyNHnL2p7vc+wBDSdQuUpNw3M2u6xb9QsAY5Eg==",
+ "requires": {
+ "chalk": "^2.0.1"
+ }
+ },
+ "loglevel": {
+ "version": "1.6.1",
+ "resolved": "https://registry.npmjs.org/loglevel/-/loglevel-1.6.1.tgz",
+ "integrity": "sha1-4PyVEztu8nbNyIh82vJKpvFW+Po="
+ },
+ "loglevelnext": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/loglevelnext/-/loglevelnext-1.0.5.tgz",
+ "integrity": "sha512-V/73qkPuJmx4BcBF19xPBr+0ZRVBhc4POxvZTZdMeXpJ4NItXSJ/MSwuFT0kQJlCbXvdlZoQQ/418bS1y9Jh6A==",
+ "requires": {
+ "es6-symbol": "^3.1.1",
+ "object.assign": "^4.1.0"
+ }
+ },
+ "loose-envify": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz",
+ "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==",
+ "requires": {
+ "js-tokens": "^3.0.0 || ^4.0.0"
+ }
+ },
+ "lru-cache": {
+ "version": "5.1.1",
+ "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz",
+ "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==",
+ "requires": {
+ "yallist": "^3.0.2"
+ }
+ },
+ "make-dir": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-1.3.0.tgz",
+ "integrity": "sha512-2w31R7SJtieJJnQtGc7RVL2StM2vGYVfqUOvUDxH6bC6aJTxPxTF0GnIgCyu7tjockiUWAYQRbxa7vKn34s5sQ==",
+ "requires": {
+ "pify": "^3.0.0"
+ }
+ },
+ "make-error": {
+ "version": "1.3.5",
+ "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.5.tgz",
+ "integrity": "sha512-c3sIjNUow0+8swNwVpqoH4YCShKNFkMaw6oH1mNS2haDZQqkeZFlHS3dhoeEbKKmJB4vXpJucU6oH75aDYeE9g=="
+ },
+ "makeerror": {
+ "version": "1.0.11",
+ "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.11.tgz",
+ "integrity": "sha1-4BpckQnyr3lmDk6LlYd5AYT1qWw=",
+ "requires": {
+ "tmpl": "1.0.x"
+ }
+ },
+ "mamacro": {
+ "version": "0.0.3",
+ "resolved": "https://registry.npmjs.org/mamacro/-/mamacro-0.0.3.tgz",
+ "integrity": "sha512-qMEwh+UujcQ+kbz3T6V+wAmO2U8veoq2w+3wY8MquqwVA3jChfwY+Tk52GZKDfACEPjuZ7r2oJLejwpt8jtwTA=="
+ },
+ "map-age-cleaner": {
+ "version": "0.1.3",
+ "resolved": "https://registry.npmjs.org/map-age-cleaner/-/map-age-cleaner-0.1.3.tgz",
+ "integrity": "sha512-bJzx6nMoP6PDLPBFmg7+xRKeFZvFboMrGlxmNj9ClvX53KrmvM5bXFXEWjbz4cz1AFn+jWJ9z/DJSz7hrs0w3w==",
+ "requires": {
+ "p-defer": "^1.0.0"
+ }
+ },
+ "map-cache": {
+ "version": "0.2.2",
+ "resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz",
+ "integrity": "sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8="
+ },
+ "map-visit": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/map-visit/-/map-visit-1.0.0.tgz",
+ "integrity": "sha1-7Nyo8TFE5mDxtb1B8S80edmN+48=",
+ "requires": {
+ "object-visit": "^1.0.0"
+ }
+ },
+ "md5.js": {
+ "version": "1.3.5",
+ "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz",
+ "integrity": "sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==",
+ "requires": {
+ "hash-base": "^3.0.0",
+ "inherits": "^2.0.1",
+ "safe-buffer": "^5.1.2"
+ }
+ },
+ "media-typer": {
+ "version": "0.3.0",
+ "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz",
+ "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g="
+ },
+ "mem": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/mem/-/mem-4.1.0.tgz",
+ "integrity": "sha512-I5u6Q1x7wxO0kdOpYBB28xueHADYps5uty/zg936CiG8NTe5sJL8EjrCuLneuDW3PlMdZBGDIn8BirEVdovZvg==",
+ "requires": {
+ "map-age-cleaner": "^0.1.1",
+ "mimic-fn": "^1.0.0",
+ "p-is-promise": "^2.0.0"
+ }
+ },
+ "memory-fs": {
+ "version": "0.4.1",
+ "resolved": "https://registry.npmjs.org/memory-fs/-/memory-fs-0.4.1.tgz",
+ "integrity": "sha1-OpoguEYlI+RHz7x+i7gO1me/xVI=",
+ "requires": {
+ "errno": "^0.1.3",
+ "readable-stream": "^2.0.1"
+ }
+ },
+ "merge-descriptors": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz",
+ "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E="
+ },
+ "merge-stream": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-1.0.1.tgz",
+ "integrity": "sha1-QEEgLVCKNCugAXQAjfDCUbjBNeE=",
+ "requires": {
+ "readable-stream": "^2.0.1"
+ }
+ },
+ "methods": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz",
+ "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4="
+ },
+ "micromatch": {
+ "version": "3.1.10",
+ "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz",
+ "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==",
+ "requires": {
+ "arr-diff": "^4.0.0",
+ "array-unique": "^0.3.2",
+ "braces": "^2.3.1",
+ "define-property": "^2.0.2",
+ "extend-shallow": "^3.0.2",
+ "extglob": "^2.0.4",
+ "fragment-cache": "^0.2.1",
+ "kind-of": "^6.0.2",
+ "nanomatch": "^1.2.9",
+ "object.pick": "^1.3.0",
+ "regex-not": "^1.0.0",
+ "snapdragon": "^0.8.1",
+ "to-regex": "^3.0.2"
+ }
+ },
+ "miller-rabin": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/miller-rabin/-/miller-rabin-4.0.1.tgz",
+ "integrity": "sha512-115fLhvZVqWwHPbClyntxEVfVDfl9DLLTuJvq3g2O/Oxi8AiNouAHvDSzHS0viUJc+V5vm3eq91Xwqn9dp4jRA==",
+ "requires": {
+ "bn.js": "^4.0.0",
+ "brorand": "^1.0.1"
+ }
+ },
+ "mime": {
+ "version": "1.4.1",
+ "resolved": "https://registry.npmjs.org/mime/-/mime-1.4.1.tgz",
+ "integrity": "sha512-KI1+qOZu5DcW6wayYHSzR/tXKCDC5Om4s1z2QJjDULzLcmf3DvzS7oluY4HCTrc+9FiKmWUgeNLg7W3uIQvxtQ=="
+ },
+ "mime-db": {
+ "version": "1.38.0",
+ "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.38.0.tgz",
+ "integrity": "sha512-bqVioMFFzc2awcdJZIzR3HjZFX20QhilVS7hytkKrv7xFAn8bM1gzc/FOX2awLISvWe0PV8ptFKcon+wZ5qYkg=="
+ },
+ "mime-types": {
+ "version": "2.1.22",
+ "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.22.tgz",
+ "integrity": "sha512-aGl6TZGnhm/li6F7yx82bJiBZwgiEa4Hf6CNr8YO+r5UHr53tSTYZb102zyU50DOWWKeOv0uQLRL0/9EiKWCog==",
+ "requires": {
+ "mime-db": "~1.38.0"
+ }
+ },
+ "mimic-fn": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.2.0.tgz",
+ "integrity": "sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ=="
+ },
+ "mini-css-extract-plugin": {
+ "version": "0.5.0",
+ "resolved": "https://registry.npmjs.org/mini-css-extract-plugin/-/mini-css-extract-plugin-0.5.0.tgz",
+ "integrity": "sha512-IuaLjruM0vMKhUUT51fQdQzBYTX49dLj8w68ALEAe2A4iYNpIC4eMac67mt3NzycvjOlf07/kYxJDc0RTl1Wqw==",
+ "requires": {
+ "loader-utils": "^1.1.0",
+ "schema-utils": "^1.0.0",
+ "webpack-sources": "^1.1.0"
+ }
+ },
+ "minimalistic-assert": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz",
+ "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A=="
+ },
+ "minimalistic-crypto-utils": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz",
+ "integrity": "sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo="
+ },
+ "minimatch": {
+ "version": "3.0.4",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
+ "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
+ "requires": {
+ "brace-expansion": "^1.1.7"
+ }
+ },
+ "minimist": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz",
+ "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ="
+ },
+ "mississippi": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/mississippi/-/mississippi-3.0.0.tgz",
+ "integrity": "sha512-x471SsVjUtBRtcvd4BzKE9kFC+/2TeWgKCgw0bZcw1b9l2X3QX5vCWgF+KaZaYm87Ss//rHnWryupDrgLvmSkA==",
+ "requires": {
+ "concat-stream": "^1.5.0",
+ "duplexify": "^3.4.2",
+ "end-of-stream": "^1.1.0",
+ "flush-write-stream": "^1.0.0",
+ "from2": "^2.1.0",
+ "parallel-transform": "^1.1.0",
+ "pump": "^3.0.0",
+ "pumpify": "^1.3.3",
+ "stream-each": "^1.1.0",
+ "through2": "^2.0.0"
+ }
+ },
+ "mixin-deep": {
+ "version": "1.3.1",
+ "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.1.tgz",
+ "integrity": "sha512-8ZItLHeEgaqEvd5lYBXfm4EZSFCX29Jb9K+lAHhDKzReKBQKj3R+7NOF6tjqYi9t4oI8VUfaWITJQm86wnXGNQ==",
+ "requires": {
+ "for-in": "^1.0.2",
+ "is-extendable": "^1.0.1"
+ },
+ "dependencies": {
+ "is-extendable": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz",
+ "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==",
+ "requires": {
+ "is-plain-object": "^2.0.4"
+ }
+ }
+ }
+ },
+ "mkdirp": {
+ "version": "0.5.1",
+ "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz",
+ "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=",
+ "requires": {
+ "minimist": "0.0.8"
+ },
+ "dependencies": {
+ "minimist": {
+ "version": "0.0.8",
+ "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz",
+ "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0="
+ }
+ }
+ },
+ "move-concurrently": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/move-concurrently/-/move-concurrently-1.0.1.tgz",
+ "integrity": "sha1-viwAX9oy4LKa8fBdfEszIUxwH5I=",
+ "requires": {
+ "aproba": "^1.1.1",
+ "copy-concurrently": "^1.0.0",
+ "fs-write-stream-atomic": "^1.0.8",
+ "mkdirp": "^0.5.1",
+ "rimraf": "^2.5.4",
+ "run-queue": "^1.0.3"
+ }
+ },
+ "ms": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+ "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
+ },
+ "multicast-dns": {
+ "version": "6.2.3",
+ "resolved": "https://registry.npmjs.org/multicast-dns/-/multicast-dns-6.2.3.tgz",
+ "integrity": "sha512-ji6J5enbMyGRHIAkAOu3WdV8nggqviKCEKtXcOqfphZZtQrmHKycfynJ2V7eVPUA4NhJ6V7Wf4TmGbTwKE9B6g==",
+ "requires": {
+ "dns-packet": "^1.3.1",
+ "thunky": "^1.0.2"
+ }
+ },
+ "multicast-dns-service-types": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/multicast-dns-service-types/-/multicast-dns-service-types-1.1.0.tgz",
+ "integrity": "sha1-iZ8R2WhuXgXLkbNdXw5jt3PPyQE="
+ },
+ "mute-stream": {
+ "version": "0.0.7",
+ "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.7.tgz",
+ "integrity": "sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s="
+ },
+ "nan": {
+ "version": "2.12.1",
+ "resolved": "https://registry.npmjs.org/nan/-/nan-2.12.1.tgz",
+ "integrity": "sha512-JY7V6lRkStKcKTvHO5NVSQRv+RV+FIL5pvDoLiAtSL9pKlC5x9PKQcZDsq7m4FO4d57mkhC6Z+QhAh3Jdk5JFw==",
+ "optional": true
+ },
+ "nanomatch": {
+ "version": "1.2.13",
+ "resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz",
+ "integrity": "sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA==",
+ "requires": {
+ "arr-diff": "^4.0.0",
+ "array-unique": "^0.3.2",
+ "define-property": "^2.0.2",
+ "extend-shallow": "^3.0.2",
+ "fragment-cache": "^0.2.1",
+ "is-windows": "^1.0.2",
+ "kind-of": "^6.0.2",
+ "object.pick": "^1.3.0",
+ "regex-not": "^1.0.0",
+ "snapdragon": "^0.8.1",
+ "to-regex": "^3.0.1"
+ }
+ },
+ "natural-compare": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz",
+ "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc="
+ },
+ "negotiator": {
+ "version": "0.6.1",
+ "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.1.tgz",
+ "integrity": "sha1-KzJxhOiZIQEXeyhWP7XnECrNDKk="
+ },
+ "neo-async": {
+ "version": "2.6.0",
+ "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.0.tgz",
+ "integrity": "sha512-MFh0d/Wa7vkKO3Y3LlacqAEeHK0mckVqzDieUKTT+KGxi+zIpeVsFxymkIiRpbpDziHc290Xr9A1O4Om7otoRA=="
+ },
+ "next-tick": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.0.0.tgz",
+ "integrity": "sha1-yobR/ogoFpsBICCOPchCS524NCw="
+ },
+ "nice-try": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz",
+ "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ=="
+ },
+ "node-forge": {
+ "version": "0.7.5",
+ "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-0.7.5.tgz",
+ "integrity": "sha512-MmbQJ2MTESTjt3Gi/3yG1wGpIMhUfcIypUCGtTizFR9IiccFwxSpfp0vtIZlkFclEqERemxfnSdZEMR9VqqEFQ=="
+ },
+ "node-int64": {
+ "version": "0.4.0",
+ "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz",
+ "integrity": "sha1-h6kGXNs1XTGC2PlM4RGIuCXGijs="
+ },
+ "node-libs-browser": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/node-libs-browser/-/node-libs-browser-2.2.0.tgz",
+ "integrity": "sha512-5MQunG/oyOaBdttrL40dA7bUfPORLRWMUJLQtMg7nluxUvk5XwnLdL9twQHFAjRx/y7mIMkLKT9++qPbbk6BZA==",
+ "requires": {
+ "assert": "^1.1.1",
+ "browserify-zlib": "^0.2.0",
+ "buffer": "^4.3.0",
+ "console-browserify": "^1.1.0",
+ "constants-browserify": "^1.0.0",
+ "crypto-browserify": "^3.11.0",
+ "domain-browser": "^1.1.1",
+ "events": "^3.0.0",
+ "https-browserify": "^1.0.0",
+ "os-browserify": "^0.3.0",
+ "path-browserify": "0.0.0",
+ "process": "^0.11.10",
+ "punycode": "^1.2.4",
+ "querystring-es3": "^0.2.0",
+ "readable-stream": "^2.3.3",
+ "stream-browserify": "^2.0.1",
+ "stream-http": "^2.7.2",
+ "string_decoder": "^1.0.0",
+ "timers-browserify": "^2.0.4",
+ "tty-browserify": "0.0.0",
+ "url": "^0.11.0",
+ "util": "^0.11.0",
+ "vm-browserify": "0.0.4"
+ },
+ "dependencies": {
+ "punycode": {
+ "version": "1.4.1",
+ "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz",
+ "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4="
+ }
+ }
+ },
+ "node-modules-regexp": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/node-modules-regexp/-/node-modules-regexp-1.0.0.tgz",
+ "integrity": "sha1-jZ2+KJZKSsVxLpExZCEHxx6Q7EA="
+ },
+ "node-notifier": {
+ "version": "5.4.0",
+ "resolved": "https://registry.npmjs.org/node-notifier/-/node-notifier-5.4.0.tgz",
+ "integrity": "sha512-SUDEb+o71XR5lXSTyivXd9J7fCloE3SyP4lSgt3lU2oSANiox+SxlNRGPjDKrwU1YN3ix2KN/VGGCg0t01rttQ==",
+ "requires": {
+ "growly": "^1.3.0",
+ "is-wsl": "^1.1.0",
+ "semver": "^5.5.0",
+ "shellwords": "^0.1.1",
+ "which": "^1.3.0"
+ }
+ },
+ "normalize-package-data": {
+ "version": "2.5.0",
+ "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz",
+ "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==",
+ "requires": {
+ "hosted-git-info": "^2.1.4",
+ "resolve": "^1.10.0",
+ "semver": "2 || 3 || 4 || 5",
+ "validate-npm-package-license": "^3.0.1"
+ }
+ },
+ "normalize-path": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
+ "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA=="
+ },
+ "npm-run-path": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz",
+ "integrity": "sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=",
+ "requires": {
+ "path-key": "^2.0.0"
+ }
+ },
+ "number-is-nan": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz",
+ "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0="
+ },
+ "nwsapi": {
+ "version": "2.1.3",
+ "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.1.3.tgz",
+ "integrity": "sha512-RowAaJGEgYXEZfQ7tvvdtAQUKPyTR6T6wNu0fwlNsGQYr/h3yQc6oI8WnVZh3Y/Sylwc+dtAlvPqfFZjhTyk3A=="
+ },
+ "oauth-sign": {
+ "version": "0.9.0",
+ "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz",
+ "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ=="
+ },
+ "object-assign": {
+ "version": "4.1.1",
+ "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
+ "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM="
+ },
+ "object-copy": {
+ "version": "0.1.0",
+ "resolved": "https://registry.npmjs.org/object-copy/-/object-copy-0.1.0.tgz",
+ "integrity": "sha1-fn2Fi3gb18mRpBupde04EnVOmYw=",
+ "requires": {
+ "copy-descriptor": "^0.1.0",
+ "define-property": "^0.2.5",
+ "kind-of": "^3.0.3"
+ },
+ "dependencies": {
+ "define-property": {
+ "version": "0.2.5",
+ "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz",
+ "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=",
+ "requires": {
+ "is-descriptor": "^0.1.0"
+ }
+ },
+ "kind-of": {
+ "version": "3.2.2",
+ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
+ "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
+ "requires": {
+ "is-buffer": "^1.1.5"
+ }
+ }
+ }
+ },
+ "object-keys": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.0.tgz",
+ "integrity": "sha512-6OO5X1+2tYkNyNEx6TsCxEqFfRWaqx6EtMiSbGrw8Ob8v9Ne+Hl8rBAgLBZn5wjEz3s/s6U1WXFUFOcxxAwUpg=="
+ },
+ "object-visit": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/object-visit/-/object-visit-1.0.1.tgz",
+ "integrity": "sha1-95xEk68MU3e1n+OdOV5BBC3QRbs=",
+ "requires": {
+ "isobject": "^3.0.0"
+ }
+ },
+ "object.assign": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.0.tgz",
+ "integrity": "sha512-exHJeq6kBKj58mqGyTQ9DFvrZC/eR6OwxzoM9YRoGBqrXYonaFyGiFMuc9VZrXf7DarreEwMpurG3dd+CNyW5w==",
+ "requires": {
+ "define-properties": "^1.1.2",
+ "function-bind": "^1.1.1",
+ "has-symbols": "^1.0.0",
+ "object-keys": "^1.0.11"
+ }
+ },
+ "object.getownpropertydescriptors": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.0.3.tgz",
+ "integrity": "sha1-h1jIRvW0B62rDyNuCYbxSwUcqhY=",
+ "requires": {
+ "define-properties": "^1.1.2",
+ "es-abstract": "^1.5.1"
+ }
+ },
+ "object.pick": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz",
+ "integrity": "sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c=",
+ "requires": {
+ "isobject": "^3.0.1"
+ }
+ },
+ "obuf": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/obuf/-/obuf-1.1.2.tgz",
+ "integrity": "sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg=="
+ },
+ "on-finished": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz",
+ "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=",
+ "requires": {
+ "ee-first": "1.1.1"
+ }
+ },
+ "on-headers": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz",
+ "integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA=="
+ },
+ "once": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
+ "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
+ "requires": {
+ "wrappy": "1"
+ }
+ },
+ "onetime": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/onetime/-/onetime-2.0.1.tgz",
+ "integrity": "sha1-BnQoIw/WdEOyeUsiu6UotoZ5YtQ=",
+ "requires": {
+ "mimic-fn": "^1.0.0"
+ }
+ },
+ "opn": {
+ "version": "5.5.0",
+ "resolved": "https://registry.npmjs.org/opn/-/opn-5.5.0.tgz",
+ "integrity": "sha512-PqHpggC9bLV0VeWcdKhkpxY+3JTzetLSqTCWL/z/tFIbI6G8JCjondXklT1JinczLz2Xib62sSp0T/gKT4KksA==",
+ "requires": {
+ "is-wsl": "^1.1.0"
+ }
+ },
+ "optimist": {
+ "version": "0.6.1",
+ "resolved": "https://registry.npmjs.org/optimist/-/optimist-0.6.1.tgz",
+ "integrity": "sha1-2j6nRob6IaGaERwybpDrFaAZZoY=",
+ "requires": {
+ "minimist": "~0.0.1",
+ "wordwrap": "~0.0.2"
+ },
+ "dependencies": {
+ "minimist": {
+ "version": "0.0.10",
+ "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.10.tgz",
+ "integrity": "sha1-3j+YVD2/lggr5IrRoMfNqDYwHc8="
+ },
+ "wordwrap": {
+ "version": "0.0.3",
+ "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz",
+ "integrity": "sha1-o9XabNXAvAAI03I0u68b7WMFkQc="
+ }
+ }
+ },
+ "optionator": {
+ "version": "0.8.2",
+ "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.2.tgz",
+ "integrity": "sha1-NkxeQJ0/TWMB1sC0wFu6UBgK62Q=",
+ "requires": {
+ "deep-is": "~0.1.3",
+ "fast-levenshtein": "~2.0.4",
+ "levn": "~0.3.0",
+ "prelude-ls": "~1.1.2",
+ "type-check": "~0.3.2",
+ "wordwrap": "~1.0.0"
+ }
+ },
+ "original": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/original/-/original-1.0.2.tgz",
+ "integrity": "sha512-hyBVl6iqqUOJ8FqRe+l/gS8H+kKYjrEndd5Pm1MfBtsEKA038HkkdbAl/72EAXGyonD/PFsvmVG+EvcIpliMBg==",
+ "requires": {
+ "url-parse": "^1.4.3"
+ }
+ },
+ "os-browserify": {
+ "version": "0.3.0",
+ "resolved": "https://registry.npmjs.org/os-browserify/-/os-browserify-0.3.0.tgz",
+ "integrity": "sha1-hUNzx/XCMVkU/Jv8a9gjj92h7Cc="
+ },
+ "os-locale": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-3.1.0.tgz",
+ "integrity": "sha512-Z8l3R4wYWM40/52Z+S265okfFj8Kt2cC2MKY+xNi3kFs+XGI7WXu/I309QQQYbRW4ijiZ+yxs9pqEhJh0DqW3Q==",
+ "requires": {
+ "execa": "^1.0.0",
+ "lcid": "^2.0.0",
+ "mem": "^4.0.0"
+ }
+ },
+ "os-tmpdir": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz",
+ "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ="
+ },
+ "p-defer": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/p-defer/-/p-defer-1.0.0.tgz",
+ "integrity": "sha1-n26xgvbJqozXQwBKfU+WsZaw+ww="
+ },
+ "p-each-series": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/p-each-series/-/p-each-series-1.0.0.tgz",
+ "integrity": "sha1-kw89Et0fUOdDRFeiLNbwSsatf3E=",
+ "requires": {
+ "p-reduce": "^1.0.0"
+ }
+ },
+ "p-finally": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz",
+ "integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4="
+ },
+ "p-is-promise": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/p-is-promise/-/p-is-promise-2.0.0.tgz",
+ "integrity": "sha512-pzQPhYMCAgLAKPWD2jC3Se9fEfrD9npNos0y150EeqZll7akhEgGhTW/slB6lHku8AvYGiJ+YJ5hfHKePPgFWg=="
+ },
+ "p-limit": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.1.0.tgz",
+ "integrity": "sha512-NhURkNcrVB+8hNfLuysU8enY5xn2KXphsHBaC2YmRNTZRc7RWusw6apSpdEj3jo4CMb6W9nrF6tTnsJsJeyu6g==",
+ "requires": {
+ "p-try": "^2.0.0"
+ }
+ },
+ "p-locate": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz",
+ "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==",
+ "requires": {
+ "p-limit": "^2.0.0"
+ }
+ },
+ "p-map": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/p-map/-/p-map-2.1.0.tgz",
+ "integrity": "sha512-y3b8Kpd8OAN444hxfBbFfj1FY/RjtTd8tzYwhUqNYXx0fXx2iX4maP4Qr6qhIKbQXI02wTLAda4fYUbDagTUFw=="
+ },
+ "p-reduce": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/p-reduce/-/p-reduce-1.0.0.tgz",
+ "integrity": "sha1-GMKw3ZNqRpClKfgjH1ig/bakffo="
+ },
+ "p-try": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.0.0.tgz",
+ "integrity": "sha512-hMp0onDKIajHfIkdRk3P4CdCmErkYAxxDtP3Wx/4nZ3aGlau2VKh3mZpcuFkH27WQkL/3WBCPOktzA9ZOAnMQQ=="
+ },
+ "pako": {
+ "version": "1.0.10",
+ "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.10.tgz",
+ "integrity": "sha512-0DTvPVU3ed8+HNXOu5Bs+o//Mbdj9VNQMUOe9oKCwh8l0GNwpTDMKCWbRjgtD291AWnkAgkqA/LOnQS8AmS1tw=="
+ },
+ "parallel-transform": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/parallel-transform/-/parallel-transform-1.1.0.tgz",
+ "integrity": "sha1-1BDwZbBdojCB/NEPKIVMKb2jOwY=",
+ "requires": {
+ "cyclist": "~0.2.2",
+ "inherits": "^2.0.3",
+ "readable-stream": "^2.1.5"
+ }
+ },
+ "parent-module": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz",
+ "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==",
+ "requires": {
+ "callsites": "^3.0.0"
+ }
+ },
+ "parse-asn1": {
+ "version": "5.1.4",
+ "resolved": "https://registry.npmjs.org/parse-asn1/-/parse-asn1-5.1.4.tgz",
+ "integrity": "sha512-Qs5duJcuvNExRfFZ99HDD3z4mAi3r9Wl/FOjEOijlxwCZs7E7mW2vjTpgQ4J8LpTF8x5v+1Vn5UQFejmWT11aw==",
+ "requires": {
+ "asn1.js": "^4.0.0",
+ "browserify-aes": "^1.0.0",
+ "create-hash": "^1.1.0",
+ "evp_bytestokey": "^1.0.0",
+ "pbkdf2": "^3.0.3",
+ "safe-buffer": "^5.1.1"
+ }
+ },
+ "parse-json": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz",
+ "integrity": "sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA=",
+ "requires": {
+ "error-ex": "^1.3.1",
+ "json-parse-better-errors": "^1.0.1"
+ }
+ },
+ "parse-passwd": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/parse-passwd/-/parse-passwd-1.0.0.tgz",
+ "integrity": "sha1-bVuTSkVpk7I9N/QKOC1vFmao5cY="
+ },
+ "parse5": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/parse5/-/parse5-4.0.0.tgz",
+ "integrity": "sha512-VrZ7eOd3T1Fk4XWNXMgiGBK/z0MG48BWG2uQNU4I72fkQuKUTZpl+u9k+CxEG0twMVzSmXEEz12z5Fnw1jIQFA=="
+ },
+ "parseurl": {
+ "version": "1.3.2",
+ "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.2.tgz",
+ "integrity": "sha1-/CidTtiZMRlGDBViUyYs3I3mW/M="
+ },
+ "pascalcase": {
+ "version": "0.1.1",
+ "resolved": "https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz",
+ "integrity": "sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ="
+ },
+ "path-browserify": {
+ "version": "0.0.0",
+ "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-0.0.0.tgz",
+ "integrity": "sha1-oLhwcpquIUAFt9UDLsLLuw+0RRo="
+ },
+ "path-dirname": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/path-dirname/-/path-dirname-1.0.2.tgz",
+ "integrity": "sha1-zDPSTVJeCZpTiMAzbG4yuRYGCeA="
+ },
+ "path-exists": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz",
+ "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU="
+ },
+ "path-is-absolute": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
+ "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18="
+ },
+ "path-is-inside": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz",
+ "integrity": "sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM="
+ },
+ "path-key": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz",
+ "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A="
+ },
+ "path-parse": {
+ "version": "1.0.6",
+ "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz",
+ "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw=="
+ },
+ "path-to-regexp": {
+ "version": "0.1.7",
+ "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz",
+ "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w="
+ },
+ "path-type": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz",
+ "integrity": "sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==",
+ "requires": {
+ "pify": "^3.0.0"
+ }
+ },
+ "pbkdf2": {
+ "version": "3.0.17",
+ "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.0.17.tgz",
+ "integrity": "sha512-U/il5MsrZp7mGg3mSQfn742na2T+1/vHDCG5/iTI3X9MKUuYUZVLQhyRsg06mCgDBTd57TxzgZt7P+fYfjRLtA==",
+ "requires": {
+ "create-hash": "^1.1.2",
+ "create-hmac": "^1.1.4",
+ "ripemd160": "^2.0.1",
+ "safe-buffer": "^5.0.1",
+ "sha.js": "^2.4.8"
+ }
+ },
+ "performance-now": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz",
+ "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns="
+ },
+ "pify": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz",
+ "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY="
+ },
+ "pinkie": {
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz",
+ "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA="
+ },
+ "pinkie-promise": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz",
+ "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=",
+ "requires": {
+ "pinkie": "^2.0.0"
+ }
+ },
+ "pirates": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.1.tgz",
+ "integrity": "sha512-WuNqLTbMI3tmfef2TKxlQmAiLHKtFhlsCZnPIpuv2Ow0RDVO8lfy1Opf4NUzlMXLjPl+Men7AuVdX6TA+s+uGA==",
+ "requires": {
+ "node-modules-regexp": "^1.0.0"
+ }
+ },
+ "pkg-dir": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-3.0.0.tgz",
+ "integrity": "sha512-/E57AYkoeQ25qkxMj5PBOVgF8Kiu/h7cYS30Z5+R7WaiCCBfLq58ZI/dSeaEKb9WVJV5n/03QwrN3IeWIFllvw==",
+ "requires": {
+ "find-up": "^3.0.0"
+ }
+ },
+ "pn": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/pn/-/pn-1.1.0.tgz",
+ "integrity": "sha512-2qHaIQr2VLRFoxe2nASzsV6ef4yOOH+Fi9FBOVH6cqeSgUnoyySPZkxzLuzd+RYOQTRpROA0ztTMqxROKSb/nA=="
+ },
+ "portfinder": {
+ "version": "1.0.20",
+ "resolved": "https://registry.npmjs.org/portfinder/-/portfinder-1.0.20.tgz",
+ "integrity": "sha512-Yxe4mTyDzTd59PZJY4ojZR8F+E5e97iq2ZOHPz3HDgSvYC5siNad2tLooQ5y5QHyQhc3xVqvyk/eNA3wuoa7Sw==",
+ "requires": {
+ "async": "^1.5.2",
+ "debug": "^2.2.0",
+ "mkdirp": "0.5.x"
+ },
+ "dependencies": {
+ "async": {
+ "version": "1.5.2",
+ "resolved": "https://registry.npmjs.org/async/-/async-1.5.2.tgz",
+ "integrity": "sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo="
+ }
+ }
+ },
+ "posix-character-classes": {
+ "version": "0.1.1",
+ "resolved": "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz",
+ "integrity": "sha1-AerA/jta9xoqbAL+q7jB/vfgDqs="
+ },
+ "postcss": {
+ "version": "7.0.14",
+ "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.14.tgz",
+ "integrity": "sha512-NsbD6XUUMZvBxtQAJuWDJeeC4QFsmWsfozWxCJPWf3M55K9iu2iMDaKqyoOdTJ1R4usBXuxlVFAIo8rZPQD4Bg==",
+ "requires": {
+ "chalk": "^2.4.2",
+ "source-map": "^0.6.1",
+ "supports-color": "^6.1.0"
+ },
+ "dependencies": {
+ "source-map": {
+ "version": "0.6.1",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
+ "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="
+ },
+ "supports-color": {
+ "version": "6.1.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz",
+ "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==",
+ "requires": {
+ "has-flag": "^3.0.0"
+ }
+ }
+ }
+ },
+ "postcss-load-config": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-2.0.0.tgz",
+ "integrity": "sha512-V5JBLzw406BB8UIfsAWSK2KSwIJ5yoEIVFb4gVkXci0QdKgA24jLmHZ/ghe/GgX0lJ0/D1uUK1ejhzEY94MChQ==",
+ "requires": {
+ "cosmiconfig": "^4.0.0",
+ "import-cwd": "^2.0.0"
+ }
+ },
+ "postcss-loader": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/postcss-loader/-/postcss-loader-3.0.0.tgz",
+ "integrity": "sha512-cLWoDEY5OwHcAjDnkyRQzAXfs2jrKjXpO/HQFcc5b5u/r7aa471wdmChmwfnv7x2u840iat/wi0lQ5nbRgSkUA==",
+ "requires": {
+ "loader-utils": "^1.1.0",
+ "postcss": "^7.0.0",
+ "postcss-load-config": "^2.0.0",
+ "schema-utils": "^1.0.0"
+ }
+ },
+ "postcss-modules-extract-imports": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/postcss-modules-extract-imports/-/postcss-modules-extract-imports-2.0.0.tgz",
+ "integrity": "sha512-LaYLDNS4SG8Q5WAWqIJgdHPJrDDr/Lv775rMBFUbgjTz6j34lUznACHcdRWroPvXANP2Vj7yNK57vp9eFqzLWQ==",
+ "requires": {
+ "postcss": "^7.0.5"
+ }
+ },
+ "postcss-modules-local-by-default": {
+ "version": "2.0.6",
+ "resolved": "https://registry.npmjs.org/postcss-modules-local-by-default/-/postcss-modules-local-by-default-2.0.6.tgz",
+ "integrity": "sha512-oLUV5YNkeIBa0yQl7EYnxMgy4N6noxmiwZStaEJUSe2xPMcdNc8WmBQuQCx18H5psYbVxz8zoHk0RAAYZXP9gA==",
+ "requires": {
+ "postcss": "^7.0.6",
+ "postcss-selector-parser": "^6.0.0",
+ "postcss-value-parser": "^3.3.1"
+ }
+ },
+ "postcss-modules-scope": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/postcss-modules-scope/-/postcss-modules-scope-2.1.0.tgz",
+ "integrity": "sha512-91Rjps0JnmtUB0cujlc8KIKCsJXWjzuxGeT/+Q2i2HXKZ7nBUeF9YQTZZTNvHVoNYj1AthsjnGLtqDUE0Op79A==",
+ "requires": {
+ "postcss": "^7.0.6",
+ "postcss-selector-parser": "^6.0.0"
+ }
+ },
+ "postcss-modules-values": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/postcss-modules-values/-/postcss-modules-values-2.0.0.tgz",
+ "integrity": "sha512-Ki7JZa7ff1N3EIMlPnGTZfUMe69FFwiQPnVSXC9mnn3jozCRBYIxiZd44yJOV2AmabOo4qFf8s0dC/+lweG7+w==",
+ "requires": {
+ "icss-replace-symbols": "^1.1.0",
+ "postcss": "^7.0.6"
+ }
+ },
+ "postcss-selector-parser": {
+ "version": "6.0.2",
+ "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.2.tgz",
+ "integrity": "sha512-36P2QR59jDTOAiIkqEprfJDsoNrvwFei3eCqKd1Y0tUsBimsq39BLp7RD+JWny3WgB1zGhJX8XVePwm9k4wdBg==",
+ "requires": {
+ "cssesc": "^3.0.0",
+ "indexes-of": "^1.0.1",
+ "uniq": "^1.0.1"
+ }
+ },
+ "postcss-value-parser": {
+ "version": "3.3.1",
+ "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz",
+ "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ=="
+ },
+ "prelude-ls": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz",
+ "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ="
+ },
+ "prettier": {
+ "version": "1.16.4",
+ "resolved": "https://registry.npmjs.org/prettier/-/prettier-1.16.4.tgz",
+ "integrity": "sha512-ZzWuos7TI5CKUeQAtFd6Zhm2s6EpAD/ZLApIhsF9pRvRtM1RFo61dM/4MSRUA0SuLugA/zgrZD8m0BaY46Og7g=="
+ },
+ "prettier-linter-helpers": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz",
+ "integrity": "sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==",
+ "requires": {
+ "fast-diff": "^1.1.2"
+ }
+ },
+ "pretty-format": {
+ "version": "24.7.0",
+ "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-24.7.0.tgz",
+ "integrity": "sha512-apen5cjf/U4dj7tHetpC7UEFCvtAgnNZnBDkfPv3fokzIqyOJckAG9OlAPC1BlFALnqT/lGB2tl9EJjlK6eCsA==",
+ "requires": {
+ "@jest/types": "^24.7.0",
+ "ansi-regex": "^4.0.0",
+ "ansi-styles": "^3.2.0",
+ "react-is": "^16.8.4"
+ },
+ "dependencies": {
+ "ansi-regex": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz",
+ "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg=="
+ }
+ }
+ },
+ "process": {
+ "version": "0.11.10",
+ "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz",
+ "integrity": "sha1-czIwDoQBYb2j5podHZGn1LwW8YI="
+ },
+ "process-nextick-args": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz",
+ "integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw=="
+ },
+ "progress": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz",
+ "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA=="
+ },
+ "promise-inflight": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/promise-inflight/-/promise-inflight-1.0.1.tgz",
+ "integrity": "sha1-mEcocL8igTL8vdhoEputEsPAKeM="
+ },
+ "prompts": {
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.0.4.tgz",
+ "integrity": "sha512-HTzM3UWp/99A0gk51gAegwo1QRYA7xjcZufMNe33rCclFszUYAuHe1fIN/3ZmiHeGPkUsNaRyQm1hHOfM0PKxA==",
+ "requires": {
+ "kleur": "^3.0.2",
+ "sisteransi": "^1.0.0"
+ }
+ },
+ "proxy-addr": {
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.4.tgz",
+ "integrity": "sha512-5erio2h9jp5CHGwcybmxmVqHmnCBZeewlfJ0pex+UW7Qny7OOZXTtH56TGNyBizkgiOwhJtMKrVzDTeKcySZwA==",
+ "requires": {
+ "forwarded": "~0.1.2",
+ "ipaddr.js": "1.8.0"
+ }
+ },
+ "prr": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/prr/-/prr-1.0.1.tgz",
+ "integrity": "sha1-0/wRS6BplaRexok/SEzrHXj19HY="
+ },
+ "psl": {
+ "version": "1.1.31",
+ "resolved": "https://registry.npmjs.org/psl/-/psl-1.1.31.tgz",
+ "integrity": "sha512-/6pt4+C+T+wZUieKR620OpzN/LlnNKuWjy1iFLQ/UG35JqHlR/89MP1d96dUfkf6Dne3TuLQzOYEYshJ+Hx8mw=="
+ },
+ "public-encrypt": {
+ "version": "4.0.3",
+ "resolved": "https://registry.npmjs.org/public-encrypt/-/public-encrypt-4.0.3.tgz",
+ "integrity": "sha512-zVpa8oKZSz5bTMTFClc1fQOnyyEzpl5ozpi1B5YcvBrdohMjH2rfsBtyXcuNuwjsDIXmBYlF2N5FlJYhR29t8Q==",
+ "requires": {
+ "bn.js": "^4.1.0",
+ "browserify-rsa": "^4.0.0",
+ "create-hash": "^1.1.0",
+ "parse-asn1": "^5.0.0",
+ "randombytes": "^2.0.1",
+ "safe-buffer": "^5.1.2"
+ }
+ },
+ "pump": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz",
+ "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==",
+ "requires": {
+ "end-of-stream": "^1.1.0",
+ "once": "^1.3.1"
+ }
+ },
+ "pumpify": {
+ "version": "1.5.1",
+ "resolved": "https://registry.npmjs.org/pumpify/-/pumpify-1.5.1.tgz",
+ "integrity": "sha512-oClZI37HvuUJJxSKKrC17bZ9Cu0ZYhEAGPsPUy9KlMUmv9dKX2o77RUmq7f3XjIxbwyGwYzbzQ1L2Ks8sIradQ==",
+ "requires": {
+ "duplexify": "^3.6.0",
+ "inherits": "^2.0.3",
+ "pump": "^2.0.0"
+ },
+ "dependencies": {
+ "pump": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/pump/-/pump-2.0.1.tgz",
+ "integrity": "sha512-ruPMNRkN3MHP1cWJc9OWr+T/xDP0jhXYCLfJcBuX54hhfIBnaQmAUMfDcG4DM5UMWByBbJY69QSphm3jtDKIkA==",
+ "requires": {
+ "end-of-stream": "^1.1.0",
+ "once": "^1.3.1"
+ }
+ }
+ }
+ },
+ "punycode": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz",
+ "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A=="
+ },
+ "qs": {
+ "version": "6.5.2",
+ "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz",
+ "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA=="
+ },
+ "querystring": {
+ "version": "0.2.0",
+ "resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz",
+ "integrity": "sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA="
+ },
+ "querystring-es3": {
+ "version": "0.2.1",
+ "resolved": "https://registry.npmjs.org/querystring-es3/-/querystring-es3-0.2.1.tgz",
+ "integrity": "sha1-nsYfeQSYdXB9aUFFlv2Qek1xHnM="
+ },
+ "querystringify": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.1.1.tgz",
+ "integrity": "sha512-w7fLxIRCRT7U8Qu53jQnJyPkYZIaR4n5151KMfcJlO/A9397Wxb1amJvROTK6TOnp7PfoAmg/qXiNHI+08jRfA=="
+ },
+ "randombytes": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz",
+ "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==",
+ "requires": {
+ "safe-buffer": "^5.1.0"
+ }
+ },
+ "randomfill": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/randomfill/-/randomfill-1.0.4.tgz",
+ "integrity": "sha512-87lcbR8+MhcWcUiQ+9e+Rwx8MyR2P7qnt15ynUlbm3TU/fjbgz4GsvfSUDTemtCCtVCqb4ZcEFlyPNTh9bBTLw==",
+ "requires": {
+ "randombytes": "^2.0.5",
+ "safe-buffer": "^5.1.0"
+ }
+ },
+ "range-parser": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.0.tgz",
+ "integrity": "sha1-9JvmtIeJTdxA3MlKMi9hEJLgDV4="
+ },
+ "raw-body": {
+ "version": "2.3.3",
+ "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.3.3.tgz",
+ "integrity": "sha512-9esiElv1BrZoI3rCDuOuKCBRbuApGGaDPQfjSflGxdy4oyzqghxu6klEkkVIvBje+FF0BX9coEv8KqW6X/7njw==",
+ "requires": {
+ "bytes": "3.0.0",
+ "http-errors": "1.6.3",
+ "iconv-lite": "0.4.23",
+ "unpipe": "1.0.0"
+ },
+ "dependencies": {
+ "iconv-lite": {
+ "version": "0.4.23",
+ "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.23.tgz",
+ "integrity": "sha512-neyTUVFtahjf0mB3dZT77u+8O0QB89jFdnBkd5P1JgYPbPaia3gXXOVL2fq8VyU2gMMD7SaN7QukTB/pmXYvDA==",
+ "requires": {
+ "safer-buffer": ">= 2.1.2 < 3"
+ }
+ }
+ }
+ },
+ "react-is": {
+ "version": "16.8.6",
+ "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.8.6.tgz",
+ "integrity": "sha512-aUk3bHfZ2bRSVFFbbeVS4i+lNPZr3/WM5jT2J5omUVV1zzcs1nAaf3l51ctA5FFvCRbhrH0bdAsRRQddFJZPtA=="
+ },
+ "read-pkg": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-3.0.0.tgz",
+ "integrity": "sha1-nLxoaXj+5l0WwA4rGcI3/Pbjg4k=",
+ "requires": {
+ "load-json-file": "^4.0.0",
+ "normalize-package-data": "^2.3.2",
+ "path-type": "^3.0.0"
+ }
+ },
+ "read-pkg-up": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-4.0.0.tgz",
+ "integrity": "sha512-6etQSH7nJGsK0RbG/2TeDzZFa8shjQ1um+SwQQ5cwKy0dhSXdOncEhb1CPpvQG4h7FyOV6EB6YlV0yJvZQNAkA==",
+ "requires": {
+ "find-up": "^3.0.0",
+ "read-pkg": "^3.0.0"
+ }
+ },
+ "readable-stream": {
+ "version": "2.3.6",
+ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
+ "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==",
+ "requires": {
+ "core-util-is": "~1.0.0",
+ "inherits": "~2.0.3",
+ "isarray": "~1.0.0",
+ "process-nextick-args": "~2.0.0",
+ "safe-buffer": "~5.1.1",
+ "string_decoder": "~1.1.1",
+ "util-deprecate": "~1.0.1"
+ }
+ },
+ "readdirp": {
+ "version": "2.2.1",
+ "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-2.2.1.tgz",
+ "integrity": "sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ==",
+ "requires": {
+ "graceful-fs": "^4.1.11",
+ "micromatch": "^3.1.10",
+ "readable-stream": "^2.0.2"
+ }
+ },
+ "realpath-native": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/realpath-native/-/realpath-native-1.1.0.tgz",
+ "integrity": "sha512-wlgPA6cCIIg9gKz0fgAPjnzh4yR/LnXovwuo9hvyGvx3h8nX4+/iLZplfUWasXpqD8BdnGnP5njOFjkUwPzvjA==",
+ "requires": {
+ "util.promisify": "^1.0.0"
+ }
+ },
+ "regex-not": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz",
+ "integrity": "sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A==",
+ "requires": {
+ "extend-shallow": "^3.0.2",
+ "safe-regex": "^1.1.0"
+ }
+ },
+ "regexpp": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-2.0.1.tgz",
+ "integrity": "sha512-lv0M6+TkDVniA3aD1Eg0DVpfU/booSu7Eev3TDO/mZKHBfVjgCGTV4t4buppESEYDtkArYFOxTJWv6S5C+iaNw=="
+ },
+ "remove-trailing-separator": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz",
+ "integrity": "sha1-wkvOKig62tW8P1jg1IJJuSN52O8="
+ },
+ "repeat-element": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.3.tgz",
+ "integrity": "sha512-ahGq0ZnV5m5XtZLMb+vP76kcAM5nkLqk0lpqAuojSKGgQtn4eRi4ZZGm2olo2zKFH+sMsWaqOCW1dqAnOru72g=="
+ },
+ "repeat-string": {
+ "version": "1.6.1",
+ "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz",
+ "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc="
+ },
+ "request": {
+ "version": "2.88.0",
+ "resolved": "https://registry.npmjs.org/request/-/request-2.88.0.tgz",
+ "integrity": "sha512-NAqBSrijGLZdM0WZNsInLJpkJokL72XYjUpnB0iwsRgxh7dB6COrHnTBNwN0E+lHDAJzu7kLAkDeY08z2/A0hg==",
+ "requires": {
+ "aws-sign2": "~0.7.0",
+ "aws4": "^1.8.0",
+ "caseless": "~0.12.0",
+ "combined-stream": "~1.0.6",
+ "extend": "~3.0.2",
+ "forever-agent": "~0.6.1",
+ "form-data": "~2.3.2",
+ "har-validator": "~5.1.0",
+ "http-signature": "~1.2.0",
+ "is-typedarray": "~1.0.0",
+ "isstream": "~0.1.2",
+ "json-stringify-safe": "~5.0.1",
+ "mime-types": "~2.1.19",
+ "oauth-sign": "~0.9.0",
+ "performance-now": "^2.1.0",
+ "qs": "~6.5.2",
+ "safe-buffer": "^5.1.2",
+ "tough-cookie": "~2.4.3",
+ "tunnel-agent": "^0.6.0",
+ "uuid": "^3.3.2"
+ },
+ "dependencies": {
+ "punycode": {
+ "version": "1.4.1",
+ "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz",
+ "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4="
+ },
+ "tough-cookie": {
+ "version": "2.4.3",
+ "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.4.3.tgz",
+ "integrity": "sha512-Q5srk/4vDM54WJsJio3XNn6K2sCG+CQ8G5Wz6bZhRZoAe/+TxjWB/GlFAnYEbkYVlON9FMk/fE3h2RLpPXo4lQ==",
+ "requires": {
+ "psl": "^1.1.24",
+ "punycode": "^1.4.1"
+ }
+ }
+ }
+ },
+ "request-promise-core": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/request-promise-core/-/request-promise-core-1.1.2.tgz",
+ "integrity": "sha512-UHYyq1MO8GsefGEt7EprS8UrXsm1TxEvFUX1IMTuSLU2Rh7fTIdFtl8xD7JiEYiWU2dl+NYAjCTksTehQUxPag==",
+ "requires": {
+ "lodash": "^4.17.11"
+ }
+ },
+ "request-promise-native": {
+ "version": "1.0.7",
+ "resolved": "https://registry.npmjs.org/request-promise-native/-/request-promise-native-1.0.7.tgz",
+ "integrity": "sha512-rIMnbBdgNViL37nZ1b3L/VfPOpSi0TqVDQPAvO6U14lMzOLrt5nilxCQqtDKhZeDiW0/hkCXGoQjhgJd/tCh6w==",
+ "requires": {
+ "request-promise-core": "1.1.2",
+ "stealthy-require": "^1.1.1",
+ "tough-cookie": "^2.3.3"
+ }
+ },
+ "require-directory": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz",
+ "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I="
+ },
+ "require-from-string": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz",
+ "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw=="
+ },
+ "require-main-filename": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-1.0.1.tgz",
+ "integrity": "sha1-l/cXtp1IeE9fUmpsWqj/3aBVpNE="
+ },
+ "requireindex": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/requireindex/-/requireindex-1.2.0.tgz",
+ "integrity": "sha512-L9jEkOi3ASd9PYit2cwRfyppc9NoABujTP8/5gFcbERmo5jUoAKovIC3fsF17pkTnGsrByysqX+Kxd2OTNI1ww=="
+ },
+ "requires-port": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz",
+ "integrity": "sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8="
+ },
+ "resolve": {
+ "version": "1.10.0",
+ "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.10.0.tgz",
+ "integrity": "sha512-3sUr9aq5OfSg2S9pNtPA9hL1FVEAjvfOC4leW0SNf/mpnaakz2a9femSd6LqAww2RaFctwyf1lCqnTHuF1rxDg==",
+ "requires": {
+ "path-parse": "^1.0.6"
+ }
+ },
+ "resolve-cwd": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-2.0.0.tgz",
+ "integrity": "sha1-AKn3OHVW4nA46uIyyqNypqWbZlo=",
+ "requires": {
+ "resolve-from": "^3.0.0"
+ },
+ "dependencies": {
+ "resolve-from": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-3.0.0.tgz",
+ "integrity": "sha1-six699nWiBvItuZTM17rywoYh0g="
+ }
+ }
+ },
+ "resolve-dir": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/resolve-dir/-/resolve-dir-1.0.1.tgz",
+ "integrity": "sha1-eaQGRMNivoLybv/nOcm7U4IEb0M=",
+ "requires": {
+ "expand-tilde": "^2.0.0",
+ "global-modules": "^1.0.0"
+ }
+ },
+ "resolve-from": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz",
+ "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g=="
+ },
+ "resolve-url": {
+ "version": "0.2.1",
+ "resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz",
+ "integrity": "sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo="
+ },
+ "restore-cursor": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-2.0.0.tgz",
+ "integrity": "sha1-n37ih/gv0ybU/RYpI9YhKe7g368=",
+ "requires": {
+ "onetime": "^2.0.0",
+ "signal-exit": "^3.0.2"
+ }
+ },
+ "ret": {
+ "version": "0.1.15",
+ "resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz",
+ "integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg=="
+ },
+ "rimraf": {
+ "version": "2.6.3",
+ "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz",
+ "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==",
+ "requires": {
+ "glob": "^7.1.3"
+ }
+ },
+ "ripemd160": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.2.tgz",
+ "integrity": "sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA==",
+ "requires": {
+ "hash-base": "^3.0.0",
+ "inherits": "^2.0.1"
+ }
+ },
+ "rsvp": {
+ "version": "4.8.4",
+ "resolved": "https://registry.npmjs.org/rsvp/-/rsvp-4.8.4.tgz",
+ "integrity": "sha512-6FomvYPfs+Jy9TfXmBpBuMWNH94SgCsZmJKcanySzgNNP6LjWxBvyLTa9KaMfDDM5oxRfrKDB0r/qeRsLwnBfA=="
+ },
+ "run-async": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.3.0.tgz",
+ "integrity": "sha1-A3GrSuC91yDUFm19/aZP96RFpsA=",
+ "requires": {
+ "is-promise": "^2.1.0"
+ }
+ },
+ "run-queue": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/run-queue/-/run-queue-1.0.3.tgz",
+ "integrity": "sha1-6Eg5bwV9Ij8kOGkkYY4laUFh7Ec=",
+ "requires": {
+ "aproba": "^1.1.1"
+ }
+ },
+ "rxjs": {
+ "version": "6.4.0",
+ "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.4.0.tgz",
+ "integrity": "sha512-Z9Yfa11F6B9Sg/BK9MnqnQ+aQYicPLtilXBp2yUtDt2JRCE0h26d33EnfO3ZxoNxG0T92OUucP3Ct7cpfkdFfw==",
+ "requires": {
+ "tslib": "^1.9.0"
+ }
+ },
+ "safe-buffer": {
+ "version": "5.1.2",
+ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
+ "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="
+ },
+ "safe-regex": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz",
+ "integrity": "sha1-QKNmnzsHfR6UPURinhV91IAjvy4=",
+ "requires": {
+ "ret": "~0.1.10"
+ }
+ },
+ "safer-buffer": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
+ "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
+ },
+ "sane": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/sane/-/sane-4.1.0.tgz",
+ "integrity": "sha512-hhbzAgTIX8O7SHfp2c8/kREfEn4qO/9q8C9beyY6+tvZ87EpoZ3i1RIEvp27YBswnNbY9mWd6paKVmKbAgLfZA==",
+ "requires": {
+ "@cnakazawa/watch": "^1.0.3",
+ "anymatch": "^2.0.0",
+ "capture-exit": "^2.0.0",
+ "exec-sh": "^0.3.2",
+ "execa": "^1.0.0",
+ "fb-watchman": "^2.0.0",
+ "micromatch": "^3.1.4",
+ "minimist": "^1.1.1",
+ "walker": "~1.0.5"
+ }
+ },
+ "sax": {
+ "version": "1.2.4",
+ "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz",
+ "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw=="
+ },
+ "schema-utils": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-1.0.0.tgz",
+ "integrity": "sha512-i27Mic4KovM/lnGsy8whRCHhc7VicJajAjTrYg11K9zfZXnYIt4k5F+kZkwjnrhKzLic/HLU4j11mjsz2G/75g==",
+ "requires": {
+ "ajv": "^6.1.0",
+ "ajv-errors": "^1.0.0",
+ "ajv-keywords": "^3.1.0"
+ }
+ },
+ "select-hose": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/select-hose/-/select-hose-2.0.0.tgz",
+ "integrity": "sha1-Yl2GWPhlr0Psliv8N2o3NZpJlMo="
+ },
+ "selfsigned": {
+ "version": "1.10.4",
+ "resolved": "https://registry.npmjs.org/selfsigned/-/selfsigned-1.10.4.tgz",
+ "integrity": "sha512-9AukTiDmHXGXWtWjembZ5NDmVvP2695EtpgbCsxCa68w3c88B+alqbmZ4O3hZ4VWGXeGWzEVdvqgAJD8DQPCDw==",
+ "requires": {
+ "node-forge": "0.7.5"
+ }
+ },
+ "semver": {
+ "version": "5.5.0",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-5.5.0.tgz",
+ "integrity": "sha512-4SJ3dm0WAwWy/NVeioZh5AntkdJoWKxHxcmyP622fOkgHa4z3R0TdBJICINyaSDE6uNwVc8gZr+ZinwZAH4xIA=="
+ },
+ "send": {
+ "version": "0.16.2",
+ "resolved": "https://registry.npmjs.org/send/-/send-0.16.2.tgz",
+ "integrity": "sha512-E64YFPUssFHEFBvpbbjr44NCLtI1AohxQ8ZSiJjQLskAdKuriYEP6VyGEsRDH8ScozGpkaX1BGvhanqCwkcEZw==",
+ "requires": {
+ "debug": "2.6.9",
+ "depd": "~1.1.2",
+ "destroy": "~1.0.4",
+ "encodeurl": "~1.0.2",
+ "escape-html": "~1.0.3",
+ "etag": "~1.8.1",
+ "fresh": "0.5.2",
+ "http-errors": "~1.6.2",
+ "mime": "1.4.1",
+ "ms": "2.0.0",
+ "on-finished": "~2.3.0",
+ "range-parser": "~1.2.0",
+ "statuses": "~1.4.0"
+ }
+ },
+ "serialize-javascript": {
+ "version": "1.6.1",
+ "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-1.6.1.tgz",
+ "integrity": "sha512-A5MOagrPFga4YaKQSWHryl7AXvbQkEqpw4NNYMTNYUNV51bA8ABHgYFpqKx+YFFrw59xMV1qGH1R4AgoNIVgCw=="
+ },
+ "serve-index": {
+ "version": "1.9.1",
+ "resolved": "https://registry.npmjs.org/serve-index/-/serve-index-1.9.1.tgz",
+ "integrity": "sha1-03aNabHn2C5c4FD/9bRTvqEqkjk=",
+ "requires": {
+ "accepts": "~1.3.4",
+ "batch": "0.6.1",
+ "debug": "2.6.9",
+ "escape-html": "~1.0.3",
+ "http-errors": "~1.6.2",
+ "mime-types": "~2.1.17",
+ "parseurl": "~1.3.2"
+ }
+ },
+ "serve-static": {
+ "version": "1.13.2",
+ "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.13.2.tgz",
+ "integrity": "sha512-p/tdJrO4U387R9oMjb1oj7qSMaMfmOyd4j9hOFoxZe2baQszgHcSWjuya/CiT5kgZZKRudHNOA0pYXOl8rQ5nw==",
+ "requires": {
+ "encodeurl": "~1.0.2",
+ "escape-html": "~1.0.3",
+ "parseurl": "~1.3.2",
+ "send": "0.16.2"
+ }
+ },
+ "set-blocking": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz",
+ "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc="
+ },
+ "set-value": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.0.tgz",
+ "integrity": "sha512-hw0yxk9GT/Hr5yJEYnHNKYXkIA8mVJgd9ditYZCe16ZczcaELYYcfvaXesNACk2O8O0nTiPQcQhGUQj8JLzeeg==",
+ "requires": {
+ "extend-shallow": "^2.0.1",
+ "is-extendable": "^0.1.1",
+ "is-plain-object": "^2.0.3",
+ "split-string": "^3.0.1"
+ },
+ "dependencies": {
+ "extend-shallow": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
+ "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
+ "requires": {
+ "is-extendable": "^0.1.0"
+ }
+ }
+ }
+ },
+ "setimmediate": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz",
+ "integrity": "sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU="
+ },
+ "setprototypeof": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz",
+ "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ=="
+ },
+ "sha.js": {
+ "version": "2.4.11",
+ "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz",
+ "integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==",
+ "requires": {
+ "inherits": "^2.0.1",
+ "safe-buffer": "^5.0.1"
+ }
+ },
+ "shebang-command": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz",
+ "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=",
+ "requires": {
+ "shebang-regex": "^1.0.0"
+ }
+ },
+ "shebang-regex": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz",
+ "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM="
+ },
+ "shellwords": {
+ "version": "0.1.1",
+ "resolved": "https://registry.npmjs.org/shellwords/-/shellwords-0.1.1.tgz",
+ "integrity": "sha512-vFwSUfQvqybiICwZY5+DAWIPLKsWO31Q91JSKl3UYv+K5c2QRPzn0qzec6QPu1Qc9eHYItiP3NdJqNVqetYAww=="
+ },
+ "signal-exit": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz",
+ "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0="
+ },
+ "sisteransi": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.0.tgz",
+ "integrity": "sha512-N+z4pHB4AmUv0SjveWRd6q1Nj5w62m5jodv+GD8lvmbY/83T/rpbJGZOnK5T149OldDj4Db07BSv9xY4K6NTPQ=="
+ },
+ "slash": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/slash/-/slash-2.0.0.tgz",
+ "integrity": "sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A=="
+ },
+ "slice-ansi": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-2.1.0.tgz",
+ "integrity": "sha512-Qu+VC3EwYLldKa1fCxuuvULvSJOKEgk9pi8dZeCVK7TqBfUNTH4sFkk4joj8afVSfAYgJoSOetjx9QWOJ5mYoQ==",
+ "requires": {
+ "ansi-styles": "^3.2.0",
+ "astral-regex": "^1.0.0",
+ "is-fullwidth-code-point": "^2.0.0"
+ }
+ },
+ "snapdragon": {
+ "version": "0.8.2",
+ "resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz",
+ "integrity": "sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg==",
+ "requires": {
+ "base": "^0.11.1",
+ "debug": "^2.2.0",
+ "define-property": "^0.2.5",
+ "extend-shallow": "^2.0.1",
+ "map-cache": "^0.2.2",
+ "source-map": "^0.5.6",
+ "source-map-resolve": "^0.5.0",
+ "use": "^3.1.0"
+ },
+ "dependencies": {
+ "define-property": {
+ "version": "0.2.5",
+ "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz",
+ "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=",
+ "requires": {
+ "is-descriptor": "^0.1.0"
+ }
+ },
+ "extend-shallow": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
+ "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
+ "requires": {
+ "is-extendable": "^0.1.0"
+ }
+ }
+ }
+ },
+ "snapdragon-node": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/snapdragon-node/-/snapdragon-node-2.1.1.tgz",
+ "integrity": "sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw==",
+ "requires": {
+ "define-property": "^1.0.0",
+ "isobject": "^3.0.0",
+ "snapdragon-util": "^3.0.1"
+ },
+ "dependencies": {
+ "define-property": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz",
+ "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=",
+ "requires": {
+ "is-descriptor": "^1.0.0"
+ }
+ },
+ "is-accessor-descriptor": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz",
+ "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==",
+ "requires": {
+ "kind-of": "^6.0.0"
+ }
+ },
+ "is-data-descriptor": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz",
+ "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==",
+ "requires": {
+ "kind-of": "^6.0.0"
+ }
+ },
+ "is-descriptor": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz",
+ "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==",
+ "requires": {
+ "is-accessor-descriptor": "^1.0.0",
+ "is-data-descriptor": "^1.0.0",
+ "kind-of": "^6.0.2"
+ }
+ }
+ }
+ },
+ "snapdragon-util": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/snapdragon-util/-/snapdragon-util-3.0.1.tgz",
+ "integrity": "sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ==",
+ "requires": {
+ "kind-of": "^3.2.0"
+ },
+ "dependencies": {
+ "kind-of": {
+ "version": "3.2.2",
+ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
+ "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
+ "requires": {
+ "is-buffer": "^1.1.5"
+ }
+ }
+ }
+ },
+ "sockjs": {
+ "version": "0.3.19",
+ "resolved": "https://registry.npmjs.org/sockjs/-/sockjs-0.3.19.tgz",
+ "integrity": "sha512-V48klKZl8T6MzatbLlzzRNhMepEys9Y4oGFpypBFFn1gLI/QQ9HtLLyWJNbPlwGLelOVOEijUbTTJeLLI59jLw==",
+ "requires": {
+ "faye-websocket": "^0.10.0",
+ "uuid": "^3.0.1"
+ }
+ },
+ "sockjs-client": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/sockjs-client/-/sockjs-client-1.3.0.tgz",
+ "integrity": "sha512-R9jxEzhnnrdxLCNln0xg5uGHqMnkhPSTzUZH2eXcR03S/On9Yvoq2wyUZILRUhZCNVu2PmwWVoyuiPz8th8zbg==",
+ "requires": {
+ "debug": "^3.2.5",
+ "eventsource": "^1.0.7",
+ "faye-websocket": "~0.11.1",
+ "inherits": "^2.0.3",
+ "json3": "^3.3.2",
+ "url-parse": "^1.4.3"
+ },
+ "dependencies": {
+ "debug": {
+ "version": "3.2.6",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz",
+ "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==",
+ "requires": {
+ "ms": "^2.1.1"
+ }
+ },
+ "faye-websocket": {
+ "version": "0.11.1",
+ "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.11.1.tgz",
+ "integrity": "sha1-8O/hjE9W5PQK/H4Gxxn9XuYYjzg=",
+ "requires": {
+ "websocket-driver": ">=0.5.1"
+ }
+ },
+ "ms": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz",
+ "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg=="
+ }
+ }
+ },
+ "source-list-map": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/source-list-map/-/source-list-map-2.0.1.tgz",
+ "integrity": "sha512-qnQ7gVMxGNxsiL4lEuJwe/To8UnK7fAnmbGEEH8RpLouuKbeEm0lhbQVFIrNSuB+G7tVrAlVsZgETT5nljf+Iw=="
+ },
+ "source-map": {
+ "version": "0.5.7",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
+ "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w="
+ },
+ "source-map-resolve": {
+ "version": "0.5.2",
+ "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.2.tgz",
+ "integrity": "sha512-MjqsvNwyz1s0k81Goz/9vRBe9SZdB09Bdw+/zYyO+3CuPk6fouTaxscHkgtE8jKvf01kVfl8riHzERQ/kefaSA==",
+ "requires": {
+ "atob": "^2.1.1",
+ "decode-uri-component": "^0.2.0",
+ "resolve-url": "^0.2.1",
+ "source-map-url": "^0.4.0",
+ "urix": "^0.1.0"
+ }
+ },
+ "source-map-support": {
+ "version": "0.5.10",
+ "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.10.tgz",
+ "integrity": "sha512-YfQ3tQFTK/yzlGJuX8pTwa4tifQj4QS2Mj7UegOu8jAz59MqIiMGPXxQhVQiIMNzayuUSF/jEuVnfFF5JqybmQ==",
+ "requires": {
+ "buffer-from": "^1.0.0",
+ "source-map": "^0.6.0"
+ },
+ "dependencies": {
+ "source-map": {
+ "version": "0.6.1",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
+ "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="
+ }
+ }
+ },
+ "source-map-url": {
+ "version": "0.4.0",
+ "resolved": "https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.0.tgz",
+ "integrity": "sha1-PpNdfd1zYxuXZZlW1VEo6HtQhKM="
+ },
+ "spdx-correct": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.0.tgz",
+ "integrity": "sha512-lr2EZCctC2BNR7j7WzJ2FpDznxky1sjfxvvYEyzxNyb6lZXHODmEoJeFu4JupYlkfha1KZpJyoqiJ7pgA1qq8Q==",
+ "requires": {
+ "spdx-expression-parse": "^3.0.0",
+ "spdx-license-ids": "^3.0.0"
+ }
+ },
+ "spdx-exceptions": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.2.0.tgz",
+ "integrity": "sha512-2XQACfElKi9SlVb1CYadKDXvoajPgBVPn/gOQLrTvHdElaVhr7ZEbqJaRnJLVNeaI4cMEAgVCeBMKF6MWRDCRA=="
+ },
+ "spdx-expression-parse": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.0.tgz",
+ "integrity": "sha512-Yg6D3XpRD4kkOmTpdgbUiEJFKghJH03fiC1OPll5h/0sO6neh2jqRDVHOQ4o/LMea0tgCkbMgea5ip/e+MkWyg==",
+ "requires": {
+ "spdx-exceptions": "^2.1.0",
+ "spdx-license-ids": "^3.0.0"
+ }
+ },
+ "spdx-license-ids": {
+ "version": "3.0.4",
+ "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.4.tgz",
+ "integrity": "sha512-7j8LYJLeY/Yb6ACbQ7F76qy5jHkp0U6jgBfJsk97bwWlVUnUWsAgpyaCvo17h0/RQGnQ036tVDomiwoI4pDkQA=="
+ },
+ "spdy": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/spdy/-/spdy-4.0.0.tgz",
+ "integrity": "sha512-ot0oEGT/PGUpzf/6uk4AWLqkq+irlqHXkrdbk51oWONh3bxQmBuljxPNl66zlRRcIJStWq0QkLUCPOPjgjvU0Q==",
+ "requires": {
+ "debug": "^4.1.0",
+ "handle-thing": "^2.0.0",
+ "http-deceiver": "^1.2.7",
+ "select-hose": "^2.0.0",
+ "spdy-transport": "^3.0.0"
+ },
+ "dependencies": {
+ "debug": {
+ "version": "4.1.1",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz",
+ "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==",
+ "requires": {
+ "ms": "^2.1.1"
+ }
+ },
+ "ms": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz",
+ "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg=="
+ }
+ }
+ },
+ "spdy-transport": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/spdy-transport/-/spdy-transport-3.0.0.tgz",
+ "integrity": "sha512-hsLVFE5SjA6TCisWeJXFKniGGOpBgMLmerfO2aCyCU5s7nJ/rpAepqmFifv/GCbSbueEeAJJnmSQ2rKC/g8Fcw==",
+ "requires": {
+ "debug": "^4.1.0",
+ "detect-node": "^2.0.4",
+ "hpack.js": "^2.1.6",
+ "obuf": "^1.1.2",
+ "readable-stream": "^3.0.6",
+ "wbuf": "^1.7.3"
+ },
+ "dependencies": {
+ "debug": {
+ "version": "4.1.1",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz",
+ "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==",
+ "requires": {
+ "ms": "^2.1.1"
+ }
+ },
+ "ms": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz",
+ "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg=="
+ },
+ "readable-stream": {
+ "version": "3.3.0",
+ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.3.0.tgz",
+ "integrity": "sha512-EsI+s3k3XsW+fU8fQACLN59ky34AZ14LoeVZpYwmZvldCFo0r0gnelwF2TcMjLor/BTL5aDJVBMkss0dthToPw==",
+ "requires": {
+ "inherits": "^2.0.3",
+ "string_decoder": "^1.1.1",
+ "util-deprecate": "^1.0.1"
+ }
+ }
+ }
+ },
+ "split-string": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz",
+ "integrity": "sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==",
+ "requires": {
+ "extend-shallow": "^3.0.0"
+ }
+ },
+ "sprintf-js": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz",
+ "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw="
+ },
+ "sshpk": {
+ "version": "1.16.1",
+ "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.16.1.tgz",
+ "integrity": "sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg==",
+ "requires": {
+ "asn1": "~0.2.3",
+ "assert-plus": "^1.0.0",
+ "bcrypt-pbkdf": "^1.0.0",
+ "dashdash": "^1.12.0",
+ "ecc-jsbn": "~0.1.1",
+ "getpass": "^0.1.1",
+ "jsbn": "~0.1.0",
+ "safer-buffer": "^2.0.2",
+ "tweetnacl": "~0.14.0"
+ }
+ },
+ "ssri": {
+ "version": "6.0.1",
+ "resolved": "https://registry.npmjs.org/ssri/-/ssri-6.0.1.tgz",
+ "integrity": "sha512-3Wge10hNcT1Kur4PDFwEieXSCMCJs/7WvSACcrMYrNp+b8kDL1/0wJch5Ni2WrtwEa2IO8OsVfeKIciKCDx/QA==",
+ "requires": {
+ "figgy-pudding": "^3.5.1"
+ }
+ },
+ "stack-utils": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-1.0.2.tgz",
+ "integrity": "sha512-MTX+MeG5U994cazkjd/9KNAapsHnibjMLnfXodlkXw76JEea0UiNzrqidzo1emMwk7w5Qhc9jd4Bn9TBb1MFwA=="
+ },
+ "static-extend": {
+ "version": "0.1.2",
+ "resolved": "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz",
+ "integrity": "sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY=",
+ "requires": {
+ "define-property": "^0.2.5",
+ "object-copy": "^0.1.0"
+ },
+ "dependencies": {
+ "define-property": {
+ "version": "0.2.5",
+ "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz",
+ "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=",
+ "requires": {
+ "is-descriptor": "^0.1.0"
+ }
+ }
+ }
+ },
+ "statuses": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.4.0.tgz",
+ "integrity": "sha512-zhSCtt8v2NDrRlPQpCNtw/heZLtfUDqxBM1udqikb/Hbk52LK4nQSwr10u77iopCW5LsyHpuXS0GnEc48mLeew=="
+ },
+ "stealthy-require": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/stealthy-require/-/stealthy-require-1.1.1.tgz",
+ "integrity": "sha1-NbCYdbT/SfJqd35QmzCQoyJr8ks="
+ },
+ "stream-browserify": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/stream-browserify/-/stream-browserify-2.0.2.tgz",
+ "integrity": "sha512-nX6hmklHs/gr2FuxYDltq8fJA1GDlxKQCz8O/IM4atRqBH8OORmBNgfvW5gG10GT/qQ9u0CzIvr2X5Pkt6ntqg==",
+ "requires": {
+ "inherits": "~2.0.1",
+ "readable-stream": "^2.0.2"
+ }
+ },
+ "stream-each": {
+ "version": "1.2.3",
+ "resolved": "https://registry.npmjs.org/stream-each/-/stream-each-1.2.3.tgz",
+ "integrity": "sha512-vlMC2f8I2u/bZGqkdfLQW/13Zihpej/7PmSiMQsbYddxuTsJp8vRe2x2FvVExZg7FaOds43ROAuFJwPR4MTZLw==",
+ "requires": {
+ "end-of-stream": "^1.1.0",
+ "stream-shift": "^1.0.0"
+ }
+ },
+ "stream-http": {
+ "version": "2.8.3",
+ "resolved": "https://registry.npmjs.org/stream-http/-/stream-http-2.8.3.tgz",
+ "integrity": "sha512-+TSkfINHDo4J+ZobQLWiMouQYB+UVYFttRA94FpEzzJ7ZdqcL4uUUQ7WkdkI4DSozGmgBUE/a47L+38PenXhUw==",
+ "requires": {
+ "builtin-status-codes": "^3.0.0",
+ "inherits": "^2.0.1",
+ "readable-stream": "^2.3.6",
+ "to-arraybuffer": "^1.0.0",
+ "xtend": "^4.0.0"
+ }
+ },
+ "stream-shift": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/stream-shift/-/stream-shift-1.0.0.tgz",
+ "integrity": "sha1-1cdSgl5TZ+eG944Y5EXqIjoVWVI="
+ },
+ "string-length": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/string-length/-/string-length-2.0.0.tgz",
+ "integrity": "sha1-1A27aGo6zpYMHP/KVivyxF+DY+0=",
+ "requires": {
+ "astral-regex": "^1.0.0",
+ "strip-ansi": "^4.0.0"
+ }
+ },
+ "string-width": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz",
+ "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==",
+ "requires": {
+ "is-fullwidth-code-point": "^2.0.0",
+ "strip-ansi": "^4.0.0"
+ }
+ },
+ "string_decoder": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
+ "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
+ "requires": {
+ "safe-buffer": "~5.1.0"
+ }
+ },
+ "strip-ansi": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz",
+ "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=",
+ "requires": {
+ "ansi-regex": "^3.0.0"
+ }
+ },
+ "strip-bom": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz",
+ "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM="
+ },
+ "strip-eof": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz",
+ "integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8="
+ },
+ "strip-json-comments": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz",
+ "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo="
+ },
+ "supports-color": {
+ "version": "5.5.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
+ "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
+ "requires": {
+ "has-flag": "^3.0.0"
+ }
+ },
+ "symbol-tree": {
+ "version": "3.2.2",
+ "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.2.tgz",
+ "integrity": "sha1-rifbOPZgp64uHDt9G8KQgZuFGeY="
+ },
+ "table": {
+ "version": "5.2.3",
+ "resolved": "https://registry.npmjs.org/table/-/table-5.2.3.tgz",
+ "integrity": "sha512-N2RsDAMvDLvYwFcwbPyF3VmVSSkuF+G1e+8inhBLtHpvwXGw4QRPEZhihQNeEN0i1up6/f6ObCJXNdlRG3YVyQ==",
+ "requires": {
+ "ajv": "^6.9.1",
+ "lodash": "^4.17.11",
+ "slice-ansi": "^2.1.0",
+ "string-width": "^3.0.0"
+ },
+ "dependencies": {
+ "ansi-regex": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz",
+ "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg=="
+ },
+ "string-width": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz",
+ "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==",
+ "requires": {
+ "emoji-regex": "^7.0.1",
+ "is-fullwidth-code-point": "^2.0.0",
+ "strip-ansi": "^5.1.0"
+ }
+ },
+ "strip-ansi": {
+ "version": "5.2.0",
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz",
+ "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==",
+ "requires": {
+ "ansi-regex": "^4.1.0"
+ }
+ }
+ }
+ },
+ "tapable": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/tapable/-/tapable-1.1.1.tgz",
+ "integrity": "sha512-9I2ydhj8Z9veORCw5PRm4u9uebCn0mcCa6scWoNcbZ6dAtoo2618u9UUzxgmsCOreJpqDDuv61LvwofW7hLcBA=="
+ },
+ "terser": {
+ "version": "3.17.0",
+ "resolved": "https://registry.npmjs.org/terser/-/terser-3.17.0.tgz",
+ "integrity": "sha512-/FQzzPJmCpjAH9Xvk2paiWrFq+5M6aVOf+2KRbwhByISDX/EujxsK+BAvrhb6H+2rtrLCHK9N01wO014vrIwVQ==",
+ "requires": {
+ "commander": "^2.19.0",
+ "source-map": "~0.6.1",
+ "source-map-support": "~0.5.10"
+ },
+ "dependencies": {
+ "source-map": {
+ "version": "0.6.1",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
+ "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="
+ }
+ }
+ },
+ "terser-webpack-plugin": {
+ "version": "1.2.3",
+ "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-1.2.3.tgz",
+ "integrity": "sha512-GOK7q85oAb/5kE12fMuLdn2btOS9OBZn4VsecpHDywoUC/jLhSAKOiYo0ezx7ss2EXPMzyEWFoE0s1WLE+4+oA==",
+ "requires": {
+ "cacache": "^11.0.2",
+ "find-cache-dir": "^2.0.0",
+ "schema-utils": "^1.0.0",
+ "serialize-javascript": "^1.4.0",
+ "source-map": "^0.6.1",
+ "terser": "^3.16.1",
+ "webpack-sources": "^1.1.0",
+ "worker-farm": "^1.5.2"
+ },
+ "dependencies": {
+ "source-map": {
+ "version": "0.6.1",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
+ "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="
+ }
+ }
+ },
+ "test-exclude": {
+ "version": "5.1.0",
+ "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-5.1.0.tgz",
+ "integrity": "sha512-gwf0S2fFsANC55fSeSqpb8BYk6w3FDvwZxfNjeF6FRgvFa43r+7wRiA/Q0IxoRU37wB/LE8IQ4221BsNucTaCA==",
+ "requires": {
+ "arrify": "^1.0.1",
+ "minimatch": "^3.0.4",
+ "read-pkg-up": "^4.0.0",
+ "require-main-filename": "^1.0.1"
+ }
+ },
+ "text-table": {
+ "version": "0.2.0",
+ "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz",
+ "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ="
+ },
+ "throat": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/throat/-/throat-4.1.0.tgz",
+ "integrity": "sha1-iQN8vJLFarGJJua6TLsgDhVnKmo="
+ },
+ "through": {
+ "version": "2.3.8",
+ "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz",
+ "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU="
+ },
+ "through2": {
+ "version": "2.0.5",
+ "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz",
+ "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==",
+ "requires": {
+ "readable-stream": "~2.3.6",
+ "xtend": "~4.0.1"
+ }
+ },
+ "thunky": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/thunky/-/thunky-1.0.3.tgz",
+ "integrity": "sha512-YwT8pjmNcAXBZqrubu22P4FYsh2D4dxRmnWBOL8Jk8bUcRUtc5326kx32tuTmFDAZtLOGEVNl8POAR8j896Iow=="
+ },
+ "timers-browserify": {
+ "version": "2.0.10",
+ "resolved": "https://registry.npmjs.org/timers-browserify/-/timers-browserify-2.0.10.tgz",
+ "integrity": "sha512-YvC1SV1XdOUaL6gx5CoGroT3Gu49pK9+TZ38ErPldOWW4j49GI1HKs9DV+KGq/w6y+LZ72W1c8cKz2vzY+qpzg==",
+ "requires": {
+ "setimmediate": "^1.0.4"
+ }
+ },
+ "tmp": {
+ "version": "0.0.33",
+ "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz",
+ "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==",
+ "requires": {
+ "os-tmpdir": "~1.0.2"
+ }
+ },
+ "tmpl": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.4.tgz",
+ "integrity": "sha1-I2QN17QtAEM5ERQIIOXPRA5SHdE="
+ },
+ "to-arraybuffer": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/to-arraybuffer/-/to-arraybuffer-1.0.1.tgz",
+ "integrity": "sha1-fSKbH8xjfkZsoIEYCDanqr/4P0M="
+ },
+ "to-fast-properties": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz",
+ "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4="
+ },
+ "to-object-path": {
+ "version": "0.3.0",
+ "resolved": "https://registry.npmjs.org/to-object-path/-/to-object-path-0.3.0.tgz",
+ "integrity": "sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68=",
+ "requires": {
+ "kind-of": "^3.0.2"
+ },
+ "dependencies": {
+ "kind-of": {
+ "version": "3.2.2",
+ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
+ "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
+ "requires": {
+ "is-buffer": "^1.1.5"
+ }
+ }
+ }
+ },
+ "to-regex": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/to-regex/-/to-regex-3.0.2.tgz",
+ "integrity": "sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw==",
+ "requires": {
+ "define-property": "^2.0.2",
+ "extend-shallow": "^3.0.2",
+ "regex-not": "^1.0.2",
+ "safe-regex": "^1.1.0"
+ }
+ },
+ "to-regex-range": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz",
+ "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=",
+ "requires": {
+ "is-number": "^3.0.0",
+ "repeat-string": "^1.6.1"
+ }
+ },
+ "tough-cookie": {
+ "version": "2.5.0",
+ "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz",
+ "integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==",
+ "requires": {
+ "psl": "^1.1.28",
+ "punycode": "^2.1.1"
+ }
+ },
+ "tr46": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/tr46/-/tr46-1.0.1.tgz",
+ "integrity": "sha1-qLE/1r/SSJUZZ0zN5VujaTtwbQk=",
+ "requires": {
+ "punycode": "^2.1.0"
+ }
+ },
+ "trim-right": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/trim-right/-/trim-right-1.0.1.tgz",
+ "integrity": "sha1-yy4SAwZ+DI3h9hQJS5/kVwTqYAM="
+ },
+ "ts-jest": {
+ "version": "24.0.2",
+ "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-24.0.2.tgz",
+ "integrity": "sha512-h6ZCZiA1EQgjczxq+uGLXQlNgeg02WWJBbeT8j6nyIBRQdglqbvzDoHahTEIiS6Eor6x8mK6PfZ7brQ9Q6tzHw==",
+ "requires": {
+ "bs-logger": "0.x",
+ "buffer-from": "1.x",
+ "fast-json-stable-stringify": "2.x",
+ "json5": "2.x",
+ "make-error": "1.x",
+ "mkdirp": "0.x",
+ "resolve": "1.x",
+ "semver": "^5.5",
+ "yargs-parser": "10.x"
+ },
+ "dependencies": {
+ "camelcase": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-4.1.0.tgz",
+ "integrity": "sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0="
+ },
+ "json5": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/json5/-/json5-2.1.0.tgz",
+ "integrity": "sha512-8Mh9h6xViijj36g7Dxi+Y4S6hNGV96vcJZr/SrlHh1LR/pEn/8j/+qIBbs44YKl69Lrfctp4QD+AdWLTMqEZAQ==",
+ "requires": {
+ "minimist": "^1.2.0"
+ }
+ },
+ "yargs-parser": {
+ "version": "10.1.0",
+ "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-10.1.0.tgz",
+ "integrity": "sha512-VCIyR1wJoEBZUqk5PA+oOBF6ypbwh5aNB3I50guxAL/quggdfs4TtNHQrSazFA3fYZ+tEqfs0zIGlv0c/rgjbQ==",
+ "requires": {
+ "camelcase": "^4.1.0"
+ }
+ }
+ }
+ },
+ "tslib": {
+ "version": "1.9.3",
+ "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.9.3.tgz",
+ "integrity": "sha512-4krF8scpejhaOgqzBEcGM7yDIEfi0/8+8zDRZhNZZ2kjmHJ4hv3zCbQWxoJGz1iw5U0Jl0nma13xzHXcncMavQ=="
+ },
+ "tsutils": {
+ "version": "3.10.0",
+ "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.10.0.tgz",
+ "integrity": "sha512-q20XSMq7jutbGB8luhKKsQldRKWvyBO2BGqni3p4yq8Ys9bEP/xQw3KepKmMRt9gJ4lvQSScrihJrcKdKoSU7Q==",
+ "requires": {
+ "tslib": "^1.8.1"
+ }
+ },
+ "tty-browserify": {
+ "version": "0.0.0",
+ "resolved": "https://registry.npmjs.org/tty-browserify/-/tty-browserify-0.0.0.tgz",
+ "integrity": "sha1-oVe6QC2iTpv5V/mqadUk7tQpAaY="
+ },
+ "tunnel-agent": {
+ "version": "0.6.0",
+ "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz",
+ "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=",
+ "requires": {
+ "safe-buffer": "^5.0.1"
+ }
+ },
+ "tweetnacl": {
+ "version": "0.14.5",
+ "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz",
+ "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q="
+ },
+ "type-check": {
+ "version": "0.3.2",
+ "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz",
+ "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=",
+ "requires": {
+ "prelude-ls": "~1.1.2"
+ }
+ },
+ "type-is": {
+ "version": "1.6.16",
+ "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.16.tgz",
+ "integrity": "sha512-HRkVv/5qY2G6I8iab9cI7v1bOIdhm94dVjQCPFElW9W+3GeDOSHmy2EBYe4VTApuzolPcmgFTN3ftVJRKR2J9Q==",
+ "requires": {
+ "media-typer": "0.3.0",
+ "mime-types": "~2.1.18"
+ }
+ },
+ "typedarray": {
+ "version": "0.0.6",
+ "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz",
+ "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c="
+ },
+ "typescript": {
+ "version": "3.4.3",
+ "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.4.3.tgz",
+ "integrity": "sha512-FFgHdPt4T/duxx6Ndf7hwgMZZjZpB+U0nMNGVCYPq0rEzWKjEDobm4J6yb3CS7naZ0yURFqdw9Gwc7UOh/P9oQ=="
+ },
+ "uglify-js": {
+ "version": "3.5.4",
+ "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.5.4.tgz",
+ "integrity": "sha512-GpKo28q/7Bm5BcX9vOu4S46FwisbPbAmkkqPnGIpKvKTM96I85N6XHQV+k4I6FA2wxgLhcsSyHoNhzucwCflvA==",
+ "optional": true,
+ "requires": {
+ "commander": "~2.20.0",
+ "source-map": "~0.6.1"
+ },
+ "dependencies": {
+ "commander": {
+ "version": "2.20.0",
+ "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.0.tgz",
+ "integrity": "sha512-7j2y+40w61zy6YC2iRNpUe/NwhNyoXrYpHMrSunaMG64nRnaf96zO/KMQR4OyN/UnE5KLyEBnKHd4aG3rskjpQ==",
+ "optional": true
+ },
+ "source-map": {
+ "version": "0.6.1",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
+ "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
+ "optional": true
+ }
+ }
+ },
+ "union-value": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.0.tgz",
+ "integrity": "sha1-XHHDTLW61dzr4+oM0IIHulqhrqQ=",
+ "requires": {
+ "arr-union": "^3.1.0",
+ "get-value": "^2.0.6",
+ "is-extendable": "^0.1.1",
+ "set-value": "^0.4.3"
+ },
+ "dependencies": {
+ "extend-shallow": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
+ "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
+ "requires": {
+ "is-extendable": "^0.1.0"
+ }
+ },
+ "set-value": {
+ "version": "0.4.3",
+ "resolved": "https://registry.npmjs.org/set-value/-/set-value-0.4.3.tgz",
+ "integrity": "sha1-fbCPnT0i3H945Trzw79GZuzfzPE=",
+ "requires": {
+ "extend-shallow": "^2.0.1",
+ "is-extendable": "^0.1.1",
+ "is-plain-object": "^2.0.1",
+ "to-object-path": "^0.3.0"
+ }
+ }
+ }
+ },
+ "uniq": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/uniq/-/uniq-1.0.1.tgz",
+ "integrity": "sha1-sxxa6CVIRKOoKBVBzisEuGWnNP8="
+ },
+ "unique-filename": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-1.1.1.tgz",
+ "integrity": "sha512-Vmp0jIp2ln35UTXuryvjzkjGdRyf9b2lTXuSYUiPmzRcl3FDtYqAwOnTJkAngD9SWhnoJzDbTKwaOrZ+STtxNQ==",
+ "requires": {
+ "unique-slug": "^2.0.0"
+ }
+ },
+ "unique-slug": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/unique-slug/-/unique-slug-2.0.1.tgz",
+ "integrity": "sha512-n9cU6+gITaVu7VGj1Z8feKMmfAjEAQGhwD9fE3zvpRRa0wEIx8ODYkVGfSc94M2OX00tUFV8wH3zYbm1I8mxFg==",
+ "requires": {
+ "imurmurhash": "^0.1.4"
+ }
+ },
+ "unpipe": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz",
+ "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw="
+ },
+ "unset-value": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/unset-value/-/unset-value-1.0.0.tgz",
+ "integrity": "sha1-g3aHP30jNRef+x5vw6jtDfyKtVk=",
+ "requires": {
+ "has-value": "^0.3.1",
+ "isobject": "^3.0.0"
+ },
+ "dependencies": {
+ "has-value": {
+ "version": "0.3.1",
+ "resolved": "https://registry.npmjs.org/has-value/-/has-value-0.3.1.tgz",
+ "integrity": "sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8=",
+ "requires": {
+ "get-value": "^2.0.3",
+ "has-values": "^0.1.4",
+ "isobject": "^2.0.0"
+ },
+ "dependencies": {
+ "isobject": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz",
+ "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=",
+ "requires": {
+ "isarray": "1.0.0"
+ }
+ }
+ }
+ },
+ "has-values": {
+ "version": "0.1.4",
+ "resolved": "https://registry.npmjs.org/has-values/-/has-values-0.1.4.tgz",
+ "integrity": "sha1-bWHeldkd/Km5oCCJrThL/49it3E="
+ }
+ }
+ },
+ "upath": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/upath/-/upath-1.1.0.tgz",
+ "integrity": "sha512-bzpH/oBhoS/QI/YtbkqCg6VEiPYjSZtrHQM6/QnJS6OL9pKUFLqb3aFh4Scvwm45+7iAgiMkLhSbaZxUqmrprw=="
+ },
+ "uri-js": {
+ "version": "4.2.2",
+ "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz",
+ "integrity": "sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ==",
+ "requires": {
+ "punycode": "^2.1.0"
+ }
+ },
+ "urix": {
+ "version": "0.1.0",
+ "resolved": "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz",
+ "integrity": "sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI="
+ },
+ "url": {
+ "version": "0.11.0",
+ "resolved": "https://registry.npmjs.org/url/-/url-0.11.0.tgz",
+ "integrity": "sha1-ODjpfPxgUh63PFJajlW/3Z4uKPE=",
+ "requires": {
+ "punycode": "1.3.2",
+ "querystring": "0.2.0"
+ },
+ "dependencies": {
+ "punycode": {
+ "version": "1.3.2",
+ "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz",
+ "integrity": "sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0="
+ }
+ }
+ },
+ "url-loader": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/url-loader/-/url-loader-1.1.2.tgz",
+ "integrity": "sha512-dXHkKmw8FhPqu8asTc1puBfe3TehOCo2+RmOOev5suNCIYBcT626kxiWg1NBVkwc4rO8BGa7gP70W7VXuqHrjg==",
+ "requires": {
+ "loader-utils": "^1.1.0",
+ "mime": "^2.0.3",
+ "schema-utils": "^1.0.0"
+ },
+ "dependencies": {
+ "mime": {
+ "version": "2.4.0",
+ "resolved": "https://registry.npmjs.org/mime/-/mime-2.4.0.tgz",
+ "integrity": "sha512-ikBcWwyqXQSHKtciCcctu9YfPbFYZ4+gbHEmE0Q8jzcTYQg5dHCr3g2wwAZjPoJfQVXZq6KXAjpXOTf5/cjT7w=="
+ }
+ }
+ },
+ "url-parse": {
+ "version": "1.4.5",
+ "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.4.5.tgz",
+ "integrity": "sha512-4XDvC5vZRjEpjP0L4znrWeoH8P8F0XGBlfLdABi/6oV4o8xUVbTpyrxWHxkK2bT0pSIpcjdIzSoWUhlUfawCAQ==",
+ "requires": {
+ "querystringify": "^2.0.0",
+ "requires-port": "^1.0.0"
+ }
+ },
+ "use": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz",
+ "integrity": "sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ=="
+ },
+ "util": {
+ "version": "0.11.1",
+ "resolved": "https://registry.npmjs.org/util/-/util-0.11.1.tgz",
+ "integrity": "sha512-HShAsny+zS2TZfaXxD9tYj4HQGlBezXZMZuM/S5PKLLoZkShZiGk9o5CzukI1LVHZvjdvZ2Sj1aW/Ndn2NB/HQ==",
+ "requires": {
+ "inherits": "2.0.3"
+ }
+ },
+ "util-deprecate": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
+ "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8="
+ },
+ "util.promisify": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/util.promisify/-/util.promisify-1.0.0.tgz",
+ "integrity": "sha512-i+6qA2MPhvoKLuxnJNpXAGhg7HphQOSUq2LKMZD0m15EiskXUkMvKdF4Uui0WYeCUGea+o2cw/ZuwehtfsrNkA==",
+ "requires": {
+ "define-properties": "^1.1.2",
+ "object.getownpropertydescriptors": "^2.0.3"
+ }
+ },
+ "utils-merge": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz",
+ "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM="
+ },
+ "uuid": {
+ "version": "3.3.2",
+ "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.2.tgz",
+ "integrity": "sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA=="
+ },
+ "v8-compile-cache": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.0.2.tgz",
+ "integrity": "sha512-1wFuMUIM16MDJRCrpbpuEPTUGmM5QMUg0cr3KFwra2XgOgFcPGDQHDh3CszSCD2Zewc/dh/pamNEW8CbfDebUw=="
+ },
+ "validate-npm-package-license": {
+ "version": "3.0.4",
+ "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz",
+ "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==",
+ "requires": {
+ "spdx-correct": "^3.0.0",
+ "spdx-expression-parse": "^3.0.0"
+ }
+ },
+ "vary": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
+ "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw="
+ },
+ "verror": {
+ "version": "1.10.0",
+ "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz",
+ "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=",
+ "requires": {
+ "assert-plus": "^1.0.0",
+ "core-util-is": "1.0.2",
+ "extsprintf": "^1.2.0"
+ }
+ },
+ "vm-browserify": {
+ "version": "0.0.4",
+ "resolved": "https://registry.npmjs.org/vm-browserify/-/vm-browserify-0.0.4.tgz",
+ "integrity": "sha1-XX6kW7755Kb/ZflUOOCofDV9WnM=",
+ "requires": {
+ "indexof": "0.0.1"
+ }
+ },
+ "w3c-hr-time": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/w3c-hr-time/-/w3c-hr-time-1.0.1.tgz",
+ "integrity": "sha1-gqwr/2PZUOqeMYmlimViX+3xkEU=",
+ "requires": {
+ "browser-process-hrtime": "^0.1.2"
+ }
+ },
+ "walker": {
+ "version": "1.0.7",
+ "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.7.tgz",
+ "integrity": "sha1-L3+bj9ENZ3JisYqITijRlhjgKPs=",
+ "requires": {
+ "makeerror": "1.0.x"
+ }
+ },
+ "watchpack": {
+ "version": "1.6.0",
+ "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-1.6.0.tgz",
+ "integrity": "sha512-i6dHe3EyLjMmDlU1/bGQpEw25XSjkJULPuAVKCbNRefQVq48yXKUpwg538F7AZTf9kyr57zj++pQFltUa5H7yA==",
+ "requires": {
+ "chokidar": "^2.0.2",
+ "graceful-fs": "^4.1.2",
+ "neo-async": "^2.5.0"
+ }
+ },
+ "wbuf": {
+ "version": "1.7.3",
+ "resolved": "https://registry.npmjs.org/wbuf/-/wbuf-1.7.3.tgz",
+ "integrity": "sha512-O84QOnr0icsbFGLS0O3bI5FswxzRr8/gHwWkDlQFskhSPryQXvrTMxjxGP4+iWYoauLoBvfDpkrOauZ+0iZpDA==",
+ "requires": {
+ "minimalistic-assert": "^1.0.0"
+ }
+ },
+ "webidl-conversions": {
+ "version": "4.0.2",
+ "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-4.0.2.tgz",
+ "integrity": "sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg=="
+ },
+ "webpack": {
+ "version": "4.29.6",
+ "resolved": "https://registry.npmjs.org/webpack/-/webpack-4.29.6.tgz",
+ "integrity": "sha512-MwBwpiE1BQpMDkbnUUaW6K8RFZjljJHArC6tWQJoFm0oQtfoSebtg4Y7/QHnJ/SddtjYLHaKGX64CFjG5rehJw==",
+ "requires": {
+ "@webassemblyjs/ast": "1.8.5",
+ "@webassemblyjs/helper-module-context": "1.8.5",
+ "@webassemblyjs/wasm-edit": "1.8.5",
+ "@webassemblyjs/wasm-parser": "1.8.5",
+ "acorn": "^6.0.5",
+ "acorn-dynamic-import": "^4.0.0",
+ "ajv": "^6.1.0",
+ "ajv-keywords": "^3.1.0",
+ "chrome-trace-event": "^1.0.0",
+ "enhanced-resolve": "^4.1.0",
+ "eslint-scope": "^4.0.0",
+ "json-parse-better-errors": "^1.0.2",
+ "loader-runner": "^2.3.0",
+ "loader-utils": "^1.1.0",
+ "memory-fs": "~0.4.1",
+ "micromatch": "^3.1.8",
+ "mkdirp": "~0.5.0",
+ "neo-async": "^2.5.0",
+ "node-libs-browser": "^2.0.0",
+ "schema-utils": "^1.0.0",
+ "tapable": "^1.1.0",
+ "terser-webpack-plugin": "^1.1.0",
+ "watchpack": "^1.5.0",
+ "webpack-sources": "^1.3.0"
+ }
+ },
+ "webpack-cli": {
+ "version": "3.3.0",
+ "resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-3.3.0.tgz",
+ "integrity": "sha512-t1M7G4z5FhHKJ92WRKwZ1rtvi7rHc0NZoZRbSkol0YKl4HvcC8+DsmGDmK7MmZxHSAetHagiOsjOB6MmzC2TUw==",
+ "requires": {
+ "chalk": "^2.4.1",
+ "cross-spawn": "^6.0.5",
+ "enhanced-resolve": "^4.1.0",
+ "findup-sync": "^2.0.0",
+ "global-modules": "^1.0.0",
+ "import-local": "^2.0.0",
+ "interpret": "^1.1.0",
+ "loader-utils": "^1.1.0",
+ "supports-color": "^5.5.0",
+ "v8-compile-cache": "^2.0.2",
+ "yargs": "^12.0.5"
+ }
+ },
+ "webpack-dev-middleware": {
+ "version": "3.6.2",
+ "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-3.6.2.tgz",
+ "integrity": "sha512-A47I5SX60IkHrMmZUlB0ZKSWi29TZTcPz7cha1Z75yYOsgWh/1AcPmQEbC8ZIbU3A1ytSv1PMU0PyPz2Lmz2jg==",
+ "requires": {
+ "memory-fs": "^0.4.1",
+ "mime": "^2.3.1",
+ "range-parser": "^1.0.3",
+ "webpack-log": "^2.0.0"
+ },
+ "dependencies": {
+ "mime": {
+ "version": "2.4.2",
+ "resolved": "https://registry.npmjs.org/mime/-/mime-2.4.2.tgz",
+ "integrity": "sha512-zJBfZDkwRu+j3Pdd2aHsR5GfH2jIWhmL1ZzBoc+X+3JEti2hbArWcyJ+1laC1D2/U/W1a/+Cegj0/OnEU2ybjg=="
+ },
+ "webpack-log": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/webpack-log/-/webpack-log-2.0.0.tgz",
+ "integrity": "sha512-cX8G2vR/85UYG59FgkoMamwHUIkSSlV3bBMRsbxVXVUk2j6NleCKjQ/WE9eYg9WY4w25O9w8wKP4rzNZFmUcUg==",
+ "requires": {
+ "ansi-colors": "^3.0.0",
+ "uuid": "^3.3.2"
+ }
+ }
+ }
+ },
+ "webpack-dev-server": {
+ "version": "3.3.1",
+ "resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-3.3.1.tgz",
+ "integrity": "sha512-jY09LikOyGZrxVTXK0mgIq9y2IhCoJ05848dKZqX1gAGLU1YDqgpOT71+W53JH/wI4v6ky4hm+KvSyW14JEs5A==",
+ "requires": {
+ "ansi-html": "0.0.7",
+ "bonjour": "^3.5.0",
+ "chokidar": "^2.1.5",
+ "compression": "^1.7.4",
+ "connect-history-api-fallback": "^1.6.0",
+ "debug": "^4.1.1",
+ "del": "^4.1.0",
+ "express": "^4.16.4",
+ "html-entities": "^1.2.1",
+ "http-proxy-middleware": "^0.19.1",
+ "import-local": "^2.0.0",
+ "internal-ip": "^4.2.0",
+ "ip": "^1.1.5",
+ "killable": "^1.0.1",
+ "loglevel": "^1.6.1",
+ "opn": "^5.5.0",
+ "portfinder": "^1.0.20",
+ "schema-utils": "^1.0.0",
+ "selfsigned": "^1.10.4",
+ "semver": "^6.0.0",
+ "serve-index": "^1.9.1",
+ "sockjs": "0.3.19",
+ "sockjs-client": "1.3.0",
+ "spdy": "^4.0.0",
+ "strip-ansi": "^3.0.1",
+ "supports-color": "^6.1.0",
+ "url": "^0.11.0",
+ "webpack-dev-middleware": "^3.6.2",
+ "webpack-log": "^2.0.0",
+ "yargs": "12.0.5"
+ },
+ "dependencies": {
+ "ansi-regex": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz",
+ "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8="
+ },
+ "chokidar": {
+ "version": "2.1.5",
+ "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.1.5.tgz",
+ "integrity": "sha512-i0TprVWp+Kj4WRPtInjexJ8Q+BqTE909VpH8xVhXrJkoc5QC8VO9TryGOqTr+2hljzc1sC62t22h5tZePodM/A==",
+ "requires": {
+ "anymatch": "^2.0.0",
+ "async-each": "^1.0.1",
+ "braces": "^2.3.2",
+ "fsevents": "^1.2.7",
+ "glob-parent": "^3.1.0",
+ "inherits": "^2.0.3",
+ "is-binary-path": "^1.0.0",
+ "is-glob": "^4.0.0",
+ "normalize-path": "^3.0.0",
+ "path-is-absolute": "^1.0.0",
+ "readdirp": "^2.2.1",
+ "upath": "^1.1.1"
+ }
+ },
+ "debug": {
+ "version": "4.1.1",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz",
+ "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==",
+ "requires": {
+ "ms": "^2.1.1"
+ }
+ },
+ "ms": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz",
+ "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg=="
+ },
+ "semver": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-6.0.0.tgz",
+ "integrity": "sha512-0UewU+9rFapKFnlbirLi3byoOuhrSsli/z/ihNnvM24vgF+8sNBiI1LZPBSH9wJKUwaUbw+s3hToDLCXkrghrQ=="
+ },
+ "strip-ansi": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz",
+ "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=",
+ "requires": {
+ "ansi-regex": "^2.0.0"
+ }
+ },
+ "supports-color": {
+ "version": "6.1.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz",
+ "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==",
+ "requires": {
+ "has-flag": "^3.0.0"
+ }
+ },
+ "upath": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/upath/-/upath-1.1.2.tgz",
+ "integrity": "sha512-kXpym8nmDmlCBr7nKdIx8P2jNBa+pBpIUFRnKJ4dr8htyYGJFokkr2ZvERRtUN+9SY+JqXouNgUPtv6JQva/2Q=="
+ },
+ "webpack-log": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/webpack-log/-/webpack-log-2.0.0.tgz",
+ "integrity": "sha512-cX8G2vR/85UYG59FgkoMamwHUIkSSlV3bBMRsbxVXVUk2j6NleCKjQ/WE9eYg9WY4w25O9w8wKP4rzNZFmUcUg==",
+ "requires": {
+ "ansi-colors": "^3.0.0",
+ "uuid": "^3.3.2"
+ }
+ }
+ }
+ },
+ "webpack-log": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/webpack-log/-/webpack-log-1.2.0.tgz",
+ "integrity": "sha512-U9AnICnu50HXtiqiDxuli5gLB5PGBo7VvcHx36jRZHwK4vzOYLbImqT4lwWwoMHdQWwEKw736fCHEekokTEKHA==",
+ "requires": {
+ "chalk": "^2.1.0",
+ "log-symbols": "^2.1.0",
+ "loglevelnext": "^1.0.1",
+ "uuid": "^3.1.0"
+ }
+ },
+ "webpack-sources": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-1.3.0.tgz",
+ "integrity": "sha512-OiVgSrbGu7NEnEvQJJgdSFPl2qWKkWq5lHMhgiToIiN9w34EBnjYzSYs+VbL5KoYiLNtFFa7BZIKxRED3I32pA==",
+ "requires": {
+ "source-list-map": "^2.0.0",
+ "source-map": "~0.6.1"
+ },
+ "dependencies": {
+ "source-map": {
+ "version": "0.6.1",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
+ "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="
+ }
+ }
+ },
+ "websocket-driver": {
+ "version": "0.7.0",
+ "resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.0.tgz",
+ "integrity": "sha1-DK+dLXVdk67gSdS90NP+LMoqJOs=",
+ "requires": {
+ "http-parser-js": ">=0.4.0",
+ "websocket-extensions": ">=0.1.1"
+ }
+ },
+ "websocket-extensions": {
+ "version": "0.1.3",
+ "resolved": "https://registry.npmjs.org/websocket-extensions/-/websocket-extensions-0.1.3.tgz",
+ "integrity": "sha512-nqHUnMXmBzT0w570r2JpJxfiSD1IzoI+HGVdd3aZ0yNi3ngvQ4jv1dtHt5VGxfI2yj5yqImPhOK4vmIh2xMbGg=="
+ },
+ "whatwg-encoding": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-1.0.5.tgz",
+ "integrity": "sha512-b5lim54JOPN9HtzvK9HFXvBma/rnfFeqsic0hSpjtDbVxR3dJKLc+KB4V6GgiGOvl7CY/KNh8rxSo9DKQrnUEw==",
+ "requires": {
+ "iconv-lite": "0.4.24"
+ }
+ },
+ "whatwg-mimetype": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-2.3.0.tgz",
+ "integrity": "sha512-M4yMwr6mAnQz76TbJm914+gPpB/nCwvZbJU28cUD6dR004SAxDLOOSUaB1JDRqLtaOV/vi0IC5lEAGFgrjGv/g=="
+ },
+ "whatwg-url": {
+ "version": "6.5.0",
+ "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-6.5.0.tgz",
+ "integrity": "sha512-rhRZRqx/TLJQWUpQ6bmrt2UV4f0HCQ463yQuONJqC6fO2VoEb1pTYddbe59SkYq87aoM5A3bdhMZiUiVws+fzQ==",
+ "requires": {
+ "lodash.sortby": "^4.7.0",
+ "tr46": "^1.0.1",
+ "webidl-conversions": "^4.0.2"
+ }
+ },
+ "which": {
+ "version": "1.3.1",
+ "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz",
+ "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==",
+ "requires": {
+ "isexe": "^2.0.0"
+ }
+ },
+ "which-module": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz",
+ "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho="
+ },
+ "wordwrap": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz",
+ "integrity": "sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus="
+ },
+ "worker-farm": {
+ "version": "1.6.0",
+ "resolved": "https://registry.npmjs.org/worker-farm/-/worker-farm-1.6.0.tgz",
+ "integrity": "sha512-6w+3tHbM87WnSWnENBUvA2pxJPLhQUg5LKwUQHq3r+XPhIM+Gh2R5ycbwPCyuGbNg+lPgdcnQUhuC02kJCvffQ==",
+ "requires": {
+ "errno": "~0.1.7"
+ }
+ },
+ "wrap-ansi": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz",
+ "integrity": "sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU=",
+ "requires": {
+ "string-width": "^1.0.1",
+ "strip-ansi": "^3.0.1"
+ },
+ "dependencies": {
+ "ansi-regex": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz",
+ "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8="
+ },
+ "is-fullwidth-code-point": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz",
+ "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=",
+ "requires": {
+ "number-is-nan": "^1.0.0"
+ }
+ },
+ "string-width": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz",
+ "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=",
+ "requires": {
+ "code-point-at": "^1.0.0",
+ "is-fullwidth-code-point": "^1.0.0",
+ "strip-ansi": "^3.0.0"
+ }
+ },
+ "strip-ansi": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz",
+ "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=",
+ "requires": {
+ "ansi-regex": "^2.0.0"
+ }
+ }
+ }
+ },
+ "wrappy": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
+ "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8="
+ },
+ "write": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/write/-/write-1.0.3.tgz",
+ "integrity": "sha512-/lg70HAjtkUgWPVZhZcm+T4hkL8Zbtp1nFNOn3lRrxnlv50SRBv7cR7RqR+GMsd3hUXy9hWBo4CHTbFTcOYwig==",
+ "requires": {
+ "mkdirp": "^0.5.1"
+ }
+ },
+ "write-file-atomic": {
+ "version": "2.4.1",
+ "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-2.4.1.tgz",
+ "integrity": "sha512-TGHFeZEZMnv+gBFRfjAcxL5bPHrsGKtnb4qsFAws7/vlh+QfwAaySIw4AXP9ZskTTh5GWu3FLuJhsWVdiJPGvg==",
+ "requires": {
+ "graceful-fs": "^4.1.11",
+ "imurmurhash": "^0.1.4",
+ "signal-exit": "^3.0.2"
+ }
+ },
+ "ws": {
+ "version": "5.2.2",
+ "resolved": "https://registry.npmjs.org/ws/-/ws-5.2.2.tgz",
+ "integrity": "sha512-jaHFD6PFv6UgoIVda6qZllptQsMlDEJkTQcybzzXDYM1XO9Y8em691FGMPmM46WGyLU4z9KMgQN+qrux/nhlHA==",
+ "requires": {
+ "async-limiter": "~1.0.0"
+ }
+ },
+ "xml-name-validator": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-3.0.0.tgz",
+ "integrity": "sha512-A5CUptxDsvxKJEU3yO6DuWBSJz/qizqzJKOMIfUJHETbBw/sFaDxgd6fxm1ewUaM0jZ444Fc5vC5ROYurg/4Pw=="
+ },
+ "xtend": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz",
+ "integrity": "sha1-pcbVMr5lbiPbgg77lDofBJmNY68="
+ },
+ "y18n": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.0.tgz",
+ "integrity": "sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w=="
+ },
+ "yallist": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.0.3.tgz",
+ "integrity": "sha512-S+Zk8DEWE6oKpV+vI3qWkaK+jSbIK86pCwe2IF/xwIpQ8jEuxpw9NyaGjmp9+BoJv5FV2piqCDcoCtStppiq2A=="
+ },
+ "yargs": {
+ "version": "12.0.5",
+ "resolved": "https://registry.npmjs.org/yargs/-/yargs-12.0.5.tgz",
+ "integrity": "sha512-Lhz8TLaYnxq/2ObqHDql8dX8CJi97oHxrjUcYtzKbbykPtVW9WB+poxI+NM2UIzsMgNCZTIf0AQwsjK5yMAqZw==",
+ "requires": {
+ "cliui": "^4.0.0",
+ "decamelize": "^1.2.0",
+ "find-up": "^3.0.0",
+ "get-caller-file": "^1.0.1",
+ "os-locale": "^3.0.0",
+ "require-directory": "^2.1.1",
+ "require-main-filename": "^1.0.1",
+ "set-blocking": "^2.0.0",
+ "string-width": "^2.0.0",
+ "which-module": "^2.0.0",
+ "y18n": "^3.2.1 || ^4.0.0",
+ "yargs-parser": "^11.1.1"
+ }
+ },
+ "yargs-parser": {
+ "version": "11.1.1",
+ "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-11.1.1.tgz",
+ "integrity": "sha512-C6kB/WJDiaxONLJQnF8ccx9SEeoTTLek8RVbaOIsrAUS8VrBEXfmeSnCZxygc+XC2sNMBIwOOnfcxiynjHsVSQ==",
+ "requires": {
+ "camelcase": "^5.0.0",
+ "decamelize": "^1.2.0"
+ }
+ }
+ }
+}
diff --git a/visual_console_client/package.json b/visual_console_client/package.json
new file mode 100644
index 0000000000..d049a39b10
--- /dev/null
+++ b/visual_console_client/package.json
@@ -0,0 +1,50 @@
+{
+ "name": "pandora-fms-visual-console",
+ "version": "1.0.0",
+ "description": "Visual Console",
+ "scripts": {
+ "build": "BUILD_PATH=\"pandora_console/include/visual-console-client\" NODE_ENV=production webpack",
+ "build:dev": "BUILD_PATH=\"pandora_console/include/visual-console-client\" NODE_ENV=development webpack",
+ "build:watch": "npm run build -- --watch",
+ "format": "prettier",
+ "lint": "eslint \"src/**/*.ts\"",
+ "start": "webpack-dev-server --color --mode=development",
+ "test": "jest",
+ "test:watch": "jest --watch"
+ },
+ "repository": {
+ "type": "git",
+ "url": "git+https://github.com/pandorafms/pandorafms.git"
+ },
+ "author": "Alejandro Gallardo Escobar ",
+ "license": "GPL2",
+ "private": true,
+ "bugs": {
+ "url": "https://github.com/pandorafms/pandorafms/issues"
+ },
+ "homepage": "https://github.com/pandorafms/pandorafms#readme",
+ "dependencies": {
+ "@types/d3-shape": "^1.3.1",
+ "@types/jest": "^24.0.11",
+ "@typescript-eslint/eslint-plugin": "^1.6.0",
+ "@typescript-eslint/parser": "^1.6.0",
+ "awesome-typescript-loader": "^5.2.1",
+ "clean-webpack-plugin": "^2.0.1",
+ "css-loader": "^2.1.1",
+ "d3-shape": "^1.3.5",
+ "eslint": "^5.16.0",
+ "eslint-config-prettier": "^4.1.0",
+ "eslint-plugin-prettier": "^3.0.1",
+ "file-loader": "^3.0.1",
+ "jest": "^24.7.1",
+ "mini-css-extract-plugin": "^0.5.0",
+ "postcss-loader": "^3.0.0",
+ "prettier": "^1.16.1",
+ "ts-jest": "^24.0.2",
+ "typescript": "^3.4.3",
+ "url-loader": "^1.1.2",
+ "webpack": "^4.29.6",
+ "webpack-cli": "^3.3.0",
+ "webpack-dev-server": "^3.3.1"
+ }
+}
diff --git a/visual_console_client/playground/index.html b/visual_console_client/playground/index.html
new file mode 100644
index 0000000000..a42ddd5907
--- /dev/null
+++ b/visual_console_client/playground/index.html
@@ -0,0 +1,365 @@
+
+
+
+
+
+ Visual Console Sandbox
+
+
+
+
+
+
+
+
+
+
diff --git a/visual_console_client/src/Item.ts b/visual_console_client/src/Item.ts
new file mode 100644
index 0000000000..2b635627c0
--- /dev/null
+++ b/visual_console_client/src/Item.ts
@@ -0,0 +1,553 @@
+import { Position, Size, UnknownObject, WithModuleProps } from "./types";
+import {
+ sizePropsDecoder,
+ positionPropsDecoder,
+ parseIntOr,
+ parseBoolean,
+ notEmptyStringOr,
+ replaceMacros,
+ humanDate,
+ humanTime
+} from "./lib";
+import TypedEvent, { Listener, Disposable } from "./TypedEvent";
+
+// Enum: https://www.typescriptlang.org/docs/handbook/enums.html.
+export const enum ItemType {
+ STATIC_GRAPH = 0,
+ MODULE_GRAPH = 1,
+ SIMPLE_VALUE = 2,
+ PERCENTILE_BAR = 3,
+ LABEL = 4,
+ ICON = 5,
+ SIMPLE_VALUE_MAX = 6,
+ SIMPLE_VALUE_MIN = 7,
+ SIMPLE_VALUE_AVG = 8,
+ PERCENTILE_BUBBLE = 9,
+ SERVICE = 10,
+ GROUP_ITEM = 11,
+ BOX_ITEM = 12,
+ LINE_ITEM = 13,
+ AUTO_SLA_GRAPH = 14,
+ CIRCULAR_PROGRESS_BAR = 15,
+ CIRCULAR_INTERIOR_PROGRESS_BAR = 16,
+ DONUT_GRAPH = 17,
+ BARS_GRAPH = 18,
+ CLOCK = 19,
+ COLOR_CLOUD = 20
+}
+
+// Base item properties. This interface should be extended by the item implementations.
+export interface ItemProps extends Position, Size {
+ readonly id: number;
+ readonly type: ItemType;
+ label: string | null;
+ labelPosition: "up" | "right" | "down" | "left";
+ isLinkEnabled: boolean;
+ link: string | null;
+ isOnTop: boolean;
+ parentId: number | null;
+ aclGroupId: number | null;
+}
+
+// FIXME: Fix type compatibility.
+export interface ItemClickEvent {
+ // data: Props;
+ data: UnknownObject;
+ nativeEvent: Event;
+}
+
+// FIXME: Fix type compatibility.
+export interface ItemRemoveEvent {
+ // data: Props;
+ data: UnknownObject;
+}
+
+/**
+ * Extract a valid enum value from a raw label positi9on value.
+ * @param labelPosition Raw value.
+ */
+const parseLabelPosition = (
+ labelPosition: any // eslint-disable-line @typescript-eslint/no-explicit-any
+): ItemProps["labelPosition"] => {
+ switch (labelPosition) {
+ case "up":
+ case "right":
+ case "down":
+ case "left":
+ return labelPosition;
+ default:
+ return "down";
+ }
+};
+
+/**
+ * Build a valid typed object from a raw object.
+ * This will allow us to ensure the type safety.
+ *
+ * @param data Raw object.
+ * @return An object representing the item props.
+ * @throws Will throw a TypeError if some property
+ * is missing from the raw object or have an invalid type.
+ */
+export function itemBasePropsDecoder(data: UnknownObject): ItemProps | never {
+ if (data.id == null || isNaN(parseInt(data.id))) {
+ throw new TypeError("invalid id.");
+ }
+ if (data.type == null || isNaN(parseInt(data.type))) {
+ throw new TypeError("invalid type.");
+ }
+
+ return {
+ id: parseInt(data.id),
+ type: parseInt(data.type),
+ label: notEmptyStringOr(data.label, null),
+ labelPosition: parseLabelPosition(data.labelPosition),
+ isLinkEnabled: parseBoolean(data.isLinkEnabled),
+ link: notEmptyStringOr(data.link, null),
+ isOnTop: parseBoolean(data.isOnTop),
+ parentId: parseIntOr(data.parentId, null),
+ aclGroupId: parseIntOr(data.aclGroupId, null),
+ ...sizePropsDecoder(data), // Object spread. It will merge the properties of the two objects.
+ ...positionPropsDecoder(data) // Object spread. It will merge the properties of the two objects.
+ };
+}
+
+/**
+ * Base class of the visual console items. Should be extended to use its capabilities.
+ */
+abstract class VisualConsoleItem {
+ // Properties of the item.
+ private itemProps: Props;
+ // Reference to the DOM element which will contain the item.
+ public elementRef: HTMLElement;
+ public readonly labelElementRef: HTMLElement;
+ // Reference to the DOM element which will contain the view of the item which extends this class.
+ protected readonly childElementRef: HTMLElement;
+ // Event manager for click events.
+ private readonly clickEventManager = new TypedEvent>();
+ // Event manager for remove events.
+ private readonly removeEventManager = new TypedEvent<
+ ItemRemoveEvent
+ >();
+ // List of references to clean the event listeners.
+ private readonly disposables: Disposable[] = [];
+
+ /**
+ * To create a new element which will be inside the item box.
+ * @return Item.
+ */
+ protected abstract createDomElement(): HTMLElement;
+
+ public constructor(props: Props) {
+ this.itemProps = props;
+
+ /*
+ * Get a HTMLElement which represents the container box
+ * of the Visual Console item. This element will manage
+ * all the common things like click events, show a border
+ * when hovered, etc.
+ */
+ this.elementRef = this.createContainerDomElement();
+ this.labelElementRef = this.createLabelDomElement();
+
+ /*
+ * Get a HTMLElement which represents the custom view
+ * of the Visual Console item. This element will be
+ * different depending on the item implementation.
+ */
+ this.childElementRef = this.createDomElement();
+
+ // Insert the elements into the container.
+ this.elementRef.append(this.childElementRef, this.labelElementRef);
+
+ // Resize element.
+ this.resizeElement(props.width, props.height);
+ // Set label position.
+ this.changeLabelPosition(props.labelPosition);
+ }
+
+ /**
+ * To create a new box for the visual console item.
+ * @return Item box.
+ */
+ private createContainerDomElement(): HTMLElement {
+ let box;
+ if (this.props.isLinkEnabled) {
+ box = document.createElement("a");
+ box as HTMLAnchorElement;
+ if (this.props.link) box.href = this.props.link;
+ } else {
+ box = document.createElement("div");
+ box as HTMLDivElement;
+ }
+
+ box.className = "visual-console-item";
+ box.style.zIndex = this.props.isOnTop ? "2" : "1";
+ box.style.left = `${this.props.x}px`;
+ box.style.top = `${this.props.y}px`;
+ box.onclick = e =>
+ this.clickEventManager.emit({ data: this.props, nativeEvent: e });
+
+ return box;
+ }
+
+ /**
+ * To create a new label for the visual console item.
+ * @return Item label.
+ */
+ protected createLabelDomElement(): HTMLElement {
+ const element = document.createElement("div");
+ element.className = "visual-console-item-label";
+ // Add the label if it exists.
+ const label = this.getLabelWithMacrosReplaced();
+ if (label.length > 0) {
+ // Ugly table we need to use to replicate the legacy style.
+ const table = document.createElement("table");
+ const row = document.createElement("tr");
+ const emptyRow1 = document.createElement("tr");
+ const emptyRow2 = document.createElement("tr");
+ const cell = document.createElement("td");
+
+ cell.innerHTML = label;
+ row.append(cell);
+ table.append(emptyRow1, row, emptyRow2);
+ table.style.textAlign = "center";
+
+ // Change the table size depending on its position.
+ switch (this.props.labelPosition) {
+ case "up":
+ case "down":
+ if (this.props.width > 0) {
+ table.style.width = `${this.props.width}px`;
+ table.style.height = null;
+ }
+ break;
+ case "left":
+ case "right":
+ if (this.props.height > 0) {
+ table.style.width = null;
+ table.style.height = `${this.props.height}px`;
+ }
+ break;
+ }
+
+ // element.innerHTML = this.props.label;
+ element.append(table);
+ }
+
+ return element;
+ }
+
+ /**
+ * Return the label stored into the props with some macros replaced.
+ */
+ protected getLabelWithMacrosReplaced(): string {
+ // We assert that the props may have some needed properties.
+ const props = this.props as Partial;
+
+ return replaceMacros(
+ [
+ {
+ macro: "_date_",
+ value: humanDate(new Date())
+ },
+ {
+ macro: "_time_",
+ value: humanTime(new Date())
+ },
+ {
+ macro: "_agent_",
+ value: props.agentAlias != null ? props.agentAlias : ""
+ },
+ {
+ macro: "_agentdescription_",
+ value: props.agentDescription != null ? props.agentDescription : ""
+ },
+ {
+ macro: "_address_",
+ value: props.agentAddress != null ? props.agentAddress : ""
+ },
+ {
+ macro: "_module_",
+ value: props.moduleName != null ? props.moduleName : ""
+ },
+ {
+ macro: "_moduledescription_",
+ value: props.moduleDescription != null ? props.moduleDescription : ""
+ }
+ ],
+ this.props.label || ""
+ );
+ }
+
+ /**
+ * To update the content element.
+ * @return Item.
+ */
+ protected updateDomElement(element: HTMLElement): void {
+ element.innerHTML = this.createDomElement().innerHTML;
+ }
+
+ /**
+ * Public accessor of the `props` property.
+ * @return Properties.
+ */
+ public get props(): Props {
+ return { ...this.itemProps }; // Return a copy.
+ }
+
+ /**
+ * Public setter of the `props` property.
+ * If the new props are different enough than the
+ * stored props, a render would be fired.
+ * @param newProps
+ */
+ public set props(newProps: Props) {
+ const prevProps = this.props;
+ // Update the internal props.
+ this.itemProps = newProps;
+
+ // From this point, things which rely on this.props can access to the changes.
+
+ // Check if we should re-render.
+ if (this.shouldBeUpdated(prevProps, newProps)) this.render(prevProps);
+ }
+
+ /**
+ * To compare the previous and the new props and returns a boolean value
+ * in case the difference is meaningfull enough to perform DOM changes.
+ *
+ * Here, the only comparision is done by reference.
+ *
+ * Override this function to perform a different comparision depending on the item needs.
+ *
+ * @param prevProps
+ * @param newProps
+ * @return Whether the difference is meaningful enough to perform DOM changes or not.
+ */
+ protected shouldBeUpdated(prevProps: Props, newProps: Props): boolean {
+ return prevProps !== newProps;
+ }
+
+ /**
+ * To recreate or update the HTMLElement which represents the item into the DOM.
+ * @param prevProps If exists it will be used to only perform DOM updates instead of a full replace.
+ */
+ public render(prevProps: Props | null = null): void {
+ this.updateDomElement(this.childElementRef);
+
+ // Move box.
+ if (!prevProps || this.positionChanged(prevProps, this.props)) {
+ this.moveElement(this.props.x, this.props.y);
+ }
+ // Resize box.
+ if (!prevProps || this.sizeChanged(prevProps, this.props)) {
+ this.resizeElement(this.props.width, this.props.height);
+ }
+ // Change label.
+ const oldLabelHtml = this.labelElementRef.innerHTML;
+ const newLabelHtml = this.createLabelDomElement().innerHTML;
+ if (oldLabelHtml !== newLabelHtml) {
+ this.labelElementRef.innerHTML = newLabelHtml;
+ }
+ // Change label position.
+ if (!prevProps || prevProps.labelPosition !== this.props.labelPosition) {
+ this.changeLabelPosition(this.props.labelPosition);
+ }
+ // Change link.
+ if (
+ prevProps &&
+ (prevProps.isLinkEnabled !== this.props.isLinkEnabled ||
+ (this.props.isLinkEnabled && prevProps.link !== this.props.link))
+ ) {
+ const container = this.createContainerDomElement();
+ // Add the children of the old element.
+ container.innerHTML = this.elementRef.innerHTML;
+ // Copy the attributes.
+ const attrs = this.elementRef.attributes;
+ for (let i = 0; i < attrs.length; i++) {
+ if (attrs[i].nodeName !== "id") {
+ container.setAttributeNode(attrs[i]);
+ }
+ }
+ // Replace the reference.
+ if (this.elementRef.parentNode !== null) {
+ this.elementRef.parentNode.replaceChild(container, this.elementRef);
+ }
+
+ // Changed the reference to the main element. It's ugly, but needed.
+ this.elementRef = container;
+ }
+ }
+
+ /**
+ * To remove the event listeners and the elements from the DOM.
+ */
+ public remove(): void {
+ // Call the remove event.
+ this.removeEventManager.emit({ data: this.props });
+ // Event listeners.
+ this.disposables.forEach(disposable => {
+ try {
+ disposable.dispose();
+ } catch (ignored) {} // eslint-disable-line no-empty
+ });
+ // VisualConsoleItem DOM element.
+ this.elementRef.remove();
+ }
+
+ /**
+ * Compare the previous and the new position and return
+ * a boolean value in case the position changed.
+ * @param prevPosition
+ * @param newPosition
+ * @return Whether the position changed or not.
+ */
+ protected positionChanged(
+ prevPosition: Position,
+ newPosition: Position
+ ): boolean {
+ return prevPosition.x !== newPosition.x || prevPosition.y !== newPosition.y;
+ }
+
+ /**
+ * Move the label around the item content.
+ * @param position Label position.
+ */
+ protected changeLabelPosition(position: Props["labelPosition"]): void {
+ switch (position) {
+ case "up":
+ this.elementRef.style.flexDirection = "column-reverse";
+ break;
+ case "left":
+ this.elementRef.style.flexDirection = "row-reverse";
+ break;
+ case "right":
+ this.elementRef.style.flexDirection = "row";
+ break;
+ case "down":
+ default:
+ this.elementRef.style.flexDirection = "column";
+ break;
+ }
+
+ // Ugly table to show the label as its legacy counterpart.
+ const tables = this.labelElementRef.getElementsByTagName("table");
+ const table = tables.length > 0 ? tables.item(0) : null;
+ // Change the table size depending on its position.
+ if (table) {
+ switch (this.props.labelPosition) {
+ case "up":
+ case "down":
+ if (this.props.width > 0) {
+ table.style.width = `${this.props.width}px`;
+ table.style.height = null;
+ }
+ break;
+ case "left":
+ case "right":
+ if (this.props.height > 0) {
+ table.style.width = null;
+ table.style.height = `${this.props.height}px`;
+ }
+ break;
+ }
+ }
+ }
+
+ /**
+ * Move the DOM container.
+ * @param x Horizontal axis position.
+ * @param y Vertical axis position.
+ */
+ protected moveElement(x: number, y: number): void {
+ this.elementRef.style.left = `${x}px`;
+ this.elementRef.style.top = `${y}px`;
+ }
+
+ /**
+ * Update the position into the properties and move the DOM container.
+ * @param x Horizontal axis position.
+ * @param y Vertical axis position.
+ */
+ public move(x: number, y: number): void {
+ this.moveElement(x, y);
+ this.itemProps = {
+ ...this.props, // Object spread: http://es6-features.org/#SpreadOperator
+ x,
+ y
+ };
+ }
+
+ /**
+ * Compare the previous and the new size and return
+ * a boolean value in case the size changed.
+ * @param prevSize
+ * @param newSize
+ * @return Whether the size changed or not.
+ */
+ protected sizeChanged(prevSize: Size, newSize: Size): boolean {
+ return (
+ prevSize.width !== newSize.width || prevSize.height !== newSize.height
+ );
+ }
+
+ /**
+ * Resize the DOM content container.
+ * @param width
+ * @param height
+ */
+ protected resizeElement(width: number, height: number): void {
+ // The most valuable size is the content size.
+ this.childElementRef.style.width = width > 0 ? `${width}px` : null;
+ this.childElementRef.style.height = height > 0 ? `${height}px` : null;
+ }
+
+ /**
+ * Update the size into the properties and resize the DOM container.
+ * @param width
+ * @param height
+ */
+ public resize(width: number, height: number): void {
+ this.resizeElement(width, height);
+ this.itemProps = {
+ ...this.props, // Object spread: http://es6-features.org/#SpreadOperator
+ width,
+ height
+ };
+ }
+
+ /**
+ * To add an event handler to the click of the linked visual console elements.
+ * @param listener Function which is going to be executed when a linked console is clicked.
+ */
+ public onClick(listener: Listener>): Disposable {
+ /*
+ * The '.on' function returns a function which will clean the event
+ * listener when executed. We store all the 'dispose' functions to
+ * call them when the item should be cleared.
+ */
+ const disposable = this.clickEventManager.on(listener);
+ this.disposables.push(disposable);
+
+ return disposable;
+ }
+
+ /**
+ * To add an event handler to the removal of the item.
+ * @param listener Function which is going to be executed when a item is removed.
+ */
+ public onRemove(listener: Listener>): Disposable {
+ /*
+ * The '.on' function returns a function which will clean the event
+ * listener when executed. We store all the 'dispose' functions to
+ * call them when the item should be cleared.
+ */
+ const disposable = this.removeEventManager.on(listener);
+ this.disposables.push(disposable);
+
+ return disposable;
+ }
+}
+
+export default VisualConsoleItem;
diff --git a/visual_console_client/src/TypedEvent.ts b/visual_console_client/src/TypedEvent.ts
new file mode 100644
index 0000000000..e199470f6c
--- /dev/null
+++ b/visual_console_client/src/TypedEvent.ts
@@ -0,0 +1,40 @@
+export interface Listener {
+ (event: T): void;
+}
+
+export interface Disposable {
+ dispose: () => void;
+}
+
+/** passes through events as they happen. You will not get events from before you start listening */
+export default class TypedEvent {
+ private listeners: Listener[] = [];
+ private listenersOncer: Listener[] = [];
+
+ public on = (listener: Listener): Disposable => {
+ this.listeners.push(listener);
+ return {
+ dispose: () => this.off(listener)
+ };
+ };
+
+ public once = (listener: Listener): void => {
+ this.listenersOncer.push(listener);
+ };
+
+ public off = (listener: Listener): void => {
+ const callbackIndex = this.listeners.indexOf(listener);
+ if (callbackIndex > -1) this.listeners.splice(callbackIndex, 1);
+ };
+
+ public emit = (event: T): void => {
+ /** Update any general listeners */
+ this.listeners.forEach(listener => listener(event));
+
+ /** Clear the `once` queue */
+ this.listenersOncer.forEach(listener => listener(event));
+ this.listenersOncer = [];
+ };
+
+ public pipe = (te: TypedEvent): Disposable => this.on(e => te.emit(e));
+}
diff --git a/visual_console_client/src/VisualConsole.ts b/visual_console_client/src/VisualConsole.ts
new file mode 100644
index 0000000000..7b45ccc2f1
--- /dev/null
+++ b/visual_console_client/src/VisualConsole.ts
@@ -0,0 +1,560 @@
+import { UnknownObject, Size } from "./types";
+import {
+ parseBoolean,
+ sizePropsDecoder,
+ parseIntOr,
+ notEmptyStringOr
+} from "./lib";
+import Item, {
+ ItemType,
+ ItemProps,
+ ItemClickEvent,
+ ItemRemoveEvent
+} from "./Item";
+import StaticGraph, { staticGraphPropsDecoder } from "./items/StaticGraph";
+import Icon, { iconPropsDecoder } from "./items/Icon";
+import ColorCloud, { colorCloudPropsDecoder } from "./items/ColorCloud";
+import Group, { groupPropsDecoder } from "./items/Group";
+import Clock, { clockPropsDecoder } from "./items/Clock";
+import Box, { boxPropsDecoder } from "./items/Box";
+import Line, { linePropsDecoder } from "./items/Line";
+import Label, { labelPropsDecoder } from "./items/Label";
+import SimpleValue, { simpleValuePropsDecoder } from "./items/SimpleValue";
+import EventsHistory, {
+ eventsHistoryPropsDecoder
+} from "./items/EventsHistory";
+import Percentile, { percentilePropsDecoder } from "./items/Percentile";
+import TypedEvent, { Disposable, Listener } from "./TypedEvent";
+import DonutGraph, { donutGraphPropsDecoder } from "./items/DonutGraph";
+import BarsGraph, { barsGraphPropsDecoder } from "./items/BarsGraph";
+import ModuleGraph, { moduleGraphPropsDecoder } from "./items/ModuleGraph";
+import Service, { servicePropsDecoder } from "./items/Service";
+
+// TODO: Document.
+// eslint-disable-next-line @typescript-eslint/explicit-function-return-type
+function itemInstanceFrom(data: UnknownObject) {
+ const type = parseIntOr(data.type, null);
+ if (type == null) throw new TypeError("missing item type.");
+
+ switch (type as ItemType) {
+ case ItemType.STATIC_GRAPH:
+ return new StaticGraph(staticGraphPropsDecoder(data));
+ case ItemType.MODULE_GRAPH:
+ return new ModuleGraph(moduleGraphPropsDecoder(data));
+ case ItemType.SIMPLE_VALUE:
+ case ItemType.SIMPLE_VALUE_MAX:
+ case ItemType.SIMPLE_VALUE_MIN:
+ case ItemType.SIMPLE_VALUE_AVG:
+ return new SimpleValue(simpleValuePropsDecoder(data));
+ case ItemType.PERCENTILE_BAR:
+ case ItemType.PERCENTILE_BUBBLE:
+ case ItemType.CIRCULAR_PROGRESS_BAR:
+ case ItemType.CIRCULAR_INTERIOR_PROGRESS_BAR:
+ return new Percentile(percentilePropsDecoder(data));
+ case ItemType.LABEL:
+ return new Label(labelPropsDecoder(data));
+ case ItemType.ICON:
+ return new Icon(iconPropsDecoder(data));
+ case ItemType.SERVICE:
+ return new Service(servicePropsDecoder(data));
+ case ItemType.GROUP_ITEM:
+ return new Group(groupPropsDecoder(data));
+ case ItemType.BOX_ITEM:
+ return new Box(boxPropsDecoder(data));
+ case ItemType.LINE_ITEM:
+ return new Line(linePropsDecoder(data));
+ case ItemType.AUTO_SLA_GRAPH:
+ return new EventsHistory(eventsHistoryPropsDecoder(data));
+ case ItemType.DONUT_GRAPH:
+ return new DonutGraph(donutGraphPropsDecoder(data));
+ case ItemType.BARS_GRAPH:
+ return new BarsGraph(barsGraphPropsDecoder(data));
+ case ItemType.CLOCK:
+ return new Clock(clockPropsDecoder(data));
+ case ItemType.COLOR_CLOUD:
+ return new ColorCloud(colorCloudPropsDecoder(data));
+ default:
+ throw new TypeError("item not found");
+ }
+}
+
+// TODO: Document.
+// eslint-disable-next-line @typescript-eslint/explicit-function-return-type
+function decodeProps(data: UnknownObject) {
+ const type = parseIntOr(data.type, null);
+ if (type == null) throw new TypeError("missing item type.");
+
+ switch (type as ItemType) {
+ case ItemType.STATIC_GRAPH:
+ return staticGraphPropsDecoder(data);
+ case ItemType.MODULE_GRAPH:
+ return moduleGraphPropsDecoder(data);
+ case ItemType.SIMPLE_VALUE:
+ case ItemType.SIMPLE_VALUE_MAX:
+ case ItemType.SIMPLE_VALUE_MIN:
+ case ItemType.SIMPLE_VALUE_AVG:
+ return simpleValuePropsDecoder(data);
+ case ItemType.PERCENTILE_BAR:
+ case ItemType.PERCENTILE_BUBBLE:
+ case ItemType.CIRCULAR_PROGRESS_BAR:
+ case ItemType.CIRCULAR_INTERIOR_PROGRESS_BAR:
+ return percentilePropsDecoder(data);
+ case ItemType.LABEL:
+ return labelPropsDecoder(data);
+ case ItemType.ICON:
+ return iconPropsDecoder(data);
+ case ItemType.SERVICE:
+ return servicePropsDecoder(data);
+ case ItemType.GROUP_ITEM:
+ return groupPropsDecoder(data);
+ case ItemType.BOX_ITEM:
+ return boxPropsDecoder(data);
+ case ItemType.LINE_ITEM:
+ return linePropsDecoder(data);
+ case ItemType.AUTO_SLA_GRAPH:
+ return eventsHistoryPropsDecoder(data);
+ case ItemType.DONUT_GRAPH:
+ return donutGraphPropsDecoder(data);
+ case ItemType.BARS_GRAPH:
+ return barsGraphPropsDecoder(data);
+ case ItemType.CLOCK:
+ return clockPropsDecoder(data);
+ case ItemType.COLOR_CLOUD:
+ return colorCloudPropsDecoder(data);
+ default:
+ throw new TypeError("decoder not found");
+ }
+}
+
+// Base properties.
+export interface VisualConsoleProps extends Size {
+ readonly id: number;
+ name: string;
+ groupId: number;
+ backgroundURL: string | null; // URL?
+ backgroundColor: string | null;
+ isFavorite: boolean;
+ relationLineWidth: number;
+}
+
+/**
+ * Build a valid typed object from a raw object.
+ * This will allow us to ensure the type safety.
+ *
+ * @param data Raw object.
+ * @return An object representing the Visual Console props.
+ * @throws Will throw a TypeError if some property
+ * is missing from the raw object or have an invalid type.
+ */
+export function visualConsolePropsDecoder(
+ data: UnknownObject
+): VisualConsoleProps | never {
+ // Object destructuring: http://es6-features.org/#ObjectMatchingShorthandNotation
+ const {
+ id,
+ name,
+ groupId,
+ backgroundURL,
+ backgroundColor,
+ isFavorite,
+ relationLineWidth
+ } = data;
+
+ if (id == null || isNaN(parseInt(id))) {
+ throw new TypeError("invalid Id.");
+ }
+ if (typeof name !== "string" || name.length === 0) {
+ throw new TypeError("invalid name.");
+ }
+ if (groupId == null || isNaN(parseInt(groupId))) {
+ throw new TypeError("invalid group Id.");
+ }
+
+ return {
+ id: parseInt(id),
+ name,
+ groupId: parseInt(groupId),
+ backgroundURL: notEmptyStringOr(backgroundURL, null),
+ backgroundColor: notEmptyStringOr(backgroundColor, null),
+ isFavorite: parseBoolean(isFavorite),
+ relationLineWidth: parseIntOr(relationLineWidth, 0),
+ ...sizePropsDecoder(data)
+ };
+}
+
+export default class VisualConsole {
+ // Reference to the DOM element which will contain the items.
+ private readonly containerRef: HTMLElement;
+ // Properties.
+ private _props: VisualConsoleProps;
+ // Visual Console Item instances by their Id.
+ private elementsById: {
+ [key: number]: Item;
+ } = {};
+ // Visual Console Item Ids.
+ private elementIds: ItemProps["id"][] = [];
+ // Dictionary which store the created lines.
+ private relations: {
+ [key: string]: Line;
+ } = {};
+ // Event manager for click events.
+ private readonly clickEventManager = new TypedEvent<
+ ItemClickEvent
+ >();
+ // List of references to clean the event listeners.
+ private readonly disposables: Disposable[] = [];
+
+ /**
+ * React to a click on an element.
+ * @param e Event object.
+ */
+ private handleElementClick: (e: ItemClickEvent) => void = e => {
+ this.clickEventManager.emit(e);
+ // console.log(`Clicked element #${e.data.id}`, e);
+ };
+
+ /**
+ * Clear some element references.
+ * @param e Event object.
+ */
+ private handleElementRemove: (e: ItemRemoveEvent) => void = e => {
+ // Remove the element from the list and its relations.
+ this.elementIds = this.elementIds.filter(id => id !== e.data.id);
+ delete this.elementsById[e.data.id];
+ this.clearRelations(e.data.id);
+ };
+
+ public constructor(
+ container: HTMLElement,
+ props: UnknownObject,
+ items: UnknownObject[]
+ ) {
+ this.containerRef = container;
+ this._props = visualConsolePropsDecoder(props);
+
+ // Force the first render.
+ this.render();
+
+ // Sort by isOnTop, id ASC
+ items = items.sort(function(a, b) {
+ if (
+ a.isOnTop == null ||
+ b.isOnTop == null ||
+ a.id == null ||
+ b.id == null
+ ) {
+ return 0;
+ }
+
+ if (a.isOnTop && !b.isOnTop) return 1;
+ else if (!a.isOnTop && b.isOnTop) return -1;
+ else if (a.id > b.id) return 1;
+ else return -1;
+ });
+
+ // Initialize the items.
+ items.forEach(item => {
+ try {
+ const itemInstance = itemInstanceFrom(item);
+ // Add the item to the list.
+ this.elementsById[itemInstance.props.id] = itemInstance;
+ this.elementIds.push(itemInstance.props.id);
+ // Item event handlers.
+ itemInstance.onClick(this.handleElementClick);
+ itemInstance.onRemove(this.handleElementRemove);
+ // Add the item to the DOM.
+ this.containerRef.append(itemInstance.elementRef);
+ } catch (error) {
+ console.log("Error creating a new element:", error.message);
+ }
+ });
+
+ // Create lines.
+ this.buildRelations();
+ }
+
+ /**
+ * Public accessor of the `elements` property.
+ * @return Properties.
+ */
+ public get elements(): Item[] {
+ // Ensure the type cause Typescript doesn't know the filter removes null items.
+ return this.elementIds
+ .map(id => this.elementsById[id])
+ .filter(_ => _ != null) as Item[];
+ }
+
+ /**
+ * Public setter of the `elements` property.
+ * @param items.
+ */
+ public updateElements(items: UnknownObject[]): void {
+ const itemIds = items.map(item => item.id || null).filter(id => id != null);
+ itemIds as number[]; // Tell the type system to rely on us.
+ // Get the elements we should delete.
+ const deletedIds: number[] = this.elementIds.filter(
+ id => itemIds.indexOf(id) < 0
+ );
+ // Delete the elements.
+ deletedIds.forEach(id => {
+ if (this.elementsById[id] != null) {
+ this.elementsById[id].remove();
+ delete this.elementsById[id];
+ }
+ });
+ // Replace the element ids.
+ this.elementIds = itemIds;
+
+ // Initialize the items.
+ items.forEach(item => {
+ if (item.id) {
+ if (this.elementsById[item.id] == null) {
+ // New item.
+ try {
+ const itemInstance = itemInstanceFrom(item);
+ // Add the item to the list.
+ this.elementsById[itemInstance.props.id] = itemInstance;
+ // Item event handlers.
+ itemInstance.onClick(this.handleElementClick);
+ itemInstance.onRemove(this.handleElementRemove);
+ // Add the item to the DOM.
+ this.containerRef.append(itemInstance.elementRef);
+ } catch (error) {
+ console.log("Error creating a new element:", error.message);
+ }
+ } else {
+ // Update item.
+ try {
+ this.elementsById[item.id].props = decodeProps(item);
+ } catch (error) {
+ console.log("Error updating an element:", error.message);
+ }
+ }
+ }
+ });
+
+ // Re-build relations.
+ this.buildRelations();
+ }
+
+ /**
+ * Public accessor of the `props` property.
+ * @return Properties.
+ */
+ public get props(): VisualConsoleProps {
+ return { ...this._props }; // Return a copy.
+ }
+
+ /**
+ * Public setter of the `props` property.
+ * If the new props are different enough than the
+ * stored props, a render would be fired.
+ * @param newProps
+ */
+ public set props(newProps: VisualConsoleProps) {
+ const prevProps = this.props;
+ // Update the internal props.
+ this._props = newProps;
+
+ // From this point, things which rely on this.props can access to the changes.
+
+ // Re-render.
+ this.render(prevProps);
+ }
+
+ /**
+ * Recreate or update the HTMLElement which represents the Visual Console into the DOM.
+ * @param prevProps If exists it will be used to only DOM updates instead of a full replace.
+ */
+ public render(prevProps: VisualConsoleProps | null = null): void {
+ if (prevProps) {
+ if (prevProps.backgroundURL !== this.props.backgroundURL) {
+ this.containerRef.style.backgroundImage =
+ this.props.backgroundURL !== null
+ ? `url(${this.props.backgroundURL})`
+ : null;
+ }
+ if (prevProps.backgroundColor !== this.props.backgroundColor) {
+ this.containerRef.style.backgroundColor = this.props.backgroundColor;
+ }
+ if (this.sizeChanged(prevProps, this.props)) {
+ this.resizeElement(this.props.width, this.props.height);
+ }
+ } else {
+ this.containerRef.style.backgroundImage =
+ this.props.backgroundURL !== null
+ ? `url(${this.props.backgroundURL})`
+ : null;
+
+ this.containerRef.style.backgroundColor = this.props.backgroundColor;
+ this.resizeElement(this.props.width, this.props.height);
+ }
+ }
+
+ /**
+ * Compare the previous and the new size and return
+ * a boolean value in case the size changed.
+ * @param prevSize
+ * @param newSize
+ * @return Whether the size changed or not.
+ */
+ public sizeChanged(prevSize: Size, newSize: Size): boolean {
+ return (
+ prevSize.width !== newSize.width || prevSize.height !== newSize.height
+ );
+ }
+
+ /**
+ * Resize the DOM container.
+ * @param width
+ * @param height
+ */
+ public resizeElement(width: number, height: number): void {
+ this.containerRef.style.width = `${width}px`;
+ this.containerRef.style.height = `${height}px`;
+ }
+
+ /**
+ * Update the size into the properties and resize the DOM container.
+ * @param width
+ * @param height
+ */
+ public resize(width: number, height: number): void {
+ this.props = {
+ ...this.props, // Object spread: http://es6-features.org/#SpreadOperator
+ width,
+ height
+ };
+ }
+
+ /**
+ * To remove the event listeners and the elements from the DOM.
+ */
+ public remove(): void {
+ this.disposables.forEach(d => d.dispose()); // Arrow function.
+ this.elements.forEach(e => e.remove()); // Arrow function.
+ this.elementsById = {};
+ this.elementIds = [];
+ // Clear relations.
+ this.clearRelations();
+ // Clean container.
+ this.containerRef.innerHTML = "";
+ }
+
+ /**
+ * Create line elements which connect the elements with their parents.
+ */
+ private buildRelations(): void {
+ // Clear relations.
+ this.clearRelations();
+ // Add relations.
+ this.elements.forEach(item => {
+ if (item.props.parentId !== null) {
+ const parent = this.elementsById[item.props.parentId];
+ const child = this.elementsById[item.props.id];
+ if (parent && child) this.addRelationLine(parent, child);
+ }
+ });
+ }
+
+ /**
+ * @param itemId Optional identifier of a parent or child item.
+ * Remove the line elements which connect the elements with their parents.
+ */
+ private clearRelations(itemId?: number): void {
+ if (itemId != null) {
+ for (let key in this.relations) {
+ const ids = key.split("|");
+ const parentId = Number.parseInt(ids[0]);
+ const childId = Number.parseInt(ids[1]);
+
+ if (itemId === parentId || itemId === childId) {
+ this.relations[key].remove();
+ delete this.relations[key];
+ }
+ }
+ } else {
+ for (let key in this.relations) {
+ this.relations[key].remove();
+ delete this.relations[key];
+ }
+ }
+ }
+
+ /**
+ * Retrieve the line element which represent the relation between items.
+ * @param parentId Identifier of the parent item.
+ * @param childId Itentifier of the child item.
+ * @return The line element or nothing.
+ */
+ private getRelationLine(parentId: number, childId: number): Line | null {
+ const identifier = `${parentId}|${childId}`;
+ return this.relations[identifier] || null;
+ }
+
+ /**
+ * Add a new line item to represent a relation between the items.
+ * @param parent Parent item.
+ * @param child Child item.
+ * @return Whether the line was added or not.
+ */
+ private addRelationLine(
+ parent: Item,
+ child: Item
+ ): Line {
+ const identifier = `${parent.props.id}|${child.props.id}`;
+ if (this.relations[identifier] != null) {
+ this.relations[identifier].remove();
+ }
+
+ // Get the items center.
+ const startX = parent.props.x + parent.elementRef.clientWidth / 2;
+ const startY =
+ parent.props.y +
+ (parent.elementRef.clientHeight - parent.labelElementRef.clientHeight) /
+ 2;
+ const endX = child.props.x + child.elementRef.clientWidth / 2;
+ const endY =
+ child.props.y +
+ (child.elementRef.clientHeight - child.labelElementRef.clientHeight) / 2;
+
+ const line = new Line(
+ linePropsDecoder({
+ id: 0,
+ type: ItemType.LINE_ITEM,
+ startX,
+ startY,
+ endX,
+ endY,
+ width: 0,
+ height: 0,
+ lineWidth: this.props.relationLineWidth,
+ color: "#CCCCCC"
+ })
+ );
+ // Save a reference to the line item.
+ this.relations[identifier] = line;
+
+ // Add the line to the DOM.
+ line.elementRef.style.zIndex = "0";
+ this.containerRef.append(line.elementRef);
+
+ return line;
+ }
+
+ /**
+ * Add an event handler to the click of the linked visual console elements.
+ * @param listener Function which is going to be executed when a linked console is clicked.
+ */
+ public onClick(listener: Listener>): Disposable {
+ /*
+ * The '.on' function returns a function which will clean the event
+ * listener when executed. We store all the 'dispose' functions to
+ * call them when the item should be cleared.
+ */
+ const disposable = this.clickEventManager.on(listener);
+ this.disposables.push(disposable);
+
+ return disposable;
+ }
+}
diff --git a/visual_console_client/src/index.ts b/visual_console_client/src/index.ts
new file mode 100644
index 0000000000..a7e8656d8d
--- /dev/null
+++ b/visual_console_client/src/index.ts
@@ -0,0 +1,14 @@
+/*
+ * Useful resources.
+ * http://es6-features.org/
+ * http://exploringjs.com/es6
+ * https://www.typescriptlang.org/
+ */
+
+import "./main.css"; // CSS import.
+import VisualConsole from "./VisualConsole";
+
+// Export the VisualConsole class to the global object.
+
+// eslint-disable-next-line
+(window as any).VisualConsole = VisualConsole;
diff --git a/visual_console_client/src/items/BarsGraph.ts b/visual_console_client/src/items/BarsGraph.ts
new file mode 100644
index 0000000000..d1a6fe97a5
--- /dev/null
+++ b/visual_console_client/src/items/BarsGraph.ts
@@ -0,0 +1,67 @@
+import { UnknownObject, WithModuleProps } from "../types";
+import { modulePropsDecoder, decodeBase64, stringIsEmpty } from "../lib";
+import Item, { ItemType, ItemProps, itemBasePropsDecoder } from "../Item";
+
+export type BarsGraphProps = {
+ type: ItemType.BARS_GRAPH;
+ html: string;
+} & ItemProps &
+ WithModuleProps;
+
+/**
+ * Build a valid typed object from a raw object.
+ * This will allow us to ensure the type safety.
+ *
+ * @param data Raw object.
+ * @return An object representing the bars graph props.
+ * @throws Will throw a TypeError if some property
+ * is missing from the raw object or have an invalid type.
+ */
+export function barsGraphPropsDecoder(
+ data: UnknownObject
+): BarsGraphProps | never {
+ if (stringIsEmpty(data.html) && stringIsEmpty(data.encodedHtml)) {
+ throw new TypeError("missing html content.");
+ }
+
+ return {
+ ...itemBasePropsDecoder(data), // Object spread. It will merge the properties of the two objects.
+ type: ItemType.BARS_GRAPH,
+ html: !stringIsEmpty(data.html)
+ ? data.html
+ : decodeBase64(data.encodedHtml),
+ ...modulePropsDecoder(data) // Object spread. It will merge the properties of the two objects.
+ };
+}
+
+export default class BarsGraph extends Item {
+ protected createDomElement(): HTMLElement {
+ const element = document.createElement("div");
+ element.className = "bars-graph";
+ element.innerHTML = this.props.html;
+
+ // Hack to execute the JS after the HTML is added to the DOM.
+ const scripts = element.getElementsByTagName("script");
+ for (let i = 0; i < scripts.length; i++) {
+ setTimeout(() => {
+ if (scripts[i].src.length === 0) eval(scripts[i].innerHTML.trim());
+ }, 0);
+ }
+
+ return element;
+ }
+
+ protected updateDomElement(element: HTMLElement): void {
+ element.innerHTML = this.props.html;
+
+ // Hack to execute the JS after the HTML is added to the DOM.
+ const aux = document.createElement("div");
+ aux.innerHTML = this.props.html;
+ const scripts = aux.getElementsByTagName("script");
+ for (let i = 0; i < scripts.length; i++) {
+ if (scripts[i].src.length === 0) {
+ eval(scripts[i].innerHTML.trim());
+ }
+ }
+ }
+}
diff --git a/visual_console_client/src/items/Box.ts b/visual_console_client/src/items/Box.ts
new file mode 100644
index 0000000000..ca3078c0a6
--- /dev/null
+++ b/visual_console_client/src/items/Box.ts
@@ -0,0 +1,68 @@
+import { UnknownObject } from "../types";
+import { parseIntOr, notEmptyStringOr } from "../lib";
+import Item, { ItemType, ItemProps, itemBasePropsDecoder } from "../Item";
+
+interface BoxProps extends ItemProps {
+ // Overrided properties.
+ readonly type: ItemType.BOX_ITEM;
+ label: null;
+ isLinkEnabled: false;
+ parentId: null;
+ aclGroupId: null;
+ // Custom properties.
+ borderWidth: number;
+ borderColor: string | null;
+ fillColor: string | null;
+}
+
+/**
+ * Build a valid typed object from a raw object.
+ * This will allow us to ensure the type safety.
+ *
+ * @param data Raw object.
+ * @return An object representing the item props.
+ * @throws Will throw a TypeError if some property
+ * is missing from the raw object or have an invalid type.
+ */
+export function boxPropsDecoder(data: UnknownObject): BoxProps | never {
+ return {
+ ...itemBasePropsDecoder(data), // Object spread. It will merge the properties of the two objects.
+ type: ItemType.BOX_ITEM,
+ label: null,
+ isLinkEnabled: false,
+ parentId: null,
+ aclGroupId: null,
+ // Custom properties.
+ borderWidth: parseIntOr(data.borderWidth, 0),
+ borderColor: notEmptyStringOr(data.borderColor, null),
+ fillColor: notEmptyStringOr(data.fillColor, null)
+ };
+}
+
+export default class Box extends Item {
+ protected createDomElement(): HTMLElement {
+ const box: HTMLDivElement = document.createElement("div");
+ box.className = "box";
+ // To prevent this item to expand beyond its parent.
+ box.style.boxSizing = "border-box";
+
+ if (this.props.fillColor) {
+ box.style.backgroundColor = this.props.fillColor;
+ }
+
+ // Border.
+ if (this.props.borderWidth > 0) {
+ box.style.borderStyle = "solid";
+ // Control the max width to prevent this item to expand beyond its parent.
+ const maxBorderWidth = Math.min(this.props.width, this.props.height) / 2;
+ const borderWidth = Math.min(this.props.borderWidth, maxBorderWidth);
+ box.style.borderWidth = `${borderWidth}px`;
+
+ if (this.props.borderColor) {
+ box.style.borderColor = this.props.borderColor;
+ }
+ }
+
+ return box;
+ }
+}
diff --git a/visual_console_client/src/items/Clock/alarm-clock.ttf b/visual_console_client/src/items/Clock/alarm-clock.ttf
new file mode 100755
index 0000000000..9e9b593459
Binary files /dev/null and b/visual_console_client/src/items/Clock/alarm-clock.ttf differ
diff --git a/visual_console_client/src/items/Clock/index.ts b/visual_console_client/src/items/Clock/index.ts
new file mode 100644
index 0000000000..a65f188659
--- /dev/null
+++ b/visual_console_client/src/items/Clock/index.ts
@@ -0,0 +1,601 @@
+import "./styles.css";
+
+import { LinkedVisualConsoleProps, UnknownObject, Size } from "../../types";
+import {
+ linkedVCPropsDecoder,
+ parseIntOr,
+ parseBoolean,
+ prefixedCssRules,
+ notEmptyStringOr,
+ humanDate,
+ humanTime
+} from "../../lib";
+import Item, { ItemProps, itemBasePropsDecoder, ItemType } from "../../Item";
+
+export type ClockProps = {
+ type: ItemType.CLOCK;
+ clockType: "analogic" | "digital";
+ clockFormat: "datetime" | "time";
+ clockTimezone: string;
+ clockTimezoneOffset: number; // Offset of the timezone to UTC in seconds.
+ showClockTimezone: boolean;
+ color?: string | null;
+} & ItemProps &
+ LinkedVisualConsoleProps;
+
+/**
+ * Extract a valid enum value from a raw unknown value.
+ * @param clockType Raw value.
+ */
+const parseClockType = (
+ clockType: any // eslint-disable-line @typescript-eslint/no-explicit-any
+): ClockProps["clockType"] => {
+ switch (clockType) {
+ case "analogic":
+ case "digital":
+ return clockType;
+ default:
+ return "analogic";
+ }
+};
+
+/**
+ * Extract a valid enum value from a raw unknown value.
+ * @param clockFormat Raw value.
+ */
+const parseClockFormat = (
+ clockFormat: any // eslint-disable-line @typescript-eslint/no-explicit-any
+): ClockProps["clockFormat"] => {
+ switch (clockFormat) {
+ case "datetime":
+ case "date":
+ case "time":
+ return clockFormat;
+ default:
+ return "datetime";
+ }
+};
+
+/**
+ * Build a valid typed object from a raw object.
+ * This will allow us to ensure the type safety.
+ *
+ * @param data Raw object.
+ * @return An object representing the clock props.
+ * @throws Will throw a TypeError if some property
+ * is missing from the raw object or have an invalid type.
+ */
+export function clockPropsDecoder(data: UnknownObject): ClockProps | never {
+ if (
+ typeof data.clockTimezone !== "string" ||
+ data.clockTimezone.length === 0
+ ) {
+ throw new TypeError("invalid timezone.");
+ }
+
+ return {
+ ...itemBasePropsDecoder(data), // Object spread. It will merge the properties of the two objects.
+ type: ItemType.CLOCK,
+ clockType: parseClockType(data.clockType),
+ clockFormat: parseClockFormat(data.clockFormat),
+ clockTimezone: data.clockTimezone,
+ clockTimezoneOffset: parseIntOr(data.clockTimezoneOffset, 0),
+ showClockTimezone: parseBoolean(data.showClockTimezone),
+ color: notEmptyStringOr(data.color, null),
+ ...linkedVCPropsDecoder(data) // Object spread. It will merge the properties of the two objects.
+ };
+}
+
+export default class Clock extends Item {
+ public static readonly TICK_INTERVAL = 1000; // In ms.
+ private intervalRef: number | null = null;
+
+ public constructor(props: ClockProps) {
+ // Call the superclass constructor.
+ super(props);
+
+ /* The item is already loaded and inserted into the DOM.
+ * The class properties are now initialized.
+ * Now you can modify the item, add event handlers, timers, etc.
+ */
+
+ /* The use of the arrow function is important here. startTick will
+ * use the function passed as an argument to call the global setInterval
+ * function. The interval, timeout or event functions, among other, are
+ * called into another execution loop and using a different context.
+ * The arrow functions, unlike the classic functions, doesn't create
+ * their own context (this), so their context at execution time will be
+ * use the current context at the declaration time.
+ * http://es6-features.org/#Lexicalthis
+ */
+ this.startTick(
+ () => {
+ // Replace the old element with the updated date.
+ this.childElementRef.innerHTML = this.createClock().innerHTML;
+ },
+ /* The analogic clock doesn't need to tick,
+ * but it will be refreshed every 20 seconds
+ * to avoid a desync caused by page freezes.
+ */
+ this.props.clockType === "analogic" ? 20000 : Clock.TICK_INTERVAL
+ );
+ }
+
+ /**
+ * Wrap a window.clearInterval call.
+ */
+ private stopTick(): void {
+ if (this.intervalRef !== null) {
+ window.clearInterval(this.intervalRef);
+ this.intervalRef = null;
+ }
+ }
+
+ /**
+ * Wrap a window.setInterval call.
+ * @param handler Function to be called every time the interval
+ * timer is reached.
+ * @param interval Number in milliseconds for the interval timer.
+ */
+ private startTick(
+ handler: TimerHandler,
+ interval: number = Clock.TICK_INTERVAL
+ ): void {
+ this.stopTick();
+ this.intervalRef = window.setInterval(handler, interval);
+ }
+
+ /**
+ * Create a element which contains the DOM representation of the item.
+ * @return DOM Element.
+ * @override
+ */
+ protected createDomElement(): HTMLElement | never {
+ return this.createClock();
+ }
+
+ /**
+ * To remove the event listeners and the elements from the DOM.
+ * @override
+ */
+ public remove(): void {
+ // Clear the interval.
+ this.stopTick();
+ // Call to the parent clean function.
+ super.remove();
+ }
+
+ /**
+ * @override Item.resizeElement
+ * Resize the DOM content container.
+ * @param width
+ * @param height
+ */
+ protected resizeElement(width: number, height: number): void {
+ const { width: newWidth, height: newHeight } = this.getElementSize(
+ width,
+ height
+ ); // Destructuring assigment: http://es6-features.org/#ObjectMatchingShorthandNotation
+ super.resizeElement(newWidth, newHeight);
+ // Re-render the item to force it calculate a new font size.
+ if (this.props.clockType === "digital") {
+ // Replace the old element with the updated date.
+ this.childElementRef.innerHTML = this.createClock().innerHTML;
+ }
+ }
+
+ /**
+ * Create a element which contains a representation of a clock.
+ * It choose between the clock types.
+ * @return DOM Element.
+ * @throws Error.
+ */
+ private createClock(): HTMLElement | never {
+ switch (this.props.clockType) {
+ case "analogic":
+ return this.createAnalogicClock();
+ case "digital":
+ return this.createDigitalClock();
+ default:
+ throw new Error("invalid clock type.");
+ }
+ }
+
+ /**
+ * Create a element which contains a representation of an analogic clock.
+ * @return DOM Element.
+ */
+ private createAnalogicClock(): HTMLElement {
+ const svgNS = "http://www.w3.org/2000/svg";
+ const colors = {
+ watchFace: "#FFFFF0",
+ watchFaceBorder: "#242124",
+ mark: "#242124",
+ handDark: "#242124",
+ handLight: "#525252",
+ secondHand: "#DC143C"
+ };
+
+ const { width, height } = this.getElementSize(); // Destructuring assigment: http://es6-features.org/#ObjectMatchingShorthandNotation
+
+ const div = document.createElement("div");
+ div.className = "analogic-clock";
+ div.style.width = `${width}px`;
+ div.style.height = `${height}px`;
+
+ // SVG container.
+ const svg = document.createElementNS(svgNS, "svg");
+ // Auto resize SVG using the view box magic: https://css-tricks.com/scale-svg/
+ svg.setAttribute("viewBox", "0 0 100 100");
+
+ // Clock face.
+ const clockFace = document.createElementNS(svgNS, "g");
+ clockFace.setAttribute("class", "clockface");
+ const clockFaceBackground = document.createElementNS(svgNS, "circle");
+ clockFaceBackground.setAttribute("cx", "50");
+ clockFaceBackground.setAttribute("cy", "50");
+ clockFaceBackground.setAttribute("r", "48");
+ clockFaceBackground.setAttribute("fill", colors.watchFace);
+ clockFaceBackground.setAttribute("stroke", colors.watchFaceBorder);
+ clockFaceBackground.setAttribute("stroke-width", "2");
+ clockFaceBackground.setAttribute("stroke-linecap", "round");
+ // Insert the clockface background into the clockface group.
+ clockFace.append(clockFaceBackground);
+
+ // Timezone complication.
+ const city = this.getHumanTimezone();
+ if (city.length > 0) {
+ const timezoneComplication = document.createElementNS(svgNS, "text");
+ timezoneComplication.setAttribute("text-anchor", "middle");
+ timezoneComplication.setAttribute("font-size", "8");
+ timezoneComplication.setAttribute(
+ "transform",
+ "translate(30 50) rotate(90)" // Rotate to counter the clock rotation.
+ );
+ timezoneComplication.setAttribute("fill", colors.mark);
+ timezoneComplication.textContent = city;
+ clockFace.append(timezoneComplication);
+ }
+
+ // Marks group.
+ const marksGroup = document.createElementNS(svgNS, "g");
+ marksGroup.setAttribute("class", "marks");
+ // Build the 12 hours mark.
+ const mainMarkGroup = document.createElementNS(svgNS, "g");
+ mainMarkGroup.setAttribute("class", "mark");
+ mainMarkGroup.setAttribute("transform", "translate(50 50)");
+ const mark1a = document.createElementNS(svgNS, "line");
+ mark1a.setAttribute("x1", "36");
+ mark1a.setAttribute("y1", "0");
+ mark1a.setAttribute("x2", "46");
+ mark1a.setAttribute("y2", "0");
+ mark1a.setAttribute("stroke", colors.mark);
+ mark1a.setAttribute("stroke-width", "5");
+ const mark1b = document.createElementNS(svgNS, "line");
+ mark1b.setAttribute("x1", "36");
+ mark1b.setAttribute("y1", "0");
+ mark1b.setAttribute("x2", "46");
+ mark1b.setAttribute("y2", "0");
+ mark1b.setAttribute("stroke", colors.watchFace);
+ mark1b.setAttribute("stroke-width", "1");
+ // Insert the 12 mark lines into their group.
+ mainMarkGroup.append(mark1a, mark1b);
+ // Insert the main mark into the marks group.
+ marksGroup.append(mainMarkGroup);
+ // Build the rest of the marks.
+ for (let i = 1; i < 60; i++) {
+ const mark = document.createElementNS(svgNS, "line");
+ mark.setAttribute("y1", "0");
+ mark.setAttribute("y2", "0");
+ mark.setAttribute("stroke", colors.mark);
+ mark.setAttribute("transform", `translate(50 50) rotate(${i * 6})`);
+
+ if (i % 5 === 0) {
+ mark.setAttribute("x1", "38");
+ mark.setAttribute("x2", "46");
+ mark.setAttribute("stroke-width", i % 15 === 0 ? "2" : "1");
+ } else {
+ mark.setAttribute("x1", "42");
+ mark.setAttribute("x2", "46");
+ mark.setAttribute("stroke-width", "0.5");
+ }
+
+ // Insert the mark into the marks group.
+ marksGroup.append(mark);
+ }
+
+ /* Clock hands */
+
+ // Hour hand.
+ const hourHand = document.createElementNS(svgNS, "g");
+ hourHand.setAttribute("class", "hour-hand");
+ hourHand.setAttribute("transform", "translate(50 50)");
+ // This will go back and will act like a border.
+ const hourHandA = document.createElementNS(svgNS, "line");
+ hourHandA.setAttribute("class", "hour-hand-a");
+ hourHandA.setAttribute("x1", "0");
+ hourHandA.setAttribute("y1", "0");
+ hourHandA.setAttribute("x2", "30");
+ hourHandA.setAttribute("y2", "0");
+ hourHandA.setAttribute("stroke", colors.handLight);
+ hourHandA.setAttribute("stroke-width", "4");
+ hourHandA.setAttribute("stroke-linecap", "round");
+ // This will go in front of the previous line.
+ const hourHandB = document.createElementNS(svgNS, "line");
+ hourHandB.setAttribute("class", "hour-hand-b");
+ hourHandB.setAttribute("x1", "0");
+ hourHandB.setAttribute("y1", "0");
+ hourHandB.setAttribute("x2", "29.9");
+ hourHandB.setAttribute("y2", "0");
+ hourHandB.setAttribute("stroke", colors.handDark);
+ hourHandB.setAttribute("stroke-width", "3.1");
+ hourHandB.setAttribute("stroke-linecap", "round");
+ // Append the elements to finish the hour hand.
+ hourHand.append(hourHandA, hourHandB);
+
+ // Minute hand.
+ const minuteHand = document.createElementNS(svgNS, "g");
+ minuteHand.setAttribute("class", "minute-hand");
+ minuteHand.setAttribute("transform", "translate(50 50)");
+ // This will go back and will act like a border.
+ const minuteHandA = document.createElementNS(svgNS, "line");
+ minuteHandA.setAttribute("class", "minute-hand-a");
+ minuteHandA.setAttribute("x1", "0");
+ minuteHandA.setAttribute("y1", "0");
+ minuteHandA.setAttribute("x2", "40");
+ minuteHandA.setAttribute("y2", "0");
+ minuteHandA.setAttribute("stroke", colors.handLight);
+ minuteHandA.setAttribute("stroke-width", "2");
+ minuteHandA.setAttribute("stroke-linecap", "round");
+ // This will go in front of the previous line.
+ const minuteHandB = document.createElementNS(svgNS, "line");
+ minuteHandB.setAttribute("class", "minute-hand-b");
+ minuteHandB.setAttribute("x1", "0");
+ minuteHandB.setAttribute("y1", "0");
+ minuteHandB.setAttribute("x2", "39.9");
+ minuteHandB.setAttribute("y2", "0");
+ minuteHandB.setAttribute("stroke", colors.handDark);
+ minuteHandB.setAttribute("stroke-width", "1.5");
+ minuteHandB.setAttribute("stroke-linecap", "round");
+ const minuteHandPin = document.createElementNS(svgNS, "circle");
+ minuteHandPin.setAttribute("r", "3");
+ minuteHandPin.setAttribute("fill", colors.handDark);
+ // Append the elements to finish the minute hand.
+ minuteHand.append(minuteHandA, minuteHandB, minuteHandPin);
+
+ // Second hand.
+ const secondHand = document.createElementNS(svgNS, "g");
+ secondHand.setAttribute("class", "second-hand");
+ secondHand.setAttribute("transform", "translate(50 50)");
+ const secondHandBar = document.createElementNS(svgNS, "line");
+ secondHandBar.setAttribute("x1", "0");
+ secondHandBar.setAttribute("y1", "0");
+ secondHandBar.setAttribute("x2", "46");
+ secondHandBar.setAttribute("y2", "0");
+ secondHandBar.setAttribute("stroke", colors.secondHand);
+ secondHandBar.setAttribute("stroke-width", "1");
+ secondHandBar.setAttribute("stroke-linecap", "round");
+ const secondHandPin = document.createElementNS(svgNS, "circle");
+ secondHandPin.setAttribute("r", "2");
+ secondHandPin.setAttribute("fill", colors.secondHand);
+ // Append the elements to finish the second hand.
+ secondHand.append(secondHandBar, secondHandPin);
+
+ // Pin.
+ const pin = document.createElementNS(svgNS, "circle");
+ pin.setAttribute("cx", "50");
+ pin.setAttribute("cy", "50");
+ pin.setAttribute("r", "0.3");
+ pin.setAttribute("fill", colors.handDark);
+
+ // Get the hand angles.
+ const date = this.getOriginDate();
+ const seconds = date.getSeconds();
+ const minutes = date.getMinutes();
+ const hours = date.getHours();
+ const secAngle = (360 / 60) * seconds;
+ const minuteAngle = (360 / 60) * minutes + (360 / 60) * (seconds / 60);
+ const hourAngle = (360 / 12) * hours + (360 / 12) * (minutes / 60);
+ // Set the clock time by moving the hands.
+ hourHand.setAttribute("transform", `translate(50 50) rotate(${hourAngle})`);
+ minuteHand.setAttribute(
+ "transform",
+ `translate(50 50) rotate(${minuteAngle})`
+ );
+ secondHand.setAttribute(
+ "transform",
+ `translate(50 50) rotate(${secAngle})`
+ );
+
+ // Build the clock
+ svg.append(clockFace, marksGroup, hourHand, minuteHand, secondHand, pin);
+ // Rotate the clock to its normal position.
+ svg.setAttribute("transform", "rotate(-90)");
+
+ /* Add the animation declaration to the container.
+ * Since the animation keyframes need to know the
+ * start angle, this angle is dynamic (current time),
+ * and we can't edit keyframes through javascript
+ * safely and with backwards compatibility, we need
+ * to inject it.
+ */
+ div.innerHTML = `
+
+ `;
+ // Add the clock to the container
+ div.append(svg);
+
+ return div;
+ }
+
+ /**
+ * Create a element which contains a representation of a digital clock.
+ * @return DOM Element.
+ */
+ private createDigitalClock(): HTMLElement {
+ const element: HTMLDivElement = document.createElement("div");
+ element.className = "digital-clock";
+
+ const { width } = this.getElementSize(); // Destructuring assigment: http://es6-features.org/#ObjectMatchingShorthandNotation
+
+ // Calculate font size to adapt the font to the item size.
+ const baseTimeFontSize = 20; // Per 100px of width.
+ const dateFontSizeMultiplier = 0.5;
+ const tzFontSizeMultiplier = 6 / this.props.clockTimezone.length;
+ const timeFontSize = (baseTimeFontSize * width) / 100;
+ const dateFontSize =
+ (baseTimeFontSize * dateFontSizeMultiplier * width) / 100;
+ const tzFontSize = Math.min(
+ (baseTimeFontSize * tzFontSizeMultiplier * width) / 100,
+ (width / 100) * 10
+ );
+
+ // Date calculated using the original timezone.
+ const date = this.getOriginDate();
+
+ // Date.
+ if (this.props.clockFormat === "datetime") {
+ const dateElem: HTMLSpanElement = document.createElement("span");
+ dateElem.className = "date";
+ dateElem.textContent = humanDate(date, "default");
+ dateElem.style.fontSize = `${dateFontSize}px`;
+ if (this.props.color) dateElem.style.color = this.props.color;
+ element.append(dateElem);
+ }
+
+ // Time.
+ const timeElem: HTMLSpanElement = document.createElement("span");
+ timeElem.className = "time";
+ timeElem.textContent = humanTime(date);
+ timeElem.style.fontSize = `${timeFontSize}px`;
+ if (this.props.color) timeElem.style.color = this.props.color;
+ element.append(timeElem);
+
+ // City name.
+ const city = this.getHumanTimezone();
+ if (city.length > 0) {
+ const tzElem: HTMLSpanElement = document.createElement("span");
+ tzElem.className = "timezone";
+ tzElem.textContent = city;
+ tzElem.style.fontSize = `${tzFontSize}px`;
+ if (this.props.color) tzElem.style.color = this.props.color;
+ element.append(tzElem);
+ }
+
+ return element;
+ }
+
+ /**
+ * Generate the current date using the timezone offset stored into the properties.
+ * @return The current date.
+ */
+ private getOriginDate(initialDate: Date | null = null): Date {
+ const d = initialDate ? initialDate : new Date();
+ const targetTZOffset = this.props.clockTimezoneOffset * 1000; // In ms.
+ const localTZOffset = d.getTimezoneOffset() * 60 * 1000; // In ms.
+ const utimestamp = d.getTime() + targetTZOffset + localTZOffset;
+
+ return new Date(utimestamp);
+ }
+
+ /**
+ * Extract a human readable city name from the timezone text.
+ * @param timezone Timezone text.
+ */
+ public getHumanTimezone(timezone: string = this.props.clockTimezone): string {
+ const [, city = ""] = timezone.split("/");
+ return city.replace("_", " ");
+ }
+
+ /**
+ * Generate a element size using the current size and the default values.
+ * @return The size.
+ */
+ private getElementSize(
+ width: number = this.props.width,
+ height: number = this.props.height
+ ): Size {
+ switch (this.props.clockType) {
+ case "analogic": {
+ let diameter = 100; // Default value.
+
+ if (width > 0 && height > 0) {
+ diameter = Math.min(width, height);
+ } else if (width > 0) {
+ diameter = width;
+ } else if (height > 0) {
+ diameter = height;
+ }
+
+ return {
+ width: diameter,
+ height: diameter
+ };
+ }
+ case "digital": {
+ if (width > 0 && height > 0) {
+ // The proportion of the clock should be (width = height / 2) aproximately.
+ height = width / 2 < height ? width / 2 : height;
+ } else if (width > 0) {
+ height = width / 2;
+ } else if (height > 0) {
+ // The proportion of the clock should be (height * 2 = width) aproximately.
+ width = height * 2;
+ } else {
+ width = 100; // Default value.
+ height = 50; // Default value.
+ }
+
+ return {
+ width,
+ height
+ };
+ }
+ default:
+ throw new Error("invalid clock type.");
+ }
+ }
+}
diff --git a/visual_console_client/src/items/Clock/spec.ts b/visual_console_client/src/items/Clock/spec.ts
new file mode 100644
index 0000000000..7380f98468
--- /dev/null
+++ b/visual_console_client/src/items/Clock/spec.ts
@@ -0,0 +1,67 @@
+import Clock, { clockPropsDecoder } from ".";
+
+const genericRawProps = {
+ id: 1,
+ type: 19, // Clock item = 19
+ label: null,
+ isLinkEnabled: false,
+ isOnTop: false,
+ parentId: null,
+ aclGroupId: null
+};
+
+const positionRawProps = {
+ x: 100,
+ y: 50
+};
+
+const sizeRawProps = {
+ width: 100,
+ height: 100
+};
+
+const digitalClockProps = {
+ clockType: "digital",
+ clockFormat: "datetime",
+ clockTimezone: "Madrid",
+ clockTimezoneOffset: 60,
+ showClockTimezone: true,
+ color: "white"
+};
+
+const linkedModuleProps = {
+ // Agent props.
+ agentId: null,
+ agentName: null,
+ // Module props.
+ moduleId: null,
+ moduleName: null
+};
+
+describe("Clock item", () => {
+ const clockInstance = new Clock(
+ clockPropsDecoder({
+ ...genericRawProps,
+ ...positionRawProps,
+ ...sizeRawProps,
+ ...linkedModuleProps,
+ ...digitalClockProps
+ })
+ );
+
+ it("should have the digital-clock class", () => {
+ expect(
+ clockInstance.elementRef.getElementsByClassName("digital-clock").length
+ ).toBeGreaterThan(0);
+ });
+
+ describe("getHumanTimezone function", () => {
+ it("should return a better timezone", () => {
+ expect(clockInstance.getHumanTimezone("America/New_York")).toBe(
+ "New York"
+ );
+ expect(clockInstance.getHumanTimezone("Europe/Madrid")).toBe("Madrid");
+ expect(clockInstance.getHumanTimezone("Asia/Tokyo")).toBe("Tokyo");
+ });
+ });
+});
diff --git a/visual_console_client/src/items/Clock/styles.css b/visual_console_client/src/items/Clock/styles.css
new file mode 100644
index 0000000000..cfa6f11eb5
--- /dev/null
+++ b/visual_console_client/src/items/Clock/styles.css
@@ -0,0 +1,48 @@
+@font-face {
+ font-family: Alarm Clock;
+ src: url(./alarm-clock.ttf);
+}
+
+/* Digital clock */
+
+.visual-console-item .digital-clock {
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ justify-items: center;
+ align-content: center;
+ align-items: center;
+}
+
+.visual-console-item .digital-clock > span {
+ font-family: "Alarm Clock", "Courier New", Courier, monospace;
+ font-size: 50px;
+
+ /* To improve legibility */
+ -webkit-font-smoothing: antialiased;
+ -moz-osx-font-smoothing: grayscale;
+ text-rendering: optimizeLegibility;
+ text-shadow: rgba(0, 0, 0, 0.01) 0 0 1px;
+}
+
+.visual-console-item .digital-clock > span.date {
+ font-size: 25px;
+}
+
+.visual-console-item .digital-clock > span.timezone {
+ font-size: 25px;
+}
+
+/* Analog clock */
+
+.visual-console-item .analogic-clock .hour-hand {
+ animation: rotate-hour 43200s infinite linear;
+}
+
+.visual-console-item .analogic-clock .minute-hand {
+ animation: rotate-minute 3600s infinite linear;
+}
+
+.visual-console-item .analogic-clock .second-hand {
+ animation: rotate-second 60s infinite linear;
+}
diff --git a/visual_console_client/src/items/ColorCloud.spec.ts b/visual_console_client/src/items/ColorCloud.spec.ts
new file mode 100644
index 0000000000..103850b04b
--- /dev/null
+++ b/visual_console_client/src/items/ColorCloud.spec.ts
@@ -0,0 +1,64 @@
+import ColorCloud, { colorCloudPropsDecoder } from "./ColorCloud";
+
+const genericRawProps = {
+ id: 1,
+ type: 20, // COlor cloud item = 20
+ label: null,
+ isLinkEnabled: false,
+ isOnTop: false,
+ parentId: null,
+ aclGroupId: null
+};
+
+const positionRawProps = {
+ x: 100,
+ y: 50
+};
+
+const sizeRawProps = {
+ width: 100,
+ height: 100
+};
+
+const colorCloudProps = {
+ color: "rgb(100, 50, 245)"
+};
+
+const linkedModuleProps = {
+ // Agent props.
+ agentId: null,
+ agentName: null,
+ // Module props.
+ moduleId: null,
+ moduleName: null
+};
+
+describe("Color cloud item", () => {
+ const colorCloudInstance = new ColorCloud(
+ colorCloudPropsDecoder({
+ ...genericRawProps,
+ ...positionRawProps,
+ ...sizeRawProps,
+ ...linkedModuleProps,
+ ...colorCloudProps
+ })
+ );
+
+ it("should throw when using an invalid color into the props decoder", () => {
+ expect(() =>
+ colorCloudPropsDecoder({
+ ...genericRawProps,
+ ...positionRawProps,
+ ...sizeRawProps,
+ ...linkedModuleProps,
+ color: null
+ })
+ ).toThrowError(TypeError);
+ });
+
+ it("should have the color-cloud class", () => {
+ expect(
+ colorCloudInstance.elementRef.getElementsByClassName("color-cloud").length
+ ).toBeGreaterThan(0);
+ });
+});
diff --git a/visual_console_client/src/items/ColorCloud.ts b/visual_console_client/src/items/ColorCloud.ts
new file mode 100644
index 0000000000..0b5dfe9948
--- /dev/null
+++ b/visual_console_client/src/items/ColorCloud.ts
@@ -0,0 +1,100 @@
+import {
+ WithModuleProps,
+ LinkedVisualConsoleProps,
+ UnknownObject
+} from "../types";
+import { modulePropsDecoder, linkedVCPropsDecoder } from "../lib";
+import Item, { itemBasePropsDecoder, ItemType, ItemProps } from "../Item";
+
+export type ColorCloudProps = {
+ type: ItemType.COLOR_CLOUD;
+ color: string;
+ // TODO: Add the rest of the color cloud values?
+} & ItemProps &
+ WithModuleProps &
+ LinkedVisualConsoleProps;
+
+/**
+ * Build a valid typed object from a raw object.
+ * This will allow us to ensure the type safety.
+ *
+ * @param data Raw object.
+ * @return An object representing the static graph props.
+ * @throws Will throw a TypeError if some property
+ * is missing from the raw object or have an invalid type.
+ */
+export function colorCloudPropsDecoder(
+ data: UnknownObject
+): ColorCloudProps | never {
+ // TODO: Validate the color.
+ if (typeof data.color !== "string" || data.color.length === 0) {
+ throw new TypeError("invalid color.");
+ }
+
+ return {
+ ...itemBasePropsDecoder(data), // Object spread. It will merge the properties of the two objects.
+ type: ItemType.COLOR_CLOUD,
+ color: data.color,
+ ...modulePropsDecoder(data), // Object spread. It will merge the properties of the two objects.
+ ...linkedVCPropsDecoder(data) // Object spread. It will merge the properties of the two objects.
+ };
+}
+
+const svgNS = "http://www.w3.org/2000/svg";
+
+export default class ColorCloud extends Item {
+ protected createDomElement(): HTMLElement {
+ const container: HTMLDivElement = document.createElement("div");
+ container.className = "color-cloud";
+
+ // Add the SVG.
+ container.append(this.createSvgElement());
+
+ return container;
+ }
+
+ public createSvgElement(): SVGSVGElement {
+ const gradientId = `grad_${this.props.id}`;
+ // SVG container.
+ const svg = document.createElementNS(svgNS, "svg");
+ // Auto resize SVG using the view box magic: https://css-tricks.com/scale-svg/
+ svg.setAttribute("viewBox", "0 0 100 100");
+
+ // Defs.
+ const defs = document.createElementNS(svgNS, "defs");
+ // Radial gradient.
+ const radialGradient = document.createElementNS(svgNS, "radialGradient");
+ radialGradient.setAttribute("id", gradientId);
+ radialGradient.setAttribute("cx", "50%");
+ radialGradient.setAttribute("cy", "50%");
+ radialGradient.setAttribute("r", "50%");
+ radialGradient.setAttribute("fx", "50%");
+ radialGradient.setAttribute("fy", "50%");
+ // Stops.
+ const stop0 = document.createElementNS(svgNS, "stop");
+ stop0.setAttribute("offset", "0%");
+ stop0.setAttribute(
+ "style",
+ `stop-color:${this.props.color};stop-opacity:0.9`
+ );
+ const stop100 = document.createElementNS(svgNS, "stop");
+ stop100.setAttribute("offset", "100%");
+ stop100.setAttribute(
+ "style",
+ `stop-color:${this.props.color};stop-opacity:0`
+ );
+ // Circle.
+ const circle = document.createElementNS(svgNS, "circle");
+ circle.setAttribute("fill", `url(#${gradientId})`);
+ circle.setAttribute("cx", "50%");
+ circle.setAttribute("cy", "50%");
+ circle.setAttribute("r", "50%");
+
+ // Append elements.
+ radialGradient.append(stop0, stop100);
+ defs.append(radialGradient);
+ svg.append(defs, circle);
+
+ return svg;
+ }
+}
diff --git a/visual_console_client/src/items/DonutGraph.ts b/visual_console_client/src/items/DonutGraph.ts
new file mode 100644
index 0000000000..d60f268567
--- /dev/null
+++ b/visual_console_client/src/items/DonutGraph.ts
@@ -0,0 +1,78 @@
+import {
+ LinkedVisualConsoleProps,
+ UnknownObject,
+ WithModuleProps
+} from "../types";
+import {
+ linkedVCPropsDecoder,
+ modulePropsDecoder,
+ decodeBase64,
+ stringIsEmpty
+} from "../lib";
+import Item, { ItemType, ItemProps, itemBasePropsDecoder } from "../Item";
+
+export type DonutGraphProps = {
+ type: ItemType.DONUT_GRAPH;
+ html: string;
+} & ItemProps &
+ WithModuleProps &
+ LinkedVisualConsoleProps;
+
+/**
+ * Build a valid typed object from a raw object.
+ * This will allow us to ensure the type safety.
+ *
+ * @param data Raw object.
+ * @return An object representing the donut graph props.
+ * @throws Will throw a TypeError if some property
+ * is missing from the raw object or have an invalid type.
+ */
+export function donutGraphPropsDecoder(
+ data: UnknownObject
+): DonutGraphProps | never {
+ if (stringIsEmpty(data.html) && stringIsEmpty(data.encodedHtml)) {
+ throw new TypeError("missing html content.");
+ }
+
+ return {
+ ...itemBasePropsDecoder(data), // Object spread. It will merge the properties of the two objects.
+ type: ItemType.DONUT_GRAPH,
+ html: !stringIsEmpty(data.html)
+ ? data.html
+ : decodeBase64(data.encodedHtml),
+ ...modulePropsDecoder(data), // Object spread. It will merge the properties of the two objects.
+ ...linkedVCPropsDecoder(data) // Object spread. It will merge the properties of the two objects.
+ };
+}
+
+export default class DonutGraph extends Item {
+ protected createDomElement(): HTMLElement {
+ const element = document.createElement("div");
+ element.className = "donut-graph";
+ element.innerHTML = this.props.html;
+
+ // Hack to execute the JS after the HTML is added to the DOM.
+ const scripts = element.getElementsByTagName("script");
+ for (let i = 0; i < scripts.length; i++) {
+ setTimeout(() => {
+ if (scripts[i].src.length === 0) eval(scripts[i].innerHTML.trim());
+ }, 0);
+ }
+
+ return element;
+ }
+
+ protected updateDomElement(element: HTMLElement): void {
+ element.innerHTML = this.props.html;
+
+ // Hack to execute the JS after the HTML is added to the DOM.
+ const aux = document.createElement("div");
+ aux.innerHTML = this.props.html;
+ const scripts = aux.getElementsByTagName("script");
+ for (let i = 0; i < scripts.length; i++) {
+ if (scripts[i].src.length === 0) {
+ eval(scripts[i].innerHTML.trim());
+ }
+ }
+ }
+}
diff --git a/visual_console_client/src/items/EventsHistory.ts b/visual_console_client/src/items/EventsHistory.ts
new file mode 100644
index 0000000000..7e9db0ae9b
--- /dev/null
+++ b/visual_console_client/src/items/EventsHistory.ts
@@ -0,0 +1,78 @@
+import { UnknownObject, WithModuleProps } from "../types";
+import {
+ modulePropsDecoder,
+ parseIntOr,
+ decodeBase64,
+ stringIsEmpty
+} from "../lib";
+import Item, { ItemType, ItemProps, itemBasePropsDecoder } from "../Item";
+
+export type EventsHistoryProps = {
+ type: ItemType.AUTO_SLA_GRAPH;
+ maxTime: number | null;
+ html: string;
+} & ItemProps &
+ WithModuleProps;
+
+/**
+ * Build a valid typed object from a raw object.
+ * This will allow us to ensure the type safety.
+ *
+ * @param data Raw object.
+ * @return An object representing the events history props.
+ * @throws Will throw a TypeError if some property
+ * is missing from the raw object or have an invalid type.
+ */
+export function eventsHistoryPropsDecoder(
+ data: UnknownObject
+): EventsHistoryProps | never {
+ if (stringIsEmpty(data.html) && stringIsEmpty(data.encodedHtml)) {
+ throw new TypeError("missing html content.");
+ }
+
+ return {
+ ...itemBasePropsDecoder(data), // Object spread. It will merge the properties of the two objects.
+ type: ItemType.AUTO_SLA_GRAPH,
+ maxTime: parseIntOr(data.maxTime, null),
+ html: !stringIsEmpty(data.html)
+ ? data.html
+ : decodeBase64(data.encodedHtml),
+ ...modulePropsDecoder(data) // Object spread. It will merge the properties of the two objects.
+ };
+}
+
+export default class EventsHistory extends Item {
+ protected createDomElement(): HTMLElement {
+ const element = document.createElement("div");
+ element.className = "events-history";
+ element.innerHTML = this.props.html;
+
+ // Hack to execute the JS after the HTML is added to the DOM.
+ const scripts = element.getElementsByTagName("script");
+ for (let i = 0; i < scripts.length; i++) {
+ if (scripts[i].src.length === 0) {
+ setTimeout(() => {
+ try {
+ eval(scripts[i].innerHTML.trim());
+ } catch (ignored) {} // eslint-disable-line no-empty
+ }, 0);
+ }
+ }
+
+ return element;
+ }
+
+ protected updateDomElement(element: HTMLElement): void {
+ element.innerHTML = this.props.html;
+
+ // Hack to execute the JS after the HTML is added to the DOM.
+ const aux = document.createElement("div");
+ aux.innerHTML = this.props.html;
+ const scripts = aux.getElementsByTagName("script");
+ for (let i = 0; i < scripts.length; i++) {
+ if (scripts[i].src.length === 0) {
+ eval(scripts[i].innerHTML.trim());
+ }
+ }
+ }
+}
diff --git a/visual_console_client/src/items/Group.spec.ts b/visual_console_client/src/items/Group.spec.ts
new file mode 100644
index 0000000000..e00a5cf327
--- /dev/null
+++ b/visual_console_client/src/items/Group.spec.ts
@@ -0,0 +1,44 @@
+import Group, { groupPropsDecoder } from "./Group";
+
+const genericRawProps = {
+ id: 1,
+ type: 11, // Group item = 11
+ label: null,
+ isLinkEnabled: false,
+ isOnTop: false,
+ parentId: null,
+ aclGroupId: null
+};
+
+const positionRawProps = {
+ x: 100,
+ y: 50
+};
+
+const sizeRawProps = {
+ width: 100,
+ height: 100
+};
+
+const groupRawProps = {
+ imageSrc:
+ "https://brutus.artica.lan:8081/uploads/-/system/project/avatar/1/1.png",
+ groupId: 1
+};
+
+describe("Group item", () => {
+ const groupInstance = new Group(
+ groupPropsDecoder({
+ ...genericRawProps,
+ ...positionRawProps,
+ ...sizeRawProps,
+ ...groupRawProps
+ })
+ );
+
+ it("should have the group class", () => {
+ expect(
+ groupInstance.elementRef.getElementsByClassName("group").length
+ ).toBeGreaterThan(0);
+ });
+});
diff --git a/visual_console_client/src/items/Group.ts b/visual_console_client/src/items/Group.ts
new file mode 100644
index 0000000000..fa97f69a62
--- /dev/null
+++ b/visual_console_client/src/items/Group.ts
@@ -0,0 +1,80 @@
+import { LinkedVisualConsoleProps, UnknownObject } from "../types";
+import {
+ linkedVCPropsDecoder,
+ parseIntOr,
+ notEmptyStringOr,
+ stringIsEmpty,
+ decodeBase64,
+ parseBoolean
+} from "../lib";
+import Item, { ItemProps, itemBasePropsDecoder, ItemType } from "../Item";
+
+export type GroupProps = {
+ type: ItemType.GROUP_ITEM;
+ groupId: number;
+ imageSrc: string | null; // URL?
+ statusImageSrc: string | null;
+ showStatistics: boolean;
+ html?: string | null;
+} & ItemProps &
+ LinkedVisualConsoleProps;
+
+function extractHtml(data: UnknownObject): string | null {
+ if (!stringIsEmpty(data.html)) return data.html;
+ if (!stringIsEmpty(data.encodedHtml)) return decodeBase64(data.encodedHtml);
+ return null;
+}
+
+/**
+ * Build a valid typed object from a raw object.
+ * This will allow us to ensure the type safety.
+ *
+ * @param data Raw object.
+ * @return An object representing the group props.
+ * @throws Will throw a TypeError if some property
+ * is missing from the raw object or have an invalid type.
+ */
+export function groupPropsDecoder(data: UnknownObject): GroupProps | never {
+ if (
+ (typeof data.imageSrc !== "string" || data.imageSrc.length === 0) &&
+ data.encodedHtml === null
+ ) {
+ throw new TypeError("invalid image src.");
+ }
+ if (parseIntOr(data.groupId, null) === null) {
+ throw new TypeError("invalid group Id.");
+ }
+
+ const showStatistics = parseBoolean(data.showStatistics);
+ const html = showStatistics ? extractHtml(data) : null;
+
+ return {
+ ...itemBasePropsDecoder(data), // Object spread. It will merge the properties of the two objects.
+ type: ItemType.GROUP_ITEM,
+ groupId: parseInt(data.groupId),
+ imageSrc: notEmptyStringOr(data.imageSrc, null),
+ statusImageSrc: notEmptyStringOr(data.statusImageSrc, null),
+ showStatistics,
+ html,
+ ...linkedVCPropsDecoder(data) // Object spread. It will merge the properties of the two objects.
+ };
+}
+
+export default class Group extends Item {
+ protected createDomElement(): HTMLElement {
+ const element = document.createElement("div");
+ element.className = "group";
+
+ if (!this.props.showStatistics && this.props.statusImageSrc !== null) {
+ // Icon with status.
+ element.style.background = `url(${this.props.statusImageSrc}) no-repeat`;
+ element.style.backgroundSize = "contain";
+ element.style.backgroundPosition = "center";
+ } else if (this.props.showStatistics && this.props.html != null) {
+ // Stats table.
+ element.innerHTML = this.props.html;
+ }
+
+ return element;
+ }
+}
diff --git a/visual_console_client/src/items/Icon.ts b/visual_console_client/src/items/Icon.ts
new file mode 100644
index 0000000000..12c1b035c7
--- /dev/null
+++ b/visual_console_client/src/items/Icon.ts
@@ -0,0 +1,43 @@
+import { LinkedVisualConsoleProps, UnknownObject } from "../types";
+import { linkedVCPropsDecoder } from "../lib";
+import Item, { ItemType, ItemProps, itemBasePropsDecoder } from "../Item";
+
+export type IconProps = {
+ type: ItemType.ICON;
+ imageSrc: string; // URL?
+} & ItemProps &
+ LinkedVisualConsoleProps;
+
+/**
+ * Build a valid typed object from a raw object.
+ * This will allow us to ensure the type safety.
+ *
+ * @param data Raw object.
+ * @return An object representing the icon props.
+ * @throws Will throw a TypeError if some property
+ * is missing from the raw object or have an invalid type.
+ */
+export function iconPropsDecoder(data: UnknownObject): IconProps | never {
+ if (typeof data.imageSrc !== "string" || data.imageSrc.length === 0) {
+ throw new TypeError("invalid image src.");
+ }
+
+ return {
+ ...itemBasePropsDecoder(data), // Object spread. It will merge the properties of the two objects.
+ type: ItemType.ICON,
+ imageSrc: data.imageSrc,
+ ...linkedVCPropsDecoder(data) // Object spread. It will merge the properties of the two objects.
+ };
+}
+
+export default class Icon extends Item {
+ protected createDomElement(): HTMLElement {
+ const element = document.createElement("div");
+ element.className = "icon";
+ element.style.background = `url(${this.props.imageSrc}) no-repeat`;
+ element.style.backgroundSize = "contain";
+ element.style.backgroundPosition = "center";
+
+ return element;
+ }
+}
diff --git a/visual_console_client/src/items/Label.ts b/visual_console_client/src/items/Label.ts
new file mode 100644
index 0000000000..c8de572c15
--- /dev/null
+++ b/visual_console_client/src/items/Label.ts
@@ -0,0 +1,47 @@
+import { LinkedVisualConsoleProps, UnknownObject } from "../types";
+import { linkedVCPropsDecoder } from "../lib";
+import Item, { ItemType, ItemProps, itemBasePropsDecoder } from "../Item";
+
+export type LabelProps = {
+ type: ItemType.LABEL;
+} & ItemProps &
+ LinkedVisualConsoleProps;
+
+/**
+ * Build a valid typed object from a raw object.
+ * This will allow us to ensure the type safety.
+ *
+ * @param data Raw object.
+ * @return An object representing the label props.
+ * @throws Will throw a TypeError if some property
+ * is missing from the raw object or have an invalid type.
+ */
+export function labelPropsDecoder(data: UnknownObject): LabelProps | never {
+ return {
+ ...itemBasePropsDecoder(data), // Object spread. It will merge the properties of the two objects.
+ type: ItemType.LABEL,
+ ...linkedVCPropsDecoder(data) // Object spread. It will merge the properties of the two objects.
+ };
+}
+
+export default class Label extends Item {
+ protected createDomElement(): HTMLElement {
+ const element = document.createElement("div");
+ element.className = "label";
+ element.innerHTML = this.getLabelWithMacrosReplaced();
+
+ return element;
+ }
+
+ /**
+ * @override Item.createLabelDomElement
+ * Create a new label for the visual console item.
+ * @return Item label.
+ */
+ public createLabelDomElement(): HTMLElement {
+ const element = document.createElement("div");
+ element.className = "visual-console-item-label";
+ // Always return an empty label.
+ return element;
+ }
+}
diff --git a/visual_console_client/src/items/Line.ts b/visual_console_client/src/items/Line.ts
new file mode 100644
index 0000000000..20532e44ea
--- /dev/null
+++ b/visual_console_client/src/items/Line.ts
@@ -0,0 +1,147 @@
+import { UnknownObject, Position, Size } from "../types";
+import { parseIntOr, notEmptyStringOr } from "../lib";
+import Item, { ItemType, ItemProps, itemBasePropsDecoder } from "../Item";
+
+interface LineProps extends ItemProps {
+ // Overrided properties.
+ readonly type: ItemType.LINE_ITEM;
+ label: null;
+ isLinkEnabled: false;
+ parentId: null;
+ aclGroupId: null;
+ // Custom properties.
+ startPosition: Position;
+ endPosition: Position;
+ lineWidth: number;
+ color: string | null;
+}
+
+/**
+ * Build a valid typed object from a raw object.
+ * This will allow us to ensure the type safety.
+ *
+ * @param data Raw object.
+ * @return An object representing the item props.
+ * @throws Will throw a TypeError if some property
+ * is missing from the raw object or have an invalid type.
+ */
+export function linePropsDecoder(data: UnknownObject): LineProps | never {
+ const props: LineProps = {
+ ...itemBasePropsDecoder({ ...data, width: 1, height: 1 }), // Object spread. It will merge the properties of the two objects.
+ type: ItemType.LINE_ITEM,
+ label: null,
+ isLinkEnabled: false,
+ parentId: null,
+ aclGroupId: null,
+ // Initialize Position & Size.
+ x: 0,
+ y: 0,
+ width: 0,
+ height: 0,
+ // Custom properties.
+ startPosition: {
+ x: parseIntOr(data.startX, 0),
+ y: parseIntOr(data.startY, 0)
+ },
+ endPosition: {
+ x: parseIntOr(data.endX, 0),
+ y: parseIntOr(data.endY, 0)
+ },
+ lineWidth: parseIntOr(data.lineWidth || data.borderWidth, 1),
+ color: notEmptyStringOr(data.borderColor || data.color, null)
+ };
+
+ /*
+ * We need to enhance the props with the extracted size and position
+ * of the box cause there are missing at the props update. A better
+ * solution would be overriding the props setter to do it there, but
+ * the language doesn't allow it while targetting ES5.
+ * TODO: We need to figure out a more consistent solution.
+ */
+
+ return {
+ ...props,
+ // Enhance the props extracting the box size and position.
+ // eslint-disable-next-line @typescript-eslint/no-use-before-define
+ ...Line.extractBoxSizeAndPosition(props)
+ };
+}
+
+export default class Line extends Item {
+ /**
+ * @override
+ */
+ public constructor(props: LineProps) {
+ /*
+ * We need to override the constructor cause we need to obtain
+ * the
+ * box size and position from the start and finish points
+ * of the line.
+ */
+ super({
+ ...props,
+ ...Line.extractBoxSizeAndPosition(props)
+ });
+ }
+
+ /**
+ * @override
+ * To create the item's DOM representation.
+ * @return Item.
+ */
+ protected createDomElement(): HTMLElement {
+ const element: HTMLDivElement = document.createElement("div");
+ element.className = "line";
+
+ const svgNS = "http://www.w3.org/2000/svg";
+ // SVG container.
+ const svg = document.createElementNS(svgNS, "svg");
+ // Set SVG size.
+ svg.setAttribute(
+ "width",
+ (this.props.width + this.props.lineWidth).toString()
+ );
+ svg.setAttribute(
+ "height",
+ (this.props.height + this.props.lineWidth).toString()
+ );
+ const line = document.createElementNS(svgNS, "line");
+ line.setAttribute(
+ "x1",
+ `${this.props.startPosition.x - this.props.x + this.props.lineWidth / 2}`
+ );
+ line.setAttribute(
+ "y1",
+ `${this.props.startPosition.y - this.props.y + this.props.lineWidth / 2}`
+ );
+ line.setAttribute(
+ "x2",
+ `${this.props.endPosition.x - this.props.x + this.props.lineWidth / 2}`
+ );
+ line.setAttribute(
+ "y2",
+ `${this.props.endPosition.y - this.props.y + this.props.lineWidth / 2}`
+ );
+ line.setAttribute("stroke", this.props.color || "black");
+ line.setAttribute("stroke-width", this.props.lineWidth.toString());
+
+ svg.append(line);
+ element.append(svg);
+
+ return element;
+ }
+
+ /**
+ * Extract the size and position of the box from
+ * the start and the finish of the line.
+ * @param props Item properties.
+ */
+ public static extractBoxSizeAndPosition(props: LineProps): Size & Position {
+ return {
+ width: Math.abs(props.startPosition.x - props.endPosition.x),
+ height: Math.abs(props.startPosition.y - props.endPosition.y),
+ x: Math.min(props.startPosition.x, props.endPosition.x),
+ y: Math.min(props.startPosition.y, props.endPosition.y)
+ };
+ }
+}
diff --git a/visual_console_client/src/items/ModuleGraph.ts b/visual_console_client/src/items/ModuleGraph.ts
new file mode 100644
index 0000000000..3440496d19
--- /dev/null
+++ b/visual_console_client/src/items/ModuleGraph.ts
@@ -0,0 +1,118 @@
+import {
+ LinkedVisualConsoleProps,
+ UnknownObject,
+ WithModuleProps
+} from "../types";
+import {
+ linkedVCPropsDecoder,
+ modulePropsDecoder,
+ decodeBase64,
+ stringIsEmpty
+} from "../lib";
+import Item, { ItemType, ItemProps, itemBasePropsDecoder } from "../Item";
+
+export type ModuleGraphProps = {
+ type: ItemType.MODULE_GRAPH;
+ html: string;
+} & ItemProps &
+ WithModuleProps &
+ LinkedVisualConsoleProps;
+
+/**
+ * Build a valid typed object from a raw object.
+ * This will allow us to ensure the type safety.
+ *
+ * @param data Raw object.
+ * @return An object representing the module graph props.
+ * @throws Will throw a TypeError if some property
+ * is missing from the raw object or have an invalid type.
+ */
+export function moduleGraphPropsDecoder(
+ data: UnknownObject
+): ModuleGraphProps | never {
+ if (stringIsEmpty(data.html) && stringIsEmpty(data.encodedHtml)) {
+ throw new TypeError("missing html content.");
+ }
+
+ return {
+ ...itemBasePropsDecoder(data), // Object spread. It will merge the properties of the two objects.
+ type: ItemType.MODULE_GRAPH,
+ html: !stringIsEmpty(data.html)
+ ? data.html
+ : decodeBase64(data.encodedHtml),
+ ...modulePropsDecoder(data), // Object spread. It will merge the properties of the two objects.
+ ...linkedVCPropsDecoder(data) // Object spread. It will merge the properties of the two objects.
+ };
+}
+
+export default class ModuleGraph extends Item {
+ /**
+ * @override Item.resizeElement.
+ * Resize the DOM content container.
+ * We need to override the resize function cause this item's height
+ * is larger than the configured and the graph is over the label.
+ * @param width
+ * @param height
+ */
+ protected resizeElement(width: number): void {
+ super.resizeElement(width, 0);
+ }
+
+ protected createDomElement(): HTMLElement {
+ const element = document.createElement("div");
+ element.className = "module-graph";
+ element.innerHTML = this.props.html;
+
+ // Remove the overview graph.
+ const legendP = element.getElementsByTagName("p");
+ for (let i = 0; i < legendP.length; i++) {
+ legendP[i].style.margin = "0px";
+ }
+
+ // Remove the overview graph.
+ const overviewGraphs = element.getElementsByClassName("overview_graph");
+ for (let i = 0; i < overviewGraphs.length; i++) {
+ overviewGraphs[i].remove();
+ }
+
+ // Hack to execute the JS after the HTML is added to the DOM.
+ const scripts = element.getElementsByTagName("script");
+ for (let i = 0; i < scripts.length; i++) {
+ if (scripts[i].src.length === 0) {
+ setTimeout(() => {
+ try {
+ eval(scripts[i].innerHTML.trim());
+ } catch (ignored) {} // eslint-disable-line no-empty
+ }, 0);
+ }
+ }
+
+ return element;
+ }
+
+ protected updateDomElement(element: HTMLElement): void {
+ element.innerHTML = this.props.html;
+
+ // Remove the overview graph.
+ const legendP = element.getElementsByTagName("p");
+ for (let i = 0; i < legendP.length; i++) {
+ legendP[i].style.margin = "0px";
+ }
+
+ // Remove the overview graph.
+ const overviewGraphs = element.getElementsByClassName("overview_graph");
+ for (let i = 0; i < overviewGraphs.length; i++) {
+ overviewGraphs[i].remove();
+ }
+
+ // Hack to execute the JS after the HTML is added to the DOM.
+ const aux = document.createElement("div");
+ aux.innerHTML = this.props.html;
+ const scripts = aux.getElementsByTagName("script");
+ for (let i = 0; i < scripts.length; i++) {
+ if (scripts[i].src.length === 0) {
+ eval(scripts[i].innerHTML.trim());
+ }
+ }
+ }
+}
diff --git a/visual_console_client/src/items/Percentile.ts b/visual_console_client/src/items/Percentile.ts
new file mode 100644
index 0000000000..d4dec30d59
--- /dev/null
+++ b/visual_console_client/src/items/Percentile.ts
@@ -0,0 +1,260 @@
+import { arc as arcFactory } from "d3-shape";
+
+import {
+ LinkedVisualConsoleProps,
+ UnknownObject,
+ WithModuleProps
+} from "../types";
+import {
+ linkedVCPropsDecoder,
+ modulePropsDecoder,
+ notEmptyStringOr,
+ parseIntOr,
+ parseFloatOr
+} from "../lib";
+import Item, { ItemType, ItemProps, itemBasePropsDecoder } from "../Item";
+
+export type PercentileProps = {
+ type: ItemType.PERCENTILE_BAR;
+ percentileType:
+ | "progress-bar"
+ | "bubble"
+ | "circular-progress-bar"
+ | "circular-progress-bar-alt";
+ valueType: "percent" | "value";
+ minValue: number | null;
+ maxValue: number | null;
+ color: string | null;
+ labelColor: string | null;
+ value: number | null;
+ unit: string | null;
+} & ItemProps &
+ WithModuleProps &
+ LinkedVisualConsoleProps;
+
+/**
+ * Extract a valid enum value from a raw type value.
+ * @param type Raw value.
+ */
+// eslint-disable-next-line @typescript-eslint/no-explicit-any
+function extractPercentileType(type: any): PercentileProps["percentileType"] {
+ switch (type) {
+ case "progress-bar":
+ case "bubble":
+ case "circular-progress-bar":
+ case "circular-progress-bar-alt":
+ return type;
+ default:
+ case ItemType.PERCENTILE_BAR:
+ return "progress-bar";
+ case ItemType.PERCENTILE_BUBBLE:
+ return "bubble";
+ case ItemType.CIRCULAR_PROGRESS_BAR:
+ return "circular-progress-bar";
+ case ItemType.CIRCULAR_INTERIOR_PROGRESS_BAR:
+ return "circular-progress-bar-alt";
+ }
+}
+
+/**
+ * Extract a valid enum value from a raw value type value.
+ * @param type Raw value.
+ */
+// eslint-disable-next-line @typescript-eslint/no-explicit-any
+function extractValueType(valueType: any): PercentileProps["valueType"] {
+ switch (valueType) {
+ case "percent":
+ case "value":
+ return valueType;
+ default:
+ return "percent";
+ }
+}
+
+/**
+ * Build a valid typed object from a raw object.
+ * This will allow us to ensure the type safety.
+ *
+ * @param data Raw object.
+ * @return An object representing the percentile props.
+ * @throws Will throw a TypeError if some property
+ * is missing from the raw object or have an invalid type.
+ */
+export function percentilePropsDecoder(
+ data: UnknownObject
+): PercentileProps | never {
+ return {
+ ...itemBasePropsDecoder(data), // Object spread. It will merge the properties of the two objects.
+ type: ItemType.PERCENTILE_BAR,
+ percentileType: extractPercentileType(data.percentileType || data.type),
+ valueType: extractValueType(data.valueType),
+ minValue: parseIntOr(data.minValue, null),
+ maxValue: parseIntOr(data.maxValue, null),
+ color: notEmptyStringOr(data.color, null),
+ labelColor: notEmptyStringOr(data.labelColor, null),
+ value: parseFloatOr(data.value, null),
+ unit: notEmptyStringOr(data.unit, null),
+ ...modulePropsDecoder(data), // Object spread. It will merge the properties of the two objects.
+ ...linkedVCPropsDecoder(data) // Object spread. It will merge the properties of the two objects.
+ };
+}
+
+const svgNS = "http://www.w3.org/2000/svg";
+
+export default class Percentile extends Item {
+ protected createDomElement(): HTMLElement {
+ const colors = {
+ background: "#000000",
+ progress: this.props.color || "#F0F0F0",
+ text: this.props.labelColor || "#444444"
+ };
+ // Progress.
+ const progress = this.getProgress();
+ // Main element.
+ const element = document.createElement("div");
+ // SVG container.
+ const svg = document.createElementNS(svgNS, "svg");
+
+ switch (this.props.percentileType) {
+ case "progress-bar":
+ {
+ const backgroundRect = document.createElementNS(svgNS, "rect");
+ backgroundRect.setAttribute("fill", colors.background);
+ backgroundRect.setAttribute("fill-opacity", "0.5");
+ backgroundRect.setAttribute("width", "100");
+ backgroundRect.setAttribute("height", "20");
+ backgroundRect.setAttribute("rx", "5");
+ backgroundRect.setAttribute("ry", "5");
+ const progressRect = document.createElementNS(svgNS, "rect");
+ progressRect.setAttribute("fill", colors.progress);
+ progressRect.setAttribute("fill-opacity", "1");
+ progressRect.setAttribute("width", `${progress}`);
+ progressRect.setAttribute("height", "20");
+ progressRect.setAttribute("rx", "5");
+ progressRect.setAttribute("ry", "5");
+ const text = document.createElementNS(svgNS, "text");
+ text.setAttribute("text-anchor", "middle");
+ text.setAttribute("alignment-baseline", "middle");
+ text.setAttribute("font-size", "12");
+ text.setAttribute("font-family", "arial");
+ text.setAttribute("font-weight", "bold");
+ text.setAttribute("transform", "translate(50 11)");
+ text.setAttribute("fill", colors.text);
+
+ if (this.props.valueType === "value") {
+ text.textContent = this.props.unit
+ ? `${this.props.value} ${this.props.unit}`
+ : `${this.props.value}`;
+ } else {
+ text.textContent = `${progress}%`;
+ }
+
+ // Auto resize SVG using the view box magic: https://css-tricks.com/scale-svg/
+ svg.setAttribute("viewBox", "0 0 100 20");
+ svg.append(backgroundRect, progressRect, text);
+ }
+ break;
+ case "bubble":
+ case "circular-progress-bar":
+ case "circular-progress-bar-alt":
+ {
+ // Auto resize SVG using the view box magic: https://css-tricks.com/scale-svg/
+ svg.setAttribute("viewBox", "0 0 100 100");
+
+ if (this.props.percentileType === "bubble") {
+ // Create and append the circles.
+ const backgroundCircle = document.createElementNS(svgNS, "circle");
+ backgroundCircle.setAttribute("transform", "translate(50 50)");
+ backgroundCircle.setAttribute("fill", colors.background);
+ backgroundCircle.setAttribute("fill-opacity", "0.5");
+ backgroundCircle.setAttribute("r", "50");
+ const progressCircle = document.createElementNS(svgNS, "circle");
+ progressCircle.setAttribute("transform", "translate(50 50)");
+ progressCircle.setAttribute("fill", colors.progress);
+ progressCircle.setAttribute("fill-opacity", "1");
+ progressCircle.setAttribute("r", `${progress / 2}`);
+
+ svg.append(backgroundCircle, progressCircle);
+ } else {
+ // Create and append the circles.
+ const arcProps = {
+ innerRadius:
+ this.props.percentileType === "circular-progress-bar" ? 30 : 0,
+ outerRadius: 50,
+ startAngle: 0,
+ endAngle: Math.PI * 2
+ };
+ const arc = arcFactory();
+
+ const backgroundCircle = document.createElementNS(svgNS, "path");
+ backgroundCircle.setAttribute("transform", "translate(50 50)");
+ backgroundCircle.setAttribute("fill", colors.background);
+ backgroundCircle.setAttribute("fill-opacity", "0.5");
+ backgroundCircle.setAttribute("d", `${arc(arcProps)}`);
+ const progressCircle = document.createElementNS(svgNS, "path");
+ progressCircle.setAttribute("transform", "translate(50 50)");
+ progressCircle.setAttribute("fill", colors.progress);
+ progressCircle.setAttribute("fill-opacity", "1");
+ progressCircle.setAttribute(
+ "d",
+ `${arc({
+ ...arcProps,
+ endAngle: arcProps.endAngle * (progress / 100)
+ })}`
+ );
+
+ svg.append(backgroundCircle, progressCircle);
+ }
+
+ // Create and append the text.
+ const text = document.createElementNS(svgNS, "text");
+ text.setAttribute("text-anchor", "middle");
+ text.setAttribute("alignment-baseline", "middle");
+ text.setAttribute("font-size", "16");
+ text.setAttribute("font-family", "arial");
+ text.setAttribute("font-weight", "bold");
+ text.setAttribute("fill", colors.text);
+
+ if (this.props.valueType === "value") {
+ // Show value and unit in 1 (no unit) or 2 lines.
+ if (this.props.unit && this.props.unit.length > 0) {
+ const value = document.createElementNS(svgNS, "tspan");
+ value.setAttribute("x", "0");
+ value.setAttribute("dy", "1em");
+ value.textContent = `${this.props.value}`;
+ const unit = document.createElementNS(svgNS, "tspan");
+ unit.setAttribute("x", "0");
+ unit.setAttribute("dy", "1em");
+ unit.textContent = `${this.props.unit}`;
+ text.append(value, unit);
+ text.setAttribute("transform", "translate(50 33)");
+ } else {
+ text.textContent = `${this.props.value}`;
+ text.setAttribute("transform", "translate(50 50)");
+ }
+ } else {
+ // Percentage.
+ text.textContent = `${progress}%`;
+ text.setAttribute("transform", "translate(50 50)");
+ }
+
+ svg.append(text);
+ }
+ break;
+ }
+
+ element.append(svg);
+
+ return element;
+ }
+
+ private getProgress(): number {
+ const minValue = this.props.minValue || 0;
+ const maxValue = this.props.maxValue || 100;
+ const value = this.props.value == null ? 0 : this.props.value;
+
+ if (value <= minValue) return 0;
+ else if (value >= maxValue) return 100;
+ else return Math.trunc(((value - minValue) / (maxValue - minValue)) * 100);
+ }
+}
diff --git a/visual_console_client/src/items/Service.ts b/visual_console_client/src/items/Service.ts
new file mode 100644
index 0000000000..9440503e80
--- /dev/null
+++ b/visual_console_client/src/items/Service.ts
@@ -0,0 +1,70 @@
+import { UnknownObject } from "../types";
+import {
+ stringIsEmpty,
+ notEmptyStringOr,
+ decodeBase64,
+ parseIntOr
+} from "../lib";
+import Item, { ItemType, ItemProps, itemBasePropsDecoder } from "../Item";
+
+export type ServiceProps = {
+ type: ItemType.SERVICE;
+ serviceId: number;
+ imageSrc: string | null;
+ statusImageSrc: string | null;
+ encodedTitle: string | null;
+} & ItemProps;
+
+/**
+ * Build a valid typed object from a raw object.
+ * This will allow us to ensure the type safety.
+ *
+ * @param data Raw object.
+ * @return An object representing the service props.
+ * @throws Will throw a TypeError if some property
+ * is missing from the raw object or have an invalid type.
+ */
+export function servicePropsDecoder(data: UnknownObject): ServiceProps | never {
+ if (data.imageSrc !== null) {
+ if (
+ typeof data.statusImageSrc !== "string" ||
+ data.imageSrc.statusImageSrc === 0
+ ) {
+ throw new TypeError("invalid status image src.");
+ }
+ } else {
+ if (stringIsEmpty(data.encodedTitle)) {
+ throw new TypeError("missing encode tittle content.");
+ }
+ }
+
+ if (parseIntOr(data.serviceId, null) === null) {
+ throw new TypeError("invalid service id.");
+ }
+
+ return {
+ ...itemBasePropsDecoder(data), // Object spread. It will merge the properties of the two objects.
+ type: ItemType.SERVICE,
+ serviceId: data.serviceId,
+ imageSrc: notEmptyStringOr(data.imageSrc, null),
+ statusImageSrc: notEmptyStringOr(data.statusImageSrc, null),
+ encodedTitle: notEmptyStringOr(data.encodedTitle, null)
+ };
+}
+
+export default class Service extends Item {
+ public createDomElement(): HTMLElement {
+ const element = document.createElement("div");
+ element.className = "service";
+
+ if (this.props.statusImageSrc !== null) {
+ element.style.background = `url(${this.props.statusImageSrc}) no-repeat`;
+ element.style.backgroundSize = "contain";
+ element.style.backgroundPosition = "center";
+ } else if (this.props.encodedTitle !== null) {
+ element.innerHTML = decodeBase64(this.props.encodedTitle);
+ }
+
+ return element;
+ }
+}
diff --git a/visual_console_client/src/items/SimpleValue.ts b/visual_console_client/src/items/SimpleValue.ts
new file mode 100644
index 0000000000..8464881a61
--- /dev/null
+++ b/visual_console_client/src/items/SimpleValue.ts
@@ -0,0 +1,129 @@
+import {
+ LinkedVisualConsoleProps,
+ UnknownObject,
+ WithModuleProps
+} from "../types";
+import {
+ linkedVCPropsDecoder,
+ parseIntOr,
+ modulePropsDecoder,
+ replaceMacros
+} from "../lib";
+import Item, { ItemType, ItemProps, itemBasePropsDecoder } from "../Item";
+
+export type SimpleValueProps = {
+ type: ItemType.SIMPLE_VALUE;
+ valueType: "string" | "image";
+ value: string;
+} & (
+ | {
+ processValue: "none";
+ }
+ | {
+ processValue: "avg" | "max" | "min";
+ period: number;
+ }) &
+ ItemProps &
+ WithModuleProps &
+ LinkedVisualConsoleProps;
+
+/**
+ * Extract a valid enum value from a raw value type.
+ * @param valueType Raw value.
+ */
+const parseValueType = (
+ valueType: any // eslint-disable-line @typescript-eslint/no-explicit-any
+): SimpleValueProps["valueType"] => {
+ switch (valueType) {
+ case "string":
+ case "image":
+ return valueType;
+ default:
+ return "string";
+ }
+};
+
+/**
+ * Extract a valid enum value from a raw process value.
+ * @param processValue Raw value.
+ */
+const parseProcessValue = (
+ processValue: any // eslint-disable-line @typescript-eslint/no-explicit-any
+): SimpleValueProps["processValue"] => {
+ switch (processValue) {
+ case "none":
+ case "avg":
+ case "max":
+ case "min":
+ return processValue;
+ default:
+ return "none";
+ }
+};
+
+/**
+ * Build a valid typed object from a raw object.
+ * This will allow us to ensure the type safety.
+ *
+ * @param data Raw object.
+ * @return An object representing the simple value props.
+ * @throws Will throw a TypeError if some property
+ * is missing from the raw object or have an invalid type.
+ */
+export function simpleValuePropsDecoder(
+ data: UnknownObject
+): SimpleValueProps | never {
+ if (typeof data.value !== "string" || data.value.length === 0) {
+ throw new TypeError("invalid value");
+ }
+
+ const processValue = parseProcessValue(data.processValue);
+
+ return {
+ ...itemBasePropsDecoder(data), // Object spread. It will merge the properties of the two objects.
+ type: ItemType.SIMPLE_VALUE,
+ valueType: parseValueType(data.valueType),
+ value: data.value,
+ ...(processValue === "none"
+ ? { processValue }
+ : { processValue, period: parseIntOr(data.period, 0) }), // Object spread. It will merge the properties of the two objects.
+ ...modulePropsDecoder(data), // Object spread. It will merge the properties of the two objects.
+ ...linkedVCPropsDecoder(data) // Object spread. It will merge the properties of the two objects.
+ };
+}
+
+export default class SimpleValue extends Item {
+ protected createDomElement(): HTMLElement {
+ const element = document.createElement("div");
+ element.className = "simple-value";
+
+ if (this.props.valueType === "image") {
+ const img = document.createElement("img");
+ img.src = this.props.value;
+ element.append(img);
+ } else {
+ // Add the value to the label and show it.
+ let text = this.props.value;
+ let label = this.getLabelWithMacrosReplaced();
+ if (label.length > 0) {
+ text = replaceMacros([{ macro: /\(?_VALUE_\)?/i, value: text }], label);
+ }
+
+ element.innerHTML = text;
+ }
+
+ return element;
+ }
+
+ /**
+ * @override Item.createLabelDomElement
+ * Create a new label for the visual console item.
+ * @return Item label.
+ */
+ protected createLabelDomElement(): HTMLElement {
+ const element = document.createElement("div");
+ element.className = "visual-console-item-label";
+ // Always return an empty label.
+ return element;
+ }
+}
diff --git a/visual_console_client/src/items/StaticGraph.ts b/visual_console_client/src/items/StaticGraph.ts
new file mode 100644
index 0000000000..0e713dc5f3
--- /dev/null
+++ b/visual_console_client/src/items/StaticGraph.ts
@@ -0,0 +1,89 @@
+import {
+ WithModuleProps,
+ LinkedVisualConsoleProps,
+ UnknownObject
+} from "../types";
+
+import {
+ modulePropsDecoder,
+ linkedVCPropsDecoder,
+ notEmptyStringOr
+} from "../lib";
+import Item, { ItemType, ItemProps, itemBasePropsDecoder } from "../Item";
+
+export type StaticGraphProps = {
+ type: ItemType.STATIC_GRAPH;
+ imageSrc: string; // URL?
+ showLastValueTooltip: "default" | "enabled" | "disabled";
+ statusImageSrc: string | null; // URL?
+ lastValue: string | null;
+} & ItemProps &
+ (WithModuleProps | LinkedVisualConsoleProps);
+
+/**
+ * Extract a valid enum value from a raw unknown value.
+ * @param showLastValueTooltip Raw value.
+ */
+const parseShowLastValueTooltip = (
+ showLastValueTooltip: any // eslint-disable-line @typescript-eslint/no-explicit-any
+): StaticGraphProps["showLastValueTooltip"] => {
+ switch (showLastValueTooltip) {
+ case "default":
+ case "enabled":
+ case "disabled":
+ return showLastValueTooltip;
+ default:
+ return "default";
+ }
+};
+
+/**
+ * Build a valid typed object from a raw object.
+ * This will allow us to ensure the type safety.
+ *
+ * @param data Raw object.
+ * @return An object representing the static graph props.
+ * @throws Will throw a TypeError if some property
+ * is missing from the raw object or have an invalid type.
+ */
+export function staticGraphPropsDecoder(
+ data: UnknownObject
+): StaticGraphProps | never {
+ if (typeof data.imageSrc !== "string" || data.imageSrc.length === 0) {
+ throw new TypeError("invalid image src.");
+ }
+
+ return {
+ ...itemBasePropsDecoder(data), // Object spread. It will merge the properties of the two objects.
+ type: ItemType.STATIC_GRAPH,
+ imageSrc: data.imageSrc,
+ showLastValueTooltip: parseShowLastValueTooltip(data.showLastValueTooltip),
+ statusImageSrc: notEmptyStringOr(data.statusImageSrc, null),
+ lastValue: notEmptyStringOr(data.lastValue, null),
+ ...modulePropsDecoder(data), // Object spread. It will merge the properties of the two objects.
+ ...linkedVCPropsDecoder(data) // Object spread. It will merge the properties of the two objects.
+ };
+}
+
+export default class StaticGraph extends Item {
+ protected createDomElement(): HTMLElement {
+ const imgSrc = this.props.statusImageSrc || this.props.imageSrc;
+ const element = document.createElement("div");
+ element.className = "static-graph";
+ element.style.background = `url(${imgSrc}) no-repeat`;
+ element.style.backgroundSize = "contain";
+ element.style.backgroundPosition = "center";
+
+ // Show last value in a tooltip.
+ if (
+ this.props.lastValue !== null &&
+ this.props.showLastValueTooltip !== "disabled"
+ ) {
+ element.className = "static-graph image forced_title";
+ element.setAttribute("data-use_title_for_force_title", "1");
+ element.setAttribute("data-title", this.props.lastValue);
+ }
+
+ return element;
+ }
+}
diff --git a/visual_console_client/src/lib.spec.ts b/visual_console_client/src/lib.spec.ts
new file mode 100644
index 0000000000..3330773be7
--- /dev/null
+++ b/visual_console_client/src/lib.spec.ts
@@ -0,0 +1,120 @@
+import {
+ parseIntOr,
+ stringIsEmpty,
+ notEmptyStringOr,
+ leftPad,
+ prefixedCssRules,
+ decodeBase64,
+ humanDate,
+ humanTime,
+ replaceMacros
+} from "./lib";
+
+describe("function parseIntOr", () => {
+ it("should retrieve valid int or a default value", () => {
+ expect(parseIntOr("Foo", null)).toBe(null);
+ expect(parseIntOr("1a", null)).toBe(1);
+ expect(parseIntOr("a1", null)).toBe(null);
+ expect(parseIntOr("1", null)).toBe(1);
+ expect(parseIntOr(false, null)).toBe(null);
+ expect(parseIntOr(true, null)).toBe(null);
+ expect(parseIntOr(1, null)).toBe(1);
+ });
+});
+
+describe("function stringIsEmpty", () => {
+ it("should check properly if a string is empry or not", () => {
+ expect(stringIsEmpty()).toBe(true);
+ expect(stringIsEmpty("")).toBe(true);
+ expect(stringIsEmpty("foo")).toBe(false);
+ expect(stringIsEmpty("bar")).toBe(false);
+ });
+});
+
+describe("function notEmptyStringOr", () => {
+ it("should retrieve not empty string or a default value", () => {
+ expect(notEmptyStringOr("", null)).toBe(null);
+ expect(notEmptyStringOr("Foo", null)).toBe("Foo");
+ expect(notEmptyStringOr(1, 1)).toBe(1);
+ expect(notEmptyStringOr(1, 0)).toBe(0);
+ expect(notEmptyStringOr("", 0)).toBe(0);
+ expect(notEmptyStringOr("Foo", "Bar")).toBe("Foo");
+ expect(notEmptyStringOr(0, "Bar")).toBe("Bar");
+ });
+});
+
+describe("function leftPad", () => {
+ it("should pad properly", () => {
+ expect(leftPad(1, 2, 0)).toBe("01");
+ expect(leftPad(1, 4, 0)).toBe("0001");
+ expect(leftPad(1, 4, "0")).toBe("0001");
+ expect(leftPad("1", 4, "0")).toBe("0001");
+ expect(leftPad(10, 4, 0)).toBe("0010");
+ expect(leftPad("bar", 6, "foo")).toBe("foobar");
+ expect(leftPad("bar", 11, "foo")).toBe("foofoofobar");
+ expect(leftPad("bar", 4, "foo")).toBe("fbar");
+ expect(leftPad("bar", 2, "foo")).toBe("ar");
+ expect(leftPad("bar", 3, "foo")).toBe("bar");
+ });
+});
+
+describe("function prefixedCssRules", () => {
+ it("should add the prefixes to the rules", () => {
+ const rules = prefixedCssRules("transform", "rotate(0)");
+ expect(rules).toContainEqual("transform: rotate(0);");
+ expect(rules).toContainEqual("-webkit-transform: rotate(0);");
+ expect(rules).toContainEqual("-moz-transform: rotate(0);");
+ expect(rules).toContainEqual("-ms-transform: rotate(0);");
+ expect(rules).toContainEqual("-o-transform: rotate(0);");
+ expect(rules).toHaveLength(5);
+ });
+});
+
+describe("function decodeBase64", () => {
+ it("should decode the base64 without errors", () => {
+ expect(decodeBase64("SGkgSSdtIGRlY29kZWQ=")).toEqual("Hi I'm decoded");
+ expect(decodeBase64("Rk9PQkFSQkFa")).toEqual("FOOBARBAZ");
+ expect(decodeBase64("eyJpZCI6MSwibmFtZSI6ImZvbyJ9")).toEqual(
+ '{"id":1,"name":"foo"}'
+ );
+ expect(
+ decodeBase64("PGRpdj5Cb3ggPHA+UGFyYWdyYXBoPC9wPjxociAvPjwvZGl2Pg==")
+ ).toEqual("");
+ });
+});
+
+describe("humanDate function", () => {
+ it("should return the date with padded 0's", () => {
+ const expected = "01/02/0123";
+ const date = new Date(`02/01/0123 12:00:00`);
+ const digitalDate = humanDate(date);
+ expect(digitalDate).toBe(expected);
+ });
+});
+
+describe("humanTime function", () => {
+ it("should return the time with padded 0's when hours/minutes/seconds are less than 10", () => {
+ const expected = "01:02:03";
+ const date = new Date(`01/01/1970 ${expected}`);
+ const digitalTime = humanTime(date);
+ expect(digitalTime).toBe(expected);
+ });
+});
+
+describe("replaceMacros function", () => {
+ const macros = [
+ { macro: "_foo_", value: "foo" },
+ { macro: "_bar_", value: "bar" },
+ { macro: "_baz_", value: "baz" }
+ ];
+
+ it("should not replace anything if it doesn't find any macro", () => {
+ const text = "Lorem Ipsum";
+ expect(replaceMacros(macros, text)).toBe(text);
+ });
+
+ it("should replace the macros", () => {
+ const text = "Lorem _foo_ Ipsum _baz_";
+ expect(replaceMacros(macros, text)).toBe("Lorem foo Ipsum baz");
+ });
+});
diff --git a/visual_console_client/src/lib.ts b/visual_console_client/src/lib.ts
new file mode 100644
index 0000000000..57b4f1c221
--- /dev/null
+++ b/visual_console_client/src/lib.ts
@@ -0,0 +1,335 @@
+import {
+ UnknownObject,
+ Position,
+ Size,
+ WithAgentProps,
+ WithModuleProps,
+ LinkedVisualConsoleProps,
+ LinkedVisualConsolePropsStatus
+} from "./types";
+
+/**
+ * Return a number or a default value from a raw value.
+ * @param value Raw value from which we will try to extract a valid number.
+ * @param defaultValue Default value to use if we cannot extract a valid number.
+ * @return A valid number or the default value.
+ */
+// eslint-disable-next-line @typescript-eslint/no-explicit-any
+export function parseIntOr(value: any, defaultValue: T): number | T {
+ if (typeof value === "number") return value;
+ if (typeof value === "string" && value.length > 0 && !isNaN(parseInt(value)))
+ return parseInt(value);
+ else return defaultValue;
+}
+
+/**
+ * Return a number or a default value from a raw value.
+ * @param value Raw value from which we will try to extract a valid number.
+ * @param defaultValue Default value to use if we cannot extract a valid number.
+ * @return A valid number or the default value.
+ */
+// eslint-disable-next-line @typescript-eslint/no-explicit-any
+export function parseFloatOr(value: any, defaultValue: T): number | T {
+ if (typeof value === "number") return value;
+ if (
+ typeof value === "string" &&
+ value.length > 0 &&
+ !isNaN(parseFloat(value))
+ )
+ return parseFloat(value);
+ else return defaultValue;
+}
+
+/**
+ * Check if a string exists and it's not empty.
+ * @param value Value to check.
+ * @return The check result.
+ */
+export function stringIsEmpty(value?: string | null): boolean {
+ return value == null || value.length === 0;
+}
+
+/**
+ * Return a not empty string or a default value from a raw value.
+ * @param value Raw value from which we will try to extract a non empty string.
+ * @param defaultValue Default value to use if we cannot extract a non empty string.
+ * @return A non empty string or the default value.
+ */
+// eslint-disable-next-line @typescript-eslint/no-explicit-any
+export function notEmptyStringOr(value: any, defaultValue: T): string | T {
+ return typeof value === "string" && value.length > 0 ? value : defaultValue;
+}
+
+/**
+ * Return a boolean from a raw value.
+ * @param value Raw value from which we will try to extract the boolean.
+ * @return A valid boolean value. false by default.
+ */
+// eslint-disable-next-line @typescript-eslint/no-explicit-any
+export function parseBoolean(value: any): boolean {
+ if (typeof value === "boolean") return value;
+ else if (typeof value === "number") return value > 0;
+ else if (typeof value === "string") return value === "1" || value === "true";
+ else return false;
+}
+
+/**
+ * Pad the current string with another string (multiple times, if needed)
+ * until the resulting string reaches the given length.
+ * The padding is applied from the start (left) of the current string.
+ * @param value Text that needs to be padded.
+ * @param length Length of the returned text.
+ * @param pad Text to add.
+ * @return Padded text.
+ */
+export function leftPad(
+ value: string | number,
+ length: number,
+ pad: string | number = " "
+): string {
+ if (typeof value === "number") value = `${value}`;
+ if (typeof pad === "number") pad = `${pad}`;
+
+ const diffLength = length - value.length;
+ if (diffLength === 0) return value;
+ if (diffLength < 0) return value.substr(Math.abs(diffLength));
+
+ if (diffLength === pad.length) return `${pad}${value}`;
+ if (diffLength < pad.length) return `${pad.substring(0, diffLength)}${value}`;
+
+ const repeatTimes = Math.floor(diffLength / pad.length);
+ const restLength = diffLength - pad.length * repeatTimes;
+
+ let newPad = "";
+ for (let i = 0; i < repeatTimes; i++) newPad += pad;
+
+ if (restLength === 0) return `${newPad}${value}`;
+ return `${newPad}${pad.substring(0, restLength)}${value}`;
+}
+
+/* Decoders */
+
+/**
+ * Build a valid typed object from a raw object.
+ * @param data Raw object.
+ * @return An object representing the position.
+ */
+export function positionPropsDecoder(data: UnknownObject): Position {
+ return {
+ x: parseIntOr(data.x, 0),
+ y: parseIntOr(data.y, 0)
+ };
+}
+
+/**
+ * Build a valid typed object from a raw object.
+ * @param data Raw object.
+ * @return An object representing the size.
+ * @throws Will throw a TypeError if the width and height are not valid numbers.
+ */
+export function sizePropsDecoder(data: UnknownObject): Size | never {
+ if (
+ data.width == null ||
+ isNaN(parseInt(data.width)) ||
+ data.height == null ||
+ isNaN(parseInt(data.height))
+ ) {
+ throw new TypeError("invalid size.");
+ }
+
+ return {
+ width: parseInt(data.width),
+ height: parseInt(data.height)
+ };
+}
+
+/**
+ * Build a valid typed object from a raw object.
+ * @param data Raw object.
+ * @return An object representing the agent properties.
+ */
+export function agentPropsDecoder(data: UnknownObject): WithAgentProps {
+ const agentProps: WithAgentProps = {
+ agentId: parseIntOr(data.agent, null),
+ agentName: notEmptyStringOr(data.agentName, null),
+ agentAlias: notEmptyStringOr(data.agentAlias, null),
+ agentDescription: notEmptyStringOr(data.agentDescription, null),
+ agentAddress: notEmptyStringOr(data.agentAddress, null)
+ };
+
+ return data.metaconsoleId != null
+ ? {
+ metaconsoleId: data.metaconsoleId,
+ ...agentProps // Object spread: http://es6-features.org/#SpreadOperator
+ }
+ : agentProps;
+}
+
+/**
+ * Build a valid typed object from a raw object.
+ * @param data Raw object.
+ * @return An object representing the module and agent properties.
+ */
+export function modulePropsDecoder(data: UnknownObject): WithModuleProps {
+ return {
+ moduleId: parseIntOr(data.moduleId, null),
+ moduleName: notEmptyStringOr(data.moduleName, null),
+ moduleDescription: notEmptyStringOr(data.moduleDescription, null),
+ ...agentPropsDecoder(data) // Object spread: http://es6-features.org/#SpreadOperator
+ };
+}
+
+/**
+ * Build a valid typed object from a raw object.
+ * @param data Raw object.
+ * @return An object representing the linked visual console properties.
+ * @throws Will throw a TypeError if the status calculation properties are invalid.
+ */
+export function linkedVCPropsDecoder(
+ data: UnknownObject
+): LinkedVisualConsoleProps | never {
+ // Object destructuring: http://es6-features.org/#ObjectMatchingShorthandNotation
+ const {
+ metaconsoleId,
+ linkedLayoutId: id,
+ linkedLayoutAgentId: agentId
+ } = data;
+
+ let linkedLayoutStatusProps: LinkedVisualConsolePropsStatus = {
+ linkedLayoutStatusType: "default"
+ };
+ switch (data.linkedLayoutStatusType) {
+ case "weight": {
+ const weight = parseIntOr(data.linkedLayoutStatusTypeWeight, null);
+ if (weight == null)
+ throw new TypeError("invalid status calculation properties.");
+
+ if (data.linkedLayoutStatusTypeWeight)
+ linkedLayoutStatusProps = {
+ linkedLayoutStatusType: "weight",
+ linkedLayoutStatusTypeWeight: weight
+ };
+ break;
+ }
+ case "service": {
+ const warningThreshold = parseIntOr(
+ data.linkedLayoutStatusTypeWarningThreshold,
+ null
+ );
+ const criticalThreshold = parseIntOr(
+ data.linkedLayoutStatusTypeCriticalThreshold,
+ null
+ );
+ if (warningThreshold == null || criticalThreshold == null) {
+ throw new TypeError("invalid status calculation properties.");
+ }
+
+ linkedLayoutStatusProps = {
+ linkedLayoutStatusType: "service",
+ linkedLayoutStatusTypeWarningThreshold: warningThreshold,
+ linkedLayoutStatusTypeCriticalThreshold: criticalThreshold
+ };
+ break;
+ }
+ }
+
+ const linkedLayoutBaseProps = {
+ linkedLayoutId: parseIntOr(id, null),
+ linkedLayoutAgentId: parseIntOr(agentId, null),
+ ...linkedLayoutStatusProps // Object spread: http://es6-features.org/#SpreadOperator
+ };
+
+ return metaconsoleId != null
+ ? {
+ metaconsoleId,
+ ...linkedLayoutBaseProps // Object spread: http://es6-features.org/#SpreadOperator
+ }
+ : linkedLayoutBaseProps;
+}
+
+/**
+ * To get a CSS rule with the most used prefixes.
+ * @param ruleName Name of the CSS rule.
+ * @param ruleValue Value of the CSS rule.
+ * @return An array of rules with the prefixes applied.
+ */
+export function prefixedCssRules(
+ ruleName: string,
+ ruleValue: string
+): string[] {
+ const rule = `${ruleName}: ${ruleValue};`;
+ return [
+ `-webkit-${rule}`,
+ `-moz-${rule}`,
+ `-ms-${rule}`,
+ `-o-${rule}`,
+ `${rule}`
+ ];
+}
+
+/**
+ * Decode a base64 string.
+ * @param input Data encoded using base64.
+ * @return Decoded data.
+ */
+export function decodeBase64(input: string): string {
+ return decodeURIComponent(escape(window.atob(input)));
+}
+
+/**
+ * Generate a date representation with the format 'd/m/Y'.
+ * @param initialDate Date to be used instead of a generated one.
+ * @param locale Locale to use if localization is required and available.
+ * @example 24/02/2020.
+ * @return Date representation.
+ */
+export function humanDate(date: Date, locale: string | null = null): string {
+ if (locale && Intl && Intl.DateTimeFormat) {
+ // Format using the user locale.
+ const options: Intl.DateTimeFormatOptions = {
+ day: "2-digit",
+ month: "2-digit",
+ year: "numeric"
+ };
+ return Intl.DateTimeFormat(locale, options).format(date);
+ } else {
+ // Use getDate, getDay returns the week day.
+ const day = leftPad(date.getDate(), 2, 0);
+ // The getMonth function returns the month starting by 0.
+ const month = leftPad(date.getMonth() + 1, 2, 0);
+ const year = leftPad(date.getFullYear(), 4, 0);
+
+ // Format: 'd/m/Y'.
+ return `${day}/${month}/${year}`;
+ }
+}
+
+/**
+ * Generate a time representation with the format 'hh:mm:ss'.
+ * @param initialDate Date to be used instead of a generated one.
+ * @example 01:34:09.
+ * @return Time representation.
+ */
+export function humanTime(date: Date): string {
+ const hours = leftPad(date.getHours(), 2, 0);
+ const minutes = leftPad(date.getMinutes(), 2, 0);
+ const seconds = leftPad(date.getSeconds(), 2, 0);
+
+ return `${hours}:${minutes}:${seconds}`;
+}
+
+interface Macro {
+ macro: string | RegExp;
+ value: string;
+}
+/**
+ * Replace the macros of a text.
+ * @param macros List of macros and their replacements.
+ * @param text Text in which we need to replace the macros.
+ */
+export function replaceMacros(macros: Macro[], text: string): string {
+ return macros.reduce(
+ (acc, { macro, value }) => acc.replace(macro, value),
+ text
+ );
+}
diff --git a/visual_console_client/src/main.css b/visual_console_client/src/main.css
new file mode 100644
index 0000000000..427c8895af
--- /dev/null
+++ b/visual_console_client/src/main.css
@@ -0,0 +1,16 @@
+#visual-console-container {
+ margin: 0px auto;
+ position: relative;
+ background-repeat: no-repeat;
+ background-size: 100% 100%;
+ background-position: center;
+}
+
+.visual-console-item {
+ position: absolute;
+ display: flex;
+ flex-direction: initial;
+ justify-items: center;
+ align-items: center;
+ user-select: text;
+}
diff --git a/visual_console_client/src/types.ts b/visual_console_client/src/types.ts
new file mode 100644
index 0000000000..79dee56e74
--- /dev/null
+++ b/visual_console_client/src/types.ts
@@ -0,0 +1,47 @@
+export interface UnknownObject {
+ [key: string]: any; // eslint-disable-line @typescript-eslint/no-explicit-any
+}
+
+export interface Position {
+ x: number;
+ y: number;
+}
+
+export interface Size {
+ width: number;
+ height: number;
+}
+
+export interface WithAgentProps {
+ metaconsoleId?: number | null;
+ agentId: number | null;
+ agentName: string | null;
+ agentAlias: string | null;
+ agentDescription: string | null;
+ agentAddress: string | null;
+}
+
+export interface WithModuleProps extends WithAgentProps {
+ moduleId: number | null;
+ moduleName: string | null;
+ moduleDescription: string | null;
+}
+
+export type LinkedVisualConsolePropsStatus =
+ | {
+ linkedLayoutStatusType: "default";
+ }
+ | {
+ linkedLayoutStatusType: "weight";
+ linkedLayoutStatusTypeWeight: number;
+ }
+ | {
+ linkedLayoutStatusType: "service";
+ linkedLayoutStatusTypeWarningThreshold: number;
+ linkedLayoutStatusTypeCriticalThreshold: number;
+ };
+export type LinkedVisualConsoleProps = {
+ metaconsoleId?: number | null;
+ linkedLayoutId: number | null;
+ linkedLayoutAgentId: number | null;
+} & LinkedVisualConsolePropsStatus;
diff --git a/visual_console_client/tsconfig.json b/visual_console_client/tsconfig.json
new file mode 100644
index 0000000000..5f047a33d6
--- /dev/null
+++ b/visual_console_client/tsconfig.json
@@ -0,0 +1,22 @@
+{
+ "compilerOptions": {
+ "target": "es5",
+ "module": "es6",
+ "strict": true,
+ "alwaysStrict": true,
+ "allowJs": true,
+ "esModuleInterop": true,
+ "allowSyntheticDefaultImports": true,
+ "forceConsistentCasingInFileNames": true,
+ "moduleResolution": "node",
+ "resolveJsonModule": true,
+ "sourceMap": true,
+ // "isolatedModules": true,
+ "noEmit": true,
+ "noImplicitAny": true,
+ "noImplicitReturns": true,
+ "pretty": true
+ },
+ "include": ["**/*.ts"],
+ "exclude": ["node_modules"]
+}
diff --git a/visual_console_client/webpack.config.js b/visual_console_client/webpack.config.js
new file mode 100644
index 0000000000..ffce749d99
--- /dev/null
+++ b/visual_console_client/webpack.config.js
@@ -0,0 +1,104 @@
+// eslint-disable-next-line @typescript-eslint/no-var-requires
+const path = require("path");
+// eslint-disable-next-line @typescript-eslint/no-var-requires
+const CleanWebpackPlugin = require("clean-webpack-plugin");
+// eslint-disable-next-line @typescript-eslint/no-var-requires
+const MiniCssExtractPlugin = require("mini-css-extract-plugin");
+
+const dev = process.env.NODE_ENV !== "production";
+const entry = path.join(__dirname, "src", "index.ts");
+const buildPath = path.join(
+ __dirname,
+ "..",
+ process.env.BUILD_PATH && process.env.BUILD_PATH.length > 0
+ ? process.env.BUILD_PATH
+ : "build"
+);
+
+module.exports = {
+ mode: dev ? "development" : "production",
+ entry, // Start from this file.
+ output: {
+ path: buildPath, // The files will be created here.
+ // filename: dev ? "vc.[name].min.js" : "vc.[name].[chunkhash:8].min.js"
+ filename: "vc.[name].min.js"
+ },
+ devtool: "source-map",
+ resolve: {
+ extensions: [".ts", ".js", ".json"]
+ },
+ module: {
+ rules: [
+ // Loader for the Typescript compiler.
+ {
+ test: /\.ts$/,
+ loader: "awesome-typescript-loader"
+ },
+ // This loader builds a main CSS file from all the CSS imports across the files.
+ {
+ test: /\.css$/,
+ loader: [
+ // https://github.com/webpack-contrib/mini-css-extract-plugin
+ {
+ loader: MiniCssExtractPlugin.loader,
+ options: {
+ hot: true, // if you want HMR - we try to automatically inject hot reloading but if it's not working, add it to the config
+ reloadAll: true // when desperation kicks in - this is a brute force HMR flag
+ }
+ },
+ // https://webpack.js.org/loaders/css-loader
+ {
+ loader: "css-loader",
+ options: {
+ sourceMap: true
+ }
+ },
+ // To post process CSS and add some things like prefixes to the rules. e.g.: -webkit-...
+ // https://github.com/postcss/postcss-loader
+ {
+ loader: "postcss-loader",
+ options: {
+ plugins: () => [
+ // To improve the support for old browsers.
+ require("autoprefixer")({
+ browsers: ["> 1%", "last 2 versions"]
+ })
+ ]
+ }
+ }
+ ]
+ },
+ // To allow the use of file imports. The imported files are transformed into
+ // data uris if they are small enough or it returns a path to the file.
+ // https://webpack.js.org/loaders/url-loader
+ {
+ test: /\.(png|jpg|gif|svg|eot|ttf|woff|woff2)$/,
+ loader: "url-loader",
+ options: {
+ limit: 10000,
+ // name: "[name].[hash:8].[ext]"
+ name: "[name].[ext]"
+ }
+ }
+ ]
+ },
+ plugins: [
+ // This plugin will remove all files inside Webpack's output.path directory,
+ // as well as all unused webpack assets after every successful rebuild.
+ new CleanWebpackPlugin(),
+ // Options for the plugin which extract the CSS files to build a main file.
+ new MiniCssExtractPlugin({
+ // Options similar to the same options in webpackOptions.output
+ // both options are optional
+ // filename: dev ? "vc.[name].css" : "vc.[name].[contenthash:8].css",
+ filename: "vc.[name].css",
+ // Disable to remove warnings about conflicting order between imports.
+ orderWarning: true
+ })
+ ],
+ // Static server which runs the playground on npm start.
+ devServer: {
+ open: true,
+ contentBase: "playground"
+ }
+};