更新代码

master
bettleChen 1 year ago
parent 91de3f8489
commit 8c94d49a17

@ -2,7 +2,7 @@
<module type="PYTHON_MODULE" version="4">
<component name="NewModuleRootManager">
<content url="file://$MODULE_DIR$" />
<orderEntry type="jdk" jdkName="Python 3.9 (NetworkAnalog)" jdkType="Python SDK" />
<orderEntry type="jdk" jdkName="Python 3.7" jdkType="Python SDK" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>

@ -1,4 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectRootManager" version="2" project-jdk-name="Python 3.9 (NetworkAnalog)" project-jdk-type="Python SDK" />
<component name="ProjectRootManager" version="2" project-jdk-name="Python 3.7" project-jdk-type="Python SDK" />
</project>

@ -1,226 +1,36 @@
import ipaddress
import sys
import threading
import ttkbootstrap as tk
from ttkbootstrap import *
from ttkbootstrap import ttk
from tkinter import messagebox
import re
from PIL import ImageTk, Image
from tkinter import filedialog
from SimUtil import *
from SimObjs import SimPacket, SimHost, AllSimConnect, SimRouter, SimSwitch, SimHub, SimBase
from dbUtil import search, execute_sql, delete_obj, truncate_db
from PIL import Image as imim
def round_rectangle(cv, x1, y1, x2, y2, radius=30, **kwargs):
"""
绘制圆角矩形
:param cv: canvas对象
:param radius: 圆角值
:return:
"""
points = [x1 + radius, y1,
x1 + radius, y1,
x2 - radius, y1,
x2 - radius, y1,
x2, y1,
x2, y1 + radius,
x2, y1 + radius,
x2, y2 - radius,
x2, y2 - radius,
x2, y2,
x2 - radius, y2,
x2 - radius, y2,
x1 + radius, y2,
x1 + radius, y2,
x1, y2,
x1, y2 - radius,
x1, y2 - radius,
x1, y1 + radius,
x1, y1 + radius,
x1, y1]
return cv.create_polygon(points, **kwargs, smooth=True)
def validate_ip_address(ip_address):
"""
匹配ip地址格式是否规范
:param ip_address: IP地址
:return: Boolean
"""
# 定义IP地址的正则表达式模式
pattern_with_subnet = r'^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})/(\d{1,2})$'
pattern_without_subnet = r'^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$'
# 使用re模块进行匹配
match_with_subnet = re.match(pattern_with_subnet, ip_address)
match_without_subnet = re.match(pattern_without_subnet, ip_address)
if match_with_subnet:
# 带有子网掩码的IP地址
# 检查每个组件的取值范围是否在 0-255 之间
for group in match_with_subnet.groups()[:4]:
if not (0 <= int(group) <= 255):
return False
# 检查子网掩码的取值范围是否在 0-32 之间
subnet_mask = int(match_with_subnet.groups()[4])
if not (0 <= subnet_mask <= 32):
return False
return True
elif match_without_subnet:
# 不带子网掩码的IP地址
# 检查每个组件的取值范围是否在 0-255 之间
for group in match_without_subnet.groups():
if not (0 <= int(group) <= 255):
return False
return True
else:
# IP地址格式不正确
return False
class RouterConfigWindow(tk.Toplevel):
def __init__(self, parent, router_obj):
super().__init__(parent)
self.geometry("435x433+350+200")
self.title(f"{router_obj.ObjLabel}路由表配置")
self.router_obj = router_obj
self.interface_entries = []
self.router_table = {}
self.create_interface_inputs()
self.create_router_table()
def create_interface_inputs(self):
label_text = ["接口1", "接口2", "接口3", "接口4"]
for i in range(4):
label = tk.Label(self, text=label_text[i], font=("黑体", 16))
label.grid(row=i, column=0, padx=10, pady=5, sticky="w")
entry = tk.Entry(self, width=20, font=("黑体", 16),)
entry.grid(row=i, column=1, padx=10, pady=5, sticky="w")
self.interface_entries.append(entry)
button = tk.Button(self, text="添加", font=("黑体", 16), command=lambda index=i: self.add_router_entry(index))
button.grid(row=i, column=2, padx=10, pady=5)
lab = LabelFrame(self, text="示例")
lab.grid(row=4, column=0, columnspan=3, sticky=W, padx=20)
Label(lab, text="10.1.2.0/24 或者 10.1.2.12" if self.router_obj.ObjType == 2 else "MAC11", font=("黑体", 16)).pack()
def create_router_table(self):
def on_right_click(event):
row = self.router_treeview.identify_row(event.y) # 获取鼠标位置的行索引
if row:
self.router_treeview.selection_set(row) # 选中该行
delete_menu.post(event.x_root, event.y_root) # 在鼠标位置弹出删除菜单
def delete_row():
selected_items = self.router_treeview.selection() # 获取选中的行
for item in selected_items:
ifs, network = int(self.router_treeview.item(item)["values"][0][-1:]), self.router_treeview.item(item)["values"][1]
self.router_obj.delete_config(ifs, network)
self.router_treeview.delete(item)
self.router_table_frame = tk.Frame(self)
self.router_table_frame.grid(row=5, column=0, columnspan=3, padx=10, pady=5)
style = ttk.Style()
style.configure("Custom.Treeview.Heading", font=("宋体", 15))
style.configure("Custom.Treeview", rowheight=30, font=("宋体", 15))
self.router_treeview = ttk.Treeview(self.router_table_frame, style="Custom.Treeview", columns=("Interface", "Route"), show="headings")
self.router_treeview.heading("Interface", text="接口")
self.router_treeview.heading("Route", text="网段")
self.router_treeview.pack(side="left", fill="both")
scrollbar = ttk.Scrollbar(self.router_table_frame, orient="vertical", command=self.router_treeview.yview)
scrollbar.pack(side="right", fill="y")
self.router_treeview.configure(yscrollcommand=scrollbar.set)
self.router_table = self.router_obj.router_table
self.router_treeview.bind("<Button-3>", on_right_click)
# 创建删除菜单
delete_menu = tk.Menu(root, tearoff=False)
delete_menu.add_command(label="删除", command=delete_row)
self.update_router_table()
def add_router_entry(self, index):
entry_text = self.interface_entries[index].get()
try:
ipaddress.ip_network(entry_text)
if isinstance(self.router_obj, SimRouter):
if not validate_ip_address(entry_text):
messagebox.showerror("注意", message="添加的网段信息格式不合格")
self.interface_entries[index].delete(0, tk.END)
self.focus_set()
return
if entry_text:
if index + 1 in self.router_table:
self.router_table[index + 1].append(entry_text)
else:
self.router_table[index + 1] = [entry_text]
self.interface_entries[index].delete(0, tk.END)
self.router_obj.add_config(entry_text, index + 1)
self.update_router_table()
except:
messagebox.showerror("注意", message="网段格式错误!网段示例如下:\n10.1.2.0/24\n10.1.2.12")
return
class Message(Canvas):
def __init__(self, master, **kwargs):
super().__init__(master, **kwargs)
self.message = []
self.master = master
self.scrollbar = tk.Scrollbar(master, orient="vertical", command=self.yview)
self.scrollbar.pack(side="right", fill=BOTH)
self.config(yscrollcommand=self.scrollbar.set)
def update_router_table(self):
self.router_treeview.delete(*self.router_treeview.get_children())
for i, entrys in self.router_table.items():
for entry in entrys:
self.router_treeview.insert("", "end", values=(f"接口{i}", entry))
class SwitchConfigWindow(RouterConfigWindow):
def __init__(self, parent, router_obj):
super().__init__(parent, router_obj)
self.geometry("435x433+350+200")
self.title(f"{router_obj.ObjLabel}交换表配置")
self.router_obj = router_obj
self.interface_entries = []
self.router_table = {}
self.create_interface_inputs()
self.create_router_table()
def create_router_table(self):
def on_right_click(event):
row = self.router_treeview.identify_row(event.y) # 获取鼠标位置的行索引
if row:
self.router_treeview.selection_set(row) # 选中该行
delete_menu.post(event.x_root, event.y_root) # 在鼠标位置弹出删除菜单
def delete_row():
selected_items = self.router_treeview.selection() # 获取选中的行
for item in selected_items:
ifs, network = int(self.router_treeview.item(item)["values"][0][-1:]), self.router_treeview.item(item)["values"][1]
self.router_obj.delete_config(ifs, network)
self.router_treeview.delete(item)
self.router_table_frame = tk.Frame(self)
self.router_table_frame.grid(row=5, column=0, columnspan=3, padx=10, pady=5)
self.router_treeview = ttk.Treeview(self.router_table_frame, columns=("Interface", "Route"), show="headings")
self.router_treeview.heading("Interface", text="接口")
self.router_treeview.heading("Route", text="mac")
self.router_treeview.pack(side="left", fill="both")
scrollbar = ttk.Scrollbar(self.router_table_frame, orient="vertical", command=self.router_treeview.yview)
scrollbar.pack(side="right", fill="y")
self.router_treeview.configure(yscrollcommand=scrollbar.set)
self.router_table = self.router_obj.mac_table
self.router_treeview.bind("<Button-3>", on_right_click)
# 创建删除菜单
delete_menu = tk.Menu(root, tearoff=False)
delete_menu.add_command(label="删除", command=delete_row)
self.update_router_table()
def add_router_entry(self, index):
entry_text = self.interface_entries[index].get()
if isinstance(self.router_obj, SimRouter):
if not validate_ip_address(entry_text):
messagebox.showerror("注意", message="添加的网段信息格式不合格")
self.interface_entries[index].delete(0, tk.END)
self.focus_set()
return
if entry_text:
if index + 1 in self.router_table:
self.router_table[index + 1].append(entry_text)
else:
self.router_table[index + 1] = [entry_text]
self.interface_entries[index].delete(0, tk.END)
self.router_obj.add_config(entry_text, index + 1)
self.update_router_table()
def show_message(self, message, color="#5fa8fe"):
self.message.append({"message": message, "color": color})
num = 0
self.delete("message")
for function in self.message:
self.create_text(20, 25 * num + 10, anchor="nw", text=function["message"], font=("", 15),
fill=function["color"], tags="message")
num += 1
self.update()
self.configure(scrollregion=self.bbox("all"))
self.scrollbar.set(1.0, 1.0)
self.yview_moveto(1.0)
class NetWorkAnalog(Canvas):
@ -228,17 +38,39 @@ class NetWorkAnalog(Canvas):
super().__init__(master, **kwargs)
self.master = master
self.router_img = ImageTk.PhotoImage(
Image.open(sys.path[0] + "/../datas/images/路由器.png").resize((60, 60)))
Image.open(sys.path[0] + "/../datas/images/路由器@2x.png").resize((40, 40)))
self.switch_img = ImageTk.PhotoImage(
Image.open(sys.path[0] + "/../datas/images/交换机.png").resize((60, 60)))
Image.open(sys.path[0] + "/../datas/images/交换机@2x.png").resize((40, 40)))
self.hub_img = ImageTk.PhotoImage(
Image.open(sys.path[0] + "/../datas/images/集线器.png").resize((60, 60)))
Image.open(sys.path[0] + "/../datas/images/集线器@2x.png").resize((40, 40)))
self.host_img = ImageTk.PhotoImage(
Image.open(sys.path[0] + "/../datas/images/主机.png").resize((60, 60)))
Image.open(sys.path[0] + "/../datas/images/主机@2x.png").resize((40, 40)))
self.pack_img = ImageTk.PhotoImage(
Image.open(sys.path[0] + "/../datas/images/packet.png").resize((30, 30)))
self.true_img = ImageTk.PhotoImage(
Image.open(sys.path[0] + "/../datas/images/true.png").resize((30, 30)))
self.false_img = ImageTk.PhotoImage(
Image.open(sys.path[0] + "/../datas/images/false.png").resize((30, 30)))
self.width = int(self.cget("width"))
self.height = int(self.cget("height"))
self.canvas_size = [150, 0, int(self.width * 0.8), int(self.height * 0.8)]
self.label_top_img = ImageTk.PhotoImage(imim.open("../datas/images/右上框@2x.png").resize((int(self.width - self.width * 0.85), int(self.canvas_size[3] * 0.4))))
self.label_bottom_img = ImageTk.PhotoImage(imim.open("../datas/images/右下框@2x.png").resize((int(self.width - self.width * 0.85), int(self.canvas_size[3] * 0.45))))
self.message_img = ImageTk.PhotoImage(
Image.open(sys.path[0] + "/../datas/images/日志消息展示框@2x.png").resize((self.width - 60, self.height - self.canvas_size[3] - 30))
)
message_frame = Frame(self, width=self.width - 60, height=self.height - self.canvas_size[3] - 30)
message_frame.place(x=15, y=self.canvas_size[3] + 15, anchor=NW)
self.message = Message(message_frame, width=self.width - 60, height=self.height - self.canvas_size[3] - 30)
self.message.pack()
self.message.configure(bg="#edf8ff")
self.configure(bg="#ddeafe")
self.filename = ImageTk.PhotoImage(imim.open("../datas/images/背景@2x.png").resize((self.width, self.canvas_size[3])))
self.check_filename = ImageTk.PhotoImage(Image.open("../datas/images/背景@2x.png").resize((self.width, self.height)))
self.create_image(0, 0, image=self.filename, anchor=NW)
self.chose = self.host_img
self.AllSimObjs = {}
self.receive = None
self.conns = []
self.drawLine = True # 画线标志
self.line_start_obj = None
@ -248,6 +80,7 @@ class NetWorkAnalog(Canvas):
self.chose_obj = None
self.show_label_flag = True
self.show_interface_flag = True
self.check_error_obj = None
self.create_widget()
def is_chose(self):
@ -256,8 +89,11 @@ class NetWorkAnalog(Canvas):
:return:
"""
self.delete("rectangle")
self.create_rectangle(self.chose_obj.ObjX - 25, self.chose_obj.ObjY - 25, self.chose_obj.ObjX + 25,
self.chose_obj.ObjY + 25, outline="red", tags="rectangle")
self.create_rectangle(self.chose_obj.ObjX - 35, self.chose_obj.ObjY - 35, self.chose_obj.ObjX + 15,
self.chose_obj.ObjY + 15, outline="red", tags="rectangle")
self.show_network_config()
if self.chose_obj.ObjType == 2 or self.chose_obj.ObjType == 3:
self.show_router_config()
def tag_bind_event(self):
"""
@ -323,6 +159,7 @@ class NetWorkAnalog(Canvas):
if not flag:
self.line_start_obj.connections[self.line_start_ifs - 1] = conn
self.line_end_obj.connections[self.line_end_ifs - 1] = conn
self.message.show_message(f"{self.line_start_obj.ObjLabel}连接{self.line_end_obj.ObjLabel}成功!")
conn.save()
self.conns.append(conn)
init()
@ -344,15 +181,15 @@ class NetWorkAnalog(Canvas):
if self.drawLine:
self.delete("Line")
x, y = event.x, event.y
if not (0 < x < self.width * 0.8 and 0 < y < self.height * 0.85):
if not (0 < x < self.canvas_size[2] and 0 < y < self.canvas_size[3]):
if x < 0:
x = 0
elif x > self.width * 0.8:
x = self.width * 0.8
elif x > self.canvas_size[2]:
x = self.canvas_size[2]
if y < 0:
y = 0
elif y > self.height * 0.85:
y = self.height * 0.85
elif y > self.canvas_size[3]:
y = self.canvas_size[3]
self.create_line(self.line_start_obj.ObjX, self.line_start_obj.ObjY, x + 8, y + 8, fill="#5b9bd5",
width=1,
tags="Line")
@ -380,7 +217,7 @@ class NetWorkAnalog(Canvas):
鼠标左键松开事件
:param event: 事件对象
"""
if 20 < event.x < self.width * 0.8 + 20 and 20 < event.y < self.height * 0.85 - 20: # 在方框内,无变化
if 20 + self.canvas_size[0] < event.x < self.canvas_size[2] + 20 and 20 + self.canvas_size[1] < event.y < self.canvas_size[3] - 20: # 在方框内,无变化
if name == "路由器":
tag = SimRouter(self, event.x, event.y)
elif name == "集线器":
@ -392,6 +229,7 @@ class NetWorkAnalog(Canvas):
tag.create_img()
self.AllSimObjs[tag.ObjID] = tag
tag.save()
self.message.show_message(f"组件 {tag.ObjLabel} 创建成功!")
self.tag_bind_event()
else:
self.delete("L")
@ -410,7 +248,7 @@ class NetWorkAnalog(Canvas):
else:
self.chose = self.host_img
self.delete("L")
if 20 < event.x < self.width * 0.8 + 20 and 20 < event.y < self.height * 0.85 - 20: # 在方框内,无变化
if 20 + self.canvas_size[0] < event.x < self.canvas_size[2] + 20 and 20 + self.canvas_size[1] < event.y < self.canvas_size[3] - 20: # 在方框内,无变化
pass
else: # 在方框外,显示禁止放置标识
self.create_oval(event.x - 10, event.y - 45, event.x + 10, event.y - 25, outline="red", width=2,
@ -471,7 +309,6 @@ class NetWorkAnalog(Canvas):
self.AllSimObjs = AllSimObj
self.conns = conns
for key, sim_obj in self.AllSimObjs.items():
print(key)
sim_obj.create_img()
for conn in self.conns:
conn.draw_line()
@ -498,6 +335,7 @@ class NetWorkAnalog(Canvas):
execute_sql(delete_sql)
execute_sql(delete_config_sql)
delete_obj(self.chose_obj.ObjID)
self.message.show_message(f"组件 {self.chose_obj.ObjLabel} 删除成功!")
self.delete("rectangle")
self.reload_data()
@ -565,6 +403,7 @@ class NetWorkAnalog(Canvas):
self.AllSimObjs[data[0]].connections[data[1] - 1] = None
child_d.destroy()
messagebox.showinfo("提示", f"连接线{value.get()}删除成功!")
self.message.show_message(f"连接线{value.get()}删除成功!")
btn_yes = tk.Button(child_d, text='确定', font=('黑体', 12), height=1, command=del_line)
btn_yes.place(x=240, y=20)
@ -601,6 +440,7 @@ class NetWorkAnalog(Canvas):
conn.update_info(self.chose_obj.ObjID)
child1.destroy()
messagebox.showinfo("提示", message="修改成功!")
self.message.show_message(f"{name} 修改名称成功!")
tk.Button(child1, text='确定', font=('黑体', 16), height=1, command=update_tag).grid(row=2, column=0,
sticky='e', pady=10)
@ -677,6 +517,7 @@ class NetWorkAnalog(Canvas):
addr_en.grid(row=1, column=3, padx=10)
def commit():
self.chose_obj.config(datas)
self.message.show_message(f"组件 {self.chose_obj} 网络配置成功!")
child_r.destroy()
tk.Button(ifs_frame_YN, text='确定', font=('黑体', 16), height=1, command=commit).grid(row=0, column=0,
@ -767,9 +608,9 @@ class NetWorkAnalog(Canvas):
messagebox.showerror("注意", message="请选择路由器/交换机对象!")
return
self.delete("routerSet")
self.create_text(self.width * 0.82 + 120, self.height * 0.85 / 2 + 50, text="(" + self.chose_obj.ObjLabel + ")", anchor="n", font=('微软雅黑', 14, 'bold'),
self.create_text(self.width * 0.82 + 120, self.canvas_size[3] / 2 + 50, text="(" + self.chose_obj.ObjLabel + ")", anchor="n", font=('微软雅黑', 14, 'bold'),
fill="#7030a0", tags="routerSet")
self.create_text(self.width * 0.82 + 20, self.height * 0.85 / 2 + 50 + 25, text=self.chose_obj.get_table_config(),
self.create_text(self.width * 0.82 + 20, self.canvas_size[3] / 2 + 50 + 25, text=self.chose_obj.get_table_config(),
anchor="nw", font=('宋体', 14), tags="routerSet")
def send_packet(self):
@ -793,12 +634,9 @@ class NetWorkAnalog(Canvas):
tk.Label(child2, text='目的IP:', font=('黑体', 16)).grid(row=0, column=0, columnspan=2, sticky='w', pady=10)
packet_ip = tk.Entry(child2, font=('黑体', 16), textvariable=tk.StringVar())
packet_ip.grid(row=0, column=1, pady=10)
tk.Label(child2, text='目的MAC:', font=('黑体', 16)).grid(row=1, column=0, sticky='w', pady=10) # ,sticky='w'靠左显示
packet_mac = tk.Entry(child2, font=('黑体', 16), textvariable=tk.StringVar())
packet_mac.grid(row=1, column=1, pady=10)
tk.Label(child2, text='消息:', font=('黑体', 16)).grid(row=2, column=0, sticky='w', pady=10) # ,sticky='w'靠左显示
tk.Label(child2, text='消息:', font=('黑体', 16)).grid(row=1, column=0, sticky='w', pady=10) # ,sticky='w'靠左显示
packet_message = tk.Entry(child2, font=('黑体', 16), textvariable=tk.StringVar())
packet_message.grid(row=2, column=1, pady=10)
packet_message.grid(row=1, column=1, pady=10)
def send():
"""
@ -811,16 +649,16 @@ class NetWorkAnalog(Canvas):
if not validate_ip_address(packet_ip.get()):
messagebox.showerror("注意", message="IP地址不规范")
return
if packet_mac.get() == "":
messagebox.showerror("注意", message="mac地址不能为空")
return
if packet_message.get() == "":
messagebox.showerror("注意", message="消息不能为空!")
return
self.chose_obj.create_packet(packet_ip.get(),
packet_mac.get(),
packet_message.get())
ip = packet_ip.get()
message = packet_message.get()
child2.destroy()
self.chose_obj.create_packet(ip,
None,
message)
tk.Button(child2, text='确定', font=('黑体', 16), height=1, command=send).grid(row=3, column=0, sticky='e', pady=10)
tk.Button(child2, text='取消', font=('黑体', 16), height=1, command=child2.destroy).grid(row=3, column=1, sticky='e', pady=10)
@ -840,15 +678,11 @@ class NetWorkAnalog(Canvas):
tk.Label(child2, text='目的IP:', font=('黑体', 16)).grid(row=0, column=0, columnspan=2, sticky='w', ipady=10)
packet_ip = tk.Entry(child2, font=('黑体', 16), textvariable=tk.StringVar())
packet_ip.grid(row=0, column=1, pady=5)
tk.Label(child2, text='目的MAC:', font=('黑体', 16)).grid(row=1, column=0, sticky='w',
pady=5) # ,sticky='w'靠左显示
packet_mac = tk.Entry(child2, font=('黑体', 16), textvariable=tk.StringVar())
packet_mac.grid(row=1, column=1, pady=5)
tk.Label(child2, text='消息:', font=('黑体', 16)).grid(row=2, column=0, sticky='w', pady=5) # ,sticky='w'靠左显示
tk.Label(child2, text='消息:', font=('黑体', 16)).grid(row=1, column=0, sticky='w', pady=5) # ,sticky='w'靠左显示
packet_message = tk.Entry(child2, font=('黑体', 16), textvariable=tk.StringVar())
packet_message.grid(row=2, column=1, pady=5)
packet_message.grid(row=1, column=1, pady=5)
host = StringVar()
tk.Label(child2, text='发送主机:', font=('黑体', 16)).grid(row=3, column=0, sticky='w',
tk.Label(child2, text='发送主机:', font=('黑体', 16)).grid(row=2, column=0, sticky='w',
pady=5) # ,sticky='w'靠左显示
combobox = ttk.Combobox(
master=child2, # 父容器
@ -859,7 +693,7 @@ class NetWorkAnalog(Canvas):
textvariable=host, # 通过StringVar设置可改变的值
values=list(hosts.keys()), # 设置下拉框的选项
)
combobox.grid(row=3, column=1, pady=5)
combobox.grid(row=2, column=1, pady=5)
packet_frame = tk.Frame(child2)
packet_frame.grid(row=5, column=0, columnspan=3, padx=10, pady=5)
packet_treeview = ttk.Treeview(packet_frame, columns=("source_host", "ip", "mac", "message"), show="headings")
@ -879,15 +713,14 @@ class NetWorkAnalog(Canvas):
def add():
ip = packet_ip.get()
mac = packet_mac.get()
message = packet_message.get()
chose_host = host.get()
if ip == "" or mac == "" or message == "" or chose_host == "":
if ip == "" or message == "" or chose_host == "":
messagebox.showerror("注意", message="输入框不能为空")
return
packet = SimPacket(self.AllSimObjs[hosts[chose_host]].interface[0]["ip"],
self.AllSimObjs[hosts[chose_host]].interface[0]["mac"],
ip, mac, message)
ip, None, message)
packets.append((self.AllSimObjs[hosts[chose_host]], packet))
packet_treeview.delete(*packet_treeview.get_children())
for datas in packets:
@ -928,6 +761,99 @@ class NetWorkAnalog(Canvas):
self.AllSimObjs.clear()
self.conns.clear()
def export_data(self):
try:
export = ExportUtil(sys.path[0] + "/database.xlsx")
export.export()
self.message.show_message("文件导出成功!文件位置在{}".format(sys.path[0] + "/database.xlsx"))
except Exception as E:
self.message.show_message(str(E), color="red")
def import_data(self):
truncate_db()
for tag_id, tag in self.AllSimObjs.items():
self.delete(tag_id)
self.delete(tag_id + "text")
for conn in self.conns:
conn.delete_line()
self.delete("rectangle")
self.AllSimObjs.clear()
self.conns.clear()
file_path = filedialog.askopenfilename()
if file_path:
export = ExportUtil(file_path)
export.import_data()
self.message.show_message("文件导入成功!")
self.reload_data()
def check_network(self):
"""
校验
:return:
"""
hosts = {}
for key, tag in self.AllSimObjs.items():
if tag.ObjType == 1 and tag.ConfigCorrect == 1:
hosts[tag.ObjLabel] = tag.ObjID
child2 = tk.Toplevel()
child2.title("数据包配置")
child2.geometry('392x168+200+110')
child2.grab_set() # 设置组件焦点抓取。使焦点在释放之前永远保持在这个组件上,只能在这个组件上操作
tk.Label(child2, text='发送主机:', font=('黑体', 16)).grid(row=0, column=0, columnspan=2, sticky='w', pady=10)
send_host = StringVar()
host_combobox = ttk.Combobox(
master=child2, # 父容器
height=5, # 高度,下拉显示的条目数量
width=18, # 宽度
state='readonly', # readonly(只可选)
font=('', 16), # 字体
textvariable=send_host, # 通过StringVar设置可改变的值
values=list(hosts.keys()), # 设置下拉框的选项
)
host_combobox.grid(row=0, column=1, pady=10)
tk.Label(child2, text='接收主机:', font=('黑体', 16)).grid(row=1, column=0, sticky='w',
pady=10) # ,sticky='w'靠左显示
receive_host = StringVar()
ttk.Combobox(
master=child2, # 父容器
height=5, # 高度,下拉显示的条目数量
width=18, # 宽度
state='readonly', # readonly(只可选)
font=('', 16), # 字体
textvariable=receive_host, # 通过StringVar设置可改变的值
values=list(hosts.keys()), # 设置下拉框的选项
).grid(row=1, column=1, pady=10)
def check():
"""
发送数据包
:return:
"""
if send_host.get() == "" or receive_host.get() == "":
messagebox.showerror("注意", message="信息不能为空")
return
if send_host.get() == receive_host.get():
messagebox.showerror("注意", message="发送主机和接收主机不能相同!")
send_host_obj: SimHost = self.AllSimObjs[hosts[send_host.get()]]
receive_host_obj: SimHost = self.AllSimObjs[hosts[receive_host.get()]]
child2.destroy()
send_host_obj.create_packet(receive_host_obj.interface[0]["ip"], receive_host_obj.interface[0]["mac"], "ping", True)
TransferAnimate(self, self.receive == receive_host_obj)
if self.receive == receive_host_obj:
self.message.show_message("校验成功:{}{} 能正常连通".format(send_host_obj.ObjLabel, receive_host_obj.ObjLabel))
else:
self.message.show_message(
"校验成功:{}{} 无法正常连通,请检查一下组件 {} 的配置".format(send_host_obj.ObjLabel, receive_host_obj.ObjLabel, self.check_error_obj.ObjLabel), "red")
self.check_error_obj = None
self.receive = None
tk.Button(child2, text='校验', font=('黑体', 16), height=1, command=check).grid(row=5, column=0, sticky='e',
pady=10)
tk.Button(child2, text='取消', font=('黑体', 16), height=1, command=child2.destroy).grid(row=5, column=1,
sticky='e', pady=10)
def create_config_button(self):
# 创建一个菜单栏,这里我们可以把他理解成一个容器,在窗口的上方
menubar = tk.Menu(root)
@ -958,6 +884,9 @@ class NetWorkAnalog(Canvas):
setMenu.add_command(label='批量发送数据包', command=self.send_packet_list)
menubar.add_command(label='清除屏幕', command=self.clear_canvas)
menubar.add_command(label='导出数据', command=self.export_data)
menubar.add_command(label='导入数据', command=self.import_data)
menubar.add_command(label='校验', command=self.check_network)
root.config(menu=menubar)
def create_widget(self):
@ -966,21 +895,22 @@ class NetWorkAnalog(Canvas):
创建整体页面布局
:return:
"""
self.create_rectangle(0, 0, self.width * 0.8, self.height * 0.85, outline="#7f6000", width=3) # 矩形框,左上角坐标,右下角坐标
round_rectangle(self, self.width * 0.82, 30, self.width * 0.98, self.height * 0.85 / 2 - 30, outline="#ffff00", width=3, fill="#f4b88e") # 矩形框,左上角坐标,右下角坐标
self.create_rectangle(self.canvas_size[0], self.canvas_size[1], self.canvas_size[2], self.canvas_size[3], outline="#7f6000", width=0) # 矩形框,左上角坐标,右下角坐标
self.create_image(self.width * 0.82, 30, image=self.label_top_img, anchor=NW) # 矩形框,左上角坐标,右下角坐标
self.create_text(self.width * 0.82 + 120, 30 + 15, text="网络配置信息", anchor="n", font=('微软雅黑', 18, 'bold'))
round_rectangle(self, self.width * 0.82, self.height * 0.85 / 2, self.width * 0.98, self.height * 0.85 - 30, outline="#ffff00", width=2, fill="#f4b88e") # 矩形框,左上角坐标,右下角坐标
self.create_text(self.width * 0.82 + 120, self.height * 0.85 / 2 + 15, text="路由/交换表信息", anchor="n", font=('微软雅黑', 18, 'bold'))
self.create_image(self.width * 0.82, self.canvas_size[3] / 2, image=self.label_bottom_img, anchor=NW) # 矩形框,左上角坐标,右下角坐标
# round_rectangle(self, self.width * 0.82, self.canvas_size[3] / 2, self.width * 0.98, self.canvas_size[3] - 30, outline="#ffff00", width=2, fill="#f4b88e") # 矩形框,左上角坐标,右下角坐标
self.create_text(self.width * 0.82 + 120, self.canvas_size[3] / 2 + 15, text="路由/交换表信息", anchor="n", font=('微软雅黑', 18, 'bold'))
# 显示左边的固定图片
img_height, text_height, split_width = self.height - 120, self.height - 60, 120
self.create_text(split_width, text_height, text="路由器", anchor="nw", font=('微软雅黑', 18, 'bold')) # 显示文字
router = self.create_image(split_width, img_height, image=self.router_img, anchor="nw")
self.create_text(split_width * 2, text_height, text="交换机", anchor="nw", font=('微软雅黑', 18, 'bold')) # 显示文字
switch = self.create_image(split_width * 2, img_height, image=self.switch_img, anchor="nw")
self.create_text(split_width * 3, text_height, text="集线器", anchor="nw", font=('微软雅黑', 18, 'bold')) # 显示文字
hub = self.create_image(split_width * 3, img_height, image=self.hub_img, anchor="nw")
self.create_text(split_width * 4, text_height, text="主机", anchor="nw", font=('微软雅黑', 18, 'bold')) # 显示文字
host = self.create_image(split_width * 4, img_height, image=self.host_img, anchor="nw")
img_height, text_height, split_width = 50, 40, 120
self.create_text(text_height, split_width + 40, text="路由器", anchor="nw", font=('微软雅黑', 18, 'bold')) # 显示文字
router = self.create_image(img_height, split_width, image=self.router_img, anchor="nw")
self.create_text(text_height, split_width * 2 + 40, text="交换机", anchor="nw", font=('微软雅黑', 18, 'bold')) # 显示文字
switch = self.create_image(img_height, split_width * 2, image=self.switch_img, anchor="nw")
self.create_text(text_height, split_width * 3 + 40, text="集线器", anchor="nw", font=('微软雅黑', 18, 'bold')) # 显示文字
hub = self.create_image(img_height, split_width * 3, image=self.hub_img, anchor="nw")
self.create_text(text_height, split_width * 4 + 40, text="主机", anchor="nw", font=('微软雅黑', 18, 'bold')) # 显示文字
host = self.create_image(img_height, split_width * 4, image=self.host_img, anchor="nw")
self.bind_event(router, "路由器")
self.bind_event(switch, "交换机")
self.bind_event(hub, "集线器")
@ -990,7 +920,7 @@ class NetWorkAnalog(Canvas):
if __name__ == '__main__':
root = Window()
root.title('网络拓扑图')
screen_width = root.winfo_screenwidth() # winfo方法来获取当前电脑屏幕大小
screen_width = root.winfo_screenwidth() # winfo 方法来获取当前电脑屏幕大小
screen_height = root.winfo_screenheight()
root_attr = {
"width": screen_width * 0.83,

@ -27,21 +27,21 @@ class SimBase():
self.ObjY = y
self.canvas = canvas
self.host_img = ImageTk.PhotoImage(
Image.open(sys.path[0] + "/../datas/images/主机.png").resize((60, 60)))
Image.open(sys.path[0] + "/../datas/images/主机@2x.png").resize((40, 40)))
self.host_img_tm = ImageTk.PhotoImage(
Image.open(sys.path[0] + "/../datas/images/主机_tm.png").resize((60, 60)))
Image.open(sys.path[0] + "/../datas/images/主机--暗色@2x.png").resize((40, 40)))
self.router_img = ImageTk.PhotoImage(
Image.open(sys.path[0] + "/../datas/images/路由器.png").resize((60, 60)))
Image.open(sys.path[0] + "/../datas/images/路由器@2x.png").resize((40, 40)))
self.router_img_tm = ImageTk.PhotoImage(
Image.open(sys.path[0] + "/../datas/images/路由器_tm.png").resize((60, 60)))
Image.open(sys.path[0] + "/../datas/images/路由器--暗色@2x.png").resize((40, 40)))
self.switch_img = ImageTk.PhotoImage(
Image.open(sys.path[0] + "/../datas/images/交换机.png").resize((60, 60)))
Image.open(sys.path[0] + "/../datas/images/交换机@2x.png").resize((40, 40)))
self.switch_img_tm = ImageTk.PhotoImage(
Image.open(sys.path[0] + "/../datas/images/交换机_tm.png").resize((60, 60)))
Image.open(sys.path[0] + "/../datas/images/交换机--暗色@2x.png").resize((40, 40)))
self.hub_img = ImageTk.PhotoImage(
Image.open(sys.path[0] + "/../datas/images/集线器.png").resize((60, 60)))
Image.open(sys.path[0] + "/../datas/images/集线器@2x.png").resize((40, 40)))
self.hub_img_tm = ImageTk.PhotoImage(
Image.open(sys.path[0] + "/../datas/images/集线器_tm.png").resize((60, 60)))
Image.open(sys.path[0] + "/../datas/images/集线器--暗色@2x.png").resize((40, 40)))
self.img = None
self.img_tm = None
self.interface = [{}, {}, {}, {}]
@ -90,10 +90,8 @@ class SimBase():
self.canvas.chose_obj = None
dx = event.x - self.start_x
dy = event.y - self.start_y
width = int(self.canvas.cget("width"))
height = int(self.canvas.cget("height"))
# 移动范围限制, 超出移动范围则直接返回
if not (0 + 20 <= self.ObjX + dx <= width * 0.8 - 20 and 20 <= self.ObjY + dy <= height * 0.85 - 20):
if not (self.canvas.canvas_size[0] + 20 <= self.ObjX + dx <= self.canvas.canvas_size[2] - 20 and 20 + self.canvas.canvas_size[1] <= self.ObjY + dy <= self.canvas.canvas_size[3] - 20):
return
self.ObjX += dx
self.ObjY += dy
@ -127,8 +125,8 @@ class SimBase():
image=self.img if self.ConfigCorrect == 1 else self.img_tm, anchor="nw",
tags=self.ObjID)
self.canvas.dtag("L", "L")
self.canvas.create_text(self.ObjX, self.ObjY - 40, text=self.ObjLabel, font=("", 16, "bold"),
fill="#7030a0", tags=self.ObjID + "text", anchor="nw")
self.canvas.create_text(self.ObjX - 20, self.ObjY - 60, text=self.ObjLabel, font=("", 16, "bold"),
fill="#9b78eb", tags=self.ObjID + "text", anchor="nw")
self.canvas.tag_raise(id)
self.bind_event()
@ -177,7 +175,7 @@ class SimBase():
:return:
"""
self.canvas.delete(self.ObjID + "text")
self.canvas.create_text(self.ObjX, self.ObjY - 40, text=self.ObjLabel, font=("", 16, "bold"),
self.canvas.create_text(self.ObjX - 20, self.ObjY - 60, text=self.ObjLabel, font=("", 16, "bold"),
fill="#7030a0", tags=self.ObjID + "text", anchor="nw")
sql = f"update sim_objs set objLabel='{self.ObjLabel}', ObjX={self.ObjX}," \
f"ObjY={self.ObjY}, ConfigCorrect={self.ConfigCorrect} where ObjID='{self.ObjID}'"
@ -220,7 +218,7 @@ class SimPacket():
"""
数据包类
"""
def __init__(self, source_ip, source_mac, destination_ip, destination_mac, message):
def __init__(self, source_ip, source_mac, destination_ip, destination_mac, message, ping=False):
"""
:param source_mac: 源主机mac地址
:param source_ip: 源主机ip地址
@ -234,6 +232,7 @@ class SimPacket():
self.destination_ip = destination_ip
self.message = message
self.up_jump = None # 上一跳连接对象
self.ping = ping
self.img = ImageTk.PhotoImage(
Image.open(sys.path[0] + "/../datas/images/packet.png").resize((30, 30)))
self.id = str(uuid4())
@ -260,6 +259,8 @@ class SimPacket():
cv.delete(self.id)
def transfer_packet(self, cv: Canvas, nodex_tag: SimBase, nodey_tag: SimBase):
if self.ping:
return
cv.create_image(nodex_tag.ObjX - 15, nodex_tag.ObjY - 15, image=self.img, anchor="nw", tags=self.id)
self.move(cv, nodey_tag.ObjX - 15, nodey_tag.ObjY - 15, 500)
@ -280,7 +281,7 @@ class AllSimConnect():
self.NobjE = nodey
self.IfsS = nodex_ifs
self.IfsE = nodey_ifs
self.width = 1 if self.ConfigCorrect == 0 else 4 # 线的粗细
self.width = False if self.ConfigCorrect == 0 else True # 线的粗细
def is_connected_to(self, other):
"""
@ -342,6 +343,7 @@ class AllSimConnect():
:return:
"""
if source_node == self.NobjS:
if not packet.ping:
packet.transfer_packet(self.canvas, self.NobjS, self.NobjE)
self.NobjE.receive(packet)
else:
@ -349,9 +351,13 @@ class AllSimConnect():
self.NobjS.receive(packet)
def draw_line(self):
if self.width:
line = self.canvas.create_line(self.NobjS.ObjX, self.NobjS.ObjY, self.NobjE.ObjX, self.NobjE.ObjY,
width=2, fill="#c372f0", tags=self.NobjS.ObjID + self.NobjE.ObjID + "line")
else:
line = self.canvas.create_line(self.NobjS.ObjX, self.NobjS.ObjY, self.NobjE.ObjX, self.NobjE.ObjY,
width=self.width, fill="#5b9bd5", tags=self.NobjS.ObjID + self.NobjE.ObjID + "line")
self.canvas.tag_lower(line)
width=2, dash=(250, 4), fill="#c372f0", tags=self.NobjS.ObjID + self.NobjE.ObjID + "line")
self.canvas.tag_lower(line, 2)
self.analyseIFS(self.NobjS.ObjX, self.NobjS.ObjY, self.NobjS.ObjLabel, self.IfsS,
self.NobjE.ObjX, self.NobjE.ObjY, self.NobjE.ObjLabel, self.IfsE)
@ -384,6 +390,7 @@ class AllSimConnect():
:param SLabel: S对象的标签
:param IfsS: S对象要显示的接口号
'''
offset = 15
if (EX - SX) == 0: # 即垂直的时候,NobjS在NobjE对象的正上方和正下方x坐标无变化只需要y变化
R = 18
x = 0 # x无偏移量
@ -401,10 +408,10 @@ class AllSimConnect():
x_E = EX - x
y_E = EY - y # NobjE的连接点坐标
# 显示S接口号
self.canvas.create_text((x_S - 5, y_S - 5), text=IfsS, anchor="nw", font=("幼圆", 16, "bold"), fill="red",
self.canvas.create_text((x_S + offset, y_S - offset), text=IfsS, anchor="nw", font=("幼圆", 16, "bold"), fill="#5fa6d6",
tag=self.NobjS.ObjID + self.NobjE.ObjID) # 显示文字
# 显示E接口号
self.canvas.create_text(x_E - 10, y_E - 10, text=IfsE, anchor="nw", font=("幼圆", 16, "bold"), fill="red",
self.canvas.create_text(x_E - offset, y_E - offset, text=IfsE, anchor="nw", font=("幼圆", 16, "bold"), fill="#5fa6d6",
tag=self.NobjS.ObjID + self.NobjE.ObjID) # 显示文字
elif SX < EX and SY > EY: # NobjS在NobjE的左下角NobjS的右上角连接NobjE的左下角
x_S = SX + x
@ -412,10 +419,10 @@ class AllSimConnect():
x_E = EX - x
y_E = EY + y # NobjE的连接点坐标
# 显示S接口号
self.canvas.create_text(x_S + 5, y_S - 10, text=IfsS, anchor="nw", font=("幼圆", 16, "bold"), fill="red",
self.canvas.create_text(x_S + offset, y_S - offset, text=IfsS, anchor="nw", font=("幼圆", 16, "bold"), fill="#5fa6d6",
tag=self.NobjS.ObjID + self.NobjE.ObjID) # 显示文字
# 显示E接口号
self.canvas.create_text(x_E - 5, y_E, text=IfsE, anchor="nw", font=("幼圆", 16, "bold"), fill="red",
self.canvas.create_text(x_E - offset, y_E, text=IfsE, anchor="nw", font=("幼圆", 16, "bold"), fill="#5fa6d6",
tag=self.NobjS.ObjID + self.NobjE.ObjID) # 显示文字
elif SX > EX and SY < EY: # NobjS在NobjE的右上角NobjS的左下角连接NobjE的右上角
x_S = SX - x
@ -423,10 +430,10 @@ class AllSimConnect():
x_E = EX + x
y_E = EY - y # NobjE的连接点坐标
# 显示S接口号
self.canvas.create_text(x_S - 5, y_S, text=IfsS, anchor="nw", font=("幼圆", 16, "bold"), fill="red",
self.canvas.create_text(x_S - offset, y_S, text=IfsS, anchor="nw", font=("幼圆", 16, "bold"), fill="#5fa6d6",
tag=self.NobjS.ObjID + self.NobjE.ObjID) # 显示文字
# 显示E接口号
self.canvas.create_text(x_E + 5, y_E, text=IfsE, anchor="nw", font=("幼圆", 16, "bold"), fill="red",
self.canvas.create_text(x_E + offset, y_E, text=IfsE, anchor="nw", font=("幼圆", 16, "bold"), fill="#5fa6d6",
tag=self.NobjS.ObjID + self.NobjE.ObjID) # 显示文字
elif SX >= EX and SY >= EY: # NobjS在NobjE的右下角NobjS的左上角连接NobjE的右下角
x_S = SX - x
@ -434,10 +441,10 @@ class AllSimConnect():
x_E = EX + x
y_E = EY + y # NobjE的连接点坐标
# 显示S接口号
self.canvas.create_text(x_S - 5, y_S - 15, text=IfsS, anchor="nw", font=("幼圆", 16, "bold"), fill="red",
self.canvas.create_text(x_S - offset, y_S - offset, text=IfsS, anchor="nw", font=("幼圆", 16, "bold"), fill="#5fa6d6",
tag=self.NobjS.ObjID + self.NobjE.ObjID) # 显示文字
# 显示E接口号
self.canvas.create_text(x_E - 5, y_E - 5, text=IfsE, anchor="nw", font=("幼圆", 16, "bold"), fill="red",
self.canvas.create_text(x_E + offset, y_E - offset, text=IfsE, anchor="nw", font=("幼圆", 16, "bold"), fill="#5fa6d6",
tag=self.NobjS.ObjID + self.NobjE.ObjID) # 显示文字
def save(self):
@ -485,7 +492,7 @@ class SimHost(SimBase):
self.set_default_config()
def create_packet(self, ip, mac, message):
def create_packet(self, ip, mac, message, ping=False):
"""
创建数据包
:param ip: 目的主机ip
@ -493,6 +500,9 @@ class SimHost(SimBase):
:param message: 消息
:return:
"""
if ping:
packet = SimPacket(self.interface[0]["ip"], self.interface[0]["mac"], ip, mac, message, True)
else:
packet = SimPacket(self.interface[0]["ip"], self.interface[0]["mac"], ip, mac, message)
print(f"创建数据包成功,数据包由{packet.source_ip} 发往 {packet.destination_ip}")
self.send(packet)
@ -516,7 +526,10 @@ class SimHost(SimBase):
"""
print(f"主机{self.ObjLabel}接受到数据{packet.message}")
if packet.destination_ip == self.interface[0]["ip"]:
if not packet.ping:
self.transfer_animate(True, packet)
else:
self.canvas.receive = self
else:
self.transfer_animate(False, packet)
@ -606,6 +619,9 @@ class SimRouter(SimBase):
conn.transfer(self, packet)
break
error_message = "路由寻址失败"
if packet.ping:
self.canvas.check_error_obj = self
return
self.transfer_animate(False, packet, error_message)
def receive(self, packet):

@ -0,0 +1,332 @@
import ipaddress
import re
import sqlite3
from time import sleep
from tkinter import messagebox
import ttkbootstrap as tk
from ttkbootstrap import *
from ttkbootstrap import ttk
import pandas as pd
import sys
from PIL import Image, ImageTk
from SimObjs import SimRouter
def round_rectangle(cv, x1, y1, x2, y2, radius=30, **kwargs):
"""
绘制圆角矩形
:param cv: canvas对象
:param radius: 圆角值
:return:
"""
points = [x1 + radius, y1,
x1 + radius, y1,
x2 - radius, y1,
x2 - radius, y1,
x2, y1,
x2, y1 + radius,
x2, y1 + radius,
x2, y2 - radius,
x2, y2 - radius,
x2, y2,
x2 - radius, y2,
x2 - radius, y2,
x1 + radius, y2,
x1 + radius, y2,
x1, y2,
x1, y2 - radius,
x1, y2 - radius,
x1, y1 + radius,
x1, y1 + radius,
x1, y1]
return cv.create_polygon(points, **kwargs, smooth=True)
def validate_ip_address(ip_address):
"""
匹配ip地址格式是否规范
:param ip_address: IP地址
:return: Boolean
"""
# 定义IP地址的正则表达式模式
pattern_with_subnet = r'^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})/(\d{1,2})$'
pattern_without_subnet = r'^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$'
# 使用re模块进行匹配
match_with_subnet = re.match(pattern_with_subnet, ip_address)
match_without_subnet = re.match(pattern_without_subnet, ip_address)
if match_with_subnet:
# 带有子网掩码的IP地址
# 检查每个组件的取值范围是否在 0-255 之间
for group in match_with_subnet.groups()[:4]:
if not (0 <= int(group) <= 255):
return False
# 检查子网掩码的取值范围是否在 0-32 之间
subnet_mask = int(match_with_subnet.groups()[4])
if not (0 <= subnet_mask <= 32):
return False
return True
elif match_without_subnet:
# 不带子网掩码的IP地址
# 检查每个组件的取值范围是否在 0-255 之间
for group in match_without_subnet.groups():
if not (0 <= int(group) <= 255):
return False
return True
else:
# IP地址格式不正确
return False
class ExportUtil():
def __init__(self, path):
self.conn = sqlite3.connect('./network.db')
self.path = path
def get_table_names(self):
cursor = self.conn.cursor()
cursor.execute("SELECT name FROM sqlite_master WHERE type='table';") # 如果你使用SQLite数据库
tables = cursor.fetchall()
cursor.close()
return [table[0] for table in tables]
def export(self):
tables = self.get_table_names()
with pd.ExcelWriter(self.path, engine='openpyxl') as writer:
for table in tables:
table_name = table
# a. 从数据库中获取表的数据并存储在DataFrame中
query = f"SELECT * FROM {table_name}"
df = pd.read_sql(query, self.conn)
# b. 使用Pandas将数据写入Excel文件的不同sheet中
df.to_excel(writer, sheet_name=table_name, index=False)
def import_data(self):
excel_file = pd.ExcelFile(self.path)
sheet_names = excel_file.sheet_names
print(sheet_names)
cursor = self.conn.cursor()
for sheet_name in sheet_names:
# 4. 使用 Pandas 读取工作表数据
df = pd.read_excel(excel_file, sheet_name=sheet_name)
# 5. 获取工作表的列名
columns = df.columns.tolist()
# 6. 构造插入语句
columns_str = ', '.join(columns)
placeholders = ', '.join(['?' for _ in range(len(columns))])
sql = f"INSERT INTO {sheet_name} ({columns_str}) VALUES ({placeholders})"
# 7. 将数据插入数据库
for index, row in df.iterrows():
# 8. 使用动态生成的 SQL 语句将数据插入数据库
cursor.execute(sql, tuple(row))
self.conn.commit()
class RouterConfigWindow(tk.Toplevel):
def __init__(self, parent, router_obj):
super().__init__(parent)
self.geometry("435x433+350+200")
self.title(f"{router_obj.ObjLabel}路由表配置")
self.router_obj = router_obj
self.interface_entries = []
self.router_table = {}
self.create_interface_inputs()
self.create_router_table()
def create_interface_inputs(self):
label_text = ["接口1", "接口2", "接口3", "接口4"]
for i in range(4):
label = tk.Label(self, text=label_text[i], font=("黑体", 16))
label.grid(row=i, column=0, padx=10, pady=5, sticky="w")
entry = tk.Entry(self, width=20, font=("黑体", 16),)
entry.grid(row=i, column=1, padx=10, pady=5, sticky="w")
self.interface_entries.append(entry)
button = tk.Button(self, text="添加", font=("黑体", 16), command=lambda index=i: self.add_router_entry(index))
button.grid(row=i, column=2, padx=10, pady=5)
lab = LabelFrame(self, text="示例")
lab.grid(row=4, column=0, columnspan=3, sticky=W, padx=20)
Label(lab, text="10.1.2.0/24 或者 10.1.2.12" if self.router_obj.ObjType == 2 else "MAC11", font=("黑体", 16)).pack()
def create_router_table(self):
def on_right_click(event):
row = self.router_treeview.identify_row(event.y) # 获取鼠标位置的行索引
if row:
self.router_treeview.selection_set(row) # 选中该行
delete_menu.post(event.x_root, event.y_root) # 在鼠标位置弹出删除菜单
def delete_row():
selected_items = self.router_treeview.selection() # 获取选中的行
for item in selected_items:
ifs, network = int(self.router_treeview.item(item)["values"][0][-1:]), self.router_treeview.item(item)["values"][1]
self.router_obj.delete_config(ifs, network)
self.router_treeview.delete(item)
self.router_table_frame = tk.Frame(self)
self.router_table_frame.grid(row=5, column=0, columnspan=3, padx=10, pady=5)
style = ttk.Style()
style.configure("Custom.Treeview.Heading", font=("宋体", 15))
style.configure("Custom.Treeview", rowheight=30, font=("宋体", 15))
self.router_treeview = ttk.Treeview(self.router_table_frame, style="Custom.Treeview", columns=("Interface", "Route"), show="headings")
self.router_treeview.heading("Interface", text="接口")
self.router_treeview.heading("Route", text="网段")
self.router_treeview.pack(side="left", fill="both")
scrollbar = ttk.Scrollbar(self.router_table_frame, orient="vertical", command=self.router_treeview.yview)
scrollbar.pack(side="right", fill="y")
self.router_treeview.configure(yscrollcommand=scrollbar.set)
self.router_table = self.router_obj.router_table
self.router_treeview.bind("<Button-3>", on_right_click)
# 创建删除菜单
delete_menu = tk.Menu(self.master, tearoff=False)
delete_menu.add_command(label="删除", command=delete_row)
self.update_router_table()
def add_router_entry(self, index):
entry_text = self.interface_entries[index].get()
try:
ipaddress.ip_network(entry_text)
if isinstance(self.router_obj, SimRouter):
if not validate_ip_address(entry_text):
messagebox.showerror("注意", message="添加的网段信息格式不合格")
self.interface_entries[index].delete(0, tk.END)
self.focus_set()
return
if entry_text:
if index + 1 in self.router_table:
self.router_table[index + 1].append(entry_text)
else:
self.router_table[index + 1] = [entry_text]
self.interface_entries[index].delete(0, tk.END)
self.router_obj.add_config(entry_text, index + 1)
self.update_router_table()
self.master.message.show_message(f"{self.router_obj.ObjLabel}添加配置{entry_text}成功!")
except:
messagebox.showerror("注意", message="网段格式错误!网段示例如下:\n10.1.2.0/24\n10.1.2.12")
return
def update_router_table(self):
self.router_treeview.delete(*self.router_treeview.get_children())
for i, entrys in self.router_table.items():
for entry in entrys:
self.router_treeview.insert("", "end", values=(f"接口{i}", entry))
class SwitchConfigWindow(RouterConfigWindow):
def __init__(self, parent, router_obj):
super().__init__(parent, router_obj)
self.geometry("435x433+350+200")
self.title(f"{router_obj.ObjLabel}交换表配置")
self.router_obj = router_obj
self.interface_entries = []
self.router_table = {}
self.create_interface_inputs()
self.create_router_table()
def create_router_table(self):
def on_right_click(event):
row = self.router_treeview.identify_row(event.y) # 获取鼠标位置的行索引
if row:
self.router_treeview.selection_set(row) # 选中该行
delete_menu.post(event.x_root, event.y_root) # 在鼠标位置弹出删除菜单
def delete_row():
selected_items = self.router_treeview.selection() # 获取选中的行
for item in selected_items:
ifs, network = int(self.router_treeview.item(item)["values"][0][-1:]), self.router_treeview.item(item)["values"][1]
self.router_obj.delete_config(ifs, network)
self.router_treeview.delete(item)
self.router_table_frame = tk.Frame(self)
self.router_table_frame.grid(row=5, column=0, columnspan=3, padx=10, pady=5)
self.router_treeview = ttk.Treeview(self.router_table_frame, columns=("Interface", "Route"), show="headings")
self.router_treeview.heading("Interface", text="接口")
self.router_treeview.heading("Route", text="mac")
self.router_treeview.pack(side="left", fill="both")
scrollbar = ttk.Scrollbar(self.router_table_frame, orient="vertical", command=self.router_treeview.yview)
scrollbar.pack(side="right", fill="y")
self.router_treeview.configure(yscrollcommand=scrollbar.set)
self.router_table = self.router_obj.mac_table
self.router_treeview.bind("<Button-3>", on_right_click)
# 创建删除菜单
delete_menu = tk.Menu(self.master, tearoff=False)
delete_menu.add_command(label="删除", command=delete_row)
self.update_router_table()
def add_router_entry(self, index):
entry_text = self.interface_entries[index].get()
if isinstance(self.router_obj, SimRouter):
if not validate_ip_address(entry_text):
messagebox.showerror("注意", message="添加的网段信息格式不合格")
self.interface_entries[index].delete(0, tk.END)
self.focus_set()
return
if entry_text:
if index + 1 in self.router_table:
self.router_table[index + 1].append(entry_text)
else:
self.router_table[index + 1] = [entry_text]
self.interface_entries[index].delete(0, tk.END)
self.router_obj.add_config(entry_text, index + 1)
self.master.message.show_message(f"{self.router_obj.ObjLabel}添加配置{entry_text}成功!")
self.update_router_table()
class TransferAnimate:
"""
校验动画
"""
def __init__(self, master, flag=False):
self.master = master
self.flag = flag
self.width, self.height = 320, 140
self.host_img = ImageTk.PhotoImage(
Image.open(sys.path[0] + "/../datas/images/主机@2x.png").resize((40, 40)))
self.filename = ImageTk.PhotoImage(Image.open("../datas/images/背景@2x.png").resize((self.width, self.height)))
self.toplevel = Toplevel(alpha=0.9)
self.toplevel.geometry("{}x{}+200+150".format(self.width, self.height))
self.toplevel.title("校验")
self.toplevel.resizable(width=False, height=False)
self.canvas = Canvas(self.toplevel, width=self.width, height=self.height, bg="red")
self.canvas.place(x=0, y=0, anchor=NW)
back = self.canvas.create_image(10, 20, image=master.check_filename)
self.send_x, self.receive_x, self.obj_y = 50, self.width - 50, self.height / 2 - 20
self.canvas.create_image(self.send_x, self.obj_y, image=master.host_img)
self.canvas.create_image(self.receive_x, self.obj_y, image=master.host_img)
line = self.canvas.create_line(self.send_x, self.obj_y, self.receive_x, self.obj_y, width=2, fill="#c372f0")
self.canvas.tag_lower(line)
self.canvas.tag_lower(back)
self.animate()
def animate(self):
for i in range(3):
self.canvas.create_image(self.send_x, self.obj_y, image=self.master.pack_img, tags="check_img")
self.move(self.canvas, self.receive_x, self.obj_y, 500)
self.canvas.delete("check_img")
self.canvas.update()
self.canvas.create_image(self.receive_x - self.send_x - 45, self.obj_y, image=self.master.true_img if self.flag else self.master.false_img)
self.canvas.update()
sleep(2)
if not self.flag:
messagebox.showerror("提示", "校验失败,请检查组件{}的相关配置!".format(self.master.check_error_obj.ObjLabel))
self.toplevel.destroy()
def move(self, cv, target_x, target_y, duration):
start_x, start_y = cv.coords("check_img")
distance_x = target_x - start_x
distance_y = target_y - start_y
steps = duration // 10 # 以10毫秒为间隔进行移动
step_x = distance_x / steps
step_y = distance_y / steps
self._move_step(cv, start_x, start_y, target_x, target_y, step_x, step_y, steps)
def _move_step(self, cv, start_x, start_y, target_x, target_y, step_x, step_y, steps):
if steps > 0:
new_x = start_x + step_x
new_y = start_y + step_y
cv.coords("check_img", new_x, new_y)
cv.update() # 更新画布显示
sleep(0.01) # 添加延迟以控制动画速度
self._move_step(cv, new_x, new_y, target_x, target_y, step_x, step_y, steps - 1)
else:
cv.coords("check_img", target_x, target_y)
cv.delete("check_img")

Binary file not shown.

Before

Width:  |  Height:  |  Size: 103 KiB

After

Width:  |  Height:  |  Size: 77 KiB

Binary file not shown.

@ -1,8 +1,34 @@
import sys
import sqlite3
import pandas as pd
import os
import xlwt
from PIL import Image
path = sys.path[0] + "/../datas/images/packet.png"
Image.open(path).resize((60, 60)).save(path)
class ExportUtil():
def __init__(self, path):
self.conn = sqlite3.connect('./network.db')
self.path = path
def get_table_names(self):
cursor = self.conn.cursor()
cursor.execute("SELECT name FROM sqlite_master WHERE type='table';") # 如果你使用SQLite数据库
tables = cursor.fetchall()
cursor.close()
return [table[0] for table in tables]
def export(self):
tables = self.get_table_names()
with pd.ExcelWriter(self.path, engine='openpyxl') as writer:
for table in tables:
table_name = table
# a. 从数据库中获取表的数据并存储在DataFrame中
query = f"SELECT * FROM {table_name}"
df = pd.read_sql(query, self.conn)
# b. 使用Pandas将数据写入Excel文件的不同sheet中
df.to_excel(writer, sheet_name=table_name, index=False)
export = ExportUtil("./data.xlsx")
export.export()

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 248 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.9 KiB

@ -0,0 +1,55 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="34px" height="40px" viewBox="0 0 34 40" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<title>主机</title>
<defs>
<linearGradient x1="50%" y1="0%" x2="50%" y2="100%" id="linearGradient-1">
<stop stop-color="#0055D7" offset="0%"></stop>
<stop stop-color="#4BC1FF" offset="100%"></stop>
</linearGradient>
<linearGradient x1="50%" y1="0%" x2="50%" y2="100%" id="linearGradient-2">
<stop stop-color="#0042BE" offset="0%"></stop>
<stop stop-color="#0073FC" offset="100%"></stop>
</linearGradient>
<linearGradient x1="34.9365234%" y1="39.183214%" x2="50%" y2="70.6841363%" id="linearGradient-3">
<stop stop-color="#0054D5" offset="0%"></stop>
<stop stop-color="#2A92EE" offset="100%"></stop>
</linearGradient>
<linearGradient x1="78.125%" y1="66.0866477%" x2="21.875%" y2="27.2061435%" id="linearGradient-4">
<stop stop-color="#3DA5FF" offset="0%"></stop>
<stop stop-color="#7EFFFF" offset="100%"></stop>
</linearGradient>
<linearGradient x1="50%" y1="0%" x2="50%" y2="77.6337595%" id="linearGradient-5">
<stop stop-color="#0080E3" offset="0%"></stop>
<stop stop-color="#0072C4" offset="100%"></stop>
</linearGradient>
<linearGradient x1="88.7402344%" y1="46.21875%" x2="21.1230469%" y2="53.78125%" id="linearGradient-6">
<stop stop-color="#8FC4FE" offset="0%"></stop>
<stop stop-color="#1896F6" offset="100%"></stop>
</linearGradient>
<linearGradient x1="13.234747%" y1="63.3167614%" x2="100%" y2="63.3167614%" id="linearGradient-7">
<stop stop-color="#7E8CAA" offset="0%"></stop>
<stop stop-color="#C7CDD9" offset="100%"></stop>
</linearGradient>
<linearGradient x1="50.6091477%" y1="44.7228065%" x2="48.1508876%" y2="50%" id="linearGradient-8">
<stop stop-color="#6B7997" offset="0%"></stop>
<stop stop-color="#4B4E55" offset="100%"></stop>
</linearGradient>
</defs>
<g id="页面-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="4网络构建与联通V2.0" transform="translate(-268.000000, -696.000000)">
<g id="主机" transform="translate(268.000000, 696.000000)">
<polygon id="路径-81" fill="url(#linearGradient-1)" points="23.8461538 30 23.8461538 31.5384615 30.7692308 33.8461538 16.9230769 40 6.15384615 35.3846154 10 33.8461538 18.4615385 30 23.8461538 27.6923077"></polygon>
<polygon id="路径-82" fill="url(#linearGradient-2)" points="16.9230769 40 16.9230769 35.3846154 16.9230769 30 6.15384615 35.3846154"></polygon>
<polygon id="路径-88" fill="url(#linearGradient-3)" points="26.1538462 32.3076923 16.9230769 35.3846154 16.9230769 30 23.8461538 27.6923077 23.8461538 31.5384615"></polygon>
<polygon id="路径-77" fill="url(#linearGradient-4)" points="11.5384615 33.8461538 8.46153846 8.46153846 30.7692308 0 33.8461538 24.6153846"></polygon>
<polygon id="路径-78" fill="url(#linearGradient-5)" points="11.5384615 33.8461538 1.53846154 27.6923077 0 8.46153846 8.46153846 8.46153846"></polygon>
<polygon id="路径-79" fill="url(#linearGradient-6)" points="30.7692308 0 20.7692308 0.769230769 0 8.46153846 8.46153846 8.46153846"></polygon>
<polygon id="路径-80" fill="url(#linearGradient-7)" points="11.5384615 10 29.2307692 3.84615385 31.5384615 22.3076923 13.8461538 30"></polygon>
<polygon id="路径-83" fill="url(#linearGradient-8)" points="11.5384615 10 13.0769231 10 15.3846154 29.2307692 13.8461538 30"></polygon>
<line x1="29.2307692" y1="3.84615385" x2="31.5384615" y2="22.3076923" id="路径-85" stroke="#0056D7" stroke-width="0.769230769"></line>
<line x1="29.2307692" y1="3.84615385" x2="11.5384615" y2="10" id="路径-86" stroke="#2DA2E9" stroke-width="0.769230769"></line>
<line x1="31.5384615" y1="22.3076923" x2="13.8461538" y2="30" id="路径-86" stroke="#92D6FF" stroke-width="0.769230769"></line>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.2 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 112 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.5 KiB

@ -0,0 +1,391 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="54px" height="23px" viewBox="0 0 54 23" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<title>交换机</title>
<defs>
<linearGradient x1="13.6935089%" y1="47.3733367%" x2="98.4463875%" y2="51.0994595%" id="linearGradient-1">
<stop stop-color="#8FC4FE" offset="0%"></stop>
<stop stop-color="#1896F6" offset="100%"></stop>
</linearGradient>
<linearGradient x1="8.49955214%" y1="56.2692825%" x2="100%" y2="43.7307175%" id="linearGradient-2">
<stop stop-color="#3DA5FF" offset="0%"></stop>
<stop stop-color="#7EFFFF" offset="100%"></stop>
</linearGradient>
<linearGradient x1="50%" y1="0%" x2="50%" y2="77.6337595%" id="linearGradient-3">
<stop stop-color="#0080E3" offset="0%"></stop>
<stop stop-color="#0072C4" offset="100%"></stop>
</linearGradient>
<filter x="-86.1%" y="-83.3%" width="272.1%" height="266.7%" filterUnits="objectBoundingBox" id="filter-4">
<feGaussianBlur stdDeviation="0.327635328" in="SourceGraphic"></feGaussianBlur>
</filter>
<filter x="-86.1%" y="-83.3%" width="272.1%" height="266.7%" filterUnits="objectBoundingBox" id="filter-5">
<feGaussianBlur stdDeviation="0.327635328" in="SourceGraphic"></feGaussianBlur>
</filter>
<polygon id="path-6" points="0.640744615 0.660701538 1.65175385 0.660701538 1.65175385 2.07608615 0.640744615 2.07608615"></polygon>
<polygon id="path-8" points="0.615267692 0.670326154 1.65175385 0.670326154 1.65175385 2.08571077 0.615267692 2.08571077"></polygon>
<polygon id="path-10" points="0.577193846 0.680092308 1.65175385 0.680092308 1.65175385 2.09547692 0.577193846 2.09547692"></polygon>
<polygon id="path-12" points="0.532609231 0.691132308 1.65175385 0.691132308 1.65175385 2.10651692 0.532609231 2.10651692"></polygon>
<polygon id="path-14" points="0.472030769 0.701464615 1.65175385 0.701464615 1.65175385 2.11684923 0.472030769 2.11684923"></polygon>
<polygon id="path-16" points="0.410461538 0.00297230769 1.65175385 0.00297230769 1.65175385 1.41835692 0.410461538 1.41835692"></polygon>
<polygon id="path-18" points="0.0428861538 0.0795446154 1.45827077 0.0795446154 1.45827077 1.41538462 0.0428861538 1.41538462"></polygon>
<polygon id="path-20" points="0.619938462 0.0837907692 2.03532308 0.0837907692 2.03532308 1.41538462 0.619938462 1.41538462"></polygon>
<polygon id="path-22" points="0.478258462 0.0837907692 1.89364308 0.0837907692 1.89364308 1.41538462 0.478258462 1.41538462"></polygon>
<polygon id="path-24" points="0.402535385 0.0782707692 1.81792 0.0782707692 1.81792 1.41538462 0.402535385 1.41538462"></polygon>
<polygon id="path-26" points="0.351156923 0.0733169231 1.76654154 0.0733169231 1.76654154 1.41538462 0.351156923 1.41538462"></polygon>
<polygon id="path-28" points="0.29256 0.06992 1.70794462 0.06992 1.70794462 1.41538462 0.29256 1.41538462"></polygon>
<polygon id="path-30" points="0.246843077 0.0622769231 1.66222769 0.0622769231 1.66222769 1.41538462 0.246843077 1.41538462"></polygon>
<polygon id="path-32" points="0.201550769 0.0561907692 1.61693538 0.0561907692 1.61693538 1.41538462 0.201550769 1.41538462"></polygon>
<polygon id="path-34" points="0.156541538 0.0505292308 1.57192615 0.0505292308 1.57192615 1.41538462 0.156541538 1.41538462"></polygon>
<polygon id="path-36" points="0.110966154 0.0394892308 1.52635077 0.0394892308 1.52635077 1.41538462 0.110966154 1.41538462"></polygon>
<polygon id="path-38" points="0.0660984615 0.0326953846 1.48148308 0.0326953846 1.48148308 1.41538462 0.0660984615 1.41538462"></polygon>
<polygon id="path-40" points="0.0203815385 0.0209476923 1.43576615 0.0209476923 1.43576615 1.41538462 0.0203815385 1.41538462"></polygon>
<polygon id="path-42" points="0.683913846 0.0133046154 2.09929846 0.0133046154 2.09929846 1.41538462 0.683913846 1.41538462"></polygon>
</defs>
<g id="页面-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="4网络构建与联通V2.0" transform="translate(-93.000000, -705.000000)">
<g id="交换机" transform="translate(120.000000, 716.500000) scale(-1, 1) translate(-120.000000, -716.500000) translate(93.000000, 705.000000)">
<g id="编组-11">
<polygon id="路径-58" fill="url(#linearGradient-1)" points="13.4190069 12.2371795 53.3905169 8.84615385 35.3752544 0 0 2.35897436"></polygon>
<polygon id="路径-59" fill="url(#linearGradient-2)" points="53.3905169 8.84615385 53.3905169 18.8717949 13.4190069 23 13.4190069 12.2371795"></polygon>
<polygon id="路径-60" fill="url(#linearGradient-3)" points="0 2.35897436 13.4190069 12.2371795 13.4190069 23 0 12.6794872"></polygon>
<path d="M25.5947804,19.3515137 L25.0201833,19.3716737 L24.9201833,19.3786737 L24.9811833,19.3736737 L24.6525948,19.3860849 L24.6525948,19.170015 L24.8239013,19.1786578 L24.8239013,19.0317303 L25.1661833,19.0196737 L25.1665142,17.3463855 L23.4534495,17.4953992 L23.4531833,19.1276737 L23.7960625,19.1008727 L23.7960625,19.2478002 L23.9673689,19.2391574 L23.9673689,19.4552272 L23.0251833,19.507084 L23.0251833,17.1735296 L25.5947804,17.0006737 L25.5947804,19.3515137 Z" id="形状结合" fill="#FFFFFF" transform="translate(24.309982, 18.253879) rotate(-2.000000) translate(-24.309982, -18.253879) "></path>
<path d="M22.0258956,19.7938214 L21.4512985,19.8139814 L21.3512985,19.8209814 L21.4122985,19.8159814 L21.08371,19.8283926 L21.08371,19.6123227 L21.2550165,19.6209655 L21.2550165,19.474038 L21.5972985,19.4619814 L21.5976294,17.7886932 L19.8845647,17.9377069 L19.8842985,19.5699814 L20.2271776,19.5431804 L20.2271776,19.6901079 L20.3984841,19.6814651 L20.3984841,19.8975349 L19.4562985,19.9493917 L19.4562985,17.6158373 L22.0258956,17.4429814 L22.0258956,19.7938214 Z" id="形状结合" fill="#FFFFFF" transform="translate(20.741097, 18.696187) rotate(-2.000000) translate(-20.741097, -18.696187) "></path>
<g id="编组-8" transform="translate(33.355051, 16.388638) rotate(-2.000000) translate(-33.355051, -16.388638) translate(27.855051, 12.888638)">
<polygon id="矩形" stroke="#FFFFFF" stroke-width="0.5" points="0 0.810897436 10.4687288 0 10.4687288 5.67628205 0 6.48717949"></polygon>
<polygon id="矩形" fill="#FFFFFF" points="0 3.37873932 10.4687288 2.56784188 10.4687288 3.24358974 0 4.05448718"></polygon>
<line x1="2.6171822" y1="0.540598291" x2="2.6171822" y2="6.35202991" id="路径-61" stroke="#FFFFFF" stroke-width="0.5"></line>
<line x1="5.2343644" y1="0.405448718" x2="5.2343644" y2="6.21688034" id="路径-61" stroke="#FFFFFF" stroke-width="0.5"></line>
<line x1="7.98240571" y1="0.135149573" x2="7.98240571" y2="5.9465812" id="路径-61" stroke="#FFFFFF" stroke-width="0.5"></line>
</g>
<g id="编组-8" transform="translate(45.701249, 15.072345) rotate(-2.000000) translate(-45.701249, -15.072345) translate(40.201249, 11.572345)">
<polygon id="矩形" stroke="#FFFFFF" stroke-width="0.5" points="0 0.810897436 10.4687288 0 10.4687288 5.67628205 0 6.48717949"></polygon>
<polygon id="矩形" fill="#FFFFFF" points="0 3.37873932 10.4687288 2.56784188 10.4687288 3.24358974 0 4.05448718"></polygon>
<line x1="2.6171822" y1="0.540598291" x2="2.6171822" y2="6.35202991" id="路径-61" stroke="#FFFFFF" stroke-width="0.5"></line>
<line x1="5.2343644" y1="0.405448718" x2="5.2343644" y2="6.21688034" id="路径-61" stroke="#FFFFFF" stroke-width="0.5"></line>
<line x1="7.98240571" y1="0.135149573" x2="7.98240571" y2="5.9465812" id="路径-61" stroke="#FFFFFF" stroke-width="0.5"></line>
</g>
<g id="编组-9" transform="translate(16.131359, 14.006410)" fill="#18D6FF">
<ellipse id="椭圆形" filter="url(#filter-4)" cx="0.571021571" cy="0.58974359" rx="1" ry="1"></ellipse>
<ellipse id="椭圆形" cx="0.571021571" cy="0.58974359" rx="1" ry="1"></ellipse>
</g>
<g id="编组-9" transform="translate(16.131359, 16.365385)" fill="#18D6FF">
<ellipse id="椭圆形" filter="url(#filter-5)" cx="0.571021571" cy="0.58974359" rx="1" ry="1"></ellipse>
<ellipse id="椭圆形" cx="0.571021571" cy="0.58974359" rx="1" ry="1"></ellipse>
</g>
<g id="编组-10" transform="translate(1.998575, 5.750000)" fill="#0A609F" stroke="#0865A7" stroke-width="0.5">
<line x1="0" y1="0" x2="9.42185592" y2="6.78205128" id="路径-62"></line>
<line x1="0" y1="1.62179487" x2="9.42185592" y2="8.40384615" id="路径-62"></line>
<line x1="0" y1="3.39102564" x2="9.42185592" y2="10.1730769" id="路径-62"></line>
<line x1="0" y1="5.16025641" x2="9.42185592" y2="11.9423077" id="路径-62"></line>
<line x1="0" y1="6.92948718" x2="9.42185592" y2="13.7115385" id="路径-62"></line>
</g>
<polygon id="矩形" stroke="#0865A7" stroke-width="0.5" fill="#0A609F" points="12.2769638 15.1858974 12.8479853 15.9230769 12.8479853 18.4294872 12.2769638 17.6923077"></polygon>
<polygon id="矩形" stroke="#0865A7" stroke-width="0.5" fill="#0A609F" points="0.428266178 6.78205128 0.999287749 7.51923077 0.999287749 10.025641 0.428266178 9.28846154"></polygon>
</g>
<g id="编组" transform="translate(17.692308, 2.653846)">
<g transform="translate(14.153846, 2.225423)">
<mask id="mask-7" fill="white">
<use xlink:href="#path-6"></use>
</mask>
<g id="Clip-45"></g>
<polygon id="Fill-44" fill="#0F819B" mask="url(#mask-7)" points="1.15806769 1.99116308 1.51332923 0.755532308 1.53880615 0.745624615 1.19486769 1.98267077"></polygon>
</g>
<g transform="translate(14.153846, 2.225423)">
<mask id="mask-9" fill="white">
<use xlink:href="#path-8"></use>
</mask>
<g id="Clip-49"></g>
<polygon id="Fill-48" fill="#0F859F" mask="url(#mask-9)" points="1.13188308 2.00078769 1.47440615 0.765156923 1.51403692 0.755249231 1.15877538 1.99088"></polygon>
</g>
<g transform="translate(14.153846, 2.225423)">
<mask id="mask-11" fill="white">
<use xlink:href="#path-10"></use>
</mask>
<g id="Clip-57"></g>
<polygon id="Fill-56" fill="#1089A3" mask="url(#mask-11)" points="1.09451692 2.01055385 1.43704 0.773507692 1.47525538 0.765015385 1.13131692 2.00064615"></polygon>
</g>
<g transform="translate(14.153846, 2.225423)">
<mask id="mask-13" fill="white">
<use xlink:href="#path-12"></use>
</mask>
<g id="Clip-81"></g>
<path d="M1.38891692,0.781716923 C1.39457846,0.780301538 1.39882462,0.780301538 1.40448615,0.778886154 L1.43704,0.773224615 L1.09451692,2.01027077 L1.07045538,2.01876308 C1.06337846,2.02159385 1.05347077,2.02300923 1.04356308,2.02442462 L1.38891692,0.781716923 Z" id="Fill-80" fill="#108CA7" mask="url(#mask-13)"></path>
</g>
<g transform="translate(14.153846, 2.225423)">
<mask id="mask-15" fill="white">
<use xlink:href="#path-14"></use>
</mask>
<g id="Clip-83"></g>
<path d="M1.3156,0.791341538 C1.32126154,0.791341538 1.32692308,0.789926154 1.334,0.788510769 C1.34249231,0.788510769 1.34956923,0.787095385 1.35664615,0.78568 C1.36796923,0.784264615 1.37929231,0.782849231 1.3892,0.781433846 L1.04384615,2.02414154 C1.02544615,2.02838769 1.00563077,2.03121846 0.985815385,2.03546462 L0.970246154,2.03688 L1.3156,0.791341538 Z" id="Fill-82" fill="#108FAB" mask="url(#mask-15)"></path>
</g>
<g transform="translate(14.153846, 2.933116)">
<mask id="mask-17" fill="white">
<use xlink:href="#path-16"></use>
</mask>
<g id="Clip-85"></g>
<path d="M1.3156,0.0836492308 L0.970246154,1.32918769 L0.920707692,1.33768 L1.26747692,0.0893107692 C1.28446154,0.0878953846 1.29861538,0.0850646154 1.3156,0.0836492308" id="Fill-84" fill="#1093AF" mask="url(#mask-17)"></path>
</g>
<polygon id="Fill-96" fill="#0B6173" points="12.4348615 4.50546646 11.9338154 3.95346646 12.2805846 2.70651262 12.7802154 3.25709723"></polygon>
<polygon id="Fill-98" fill="#1198B6" points="15.4211815 3.02228492 15.0758277 4.27065415 12.43472 4.505608 12.7800738 3.25723877"></polygon>
<polygon id="Fill-100" fill="#1093AF" points="12.7085969 3.26290031 12.7807815 3.25723877 12.4354277 4.505608 12.3773969 4.50136185"></polygon>
<polygon id="Fill-102" fill="#108EA9" points="12.7085969 3.26290031 12.2075508 2.71231569 12.2811508 2.70523877 12.7807815 3.25723877"></polygon>
<polygon id="Fill-104" fill="#0A5D6F" points="12.3768308 4.50136185 11.8757846 3.94936185 12.2084 2.71231569 12.7080308 3.26290031"></polygon>
<polygon id="Fill-106" fill="#1192AD" points="12.6214092 3.26148492 12.1203631 2.71090031 12.2081169 2.71231569 12.7091631 3.26290031"></polygon>
<path d="M12.5364862,3.26148492 L12.03544,2.70948492 C12.0651631,2.70948492 12.0934708,2.71090031 12.1217785,2.71090031 L12.6214092,3.26148492 L12.5364862,3.26148492" id="Fill-108" fill="#1088A2"></path>
<polygon id="Fill-109" fill="#1197B3" points="12.5364862 3.26148492 12.6214092 3.26148492 12.7091631 3.26290031 12.3765477 4.50136185 12.1840554 4.50843877 12.1741477 4.50843877 12.5195015 3.26006954"></polygon>
<polygon id="Fill-111" fill="#0B5F72" points="12.1742892 4.50815569 11.6732431 3.95615569 12.0200123 2.70920185 12.5196431 3.25978646"></polygon>
<polygon id="Fill-113" fill="#1192AD" points="12.5199262 3.26006954 12.0202954 2.70948492 12.0358646 2.70948492 12.5369108 3.26148492"></polygon>
<polygon id="Fill-115" fill="#1093AF" points="12.0817231 4.50136185 12.4242462 3.26573108 12.5204923 3.26006954 12.1737231 4.50843877 12.1581538 4.50843877"></polygon>
<polygon id="Fill-117" fill="#0A5D6F" points="12.0817231 4.50136185 11.5806769 3.95077723 11.9246154 2.71373108 12.4242462 3.26573108"></polygon>
<polygon id="Fill-119" fill="#108EA9" points="12.4245292 3.26558954 11.9248985 2.71358954 12.0197292 2.70934338 12.51936 3.259928"></polygon>
<polygon id="Fill-121" fill="#0A5B6C" points="12.0235508 4.49711569 11.5225046 3.94511569 11.8664431 2.70948492 12.3660738 3.26006954"></polygon>
<polygon id="Fill-123" fill="#108FAB" points="12.0235508 4.49711569 12.3660738 3.26006954 12.4241046 3.26573108 12.0815815 4.50136185"></polygon>
<polygon id="Fill-125" fill="#108AA5" points="12.3664985 3.26006954 11.8668677 2.70948492 11.9248985 2.71373108 12.4245292 3.26573108"></polygon>
<polygon id="Fill-127" fill="#0F839D" points="12.3207815 3.24761415 11.8197354 2.69561415 11.8664431 2.709768 12.3660738 3.26035262"></polygon>
<polygon id="Fill-129" fill="#0A596A" points="11.9772677 4.49301108 11.4762215 3.94101108 11.8102523 2.69405723 12.3112985 3.24605723"></polygon>
<path d="M12.2648738,3.24067877 L11.7652431,2.69009415 C11.7808123,2.69150954 11.7949662,2.69292492 11.80912,2.69434031 L12.3101662,3.24634031 C12.2945969,3.24492492 12.2804431,3.24350954 12.2648738,3.24067877" id="Fill-131" fill="#0E7C93"></path>
<path d="M12.3111569,3.24619877 L11.8101108,2.69419877 C11.8143569,2.69419877 11.8171877,2.69561415 11.8200185,2.69561415 L12.3210646,3.24761415 C12.3168185,3.24619877 12.3139877,3.24619877 12.3111569,3.24619877" id="Fill-132" fill="#0E7F97"></path>
<path d="M12.3207815,3.24761415 L12.3660738,3.26035262 L12.0235508,4.49739877 L11.9909969,4.494568 C11.9867508,4.494568 11.9810892,4.49315262 11.9768431,4.49315262 L12.3108738,3.24619877 C12.31512,3.24619877 12.3179508,3.24619877 12.3207815,3.24761415" id="Fill-133" fill="#108CA7"></path>
<path d="M12.2648738,3.24067877 C12.2804431,3.24350954 12.2945969,3.24492492 12.3101662,3.24634031 L11.9775508,4.49329415 C11.97472,4.49329415 11.9718892,4.49329415 11.9704738,4.49187877 C11.9534892,4.49046338 11.9365046,4.489048 11.91952,4.48621723 L12.2648738,3.24067877 Z" id="Fill-135" fill="#1089A3"></path>
<polygon id="Fill-137" fill="#0A5767" points="11.9199446 4.48607569 11.4203138 3.93407569 11.7656677 2.68995262 12.2652985 3.24053723"></polygon>
<path d="M12.2545415,3.23940492 L11.7534954,2.68882031 C11.7577415,2.68882031 11.7619877,2.68882031 11.7648185,2.69023569 L12.2644492,3.24082031 C12.2616185,3.24082031 12.2573723,3.24082031 12.2545415,3.23940492" id="Fill-139" fill="#0D7990"></path>
<path d="M12.2191569,3.23657415 L12.2545415,3.23940492 C12.2573723,3.24082031 12.2616185,3.24082031 12.2644492,3.24082031 L11.9205108,4.48635877 C11.9049415,4.483528 11.8893723,4.48211262 11.8738031,4.47928185 L12.2191569,3.23657415 Z" id="Fill-140" fill="#0F859F"></path>
<polygon id="Fill-142" fill="#0E8199" points="12.2191569 3.23657415 11.7181108 2.68598954 11.7534954 2.68882031 12.2545415 3.23940492"></polygon>
<polygon id="Fill-144" fill="#095565" points="11.8743692 4.47914031 11.3747385 3.92855569 11.7186769 2.685848 12.2197231 3.23643262"></polygon>
<polygon id="Fill-146" fill="#0E7D95" points="12.1728738 3.23374338 11.6718277 2.68174338 11.7185354 2.68598954 12.2195815 3.23657415"></polygon>
<polygon id="Fill-148" fill="#095262" points="11.82936 4.46951569 11.3283138 3.91893108 11.6722523 2.68188492 12.1732985 3.23388492"></polygon>
<path d="M11.82936,4.46951569 L12.1732985,3.23388492 L12.2185908,3.23671569 L11.8746523,4.47942338 C11.8619138,4.478008 11.8534215,4.47659262 11.8435138,4.47517723 L11.82936,4.46951569 Z" id="Fill-150" fill="#0F819B"></path>
<polygon id="Fill-152" fill="#0D758C" points="12.1515015 3.22694954 11.6518708 2.67494954 11.6731015 2.68202646 12.1727323 3.23402646"></polygon>
<polygon id="Fill-154" fill="#094E5D" points="11.7389169 4.45564492 11.2378708 3.90506031 11.5832246 2.663768 12.0828554 3.215768"></polygon>
<polygon id="Fill-156" fill="#0C6C80" points="12.0374215 3.20755877 11.5363754 2.65555877 11.5406215 2.65555877 12.0402523 3.20755877"></polygon>
<polygon id="Fill-157" fill="#084C5A" points="11.6939077 4.44602031 11.1928615 3.89402031 11.5368 2.65555877 12.0378462 3.20755877"></polygon>
<polygon id="Fill-159" fill="#084957" points="11.638 4.43087569 11.1383692 3.88029108 11.4808923 2.64466031 11.9805231 3.19666031"></polygon>
<path d="M11.9697662,3.193688 L11.46872,2.641688 C11.4729662,2.64310338 11.4772123,2.64451877 11.4814585,2.64451877 L11.9810892,3.19651877 C11.9768431,3.19510338 11.9725969,3.19510338 11.9697662,3.193688" id="Fill-161" fill="#0B6579"></path>
<polygon id="Fill-162" fill="#084755" points="11.6262523 4.43087569 11.1266215 3.87887569 11.4691446 2.64182954 11.9701908 3.19382954"></polygon>
<polygon id="Fill-164" fill="#0D738A" points="9.04558154 2.02571262 9.54521231 2.57629723 11.9697662 3.19340492 11.46872 2.64423569"></polygon>
<path d="M11.9808062,3.19651877 L11.4811754,2.64451877 C11.4995754,2.64876492 11.5179754,2.65159569 11.5377908,2.65584185 L12.0374215,3.20784185 C12.0176062,3.20359569 11.9992062,3.19934954 11.9808062,3.19651877" id="Fill-166" fill="#0C687C"></path>
<path d="M12.04096,3.20755877 L11.5399138,2.65555877 L11.5823754,2.66405108 L12.0820062,3.21605108 C12.0678523,3.21322031 12.0551138,3.21038954 12.04096,3.20755877" id="Fill-167" fill="#0C6C80"></path>
<path d="M12.0824308,3.21590954 L11.5828,2.66390954 C11.5969538,2.66674031 11.6125231,2.66815569 11.6280923,2.67098646 L12.1277231,3.22298646 C12.1121538,3.22015569 12.098,3.21732492 12.0824308,3.21590954" id="Fill-168" fill="#0D6F84"></path>
<path d="M12.1280062,3.22270338 L11.62696,2.67070338 C11.6354523,2.67211877 11.6439446,2.67353415 11.6524369,2.67494954 L12.1520677,3.22694954 C12.1435754,3.22553415 12.1350831,3.22411877 12.1280062,3.22270338" id="Fill-169" fill="#0D7288"></path>
<path d="M12.1280062,3.22270338 L11.62696,2.67070338 L12.1280062,3.22270338 Z M12.0827138,3.21562646 L11.7472677,4.42436492 L11.7840677,4.46399569 L12.1280062,3.22270338 C12.1124369,3.21987262 12.0982831,3.21704185 12.0827138,3.21562646 L12.0827138,3.21562646 Z" id="Fill-170" fill="#09505F"></path>
<path d="M12.1280062,3.22270338 C12.1350831,3.22411877 12.1435754,3.22553415 12.1520677,3.22694954 L12.1732985,3.23402646 L11.82936,4.46965723 L11.8038831,4.46824185 L11.7840677,4.46399569 L12.1280062,3.22270338 Z" id="Fill-172" fill="#0E7E97"></path>
<path d="M11.7389169,4.45564492 L12.0828554,3.215768 C12.0970092,3.21718338 12.1125785,3.22001415 12.1281477,3.22284492 L11.7842092,4.46413723 C11.7757169,4.46272185 11.7672246,4.46130646 11.7587323,4.45989108 C11.7516554,4.45847569 11.7445785,4.45706031 11.7389169,4.45564492" id="Fill-174" fill="#0E7B92"></path>
<path d="M12.0374215,3.20755877 L12.0402523,3.20755877 C12.0544062,3.21038954 12.0671446,3.21322031 12.0812985,3.21605108 L11.7387754,4.455928 C11.7217908,4.45309723 11.7076369,4.44885108 11.6934831,4.44602031 L12.0374215,3.20755877 Z" id="Fill-176" fill="#0D778E"></path>
<path d="M11.638,4.43087569 L11.9805231,3.19666031 C11.9989231,3.19949108 12.0187385,3.20373723 12.0371385,3.20798338 L11.6946154,4.44644492 C11.6847077,4.44361415 11.6748,4.44219877 11.6663077,4.439368 L11.638,4.43087569 Z" id="Fill-178" fill="#0D7389"></path>
<path d="M11.9808062,3.19651877 L11.6382831,4.43073415 L11.62696,4.43073415 L11.9694831,3.193688 C11.9737292,3.19510338 11.9779754,3.19510338 11.9808062,3.19651877" id="Fill-180" fill="#0C7085"></path>
<polygon id="Fill-184" fill="#084755" points="9.25576615 4.72244492 8.75472 4.17044492 9.09865846 2.93198338 9.59970462 3.48398338"></polygon>
<polygon id="Fill-186" fill="#084C5A" points="9.22745846 4.74325108 8.72641231 4.19125108 9.07176615 2.94995877 9.57139692 3.50054338"></polygon>
<polygon id="Fill-188" fill="#094E5D" points="9.21429538 4.75004492 8.71324923 4.19804492 9.05860308 2.95533723 9.55823385 3.50733723"></polygon>
<polygon id="Fill-190" fill="#09505F" points="9.18726154 4.76108492 8.68763077 4.20908492 9.03156923 2.96637723 9.53261538 3.51837723"></polygon>
<polygon id="Fill-192" fill="#095262" points="9.16178462 4.77085108 8.66215385 4.21885108 9.00609231 2.97614338 9.50713846 3.526728"></polygon>
<polygon id="Fill-194" fill="#095565" points="9.12371077 4.78189108 8.62408 4.22989108 8.96801846 2.985768 9.46906462 3.537768"></polygon>
<polygon id="Fill-196" fill="#0A5767" points="9.08648615 4.79024185 8.58544 4.23824185 8.93079385 2.99411877 9.43184 3.54611877"></polygon>
<polygon id="Fill-198" fill="#0A596A" points="9.03666462 4.79986646 8.53703385 4.24786646 8.88238769 3.002328 9.38201846 3.554328"></polygon>
<polygon id="Fill-200" fill="#1088A2" points="9.30756923 3.57102954 8.80652308 3.01902954 8.86455385 3.00629108 9.3656 3.55687569"></polygon>
<polygon id="Fill-202" fill="#0A5B6C" points="9.23425231 3.83372492 8.73462154 3.28172492 8.80680615 3.01987877 9.30785231 3.57046338"></polygon>
<polygon id="Fill-204" fill="#108EA9" points="9.27020308 3.56834031 8.77057231 3.01634031 8.80737231 3.01917108 9.30700308 3.57117108"></polygon>
<g transform="translate(7.784615, 2.225423)">
<path d="M1.48629538,1.34008615 L0.985249231,0.789501538 C1.01638769,0.786670769 1.04469538,0.78384 1.07158769,0.781009231 L1.57263385,1.33159385 C1.54574154,1.33584 1.51601846,1.33867077 1.48629538,1.34008615" id="Fill-206" fill="#0D6E84"></path>
<path d="M1.57206769,1.33187692 L1.07102154,0.781292308 C1.07385231,0.781292308 1.07668308,0.779876923 1.07951385,0.779876923 L1.58056,1.33187692 L1.57206769,1.33187692" id="Fill-207" fill="#0C6B80"></path>
</g>
<g transform="translate(7.784615, 2.225423)">
<polygon id="Fill-208" fill="#0F829B" points="1.58027692 1.33187692 1.07923077 0.779876923 1.08064615 0.779876923"></polygon>
<path d="M1.58098462,1.33187692 L1.07993846,0.779876923 C1.0856,0.778461538 1.09126154,0.778461538 1.09692308,0.777046154 L1.59796923,1.32904615 C1.59230769,1.33046154 1.58664615,1.33046154 1.58098462,1.33187692" id="Fill-209" fill="#0E7E96"></path>
</g>
<path d="M9.38216,3.55446954 L8.88111385,3.00246954 C8.89951385,3.00105415 8.91508308,2.99822338 8.93065231,2.99397723 L9.43169846,3.54597723 C9.41471385,3.548808 9.39914462,3.55163877 9.38216,3.55446954" id="Fill-210" fill="#0E7B93"></path>
<path d="M9.43127385,3.54626031 L8.93022769,2.99426031 C8.94438154,2.99284492 8.95712,2.98859877 8.96844308,2.985768 L9.46807385,3.537768 C9.45675077,3.54059877 9.44401231,3.54342954 9.43127385,3.54626031" id="Fill-211" fill="#0E788F"></path>
<g transform="translate(8.492308, 2.225423)">
<path d="M0.976332308,1.31248615 L0.475286154,0.760486154 C0.485193846,0.759070769 0.495101538,0.75624 0.503593846,0.753409231 L1.00464,1.30540923 C0.994732308,1.30824 0.98624,1.30965538 0.976332308,1.31248615" id="Fill-212" fill="#0D758C"></path>
<path d="M1.00393231,1.30555077 L0.502886154,0.753550769 C0.507132308,0.752135385 0.509963077,0.75072 0.514209231,0.75072 L1.01384,1.30130462 L1.00393231,1.30555077" id="Fill-213" fill="#0D7288"></path>
</g>
<path d="M9.50657231,3.52686954 L9.00552615,2.97628492 C9.01543385,2.97345415 9.02392615,2.97062338 9.03241846,2.96637723 L9.53204923,3.51837723 C9.52355692,3.521208 9.51506462,3.52403877 9.50657231,3.52686954" id="Fill-214" fill="#0D6F84"></path>
<g transform="translate(8.492308, 2.225423)">
<path d="M1.03988308,1.29309538 L0.538836923,0.741095385 C0.544498462,0.73968 0.548744615,0.738264615 0.552990769,0.736849231 L1.05262154,1.28743385 C1.04837538,1.28884923 1.04412923,1.29168 1.03988308,1.29309538" id="Fill-215" fill="#0C6C81"></path>
<path d="M1.05304615,1.28757538 L0.552,0.736990769 C0.557661538,0.73416 0.561907692,0.732744615 0.566153846,0.729913846 L1.06578462,1.28191385 C1.06153846,1.28332923 1.05729231,1.28616 1.05304615,1.28757538" id="Fill-216" fill="#0C697D"></path>
</g>
<g transform="translate(8.492308, 2.225423)">
<path d="M1.06620923,1.28205538 L0.565163077,0.730055385 C0.570824615,0.72864 0.575070769,0.725809231 0.579316923,0.724393846 L1.07894769,1.27497846 C1.07470154,1.27780923 1.07045538,1.27922462 1.06620923,1.28205538" id="Fill-217" fill="#0C667A"></path>
<polygon id="Fill-218" fill="#0B6376" points="1.07852308 1.27512 0.578892308 0.724535385 0.578892308 0.724535385"></polygon>
</g>
<g transform="translate(8.492308, 2.225423)">
<path d="M1.09310154,1.26691077 L0.592055385,0.716326154 C0.593470769,0.714910769 0.594886154,0.714910769 0.594886154,0.714910769 L1.09593231,1.26549538 C1.09451692,1.26691077 1.09310154,1.26691077 1.09310154,1.26691077" id="Fill-219" fill="#0B5D6F"></path>
<path d="M1.09579077,1.26549538 L0.594744615,0.714910769 C0.598990769,0.71208 0.603236923,0.709249231 0.606067692,0.706418462 L1.10711385,1.25841846 C1.10286769,1.26124923 1.09862154,1.26266462 1.09579077,1.26549538" id="Fill-220" fill="#0A5A6C"></path>
</g>
<polygon id="Fill-221" fill="#084957" points="9.08507077 2.94217415 9.08082462 2.96057415 9.57196308 3.50125108 9.23227077 4.72414338 9.24076308 4.73405108 9.58611692 3.49275877"></polygon>
<path d="M9.57153846,3.50054338 L9.07190769,2.94995877 C9.07615385,2.947128 9.0804,2.94429723 9.08464615,2.94146646 L9.58569231,3.49205108 C9.58003077,3.49488185 9.57578462,3.49771262 9.57153846,3.50054338" id="Fill-223" fill="#0B6072"></path>
<g transform="translate(8.492308, 2.225423)">
<polygon id="Fill-224" fill="#0A5868" points="1.10697231 1.25856 0.605926154 0.70656 0.607341538 0.70656"></polygon>
<path d="M1.10697231,1.25856 L0.607341538,0.70656 L0.617249231,0.698067692 L1.11688,1.25006769 C1.11404923,1.25289846 1.11121846,1.25572923 1.10697231,1.25856" id="Fill-225" fill="#095565"></path>
<polygon id="Fill-226" fill="#095262" points="1.11730462 1.25020923 0.617673846 0.698209231 0.62192 0.693963077 1.12155077 1.24596308"></polygon>
</g>
<path d="M9.62956923,3.45355262 L9.12852308,2.90155262 C9.13135385,2.89872185 9.13276923,2.89589108 9.1356,2.89306031 L9.63523077,3.44364492 C9.63381538,3.44647569 9.63098462,3.45072185 9.62956923,3.45355262" id="Fill-227" fill="#095060"></path>
<path d="M9.12923077,2.90211877 L9.12215385,2.93042646 L9.61329231,3.47110338 C9.60904615,3.47534954 9.6048,3.47959569 9.59913846,3.48384185 L9.48873846,3.88156492 L9.50572308,3.90138031 L9.63027692,3.45411877 L9.12923077,2.90211877 Z" id="Fill-228" fill="#094D5C"></path>
<g transform="translate(8.492308, 2.225423)">
<path d="M1.12140923,1.24610462 L0.621778462,0.694104615 C0.621778462,0.692689231 0.623193846,0.692689231 0.624609231,0.691273846 L1.12424,1.24327385 C1.12282462,1.24327385 1.12282462,1.24468923 1.12140923,1.24610462" id="Fill-230" fill="#09505F"></path>
<path d="M1.12494769,1.24341538 L0.623901538,0.691415385 C0.626732308,0.688584615 0.628147692,0.687169231 0.630978462,0.684338462 L1.13060923,1.23633846 C1.12919385,1.23775385 1.12636308,1.24058462 1.12494769,1.24341538" id="Fill-231" fill="#094D5C"></path>
<path d="M1.13103385,1.23648 L0.629987692,0.68448 C0.632818462,0.681649231 0.634233846,0.678818462 0.637064615,0.677403077 L1.13669538,1.22798769 C1.13386462,1.23081846 1.13244923,1.23364923 1.13103385,1.23648" id="Fill-232" fill="#084A58"></path>
</g>
<path d="M9.59928,3.48398338 L9.26524923,4.69130646 L9.27374154,4.69979877 L9.61343385,3.47124492 C9.60918769,3.47549108 9.60494154,3.47973723 9.59928,3.48398338" id="Fill-233" fill="#084552"></path>
<polygon id="Fill-235" fill="#0A5B6C" points="8.96405538 4.80680185 8.46300923 4.25621723 8.73476308 3.28243262 9.23439385 3.83443262"></polygon>
<path d="M9.59928,3.48398338 C9.60494154,3.47973723 9.60918769,3.47549108 9.61343385,3.47124492 L9.27374154,4.69979877 L9.25534154,4.72244492 L9.59928,3.48398338 Z" id="Fill-237" fill="#0C7085"></path>
<path d="M9.62900308,3.45355262 L9.62475692,3.47195262 L9.29072615,4.67644492 C9.28931077,4.68210646 9.28506462,4.687768 9.28223385,4.69201415 L9.27374154,4.70050646 L9.61343385,3.47195262 C9.62051077,3.46629108 9.62475692,3.46062954 9.62900308,3.45355262" id="Fill-239" fill="#0C6D81"></path>
<path d="M9.59928,3.48398338 L9.25534154,4.72244492 L9.24118769,4.733768 L9.58512615,3.49247569 C9.59078769,3.48964492 9.59503385,3.48681415 9.59928,3.48398338" id="Fill-241" fill="#0D7389"></path>
<path d="M9.57153846,3.50054338 C9.57578462,3.49771262 9.58003077,3.49488185 9.58569231,3.49205108 L9.24175385,4.73334338 L9.23326154,4.73900492 C9.23043077,4.74042031 9.22901538,4.74183569 9.2276,4.74325108 L9.57153846,3.50054338 Z" id="Fill-243" fill="#0D778E"></path>
<path d="M9.57153846,3.50054338 L9.2276,4.74325108 C9.22618462,4.74325108 9.22476923,4.74466646 9.22335385,4.74466646 L9.21769231,4.74891262 C9.21627692,4.74891262 9.21486154,4.750328 9.21486154,4.750328 L9.5588,3.50762031 C9.56304615,3.50478954 9.56729231,3.50337415 9.57153846,3.50054338" id="Fill-245" fill="#0E7B92"></path>
<path d="M9.21429538,4.75004492 C9.20580308,4.75429108 9.19731077,4.75712185 9.18740308,4.761368 L9.53275692,3.51866031 C9.54124923,3.51441415 9.54974154,3.51158338 9.55823385,3.50733723 L9.21429538,4.75004492 Z" id="Fill-247" fill="#0E7E97"></path>
<path d="M9.16178462,4.77085108 L9.50713846,3.526728 C9.51563077,3.52389723 9.52412308,3.52106646 9.53261538,3.51823569 L9.18726154,4.76094338 C9.18584615,4.76235877 9.18443077,4.76235877 9.18301538,4.76377415 L9.17027692,4.76802031 C9.16744615,4.76943569 9.16461538,4.76943569 9.16178462,4.77085108" id="Fill-249" fill="#0F819B"></path>
<g transform="translate(8.492308, 2.225423)">
<path d="M1.13726154,1.22812923 L0.636215385,0.676129231 C0.639046154,0.673298462 0.640461538,0.670467692 0.643292308,0.667636923 L1.14292308,1.21822154 C1.14150769,1.22105231 1.13867692,1.22529846 1.13726154,1.22812923" id="Fill-251" fill="#095060"></path>
<path d="M1.14278154,1.21850462 L0.643150769,0.666504615 C0.650227692,0.652350769 0.654473846,0.635366154 0.651643077,0.616966154 L1.15268923,1.16896615 C1.15410462,1.18736615 1.15127385,1.20293538 1.14278154,1.21850462" id="Fill-252" fill="#094D5D"></path>
</g>
<path d="M9.12371077,4.78189108 L9.46906462,3.537768 C9.48180308,3.53493723 9.49454154,3.53069108 9.50728,3.52644492 L9.16192615,4.770568 C9.15201846,4.77339877 9.14069538,4.77764492 9.12795692,4.78047569 C9.12654154,4.78047569 9.12512615,4.78189108 9.12371077,4.78189108" id="Fill-253" fill="#0F859F"></path>
<path d="M9.08648615,4.79024185 L9.43184,3.54611877 C9.44457846,3.543288 9.45731692,3.54045723 9.46864,3.53762646 L9.12328615,4.78174954 C9.11196308,4.78458031 9.09922462,4.78741108 9.08648615,4.79024185" id="Fill-255" fill="#1089A3"></path>
<path d="M9.03666462,4.79986646 L9.38201846,3.554328 C9.39900308,3.55149723 9.41598769,3.54866646 9.43155692,3.54583569 L9.08620308,4.78995877 C9.08195692,4.79137415 9.07912615,4.79137415 9.07488,4.79278954 C9.06638769,4.79420492 9.05789538,4.79562031 9.04798769,4.79845108 C9.04515692,4.79845108 9.04091077,4.79845108 9.03666462,4.79986646" id="Fill-257" fill="#108CA7"></path>
<path d="M9.30756923,3.57102954 L9.3656,3.55687569 C9.36984615,3.55546031 9.37550769,3.55546031 9.38258462,3.55404492 L9.03723077,4.79958338 C9.03156923,4.79958338 9.02732308,4.80099877 9.02166154,4.80241415 L8.96363077,4.80666031 L9.23396923,3.83429108 L9.30756923,3.57102954 Z" id="Fill-259" fill="#108FAB"></path>
<polygon id="Fill-261" fill="#094B59" points="9.27020308 3.56834031 8.77057231 3.01634031 8.77057231 3.01492492 9.27020308 3.56550954"></polygon>
<path d="M9.27020308,3.56834031 L9.27020308,3.56550954 C9.30417231,3.56409415 9.33531077,3.56126338 9.36503385,3.55701723 L9.30700308,3.57117108 L9.27020308,3.56834031 Z" id="Fill-263" fill="#094B59"></path>
<polygon id="Fill-267" fill="#108EA9" points="9.26128615 3.56692492 8.76024 3.01492492 8.77014769 3.01634031 9.26977846 3.56834031"></polygon>
<polygon id="Fill-269" fill="#1093AF" points="9.23425231 3.83372492 8.96391385 4.80609415 8.91437538 4.81458646 9.26114462 3.56763262 9.26963692 3.569048 9.30785231 3.57046338"></polygon>
<path d="M11.9537723,0.745780308 L11.9537723,0.750026462 L11.9523569,0.750026462 L11.9537723,0.747195692 C11.9537723,0.747195692 11.9537723,0.747195692 11.9537723,0.745780308" id="Fill-300" fill="#08434F"></path>
<path d="M11.92136,0.783146462 L11.5788369,2.01877723 L11.5519446,2.03010031 L11.8944677,0.795884923 C11.8987138,0.793054154 11.9015446,0.791638769 11.9043754,0.788808 L11.92136,0.783146462 Z" id="Fill-302" fill="#0D778E"></path>
<path d="M11.9621231,0.733324923 L11.9692,0.727663385 L11.6266769,1.96329415 L11.6096923,1.98594031 L11.9536308,0.750309538 L11.9536308,0.746063385 C11.9550462,0.744648 11.9564615,0.743232615 11.9564615,0.741817231 C11.9592923,0.738986462 11.9607077,0.736155692 11.9621231,0.733324923" id="Fill-313" fill="#0B697D"></path>
<path d="M11.8888062,0.798291077 C11.8902215,0.796875692 11.8930523,0.795460308 11.8944677,0.795460308 L11.5519446,2.02967569 L11.5377908,2.03958338 L11.8817292,0.803952615 L11.8888062,0.798291077 Z" id="Fill-319" fill="#0E7B92"></path>
<polygon id="Fill-323" fill="#0E7E97" points="11.8549785 0.813577231 11.8818708 0.803669538 11.5379323 2.03930031 11.5124554 2.05062338"></polygon>
<polygon id="Fill-327" fill="#0F819B" points="11.4859877 2.060248 11.8299262 0.823201846 11.8554031 0.813294154 11.51288 2.05034031"></polygon>
<path d="M11.7914277,0.832968 C11.7985046,0.831552615 11.8069969,0.828721846 11.8140738,0.827306462 L11.8296431,0.823060308 L11.4857046,2.06010646 L11.4489046,2.06859877 L11.7914277,0.832968 Z" id="Fill-333" fill="#0F859F"></path>
<path d="M11.7914277,0.832968 L11.2903815,0.282383385 L11.7914277,0.832968 Z M11.7546277,0.842875692 L11.4220123,2.04029108 L11.4489046,2.06859877 L11.7914277,0.832968 C11.7801046,0.837214154 11.7673662,0.840044923 11.7546277,0.842875692 L11.7546277,0.842875692 Z" id="Fill-356" fill="#095565"></path>
<path d="M11.4092738,2.08515877 L11.7546277,0.842451077 C11.7673662,0.839620308 11.7801046,0.836789538 11.7914277,0.832543385 L11.4489046,2.06817415 L11.4262585,2.08091262 C11.4205969,2.082328 11.4149354,2.08374338 11.4092738,2.08515877" id="Fill-358" fill="#1089A3"></path>
<path d="M11.3594523,2.09492492 L11.7048062,0.850801846 C11.7217908,0.847971077 11.7387754,0.845140308 11.7543446,0.842309538 L11.4089908,2.08501723 C11.3934215,2.087848 11.3764369,2.09209415 11.3594523,2.09492492" id="Fill-360" fill="#108CA7"></path>
<path d="M11.6310646,0.860568 C11.6423877,0.860568 11.6522954,0.857737231 11.6622031,0.856321846 C11.6664492,0.856321846 11.6706954,0.856321846 11.6749415,0.854906462 C11.6848492,0.853491077 11.6947569,0.852075692 11.7046646,0.850660308 L11.3593108,2.09478338 C11.3508185,2.09619877 11.3437415,2.09902954 11.3366646,2.09902954 L11.2871262,2.10469108 L11.6310646,0.860568 Z" id="Fill-365" fill="#108FAB"></path>
<path d="M11.6310646,0.860568 L11.2871262,2.10469108 L11.2489108,2.11318338 L11.59568,0.864814154 C11.6070031,0.863398769 11.6197415,0.861983385 11.6310646,0.860568" id="Fill-367" fill="#1093AF"></path>
<path d="M5.19899077,3.15773723 L5.70003692,3.70973723 C5.68446769,3.70407569 5.67031385,3.69982954 5.65474462,3.694168 L5.31788308,4.908568 L5.35468308,4.94961415 L5.70003692,3.70973723 L5.19899077,3.15773723 Z" id="Fill-481" fill="#07424F"></path>
<path d="M1.60660308,2.81634646 L1.95054154,1.57222338 C1.96328,1.57505415 1.97601846,1.57930031 1.98875692,1.58213108 C1.99017231,1.58213108 1.99300308,1.58354646 1.99583385,1.58354646 L1.65048,2.82908492 C1.64481846,2.82766954 1.63915692,2.82625415 1.63349538,2.82342338 L1.61651077,2.81917723 L1.60660308,2.81634646 Z" id="Fill-561" fill="#0C7085"></path>
<path d="M1.31843077,0.983564923 L1.81947692,1.53414954 C1.81523077,1.53414954 1.8124,1.53273415 1.80956923,1.53131877 L1.57178462,1.26805723 L1.80956923,1.53131877 C1.79824615,1.52707262 1.78692308,1.52282646 1.7756,1.51858031 L1.43873846,2.72873415 L1.47553846,2.77119569 L1.81947692,1.53414954 L1.31843077,0.983564923 Z" id="Fill-585" fill="#07404D"></path>
<path d="M15.68232,2.71967569 C15.7955508,2.78619877 15.8281046,2.85130646 15.7898892,2.90367569 C15.6596738,2.98293723 15.6129662,2.99426031 15.5577662,3.004168 C15.5195508,3.01124492 15.4940738,3.01407569 15.4700123,3.01690646 C15.4530277,3.01832185 15.4374585,3.02115262 15.4204738,3.022568 L12.7807815,3.25752185 C12.6604738,3.26601415 12.5260123,3.26459877 12.3858892,3.25327569 C12.2471815,3.24195262 12.1042277,3.22213723 11.9697662,3.19382954 L9.54521231,2.57530646 L9.64428923,3.39481415 C9.64712,3.41604492 9.64145846,3.43586031 9.63013538,3.45426031 C9.49425846,3.53069108 9.48152,3.53493723 9.46878154,3.537768 C9.45745846,3.54059877 9.44472,3.54342954 9.43056615,3.54626031 C9.41499692,3.54909108 9.39942769,3.55192185 9.38244308,3.55475262 C9.33573538,3.56182954 9.30459692,3.56466031 9.27062769,3.56607569 L6.62102769,3.80244492 C6.58988923,3.80669108 6.55875077,3.80952185 6.52619692,3.81093723 C6.41296615,3.813768 6.31955077,3.81235262 6.22613538,3.80669108 C5.94730462,3.78404492 5.66705846,3.71752185 5.50570462,3.63259877 C5.42078154,3.58306031 5.38398154,3.53493723 5.38539692,3.49247569 C5.38822769,3.41321415 5.52410462,3.34952185 5.76613538,3.33112185 L6.84465846,3.23062954 L7.62170462,3.15986031 L8.01093538,3.12447569 L7.89770462,2.16201415 L5.03721231,1.45149108 L2.78392,1.64398338 C2.72447385,1.64964492 2.66219692,1.65247569 2.59708923,1.65106031 C2.57585846,1.65106031 2.55604308,1.65106031 2.53339692,1.64964492 C2.47819692,1.64822954 2.43856615,1.64681415 2.39752,1.642568 C2.11727385,1.62275262 1.83419692,1.56047569 1.67850462,1.47555262 C1.58367385,1.42035262 1.54545846,1.36515262 1.55819692,1.31702954 C1.57659692,1.24484492 1.70681231,1.18681415 1.93185846,1.16133723 L4.58428923,0.926383385 C4.69468923,0.919306462 4.82207385,0.920721846 4.95087385,0.929214154 C5.09807385,0.940537231 5.24952,0.966014154 5.37973538,0.999983385 L7.51413538,1.52933723 L7.82976615,1.60859877 L7.71936615,0.790506462 C7.72078154,0.702752615 7.85524308,0.631983385 8.09161231,0.616414154 L10.7313046,0.381460308 C10.8544431,0.371552615 10.9889046,0.372968 11.1219508,0.382875692 C11.4078585,0.404106462 11.68952,0.469214154 11.8452123,0.562629538 C11.9556123,0.626321846 11.9895815,0.688598769 11.9570277,0.742383385 C11.8678585,0.807491077 11.8437969,0.817398769 11.8140738,0.827306462 C11.7801046,0.837214154 11.7673662,0.840044923 11.7546277,0.842875692 C11.7376431,0.845706462 11.7220738,0.848537231 11.7036738,0.851368 C11.6810277,0.855614154 11.6569662,0.858444923 11.6314892,0.861275692 C11.6187508,0.862691077 11.6074277,0.862691077 11.5946892,0.864106462 L9.35413538,1.05942954 L9.47727385,2.02330646 L10.1962892,2.20447569 L12.3363508,2.746568 L14.5698277,2.53850646 C14.6915508,2.52859877 14.8260123,2.53001415 14.9576431,2.53992185 C15.24072,2.562568 15.5195508,2.62767569 15.68232,2.71967569" id="Fill-587" fill="#18D6FF"></path>
<path d="M9.54535385,2.57587262 L11.9699077,3.19439569 L11.6259692,4.43144185 L9.50572308,3.902088 L9.63027692,3.45341108 C9.6416,3.43501108 9.64726154,3.41661108 9.64443077,3.39396492 L9.54535385,2.57587262 Z" id="Fill-589" fill="#0E7A92"></path>
<polygon id="Fill-591" fill="#1198B6" points="9.26128615 3.56692492 8.91451692 4.81529415 6.27482462 5.050248 6.62017846 3.80187877"></polygon>
<g transform="translate(5.661538, 3.640808)">
<mask id="mask-19" fill="white">
<use xlink:href="#path-18"></use>
</mask>
<g id="Clip-594"></g>
<path d="M0.887163077,0.168006154 C0.911224615,0.166590769 0.935286154,0.16376 0.959347692,0.160929231 L0.613993846,1.40929846 C0.589932308,1.41212923 0.565870769,1.41354462 0.541809231,1.41354462 L0.887163077,0.168006154 Z" id="Fill-593" fill="#1093AF" mask="url(#mask-19)"></path>
</g>
<g transform="translate(4.953846, 3.640808)">
<mask id="mask-21" fill="white">
<use xlink:href="#path-20"></use>
</mask>
<g id="Clip-596"></g>
<path d="M1.57956923,0.169421538 C1.58381538,0.168006154 1.58947692,0.168006154 1.59513846,0.168006154 L1.24978462,1.41354462 C1.23421538,1.41496 1.22006154,1.41496 1.20590769,1.41496 L1.06012308,1.41354462 L1.40264615,0.176498462 L1.51446154,0.172252308 C1.53003077,0.170836923 1.54418462,0.170836923 1.55833846,0.169421538 L1.57249231,0.169421538 L1.57956923,0.169421538 Z" id="Fill-595" fill="#1197B3" mask="url(#mask-21)"></path>
</g>
<polygon id="Fill-597" fill="#1198B6" points="11.5951138 0.864672615 11.2483446 2.11304185 10.1967138 2.20362646 9.47769846 2.02245723 9.35456 1.05999569"></polygon>
<g transform="translate(4.953846, 3.640808)">
<mask id="mask-23" fill="white">
<use xlink:href="#path-22"></use>
</mask>
<g id="Clip-600"></g>
<polygon id="Fill-599" fill="#1093AF" mask="url(#mask-23)" points="0.967981538 1.40646769 1.31050462 0.169421538 1.40392 0.176498462 1.05998154 1.41354462"></polygon>
</g>
<polygon id="Fill-601" fill="#0D7991" points="6.84522462 3.23105415 6.34417846 2.68046954 7.12122462 2.60970031 7.62227077 3.15886954"></polygon>
<g transform="translate(4.953846, 3.640808)">
<mask id="mask-25" fill="white">
<use xlink:href="#path-24"></use>
</mask>
<g id="Clip-604"></g>
<polygon id="Fill-603" fill="#108FAB" mask="url(#mask-25)" points="0.909950769 1.40094769 1.25247385 0.165316923 1.31050462 0.169563077 0.967981538 1.40660923"></polygon>
</g>
<g transform="translate(4.953846, 3.640808)">
<mask id="mask-27" fill="white">
<use xlink:href="#path-26"></use>
</mask>
<g id="Clip-606"></g>
<polygon id="Fill-605" fill="#108CA7" mask="url(#mask-27)" points="1.19543385 0.161070769 1.25346462 0.165316923 0.909526154 1.40094769 0.864233846 1.39811692"></polygon>
</g>
<g transform="translate(4.953846, 3.640808)">
<mask id="mask-29" fill="white">
<use xlink:href="#path-28"></use>
</mask>
<g id="Clip-608"></g>
<polygon id="Fill-607" fill="#1089A3" mask="url(#mask-29)" points="0.805636923 1.39401231 1.14957538 0.156966154 1.19486769 0.161212308 0.863667692 1.39825846"></polygon>
</g>
<polygon id="Fill-609" fill="#0A5869" points="7.89841231 2.16258031 8.01022769 3.12504185 7.62241231 3.15901108"></polygon>
<g transform="translate(4.953846, 3.640808)">
<mask id="mask-31" fill="white">
<use xlink:href="#path-30"></use>
</mask>
<g id="Clip-614"></g>
<path d="M0.75992,1.38849231 L1.10385846,0.145784615 C1.11235077,0.1472 1.11942769,0.148615385 1.12792,0.150030769 L1.14915077,0.157107692 L0.805212308,1.39415385 L0.789643077,1.39273846 L0.75992,1.38849231 Z" id="Fill-613" fill="#0F859F" mask="url(#mask-31)"></path>
</g>
<g transform="translate(4.953846, 3.640808)">
<mask id="mask-33" fill="white">
<use xlink:href="#path-32"></use>
</mask>
<g id="Clip-616"></g>
<path d="M1.05856615,0.138990769 C1.07413538,0.141821538 1.08828923,0.144652308 1.10385846,0.146067692 L0.75992,1.38877538 C0.744350769,1.38594462 0.730196923,1.38452923 0.714627692,1.38169846 L1.05856615,0.138990769 Z" id="Fill-615" fill="#0F819B" mask="url(#mask-33)"></path>
</g>
<g transform="translate(4.953846, 3.640808)">
<mask id="mask-35" fill="white">
<use xlink:href="#path-34"></use>
</mask>
<g id="Clip-618"></g>
<path d="M1.04328,0.13616 C1.04752615,0.137575385 1.05318769,0.138990769 1.05884923,0.138990769 L0.714910769,1.38169846 C0.705003077,1.38028308 0.695095385,1.37886769 0.685187692,1.37603692 L0.669618462,1.37037538 L1.01355692,0.134744615 L1.04328,0.13616 Z" id="Fill-617" fill="#0E7E97" mask="url(#mask-35)"></path>
</g>
<g transform="translate(4.953846, 3.640808)">
<mask id="mask-37" fill="white">
<use xlink:href="#path-36"></use>
</mask>
<g id="Clip-620"></g>
<path d="M0.967981538,0.123704615 L0.970812308,0.123704615 C0.979304615,0.12512 0.987796923,0.126535385 0.996289231,0.129366154 L1.01327385,0.135027692 L0.669335385,1.37065846 L0.639612308,1.36924308 C0.635366154,1.36782769 0.63112,1.36782769 0.628289231,1.36641231 C0.626873846,1.36641231 0.625458462,1.36641231 0.624043077,1.36499692 L0.967981538,0.123704615 Z" id="Fill-619" fill="#0E7B92" mask="url(#mask-37)"></path>
</g>
<g transform="translate(4.953846, 3.640808)">
<mask id="mask-39" fill="white">
<use xlink:href="#path-38"></use>
</mask>
<g id="Clip-622"></g>
<path d="M0.922406154,0.115495385 L0.935144615,0.116910769 C0.942221538,0.118326154 0.950713846,0.119741538 0.957790769,0.121156923 C0.962036923,0.122572308 0.964867692,0.122572308 0.967698462,0.123987692 L0.62376,1.36528 C0.620929231,1.36528 0.618098462,1.36528 0.615267692,1.36386462 C0.613852308,1.36386462 0.612436923,1.36386462 0.611021538,1.36244923 L0.579883077,1.35254154 L0.922406154,0.115495385 Z" id="Fill-621" fill="#0D778E" mask="url(#mask-39)"></path>
</g>
<g transform="translate(4.953846, 3.640808)">
<mask id="mask-41" fill="white">
<use xlink:href="#path-40"></use>
</mask>
<g id="Clip-624"></g>
<path d="M0.878104615,0.104455385 C0.890843077,0.107286154 0.902166154,0.110116923 0.912073846,0.111532308 L0.921981538,0.115778462 L0.579458462,1.35282462 L0.549735385,1.34999385 C0.546904615,1.34857846 0.544073846,1.34857846 0.539827692,1.34716308 C0.538412308,1.34716308 0.535581538,1.34716308 0.534166154,1.34574769 L0.878104615,0.104455385 Z" id="Fill-623" fill="#0D7389" mask="url(#mask-41)"></path>
</g>
<g transform="translate(4.246154, 3.640808)">
<mask id="mask-43" fill="white">
<use xlink:href="#path-42"></use>
</mask>
<g id="Clip-626"></g>
<path d="M1.54092923,0.0961046154 L1.56216,0.0989353846 C1.56782154,0.100350769 1.57348308,0.100350769 1.57914462,0.101766154 C1.58056,0.103181538 1.58339077,0.103181538 1.58622154,0.104596923 L1.24228308,1.34588923 C1.23945231,1.34588923 1.23520615,1.34447385 1.23237538,1.34447385 L1.21680615,1.34022769 L1.19699077,1.33315077 L1.54092923,0.0961046154 Z" id="Fill-625" fill="#0C7085" mask="url(#mask-43)"></path>
</g>
<polygon id="Fill-627" fill="#0C6D81" points="5.40011692 4.95881415 5.74264 3.721768 5.78651692 3.73733723 5.44399385 4.97438338"></polygon>
<path d="M5.35510769,4.94918954 L5.69904615,3.70931262 C5.71178462,3.71355877 5.72593846,3.71638954 5.73867692,3.72063569 L5.74292308,3.72205108 L5.4004,4.95909723 L5.37633846,4.95768185 C5.36926154,4.95485108 5.36218462,4.95202031 5.35510769,4.94918954" id="Fill-629" fill="#0B697D"></path>
<path d="M5.65502769,3.69402646 C5.66918154,3.699688 5.68475077,3.70393415 5.69890462,3.70959569 L5.35496615,4.94947262 C5.34081231,4.94522646 5.32524308,4.94098031 5.31108923,4.93531877 L5.65502769,3.69402646 Z" id="Fill-631" fill="#0B6579"></path>
<path d="M5.60464,3.67605108 C5.62020923,3.683128 5.63719385,3.68878954 5.65559385,3.69445108 L5.31165538,4.93574338 C5.29891692,4.93149723 5.28759385,4.92725108 5.27627077,4.92158954 L5.25787077,4.91168185 L5.60180923,3.67463569 L5.60464,3.67605108 Z" id="Fill-633" fill="#0B6275"></path>
<path d="M5.20451077,4.88974338 L5.54703385,3.65269723 C5.56260308,3.65977415 5.58100308,3.66685108 5.59798769,3.673928 L5.60081846,3.67534338 L5.25829538,4.91238954 L5.23706462,4.90531262 C5.23564923,4.90531262 5.23423385,4.90531262 5.23281846,4.90389723 C5.22291077,4.89965108 5.21300308,4.89540492 5.20451077,4.88974338" id="Fill-635" fill="#0B5F71"></path>
<path d="M5.54731692,3.65255569 L5.20479385,4.88960185 C5.19064,4.88252492 5.17507077,4.875448 5.16233231,4.86837108 L5.04485538,4.71692492 L5.38454769,3.49261723 C5.38313231,3.53507877 5.42134769,3.58320185 5.50485538,3.63132492 C5.51759385,3.63840185 5.53316308,3.64547877 5.54731692,3.65255569" id="Fill-639" fill="#0A5B6D"></path>
<path d="M7.51413538,1.52947877 L7.72078154,0.786401846 C7.72078154,0.787817231 7.71936615,0.789232615 7.71936615,0.790648 L7.51413538,1.52947877 Z" id="Fill-645" fill="#063843"></path>
<polygon id="Fill-705" fill="#0E7A92" points="5.03650462 1.45078338 7.89841231 2.16272185 7.62241231 3.15915262 6.84536615 3.23133723 4.69256615 2.68641415"></polygon>
<polygon id="Fill-713" fill="#1198B6" points="5.03650462 1.45078338 4.69256615 2.68641415 2.43785846 2.89306031 2.78321231 1.64469108"></polygon>
<path d="M2.72277538,1.65120185 L2.78363692,1.64412492 L2.43686769,2.89249415 C2.41846769,2.89390954 2.39865231,2.89532492 2.37742154,2.89674031 L2.72277538,1.65120185 Z" id="Fill-715" fill="#1093AF"></path>
<path d="M2.59694769,1.65120185 L2.61110154,1.65120185 L2.66064,1.65120185 L2.72291692,1.65120185 L2.37756308,2.89674031 C2.35491692,2.89815569 2.33085538,2.89815569 2.30679385,2.89957108 L2.18790154,2.89674031 L2.53467077,1.64978646 C2.55165538,1.65120185 2.56722462,1.65120185 2.58420923,1.65120185 L2.59694769,1.65120185 Z" id="Fill-717" fill="#1197B3"></path>
<polygon id="Fill-719" fill="#1093AF" points="2.51811077 1.64978646 2.53368 1.64978646 2.18832615 2.89674031 2.09632615 2.88966338 2.43884923 1.65403262"></polygon>
<polygon id="Fill-721" fill="#108FAB" points="2.03787077 2.88555877 2.38180923 1.64851262 2.43984 1.65417415 2.09590154 2.88980492"></polygon>
<polygon id="Fill-723" fill="#108CA7" points="2.32321231 1.64426646 2.38124308 1.64851262 2.03730462 2.88555877 1.97927385 2.88131262"></polygon>
<path d="M1.93341538,2.877208 L2.27876923,1.63166954 L2.28301538,1.63166954 C2.28584615,1.63166954 2.28726154,1.63308492 2.29009231,1.63308492 L2.32264615,1.644408 L1.98012308,2.88145415 L1.93341538,2.877208 Z" id="Fill-725" fill="#1089A3"></path>
<path d="M2.23347692,1.62629108 C2.24904615,1.62770646 2.2632,1.62912185 2.27876923,1.63195262 L1.93341538,2.87749108 L1.90369231,2.87466031 C1.89661538,2.87466031 1.89236923,2.87324492 1.88812308,2.87324492 L2.23347692,1.62629108 Z" id="Fill-729" fill="#0F859F"></path>
<path d="M2.23135385,1.62487569 L1.88741538,2.87324492 C1.886,2.87324492 1.88458462,2.87182954 1.88175385,2.87182954 L1.84353846,2.85767569 L2.17473846,1.62062954 L2.23135385,1.62487569 Z" id="Fill-731" fill="#0F819B"></path>
<polygon id="Fill-733" fill="#0E7E97" points="1.78621538 2.85371262 2.12873846 1.61808185 2.17544615 1.62091262 1.84424615 2.85795877"></polygon>
<path d="M1.74064,2.84819262 L2.08599385,1.60265415 L2.12845538,1.61822338 L1.78593231,2.85385415 L1.76045538,2.85243877 C1.75620923,2.85102338 1.75196308,2.85102338 1.74771692,2.849608 C1.74488615,2.849608 1.74205538,2.84819262 1.74064,2.84819262" id="Fill-735" fill="#0E7B92"></path>
<polygon id="Fill-737" fill="#0D778E" points="1.69648 2.83432185 2.03900308 1.59869108 2.08571077 1.60293723 1.74035692 2.84847569 1.72195692 2.84422954"></polygon>
<path d="M1.99569231,1.58340492 L2.03956923,1.59897415 L1.69704615,2.83460492 L1.67156923,2.83318954 C1.66449231,2.83177415 1.65741538,2.83035877 1.65033846,2.82894338 L1.99569231,1.58340492 Z" id="Fill-739" fill="#0D7389"></path>
<path d="M1.92449846,1.56542954 C1.93299077,1.56826031 1.94148308,1.57109108 1.95139077,1.57250646 L1.60603692,2.81662954 L1.56357538,2.80106031 L1.90609846,1.56401415 L1.92449846,1.56542954 Z" id="Fill-741" fill="#0C6D81"></path>
<polygon id="Fill-743" fill="#0B697D" points="1.51955692 2.78591569 1.86208 1.54886954 1.90595692 1.56443877 1.56343385 2.80148492"></polygon>
<path d="M1.81876923,1.53372492 C1.82018462,1.53514031 1.8216,1.53514031 1.82301538,1.53655569 C1.83009231,1.53797108 1.83716923,1.54080185 1.84283077,1.54221723 L1.86264615,1.54929415 L1.52012308,2.78634031 L1.47624615,2.77077108 L1.81876923,1.53372492 Z" id="Fill-745" fill="#0B6579"></path>
<path d="M1.43236923,2.75562646 L1.77489231,1.51858031 C1.78621538,1.52282646 1.79753846,1.52707262 1.81027692,1.53131877 C1.81310769,1.53273415 1.81593846,1.53414954 1.81876923,1.53414954 L1.47624615,2.77119569 L1.43236923,2.75562646 Z" id="Fill-747" fill="#0B6275"></path>
<path d="M1.72124923,1.49635877 C1.73823385,1.50343569 1.75663385,1.511928 1.77503385,1.51900492 L1.43251077,2.75605108 L1.40420308,2.74755877 C1.39995692,2.744728 1.39571077,2.74331262 1.39146462,2.74048185 C1.38721846,2.73906646 1.38155692,2.73623569 1.37872615,2.73482031 L1.72124923,1.49635877 Z" id="Fill-749" fill="#0B5F71"></path>
<path d="M1.72124923,1.49635877 L1.37872615,2.73482031 C1.36315692,2.726328 1.34900308,2.71925108 1.33626462,2.71075877 L1.20746462,2.55931262 L1.55423385,1.31094338 L1.55848,1.31660492 C1.54574154,1.364728 1.58395692,1.419928 1.67878769,1.475128 C1.69152615,1.48220492 1.70709538,1.48928185 1.72124923,1.49635877" id="Fill-755" fill="#0A5B6D"></path>
</g>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 59 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 96 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 39 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 111 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 48 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 169 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 180 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 388 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 187 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

@ -0,0 +1,68 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="33px" height="35px" viewBox="0 0 33 35" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<title>路由器</title>
<defs>
<linearGradient x1="50%" y1="0%" x2="50%" y2="100%" id="linearGradient-1">
<stop stop-color="#0042BE" offset="0%"></stop>
<stop stop-color="#0073FC" offset="100%"></stop>
</linearGradient>
<rect id="path-2" x="0" y="13.8738739" width="32.4774775" height="21.1261261" rx="2.52252252"></rect>
<linearGradient x1="100%" y1="56.8067642%" x2="0%" y2="40.3552058%" id="linearGradient-3">
<stop stop-color="#3DA5FF" offset="0%"></stop>
<stop stop-color="#7EFFFF" offset="100%"></stop>
</linearGradient>
<rect id="path-4" x="0" y="11.036036" width="32.4774775" height="21.1261261" rx="2.52252252"></rect>
<linearGradient x1="54.9387755%" y1="66.0866477%" x2="45.0612245%" y2="27.2061435%" id="linearGradient-5">
<stop stop-color="#3DA5FF" offset="0%"></stop>
<stop stop-color="#7EFFFF" offset="100%"></stop>
</linearGradient>
<linearGradient x1="-162.350446%" y1="50%" x2="100%" y2="50%" id="linearGradient-6">
<stop stop-color="#FFFFFF" offset="0%"></stop>
<stop stop-color="#FFFFFF" stop-opacity="0" offset="100%"></stop>
</linearGradient>
<linearGradient x1="48.3262804%" y1="34.4238281%" x2="50%" y2="79.7851562%" id="linearGradient-7">
<stop stop-color="#0054D5" offset="0%"></stop>
<stop stop-color="#2A92EE" offset="100%"></stop>
</linearGradient>
<linearGradient x1="0%" y1="50%" x2="266.454381%" y2="50%" id="linearGradient-8">
<stop stop-color="#0054D5" offset="0%"></stop>
<stop stop-color="#2A92EE" offset="100%"></stop>
</linearGradient>
</defs>
<g id="页面-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="4网络构建与联通V2.0" transform="translate(-22.000000, -699.000000)">
<g id="路由器" transform="translate(22.000000, 699.000000)">
<g id="矩形">
<use fill="#454343" xlink:href="#path-2"></use>
<use fill="url(#linearGradient-1)" xlink:href="#path-2"></use>
</g>
<g id="矩形">
<use fill="#5D5959" xlink:href="#path-4"></use>
<use fill="url(#linearGradient-3)" xlink:href="#path-4"></use>
</g>
<path d="M6.77927928,0 C7.7370704,-1.75943374e-16 8.51351351,0.776443114 8.51351351,1.73423423 L8.51351351,11.036036 L8.51351351,11.036036 L5.04504505,11.036036 L5.04504505,1.73423423 C5.04504505,0.776443114 5.82148816,1.75943374e-16 6.77927928,0 Z" id="矩形" fill="url(#linearGradient-5)"></path>
<path d="M6.14864865,1.26126126 C6.58400825,1.26126126 6.93693694,1.61418995 6.93693694,2.04954955 L6.93693694,11.036036 L6.93693694,11.036036 L5.36036036,11.036036 L5.36036036,2.04954955 C5.36036036,1.61418995 5.71328905,1.26126126 6.14864865,1.26126126 Z" id="矩形" fill="url(#linearGradient-6)"></path>
<path d="M26.3288288,0 C27.2866199,-1.75943374e-16 28.0630631,0.776443114 28.0630631,1.73423423 L28.0630631,11.036036 L28.0630631,11.036036 L24.5945946,11.036036 L24.5945946,1.73423423 C24.5945946,0.776443114 25.3710377,1.75943374e-16 26.3288288,0 Z" id="矩形" fill="url(#linearGradient-5)"></path>
<path d="M25.6981982,1.26126126 C26.1335578,1.26126126 26.4864865,1.61418995 26.4864865,2.04954955 L26.4864865,11.036036 L26.4864865,11.036036 L24.9099099,11.036036 L24.9099099,2.04954955 C24.9099099,1.61418995 25.2628386,1.26126126 25.6981982,1.26126126 Z" id="矩形" fill="url(#linearGradient-6)"></path>
<g id="编组-7" transform="translate(6.306306, 12.927928)">
<rect id="矩形" fill="url(#linearGradient-7)" x="0" y="0" width="1.26126126" height="3.78378378" rx="0.630630631"></rect>
<rect id="矩形" fill="url(#linearGradient-7)" x="2.52252252" y="0" width="1.26126126" height="3.78378378" rx="0.630630631"></rect>
<rect id="矩形" fill="url(#linearGradient-7)" x="5.36036036" y="0" width="1.26126126" height="3.78378378" rx="0.630630631"></rect>
<rect id="矩形" fill="url(#linearGradient-7)" x="7.88288288" y="0" width="1.26126126" height="3.78378378" rx="0.630630631"></rect>
<rect id="矩形" fill="url(#linearGradient-7)" x="10.7207207" y="0" width="1.26126126" height="3.78378378" rx="0.630630631"></rect>
<rect id="矩形" fill="url(#linearGradient-7)" x="13.2432432" y="0" width="1.26126126" height="3.78378378" rx="0.630630631"></rect>
<rect id="矩形" fill="url(#linearGradient-7)" x="16.0810811" y="0" width="1.26126126" height="3.78378378" rx="0.630630631"></rect>
<rect id="矩形" fill="url(#linearGradient-8)" x="18.6036036" y="0" width="1.26126126" height="3.78378378" rx="0.630630631"></rect>
</g>
<ellipse id="椭圆形" fill="#18D6FF" cx="8.1981982" cy="33.1081081" rx="1.26126126" ry="1"></ellipse>
<ellipse id="椭圆形" fill="#18D6FF" cx="13.5585586" cy="33.1081081" rx="1.26126126" ry="1"></ellipse>
<ellipse id="椭圆形" fill="#18D6FF" cx="18.9189189" cy="33.1081081" rx="1.26126126" ry="1"></ellipse>
<ellipse id="椭圆形" fill="#18D6FF" cx="23.963964" cy="33.1081081" rx="1.26126126" ry="1"></ellipse>
<g id="编组" transform="translate(12.297297, 21.441441)" stroke="#FFFFFF" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.26126126">
<polyline id="路径-45" points="0 0 2.43243243 0 5.67567568 5.67567568 8.10810811 5.67567568"></polyline>
<polyline id="路径-45" transform="translate(4.054054, 2.837838) scale(-1, 1) translate(-4.054054, -2.837838) " points="0 0 2.43243243 0 5.67567568 5.67567568 8.10810811 5.67567568"></polyline>
</g>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 6.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 150 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.7 KiB

File diff suppressed because it is too large Load Diff

After

Width:  |  Height:  |  Size: 199 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.5 KiB

Binary file not shown.
Loading…
Cancel
Save