cisco-config-parser 2.2.8__tar.gz → 2.3.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (68) hide show
  1. {cisco_config_parser-2.2.8 → cisco_config_parser-2.3.0}/PKG-INFO +4 -1
  2. {cisco_config_parser-2.2.8 → cisco_config_parser-2.3.0}/README.md +3 -0
  3. {cisco_config_parser-2.2.8 → cisco_config_parser-2.3.0}/cisco_config_parser/__init__.py +1 -1
  4. {cisco_config_parser-2.2.8 → cisco_config_parser-2.3.0}/cisco_config_parser/layer3_interface/l3_interface_obj.py +1 -0
  5. {cisco_config_parser-2.2.8 → cisco_config_parser-2.3.0}/cisco_config_parser/layer3_interface/l3_interface_parser.py +5 -0
  6. {cisco_config_parser-2.2.8 → cisco_config_parser-2.3.0}/cisco_config_parser/layer3_interface/l3_section_parser.py +57 -16
  7. {cisco_config_parser-2.2.8 → cisco_config_parser-2.3.0}/cisco_config_parser/parser_regex/ios_regex.py +3 -2
  8. {cisco_config_parser-2.2.8 → cisco_config_parser-2.3.0}/cisco_config_parser/setup.py +1 -1
  9. {cisco_config_parser-2.2.8 → cisco_config_parser-2.3.0}/cisco_config_parser.egg-info/PKG-INFO +4 -1
  10. {cisco_config_parser-2.2.8 → cisco_config_parser-2.3.0}/setup.py +1 -1
  11. {cisco_config_parser-2.2.8 → cisco_config_parser-2.3.0}/cisco_config_parser/cisco_config_parser.py +0 -0
  12. {cisco_config_parser-2.2.8 → cisco_config_parser-2.3.0}/cisco_config_parser/global_search/__init__.py +0 -0
  13. {cisco_config_parser-2.2.8 → cisco_config_parser-2.3.0}/cisco_config_parser/global_search/global_obj.py +0 -0
  14. {cisco_config_parser-2.2.8 → cisco_config_parser-2.3.0}/cisco_config_parser/global_search/global_parser.py +0 -0
  15. {cisco_config_parser-2.2.8 → cisco_config_parser-2.3.0}/cisco_config_parser/global_search/global_separator.py +0 -0
  16. {cisco_config_parser-2.2.8 → cisco_config_parser-2.3.0}/cisco_config_parser/global_search/ios/__init__.py +0 -0
  17. {cisco_config_parser-2.2.8 → cisco_config_parser-2.3.0}/cisco_config_parser/global_search/nxos/__init__.py +0 -0
  18. {cisco_config_parser-2.2.8 → cisco_config_parser-2.3.0}/cisco_config_parser/global_search/xr/__init__.py +0 -0
  19. {cisco_config_parser-2.2.8 → cisco_config_parser-2.3.0}/cisco_config_parser/helper/__init__.py +0 -0
  20. {cisco_config_parser-2.2.8 → cisco_config_parser-2.3.0}/cisco_config_parser/helper/help.py +0 -0
  21. {cisco_config_parser-2.2.8 → cisco_config_parser-2.3.0}/cisco_config_parser/helper/helper.py +0 -0
  22. {cisco_config_parser-2.2.8 → cisco_config_parser-2.3.0}/cisco_config_parser/layer2_interface/__init__.py +0 -0
  23. {cisco_config_parser-2.2.8 → cisco_config_parser-2.3.0}/cisco_config_parser/layer2_interface/l2_interface_obj.py +0 -0
  24. {cisco_config_parser-2.2.8 → cisco_config_parser-2.3.0}/cisco_config_parser/layer2_interface/l2_interface_parser.py +0 -0
  25. {cisco_config_parser-2.2.8 → cisco_config_parser-2.3.0}/cisco_config_parser/layer2_interface/l2_interface_separator.py +0 -0
  26. {cisco_config_parser-2.2.8 → cisco_config_parser-2.3.0}/cisco_config_parser/layer2_interface/l2_section_parser.py +0 -0
  27. {cisco_config_parser-2.2.8 → cisco_config_parser-2.3.0}/cisco_config_parser/layer3_interface/__init__.py +0 -0
  28. {cisco_config_parser-2.2.8 → cisco_config_parser-2.3.0}/cisco_config_parser/layer3_interface/l3_interface_separator.py +0 -0
  29. {cisco_config_parser-2.2.8 → cisco_config_parser-2.3.0}/cisco_config_parser/old_version/__init__.py +0 -0
  30. {cisco_config_parser-2.2.8 → cisco_config_parser-2.3.0}/cisco_config_parser/old_version/exceptions.py +0 -0
  31. {cisco_config_parser-2.2.8 → cisco_config_parser-2.3.0}/cisco_config_parser/old_version/obj.py +0 -0
  32. {cisco_config_parser-2.2.8 → cisco_config_parser-2.3.0}/cisco_config_parser/old_version/old_parse.py +0 -0
  33. {cisco_config_parser-2.2.8 → cisco_config_parser-2.3.0}/cisco_config_parser/old_version/ssh.py +0 -0
  34. {cisco_config_parser-2.2.8 → cisco_config_parser-2.3.0}/cisco_config_parser/old_version/utils.py +0 -0
  35. {cisco_config_parser-2.2.8 → cisco_config_parser-2.3.0}/cisco_config_parser/parent_child/__init__.py +0 -0
  36. {cisco_config_parser-2.2.8 → cisco_config_parser-2.3.0}/cisco_config_parser/parent_child/parent_child_obj.py +0 -0
  37. {cisco_config_parser-2.2.8 → cisco_config_parser-2.3.0}/cisco_config_parser/parent_child/parent_child_parser.py +0 -0
  38. {cisco_config_parser-2.2.8 → cisco_config_parser-2.3.0}/cisco_config_parser/parent_child/parent_child_separator.py +0 -0
  39. {cisco_config_parser-2.2.8 → cisco_config_parser-2.3.0}/cisco_config_parser/parser/__init__.py +0 -0
  40. {cisco_config_parser-2.2.8 → cisco_config_parser-2.3.0}/cisco_config_parser/parser/parser.py +0 -0
  41. {cisco_config_parser-2.2.8 → cisco_config_parser-2.3.0}/cisco_config_parser/parser_regex/__init__.py +0 -0
  42. {cisco_config_parser-2.2.8 → cisco_config_parser-2.3.0}/cisco_config_parser/parser_regex/common_regex.py +0 -0
  43. {cisco_config_parser-2.2.8 → cisco_config_parser-2.3.0}/cisco_config_parser/parser_regex/nxos_regex.py +0 -0
  44. {cisco_config_parser-2.2.8 → cisco_config_parser-2.3.0}/cisco_config_parser/routing_protocol/__init__.py +0 -0
  45. {cisco_config_parser-2.2.8 → cisco_config_parser-2.3.0}/cisco_config_parser/routing_protocol/ios/__init__.py +0 -0
  46. {cisco_config_parser-2.2.8 → cisco_config_parser-2.3.0}/cisco_config_parser/routing_protocol/ios/rtp_bgp.py +0 -0
  47. {cisco_config_parser-2.2.8 → cisco_config_parser-2.3.0}/cisco_config_parser/routing_protocol/ios/rtp_eigtp.py +0 -0
  48. {cisco_config_parser-2.2.8 → cisco_config_parser-2.3.0}/cisco_config_parser/routing_protocol/ios/rtp_ios_rtp_obj.py +0 -0
  49. {cisco_config_parser-2.2.8 → cisco_config_parser-2.3.0}/cisco_config_parser/routing_protocol/ios/rtp_ospf.py +0 -0
  50. {cisco_config_parser-2.2.8 → cisco_config_parser-2.3.0}/cisco_config_parser/routing_protocol/ios/rtp_static.py +0 -0
  51. {cisco_config_parser-2.2.8 → cisco_config_parser-2.3.0}/cisco_config_parser/routing_protocol/nxos/__init__.py +0 -0
  52. {cisco_config_parser-2.2.8 → cisco_config_parser-2.3.0}/cisco_config_parser/routing_protocol/nxos/rtp_bgp.py +0 -0
  53. {cisco_config_parser-2.2.8 → cisco_config_parser-2.3.0}/cisco_config_parser/routing_protocol/nxos/rtp_nxos_rtp_obj.py +0 -0
  54. {cisco_config_parser-2.2.8 → cisco_config_parser-2.3.0}/cisco_config_parser/routing_protocol/nxos/rtp_ospf.py +0 -0
  55. {cisco_config_parser-2.2.8 → cisco_config_parser-2.3.0}/cisco_config_parser/routing_protocol/nxos/rtp_static.py +0 -0
  56. {cisco_config_parser-2.2.8 → cisco_config_parser-2.3.0}/cisco_config_parser/routing_protocol/nxos/rtp_vxlan.py +0 -0
  57. {cisco_config_parser-2.2.8 → cisco_config_parser-2.3.0}/cisco_config_parser/routing_protocol/utils/__init__.py +0 -0
  58. {cisco_config_parser-2.2.8 → cisco_config_parser-2.3.0}/cisco_config_parser/routing_protocol/utils/rtp_ios_separator.py +0 -0
  59. {cisco_config_parser-2.2.8 → cisco_config_parser-2.3.0}/cisco_config_parser/routing_protocol/utils/rtp_nxos_separator.py +0 -0
  60. {cisco_config_parser-2.2.8 → cisco_config_parser-2.3.0}/cisco_config_parser/routing_protocol/utils/utils.py +0 -0
  61. {cisco_config_parser-2.2.8 → cisco_config_parser-2.3.0}/cisco_config_parser/routing_protocol/xr/__init__.py +0 -0
  62. {cisco_config_parser-2.2.8 → cisco_config_parser-2.3.0}/cisco_config_parser/separator/__init__.py +0 -0
  63. {cisco_config_parser-2.2.8 → cisco_config_parser-2.3.0}/cisco_config_parser/separator/separator.py +0 -0
  64. {cisco_config_parser-2.2.8 → cisco_config_parser-2.3.0}/cisco_config_parser.egg-info/SOURCES.txt +0 -0
  65. {cisco_config_parser-2.2.8 → cisco_config_parser-2.3.0}/cisco_config_parser.egg-info/dependency_links.txt +0 -0
  66. {cisco_config_parser-2.2.8 → cisco_config_parser-2.3.0}/cisco_config_parser.egg-info/top_level.txt +0 -0
  67. {cisco_config_parser-2.2.8 → cisco_config_parser-2.3.0}/pyproject.toml +0 -0
  68. {cisco_config_parser-2.2.8 → cisco_config_parser-2.3.0}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: cisco_config_parser
