codosdk 1.0.26__tar.gz → 1.0.28__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.
- {codosdk-1.0.26 → codosdk-1.0.28}/PKG-INFO +1 -1
- {codosdk-1.0.26 → codosdk-1.0.28}/codosdk.egg-info/PKG-INFO +1 -1
- {codosdk-1.0.26 → codosdk-1.0.28}/setup.py +1 -1
- codosdk-1.0.28/websdk2/api_set.py +57 -0
- {codosdk-1.0.26 → codosdk-1.0.28}/websdk2/utils/__init__.py +133 -53
- codosdk-1.0.26/websdk2/api_set.py +0 -43
- {codosdk-1.0.26 → codosdk-1.0.28}/LICENSE +0 -0
- {codosdk-1.0.26 → codosdk-1.0.28}/README.md +0 -0
- {codosdk-1.0.26 → codosdk-1.0.28}/codosdk.egg-info/SOURCES.txt +0 -0
- {codosdk-1.0.26 → codosdk-1.0.28}/codosdk.egg-info/dependency_links.txt +0 -0
- {codosdk-1.0.26 → codosdk-1.0.28}/codosdk.egg-info/requires.txt +0 -0
- {codosdk-1.0.26 → codosdk-1.0.28}/codosdk.egg-info/top_level.txt +0 -0
- {codosdk-1.0.26 → codosdk-1.0.28}/opssdk/__init__.py +0 -0
- {codosdk-1.0.26 → codosdk-1.0.28}/opssdk/utils/__init__.py +0 -0
- {codosdk-1.0.26 → codosdk-1.0.28}/pyproject.toml +0 -0
- {codosdk-1.0.26 → codosdk-1.0.28}/setup.cfg +0 -0
- {codosdk-1.0.26 → codosdk-1.0.28}/websdk2/__init__.py +0 -0
- {codosdk-1.0.26 → codosdk-1.0.28}/websdk2/apis/__init__.py +0 -0
- {codosdk-1.0.26 → codosdk-1.0.28}/websdk2/apis/admin_apis.py +0 -0
- {codosdk-1.0.26 → codosdk-1.0.28}/websdk2/apis/agent_apis.py +0 -0
- {codosdk-1.0.26 → codosdk-1.0.28}/websdk2/apis/cmdb_apis.py +0 -0
- {codosdk-1.0.26 → codosdk-1.0.28}/websdk2/apis/kerrigan_apis.py +0 -0
- {codosdk-1.0.26 → codosdk-1.0.28}/websdk2/apis/mgv4_apis.py +0 -0
- {codosdk-1.0.26 → codosdk-1.0.28}/websdk2/apis/notice_apis.py +0 -0
- {codosdk-1.0.26 → codosdk-1.0.28}/websdk2/apis/task_apis.py +0 -0
- {codosdk-1.0.26 → codosdk-1.0.28}/websdk2/application.py +0 -0
- {codosdk-1.0.26 → codosdk-1.0.28}/websdk2/base_handler.py +0 -0
- {codosdk-1.0.26 → codosdk-1.0.28}/websdk2/cache.py +0 -0
- {codosdk-1.0.26 → codosdk-1.0.28}/websdk2/cache_context.py +0 -0
- {codosdk-1.0.26 → codosdk-1.0.28}/websdk2/client.py +0 -0
- {codosdk-1.0.26 → codosdk-1.0.28}/websdk2/cloud/__init__.py +0 -0
- {codosdk-1.0.26 → codosdk-1.0.28}/websdk2/cloud/qcloud_api.py +0 -0
- {codosdk-1.0.26 → codosdk-1.0.28}/websdk2/cloud/ucloud_api.py +0 -0
- {codosdk-1.0.26 → codosdk-1.0.28}/websdk2/cloud_utils.py +0 -0
- {codosdk-1.0.26 → codosdk-1.0.28}/websdk2/configs.py +0 -0
- {codosdk-1.0.26 → codosdk-1.0.28}/websdk2/consts.py +0 -0
- {codosdk-1.0.26 → codosdk-1.0.28}/websdk2/crud_utils.py +0 -0
- {codosdk-1.0.26 → codosdk-1.0.28}/websdk2/db_context.py +0 -0
- {codosdk-1.0.26 → codosdk-1.0.28}/websdk2/error.py +0 -0
- {codosdk-1.0.26 → codosdk-1.0.28}/websdk2/fetch_coroutine.py +0 -0
- {codosdk-1.0.26 → codosdk-1.0.28}/websdk2/jwt_token.py +0 -0
- {codosdk-1.0.26 → codosdk-1.0.28}/websdk2/ldap.py +0 -0
- {codosdk-1.0.26 → codosdk-1.0.28}/websdk2/logger.py +0 -0
- {codosdk-1.0.26 → codosdk-1.0.28}/websdk2/model_utils.py +0 -0
- {codosdk-1.0.26 → codosdk-1.0.28}/websdk2/mqhelper.py +0 -0
- {codosdk-1.0.26 → codosdk-1.0.28}/websdk2/program.py +0 -0
- {codosdk-1.0.26 → codosdk-1.0.28}/websdk2/salt_api.py +0 -0
- {codosdk-1.0.26 → codosdk-1.0.28}/websdk2/sqlalchemy_pagination.py +0 -0
- {codosdk-1.0.26 → codosdk-1.0.28}/websdk2/tools.py +0 -0
- {codosdk-1.0.26 → codosdk-1.0.28}/websdk2/utils/cc_crypto.py +0 -0
- {codosdk-1.0.26 → codosdk-1.0.28}/websdk2/utils/date_format.py +0 -0
- {codosdk-1.0.26 → codosdk-1.0.28}/websdk2/utils/pydantic_utils.py +0 -0
- {codosdk-1.0.26 → codosdk-1.0.28}/websdk2/web_logs.py +0 -0
|
@@ -9,7 +9,7 @@ desc : CODO SDK
|
|
|
9
9
|
import sys
|
|
10
10
|
from setuptools import setup, find_packages
|
|
11
11
|
|
|
12
|
-
VERSION = '1.0.
|
|
12
|
+
VERSION = '1.0.28'
|
|
13
13
|
|
|
14
14
|
if sys.version_info < (2, 7) or (3, 0) <= sys.version_info < (3, 6):
|
|
15
15
|
print('This program requires at least Python 2.7 or 3.6 to run.')
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
#!/usr/bin/env python
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
"""
|
|
4
|
+
Version : 0.0.1
|
|
5
|
+
Contact : 191715030@qq.com
|
|
6
|
+
Author : shenshuo
|
|
7
|
+
Date : 2025/02/12 17:56
|
|
8
|
+
Desc : API集合
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
from .tools import singleton
|
|
12
|
+
from .apis import AdminAPIS, TaskAPIS, KerriganAPIS, AdminV4APIS, CMDBAPIS, AgentAPIS, NoticeAPIS
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
@singleton
|
|
16
|
+
class ConstAPIS(AdminAPIS, TaskAPIS, KerriganAPIS, AdminV4APIS, CMDBAPIS, AgentAPIS, NoticeAPIS):
|
|
17
|
+
"""
|
|
18
|
+
集合所有常用 API 配置的常量类,继承了各个 API 模块的接口配置。
|
|
19
|
+
|
|
20
|
+
提供了对 API 配置项的只读管理,并且对每个新增属性值进行校验。
|
|
21
|
+
"""
|
|
22
|
+
|
|
23
|
+
def __init__(self):
|
|
24
|
+
pass
|
|
25
|
+
|
|
26
|
+
def __setattr__(self, name: str, value: dict) -> None:
|
|
27
|
+
|
|
28
|
+
"""
|
|
29
|
+
自定义属性设置方法,确保 API 配置项的合法性。
|
|
30
|
+
|
|
31
|
+
校验条件:
|
|
32
|
+
1. 不允许重新绑定常量。
|
|
33
|
+
2. 属性值必须是字典格式。
|
|
34
|
+
3. 必须包含 'url' 和 'description' 字段。
|
|
35
|
+
|
|
36
|
+
Args:
|
|
37
|
+
name (str): 属性名称
|
|
38
|
+
value (dict): 属性值,必须为字典格式并包含必要字段
|
|
39
|
+
"""
|
|
40
|
+
|
|
41
|
+
if name in self.__dict__:
|
|
42
|
+
raise TypeError(f"Cannot rebind constant '{name}'.")
|
|
43
|
+
|
|
44
|
+
if not isinstance(value, dict):
|
|
45
|
+
raise TypeError(f"Value for '{name}' must be a dictionary.")
|
|
46
|
+
|
|
47
|
+
# 确保包含 'url' 和 'description' 字段
|
|
48
|
+
if 'url' not in value:
|
|
49
|
+
raise TypeError(f"Value for '{name}' must contain 'url'.")
|
|
50
|
+
|
|
51
|
+
if 'description' not in value:
|
|
52
|
+
raise TypeError(f"Value for '{name}' must contain 'description'.")
|
|
53
|
+
|
|
54
|
+
self.__dict__[name] = value
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
api_set = ConstAPIS()
|
|
@@ -8,101 +8,181 @@ Desc :
|
|
|
8
8
|
"""
|
|
9
9
|
|
|
10
10
|
import json
|
|
11
|
+
import logging
|
|
11
12
|
import os
|
|
12
13
|
import smtplib
|
|
13
14
|
import socket
|
|
14
15
|
import time
|
|
15
16
|
import uuid
|
|
16
17
|
from datetime import datetime
|
|
17
|
-
from
|
|
18
|
+
from typing import List, Union
|
|
18
19
|
from email.mime.text import MIMEText
|
|
20
|
+
from email.mime.multipart import MIMEMultipart
|
|
19
21
|
|
|
20
22
|
from ..consts import const
|
|
21
23
|
|
|
22
24
|
|
|
23
|
-
class SendMail
|
|
24
|
-
def __init__(self, mail_host, mail_port, mail_user, mail_password, mail_ssl=False,
|
|
25
|
+
class SendMail:
|
|
26
|
+
def __init__(self, mail_host: str, mail_port: int, mail_user: str, mail_password: str, mail_ssl: bool = False,
|
|
27
|
+
mail_tls: bool = False):
|
|
25
28
|
"""
|
|
29
|
+
初始化邮件发送客户端
|
|
30
|
+
|
|
26
31
|
:param mail_host: SMTP主机
|
|
27
32
|
:param mail_port: SMTP端口
|
|
28
33
|
:param mail_user: SMTP账号
|
|
29
34
|
:param mail_password: SMTP密码
|
|
30
|
-
:param mail_ssl: SSL
|
|
35
|
+
:param mail_ssl: 是否启用SSL加密,如果SMTP端口是465,通常需要启用SSL
|
|
36
|
+
:param mail_tls: 是否启用TLS加密,如果SMTP端口是587,通常需要启用TLS
|
|
31
37
|
"""
|
|
32
38
|
self.mail_host = mail_host
|
|
33
39
|
self.mail_port = mail_port
|
|
34
|
-
self.
|
|
35
|
-
self.__mail_password = mail_password
|
|
40
|
+
self.mail_user = mail_user
|
|
41
|
+
self.__mail_password = mail_password # 使用单下划线,表示这是一个受保护的属性
|
|
36
42
|
self.mail_ssl = mail_ssl
|
|
37
43
|
self.mail_tls = mail_tls
|
|
38
44
|
|
|
39
|
-
def send_mail(self, to_list, subject, content, subtype='plain',
|
|
45
|
+
def send_mail(self, to_list: Union[str, List[str]], subject: str, content: str, subtype: str = 'plain',
|
|
46
|
+
att: Union[str, None] = None):
|
|
40
47
|
"""
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
:param
|
|
44
|
-
:param
|
|
45
|
-
:param
|
|
48
|
+
发送邮件
|
|
49
|
+
|
|
50
|
+
:param to_list: 收件人列表,可以是单个邮箱地址字符串,也可以是多个邮箱地址的列表,必填
|
|
51
|
+
:param subject: 邮件标题,必填
|
|
52
|
+
:param content: 邮件内容,必填
|
|
53
|
+
:param subtype: 邮件内容格式,默认为plain,可选html
|
|
54
|
+
:param att: 附件路径,支持单个附件,选填
|
|
46
55
|
"""
|
|
56
|
+
|
|
57
|
+
if isinstance(to_list, list):
|
|
58
|
+
to_list = ','.join(to_list) # 将列表转换为逗号分隔的字符串
|
|
59
|
+
|
|
47
60
|
msg = MIMEMultipart()
|
|
48
|
-
msg['Subject'] = subject
|
|
49
|
-
msg['From'] = self.
|
|
50
|
-
msg['To'] = to_list
|
|
51
|
-
|
|
61
|
+
msg['Subject'] = subject
|
|
62
|
+
msg['From'] = self.mail_user
|
|
63
|
+
msg['To'] = to_list
|
|
64
|
+
|
|
52
65
|
msg.attach(MIMEText(content, subtype, 'utf-8'))
|
|
66
|
+
|
|
53
67
|
if att:
|
|
54
68
|
if not os.path.isfile(att):
|
|
55
|
-
raise FileNotFoundError('{
|
|
69
|
+
raise FileNotFoundError(f'{att} 文件不存在')
|
|
70
|
+
try:
|
|
71
|
+
with open(att, 'rb') as f:
|
|
72
|
+
file_data = f.read()
|
|
56
73
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
74
|
+
filename = os.path.basename(att)
|
|
75
|
+
attachment = MIMEText(file_data.decode('utf-8'), 'base64', 'utf-8')
|
|
76
|
+
attachment['Content-Type'] = 'application/octet-stream'
|
|
77
|
+
attachment['Content-Disposition'] = f'attachment; filename="{filename}"'
|
|
78
|
+
msg.attach(attachment)
|
|
79
|
+
except Exception as err:
|
|
80
|
+
logging.error(f"发送附件出错 {err}")
|
|
64
81
|
|
|
65
82
|
try:
|
|
66
|
-
|
|
67
|
-
''
|
|
68
|
-
|
|
69
|
-
server = smtplib.SMTP_SSL(host=self.mail_host)
|
|
70
|
-
server.connect(self.mail_host, self.mail_port) # 连接服务器
|
|
71
|
-
server.login(self.__mail_user, self.__mail_password) # 登录操作
|
|
72
|
-
server.sendmail(self.__mail_user, to_list.split(','), msg.as_string())
|
|
73
|
-
server.close()
|
|
74
|
-
elif self.mail_tls:
|
|
75
|
-
# print('Use TLS SendMail')
|
|
76
|
-
'''使用TLS模式'''
|
|
77
|
-
server = smtplib.SMTP()
|
|
78
|
-
server.connect(self.mail_host, self.mail_port) # 连接服务器
|
|
79
|
-
server.starttls()
|
|
80
|
-
server.login(self.__mail_user, self.__mail_password) # 登录操作
|
|
81
|
-
server.sendmail(self.__mail_user, to_list.split(','), msg.as_string())
|
|
82
|
-
server.close()
|
|
83
|
-
return True
|
|
84
|
-
else:
|
|
85
|
-
'''使用普通模式'''
|
|
86
|
-
server = smtplib.SMTP()
|
|
87
|
-
server.connect(self.mail_host, self.mail_port) # 连接服务器
|
|
88
|
-
server.login(self.__mail_user, self.__mail_password) # 登录操作
|
|
89
|
-
server.sendmail(self.__mail_user, to_list.split(','), msg.as_string())
|
|
90
|
-
server.close()
|
|
91
|
-
return True
|
|
83
|
+
with self._get_server() as server:
|
|
84
|
+
server.sendmail(self.mail_user, to_list.split(','), msg.as_string())
|
|
85
|
+
return True
|
|
92
86
|
except Exception as e:
|
|
93
|
-
|
|
87
|
+
logging.error(f'邮件发送失败: {e}')
|
|
94
88
|
return False
|
|
95
89
|
|
|
90
|
+
def _get_server(self):
|
|
91
|
+
if self.mail_ssl:
|
|
92
|
+
server = smtplib.SMTP_SSL(self.mail_host, self.mail_port)
|
|
93
|
+
elif self.mail_tls:
|
|
94
|
+
server = smtplib.SMTP(self.mail_host, self.mail_port)
|
|
95
|
+
server.starttls()
|
|
96
|
+
else:
|
|
97
|
+
server = smtplib.SMTP(self.mail_host, self.mail_port)
|
|
98
|
+
|
|
99
|
+
server.login(self.mail_user, self.__mail_password)
|
|
100
|
+
return server
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
# class SendMail(object):
|
|
104
|
+
# def __init__(self, mail_host, mail_port, mail_user, mail_password, mail_ssl=False, mail_tls=False):
|
|
105
|
+
# """
|
|
106
|
+
# :param mail_host: SMTP主机
|
|
107
|
+
# :param mail_port: SMTP端口
|
|
108
|
+
# :param mail_user: SMTP账号
|
|
109
|
+
# :param mail_password: SMTP密码
|
|
110
|
+
# :param mail_ssl: SSL=True, 如果SMTP端口是465,通常需要启用SSL, 如果SMTP端口是587,通常需要启用TLS
|
|
111
|
+
# """
|
|
112
|
+
# self.mail_host = mail_host
|
|
113
|
+
# self.mail_port = mail_port
|
|
114
|
+
# self.__mail_user = mail_user
|
|
115
|
+
# self.__mail_password = mail_password
|
|
116
|
+
# self.mail_ssl = mail_ssl
|
|
117
|
+
# self.mail_tls = mail_tls
|
|
118
|
+
#
|
|
119
|
+
# def send_mail(self, to_list, subject, content, subtype='plain', att=None):
|
|
120
|
+
# """
|
|
121
|
+
# :param to_list: 收件人,多收件人半角逗号分割, 必填
|
|
122
|
+
# :param subject: 标题, 必填
|
|
123
|
+
# :param content: 内容, 必填
|
|
124
|
+
# :param subtype: 格式,默认:plain, 可选html
|
|
125
|
+
# :param att: 附件,支持单附件,选填
|
|
126
|
+
# """
|
|
127
|
+
# msg = MIMEMultipart()
|
|
128
|
+
# msg['Subject'] = subject ## 标题
|
|
129
|
+
# msg['From'] = self.__mail_user ## 发件人
|
|
130
|
+
# msg['To'] = to_list # 收件人,必须是一个字符串
|
|
131
|
+
# # 邮件正文内容
|
|
132
|
+
# msg.attach(MIMEText(content, subtype, 'utf-8'))
|
|
133
|
+
# if att:
|
|
134
|
+
# if not os.path.isfile(att):
|
|
135
|
+
# raise FileNotFoundError('{0} file does not exist'.format(att))
|
|
136
|
+
#
|
|
137
|
+
# dirname, filename = os.path.split(att)
|
|
138
|
+
# # 构造附件1,传送当前目录下的 test.txt 文件
|
|
139
|
+
# att1 = MIMEText(open(att, 'rb').read(), 'base64', 'utf-8')
|
|
140
|
+
# att1["Content-Type"] = 'application/octet-stream'
|
|
141
|
+
# # 这里的filename可以任意写,写什么名字,邮件中显示什么名字
|
|
142
|
+
# att1["Content-Disposition"] = 'attachment; filename="{0}"'.format(filename)
|
|
143
|
+
# msg.attach(att1)
|
|
144
|
+
#
|
|
145
|
+
# try:
|
|
146
|
+
# if self.mail_ssl:
|
|
147
|
+
# '''SSL加密方式,通信过程加密,邮件数据安全, 使用端口465'''
|
|
148
|
+
# # print('Use SSL SendMail')
|
|
149
|
+
# server = smtplib.SMTP_SSL(host=self.mail_host)
|
|
150
|
+
# server.connect(self.mail_host, self.mail_port) # 连接服务器
|
|
151
|
+
# server.login(self.__mail_user, self.__mail_password) # 登录操作
|
|
152
|
+
# server.sendmail(self.__mail_user, to_list.split(','), msg.as_string())
|
|
153
|
+
# server.close()
|
|
154
|
+
# elif self.mail_tls:
|
|
155
|
+
# # print('Use TLS SendMail')
|
|
156
|
+
# '''使用TLS模式'''
|
|
157
|
+
# server = smtplib.SMTP(host=self.mail_host)
|
|
158
|
+
# server.connect(self.mail_host, self.mail_port) # 连接服务器
|
|
159
|
+
# server.starttls()
|
|
160
|
+
# server.login(self.__mail_user, self.__mail_password) # 登录操作
|
|
161
|
+
# server.sendmail(self.__mail_user, to_list.split(','), msg.as_string())
|
|
162
|
+
# server.close()
|
|
163
|
+
# return True
|
|
164
|
+
# else:
|
|
165
|
+
# '''使用普通模式'''
|
|
166
|
+
# server = smtplib.SMTP()
|
|
167
|
+
# server.connect(self.mail_host, self.mail_port) # 连接服务器
|
|
168
|
+
# server.login(self.__mail_user, self.__mail_password) # 登录操作
|
|
169
|
+
# server.sendmail(self.__mail_user, to_list.split(','), msg.as_string())
|
|
170
|
+
# server.close()
|
|
171
|
+
# return True
|
|
172
|
+
# except Exception as e:
|
|
173
|
+
# print(str(e))
|
|
174
|
+
# return False
|
|
175
|
+
#
|
|
96
176
|
|
|
97
177
|
def mail_login(user, password, mail_server='smtp.exmail.qq.com'):
|
|
98
|
-
|
|
178
|
+
# 模拟登录来验证邮箱
|
|
99
179
|
try:
|
|
100
180
|
server = smtplib.SMTP()
|
|
101
181
|
server.connect(mail_server)
|
|
102
182
|
server.login(user, password)
|
|
103
183
|
return True
|
|
104
184
|
except Exception as e:
|
|
105
|
-
|
|
185
|
+
logging.error(f"{user}邮箱认证出错:{e}")
|
|
106
186
|
return False
|
|
107
187
|
|
|
108
188
|
|
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env python
|
|
2
|
-
# -*- coding: utf-8 -*-
|
|
3
|
-
"""
|
|
4
|
-
Version : 0.0.1
|
|
5
|
-
Contact : 191715030@qq.com
|
|
6
|
-
Author : shenshuo
|
|
7
|
-
Date : 2019/12/12 17:56
|
|
8
|
-
Desc : API集合
|
|
9
|
-
"""
|
|
10
|
-
|
|
11
|
-
from .tools import singleton
|
|
12
|
-
from .apis import AdminAPIS, TaskAPIS, KerriganAPIS, AdminV4APIS, CMDBAPIS, AgentAPIS, NoticeAPIS
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
@singleton
|
|
16
|
-
class ConstAPIS(AdminAPIS, TaskAPIS, KerriganAPIS, AdminV4APIS, CMDBAPIS, AgentAPIS, NoticeAPIS):
|
|
17
|
-
def __init__(self):
|
|
18
|
-
pass
|
|
19
|
-
|
|
20
|
-
def __setattr__(self, name, value):
|
|
21
|
-
if name in self.__dict__:
|
|
22
|
-
raise TypeError("Can't rebind const (%s)" % name)
|
|
23
|
-
|
|
24
|
-
if not isinstance(value, dict):
|
|
25
|
-
raise TypeError("Value must be in dict format")
|
|
26
|
-
|
|
27
|
-
if not value.get('url'):
|
|
28
|
-
raise TypeError("Value must have url")
|
|
29
|
-
|
|
30
|
-
if not value.get('description'):
|
|
31
|
-
raise TypeError("Value must have description")
|
|
32
|
-
|
|
33
|
-
# body_data = value.get('body')
|
|
34
|
-
# if body_data is not None and not isinstance(body_data, (dict, list)):
|
|
35
|
-
# try:
|
|
36
|
-
# json.loads(body_data)
|
|
37
|
-
# except (TypeError, ValueError):
|
|
38
|
-
# raise TypeError("Body data cannot be loaded as JSON")
|
|
39
|
-
|
|
40
|
-
self.__dict__[name] = value
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
api_set = ConstAPIS()
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|