rc #27

Merged
deployer3000 merged 11 commits from rc into main 2025-03-26 13:30:18 +03:00
23 changed files with 1802 additions and 1124 deletions

View File

@ -23,7 +23,10 @@
"@emotion/react": "^11.14.0",
"@emotion/styled": "^11.14.0",
"@mui/material": "^6.4.7",
"@mui/icons-material": "^6.4.8"
"@mui/icons-material": "^6.4.8",
"reactflow": "^11.11.4",
"vite-plugin-svgr": "^4.3.0",
"react-scripts": "^5.0.1"
},
"devDependencies": {
"@eslint/js": "^9.17.0",

24
public/system_monitor_icon.svg Executable file → Normal file
View File

@ -1,15 +1,11 @@
<svg
width="100" height="100"
viewBox="0 0 100 100"
xmlns="http://www.w3.org/2000/svg"
fill="none" stroke="black" stroke-width="5" stroke-linecap="round" stroke-linejoin="round">
<!-- Окружность -->
<circle cx="50" cy="50" r="45" stroke="#4CAF50" stroke-width="5" fill="none" />
<!-- График нагрузки -->
<polyline points="20,70 35,40 50,60 65,30 80,50" stroke="#4CAF50" stroke-width="5" fill="none" />
<!-- Крестик в центре, символизирующий мониторинг -->
<line x1="45" y1="45" x2="55" y2="55" stroke="#4CAF50" stroke-width="4" />
<line x1="55" y1="45" x2="45" y2="55" stroke="#4CAF50" stroke-width="4" />
<svg width="43" height="43" viewBox="0 0 43 43" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M22.4391 0.0295059V0H21.5049H21.4951H20.5609V0.0295059C9.76424 0.48193 1.02264 8.95014 0.0884977 19.6116C0.0294994 20.2312 0 20.8607 0 21.5C0 22.1295 0.0294994 22.7589 0.0884977 23.3884C1.04231 34.3646 10.2756 43 21.4951 43H22.4391V39.2331H21.4951C12.37 39.2331 4.8182 32.3484 3.87423 23.3884H6.43083H14.6513C14.4349 22.7097 14.3169 21.9819 14.3169 21.2246C14.3169 20.6738 14.3858 20.1329 14.5038 19.6215H11.4752C12.37 14.8808 16.5884 11.3008 21.5049 11.3008C24.9367 11.3008 28.1226 13.0416 29.9909 15.8545H34.2584C32.0656 10.8484 27.0016 7.53385 21.5049 7.53385C14.5038 7.53385 8.58427 12.7761 7.65996 19.6215H6.2145H3.87423C4.8182 10.6615 12.37 3.77676 21.4951 3.77676H21.5049C30.63 3.77676 38.1818 10.6615 39.1258 19.6215H28.4962C28.6142 20.1427 28.6831 20.6738 28.6831 21.2246C28.6831 21.9819 28.5651 22.7097 28.3487 23.3884H28.919H31.5248H35.34H37.3067H43V21.5C43 9.95334 33.8552 0.511436 22.4391 0.0295059Z" fill="#428AC9"/>
<path d="M22.7045 32.25C22.3112 32.2992 21.9081 32.3287 21.5049 32.3287C17.2472 32.3287 13.5205 29.6436 12.016 25.8472H8.06311C9.70523 31.7681 15.1528 36.0956 21.5049 36.0956C21.9081 36.0956 22.3112 36.0759 22.7045 36.0366V32.25Z" fill="#428AC9"/>
<path d="M25.2611 24.3817C23.383 26.457 20.1873 26.6242 18.1125 24.7457C16.0377 22.8769 15.8706 19.6706 17.7388 17.5954C19.617 15.5201 22.8127 15.3529 24.8875 17.2315C26.9623 19.1002 27.1294 22.3065 25.2611 24.3817Z" fill="url(#paint0_radial_2_3)"/>
<defs>
<radialGradient id="paint0_radial_2_3" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(19.8648 18.1752) scale(7.12571 7.12734)">
<stop stop-color="#4A96D2"/>
<stop offset="1" stop-color="#1F2466"/>
</radialGradient>
</defs>
</svg>

Before

Width:  |  Height:  |  Size: 729 B

After

Width:  |  Height:  |  Size: 1.8 KiB

View File

@ -3,7 +3,7 @@ import { ThemeProvider, CssBaseline, Switch, Box } from "@mui/material";
import Dashboard from "./Components/Layout/Dashboard";
import LoginModal from "./Components/UI/LoginModal";
import { lightTheme, darkTheme } from "./Style/theme";
import "./Style/LoginModal.css";
import Logo from './assets/images/logo.svg?react'; // Импорт как компонента
function App() {
const [isAuthenticated, setIsAuthenticated] = useState(false);
@ -23,9 +23,38 @@ function App() {
<ThemeProvider theme={theme}>
<CssBaseline />
{!isAuthenticated && showLoginModal ? (
<LoginModal onLogin={handleLogin} onClose={() => setShowLoginModal(false)} />
<>
{/* Логотип */}
<Box
component="div"
sx={{
position: "fixed",
top: 24,
left: "50%", // Сдвигаем начало логотипа в центр
transform: "translateX(-50%)", // Смещаем назад на половину ширины логотипа
zIndex: 1200,
'& svg': {
width: 400,
height: 'auto'
}
}}
>
<Logo />
</Box>
<LoginModal
onLogin={handleLogin}
onClose={() => setShowLoginModal(false)}
/>
</>
) : (
<Box sx={{ display: "flex", height: "100vh", overflow: "hidden", bgcolor: "background.default", color: "text.primary" }}>
<Box sx={{
display: "flex",
height: "100vh",
overflow: "hidden",
bgcolor: "background.default",
color: "text.primary"
}}>
<Dashboard />
<Box sx={{ position: "absolute", top: 10, right: 10 }}>
<Switch checked={isDarkMode} onChange={() => setIsDarkMode((prev) => !prev)} />

View File

@ -1,17 +1,15 @@
import React, { useState } from 'react';
import { LineChart, XAxis, YAxis, CartesianGrid, Tooltip, Legend, Line, ResponsiveContainer } from 'recharts';
import { LineChart, XAxis, YAxis, CartesianGrid, Tooltip, Line, ResponsiveContainer } from 'recharts';
const LineChartComponent = ({ chartData, metricName, colors, description, onRangeSelect, filteredData }) => {
const [selectionStart, setSelectionStart] = useState(null);
const [selectionEnd, setSelectionEnd] = useState(null);
// Создаем массив уникальных временных меток
const allTimes = Object.values(chartData)
.flat()
.map(point => point.time)
.filter((time, index, self) => self.indexOf(time) === index);
// Формируем данные для графика
const data = allTimes.map(time => {
const point = { time };
Object.keys(chartData).forEach(key => {
@ -21,10 +19,8 @@ const LineChartComponent = ({ chartData, metricName, colors, description, onRang
return point;
});
// Используем отфильтрованные данные, если они есть
const displayData = filteredData || data;
// Обработчик клика на графике
const handleClick = (e) => {
if (!e || !e.activeLabel) return;
@ -45,40 +41,57 @@ const LineChartComponent = ({ chartData, metricName, colors, description, onRang
}
};
// Кастомный Tooltip для отображения значения
// Упрощенный Tooltip без указания instance
const CustomTooltip = ({ active, payload, label }) => {
if (active && payload && payload.length) {
return (
<div className="custom-tooltip" style={{ padding: '10px' }}>
<p>{`Время: ${label}`}</p>
{payload.map((entry, index) => (
<p key={index} style={{}}>
{`Значение: ${entry.value}`}
</p>
))}
<div className="custom-tooltip" style={{
backgroundColor: '#fff',
padding: '10px',
border: '1px solid #ccc',
borderRadius: '4px'
}}>
<p style={{ fontWeight: 'bold', marginBottom: '5px' }}>{`Время: ${label}`}</p>
<p>{`Значение: ${payload[0].value}`}</p>
</div>
);
}
return null;
};
return (
<div>
<ResponsiveContainer width="100%" height={400}>
<LineChart data={displayData} onClick={handleClick}>
<CartesianGrid strokeDasharray="3 3" />
<XAxis dataKey="time" />
<YAxis />
<Tooltip content={<CustomTooltip />} />
<Legend />
<LineChart
data={displayData}
onClick={handleClick}
margin={{ top: 5, right: 30, left: 20, bottom: 5 }}
>
<CartesianGrid strokeDasharray="3 3" stroke="#f0f0f0" />
<XAxis
dataKey="time"
tick={{ fill: '#666' }}
tickMargin={10}
/>
<YAxis
tick={{ fill: '#666' }}
tickMargin={10}
/>
<Tooltip
content={<CustomTooltip />}
cursor={{ stroke: '#ccc', strokeWidth: 1 }}
/>
{/* Убрали <Legend /> чтобы скрыть имена instance */}
{Object.keys(chartData).map((key, index) => (
<Line
key={key}
type="monotone"
dataKey={key}
stroke={colors[index % colors.length]}
name={key}
strokeWidth={2}
dot={false}
activeDot={{ r: 6 }}
// Убрали name чтобы не отображалось в tooltip
/>
))}
</LineChart>

View File

@ -92,15 +92,15 @@ const PrometheusChart = ({ metricName }) => {
else if (range <= 86400) step = 120;
else step = 300;
const response = await axios.get('https://192.168.2.43:3000/metrics', {
params: { metric: metricName, start, end, step },
const response = await axios.get(`${import.meta.env.VITE_BACK_URL}/metrics`, {
params: {
metric: metricName,
start,
end,
step
}
});
/*
const response = await axios.get(`${process.env.REACT_APP_BACK_URL}/metrics`, {
params: { metric: metricName, start, end, step },
}); */
const result = response.data;
let metrics = Array.isArray(result) ? result : result.data || [];
@ -125,7 +125,7 @@ const PrometheusChart = ({ metricName }) => {
? date.toLocaleString([], { day: '2-digit', month: '2-digit', hour: '2-digit', minute: '2-digit' })
: date.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit', second: '2-digit' });
const key = `${m.instance}-${m.device || m.scrape_job}`;
const key = m.instance;
if (!updatedData[key]) updatedData[key] = {};
updatedData[key][formattedTime] = m.value;
});
@ -217,19 +217,66 @@ const PrometheusChart = ({ metricName }) => {
});
return (
<div>
<div>
<label htmlFor="time-range">Выберите временной диапазон: </label>
<select id="time-range" value={selectedRange.value} onChange={handleRangeChange}>
<div style={{
backgroundColor: '#fff',
borderRadius: '8px',
padding: '20px',
marginBottom: '20px'
}}>
{/* Заголовок графика */}
<h3 style={{ marginTop: 0, color: '#333' }}>
</h3>
{/* Группа элементов управления */}
<div style={{
display: 'flex',
flexWrap: 'wrap',
gap: '15px',
alignItems: 'center',
marginBottom: '15px'
}}>
{/* Стандартные диапазоны */}
<div style={{ flex: '1 1 200px' }}>
<label htmlFor="time-range" style={{
display: 'block',
marginBottom: '5px',
fontWeight: '500',
color: '#555'
}}>Стандартные диапазоны:</label>
<select
id="time-range"
value={selectedRange.value}
onChange={handleRangeChange}
style={{
width: '100%',
padding: '8px 12px',
borderRadius: '4px',
border: '1px solid #ddd',
color: "#333",
backgroundColor: '#f9f9f9'
}}
>
{TIME_RANGES.map(range => (
<option key={range.value} value={range.value}>{range.label}</option>
))}
</select>
</div>
<div>
<label>Или выберите другой диапазон: </label>
<div>
<label>Начальная дата: </label>
{/* Кастомный диапазон */}
<div style={{ flex: '1 1 300px' }}>
<div style={{
marginBottom: '10px',
fontWeight: '500',
color: '#555'
}}>
Или укажите свой диапазон:
</div>
<div style={{
display: 'flex',
gap: '10px',
flexWrap: 'wrap'
}}>
<div style={{ flex: '1 1 200px' }}>
<DatePicker
selected={startDate}
onChange={(date) => setStartDate(date)}
@ -237,10 +284,20 @@ const PrometheusChart = ({ metricName }) => {
timeFormat="HH:mm"
timeIntervals={15}
dateFormat="yyyy-MM-dd HH:mm"
placeholderText="Начальная дата"
customInput={
<input style={{
backgroundColor: '#f9f9f9',
color: "#555",
width: '100%',
padding: '8px 12px',
borderRadius: '4px',
border: '1px solid #ddd'
}} />
}
/>
</div>
<div>
<label>Конечная дата: </label>
<div style={{ flex: '1 1 200px' }}>
<DatePicker
selected={endDate}
onChange={(date) => setEndDate(date)}
@ -248,10 +305,55 @@ const PrometheusChart = ({ metricName }) => {
timeFormat="HH:mm"
timeIntervals={15}
dateFormat="yyyy-MM-dd HH:mm"
placeholderText="Конечная дата"
customInput={
<input style={{
backgroundColor: '#f9f9f9',
color: "#555",
width: '100%',
padding: '8px 12px',
borderRadius: '4px',
border: '1px solid #ddd'
}} />
}
/>
</div>
<button onClick={handleCustomRangeChange}>Использовать кастомный диапазон</button>
<button
onClick={handleCustomRangeChange}
style={{
padding: '8px 16px',
backgroundColor: '#4a6baf',
color: 'white',
border: 'none',
borderRadius: '4px',
cursor: 'pointer',
transition: 'background-color 0.2s',
flex: '0 0 auto',
alignSelf: 'flex-end'
}}
onMouseOver={(e) => e.target.style.backgroundColor = '#3a5a9f'}
onMouseOut={(e) => e.target.style.backgroundColor = '#4a6baf'}
>
Применить
</button>
</div>
</div>
</div>
{/* Индикатор текущего диапазона */}
<div style={{
margin: '10px 0',
padding: '8px 12px',
backgroundColor: '#f0f7ff',
borderRadius: '4px',
borderLeft: '3px solid #4a6baf'
}}>
Текущий диапазон: {useCustomRange
? `${startDate.toLocaleString()} - ${endDate.toLocaleString()}`
: selectedRange.label}
</div>
{/* График */}
<LineChartComponent
chartData={chartData}
metricName={metricName}

View File

@ -23,7 +23,7 @@ const SidebarMenu = ({ data, onOpenTab, sidebarWidth, startResizing }) => {
}}
>
<List>
<h2 style={{ padding: "16px", fontWeight: "bold" }}>Меню</h2>
<h2 style={{ padding: "16px", fontWeight: "bold", }}>Меню</h2>
<MenuItem item={data} onSelectItem={handleSelectItem} />
</List>

View File

@ -1,5 +1,5 @@
import React from "react";
import { Drawer, List, ListItem, ListItemIcon, ListItemText, Collapse } from "@mui/material";
import { ListItem, ListItemIcon, ListItemText, Collapse, List } from "@mui/material";
import { ExpandLess, ExpandMore, Folder, FolderOpen } from "@mui/icons-material";
// Функция для сбора всех потомков
@ -14,7 +14,7 @@ const getAllChildren = (node) => {
return children;
};
const MenuItem = ({ item, onSelectItem }) => {
const MenuItem = ({ item, onSelectItem, level = 0 }) => { // Добавлен параметр level для отслеживания уровня вложенности
const [isOpen, setIsOpen] = React.useState(false);
const hasChildren = Array.isArray(item.items) && item.items.length > 0;
@ -30,20 +30,67 @@ const MenuItem = ({ item, onSelectItem }) => {
return (
<>
<ListItem component="div" onClick={handleToggle}>
<ListItem
component="div"
onClick={hasChildren ? handleToggle : handleOpenTab}
sx={{
cursor: "pointer", // Курсор pointer везде
pl: 2 + level * 2, // Сдвиг в зависимости от уровня вложенности
"&:hover": {
backgroundColor: "#f5f5f5", // Подсветка при наведении на весь элемент
},
}}
>
<ListItemIcon>
<div onClick={handleOpenTab} style={{ cursor: "pointer" }}>
{hasChildren ? (isOpen ? <FolderOpen /> : <Folder />) : <Folder />}
{hasChildren ? (
<div
onClick={handleOpenTab}
style={{
cursor: "pointer",
borderRadius: "4px", // Скругление углов
padding: "4px", // Отступы для увеличения области hover
"&:hover": {
backgroundColor: "#e0e0e0", // Подсветка при наведении на иконку
// transform: 2,
},
}}
>
{isOpen ? <FolderOpen /> : <Folder />}
</div>
) : (
<div
onClick={handleOpenTab}
style={{
cursor: "pointer",
borderRadius: "4px", // Скругление углов
padding: "4px", // Отступы для увеличения области hover
"&:hover": {
backgroundColor: "#e0e0e0", // Подсветка при наведении на иконку
},
}}
>
{/* Здесь можно добавить другую иконку или оставить пустым */}
</div>
)}
</ListItemIcon>
<ListItemText primary={item.title} />
<ListItemText
primary={item.title}
sx={{ cursor: "pointer" }} // Курсор pointer для текста
/>
{hasChildren && (isOpen ? <ExpandLess /> : <ExpandMore />)}
</ListItem>
{hasChildren && (
<Collapse in={isOpen} timeout="auto" unmountOnExit>
<List component="div" disablePadding>
{item.items.map((child, index) => (
<MenuItem key={index} item={child} onSelectItem={onSelectItem} />
<MenuItem
key={index}
item={child}
onSelectItem={onSelectItem}
level={level + 1} // Увеличиваем уровень вложенности
/>
))}
</List>
</Collapse>

View File

@ -0,0 +1,101 @@
import React, { useEffect, useMemo, useRef } from 'react';
import ReactFlow, { Controls, Background } from 'reactflow';
import 'reactflow/dist/style.css';
import { debounce } from 'lodash';
import { useFlowChart } from './FlowChartComponents/useFlowChart';
import { useNodeHandlers } from './FlowChartComponents/useNodeHandlers';
import { useDataParser } from './FlowChartComponents/DataParser';
import NodeWrapper from './FlowChartComponents/NodeWrapper';
const nodeTypes = {
customNode: NodeWrapper
};
const FlowChart = ({ data }) => {
const {
nodes,
edges,
nodePositions,
setNodes,
setEdges,
onNodesChange,
onEdgesChange,
setNodePositions,
collapsedNodes,
toggleNodeCollapse
} = useFlowChart(data);
const { parseData } = useDataParser(nodePositions, collapsedNodes);
const initialized = useRef(false);
const debouncedSetNodePositions = useMemo(
() => debounce(setNodePositions, 100),
[setNodePositions]
);
const { onNodeDrag, onNodeDragStop } = useNodeHandlers(debouncedSetNodePositions);
useEffect(() => {
const { nodes: initialNodes, edges: initialEdges } = parseData(data);
setNodes(initialNodes);
setEdges(initialEdges);
// Автоматически сворачиваем узлы, которые являются родителями последнего уровня
if (!initialized.current && data) {
const findAndCollapseLastLevelParents = (items) => {
items.forEach(item => {
if (item.items && item.items.length > 0) {
// Проверяем, есть ли у детей свои дети
const hasGrandchildren = item.items.some(child =>
child.items && child.items.length > 0
);
// Если у детей нет своих детей - это родители последнего уровня
if (!hasGrandchildren) {
toggleNodeCollapse(item.id);
} else {
findAndCollapseLastLevelParents(item.items);
}
}
});
};
findAndCollapseLastLevelParents(data.items || []);
initialized.current = true;
}
}, [data, parseData, setNodes, setEdges, toggleNodeCollapse]);
const onNodeClick = (event, node) => {
if (node.data.hasChildren) {
toggleNodeCollapse(node.id);
}
};
useEffect(() => {
return () => {
debouncedSetNodePositions.cancel();
};
}, [debouncedSetNodePositions]);
return (
<div style={{ height: '85vh', width: '100%' }}>
<ReactFlow
nodes={nodes}
edges={edges}
nodeTypes={nodeTypes}
onNodesChange={onNodesChange}
onEdgesChange={onEdgesChange}
onNodeDrag={onNodeDrag}
onNodeDragStop={onNodeDragStop}
nodeDragThreshold={1}
onNodeClick={onNodeClick}
fitView
>
<Background />
<Controls />
</ReactFlow>
</div>
);
};
export default React.memo(FlowChart);

View File

@ -0,0 +1,112 @@
import { useCallback } from 'react';
import { isLeafNode } from './nodeUtils';
import { getStatusColor } from '../dataUtils';
export const useDataParser = (nodePositions, collapsedNodes) => {
const getNodeStyle = useCallback((item, isLeaf) => ({
width: isLeaf ? 60 : 70,
height: isLeaf ? 60 : 70,
borderRadius: '50%',
backgroundColor: getStatusColor(item.status),
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
color: 'black',
border: '2px solid #fff',
fontSize: isLeaf ? '0.8rem' : '1rem'
}), []);
const getCenterNodeStyle = useCallback((item) => ({
width: 80,
height: 80,
borderRadius: '50%',
backgroundColor: getStatusColor(item.status),
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
color: 'black',
border: '2px solid #fff',
fontSize: '1.2rem'
}), []);
const parseData = useCallback((data) => {
if (!data) return { nodes: [], edges: [] };
const nodes = [];
const edges = [];
const centerX = 500;
const centerY = 400;
const baseLevelRadius = 150;
const traverse = (item, parentId = null, level = 0, angleStart = 0, angleEnd = 2 * Math.PI, parentRadius = 0) => {
if (!item || collapsedNodes[parentId]) return; // Пропускаем свёрнутые узлы
const nodeId = item.id;
const items = item.items || [];
const isLeaf = isLeafNode(item);
const savedPosition = nodePositions[nodeId];
let position = savedPosition || {
x: Math.round(centerX + Math.cos((angleStart + angleEnd) / 2) * (parentRadius + baseLevelRadius)),
y: Math.round(centerY + Math.sin((angleStart + angleEnd) / 2) * (parentRadius + baseLevelRadius))
};
const node = {
id: nodeId,
type: 'customNode',
position,
data: {
...item,
label: item.title,
style: getNodeStyle(item, isLeaf), // Переносим стили в data
hasChildren: items.length > 0,
collapsed: collapsedNodes[nodeId]
}
};
nodes.push(node);
if (parentId) {
edges.push({
id: `${parentId}-${nodeId}`,
source: parentId,
target: nodeId,
style: { stroke: isLeaf ? '#aaa' : '#666', strokeWidth: isLeaf ? 1 : 2 }
});
}
if (!collapsedNodes[nodeId] && items.length > 0) {
const spreadAngle = angleEnd - angleStart;
items.forEach((child, index) => {
if (!child) return;
const itemAngleStart = angleStart + (index / items.length) * spreadAngle;
const itemAngleEnd = angleStart + ((index + 1) / items.length) * spreadAngle;
traverse(child, nodeId, level + 1, itemAngleStart, itemAngleEnd, parentRadius + baseLevelRadius);
});
}
};
const centerNode = {
id: data.id,
type: 'customNode', // Добавляем тип узла
position: nodePositions[data.id] || { x: centerX, y: centerY },
style: getCenterNodeStyle(data),
data: { label: data.title, hasChildren: data.items.length > 0, collapsed: collapsedNodes[data.id] }
};
nodes.push(centerNode);
if (!collapsedNodes[data.id] && data.items.length > 0) {
const angleStep = (2 * Math.PI) / data.items.length;
data.items.forEach((child, index) => {
if (!child) return;
traverse(child, data.id, 1, index * angleStep, (index + 1) * angleStep, 0);
});
}
return { nodes, edges };
}, [nodePositions, collapsedNodes, getNodeStyle, getCenterNodeStyle]);
return { parseData };
};

View File

@ -0,0 +1,63 @@
import React, { memo } from 'react';
import { Handle } from 'reactflow';
const NodeWrapper = memo(({ id, data, selected }) => {
return (
<div
style={{
...data.style,
position: 'relative',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
overflow: 'hidden', // Чтобы текст не выходил за границы
textOverflow: 'ellipsis', // Добавляем многоточие если текст не помещается
whiteSpace: 'nowrap', // Запрещаем перенос строк
padding: '0 8px', // Горизонтальный padding для текста
boxSizing: 'border-box' // Учитываем padding в общей ширине
}}
title={data.label} // Простой tooltip при наведении
>
{/* Хендл для входящих соединений */}
<Handle
type="target"
position="top"
style={{ visibility: 'hidden' }}
/>
{/* Обёртка для текста с ограничением ширины */}
<div style={{
maxWidth: '100%',
overflow: 'hidden',
textOverflow: 'ellipsis'
}}>
{data.label}
</div>
{data.hasChildren && (
<span style={{
position: 'absolute',
top: 5,
right: 5,
fontSize: '12px',
cursor: 'pointer',
background: '#fff',
padding: '2px 5px',
borderRadius: '3px',
border: '1px solid #aaa'
}}>
{data.collapsed ? '+' : '-'}
</span>
)}
{/* Хендл для исходящих соединений */}
<Handle
type="source"
position="bottom"
style={{ visibility: 'hidden' }}
/>
</div>
);
});
export default NodeWrapper;

View File

@ -0,0 +1,3 @@
export const isLeafNode = (item) => {
return !item.items || item.items.length === 0;
};

View File

@ -0,0 +1,46 @@
import { useState, useCallback, useEffect } from 'react';
import { useNodesState, useEdgesState } from 'reactflow';
import { statusManager1 } from '../dataUtils';
export const useFlowChart = (initialData) => {
const [nodes, setNodes, onNodesChange] = useNodesState([]);
const [edges, setEdges, onEdgesChange] = useEdgesState([]);
const [nodePositions, setNodePositions] = useState({});
const [collapsedNodes, setCollapsedNodes] = useState({}); // Добавили
const toggleNodeCollapse = useCallback((nodeId) => {
setCollapsedNodes((prev) => ({
...prev,
[nodeId]: !prev[nodeId]
}));
}, []);
const initializeNodePositions = useCallback((nodes) => {
const positions = {};
nodes.forEach(node => {
positions[node.id] = node.position;
});
setNodePositions(positions);
}, []);
useEffect(() => {
const updateStatuses = (data) => {
statusManager1.updateStatuses(data);
};
updateStatuses(initialData);
}, [initialData]);
return {
nodes,
edges,
nodePositions,
setNodes,
setEdges,
onNodesChange,
onEdgesChange,
setNodePositions,
collapsedNodes,
toggleNodeCollapse,
initializeNodePositions
};
};

View File

@ -0,0 +1,24 @@
import { useCallback } from 'react';
export const useNodeHandlers = (debouncedSetNodePositions) => {
const onNodeDrag = useCallback((event, node) => {
// Фиксируем позицию сразу при перемещении
node.position = {
x: Math.round(node.position.x),
y: Math.round(node.position.y)
};
}, []);
const onNodeDragStop = useCallback((event, node) => {
node.position = {
x: Math.round(node.position.x),
y: Math.round(node.position.y)
};
debouncedSetNodePositions(prev => ({
...prev,
[node.id]: node.position
}));
}, [debouncedSetNodePositions]);
return { onNodeDrag, onNodeDragStop };
};

View File

@ -1,189 +0,0 @@
import React, { useRef, useEffect, useMemo } from "react";
import * as d3 from "d3";
import "../../Style/TreeChart.css";
import { getStatusColor } from "./dataUtils";
const TreeChart = ({ data, onNodeClick }) => {
const chartRef = useRef();
const nodePositions = useRef(new Map());
const { root, nodes, links } = useMemo(() => {
if (!data || !data.items) return { root: null, nodes: [], links: [] };
const root = d3.hierarchy(data, (d) => d.items);
const maxDepth = d3.max(root.descendants(), (d) => d.depth);
// Фильтруем узлы, исключая последний уровень
const nodes = root.descendants().filter((d) => d.depth < maxDepth);
// Фильтруем связи
const links = nodes.filter((d) => d.parent).map((d) => ({
source: d.parent,
target: d,
}));
// Размещаем узлы иерархически
const center = { x: 0, y: 0 }; // Центральная точка
const baseRadius = 150; // Базовый радиус для 1-го уровня
const branchOffset = 80; // Смещение узлов вдоль ветки
const angleOffset = Math.PI / 4; // Угол смещения для дочерних ветвей
const spreadFactor = 1.5; // Коэффициент растяжения для последних узлов
nodes.forEach((node) => {
const prev = nodePositions.current.get(node.data.id);
if (prev) {
node.x = prev.x;
node.y = prev.y;
} else {
if (node.depth === 0) {
// Центральный узел
node.x = center.x;
node.y = center.y;
} else if (node.depth === 1) {
// Первый уровень - равномерно по окружности
const parent = node.parent;
const index = parent.children.indexOf(node);
const totalSiblings = parent.children.length;
const radius = baseRadius * node.depth;
const sectorAngle = (Math.PI * 2) / totalSiblings;
const angle = index * sectorAngle;
node.x = parent.x + radius * Math.cos(angle);
node.y = parent.y + radius * Math.sin(angle);
node.angle = angle; // Запоминаем угол для веток
} else {
// Второй уровень и дальше - ветка растет в направлении родителя
const parent = node.parent;
const siblings = parent.children || [];
const index = siblings.indexOf(node);
const totalSiblings = siblings.length;
const direction = parent.angle || 0;
const offsetAngle = ((index - (totalSiblings - 1) / 2) * angleOffset) / totalSiblings;
let distance = branchOffset;
if (!node.children || node.children.length === 0) {
// Если это последний узел, увеличиваем расстояние
distance *= spreadFactor + node.depth * 0.2; // Чем глубже, тем больше разброс
}
node.x = parent.x + distance * Math.cos(direction + offsetAngle);
node.y = parent.y + distance * Math.sin(direction + offsetAngle);
node.angle = direction + offsetAngle;
}
}
nodePositions.current.set(node.data.id, { x: node.x, y: node.y });
});
return { root, nodes, links };
}, [data]);
useEffect(() => {
if (!chartRef.current) return;
const svg = d3.select(chartRef.current)
.attr("width", 2000)
.attr("height", 2000)
.attr("viewBox", [-500, -500, 1500, 1500])
.attr("style", "max-width: 100%; height: auto;");
svg.append("g").attr("class", "links");
svg.append("g").attr("class", "nodes");
svg.append("g").attr("class", "labels");
// Очищаем предыдущие элементы
svg.selectAll(".links line").remove();
svg.selectAll(".nodes circle").remove();
svg.selectAll(".labels text").remove();
// Рисуем связи
const linkGroup = svg.select(".links");
const link = linkGroup
.selectAll("line")
.data(links, (d) => `${d.source.data.id}-${d.target.data.id}`)
.join("line")
.attr("stroke", "#999")
.attr("stroke-opacity", 0.6)
.attr("x1", (d) => d.source.x)
.attr("y1", (d) => d.source.y)
.attr("x2", (d) => d.target.x)
.attr("y2", (d) => d.target.y);
// Рисуем узлы
const nodeGroup = svg.select(".nodes");
const node = nodeGroup
.selectAll("circle")
.data(nodes, (d) => d.data.id)
.join("circle")
.attr("fill", (d) => getStatusColor(d.data.status))
.attr("stroke", "#fff")
.attr("r", 7)
.attr("cx", (d) => d.x)
.attr("cy", (d) => d.y)
.call(drag());
node.on("click", (event, d) => {
if (onNodeClick) {
onNodeClick(d.data.id, d.data.title);
}
});
// Рисуем текстовые метки
const labelGroup = svg.select(".labels");
const text = labelGroup
.selectAll("text")
.data(nodes, (d) => d.data.id)
.join("text")
.text((d) => (nodes.length > 50 ? "" : d.data.title)) // Скрываем текст, если узлов много
.attr("dx", 12)
.attr("dy", 4)
.style("user-select", "none") // Запрет выделения текста
.style("pointer-events", "none") // Запрет взаимодействия с текстом
.style("fill", "var(--TreeChart-text-color)") // Используем переменную для цвета текста
.attr("x", (d) => d.x + 12)
.attr("y", (d) => d.y + 4);
}, [root, links, nodes, onNodeClick]);
const drag = () => {
function dragstarted(event, d) {
d3.select(this).raise().attr("stroke", "#000");
}
function dragged(event, d) {
d.x = event.x;
d.y = event.y;
d3.select(this).attr("cx", d.x).attr("cy", d.y);
// Обновляем текстовую метку
d3.select(this.parentNode)
.select("text")
.attr("x", d.x + 12)
.attr("y", d.y + 4);
// Обновляем связи
d3.select(chartRef.current)
.selectAll(".links line")
.filter((link) => link.source === d || link.target === d)
.attr("x1", (link) => link.source.x)
.attr("y1", (link) => link.source.y)
.attr("x2", (link) => link.target.x)
.attr("y2", (link) => link.target.y);
}
function dragended(event, d) {
d3.select(this).attr("stroke", "#fff");
nodePositions.current.set(d.data.id, { x: d.x, y: d.y });
}
return d3.drag().on("start", dragstarted).on("drag", dragged).on("end", dragended);
};
return <svg ref={chartRef} />;
};
export default TreeChart;

File diff suppressed because it is too large Load Diff

View File

@ -1,6 +1,7 @@
import React, { useState } from "react";
import Modal from "./Modal";
import "../../Style/LoginModal.css";
import Logo from '../../assets/images/logo.svg?react';
import TextField from '@mui/material/TextField';
const LoginModal = ({ onLogin, onClose }) => {
@ -16,8 +17,7 @@ const LoginModal = ({ onLogin, onClose }) => {
try {
// Отправляем данные на бэкенд
console.log("Отправляем данные:", { username, password });
const response = await fetch('http://192.168.2.43:3000/auth/login', {
const response = await fetch(`${import.meta.env.VITE_BACK_URL}/auth/login`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',

View File

@ -222,9 +222,13 @@ const TreeTable = ({ data }) => {
<tr className="tree-table-row">{renderData(filteredData)}</tr>
</tbody>
</table>
<button onClick={() => setIsLogVisible(!isLogVisible)} className="toggle-log-button">
<button
onClick={() => setIsLogVisible(!isLogVisible)}
className="toggle-log-button"
style={{ marginTop: "10px" }}
>
{isLogVisible ? "Скрыть лог" : "Показать лог"}
</button>
</button>
{isLogVisible && (
<div className="status-log">
<h3>Лог статусов</h3>

View File

@ -1,6 +1,7 @@
import SystemStatusChart from "../../Charts/SystemStatusChart";
import TreeTable from "../UI/TreeTable";
import TreeChart from "../TreeChart/TreeChart";
import FlowChart from "../TreeChart/FlowChart";
const TabContent = ({ activeTab, statusHistories, treeData1, tabContent, handleOpenTab }) => {
if (activeTab === "Главная") {
@ -22,7 +23,7 @@ const TabContent = ({ activeTab, statusHistories, treeData1, tabContent, handleO
</div>
);
} else if (activeTab === "Визуализация") {
return <TreeChart data={treeData1} onNodeClick={(id, title) => handleOpenTab(id, title)} />;
return <FlowChart data={treeData1} onNodeClick={(id, title) => handleOpenTab(id, title)} />;
} else {
const tabData = tabContent[activeTab];
return tabData ? tabData.content : <p>Нет данных</p>;

View File

@ -12,7 +12,7 @@
--modal-background: #2d2d2d;
--modal--btn-background: #333333;
--modal-text: #FFFFFF;
--table-border: #444444;
--table-border: #c70a0a;
--table-header-background: #2d2d2d;
--table-cell-background: #333333;
--table-text-color: #E0E0E0;

View File

319
src/assets/images/logo.svg Normal file
View File

@ -0,0 +1,319 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 28.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Слой_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 273.81 45.36" style="enable-background:new 0 0 273.81 45.36;" xml:space="preserve">
<style type="text/css">
.st0{fill:#428AC9;}
.st1{fill:url(#SVGID_1_);}
</style>
<g>
<rect x="58.03" y="1.44" class="st0" width="1.62" height="40.83"/>
<path class="st0" d="M29.84,0.03V0h-0.95h-0.01h-0.95v0.03C16.95,0.49,8.06,9.1,7.11,19.94c-0.06,0.63-0.09,1.27-0.09,1.92
c0,0.64,0.03,1.28,0.09,1.92c0.97,11.16,10.36,19.94,21.77,19.94h0.96v-3.83h-0.96c-9.28,0-16.96-7-17.92-16.11h2.6h8.36
c-0.22-0.69-0.34-1.43-0.34-2.2c0-0.56,0.07-1.11,0.19-1.63h-3.08c0.91-4.82,5.2-8.46,10.2-8.46c3.49,0,6.73,1.77,8.63,4.63h4.34
c-2.23-5.09-7.38-8.46-12.97-8.46c-7.12,0-13.14,5.33-14.08,12.29h-1.47h-2.38c0.96-9.11,8.64-16.11,17.92-16.11h0.01
c9.28,0,16.96,7,17.92,16.11H36c0.12,0.53,0.19,1.07,0.19,1.63c0,0.77-0.12,1.51-0.34,2.2h0.58h2.65h3.88h2h5.79v-1.92
C50.75,10.12,41.45,0.52,29.84,0.03z"/>
<path class="st0" d="M30.11,32.79c-0.4,0.05-0.81,0.08-1.22,0.08c-4.33,0-8.12-2.73-9.65-6.59h-4.02
c1.67,6.02,7.21,10.42,13.67,10.42c0.41,0,0.82-0.02,1.22-0.06V32.79z"/>
<radialGradient id="SVGID_1_" cx="-5958.7173" cy="3785.8042" r="51.5778" gradientTransform="matrix(0.1405 0 0 0.1405 864.4218 -513.426)" gradientUnits="userSpaceOnUse">
<stop offset="0" style="stop-color:#4A96D2"/>
<stop offset="1" style="stop-color:#1F2466"/>
</radialGradient>
<path class="st1" d="M32.71,24.79c-1.91,2.11-5.16,2.28-7.27,0.37c-2.11-1.9-2.28-5.16-0.38-7.27c1.91-2.11,5.16-2.28,7.27-0.37
C34.44,19.42,34.61,22.68,32.71,24.79z"/>
<g>
<path d="M77.34,11.48h-1.17V3.5h-4.29v7.98h-1.17V2.41h6.62V11.48z"/>
<path d="M80.63,14.2h-1.09V4.87h1.04v0.95h0.03c0.16-0.23,0.35-0.42,0.55-0.56c0.2-0.14,0.41-0.25,0.61-0.32
c0.2-0.07,0.4-0.11,0.58-0.14c0.18-0.02,0.33-0.03,0.45-0.03c0.52,0,0.96,0.08,1.33,0.24c0.37,0.16,0.67,0.38,0.9,0.67
c0.23,0.29,0.4,0.64,0.51,1.06c0.11,0.42,0.16,0.88,0.16,1.39c0,0.48-0.06,0.93-0.17,1.35s-0.29,0.78-0.52,1.09
c-0.23,0.31-0.53,0.56-0.89,0.74c-0.36,0.18-0.78,0.27-1.26,0.27c-0.21,0-0.41-0.02-0.62-0.05c-0.21-0.03-0.41-0.09-0.6-0.17
c-0.19-0.08-0.38-0.18-0.54-0.3c-0.17-0.12-0.31-0.27-0.43-0.45h-0.03V14.2z M82.61,10.6c0.68,0,1.17-0.22,1.47-0.65
c0.3-0.44,0.45-1.06,0.45-1.86c0-0.37-0.03-0.7-0.1-1c-0.06-0.29-0.17-0.54-0.32-0.73c-0.15-0.19-0.35-0.34-0.6-0.45
s-0.56-0.16-0.93-0.16c-0.64,0-1.12,0.22-1.46,0.67s-0.5,1.04-0.5,1.76c0,0.73,0.17,1.32,0.5,1.76S81.96,10.6,82.61,10.6z"/>
<path d="M90.1,11.58c-1.04,0-1.81-0.29-2.33-0.87c-0.52-0.58-0.78-1.43-0.78-2.53c0-1.08,0.27-1.92,0.8-2.51
c0.53-0.6,1.3-0.89,2.31-0.89c1.04,0,1.81,0.29,2.33,0.87c0.52,0.58,0.78,1.42,0.78,2.54c0,0.53-0.07,1-0.21,1.42
c-0.14,0.42-0.34,0.78-0.6,1.08c-0.26,0.29-0.59,0.52-0.98,0.67C91.03,11.5,90.59,11.58,90.1,11.58z M90.1,10.6
c0.65,0,1.13-0.2,1.46-0.59c0.32-0.39,0.49-1,0.49-1.83c0-0.82-0.15-1.43-0.45-1.83c-0.3-0.4-0.8-0.6-1.5-0.6
c-0.62,0-1.1,0.2-1.44,0.6c-0.34,0.4-0.5,1.01-0.5,1.83c0,0.84,0.17,1.45,0.52,1.84C89.03,10.4,89.51,10.6,90.1,10.6z"/>
<path d="M95.98,11.48h-1.09V4.87h4.34v0.98h-3.25V11.48z"/>
<path d="M101.46,14.2h-1.09V4.87h1.04v0.95h0.03c0.16-0.23,0.35-0.42,0.55-0.56c0.2-0.14,0.41-0.25,0.61-0.32
c0.2-0.07,0.4-0.11,0.58-0.14c0.18-0.02,0.33-0.03,0.45-0.03c0.52,0,0.96,0.08,1.33,0.24c0.37,0.16,0.67,0.38,0.9,0.67
c0.23,0.29,0.4,0.64,0.51,1.06c0.11,0.42,0.16,0.88,0.16,1.39c0,0.48-0.06,0.93-0.17,1.35s-0.29,0.78-0.52,1.09
c-0.23,0.31-0.53,0.56-0.89,0.74c-0.36,0.18-0.78,0.27-1.26,0.27c-0.21,0-0.41-0.02-0.62-0.05c-0.21-0.03-0.41-0.09-0.6-0.17
c-0.19-0.08-0.38-0.18-0.54-0.3c-0.17-0.12-0.31-0.27-0.43-0.45h-0.03V14.2z M103.44,10.6c0.68,0,1.17-0.22,1.47-0.65
c0.3-0.44,0.45-1.06,0.45-1.86c0-0.37-0.03-0.7-0.1-1c-0.06-0.29-0.17-0.54-0.32-0.73c-0.15-0.19-0.35-0.34-0.6-0.45
s-0.56-0.16-0.93-0.16c-0.64,0-1.12,0.22-1.46,0.67s-0.5,1.04-0.5,1.76c0,0.73,0.17,1.32,0.5,1.76S102.79,10.6,103.44,10.6z"/>
<path d="M112.92,11.48h-0.96v-1.21h-0.03c-0.07,0.18-0.17,0.35-0.32,0.51c-0.14,0.16-0.31,0.3-0.5,0.42
c-0.19,0.12-0.4,0.21-0.63,0.28s-0.48,0.1-0.73,0.1c-0.3,0-0.58-0.05-0.83-0.14s-0.46-0.23-0.64-0.39
c-0.18-0.17-0.32-0.37-0.41-0.59c-0.1-0.22-0.15-0.47-0.15-0.73c0-0.44,0.12-0.8,0.35-1.08C108.3,8.38,108.61,8.16,109,8
c0.38-0.16,0.82-0.27,1.31-0.34s1-0.11,1.52-0.14V7.19c0-0.48-0.11-0.84-0.34-1.08s-0.63-0.36-1.2-0.36
c-0.32,0-0.66,0.04-1.02,0.12s-0.67,0.19-0.93,0.32l-0.19-0.89c0.27-0.15,0.6-0.27,1.01-0.38c0.41-0.1,0.82-0.16,1.26-0.16
c0.49,0,0.9,0.06,1.22,0.17c0.32,0.12,0.58,0.29,0.77,0.51s0.32,0.5,0.4,0.84c0.08,0.34,0.12,0.73,0.12,1.17V11.48z M111.83,8.37
c-0.37,0.02-0.73,0.04-1.08,0.08c-0.35,0.03-0.66,0.1-0.94,0.19s-0.5,0.22-0.67,0.38c-0.17,0.16-0.25,0.37-0.25,0.63
c0,0.27,0.09,0.5,0.28,0.68c0.19,0.19,0.48,0.28,0.89,0.28c0.52,0,0.94-0.16,1.28-0.48s0.5-0.79,0.5-1.41V8.37z"/>
<path d="M121.53,4.87l0.65,6.61h-1.04l-0.39-4.53V6.28h-0.03l-0.21,0.66l-1.66,4.53h-0.95l-1.66-4.53l-0.21-0.66h-0.03v0.65
l-0.39,4.55h-1.04l0.65-6.61h1.22l1.94,5.4h0.03l1.88-5.4H121.53z"/>
<path d="M130.54,4.87l0.65,6.61h-1.04l-0.39-4.53V6.28h-0.03l-0.21,0.66l-1.66,4.53h-0.95l-1.66-4.53l-0.21-0.66h-0.03v0.65
l-0.39,4.55h-1.04l0.65-6.61h1.22l1.94,5.4h0.03l1.88-5.4H130.54z"/>
<path d="M138.5,11.48h-1.09V8.54h-3.39v2.94h-1.09V4.87h1.09v2.68h3.39V4.87h1.09V11.48z"/>
<path d="M143.3,11.58c-1.04,0-1.81-0.29-2.33-0.87c-0.52-0.58-0.78-1.43-0.78-2.53c0-1.08,0.27-1.92,0.8-2.51
c0.53-0.6,1.3-0.89,2.31-0.89c1.04,0,1.81,0.29,2.33,0.87c0.52,0.58,0.78,1.42,0.78,2.54c0,0.53-0.07,1-0.21,1.42
c-0.14,0.42-0.34,0.78-0.6,1.08c-0.26,0.29-0.59,0.52-0.98,0.67C144.23,11.5,143.79,11.58,143.3,11.58z M143.3,10.6
c0.65,0,1.13-0.2,1.46-0.59c0.32-0.39,0.49-1,0.49-1.83c0-0.82-0.15-1.43-0.45-1.83c-0.3-0.4-0.8-0.6-1.5-0.6
c-0.62,0-1.1,0.2-1.44,0.6c-0.34,0.4-0.5,1.01-0.5,1.83c0,0.84,0.17,1.45,0.52,1.84C142.23,10.4,142.7,10.6,143.3,10.6z"/>
<path d="M153.17,11.08c-0.16,0.14-0.41,0.26-0.76,0.36c-0.35,0.1-0.78,0.15-1.28,0.15c-1.17,0-2.03-0.3-2.58-0.91
c-0.56-0.6-0.84-1.45-0.84-2.53c0-0.51,0.07-0.97,0.2-1.39c0.13-0.42,0.33-0.77,0.59-1.07c0.26-0.3,0.57-0.53,0.94-0.69
c0.37-0.16,0.78-0.24,1.25-0.24c0.53,0,0.98,0.09,1.35,0.26c0.37,0.17,0.67,0.41,0.9,0.71c0.23,0.3,0.4,0.65,0.5,1.06
c0.1,0.41,0.16,0.84,0.16,1.31v0.35h-4.74c0.06,0.73,0.28,1.26,0.65,1.62c0.37,0.35,0.95,0.53,1.72,0.53
c0.42,0,0.77-0.04,1.04-0.11s0.51-0.17,0.72-0.29L153.17,11.08z M152.42,7.54c0.01-0.25-0.02-0.49-0.09-0.71
c-0.07-0.22-0.17-0.41-0.31-0.57c-0.14-0.16-0.32-0.29-0.53-0.38c-0.22-0.09-0.47-0.14-0.75-0.14c-0.56,0-1,0.15-1.31,0.45
c-0.31,0.3-0.5,0.75-0.57,1.33H152.42z"/>
<path d="M160.94,11.58c-1.04,0-1.81-0.29-2.33-0.87c-0.52-0.58-0.78-1.43-0.78-2.53c0-1.08,0.27-1.92,0.8-2.51
c0.53-0.6,1.3-0.89,2.31-0.89c1.04,0,1.81,0.29,2.33,0.87c0.52,0.58,0.78,1.42,0.78,2.54c0,0.53-0.07,1-0.21,1.42
c-0.14,0.42-0.34,0.78-0.6,1.08c-0.26,0.29-0.59,0.52-0.98,0.67C161.87,11.5,161.43,11.58,160.94,11.58z M160.94,10.6
c0.65,0,1.13-0.2,1.46-0.59c0.32-0.39,0.49-1,0.49-1.83c0-0.82-0.15-1.43-0.45-1.83c-0.3-0.4-0.8-0.6-1.5-0.6
c-0.62,0-1.1,0.2-1.44,0.6c-0.34,0.4-0.5,1.01-0.5,1.83c0,0.84,0.17,1.45,0.52,1.84C159.87,10.4,160.35,10.6,160.94,10.6z"/>
<path d="M166.4,6.35c0.18-0.48,0.49-0.85,0.91-1.1c0.43-0.25,0.95-0.38,1.57-0.38c0.94,0,1.65,0.28,2.14,0.84s0.73,1.38,0.73,2.46
c0,1.07-0.26,1.91-0.79,2.51c-0.53,0.6-1.27,0.9-2.24,0.9c-0.6,0-1.1-0.09-1.52-0.29c-0.42-0.19-0.76-0.46-1.02-0.82
c-0.26-0.36-0.45-0.79-0.57-1.3c-0.12-0.5-0.17-1.08-0.17-1.72c0-1.04,0.07-1.91,0.22-2.6c0.15-0.69,0.39-1.25,0.72-1.67
c0.33-0.42,0.77-0.73,1.3-0.93s1.19-0.31,1.97-0.36c0.25-0.02,0.48-0.04,0.67-0.07s0.41-0.08,0.63-0.14v1.02
c-0.11,0.03-0.22,0.05-0.31,0.08c-0.1,0.03-0.2,0.05-0.3,0.07c-0.11,0.02-0.23,0.03-0.36,0.05s-0.29,0.03-0.47,0.05
c-0.57,0.05-1.05,0.13-1.43,0.24c-0.38,0.11-0.7,0.28-0.93,0.53c-0.24,0.24-0.42,0.57-0.54,0.98c-0.12,0.41-0.2,0.96-0.23,1.63
H166.4z M166.64,8.17c0,0.35,0.04,0.68,0.12,0.98c0.08,0.3,0.21,0.55,0.38,0.77c0.17,0.22,0.39,0.38,0.65,0.5
c0.26,0.12,0.57,0.17,0.93,0.17c0.62,0,1.09-0.22,1.39-0.65c0.31-0.43,0.46-1.02,0.46-1.78c0-0.76-0.16-1.34-0.47-1.73
c-0.32-0.39-0.81-0.59-1.48-0.59c-0.37,0-0.68,0.07-0.93,0.19c-0.25,0.13-0.45,0.3-0.61,0.51c-0.16,0.21-0.27,0.46-0.34,0.74
C166.68,7.58,166.64,7.87,166.64,8.17z"/>
<path d="M178.51,11.08c-0.16,0.14-0.41,0.26-0.76,0.36c-0.35,0.1-0.78,0.15-1.28,0.15c-1.17,0-2.03-0.3-2.58-0.91
c-0.56-0.6-0.84-1.45-0.84-2.53c0-0.51,0.07-0.97,0.2-1.39c0.13-0.42,0.33-0.77,0.59-1.07c0.26-0.3,0.57-0.53,0.94-0.69
c0.37-0.16,0.78-0.24,1.25-0.24c0.53,0,0.98,0.09,1.35,0.26c0.37,0.17,0.67,0.41,0.9,0.71c0.23,0.3,0.4,0.65,0.5,1.06
c0.1,0.41,0.16,0.84,0.16,1.31v0.35h-4.74c0.06,0.73,0.28,1.26,0.65,1.62c0.37,0.35,0.95,0.53,1.72,0.53
c0.42,0,0.77-0.04,1.04-0.11s0.51-0.17,0.72-0.29L178.51,11.08z M177.76,7.54c0.01-0.25-0.02-0.49-0.09-0.71
c-0.07-0.22-0.17-0.41-0.31-0.57c-0.14-0.16-0.32-0.29-0.53-0.38c-0.22-0.09-0.47-0.14-0.75-0.14c-0.56,0-1,0.15-1.31,0.45
c-0.31,0.3-0.5,0.75-0.57,1.33H177.76z"/>
<path d="M185.3,11.24c-0.15,0.07-0.36,0.14-0.65,0.22c-0.29,0.08-0.69,0.12-1.21,0.12c-0.56,0-1.05-0.08-1.46-0.24
c-0.41-0.16-0.75-0.39-1.02-0.69s-0.48-0.67-0.61-1.09c-0.13-0.42-0.2-0.9-0.2-1.44c0-1.06,0.29-1.89,0.86-2.47
c0.57-0.59,1.37-0.88,2.39-0.88c0.48,0,0.86,0.04,1.13,0.11c0.27,0.07,0.49,0.13,0.66,0.17l-0.21,0.93
c-0.16-0.05-0.36-0.1-0.6-0.16s-0.51-0.08-0.84-0.08c-0.69,0-1.23,0.18-1.63,0.55s-0.6,0.94-0.6,1.72c0,0.89,0.21,1.54,0.63,1.96
c0.42,0.42,1.03,0.62,1.81,0.62c0.26,0,0.51-0.03,0.75-0.08c0.24-0.05,0.43-0.11,0.59-0.18L185.3,11.24z"/>
<path d="M192.26,11.48h-1.09V5.85h-3.32v5.62h-1.09V4.87h5.49V11.48z"/>
<path d="M199.41,11.08c-0.16,0.14-0.41,0.26-0.76,0.36c-0.35,0.1-0.78,0.15-1.28,0.15c-1.17,0-2.03-0.3-2.58-0.91
c-0.56-0.6-0.84-1.45-0.84-2.53c0-0.51,0.07-0.97,0.2-1.39c0.13-0.42,0.33-0.77,0.59-1.07c0.26-0.3,0.57-0.53,0.94-0.69
c0.37-0.16,0.78-0.24,1.25-0.24c0.53,0,0.98,0.09,1.35,0.26c0.37,0.17,0.67,0.41,0.9,0.71c0.23,0.3,0.4,0.65,0.5,1.06
c0.1,0.41,0.16,0.84,0.16,1.31v0.35h-4.74c0.06,0.73,0.28,1.26,0.65,1.62c0.37,0.35,0.95,0.53,1.72,0.53
c0.42,0,0.77-0.04,1.04-0.11s0.51-0.17,0.72-0.29L199.41,11.08z M198.66,7.54c0.01-0.25-0.02-0.49-0.09-0.71
c-0.07-0.22-0.17-0.41-0.31-0.57c-0.14-0.16-0.32-0.29-0.53-0.38c-0.22-0.09-0.47-0.14-0.75-0.14c-0.56,0-1,0.15-1.31,0.45
c-0.31,0.3-0.5,0.75-0.57,1.33H198.66z"/>
<path d="M206.22,11.48h-1.09v-2.6c-0.04,0.01-0.12,0.03-0.22,0.05c-0.1,0.03-0.23,0.05-0.38,0.08s-0.31,0.06-0.5,0.08
c-0.19,0.02-0.38,0.03-0.58,0.03c-0.35,0-0.68-0.03-0.98-0.1c-0.3-0.07-0.56-0.18-0.77-0.34c-0.22-0.16-0.38-0.36-0.51-0.6
c-0.12-0.25-0.18-0.55-0.18-0.9V4.87h1.09v1.94c0,0.27,0.04,0.49,0.12,0.65c0.08,0.17,0.19,0.3,0.33,0.4
c0.14,0.1,0.31,0.17,0.52,0.21c0.2,0.04,0.43,0.06,0.67,0.06c0.33,0,0.61-0.03,0.85-0.08c0.24-0.05,0.42-0.1,0.54-0.14V4.87h1.09
V11.48z"/>
<path d="M213.37,11.08c-0.16,0.14-0.41,0.26-0.76,0.36c-0.35,0.1-0.78,0.15-1.28,0.15c-1.17,0-2.03-0.3-2.58-0.91
c-0.56-0.6-0.84-1.45-0.84-2.53c0-0.51,0.07-0.97,0.2-1.39c0.13-0.42,0.33-0.77,0.59-1.07c0.26-0.3,0.57-0.53,0.94-0.69
c0.37-0.16,0.78-0.24,1.25-0.24c0.53,0,0.98,0.09,1.35,0.26c0.37,0.17,0.67,0.41,0.9,0.71c0.23,0.3,0.4,0.65,0.5,1.06
c0.1,0.41,0.16,0.84,0.16,1.31v0.35h-4.74c0.06,0.73,0.28,1.26,0.65,1.62c0.37,0.35,0.95,0.53,1.72,0.53
c0.42,0,0.77-0.04,1.04-0.11s0.51-0.17,0.72-0.29L213.37,11.08z M212.62,7.54c0.01-0.25-0.02-0.49-0.09-0.71
c-0.07-0.22-0.17-0.41-0.31-0.57c-0.14-0.16-0.32-0.29-0.53-0.38c-0.22-0.09-0.47-0.14-0.75-0.14c-0.56,0-1,0.15-1.31,0.45
c-0.31,0.3-0.5,0.75-0.57,1.33H212.62z"/>
<path d="M220.98,11.48h-1.09V8.54h-3.39v2.94h-1.09V4.87h1.09v2.68h3.39V4.87h1.09V11.48z"/>
<path d="M223.05,11.48V4.87h1.09v4.21l-0.04,0.87h0.01l0.43-0.69l3.08-4.39h1.04v6.61h-1.09V7.16l0.04-0.76h-0.01l-0.4,0.65
l-3.11,4.43H223.05z"/>
<path d="M235.81,11.08c-0.16,0.14-0.41,0.26-0.76,0.36c-0.35,0.1-0.78,0.15-1.28,0.15c-1.17,0-2.03-0.3-2.58-0.91
c-0.56-0.6-0.84-1.45-0.84-2.53c0-0.51,0.07-0.97,0.2-1.39c0.13-0.42,0.33-0.77,0.59-1.07c0.26-0.3,0.57-0.53,0.94-0.69
c0.37-0.16,0.78-0.24,1.25-0.24c0.53,0,0.98,0.09,1.35,0.26c0.37,0.17,0.67,0.41,0.9,0.71c0.23,0.3,0.4,0.65,0.5,1.06
c0.1,0.41,0.16,0.84,0.16,1.31v0.35h-4.74c0.06,0.73,0.28,1.26,0.65,1.62c0.37,0.35,0.95,0.53,1.72,0.53
c0.42,0,0.77-0.04,1.04-0.11s0.51-0.17,0.72-0.29L235.81,11.08z M235.06,7.54c0.01-0.25-0.02-0.49-0.09-0.71
c-0.07-0.22-0.17-0.41-0.31-0.57c-0.14-0.16-0.32-0.29-0.53-0.38c-0.22-0.09-0.47-0.14-0.75-0.14c-0.56,0-1,0.15-1.31,0.45
c-0.31,0.3-0.5,0.75-0.57,1.33H235.06z"/>
<path d="M71.68,23.32h0.35l2.5-2.9h1.4l-2.81,3.1c0.1,0.05,0.19,0.11,0.27,0.19c0.07,0.07,0.15,0.16,0.24,0.27l2.63,3.06h-1.48
l-2-2.45c-0.13-0.16-0.24-0.28-0.32-0.34s-0.21-0.09-0.36-0.09h-0.42v2.88h-1.09v-6.61h1.09V23.32z"/>
<path d="M79.87,27.13c-1.04,0-1.81-0.29-2.33-0.87c-0.52-0.58-0.78-1.43-0.78-2.53c0-1.08,0.27-1.92,0.8-2.51
c0.53-0.6,1.3-0.89,2.31-0.89c1.04,0,1.81,0.29,2.33,0.87c0.52,0.58,0.78,1.42,0.78,2.54c0,0.53-0.07,1-0.21,1.42
c-0.14,0.42-0.34,0.78-0.6,1.08c-0.26,0.29-0.59,0.52-0.98,0.67C80.8,27.05,80.36,27.13,79.87,27.13z M79.87,26.14
c0.65,0,1.13-0.2,1.46-0.59c0.32-0.39,0.49-1,0.49-1.83c0-0.82-0.15-1.43-0.45-1.83c-0.3-0.4-0.8-0.6-1.5-0.6
c-0.62,0-1.1,0.2-1.44,0.6c-0.34,0.4-0.5,1.01-0.5,1.83c0,0.84,0.17,1.45,0.52,1.84C78.8,25.95,79.27,26.14,79.87,26.14z"/>
<path d="M90.23,27.02h-1.09v-2.94h-3.39v2.94h-1.09v-6.61h1.09v2.68h3.39v-2.68h1.09V27.02z"/>
<path d="M94.73,27.02h-1.09V21.4h-2.29v-0.98h5.67v0.98h-2.29V27.02z"/>
<path d="M99.22,29.74h-1.09v-9.33h1.04v0.95h0.03c0.16-0.23,0.35-0.42,0.55-0.56c0.2-0.14,0.41-0.25,0.61-0.32
c0.2-0.07,0.4-0.11,0.58-0.14c0.18-0.02,0.33-0.03,0.45-0.03c0.52,0,0.96,0.08,1.33,0.24c0.37,0.16,0.67,0.38,0.9,0.67
c0.23,0.29,0.4,0.64,0.51,1.06c0.11,0.42,0.16,0.88,0.16,1.39c0,0.48-0.06,0.93-0.17,1.35s-0.29,0.78-0.52,1.09
c-0.23,0.31-0.53,0.56-0.89,0.74c-0.36,0.18-0.78,0.27-1.26,0.27c-0.21,0-0.41-0.02-0.62-0.05c-0.21-0.03-0.41-0.09-0.6-0.17
c-0.19-0.08-0.38-0.18-0.54-0.3c-0.17-0.12-0.31-0.27-0.43-0.45h-0.03V29.74z M101.2,26.14c0.68,0,1.17-0.22,1.47-0.65
c0.3-0.44,0.45-1.06,0.45-1.86c0-0.37-0.03-0.7-0.1-1c-0.06-0.29-0.17-0.54-0.32-0.73c-0.15-0.19-0.35-0.34-0.6-0.45
s-0.56-0.16-0.93-0.16c-0.64,0-1.12,0.22-1.46,0.67s-0.5,1.04-0.5,1.76c0,0.73,0.17,1.32,0.5,1.76S100.55,26.14,101.2,26.14z"/>
<path d="M108.69,27.13c-1.04,0-1.81-0.29-2.33-0.87c-0.52-0.58-0.78-1.43-0.78-2.53c0-1.08,0.27-1.92,0.8-2.51
c0.53-0.6,1.3-0.89,2.31-0.89c1.04,0,1.81,0.29,2.33,0.87c0.52,0.58,0.78,1.42,0.78,2.54c0,0.53-0.07,1-0.21,1.42
c-0.14,0.42-0.34,0.78-0.6,1.08c-0.26,0.29-0.59,0.52-0.98,0.67C109.63,27.05,109.18,27.13,108.69,27.13z M108.69,26.14
c0.65,0,1.13-0.2,1.46-0.59c0.32-0.39,0.49-1,0.49-1.83c0-0.82-0.15-1.43-0.45-1.83c-0.3-0.4-0.8-0.6-1.5-0.6
c-0.62,0-1.1,0.2-1.44,0.6c-0.34,0.4-0.5,1.01-0.5,1.83c0,0.84,0.17,1.45,0.52,1.84C107.62,25.95,108.1,26.14,108.69,26.14z"/>
<path d="M113.32,27.13c-0.12,0-0.23-0.01-0.32-0.03c-0.09-0.02-0.17-0.04-0.23-0.06V26c0.07,0.03,0.12,0.04,0.16,0.05
s0.09,0.01,0.16,0.01c0.22,0,0.41-0.1,0.56-0.29c0.15-0.19,0.27-0.5,0.36-0.92c0.09-0.42,0.16-0.96,0.19-1.61
c0.04-0.66,0.06-1.45,0.06-2.38v-0.44h4.51v6.61h-1.09V21.4h-2.38v0.16c0,1.01-0.03,1.87-0.1,2.57c-0.07,0.7-0.18,1.28-0.34,1.72
c-0.16,0.45-0.36,0.77-0.62,0.97C113.99,27.03,113.68,27.13,113.32,27.13z"/>
<path d="M123.62,24.5c-0.22,0-0.39,0.04-0.52,0.12c-0.13,0.08-0.25,0.21-0.36,0.39l-1.1,2.02h-1.31l1.19-2.09
c0.1-0.18,0.21-0.32,0.32-0.41c0.11-0.1,0.22-0.16,0.31-0.21c-0.47-0.09-0.84-0.29-1.13-0.59c-0.29-0.3-0.43-0.71-0.43-1.25
c0-0.34,0.07-0.65,0.2-0.91c0.13-0.26,0.31-0.47,0.54-0.64s0.49-0.3,0.79-0.38c0.3-0.09,0.62-0.13,0.96-0.13h2.67v6.61h-1.09V24.5
H123.62z M124.67,23.51V21.4h-1.46c-0.48,0-0.84,0.08-1.08,0.25c-0.24,0.17-0.36,0.45-0.36,0.85c0,0.38,0.15,0.64,0.44,0.79
c0.29,0.15,0.67,0.22,1.11,0.22H124.67z"/>
<path d="M136.34,27.02h-1.09V21.4h-3.32v5.62h-1.09v-6.61h5.49V27.02z"/>
<path d="M143.11,27.02h-0.96v-1.21h-0.03c-0.07,0.18-0.17,0.35-0.32,0.51c-0.14,0.16-0.31,0.3-0.5,0.42
c-0.19,0.12-0.4,0.21-0.63,0.28s-0.48,0.1-0.73,0.1c-0.3,0-0.58-0.05-0.83-0.14s-0.46-0.23-0.64-0.39
c-0.18-0.17-0.32-0.37-0.41-0.59c-0.1-0.22-0.15-0.47-0.15-0.73c0-0.44,0.12-0.8,0.35-1.08c0.23-0.28,0.54-0.49,0.93-0.65
s0.82-0.27,1.31-0.34s1-0.11,1.52-0.14v-0.34c0-0.48-0.11-0.84-0.34-1.08s-0.63-0.36-1.2-0.36c-0.32,0-0.66,0.04-1.02,0.12
s-0.67,0.19-0.93,0.32l-0.19-0.89c0.27-0.15,0.6-0.27,1.01-0.38c0.41-0.1,0.82-0.16,1.26-0.16c0.49,0,0.9,0.06,1.22,0.17
c0.32,0.12,0.58,0.29,0.77,0.51s0.32,0.5,0.4,0.84c0.08,0.34,0.12,0.73,0.12,1.17V27.02z M142.03,23.91
c-0.37,0.02-0.73,0.04-1.08,0.08c-0.35,0.03-0.66,0.1-0.94,0.19s-0.5,0.22-0.67,0.38c-0.17,0.16-0.25,0.37-0.25,0.63
c0,0.27,0.09,0.5,0.28,0.68c0.19,0.19,0.48,0.28,0.89,0.28c0.52,0,0.94-0.16,1.28-0.48s0.5-0.79,0.5-1.41V23.91z"/>
<path d="M146.21,29.74h-1.09v-9.33h1.04v0.95h0.03c0.16-0.23,0.35-0.42,0.55-0.56c0.2-0.14,0.41-0.25,0.61-0.32
c0.2-0.07,0.4-0.11,0.58-0.14c0.18-0.02,0.33-0.03,0.45-0.03c0.52,0,0.96,0.08,1.33,0.24c0.37,0.16,0.67,0.38,0.9,0.67
c0.23,0.29,0.4,0.64,0.51,1.06c0.11,0.42,0.16,0.88,0.16,1.39c0,0.48-0.06,0.93-0.17,1.35s-0.29,0.78-0.52,1.09
c-0.23,0.31-0.53,0.56-0.89,0.74c-0.36,0.18-0.78,0.27-1.26,0.27c-0.21,0-0.41-0.02-0.62-0.05c-0.21-0.03-0.41-0.09-0.6-0.17
c-0.19-0.08-0.38-0.18-0.54-0.3c-0.17-0.12-0.31-0.27-0.43-0.45h-0.03V29.74z M148.19,26.14c0.68,0,1.17-0.22,1.47-0.65
c0.3-0.44,0.45-1.06,0.45-1.86c0-0.37-0.03-0.7-0.1-1c-0.06-0.29-0.17-0.54-0.32-0.73c-0.15-0.19-0.35-0.34-0.6-0.45
s-0.56-0.16-0.93-0.16c-0.64,0-1.12,0.22-1.46,0.67s-0.5,1.04-0.5,1.76c0,0.73,0.17,1.32,0.5,1.76S147.54,26.14,148.19,26.14z"/>
<path d="M157.66,27.02h-0.96v-1.21h-0.03c-0.07,0.18-0.17,0.35-0.32,0.51c-0.14,0.16-0.31,0.3-0.5,0.42
c-0.19,0.12-0.4,0.21-0.63,0.28s-0.48,0.1-0.73,0.1c-0.3,0-0.58-0.05-0.83-0.14s-0.46-0.23-0.64-0.39
c-0.18-0.17-0.32-0.37-0.41-0.59c-0.1-0.22-0.15-0.47-0.15-0.73c0-0.44,0.12-0.8,0.35-1.08c0.23-0.28,0.54-0.49,0.93-0.65
s0.82-0.27,1.31-0.34s1-0.11,1.52-0.14v-0.34c0-0.48-0.11-0.84-0.34-1.08s-0.63-0.36-1.2-0.36c-0.32,0-0.66,0.04-1.02,0.12
s-0.67,0.19-0.93,0.32l-0.19-0.89c0.27-0.15,0.6-0.27,1.01-0.38c0.41-0.1,0.82-0.16,1.26-0.16c0.49,0,0.9,0.06,1.22,0.17
c0.32,0.12,0.58,0.29,0.77,0.51s0.32,0.5,0.4,0.84c0.08,0.34,0.12,0.73,0.12,1.17V27.02z M156.58,23.91
c-0.37,0.02-0.73,0.04-1.08,0.08c-0.35,0.03-0.66,0.1-0.94,0.19s-0.5,0.22-0.67,0.38c-0.17,0.16-0.25,0.37-0.25,0.63
c0,0.27,0.09,0.5,0.28,0.68c0.19,0.19,0.48,0.28,0.89,0.28c0.52,0,0.94-0.16,1.28-0.48s0.5-0.79,0.5-1.41V23.91z"/>
<path d="M166.28,20.42l0.65,6.61h-1.04l-0.39-4.53v-0.66h-0.03l-0.21,0.66l-1.66,4.53h-0.95l-1.66-4.53l-0.21-0.66h-0.03v0.65
l-0.39,4.55h-1.04l0.65-6.61h1.22l1.94,5.4h0.03l1.88-5.4H166.28z"/>
<path d="M173.76,26.62c-0.16,0.14-0.41,0.26-0.76,0.36c-0.35,0.1-0.78,0.15-1.28,0.15c-1.17,0-2.03-0.3-2.58-0.91
c-0.56-0.6-0.84-1.45-0.84-2.53c0-0.51,0.07-0.97,0.2-1.39c0.13-0.42,0.33-0.77,0.59-1.07c0.26-0.3,0.57-0.53,0.94-0.69
c0.37-0.16,0.78-0.24,1.25-0.24c0.53,0,0.98,0.09,1.35,0.26c0.37,0.17,0.67,0.41,0.9,0.71c0.23,0.3,0.4,0.65,0.5,1.06
c0.1,0.41,0.16,0.84,0.16,1.31v0.35h-4.74c0.06,0.73,0.28,1.26,0.65,1.62c0.37,0.35,0.95,0.53,1.72,0.53
c0.42,0,0.77-0.04,1.04-0.11s0.51-0.17,0.72-0.29L173.76,26.62z M173,23.09c0.01-0.25-0.02-0.49-0.09-0.71
c-0.07-0.22-0.17-0.41-0.31-0.57c-0.14-0.16-0.32-0.29-0.53-0.38c-0.22-0.09-0.47-0.14-0.75-0.14c-0.56,0-1,0.15-1.31,0.45
c-0.31,0.3-0.5,0.75-0.57,1.33H173z"/>
<path d="M178.21,27.02h-1.09V21.4h-2.29v-0.98h5.67v0.98h-2.29V27.02z"/>
<path d="M182.71,29.74h-1.09v-9.33h1.04v0.95h0.03c0.16-0.23,0.35-0.42,0.55-0.56c0.2-0.14,0.41-0.25,0.61-0.32
c0.2-0.07,0.4-0.11,0.58-0.14c0.18-0.02,0.33-0.03,0.45-0.03c0.52,0,0.96,0.08,1.33,0.24c0.37,0.16,0.67,0.38,0.9,0.67
c0.23,0.29,0.4,0.64,0.51,1.06c0.11,0.42,0.16,0.88,0.16,1.39c0,0.48-0.06,0.93-0.17,1.35s-0.29,0.78-0.52,1.09
c-0.23,0.31-0.53,0.56-0.89,0.74c-0.36,0.18-0.78,0.27-1.26,0.27c-0.21,0-0.41-0.02-0.62-0.05c-0.21-0.03-0.41-0.09-0.6-0.17
c-0.19-0.08-0.38-0.18-0.54-0.3c-0.17-0.12-0.31-0.27-0.43-0.45h-0.03V29.74z M184.69,26.14c0.68,0,1.17-0.22,1.47-0.65
c0.3-0.44,0.45-1.06,0.45-1.86c0-0.37-0.03-0.7-0.1-1c-0.06-0.29-0.17-0.54-0.32-0.73c-0.15-0.19-0.35-0.34-0.6-0.45
s-0.56-0.16-0.93-0.16c-0.64,0-1.12,0.22-1.46,0.67s-0.5,1.04-0.5,1.76c0,0.73,0.17,1.32,0.5,1.76S184.03,26.14,184.69,26.14z"/>
<path d="M192.18,27.13c-1.04,0-1.81-0.29-2.33-0.87c-0.52-0.58-0.78-1.43-0.78-2.53c0-1.08,0.27-1.92,0.8-2.51
c0.53-0.6,1.3-0.89,2.31-0.89c1.04,0,1.81,0.29,2.33,0.87c0.52,0.58,0.78,1.42,0.78,2.54c0,0.53-0.07,1-0.21,1.42
c-0.14,0.42-0.34,0.78-0.6,1.08c-0.26,0.29-0.59,0.52-0.98,0.67C193.11,27.05,192.67,27.13,192.18,27.13z M192.18,26.14
c0.65,0,1.13-0.2,1.46-0.59c0.32-0.39,0.49-1,0.49-1.83c0-0.82-0.15-1.43-0.45-1.83c-0.3-0.4-0.8-0.6-1.5-0.6
c-0.62,0-1.1,0.2-1.44,0.6c-0.34,0.4-0.5,1.01-0.5,1.83c0,0.84,0.17,1.45,0.52,1.84C191.11,25.95,191.58,26.14,192.18,26.14z"/>
<path d="M196.97,27.02v-6.61h2.47c0.81,0,1.43,0.12,1.85,0.36c0.42,0.24,0.63,0.68,0.63,1.31c0,0.36-0.11,0.68-0.32,0.95
c-0.22,0.27-0.5,0.46-0.86,0.55v0.04c0.42,0.07,0.77,0.23,1.04,0.49c0.27,0.25,0.41,0.61,0.41,1.06c0,0.36-0.06,0.66-0.18,0.9
c-0.12,0.24-0.29,0.43-0.51,0.57s-0.48,0.24-0.79,0.3c-0.31,0.06-0.64,0.08-1,0.08H196.97z M198.06,23.14h1.35
c0.16,0,0.32-0.01,0.49-0.02s0.32-0.05,0.46-0.11c0.14-0.06,0.25-0.15,0.34-0.27c0.09-0.12,0.14-0.28,0.14-0.49
c0-0.18-0.03-0.33-0.09-0.44c-0.06-0.11-0.15-0.2-0.27-0.26c-0.12-0.06-0.25-0.1-0.41-0.12c-0.16-0.02-0.33-0.03-0.52-0.03h-1.48
V23.14z M198.06,26.04h1.67c0.41,0,0.73-0.07,0.96-0.2c0.23-0.13,0.35-0.39,0.35-0.76c0-0.23-0.05-0.42-0.15-0.55
c-0.1-0.13-0.23-0.24-0.38-0.31c-0.16-0.07-0.33-0.12-0.51-0.14s-0.37-0.03-0.55-0.03h-1.39V26.04z"/>
<path d="M71.11,44.64c0.22-0.19,0.46-0.43,0.69-0.73c0.24-0.3,0.41-0.62,0.52-0.95l0.05-0.18l-2.71-6.81h1.18l2.1,5.44l1.76-5.44
h1.1l-2.42,7.01c-0.08,0.24-0.18,0.48-0.3,0.73c-0.12,0.24-0.25,0.47-0.38,0.68c-0.13,0.21-0.28,0.4-0.43,0.57
c-0.15,0.17-0.3,0.3-0.43,0.41L71.11,44.64z"/>
<path d="M81.73,42.34c-0.15,0.07-0.36,0.14-0.65,0.22c-0.29,0.08-0.69,0.12-1.21,0.12c-0.56,0-1.05-0.08-1.46-0.24
c-0.41-0.16-0.75-0.39-1.02-0.69s-0.48-0.67-0.61-1.09c-0.13-0.42-0.2-0.9-0.2-1.44c0-1.06,0.29-1.89,0.86-2.47
c0.57-0.59,1.37-0.88,2.39-0.88c0.48,0,0.86,0.04,1.13,0.11c0.27,0.07,0.49,0.13,0.66,0.17l-0.21,0.93
c-0.16-0.05-0.36-0.1-0.6-0.16s-0.51-0.08-0.84-0.08c-0.69,0-1.23,0.18-1.63,0.55s-0.6,0.94-0.6,1.72c0,0.89,0.21,1.54,0.63,1.96
c0.42,0.42,1.03,0.62,1.81,0.62c0.26,0,0.51-0.03,0.75-0.08c0.24-0.05,0.43-0.11,0.59-0.18L81.73,42.34z"/>
<path d="M85.81,42.57h-1.09v-5.62h-2.29v-0.98h5.67v0.98h-2.29V42.57z"/>
<path d="M91.94,42.67c-1.04,0-1.81-0.29-2.33-0.87c-0.52-0.58-0.78-1.43-0.78-2.53c0-1.08,0.27-1.92,0.8-2.51
c0.53-0.6,1.3-0.89,2.31-0.89c1.04,0,1.81,0.29,2.33,0.87c0.52,0.58,0.78,1.42,0.78,2.54c0,0.53-0.07,1-0.21,1.42
c-0.14,0.42-0.34,0.78-0.6,1.08c-0.26,0.29-0.59,0.52-0.98,0.67C92.87,42.6,92.43,42.67,91.94,42.67z M91.94,41.69
c0.65,0,1.13-0.2,1.46-0.59c0.32-0.39,0.49-1,0.49-1.83c0-0.82-0.15-1.43-0.45-1.83c-0.3-0.4-0.8-0.6-1.5-0.6
c-0.62,0-1.1,0.2-1.44,0.6c-0.34,0.4-0.5,1.01-0.5,1.83c0,0.84,0.17,1.45,0.52,1.84C90.87,41.5,91.34,41.69,91.94,41.69z"/>
<path d="M96.73,42.57v-6.61h1.09v4.21l-0.04,0.87h0.01l0.43-0.69l3.08-4.39h1.04v6.61h-1.09v-4.31l0.04-0.76h-0.01l-0.4,0.65
l-3.11,4.43H96.73z M101.63,33.11c-0.02,0.29-0.08,0.54-0.19,0.75s-0.26,0.39-0.44,0.54c-0.18,0.14-0.4,0.25-0.64,0.32
c-0.25,0.07-0.5,0.1-0.77,0.1c-0.28,0-0.54-0.04-0.78-0.1c-0.24-0.07-0.45-0.17-0.63-0.32c-0.18-0.14-0.33-0.32-0.45-0.54
c-0.12-0.22-0.18-0.47-0.19-0.75l0.92-0.1c0.04,0.31,0.17,0.54,0.37,0.7c0.2,0.16,0.46,0.23,0.76,0.23s0.55-0.08,0.76-0.23
c0.2-0.16,0.33-0.39,0.37-0.7L101.63,33.11z"/>
<path d="M109.2,42.57h-1.09v-2.6c-0.04,0.01-0.12,0.03-0.22,0.05c-0.1,0.03-0.23,0.05-0.38,0.08s-0.31,0.06-0.5,0.08
c-0.19,0.02-0.38,0.03-0.58,0.03c-0.35,0-0.68-0.03-0.98-0.1c-0.3-0.07-0.56-0.18-0.77-0.34c-0.22-0.16-0.38-0.36-0.51-0.6
c-0.12-0.25-0.18-0.55-0.18-0.9v-2.31h1.09v1.94c0,0.27,0.04,0.49,0.12,0.65c0.08,0.17,0.19,0.3,0.33,0.4
c0.14,0.1,0.31,0.17,0.52,0.21c0.2,0.04,0.43,0.06,0.67,0.06c0.33,0,0.61-0.03,0.85-0.08c0.24-0.05,0.42-0.1,0.54-0.14v-3.04h1.09
V42.57z"/>
<path d="M111.27,42.57v-6.61h1.09v4.21l-0.04,0.87h0.01l0.43-0.69l3.08-4.39h1.04v6.61h-1.09v-4.31l0.04-0.76h-0.01l-0.4,0.65
l-3.11,4.43H111.27z"/>
<path d="M118.95,42.57v-6.61h2.47c0.81,0,1.43,0.12,1.85,0.36c0.42,0.24,0.63,0.68,0.63,1.31c0,0.36-0.11,0.68-0.32,0.95
c-0.22,0.27-0.5,0.46-0.86,0.55v0.04c0.42,0.07,0.77,0.23,1.04,0.49c0.27,0.25,0.41,0.61,0.41,1.06c0,0.36-0.06,0.66-0.18,0.9
c-0.12,0.24-0.29,0.43-0.51,0.57s-0.48,0.24-0.79,0.3c-0.31,0.06-0.64,0.08-1,0.08H118.95z M120.04,38.68h1.35
c0.16,0,0.32-0.01,0.49-0.02s0.32-0.05,0.46-0.11c0.14-0.06,0.25-0.15,0.34-0.27c0.09-0.12,0.14-0.28,0.14-0.49
c0-0.18-0.03-0.33-0.09-0.44c-0.06-0.11-0.15-0.2-0.27-0.26c-0.12-0.06-0.25-0.1-0.41-0.12c-0.16-0.02-0.33-0.03-0.52-0.03h-1.48
V38.68z M120.04,41.59h1.67c0.41,0,0.73-0.07,0.96-0.2c0.23-0.13,0.35-0.39,0.35-0.76c0-0.23-0.05-0.42-0.15-0.55
c-0.1-0.13-0.23-0.24-0.38-0.31c-0.16-0.07-0.33-0.12-0.51-0.14s-0.37-0.03-0.55-0.03h-1.39V41.59z"/>
<path d="M128.57,42.67c-1.04,0-1.81-0.29-2.33-0.87c-0.52-0.58-0.78-1.43-0.78-2.53c0-1.08,0.27-1.92,0.8-2.51
c0.53-0.6,1.3-0.89,2.31-0.89c1.04,0,1.81,0.29,2.33,0.87c0.52,0.58,0.78,1.42,0.78,2.54c0,0.53-0.07,1-0.21,1.42
c-0.14,0.42-0.34,0.78-0.6,1.08c-0.26,0.29-0.59,0.52-0.98,0.67C129.5,42.6,129.06,42.67,128.57,42.67z M128.57,41.69
c0.65,0,1.13-0.2,1.46-0.59c0.32-0.39,0.49-1,0.49-1.83c0-0.82-0.15-1.43-0.45-1.83c-0.3-0.4-0.8-0.6-1.5-0.6
c-0.62,0-1.1,0.2-1.44,0.6c-0.34,0.4-0.5,1.01-0.5,1.83c0,0.84,0.17,1.45,0.52,1.84C127.5,41.5,127.97,41.69,128.57,41.69z"/>
<path d="M134.45,42.57h-1.09v-6.61h4.34v0.98h-3.25V42.57z"/>
<path d="M141.43,42.67c-1.04,0-1.81-0.29-2.33-0.87c-0.52-0.58-0.78-1.43-0.78-2.53c0-1.08,0.27-1.92,0.8-2.51
c0.53-0.6,1.3-0.89,2.31-0.89c1.04,0,1.81,0.29,2.33,0.87c0.52,0.58,0.78,1.42,0.78,2.54c0,0.53-0.07,1-0.21,1.42
c-0.14,0.42-0.34,0.78-0.6,1.08c-0.26,0.29-0.59,0.52-0.98,0.67C142.36,42.6,141.92,42.67,141.43,42.67z M141.43,41.69
c0.65,0,1.13-0.2,1.46-0.59c0.32-0.39,0.49-1,0.49-1.83c0-0.82-0.15-1.43-0.45-1.83c-0.3-0.4-0.8-0.6-1.5-0.6
c-0.62,0-1.1,0.2-1.44,0.6c-0.34,0.4-0.5,1.01-0.5,1.83c0,0.84,0.17,1.45,0.52,1.84C140.36,41.5,140.83,41.69,141.43,41.69z"/>
<path d="M152.3,42.65c-0.09,0.02-0.17,0.03-0.25,0.03s-0.16,0-0.24,0c-0.99,0-1.73-0.29-2.22-0.86c-0.49-0.57-0.73-1.43-0.73-2.56
c0-1.08,0.25-1.92,0.75-2.51c0.5-0.59,1.24-0.89,2.22-0.89c0.08,0,0.16,0,0.24,0c0.08,0,0.16,0.01,0.24,0.03v-3.03h1.09v3.04
c0.16-0.03,0.33-0.04,0.49-0.04c1.01,0,1.76,0.28,2.23,0.83c0.48,0.55,0.72,1.39,0.72,2.53c0,0.54-0.06,1.02-0.19,1.44
c-0.13,0.43-0.31,0.79-0.56,1.09c-0.25,0.3-0.56,0.53-0.93,0.69c-0.37,0.16-0.8,0.24-1.28,0.24h-0.48v2.62h-1.09V42.65z
M152.3,36.83c-0.12-0.03-0.28-0.04-0.47-0.04c-0.28,0-0.54,0.04-0.76,0.14s-0.41,0.24-0.57,0.43c-0.16,0.2-0.27,0.46-0.36,0.77
c-0.08,0.32-0.12,0.7-0.12,1.16c0,0.85,0.16,1.48,0.47,1.87s0.8,0.58,1.44,0.58c0.06,0,0.12,0,0.17,0s0.12,0,0.19-0.01V36.83z
M153.39,41.74h0.47c0.57,0,1.01-0.2,1.33-0.6c0.32-0.4,0.48-1.05,0.48-1.97c0-0.85-0.15-1.47-0.46-1.83s-0.8-0.55-1.47-0.55
c-0.05,0-0.11,0-0.17,0.01c-0.06,0-0.12,0.01-0.18,0.02V41.74z"/>
<path d="M159.04,44.64c0.22-0.19,0.46-0.43,0.69-0.73c0.24-0.3,0.41-0.62,0.52-0.95l0.05-0.18l-2.71-6.81h1.18l2.1,5.44l1.76-5.44
h1.1l-2.42,7.01c-0.08,0.24-0.18,0.48-0.3,0.73c-0.12,0.24-0.25,0.47-0.38,0.68c-0.13,0.21-0.28,0.4-0.43,0.57
c-0.15,0.17-0.3,0.3-0.43,0.41L159.04,44.64z"/>
<path d="M170.48,42.57h-1.09v-2.94h-3.39v2.94h-1.09v-6.61h1.09v2.68h3.39v-2.68h1.09V42.57z"/>
<path d="M173.64,38.87h0.35l2.5-2.9h1.4l-2.81,3.1c0.1,0.05,0.19,0.11,0.27,0.19c0.07,0.07,0.15,0.16,0.24,0.27l2.63,3.06h-1.48
l-2-2.45c-0.13-0.16-0.24-0.28-0.32-0.34s-0.21-0.09-0.36-0.09h-0.42v2.88h-1.09v-6.61h1.09V38.87z"/>
<path d="M185.65,44.44h-1.04v-1.87h-5.31v-6.61h1.09v5.62h3.17v-5.62h1.09v5.62h1V44.44z"/>
<path d="M187.07,42.57v-6.61h1.09v4.21l-0.04,0.87h0.01l0.43-0.69l3.08-4.39h1.04v6.61h-1.09v-4.31l0.04-0.76h-0.01l-0.4,0.65
l-3.11,4.43H187.07z"/>
<path d="M197.48,42.67c-1.04,0-1.81-0.29-2.33-0.87c-0.52-0.58-0.78-1.43-0.78-2.53c0-1.08,0.27-1.92,0.8-2.51
c0.53-0.6,1.3-0.89,2.31-0.89c1.04,0,1.81,0.29,2.33,0.87c0.52,0.58,0.78,1.42,0.78,2.54c0,0.53-0.07,1-0.21,1.42
c-0.14,0.42-0.34,0.78-0.6,1.08c-0.26,0.29-0.59,0.52-0.98,0.67C198.41,42.6,197.97,42.67,197.48,42.67z M197.48,41.69
c0.65,0,1.13-0.2,1.46-0.59c0.32-0.39,0.49-1,0.49-1.83c0-0.82-0.15-1.43-0.45-1.83c-0.3-0.4-0.8-0.6-1.5-0.6
c-0.62,0-1.1,0.2-1.44,0.6c-0.34,0.4-0.5,1.01-0.5,1.83c0,0.84,0.17,1.45,0.52,1.84C196.41,41.5,196.88,41.69,197.48,41.69z"/>
<path d="M207.84,42.57h-1.09v-2.94h-3.39v2.94h-1.09v-6.61h1.09v2.68h3.39v-2.68h1.09V42.57z"/>
<path d="M209.91,42.57v-6.61H211v4.21l-0.04,0.87h0.01l0.43-0.69l3.08-4.39h1.04v6.61h-1.09v-4.31l0.04-0.76h-0.01l-0.4,0.65
l-3.11,4.43H209.91z"/>
<path d="M218.68,45.29h-1.09v-9.33h1.04v0.95h0.03c0.16-0.23,0.35-0.42,0.55-0.56c0.2-0.14,0.41-0.25,0.61-0.32
c0.2-0.07,0.4-0.11,0.58-0.14c0.18-0.02,0.33-0.03,0.45-0.03c0.52,0,0.96,0.08,1.33,0.24c0.37,0.16,0.67,0.38,0.9,0.67
c0.23,0.29,0.4,0.64,0.51,1.06c0.11,0.42,0.16,0.88,0.16,1.39c0,0.48-0.06,0.93-0.17,1.35s-0.29,0.78-0.52,1.09
c-0.23,0.31-0.53,0.56-0.89,0.74c-0.36,0.18-0.78,0.27-1.26,0.27c-0.21,0-0.41-0.02-0.62-0.05c-0.21-0.03-0.41-0.09-0.6-0.17
c-0.19-0.08-0.38-0.18-0.54-0.3c-0.17-0.12-0.31-0.27-0.43-0.45h-0.03V45.29z M220.67,41.69c0.68,0,1.17-0.22,1.47-0.65
c0.3-0.44,0.45-1.06,0.45-1.86c0-0.37-0.03-0.7-0.1-1c-0.06-0.29-0.17-0.54-0.32-0.73c-0.15-0.19-0.35-0.34-0.6-0.45
s-0.56-0.16-0.93-0.16c-0.64,0-1.12,0.22-1.46,0.67s-0.5,1.04-0.5,1.76c0,0.73,0.17,1.32,0.5,1.76S220.01,41.69,220.67,41.69z"/>
<path d="M228.16,42.67c-1.04,0-1.81-0.29-2.33-0.87c-0.52-0.58-0.78-1.43-0.78-2.53c0-1.08,0.27-1.92,0.8-2.51
c0.53-0.6,1.3-0.89,2.31-0.89c1.04,0,1.81,0.29,2.33,0.87c0.52,0.58,0.78,1.42,0.78,2.54c0,0.53-0.07,1-0.21,1.42
c-0.14,0.42-0.34,0.78-0.6,1.08c-0.26,0.29-0.59,0.52-0.98,0.67C229.09,42.6,228.65,42.67,228.16,42.67z M228.16,41.69
c0.65,0,1.13-0.2,1.46-0.59c0.32-0.39,0.49-1,0.49-1.83c0-0.82-0.15-1.43-0.45-1.83c-0.3-0.4-0.8-0.6-1.5-0.6
c-0.62,0-1.1,0.2-1.44,0.6c-0.34,0.4-0.5,1.01-0.5,1.83c0,0.84,0.17,1.45,0.52,1.84C227.09,41.5,227.56,41.69,228.16,41.69z"/>
<path d="M232.95,42.57v-6.61h2.47c0.81,0,1.43,0.12,1.85,0.36c0.42,0.24,0.63,0.68,0.63,1.31c0,0.36-0.11,0.68-0.32,0.95
c-0.22,0.27-0.5,0.46-0.86,0.55v0.04c0.42,0.07,0.77,0.23,1.04,0.49c0.27,0.25,0.41,0.61,0.41,1.06c0,0.36-0.06,0.66-0.18,0.9
c-0.12,0.24-0.29,0.43-0.51,0.57s-0.48,0.24-0.79,0.3c-0.31,0.06-0.64,0.08-1,0.08H232.95z M234.04,38.68h1.35
c0.16,0,0.32-0.01,0.49-0.02s0.32-0.05,0.46-0.11c0.14-0.06,0.25-0.15,0.34-0.27c0.09-0.12,0.14-0.28,0.14-0.49
c0-0.18-0.03-0.33-0.09-0.44c-0.06-0.11-0.15-0.2-0.27-0.26c-0.12-0.06-0.25-0.1-0.41-0.12c-0.16-0.02-0.33-0.03-0.52-0.03h-1.48
V38.68z M234.04,41.59h1.67c0.41,0,0.73-0.07,0.96-0.2c0.23-0.13,0.35-0.39,0.35-0.76c0-0.23-0.05-0.42-0.15-0.55
c-0.1-0.13-0.23-0.24-0.38-0.31c-0.16-0.07-0.33-0.12-0.51-0.14s-0.37-0.03-0.55-0.03h-1.39V41.59z"/>
<path d="M244.54,42.57h-0.96v-1.21h-0.03c-0.07,0.18-0.17,0.35-0.32,0.51c-0.14,0.16-0.31,0.3-0.5,0.42
c-0.19,0.12-0.4,0.21-0.63,0.28s-0.48,0.1-0.73,0.1c-0.3,0-0.58-0.05-0.83-0.14s-0.46-0.23-0.64-0.39
c-0.18-0.17-0.32-0.37-0.41-0.59c-0.1-0.22-0.15-0.47-0.15-0.73c0-0.44,0.12-0.8,0.35-1.08c0.23-0.28,0.54-0.49,0.93-0.65
s0.82-0.27,1.31-0.34s1-0.11,1.52-0.14v-0.34c0-0.48-0.11-0.84-0.34-1.08s-0.63-0.36-1.2-0.36c-0.32,0-0.66,0.04-1.02,0.12
s-0.67,0.19-0.93,0.32l-0.19-0.89c0.27-0.15,0.6-0.27,1.01-0.38c0.41-0.1,0.82-0.16,1.26-0.16c0.49,0,0.9,0.06,1.22,0.17
c0.32,0.12,0.58,0.29,0.77,0.51s0.32,0.5,0.4,0.84c0.08,0.34,0.12,0.73,0.12,1.17V42.57z M243.46,39.46
c-0.37,0.02-0.73,0.04-1.08,0.08c-0.35,0.03-0.66,0.1-0.94,0.19s-0.5,0.22-0.67,0.38c-0.17,0.16-0.25,0.37-0.25,0.63
c0,0.27,0.09,0.5,0.28,0.68c0.19,0.19,0.48,0.28,0.89,0.28c0.52,0,0.94-0.16,1.28-0.48s0.5-0.79,0.5-1.41V39.46z"/>
<path d="M252.12,42.57h-1.09v-2.94h-3.39v2.94h-1.09v-6.61h1.09v2.68h3.39v-2.68h1.09V42.57z"/>
<path d="M254.2,42.57v-6.61h1.09v4.21l-0.04,0.87h0.01l0.43-0.69l3.08-4.39h1.04v6.61h-1.09v-4.31l0.04-0.76h-0.01l-0.4,0.65
l-3.11,4.43H254.2z"/>
<path d="M264.65,40.04c-0.22,0-0.39,0.04-0.52,0.12c-0.13,0.08-0.25,0.21-0.36,0.39l-1.1,2.02h-1.31l1.19-2.09
c0.1-0.18,0.21-0.32,0.32-0.41c0.11-0.1,0.22-0.16,0.31-0.21c-0.47-0.09-0.84-0.29-1.13-0.59c-0.29-0.3-0.43-0.71-0.43-1.25
c0-0.34,0.07-0.65,0.2-0.91c0.13-0.26,0.31-0.47,0.54-0.64s0.49-0.3,0.79-0.38c0.3-0.09,0.62-0.13,0.96-0.13h2.67v6.61h-1.09
v-2.53H264.65z M265.7,39.06v-2.11h-1.46c-0.48,0-0.84,0.08-1.08,0.25c-0.24,0.17-0.36,0.45-0.36,0.85c0,0.38,0.15,0.64,0.44,0.79
c0.29,0.15,0.67,0.22,1.11,0.22H265.7z"/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 33 KiB

View File

@ -1,9 +1,13 @@
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
import svgr from 'vite-plugin-svgr'
// https://vite.dev/config/
export default defineConfig({
plugins: [react()],
plugins: [
react(),
svgr()
],
server: {
host: true,
allowedHosts: ['dev.msf.enode', 'demo-msf.kis-npo.ru']