3
- Version: 2.2.8
3
+ Version: 2.3.0
4
4
  Summary: This library is used for Network Automation involving Cisco Routers and Switch. It will parse Cisco IOS, IOS-XE, IOS-XR, and NXOS configuration file into objects and/or json format
5
5
  Home-page: https://github.com/arezazadeh/cisco_config_parser
6
6
  Author: Ahmad Rezazadeh
@@ -147,6 +147,7 @@ obj.get_static_routes(return_json=True) << Returns a list of dictionaries
147
147
  In layer-3 interface, the class attempts to capture all the important attributes of the interface, such as:
148
148
 
149
149
  - IPv4 Address
150
+ - IPv6 Address
150
151
  - Subnet
151
152
  - Subnet Mask
152
153
  - Secondary IPv4 Address
@@ -217,6 +218,7 @@ Loopback202
217
218
  "name": "Loopback100",
218
219
  "description": "SWITCH01-SA01 Loopback IP",
219
220
  "ip_address": "10.241.17.8",
221
+ "ipv6_address": "2001:DB8::1/64",
220
222
  "mask": "255.255.255.255",
221
223
  "subnet": "10.241.17.8/32",
222
224
  "helpers": null,
@@ -230,6 +232,7 @@ Loopback202
230
232
  "description SWITCH01-SA01 Loopback IP",
