csc-cia-stne 0.0.24__py3-none-any.whl → 0.0.26__py3-none-any.whl
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.
- csc_cia_stne/__init__.py +3 -1
- csc_cia_stne/bc_sta.py +1 -3
- csc_cia_stne/email.py +142 -0
- csc_cia_stne/gcp_bigquery.py +146 -14
- csc_cia_stne/logger_rich.py +2 -1
- {csc_cia_stne-0.0.24.dist-info → csc_cia_stne-0.0.26.dist-info}/METADATA +2 -2
- {csc_cia_stne-0.0.24.dist-info → csc_cia_stne-0.0.26.dist-info}/RECORD +10 -9
- {csc_cia_stne-0.0.24.dist-info → csc_cia_stne-0.0.26.dist-info}/WHEEL +1 -1
- {csc_cia_stne-0.0.24.dist-info → csc_cia_stne-0.0.26.dist-info}/LICENCE +0 -0
- {csc_cia_stne-0.0.24.dist-info → csc_cia_stne-0.0.26.dist-info}/top_level.txt +0 -0
csc_cia_stne/__init__.py
CHANGED
@@ -15,6 +15,7 @@ from .stne_admin import StoneAdmin
|
|
15
15
|
from .bc_sta import BC_STA
|
16
16
|
from .bc_correios import BC_Correios
|
17
17
|
from .gcp_bigquery import BigQuery
|
18
|
+
from .email import Email
|
18
19
|
#from .utilitarios.functions import titulo
|
19
20
|
# Define os itens disponíveis para importação
|
20
21
|
__all__ = [
|
@@ -25,5 +26,6 @@ __all__ = [
|
|
25
26
|
"StoneAdmin",
|
26
27
|
"ServiceNow",
|
27
28
|
"Util",
|
28
|
-
"logger"
|
29
|
+
"logger",
|
30
|
+
"Email"
|
29
31
|
]
|
csc_cia_stne/bc_sta.py
CHANGED
@@ -1,10 +1,8 @@
|
|
1
1
|
from requests.auth import HTTPBasicAuth
|
2
|
-
import sys
|
3
|
-
from pydantic import BaseModel
|
4
2
|
import requests
|
5
3
|
import xml.etree.ElementTree as ET
|
6
4
|
import hashlib
|
7
|
-
from pydantic import BaseModel,
|
5
|
+
from pydantic import BaseModel, ValidationError, field_validator
|
8
6
|
from typing import Literal, Dict, Union, Optional
|
9
7
|
|
10
8
|
# Validações dos inputs
|
csc_cia_stne/email.py
ADDED
@@ -0,0 +1,142 @@
|
|
1
|
+
import smtplib
|
2
|
+
from email.mime.multipart import MIMEMultipart
|
3
|
+
from email.mime.text import MIMEText
|
4
|
+
from email.mime.base import MIMEBase
|
5
|
+
from email import encoders
|
6
|
+
from pydantic import BaseModel, ValidationError, field_validator
|
7
|
+
|
8
|
+
class InitParamsValidator(BaseModel):
|
9
|
+
email_sender: str
|
10
|
+
email_password: str
|
11
|
+
|
12
|
+
@field_validator('email_sender','email_password')
|
13
|
+
def check_str_input(cls, value, info):
|
14
|
+
if not isinstance(value, str) or not value.strip():
|
15
|
+
raise ValueError(f"O campo '{info.field_name}' deve ser strings e não {type(value)}")
|
16
|
+
return value
|
17
|
+
|
18
|
+
class SendEmailParamsValidator(BaseModel):
|
19
|
+
|
20
|
+
to: list
|
21
|
+
message: str
|
22
|
+
title: str
|
23
|
+
reply_to:str
|
24
|
+
attachments: list = []
|
25
|
+
cc: list = []
|
26
|
+
cco: list = []
|
27
|
+
|
28
|
+
@field_validator('message','title','reply_to')
|
29
|
+
def check_str_input(cls, value, info):
|
30
|
+
if not isinstance(value, str) or not value.strip():
|
31
|
+
raise ValueError(f"O campo '{info.field_name}' deve ser strings e não {type(value)}")
|
32
|
+
return value
|
33
|
+
|
34
|
+
@field_validator('to','attachments','cc','cco')
|
35
|
+
def check_list_input(cls, value, info):
|
36
|
+
if not isinstance(value, list):
|
37
|
+
raise ValueError(f"O parametro '{info.field_name}' deve ser uma lista")
|
38
|
+
|
39
|
+
return value
|
40
|
+
|
41
|
+
class Email():
|
42
|
+
|
43
|
+
def __init__(self, email_sender, email_password):
|
44
|
+
|
45
|
+
self.email_sender = email_sender
|
46
|
+
self.email_password = email_password
|
47
|
+
|
48
|
+
try:
|
49
|
+
|
50
|
+
InitParamsValidator(email_sender=email_sender, email_password=email_password)
|
51
|
+
|
52
|
+
except ValidationError as e:
|
53
|
+
|
54
|
+
raise ValueError("Erro na validação dos dados de input da inicialização da instância:", e.errors())
|
55
|
+
|
56
|
+
|
57
|
+
self.server = self.login_email()
|
58
|
+
|
59
|
+
if not isinstance(self.server, smtplib.SMTP) and 'status' in self.server and not self.server['status']:
|
60
|
+
|
61
|
+
raise ValueError("Erro na validação dos dados de input da inicialização da instância:", self.server['error'])
|
62
|
+
|
63
|
+
|
64
|
+
def login_email(self):
|
65
|
+
|
66
|
+
try:
|
67
|
+
|
68
|
+
server = smtplib.SMTP('smtp.gmail.com', 587)
|
69
|
+
server.starttls()
|
70
|
+
server.login(self.email_sender, self.email_password)
|
71
|
+
|
72
|
+
return server
|
73
|
+
|
74
|
+
except Exception as e:
|
75
|
+
|
76
|
+
return {
|
77
|
+
'status':False,
|
78
|
+
'error':str(e)
|
79
|
+
}
|
80
|
+
|
81
|
+
|
82
|
+
def send_email( self, to : list , message : str , title : str , reply_to: str, attachments : list = [] , cc : list = [] , cco : list = [] ) -> dict:
|
83
|
+
|
84
|
+
try:
|
85
|
+
|
86
|
+
SendEmailParamsValidator(to=to, message=message, title=title, reply_to=reply_to, attachments=attachments, cc=cc, cco=cco)
|
87
|
+
|
88
|
+
except ValidationError as e:
|
89
|
+
|
90
|
+
raise ValueError("Erro na validação dos dados para o envio do email:", e.errors())
|
91
|
+
|
92
|
+
try:
|
93
|
+
|
94
|
+
msg = MIMEMultipart()
|
95
|
+
|
96
|
+
msg["From"] = self.email_sender
|
97
|
+
|
98
|
+
msg["To"] = (",").join(to)
|
99
|
+
|
100
|
+
msg["cc"] = (",").join(cc)
|
101
|
+
|
102
|
+
msg['Reply-To'] = reply_to
|
103
|
+
|
104
|
+
msg["Subject"] = title
|
105
|
+
|
106
|
+
for file in attachments:
|
107
|
+
|
108
|
+
try:
|
109
|
+
|
110
|
+
attachment = open(file, "rb")
|
111
|
+
|
112
|
+
part = MIMEBase("application", "octet-stream")
|
113
|
+
|
114
|
+
part.set_payload(attachment.read())
|
115
|
+
|
116
|
+
encoders.encode_base64(part)
|
117
|
+
|
118
|
+
part.add_header("Content-Disposition", f"attachment; filename={file.split('/')[-1]}")
|
119
|
+
|
120
|
+
msg.attach(part)
|
121
|
+
|
122
|
+
attachment.close()
|
123
|
+
|
124
|
+
except Exception as e:
|
125
|
+
|
126
|
+
return {
|
127
|
+
'status':False,
|
128
|
+
'error':str(e)
|
129
|
+
}
|
130
|
+
|
131
|
+
msg.attach(MIMEText(message))
|
132
|
+
|
133
|
+
self.server.sendmail(self.email_sender, to + cc + cco, msg.as_string())
|
134
|
+
|
135
|
+
return True
|
136
|
+
|
137
|
+
except Exception as e:
|
138
|
+
|
139
|
+
return {
|
140
|
+
'status':False,
|
141
|
+
'error':str(e)
|
142
|
+
}
|
csc_cia_stne/gcp_bigquery.py
CHANGED
@@ -2,10 +2,104 @@ from google.cloud import bigquery
|
|
2
2
|
import json
|
3
3
|
import os
|
4
4
|
from google.oauth2 import service_account
|
5
|
+
from pydantic import BaseModel, ValidationError, field_validator,model_validator
|
6
|
+
|
7
|
+
class InitParamsValidator(BaseModel):
|
8
|
+
limit:int
|
9
|
+
id_project:str
|
10
|
+
creds_dict:dict
|
11
|
+
creds_file:str
|
12
|
+
|
13
|
+
@field_validator('limit')
|
14
|
+
def check_input_basic(cls, value, info):
|
15
|
+
if not isinstance(value, int):
|
16
|
+
raise ValueError(f"O parametro 'limit' deve ser um inteiro e não um {type(value)}")
|
17
|
+
|
18
|
+
return value
|
19
|
+
|
20
|
+
@field_validator('id_project')
|
21
|
+
def check_str_input(cls, value, info):
|
22
|
+
if not isinstance(value, str) or not value.strip():
|
23
|
+
raise ValueError(f"O parametro 'id_project' deve ser uma string e não um {type(value)} e não vazio")
|
24
|
+
return value
|
25
|
+
|
26
|
+
@model_validator(mode="after")
|
27
|
+
def check_others_input(cls, model):
|
28
|
+
creds_dict = model.creds_dict
|
29
|
+
creds_file = model.creds_file
|
30
|
+
|
31
|
+
if isinstance(creds_dict, dict):
|
32
|
+
return model
|
33
|
+
|
34
|
+
elif isinstance(creds_file, str) and creds_file.strip():
|
35
|
+
return model
|
36
|
+
|
37
|
+
else:
|
38
|
+
raise ValueError("Pelo menos um dos parâmetros 'creds_dict' ou 'creds_file' deve ser fornecido.")
|
39
|
+
|
40
|
+
|
41
|
+
class tryQueryValidator(BaseModel):
|
42
|
+
|
43
|
+
query_to_execute:str
|
44
|
+
organize:bool
|
45
|
+
use_legacy:bool
|
46
|
+
use_cache:bool
|
47
|
+
query_parameters:list
|
48
|
+
|
49
|
+
@field_validator('query_to_execute')
|
50
|
+
def check_str_input(cls, value, info):
|
51
|
+
if not isinstance(value, str) or not value.strip():
|
52
|
+
raise ValueError(f"O parametro '{info.field_name}' deve ser uma string não vazia")
|
53
|
+
|
54
|
+
return value
|
55
|
+
|
56
|
+
@field_validator('organize','use_legacy','use_cache')
|
57
|
+
def check_bool_input(cls, value, info):
|
58
|
+
if not isinstance(value, bool):
|
59
|
+
raise ValueError(f"O parametro '{info.field_name}' deve ser um boleano")
|
60
|
+
|
61
|
+
return value
|
62
|
+
|
63
|
+
@field_validator('query_parameters')
|
64
|
+
def check_list_input(cls, value, info):
|
65
|
+
if not isinstance(value, list):
|
66
|
+
raise ValueError(f"O parametro '{info.field_name}' deve ser uma lista")
|
67
|
+
|
68
|
+
return value
|
69
|
+
|
70
|
+
|
71
|
+
class tryInsertListValidator(BaseModel):
|
72
|
+
|
73
|
+
insert_limit:int
|
74
|
+
list_to_insert:list
|
75
|
+
table:str
|
76
|
+
|
77
|
+
@field_validator('list_to_insert')
|
78
|
+
def check_list_input(cls, value, info):
|
79
|
+
if not isinstance(value, list) and len(value) > 0:
|
80
|
+
raise ValueError(f"O parametro '{info.field_name}' deve ser uma lista e não estar vazia")
|
81
|
+
|
82
|
+
return value
|
83
|
+
|
84
|
+
@field_validator('table')
|
85
|
+
def check_str_input(cls, value, info):
|
86
|
+
if not isinstance(value, str) or not value.strip():
|
87
|
+
raise ValueError(f"O parametro '{info.field_name}' deve ser uma string não vazia")
|
88
|
+
|
89
|
+
return value
|
90
|
+
|
91
|
+
@field_validator('insert_limit')
|
92
|
+
def check_int_input(cls, value, info):
|
93
|
+
if not isinstance(value, int) or value > 10000:
|
94
|
+
raise ValueError(f"O parametro '{info.field_name}' deve ser um inteiro não maior que 10000")
|
95
|
+
|
96
|
+
return value
|
5
97
|
|
6
98
|
class BigQuery():
|
7
99
|
|
8
|
-
|
100
|
+
|
101
|
+
def __init__(self, id_project: str, creds_dict: dict = None, creds_file: str = "", limit: int = 3):
|
102
|
+
|
9
103
|
"""
|
10
104
|
Inicializa a classe BigQuery.
|
11
105
|
Parâmetros:
|
@@ -14,9 +108,21 @@ class BigQuery():
|
|
14
108
|
"""
|
15
109
|
|
16
110
|
self.limit = limit
|
17
|
-
self.
|
111
|
+
self.id_project = id_project
|
112
|
+
self.creds_dict = creds_dict
|
113
|
+
self.creds_file = creds_file
|
114
|
+
self.client = self.create_client()
|
18
115
|
|
19
|
-
|
116
|
+
try:
|
117
|
+
|
118
|
+
InitParamsValidator(limit=limit, id_project=id_project, creds_dict=creds_dict, creds_file=creds_file)
|
119
|
+
|
120
|
+
except ValidationError as e:
|
121
|
+
|
122
|
+
raise ValueError("Erro na validação dos dados de input da inicialização da instância:", e.errors())
|
123
|
+
|
124
|
+
|
125
|
+
def create_client(self) -> bigquery.Client:
|
20
126
|
"""
|
21
127
|
Cria um cliente BigQuery com base nas credenciais fornecidas.
|
22
128
|
Parâmetros:
|
@@ -34,19 +140,19 @@ class BigQuery():
|
|
34
140
|
|
35
141
|
try:
|
36
142
|
|
37
|
-
if(creds_dict is not None):
|
143
|
+
if(self.creds_dict is not None):
|
38
144
|
|
39
145
|
credentials = service_account.Credentials.from_service_account_info(
|
40
|
-
creds_dict,
|
146
|
+
self.creds_dict,
|
41
147
|
scopes=["https://www.googleapis.com/auth/cloud-platform"],
|
42
148
|
)
|
43
149
|
|
44
|
-
client = bigquery.Client(credentials=credentials, project=id_project)
|
150
|
+
client = bigquery.Client(credentials=credentials, project=self.id_project)
|
45
151
|
|
46
|
-
elif(str(creds_file) > 0):
|
152
|
+
elif(str(self.creds_file) > 0):
|
47
153
|
|
48
154
|
credentials = service_account.Credentials.from_service_account_file(
|
49
|
-
creds_file,
|
155
|
+
self.creds_file,
|
50
156
|
scopes=["https://www.googleapis.com/auth/cloud-platform"],
|
51
157
|
)
|
52
158
|
|
@@ -67,7 +173,9 @@ class BigQuery():
|
|
67
173
|
'details':str(e)
|
68
174
|
}
|
69
175
|
|
70
|
-
|
176
|
+
|
177
|
+
def try_query(self, query_to_execute: str, organize: bool = False, use_legacy: bool = False, use_cache: bool = False, query_parameters: list = []) -> dict:
|
178
|
+
|
71
179
|
"""
|
72
180
|
Executa uma consulta no BigQuery e retorna o resultado.
|
73
181
|
Args:
|
@@ -85,13 +193,28 @@ class BigQuery():
|
|
85
193
|
'status': False,
|
86
194
|
"""
|
87
195
|
|
196
|
+
try:
|
197
|
+
|
198
|
+
tryQueryValidator(query_to_execute=query_to_execute, organize=organize, use_legacy=use_legacy, use_cache=use_cache, query_parameters=query_parameters)
|
199
|
+
|
200
|
+
except ValidationError as e:
|
201
|
+
|
202
|
+
raise ValueError("Erro na validação dos dados de input da função para tentar executar a query:", e.errors())
|
203
|
+
|
88
204
|
error = ""
|
89
205
|
|
90
206
|
for try_out in range(self.limit):
|
91
207
|
|
92
208
|
try:
|
93
209
|
|
94
|
-
|
210
|
+
job_config = bigquery.QueryJobConfig(
|
211
|
+
priority=bigquery.QueryPriority.INTERACTIVE,
|
212
|
+
use_legacy_sql=use_legacy,
|
213
|
+
use_query_cache=use_cache,
|
214
|
+
query_parameters=query_parameters,
|
215
|
+
)
|
216
|
+
|
217
|
+
result_query = self.client.query(query_to_execute,job_config=job_config).result()
|
95
218
|
|
96
219
|
error = False
|
97
220
|
|
@@ -121,14 +244,15 @@ class BigQuery():
|
|
121
244
|
'error': str(error)
|
122
245
|
}
|
123
246
|
|
124
|
-
|
247
|
+
|
248
|
+
def insert_list(self, table: str, list_to_insert: list = [], insert_limit: int = 10000) -> dict:
|
125
249
|
|
126
250
|
"""
|
127
251
|
Insere uma lista de dicionários em uma tabela do BigQuery.
|
128
252
|
Args:
|
129
253
|
client (bigquery.Client): Cliente do BigQuery.
|
130
254
|
table (str): Nome da tabela onde os dados serão inseridos.
|
131
|
-
|
255
|
+
list_to_insert (dict, optional): Lista de dicionários a serem inseridos. O padrão é [].
|
132
256
|
limit_trys (int, optional): Número máximo de tentativas de inserção. O padrão é 3.
|
133
257
|
Returns:
|
134
258
|
dict: Dicionário contendo o status da inserção e informações adicionais.
|
@@ -138,16 +262,24 @@ class BigQuery():
|
|
138
262
|
{'status': False, 'error': error, 'last_try': list_to_insert, 'inserted': inserted}
|
139
263
|
"""
|
140
264
|
|
265
|
+
try:
|
266
|
+
|
267
|
+
tryInsertListValidator(table=table, list_to_insert=list_to_insert, insert_limit=insert_limit)
|
268
|
+
|
269
|
+
except ValidationError as e:
|
270
|
+
|
271
|
+
raise ValueError("Erro na validação dos dados de input da função para tentar inserir dados em uma tabela:", e.errors())
|
272
|
+
|
141
273
|
table_ref = self.client.get_table(table)
|
142
274
|
|
143
275
|
error = ""
|
144
276
|
|
145
277
|
inserted = []
|
146
278
|
|
147
|
-
for data in range(0, len(
|
279
|
+
for data in range(0, len(list_to_insert), insert_limit):
|
148
280
|
|
149
281
|
# listagem que será inserida no big query
|
150
|
-
list_to_insert =
|
282
|
+
list_to_insert = list_to_insert[data:data+10000]
|
151
283
|
|
152
284
|
for try_out in range(self.limit):
|
153
285
|
|
csc_cia_stne/logger_rich.py
CHANGED
@@ -97,7 +97,8 @@ def add_log_level(level_name, level_num, method_name=None):
|
|
97
97
|
|
98
98
|
if self.isEnabledFor(level_num):
|
99
99
|
|
100
|
-
self._log(level_num, message, args, **kwargs)
|
100
|
+
#self._log(level_num, message, args, **kwargs)
|
101
|
+
self._log(level_num, message, args, **{**kwargs, "stacklevel": 2})
|
101
102
|
|
102
103
|
def log_to_root(message, *args, **kwargs):
|
103
104
|
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: csc_cia_stne
|
3
|
-
Version: 0.0.
|
3
|
+
Version: 0.0.26
|
4
4
|
Summary: Biblioteca do time CSC-CIA utilizada no desenvolvimento de RPAs
|
5
5
|
License: MIT
|
6
6
|
Keywords: karavela,csc,cia,stone,rpa
|
@@ -10,7 +10,7 @@ Requires-Dist: python-json-logger
|
|
10
10
|
Requires-Dist: rich
|
11
11
|
Requires-Dist: requests
|
12
12
|
Requires-Dist: pydantic
|
13
|
-
Requires-Dist:
|
13
|
+
Requires-Dist: pydantic_settings
|
14
14
|
Requires-Dist: zeep
|
15
15
|
Requires-Dist: google-cloud-bigquery
|
16
16
|
Requires-Dist: google-cloud-storage
|
@@ -1,10 +1,11 @@
|
|
1
|
-
csc_cia_stne/__init__.py,sha256=
|
1
|
+
csc_cia_stne/__init__.py,sha256=xTOb4_9Z6FrZqXGT1zIjtgVady-GO5IwnddAaaV_gj0,758
|
2
2
|
csc_cia_stne/bc_correios.py,sha256=ANsvLyL7wdkM0MvjjBHB2Ih4eyTcyWgt5IqiK0Rv89E,23014
|
3
|
-
csc_cia_stne/bc_sta.py,sha256=
|
4
|
-
csc_cia_stne/
|
3
|
+
csc_cia_stne/bc_sta.py,sha256=uyoCp-KTpkWwpyWNWp20JuDfMRYGCKxERnRQVso80iQ,10903
|
4
|
+
csc_cia_stne/email.py,sha256=TGh4JrEPLcGV0djBxQf7yaCbQFRqXHGiHJfk1jTwzJo,4152
|
5
|
+
csc_cia_stne/gcp_bigquery.py,sha256=U-m0vPmnzzVDFonY9YrDnB-93E-fSpzNO1JjGDSB7dY,10190
|
5
6
|
csc_cia_stne/karavela.py,sha256=Q7MbQXXz_jtrLHM7QeenbSzcro07EpoFk4lKglivJ_I,3564
|
6
7
|
csc_cia_stne/logger_json.py,sha256=2G0rm0lyCtHn4o2v7fzn4wMylb0A_nbxiQatnrSZxHs,1212
|
7
|
-
csc_cia_stne/logger_rich.py,sha256=
|
8
|
+
csc_cia_stne/logger_rich.py,sha256=WcfmdbsQuVfz_lbZ1v1wtrGspaESu-PdQthyuLkKQjM,3472
|
8
9
|
csc_cia_stne/servicenow.py,sha256=vSsNSANFyCZtDu2O7YmdoCbr-_bO1sgMWnOI29mFBOA,23311
|
9
10
|
csc_cia_stne/stne_admin.py,sha256=G5ozXt18VjKL2BHtROQk4GnfVY1xM14RXSQ-rra_D54,15487
|
10
11
|
csc_cia_stne/utilitarios/__init__.py,sha256=4YFhzxu8F_CDHU6iaNhpzz9mfX-8wfJc1XEQInJzwJ4,98
|
@@ -13,8 +14,8 @@ csc_cia_stne/utilitarios/functions/func_b64.py,sha256=XGU34BIQQXWXBS0yM2B4A2wDlc
|
|
13
14
|
csc_cia_stne/utilitarios/functions/func_converters.py,sha256=EY1zvlBaRX7G1MceVSiRXwwKDQDZwUO9iECBL0fe5iU,481
|
14
15
|
csc_cia_stne/utilitarios/functions/func_recriar_pastas.py,sha256=2_unoSoQHxShcMw_0XIL9F0NgiF1QCKsX4drvg0fEb8,415
|
15
16
|
csc_cia_stne/utilitarios/functions/func_titulo.py,sha256=EhUtsiIOAz4yERNZl3EOHjiFLjj4rK3pr_KB0DxwGIA,3943
|
16
|
-
csc_cia_stne-0.0.
|
17
|
-
csc_cia_stne-0.0.
|
18
|
-
csc_cia_stne-0.0.
|
19
|
-
csc_cia_stne-0.0.
|
20
|
-
csc_cia_stne-0.0.
|
17
|
+
csc_cia_stne-0.0.26.dist-info/LICENCE,sha256=LPGMtgKki2C3KEZP7hDhA1HBrlq5JCHkIeStUCLEMx4,1073
|
18
|
+
csc_cia_stne-0.0.26.dist-info/METADATA,sha256=NRg5PPo6abhue9hU873kKPDiKmJSoJ4d2i5l21ALE4w,1003
|
19
|
+
csc_cia_stne-0.0.26.dist-info/WHEEL,sha256=PZUExdf71Ui_so67QXpySuHtCi3-J3wvF4ORK6k_S8U,91
|
20
|
+
csc_cia_stne-0.0.26.dist-info/top_level.txt,sha256=ldo7GVv3tQx5KJvwBzdZzzQmjPys2NDVVn1rv0BOF2Q,13
|
21
|
+
csc_cia_stne-0.0.26.dist-info/RECORD,,
|
File without changes
|
File without changes
|