231
233
  "ip vrf forwarding mgt100",
232
234
  "ip address 10.241.17.8 255.255.255.255",
235
+ "ipv6 address 2001:DB8::1/64",
233
236
  "ip pim sparse-mode",
234
237
  "ip ospf 100 area 0"
235
238
  ]
@@ -137,6 +137,7 @@ obj.get_static_routes(return_json=True) << Returns a list of dictionaries
137
137
  In layer-3 interface, the class attempts to capture all the important attributes of the interface, such as:
138
138
 
139
139
  - IPv4 Address
140
+ - IPv6 Address
140
141
  - Subnet
141
142
  - Subnet Mask
142
143
  - Secondary IPv4 Address
@@ -207,6 +208,7 @@ Loopback202
207
208
  "name": "Loopback100",
208
209
  "description": "SWITCH01-SA01 Loopback IP",
209
210
  "ip_address": "10.241.17.8",
211
+ "ipv6_address": "2001:DB8::1/64",
210
212
  "mask": "255.255.255.255",
211
213
  "subnet": "10.241.17.8/32",
212
214
  "helpers": null,
@@ -220,6 +222,7 @@ Loopback202
220
222
  "description SWITCH01-SA01 Loopback IP",
221
223
  "ip vrf forwarding mgt100",
222
224
  "ip address 10.241.17.8 255.255.255.255",
225
+ "ipv6 address 2001:DB8::1/64",
223
226
  "ip pim sparse-mode",
224
227
  "ip ospf 100 area 0"
225
228
  ]
@@ -6,7 +6,7 @@ _ALL_ = [
6
6
  "ConfigParserOld",
7
7
  ]
8
8
 
9
- __version__ = "2.2.8"
9
+ __version__ = "2.3.0"
10
10
  __author__ = "Ahmad Rezazadeh"
11
11
  __email__ = "ahmad@klevernet.io"
12
12
  __url__ = "klevernet.ai"
@@ -11,6 +11,7 @@ class L3Interface:
11
11
  name: str = None
12
12
  description: str = None
13
13
  ip_address: str = None
14
+ ipv6_address: str = None
14
15
  mask: str = None
15
16
  subnet: str = None
16
17
  helpers: list = None
@@ -61,6 +61,7 @@ class L3InterfaceParser:
61
61
  vrf_regex = VRF_REGEX.search(l3_interface_stripped)
62
62
  helper_address_regex = HELPER_ADDRESS_REGEX.search(l3_interface_stripped)
63
63
  sec_ip_address_regex = SECONDARY_IP_ADDRESS_REGEX.search(l3_interface_stripped)
64
+ ipv6_address_regex = IPV6_ADDRESS_REGEX.search(l3_interface_stripped)
64
65
 
65
66
 
66
67
  # if the regex is found, parse the line and store the value in the l3_intf_cls object
@@ -77,6 +78,7 @@ class L3InterfaceParser:
77
78
  if sec_ip_address_regex:
78
79
  # set the primary flag to False to indicate that the ip address is a secondary ip address
79
80
  ip_address_kwargs["primary"] = False
81
+ ip_address_kwargs["ip_address_line_regex"] = sec_ip_address_regex
80
82
  l3_intf_cls = _L3SectionParser._parse_ip_address_line(**ip_address_kwargs)
81
83
 
82
84
  if vrf_regex:
@@ -91,6 +93,9 @@ class L3InterfaceParser:
91
93
  if description_regex:
92
94
  l3_intf_cls.description = description_regex.group(1).strip()
93
95
 
96
+ if ipv6_address_regex:
97
+ l3_intf_cls.ipv6_address = ipv6_address_regex.group(1).strip()
98
+
94
99
  # if there are custom kwargs, search for the custom regex in the l3_interface section
95
100
  # if the regex is found, parse the line and store the value in the l3_intf_cls object
96
101
  if kwargs:
@@ -19,7 +19,37 @@ class _L3SectionParser:
19
19
  return: l3_interface_obj
20
20
  """
21
21
 
22
- def process_ip_address_with_cidr(ip_address_with_cidr, obj):
22
+
23
+ def cleanup_ip_address(ip_address_line_regex):
24
+ ip_address_regex = [ip_group for ip_group in ip_address_line_regex.groups() if ip_group]
25
+ if not ip_address_regex:
26
+ return None
27
+
28
+ if "/" in ip_address_regex[0]:
29
+ ip_address_config = ip_address_regex[0].split("/")
30
+ ip_addr = ip_address_config[0].strip()
31
+ cidr = ip_address_config[1].strip()
32
+ subnet_ = ipaddress.IPv4Network(f"{ip_addr}/{cidr}", strict=False)
33
+ return {
34
+ "ip_address": ip_addr.strip(),
35
+ "mask": str(subnet_.netmask),
36
+ "subnet": str(subnet_).strip()
37
+ }
38
+
39
+ else:
40
+ ip_address_section = ip_address_regex[0].split()
41
+ ip_address = ip_address_section[0].strip()
42
+ mask = ip_address_section[1].strip()
43
+ subnet = str(ipaddress.IPv4Network(f"{ip_address}/{mask}", strict=False))
44
+ return {
45
+ "ip_address": ip_address.strip(),
46
+ "mask": mask.strip(),
47
+ "subnet": subnet.strip()
48
+ }
49
+
50
+
51
+
52
+ def process_ip_address_with_cidr(ip_address_with_cidr, obj, primary=True):
23
53
  """
24
54
  Process the ip address with cidr
25
55
  :param ip_address_with_cidr: str
@@ -39,25 +69,36 @@ class _L3SectionParser:
39
69
  l3_interface_obj = kwargs.get("l3_interface_obj")
40
70
  primary = kwargs.get("primary", True)
41
71
 
42
- ip_address_regex = [ip_group for ip_group in ip_address_line_regex.groups() if ip_group]
72
+ ip_info = cleanup_ip_address(ip_address_line_regex)
73
+ # ip_address_regex = [ip_group for ip_group in ip_address_line_regex.groups() if ip_group]
43
74
 
75
+ # print(ip_address_regex)
44
76
  # Check if the ip address has a CIDR - 10.1.1.1/24
45
- if "/" in ip_address_regex[0]:
46
- l3_interface_obj = process_ip_address_with_cidr(ip_address_regex[0], l3_interface_obj)
47
- return l3_interface_obj
48
-
49
- ip_address_section = ip_address_regex[0].split()
50
- ip_address = ip_address_section[0].strip()
51
- mask = ip_address_section[1].strip()
52
- subnet = str(ipaddress.IPv4Network(f"{ip_address}/{mask}", strict=False))
77
+ # if "/" in ip_address_regex[0]:
78
+ #
79
+ # l3_interface_obj = process_ip_address_with_cidr(ip_address_regex[0], l3_interface_obj)
80
+ # return l3_interface_obj
81
+
82
+ # ip_address_section = ip_address_regex[0].split()
83
+ # ip_address = ip_address_section[0].strip()
84
+ # mask = ip_address_section[1].strip()
85
+ # subnet = str(ipaddress.IPv4Network(f"{ip_address}/{mask}", strict=False))
53
86
  if primary:
54
- l3_interface_obj.ip_address = ip_address.strip()
55
- l3_interface_obj.mask = mask.strip()
56
- l3_interface_obj.subnet = subnet.strip()
87
+ l3_interface_obj.ip_address = ip_info["ip_address"].strip()
88
+ l3_interface_obj.mask = ip_info["mask"].strip()
89
+ l3_interface_obj.subnet = ip_info["subnet"].strip()
90
+
91
+ # l3_interface_obj.ip_address = ip_address.strip()
92
+ # l3_interface_obj.mask = mask.strip()
93
+ # l3_interface_obj.subnet = subnet.strip()
57
94
  else:
58
- l3_interface_obj.sec_ip_address = ip_address.strip()
59
- l3_interface_obj.sec_mask = mask.strip()
60
- l3_interface_obj.sec_subnet = subnet.strip()
95
+ l3_interface_obj.sec_ip_address = ip_info["ip_address"].strip()
96
+ l3_interface_obj.sec_mask = ip_info["mask"].strip()
97
+ l3_interface_obj.sec_subnet = ip_info["subnet"].strip()
98
+
99
+ # l3_interface_obj.sec_ip_address = ip_address.strip()
100
+ # l3_interface_obj.sec_mask = mask.strip()
101
+ # l3_interface_obj.sec_subnet = subnet.strip()
61
102
 
62
103
  return l3_interface_obj
63
104
 
@@ -28,11 +28,12 @@ INTERFACE_REGEX = re.compile(r"interface\s(.*)", flags=re.MULTILINE)
28
28
  # L3 Interface
29
29
  DESCRIPTION_REGEX = re.compile(r"description\s(.*)", flags=re.MULTILINE)
30
30
  IP_ADDRESS_REGEX = re.compile(r"ip\saddress\s(\d+\.\d+\.\d+\.\d+\s\d+\.\d+\.\d+\.\d+)|ip\saddress\s(\d+\.\d+\.\d+\.\d+/\d+)|ipv4\saddress\s(\d+\.\d+\.\d+\.\d+\s\d+\.\d+\.\d+\.\d+)|ipv4\saddress\s(\d+\.\d+\.\d+\.\d+/\d+)")
31
+ # IP_ADDRESS_REGEX = re.compile(r"ipv?4?\saddress\s(\d+\.\d+\.\d+\.\d+)(\s\d+\.\d+\.\d+\.\d+|/\d+)?", flags=re.MULTILINE)
31
32
  IP_ADDRESS_CIDR_REGEX = re.compile(r"ip\saddress\s(\d+\.\d+\.\d+\.\d+/\d+)", flags=re.MULTILINE)
32
33
  HELPER_ADDRESS_REGEX = re.compile(r"ip\shelper-address\s(.*)", flags=re.MULTILINE)
33
- SECONDARY_IP_ADDRESS_REGEX = re.compile(r"ip\saddress\s(.*)secondary", flags=re.MULTILINE)
34
+ SECONDARY_IP_ADDRESS_REGEX = re.compile(r"^ip\saddress\s(.*)\ssecondary", flags=re.MULTILINE)
34
35
  VRF_REGEX = re.compile(r"^ip\svrf\sforwarding\s(.*)|^vrf\smember\s(.*)|^vrf\sforwarding\s(.*)|^vrf\s(\S+)$", flags=re.MULTILINE)
35
-
36
+ IPV6_ADDRESS_REGEX = re.compile(r"ipv6\saddress\s(.*)", flags=re.MULTILINE)
36
37
 
37
38
 
38
39
  # L2 Interface
@@ -3,6 +3,6 @@ from setuptools import setup, find_packages
3
3
 
4
4
  setup(
5
5
  name='cisco_config_parser',
6
- version='2.2.8',
6
+ version='2.3.0',
7
7
  packages=find_packages(),
8
8
  )
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: cisco_config_parser
3
- Version: 2.2.8
3
+ Version: 2.3.0
4
4
  Summary: This library is used for Network Automation involving Cisco Routers and Switch. It will parse Cisco IOS, IOS-XE, IOS-XR, and NXOS configuration file into objects and/or json format
5
5
  Home-page: https://github.com/arezazadeh/cisco_config_parser
6
6
  Author: Ahmad Rezazadeh
@@ -147,6 +147,7 @@ obj.get_static_routes(return_json=True) << Returns a list of dictionaries
147
147
  In layer-3 interface, the class attempts to capture all the important attributes of the interface, such as:
148
148
 
149
149
  - IPv4 Address
150
+ - IPv6 Address
150
151
  - Subnet
151
152
  - Subnet Mask
152
153
  - Secondary IPv4 Address
@@ -217,6 +218,7 @@ Loopback202
217
218
  "name": "Loopback100",
218
219
  "description": "SWITCH01-SA01 Loopback IP",
219
220
  "ip_address": "10.241.17.8",
221
+ "ipv6_address": "2001:DB8::1/64",
220
222
  "mask": "255.255.255.255",
221
223
  "subnet": "10.241.17.8/32",
222
224
  "helpers": null,
@@ -230,6 +232,7 @@ Loopback202
230
232
  "description SWITCH01-SA01 Loopback IP",
231
233
  "ip vrf forwarding mgt100",
232
234
  "ip address 10.241.17.8 255.255.255.255",
235
+ "ipv6 address 2001:DB8::1/64",
233
236
  "ip pim sparse-mode",
234
237
  "ip ospf 100 area 0"
235
238
  ]
@@ -3,7 +3,7 @@ from setuptools import setup, find_packages
3
3
 
4
4
  HERE = pathlib.Path(__file__).parent
5
5
 
6
- VERSION = '2.2.8'
6
+ VERSION = '2.3.0'
7
7
  PACKAGE_NAME = 'cisco_config_parser'
8
8
  AUTHOR = 'Ahmad Rezazadeh'
9
9
  AUTHOR_EMAIL = 'ahmad@klevernet.io'