dcs-sdk 1.6.4__py3-none-any.whl → 1.6.6__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.
- dcs_core/__init__.py +13 -0
- dcs_core/__main__.py +17 -0
- dcs_core/__version__.py +15 -0
- dcs_core/cli/__init__.py +13 -0
- dcs_core/cli/cli.py +165 -0
- dcs_core/core/__init__.py +19 -0
- dcs_core/core/common/__init__.py +13 -0
- dcs_core/core/common/errors.py +50 -0
- dcs_core/core/common/models/__init__.py +13 -0
- dcs_core/core/common/models/configuration.py +284 -0
- dcs_core/core/common/models/dashboard.py +24 -0
- dcs_core/core/common/models/data_source_resource.py +75 -0
- dcs_core/core/common/models/metric.py +160 -0
- dcs_core/core/common/models/profile.py +75 -0
- dcs_core/core/common/models/validation.py +216 -0
- dcs_core/core/common/models/widget.py +44 -0
- dcs_core/core/configuration/__init__.py +13 -0
- dcs_core/core/configuration/config_loader.py +139 -0
- dcs_core/core/configuration/configuration_parser.py +262 -0
- dcs_core/core/configuration/configuration_parser_arc.py +328 -0
- dcs_core/core/datasource/__init__.py +13 -0
- dcs_core/core/datasource/base.py +62 -0
- dcs_core/core/datasource/manager.py +112 -0
- dcs_core/core/datasource/search_datasource.py +421 -0
- dcs_core/core/datasource/sql_datasource.py +1094 -0
- dcs_core/core/inspect.py +163 -0
- dcs_core/core/logger/__init__.py +13 -0
- dcs_core/core/logger/base.py +32 -0
- dcs_core/core/logger/default_logger.py +94 -0
- dcs_core/core/metric/__init__.py +13 -0
- dcs_core/core/metric/base.py +220 -0
- dcs_core/core/metric/combined_metric.py +98 -0
- dcs_core/core/metric/custom_metric.py +34 -0
- dcs_core/core/metric/manager.py +137 -0
- dcs_core/core/metric/numeric_metric.py +403 -0
- dcs_core/core/metric/reliability_metric.py +90 -0
- dcs_core/core/profiling/__init__.py +13 -0
- dcs_core/core/profiling/datasource_profiling.py +136 -0
- dcs_core/core/profiling/numeric_field_profiling.py +72 -0
- dcs_core/core/profiling/text_field_profiling.py +67 -0
- dcs_core/core/repository/__init__.py +13 -0
- dcs_core/core/repository/metric_repository.py +77 -0
- dcs_core/core/utils/__init__.py +13 -0
- dcs_core/core/utils/log.py +29 -0
- dcs_core/core/utils/tracking.py +105 -0
- dcs_core/core/utils/utils.py +44 -0
- dcs_core/core/validation/__init__.py +13 -0
- dcs_core/core/validation/base.py +230 -0
- dcs_core/core/validation/completeness_validation.py +153 -0
- dcs_core/core/validation/custom_query_validation.py +24 -0
- dcs_core/core/validation/manager.py +282 -0
- dcs_core/core/validation/numeric_validation.py +276 -0
- dcs_core/core/validation/reliability_validation.py +91 -0
- dcs_core/core/validation/uniqueness_validation.py +61 -0
- dcs_core/core/validation/validity_validation.py +738 -0
- dcs_core/integrations/__init__.py +13 -0
- dcs_core/integrations/databases/__init__.py +13 -0
- dcs_core/integrations/databases/bigquery.py +187 -0
- dcs_core/integrations/databases/databricks.py +51 -0
- dcs_core/integrations/databases/db2.py +652 -0
- dcs_core/integrations/databases/elasticsearch.py +61 -0
- dcs_core/integrations/databases/mssql.py +979 -0
- dcs_core/integrations/databases/mysql.py +409 -0
- dcs_core/integrations/databases/opensearch.py +64 -0
- dcs_core/integrations/databases/oracle.py +719 -0
- dcs_core/integrations/databases/postgres.py +570 -0
- dcs_core/integrations/databases/redshift.py +53 -0
- dcs_core/integrations/databases/snowflake.py +48 -0
- dcs_core/integrations/databases/spark_df.py +111 -0
- dcs_core/integrations/databases/sybase.py +1069 -0
- dcs_core/integrations/storage/__init__.py +13 -0
- dcs_core/integrations/storage/local_file.py +149 -0
- dcs_core/integrations/utils/__init__.py +13 -0
- dcs_core/integrations/utils/utils.py +36 -0
- dcs_core/report/__init__.py +13 -0
- dcs_core/report/dashboard.py +211 -0
- dcs_core/report/models.py +88 -0
- dcs_core/report/static/assets/fonts/DMSans-Bold.ttf +0 -0
- dcs_core/report/static/assets/fonts/DMSans-Medium.ttf +0 -0
- dcs_core/report/static/assets/fonts/DMSans-Regular.ttf +0 -0
- dcs_core/report/static/assets/fonts/DMSans-SemiBold.ttf +0 -0
- dcs_core/report/static/assets/images/docs.svg +6 -0
- dcs_core/report/static/assets/images/github.svg +4 -0
- dcs_core/report/static/assets/images/logo.svg +7 -0
- dcs_core/report/static/assets/images/slack.svg +13 -0
- dcs_core/report/static/index.js +2 -0
- dcs_core/report/static/index.js.LICENSE.txt +3971 -0
- dcs_sdk/__version__.py +1 -1
- dcs_sdk/cli/cli.py +3 -0
- {dcs_sdk-1.6.4.dist-info → dcs_sdk-1.6.6.dist-info}/METADATA +24 -2
- dcs_sdk-1.6.6.dist-info/RECORD +159 -0
- {dcs_sdk-1.6.4.dist-info → dcs_sdk-1.6.6.dist-info}/entry_points.txt +1 -0
- dcs_sdk-1.6.4.dist-info/RECORD +0 -72
- {dcs_sdk-1.6.4.dist-info → dcs_sdk-1.6.6.dist-info}/WHEEL +0 -0
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# Copyright 2022-present, the Waterdip Labs Pvt. Ltd.
|
|
2
|
+
#
|
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
# you may not use this file except in compliance with the License.
|
|
5
|
+
# You may obtain a copy of the License at
|
|
6
|
+
#
|
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
#
|
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
# See the License for the specific language governing permissions and
|
|
13
|
+
# limitations under the License.
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
# Copyright 2022-present, the Waterdip Labs Pvt. Ltd.
|
|
2
|
+
#
|
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
# you may not use this file except in compliance with the License.
|
|
5
|
+
# You may obtain a copy of the License at
|
|
6
|
+
#
|
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
#
|
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
# See the License for the specific language governing permissions and
|
|
13
|
+
# limitations under the License.
|
|
14
|
+
|
|
15
|
+
import datetime as dt
|
|
16
|
+
import os
|
|
17
|
+
from datetime import datetime
|
|
18
|
+
from pathlib import Path
|
|
19
|
+
from typing import Dict, List, Literal, Tuple, Union
|
|
20
|
+
|
|
21
|
+
from dcs_core.core.common.errors import DataChecksRuntimeError
|
|
22
|
+
from dcs_core.core.common.models.metric import MetricValue
|
|
23
|
+
from dcs_core.core.repository.metric_repository import MetricRepository
|
|
24
|
+
from dcs_core.core.utils.utils import ensure_directory_exists, write_to_file
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
class LocalFileMetricRepository(MetricRepository):
|
|
28
|
+
"""
|
|
29
|
+
Directory Structure:
|
|
30
|
+
|
|
31
|
+
Dir:metric_identifier
|
|
32
|
+
- Dir:daily:
|
|
33
|
+
- file:metric_identifier__date1.json
|
|
34
|
+
- file:metric_identifier__date2.json
|
|
35
|
+
- Dir:hourly:
|
|
36
|
+
- file:metric_identifier__date1.json
|
|
37
|
+
- file:metric_identifier__date2.json
|
|
38
|
+
"""
|
|
39
|
+
|
|
40
|
+
def __init__(self, storage_path):
|
|
41
|
+
self.storage_path = f"{storage_path}/metrics"
|
|
42
|
+
try:
|
|
43
|
+
ensure_directory_exists(self.storage_path, create_if_not_exists=True)
|
|
44
|
+
except Exception as e:
|
|
45
|
+
raise DataChecksRuntimeError(
|
|
46
|
+
f"Unable to locate metric storage directory: {self.storage_path} due to error: {e}"
|
|
47
|
+
)
|
|
48
|
+
|
|
49
|
+
@staticmethod
|
|
50
|
+
def get_timestamp_keys(metric_value: MetricValue):
|
|
51
|
+
metric_timestamp = metric_value.timestamp
|
|
52
|
+
metric_timestamp_hour = metric_timestamp.hour
|
|
53
|
+
|
|
54
|
+
# This is 'YYYY-MM-DD'.
|
|
55
|
+
timestamp_date_key = metric_timestamp.date().isoformat()
|
|
56
|
+
timestamp_hour_key = f"{timestamp_date_key}_{metric_timestamp_hour}"
|
|
57
|
+
return timestamp_date_key, timestamp_hour_key
|
|
58
|
+
|
|
59
|
+
def _generate_file_names(self, metric_id: str, metric_value: MetricValue) -> Tuple[str, str]:
|
|
60
|
+
timestamp_date_key, timestamp_hour_key = self.get_timestamp_keys(metric_value)
|
|
61
|
+
|
|
62
|
+
daily_directory = f"{self.storage_path}/{metric_id}/daily"
|
|
63
|
+
hourly_directory = f"{self.storage_path}/{metric_id}/hourly"
|
|
64
|
+
|
|
65
|
+
ensure_directory_exists(daily_directory, create_if_not_exists=True)
|
|
66
|
+
ensure_directory_exists(hourly_directory, create_if_not_exists=True)
|
|
67
|
+
|
|
68
|
+
daily_file_name = f"{daily_directory}/{timestamp_date_key}.json"
|
|
69
|
+
hourly_file_name = f"{hourly_directory}/{timestamp_hour_key}.json"
|
|
70
|
+
|
|
71
|
+
return daily_file_name, hourly_file_name
|
|
72
|
+
|
|
73
|
+
def save_metric(self, metric_id: str, metric_value: MetricValue) -> int:
|
|
74
|
+
try:
|
|
75
|
+
daily_file, hourly_file = self._generate_file_names(metric_id, metric_value)
|
|
76
|
+
write_to_file(daily_file, metric_value.json)
|
|
77
|
+
write_to_file(hourly_file, metric_value.json)
|
|
78
|
+
return 1
|
|
79
|
+
except Exception as e:
|
|
80
|
+
raise DataChecksRuntimeError(f"Unable to save metric: {metric_id} due to error: {e}")
|
|
81
|
+
|
|
82
|
+
def save_all_metrics(self, metrics: List[MetricValue]) -> int:
|
|
83
|
+
try:
|
|
84
|
+
for metric in metrics:
|
|
85
|
+
self.save_metric(metric.identity, metric)
|
|
86
|
+
return len(metrics)
|
|
87
|
+
except Exception as e:
|
|
88
|
+
raise DataChecksRuntimeError(f"Unable to save metrics due to error: {e}")
|
|
89
|
+
|
|
90
|
+
def _get_all_metric_files(
|
|
91
|
+
self,
|
|
92
|
+
metric_id: str,
|
|
93
|
+
start_date: datetime = None,
|
|
94
|
+
end_date: datetime = None,
|
|
95
|
+
granularity: Literal["daily", "hourly"] = "daily",
|
|
96
|
+
) -> List[str]:
|
|
97
|
+
directory_name = f"{self.storage_path}/{metric_id}/{granularity}"
|
|
98
|
+
if start_date is None and end_date is None:
|
|
99
|
+
return [directory_name + "/" + file for file in os.listdir(directory_name)]
|
|
100
|
+
elif start_date is not None and end_date is not None:
|
|
101
|
+
dates = [
|
|
102
|
+
(start_date + dt.timedelta(days=x)).date().isoformat() for x in range((end_date - start_date).days + 1)
|
|
103
|
+
]
|
|
104
|
+
|
|
105
|
+
if granularity == "hourly":
|
|
106
|
+
return [f"{directory_name}/{date}_{hour}.json" for date in dates for hour in range(0, 24)]
|
|
107
|
+
else:
|
|
108
|
+
return [f"{directory_name}/{date}.json" for date in dates]
|
|
109
|
+
else:
|
|
110
|
+
raise DataChecksRuntimeError(
|
|
111
|
+
"Both start_date and end_date should be provided or none of them should be provided."
|
|
112
|
+
)
|
|
113
|
+
|
|
114
|
+
@staticmethod
|
|
115
|
+
def _json_to_metric_value(file_path: str) -> Union[MetricValue, None]:
|
|
116
|
+
file_exists = Path(file_path).exists()
|
|
117
|
+
if not file_exists:
|
|
118
|
+
return None
|
|
119
|
+
with open(file_path, "r") as f:
|
|
120
|
+
json = f.read()
|
|
121
|
+
return MetricValue.from_json(json)
|
|
122
|
+
|
|
123
|
+
def get_metric_by_id(
|
|
124
|
+
self, metric_id: str, start_date: datetime = None, end_date: datetime = None
|
|
125
|
+
) -> Tuple[List[MetricValue], List[MetricValue]]:
|
|
126
|
+
daily_file_list = self._get_all_metric_files(metric_id, start_date, end_date, "daily")
|
|
127
|
+
hourly_file_list = self._get_all_metric_files(metric_id, start_date, end_date, "hourly")
|
|
128
|
+
daily_metrics: List[MetricValue] = []
|
|
129
|
+
hourly_metrics: List[MetricValue] = []
|
|
130
|
+
for file in daily_file_list:
|
|
131
|
+
if (json_value := self._json_to_metric_value(file)) is not None:
|
|
132
|
+
daily_metrics.append(json_value)
|
|
133
|
+
for file in hourly_file_list:
|
|
134
|
+
if (json_value := self._json_to_metric_value(file)) is not None:
|
|
135
|
+
hourly_metrics.append(json_value)
|
|
136
|
+
|
|
137
|
+
return daily_metrics, hourly_metrics
|
|
138
|
+
|
|
139
|
+
def get_all_metrics(
|
|
140
|
+
self, start_date: datetime = None, end_date: datetime = None
|
|
141
|
+
) -> Dict[str, Tuple[List[MetricValue], List[MetricValue]]]:
|
|
142
|
+
metrics_ids = os.listdir(self.storage_path)
|
|
143
|
+
|
|
144
|
+
metrics = {}
|
|
145
|
+
for metric_id in metrics_ids:
|
|
146
|
+
daily_metrics, hourly_metrics = self.get_metric_by_id(metric_id, start_date, end_date)
|
|
147
|
+
metrics[metric_id] = (daily_metrics, hourly_metrics)
|
|
148
|
+
|
|
149
|
+
return metrics
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# Copyright 2022-present, the Waterdip Labs Pvt. Ltd.
|
|
2
|
+
#
|
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
# you may not use this file except in compliance with the License.
|
|
5
|
+
# You may obtain a copy of the License at
|
|
6
|
+
#
|
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
#
|
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
# See the License for the specific language governing permissions and
|
|
13
|
+
# limitations under the License.
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
# Copyright 2022-present, the Waterdip Labs Pvt. Ltd.
|
|
2
|
+
#
|
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
# you may not use this file except in compliance with the License.
|
|
5
|
+
# You may obtain a copy of the License at
|
|
6
|
+
#
|
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
#
|
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
# See the License for the specific language governing permissions and
|
|
13
|
+
# limitations under the License.
|
|
14
|
+
|
|
15
|
+
import os
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def ibm_db2_dll_files_loader():
|
|
19
|
+
"""
|
|
20
|
+
Load the IBM DB2 shared library on Windows.
|
|
21
|
+
|
|
22
|
+
Instructions:
|
|
23
|
+
- Download the IBM DB2 client from
|
|
24
|
+
https://www.ibm.com/support/pages/db2-odbc-cli-driver-download-and-installation-information
|
|
25
|
+
- Add a system variable `IBM_DB_HOME` with the path to the extracted folder
|
|
26
|
+
(e.g., C:\Program Files\IBM\SQLLIB).
|
|
27
|
+
Do not include 'bin' in the path.
|
|
28
|
+
"""
|
|
29
|
+
if os.name == "nt":
|
|
30
|
+
ibm_db_home = os.getenv("IBM_DB_HOME")
|
|
31
|
+
|
|
32
|
+
if ibm_db_home:
|
|
33
|
+
dll_directory = os.path.join(ibm_db_home, "bin")
|
|
34
|
+
os.add_dll_directory(dll_directory)
|
|
35
|
+
else:
|
|
36
|
+
print("IBM_DB_HOME environment variable is not set. Please set to use DB2.")
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# Copyright 2022-present, the Waterdip Labs Pvt. Ltd.
|
|
2
|
+
#
|
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
# you may not use this file except in compliance with the License.
|
|
5
|
+
# You may obtain a copy of the License at
|
|
6
|
+
#
|
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
#
|
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
# See the License for the specific language governing permissions and
|
|
13
|
+
# limitations under the License.
|
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
# Copyright 2022-present, the Waterdip Labs Pvt. Ltd.
|
|
2
|
+
#
|
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
# you may not use this file except in compliance with the License.
|
|
5
|
+
# You may obtain a copy of the License at
|
|
6
|
+
#
|
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
#
|
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
# See the License for the specific language governing permissions and
|
|
13
|
+
# limitations under the License.
|
|
14
|
+
|
|
15
|
+
import base64
|
|
16
|
+
import json
|
|
17
|
+
import os
|
|
18
|
+
import uuid
|
|
19
|
+
from dataclasses import asdict
|
|
20
|
+
|
|
21
|
+
from dcs_core.core.common.models.metric import DataSourceMetrics
|
|
22
|
+
from dcs_core.core.inspect import InspectOutput
|
|
23
|
+
from dcs_core.report.models import (
|
|
24
|
+
DashboardInfo,
|
|
25
|
+
DashboardMetricOverview,
|
|
26
|
+
GroupedMetricsType,
|
|
27
|
+
MetricHealthStatus,
|
|
28
|
+
MetricRow,
|
|
29
|
+
TemplateParams,
|
|
30
|
+
)
|
|
31
|
+
|
|
32
|
+
STATIC_PATH = os.path.join(os.path.dirname(__file__), "static")
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def __load_js():
|
|
36
|
+
return open(f"{STATIC_PATH}/index.js", encoding="utf-8").read()
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
def __load_font(font: str):
|
|
40
|
+
return base64.b64encode(open(f"{STATIC_PATH}/assets/fonts/{font}", "rb").read()).decode()
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def __load_image(image: str):
|
|
44
|
+
return base64.b64encode(open(f"{STATIC_PATH}/assets/images/{image}", "rb").read()).decode()
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
def dashboard_info_to_json(dashboard_info: DashboardInfo):
|
|
48
|
+
asdict_result = asdict(dashboard_info)
|
|
49
|
+
return json.dumps(asdict_result)
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
def html_template(params: TemplateParams):
|
|
53
|
+
lib_block = f"""<script>{__load_js()}</script>""" if params.embed_lib else "<!-- no embedded lib -->"
|
|
54
|
+
data_block = (
|
|
55
|
+
f"""<script>
|
|
56
|
+
var data_{params.dashboard_id} = {dashboard_info_to_json(params.dashboard_info)};
|
|
57
|
+
</script>"""
|
|
58
|
+
if params.embed_data
|
|
59
|
+
else "<!-- no embedded data -->"
|
|
60
|
+
)
|
|
61
|
+
js_files_block = "\n".join([f'<script src="{file}"></script>' for file in params.include_js_files])
|
|
62
|
+
return f"""
|
|
63
|
+
<html>
|
|
64
|
+
<head>
|
|
65
|
+
<meta charset="utf-8">
|
|
66
|
+
<style>
|
|
67
|
+
/* fallback */
|
|
68
|
+
@font-face {{
|
|
69
|
+
font-family: "DMSans";
|
|
70
|
+
font-weight: 600;
|
|
71
|
+
src: url(data:font/ttf;base64,{__load_font("DMSans-SemiBold.ttf")}) format("truetype");
|
|
72
|
+
}}
|
|
73
|
+
@font-face {{
|
|
74
|
+
font-family: "DMSans";
|
|
75
|
+
font-weight: 400;
|
|
76
|
+
src: url(data:font/ttf;base64,{__load_font("DMSans-Regular.ttf")}) format("truetype");
|
|
77
|
+
}}
|
|
78
|
+
@font-face {{
|
|
79
|
+
font-family: "DMSans";
|
|
80
|
+
font-weight: 500;
|
|
81
|
+
src: url(data:font/ttf;base64,{__load_font("DMSans-Medium.ttf")}) format("truetype");
|
|
82
|
+
}}
|
|
83
|
+
@font-face {{
|
|
84
|
+
font-family: "DMSans";
|
|
85
|
+
font-weight: 700;
|
|
86
|
+
src: url(data:font/ttf;base64,{__load_font("DMSans-Bold.ttf")}) format("truetype");
|
|
87
|
+
}}
|
|
88
|
+
.datachecks_logo {{
|
|
89
|
+
background-image: url(data:image/svg+xml;base64,{__load_image("logo.svg")});
|
|
90
|
+
background-repeat: no-repeat;
|
|
91
|
+
background-size: contain;
|
|
92
|
+
}}
|
|
93
|
+
.github_logo {{
|
|
94
|
+
background-image: url(data:image/svg+xml;base64,{__load_image("github.svg")});
|
|
95
|
+
background-repeat: no-repeat;
|
|
96
|
+
background-size: contain;
|
|
97
|
+
filter: invert(1);
|
|
98
|
+
}}
|
|
99
|
+
.slack_logo {{
|
|
100
|
+
background-image: url(data:image/svg+xml;base64,{__load_image("slack.svg")});
|
|
101
|
+
background-repeat: no-repeat;
|
|
102
|
+
background-size: contain;
|
|
103
|
+
filter: invert(1);
|
|
104
|
+
|
|
105
|
+
}}
|
|
106
|
+
.docs_logo {{
|
|
107
|
+
background-image: url(data:image/svg+xml;base64,{__load_image("docs.svg")});
|
|
108
|
+
background-repeat: no-repeat;
|
|
109
|
+
background-size: contain;
|
|
110
|
+
filter: invert(1);
|
|
111
|
+
}}
|
|
112
|
+
|
|
113
|
+
</style>
|
|
114
|
+
{data_block}
|
|
115
|
+
</head>
|
|
116
|
+
<body>
|
|
117
|
+
<div id="root_{params.dashboard_id}">Loading...</div>
|
|
118
|
+
{lib_block}
|
|
119
|
+
{js_files_block}
|
|
120
|
+
<script>
|
|
121
|
+
window.buildDashboard(data_{params.dashboard_id},
|
|
122
|
+
"root_{params.dashboard_id}"
|
|
123
|
+
);
|
|
124
|
+
</script>
|
|
125
|
+
</body>
|
|
126
|
+
</html>
|
|
127
|
+
"""
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
class DashboardInfoBuilder:
|
|
131
|
+
def __init__(self, inspect_data: InspectOutput):
|
|
132
|
+
self.inspect_data: InspectOutput = inspect_data
|
|
133
|
+
|
|
134
|
+
def build(self):
|
|
135
|
+
[dashboard, metrics] = self.__build_params()
|
|
136
|
+
return DashboardInfo(name="test", metrics=metrics, dashboard=dashboard)
|
|
137
|
+
|
|
138
|
+
def __build_params(self):
|
|
139
|
+
data = self.inspect_data
|
|
140
|
+
|
|
141
|
+
self.metrics = []
|
|
142
|
+
self.dashboard = DashboardMetricOverview(
|
|
143
|
+
**{
|
|
144
|
+
metric_type: MetricHealthStatus(
|
|
145
|
+
total_metrics=0,
|
|
146
|
+
metric_validation_success=0,
|
|
147
|
+
metric_validation_failed=0,
|
|
148
|
+
metric_validation_unchecked=0,
|
|
149
|
+
health_score=0,
|
|
150
|
+
)
|
|
151
|
+
for metric_type in DashboardMetricOverview.__dataclass_fields__.keys()
|
|
152
|
+
}
|
|
153
|
+
)
|
|
154
|
+
for data_source_name, ds_metrics in data.metrics.items():
|
|
155
|
+
row = None
|
|
156
|
+
if isinstance(ds_metrics, DataSourceMetrics):
|
|
157
|
+
for tabel_name, table_metrics in ds_metrics.table_metrics.items():
|
|
158
|
+
for metric_identifier, metric in table_metrics.metrics.items():
|
|
159
|
+
self._insert_value(metric)
|
|
160
|
+
|
|
161
|
+
for index_name, index_metrics in ds_metrics.index_metrics.items():
|
|
162
|
+
for metric_identifier, metric in index_metrics.metrics.items():
|
|
163
|
+
self._insert_value(metric)
|
|
164
|
+
else:
|
|
165
|
+
for metric_identifier, metric in ds_metrics.metrics.items():
|
|
166
|
+
self._insert_value(metric)
|
|
167
|
+
self.calculate_health_score()
|
|
168
|
+
return [self.dashboard, self.metrics]
|
|
169
|
+
|
|
170
|
+
def _insert_value(self, metric):
|
|
171
|
+
for metric_type in GroupedMetricsType.__members__.keys():
|
|
172
|
+
if metric.metric_type in GroupedMetricsType[metric_type].value:
|
|
173
|
+
current = getattr(self.dashboard, metric_type)
|
|
174
|
+
overall = getattr(self.dashboard, "overall")
|
|
175
|
+
current.total_metrics += 1
|
|
176
|
+
overall.total_metrics += 1
|
|
177
|
+
if metric.is_valid is not None:
|
|
178
|
+
if metric.is_valid:
|
|
179
|
+
current.metric_validation_success += 1
|
|
180
|
+
overall.metric_validation_success += 1
|
|
181
|
+
else:
|
|
182
|
+
current.metric_validation_failed += 1
|
|
183
|
+
overall.metric_validation_failed += 1
|
|
184
|
+
else:
|
|
185
|
+
current.metric_validation_unchecked += 1
|
|
186
|
+
overall.metric_validation_unchecked += 1
|
|
187
|
+
self.metrics.append(
|
|
188
|
+
MetricRow(
|
|
189
|
+
metric_name=metric.tags.get("metric_name"),
|
|
190
|
+
data_source=metric.data_source,
|
|
191
|
+
metric_type=metric.metric_type,
|
|
192
|
+
metric_value=f"{metric.value:.2f}",
|
|
193
|
+
is_valid=metric.is_valid,
|
|
194
|
+
reason=metric.reason,
|
|
195
|
+
).get_dict()
|
|
196
|
+
)
|
|
197
|
+
|
|
198
|
+
def calculate_health_score(self):
|
|
199
|
+
for metric_type in DashboardMetricOverview.__dataclass_fields__.keys():
|
|
200
|
+
try:
|
|
201
|
+
metric = getattr(self.dashboard, metric_type)
|
|
202
|
+
metric.health_score = round(
|
|
203
|
+
(
|
|
204
|
+
metric.metric_validation_success
|
|
205
|
+
/ (metric.metric_validation_success + metric.metric_validation_failed)
|
|
206
|
+
)
|
|
207
|
+
* 100,
|
|
208
|
+
2,
|
|
209
|
+
)
|
|
210
|
+
except ZeroDivisionError:
|
|
211
|
+
metric.health_score = 0
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
# Copyright 2022-present, the Waterdip Labs Pvt. Ltd.
|
|
2
|
+
#
|
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
# you may not use this file except in compliance with the License.
|
|
5
|
+
# You may obtain a copy of the License at
|
|
6
|
+
#
|
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
#
|
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
# See the License for the specific language governing permissions and
|
|
13
|
+
# limitations under the License.
|
|
14
|
+
|
|
15
|
+
import dataclasses
|
|
16
|
+
from dataclasses import dataclass
|
|
17
|
+
from enum import Enum
|
|
18
|
+
from typing import List, Optional
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
@dataclass
|
|
22
|
+
class MetricHealthStatus:
|
|
23
|
+
total_metrics: int
|
|
24
|
+
metric_validation_success: int
|
|
25
|
+
metric_validation_failed: int
|
|
26
|
+
metric_validation_unchecked: int
|
|
27
|
+
health_score: int
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
@dataclass
|
|
31
|
+
class DashboardMetricOverview:
|
|
32
|
+
overall: MetricHealthStatus
|
|
33
|
+
reliability: MetricHealthStatus
|
|
34
|
+
numeric: MetricHealthStatus
|
|
35
|
+
uniqueness: MetricHealthStatus
|
|
36
|
+
completeness: MetricHealthStatus
|
|
37
|
+
custom: MetricHealthStatus
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
@dataclass
|
|
41
|
+
class MetricRow:
|
|
42
|
+
metric_name: str
|
|
43
|
+
data_source: str
|
|
44
|
+
metric_type: str
|
|
45
|
+
is_valid: bool
|
|
46
|
+
metric_value: str
|
|
47
|
+
reason: str
|
|
48
|
+
|
|
49
|
+
def get_dict(self):
|
|
50
|
+
return {
|
|
51
|
+
"metric_name": self.metric_name,
|
|
52
|
+
"data_source": "-" if self.data_source is None else self.data_source,
|
|
53
|
+
"metric_type": self.metric_type,
|
|
54
|
+
"is_valid": "-" if self.is_valid is None else str(self.is_valid),
|
|
55
|
+
"metric_value": self.metric_value,
|
|
56
|
+
"reason": "-" if self.reason is None else self.reason,
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
@dataclass
|
|
61
|
+
class DashboardInfo:
|
|
62
|
+
name: str
|
|
63
|
+
metrics: List[MetricRow]
|
|
64
|
+
dashboard: DashboardMetricOverview
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
class GroupedMetricsType(Enum):
|
|
68
|
+
reliability = ["row_count", "document_count", "freshness"]
|
|
69
|
+
numeric = ["min", "max", "avg", "sum", "stddev", "variance"]
|
|
70
|
+
uniqueness = ["distinct_count", "duplicate_count"]
|
|
71
|
+
completeness = [
|
|
72
|
+
"null_count",
|
|
73
|
+
"null_percentage",
|
|
74
|
+
"empty_string_count",
|
|
75
|
+
"empty_string_percentage",
|
|
76
|
+
]
|
|
77
|
+
custom = ["combined"]
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
@dataclass
|
|
81
|
+
class TemplateParams:
|
|
82
|
+
dashboard_id: str
|
|
83
|
+
dashboard_info: DashboardInfo
|
|
84
|
+
embed_font: bool = True
|
|
85
|
+
embed_lib: bool = True
|
|
86
|
+
embed_data: bool = True
|
|
87
|
+
font_file: Optional[str] = None
|
|
88
|
+
include_js_files: List[str] = dataclasses.field(default_factory=list)
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
<svg width="48" height="45" viewBox="0 0 48 45" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
2
|
+
<path d="M0 44.8V0H22.08C27.0721 0 31.4666 0.917399 35.264 2.752C39.0613 4.544 42.0266 7.104 44.16 10.432C46.2933 13.76 47.3601 17.728 47.3601 22.336C47.3601 26.9867 46.2933 30.9974 44.16 34.368C42.0266 37.696 39.0613 40.2774 35.264 42.112C31.4666 43.904 27.0721 44.8 22.08 44.8H0ZM15.1039 33.024H21.44C23.5734 33.024 25.4294 32.6187 27.0081 31.808C28.6294 30.9974 29.888 29.8027 30.784 28.224C31.6801 26.6027 32.1281 24.64 32.1281 22.336C32.1281 20.0747 31.6801 18.1547 30.784 16.576C29.888 14.9974 28.6294 13.8027 27.0081 12.992C25.4294 12.1814 23.5734 11.776 21.44 11.776H15.1039V33.024Z" fill="white"/>
|
|
3
|
+
<path d="M5.53955 0V45" stroke="#0B0949"/>
|
|
4
|
+
<path d="M3.53955 0V45" stroke="#0B0949"/>
|
|
5
|
+
<path d="M1.53955 0V45" stroke="#0B0949"/>
|
|
6
|
+
</svg>
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
<svg width="2491" height="2429" viewBox="0 0 2491 2429" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
2
|
+
<path d="M1245.17 0C557.568 0 0 557.471 0 1245.17C0 1795.32 356.777 2262.06 851.523 2426.71C913.75 2438.23 936.602 2399.7 936.602 2366.81C936.602 2337.12 935.439 2239.02 934.912 2134.98C588.496 2210.3 515.4 1988.07 515.4 1988.07C458.76 1844.14 377.148 1805.88 377.148 1805.88C264.18 1728.59 385.664 1730.18 385.664 1730.18C510.703 1738.96 576.543 1858.5 576.543 1858.5C687.598 2048.86 867.832 1993.82 938.887 1962.01C950.059 1881.52 982.334 1826.6 1017.94 1795.51C741.377 1764.01 450.635 1657.25 450.635 1180.14C450.635 1044.2 499.277 933.115 578.936 845.918C566.006 814.551 523.389 687.91 590.996 516.397C590.996 516.397 695.557 482.93 933.506 644.033C1032.82 616.436 1139.35 602.607 1245.17 602.139C1350.99 602.607 1457.59 616.436 1557.1 644.033C1794.77 482.93 1899.18 516.397 1899.18 516.397C1966.95 687.91 1924.32 814.551 1911.39 845.918C1991.22 933.115 2039.53 1044.19 2039.53 1180.14C2039.53 1658.38 1748.24 1763.69 1470.98 1794.51C1515.63 1833.15 1555.43 1908.94 1555.43 2025.1C1555.43 2191.7 1553.98 2325.79 1553.98 2366.81C1553.98 2399.94 1576.4 2438.77 1639.52 2426.54C2133.99 2261.71 2490.32 1795.14 2490.32 1245.17C2490.32 557.471 1932.83 0 1245.17 0Z" fill="white"/>
|
|
3
|
+
<path d="M466.357 1773.77C463.623 1779.95 453.876 1781.81 445.019 1777.57C435.986 1773.51 430.908 1765.07 433.837 1758.86C436.523 1752.49 446.269 1750.71 455.283 1754.99C464.335 1759.04 469.492 1767.56 466.357 1773.77ZM527.607 1828.42C521.669 1833.93 510.058 1831.37 502.177 1822.67C494.033 1813.98 492.509 1802.38 498.535 1796.79C504.658 1791.29 515.918 1793.86 524.082 1802.55C532.226 1811.33 533.808 1822.86 527.597 1828.43M569.628 1898.34C561.992 1903.64 549.511 1898.67 541.806 1887.6C534.179 1876.53 534.179 1863.25 541.972 1857.93C549.707 1852.61 561.992 1857.39 569.804 1868.38C577.421 1879.64 577.421 1892.92 569.619 1898.35M640.683 1979.33C633.857 1986.85 619.326 1984.83 608.681 1974.56C597.802 1964.52 594.765 1950.27 601.611 1942.74C608.515 1935.21 623.134 1937.32 633.857 1947.51C644.667 1957.53 647.959 1971.88 640.683 1979.33ZM732.519 2006.67C729.521 2016.42 715.517 2020.85 701.416 2016.71C687.333 2012.44 678.115 2001.02 680.957 1991.16C683.886 1981.35 697.949 1976.73 712.158 1981.16C726.22 1985.41 735.449 1996.75 732.519 2006.67ZM837.05 2018.26C837.402 2028.54 825.439 2037.05 810.634 2037.24C795.742 2037.56 783.701 2029.25 783.544 2019.15C783.544 2008.78 795.234 2000.34 810.117 2000.1C824.921 1999.8 837.05 2008.06 837.05 2018.26ZM939.726 2014.33C941.503 2024.35 931.21 2034.64 916.513 2037.37C902.06 2040.01 888.681 2033.83 886.835 2023.9C885.039 2013.62 895.527 2003.34 909.951 2000.67C924.677 1998.12 937.851 2004.14 939.726 2014.33Z" fill="white"/>
|
|
4
|
+
</svg>
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
<svg width="265" height="63" viewBox="0 0 265 63" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
2
|
+
<rect x="3.82764" y="4.12231" width="101.878" height="8.53889" rx="0.294444" fill="#F50119"/>
|
|
3
|
+
<path d="M2.7825 44.5388V16.7138H15.9398C19.0138 16.7138 21.7168 17.2836 24.0488 18.4231C26.3808 19.5626 28.196 21.1658 29.4945 23.2328C30.8195 25.2998 31.482 27.7643 31.482 30.6263C31.482 33.4618 30.8195 35.9263 29.4945 38.0198C28.196 40.0868 26.3808 41.6901 24.0488 42.8296C21.7168 43.9691 19.0138 44.5388 15.9398 44.5388H2.7825ZM10.653 38.2583H15.6218C17.2118 38.2583 18.5898 37.9668 19.7558 37.3838C20.9483 36.7743 21.8758 35.8998 22.5383 34.7603C23.2008 33.5943 23.532 32.2163 23.532 30.6263C23.532 29.0098 23.2008 27.6318 22.5383 26.4923C21.8758 25.3528 20.9483 24.4916 19.7558 23.9086C18.5898 23.2991 17.2118 22.9943 15.6218 22.9943H10.653V38.2583ZM48.4223 44.5388V40.5241L47.9056 39.5303V32.1368C47.9056 30.9443 47.5346 30.0301 46.7926 29.3941C46.0771 28.7316 44.9243 28.4003 43.3343 28.4003C42.3008 28.4003 41.2541 28.5726 40.1941 28.9171C39.1341 29.2351 38.2331 29.6856 37.4911 30.2686L34.9471 25.1408C36.1661 24.3458 37.6236 23.7363 39.3196 23.3123C41.0421 22.8618 42.7513 22.6366 44.4473 22.6366C47.9453 22.6366 50.6483 23.4448 52.5563 25.0613C54.4908 26.6513 55.4581 29.1556 55.4581 32.5741V44.5388H48.4223ZM42.0623 44.8966C40.3398 44.8966 38.8823 44.6051 37.6898 44.0221C36.4973 43.4391 35.5831 42.6441 34.9471 41.6371C34.3376 40.6301 34.0328 39.5038 34.0328 38.2583C34.0328 36.9333 34.3641 35.7938 35.0266 34.8398C35.7156 33.8593 36.7623 33.1173 38.1668 32.6138C39.5713 32.0838 41.3866 31.8188 43.6126 31.8188H48.7006V35.7541H44.6461C43.4271 35.7541 42.5658 35.9528 42.0623 36.3503C41.5853 36.7478 41.3468 37.2778 41.3468 37.9403C41.3468 38.6028 41.5986 39.1328 42.1021 39.5303C42.6056 39.9278 43.2946 40.1266 44.1691 40.1266C44.9906 40.1266 45.7326 39.9278 46.3951 39.5303C47.0841 39.1063 47.5876 38.4703 47.9056 37.6223L48.9391 40.4048C48.5416 41.8888 47.7598 43.0151 46.5938 43.7836C45.4543 44.5256 43.9438 44.8966 42.0623 44.8966ZM69.8448 44.8966C67.0888 44.8966 64.9423 44.2208 63.4053 42.8693C61.8683 41.4913 61.0998 39.4243 61.0998 36.6683V18.1846H68.6523V36.5888C68.6523 37.3573 68.8643 37.9668 69.2883 38.4173C69.7123 38.8413 70.2555 39.0533 70.918 39.0533C71.819 39.0533 72.5875 38.8281 73.2235 38.3776L75.0918 43.6643C74.4558 44.0883 73.674 44.3931 72.7465 44.5786C71.819 44.7906 70.8518 44.8966 69.8448 44.8966ZM57.9595 29.4338V23.7893H73.5813V29.4338H57.9595ZM91.1613 44.5388V40.5241L90.6446 39.5303V32.1368C90.6446 30.9443 90.2736 30.0301 89.5316 29.3941C88.8161 28.7316 87.6633 28.4003 86.0733 28.4003C85.0398 28.4003 83.9931 28.5726 82.9331 28.9171C81.8731 29.2351 80.9721 29.6856 80.2301 30.2686L77.6861 25.1408C78.9051 24.3458 80.3626 23.7363 82.0586 23.3123C83.7811 22.8618 85.4903 22.6366 87.1863 22.6366C90.6843 22.6366 93.3873 23.4448 95.2953 25.0613C97.2298 26.6513 98.1971 29.1556 98.1971 32.5741V44.5388H91.1613ZM84.8013 44.8966C83.0788 44.8966 81.6213 44.6051 80.4288 44.0221C79.2363 43.4391 78.3221 42.6441 77.6861 41.6371C77.0766 40.6301 76.7718 39.5038 76.7718 38.2583C76.7718 36.9333 77.1031 35.7938 77.7656 34.8398C78.4546 33.8593 79.5013 33.1173 80.9058 32.6138C82.3103 32.0838 84.1256 31.8188 86.3516 31.8188H91.4396V35.7541H87.3851C86.1661 35.7541 85.3048 35.9528 84.8013 36.3503C84.3243 36.7478 84.0858 37.2778 84.0858 37.9403C84.0858 38.6028 84.3376 39.1328 84.8411 39.5303C85.3446 39.9278 86.0336 40.1266 86.9081 40.1266C87.7296 40.1266 88.4716 39.9278 89.1341 39.5303C89.8231 39.1063 90.3266 38.4703 90.6446 37.6223L91.6781 40.4048C91.2806 41.8888 90.4988 43.0151 89.3328 43.7836C88.1933 44.5256 86.6828 44.8966 84.8013 44.8966ZM114.247 44.8966C111.862 44.8966 109.729 44.4196 107.847 43.4656C105.992 42.5116 104.535 41.1998 103.475 39.5303C102.415 37.8343 101.885 35.8998 101.885 33.7268C101.885 31.5538 102.415 29.6326 103.475 27.9631C104.535 26.2936 105.992 24.9951 107.847 24.0676C109.729 23.1136 111.862 22.6366 114.247 22.6366C116.685 22.6366 118.792 23.1533 120.567 24.1868C122.343 25.2203 123.601 26.6778 124.343 28.5593L118.5 31.5406C117.997 30.5336 117.374 29.8048 116.632 29.3543C115.89 28.8773 115.082 28.6388 114.207 28.6388C113.333 28.6388 112.538 28.8376 111.822 29.2351C111.107 29.6326 110.537 30.2156 110.113 30.9841C109.715 31.7261 109.517 32.6403 109.517 33.7268C109.517 34.8398 109.715 35.7806 110.113 36.5491C110.537 37.3176 111.107 37.9006 111.822 38.2981C112.538 38.6956 113.333 38.8943 114.207 38.8943C115.082 38.8943 115.89 38.6691 116.632 38.2186C117.374 37.7416 117.997 36.9996 118.5 35.9926L124.343 38.9738C123.601 40.8553 122.343 42.3128 120.567 43.3463C118.792 44.3798 116.685 44.8966 114.247 44.8966ZM141.141 22.6366C142.811 22.6366 144.321 22.9811 145.673 23.6701C147.024 24.3326 148.084 25.3661 148.853 26.7706C149.648 28.1751 150.045 29.9903 150.045 32.2163V44.5388H142.493V33.4486C142.493 31.9116 142.175 30.7986 141.539 30.1096C140.929 29.3941 140.068 29.0363 138.955 29.0363C138.16 29.0363 137.431 29.2218 136.769 29.5928C136.106 29.9373 135.589 30.4806 135.218 31.2226C134.847 31.9646 134.662 32.9318 134.662 34.1243V44.5388H127.109V15.0443H134.662V29.1158L132.913 27.3271C133.734 25.7636 134.861 24.5976 136.292 23.8291C137.723 23.0341 139.339 22.6366 141.141 22.6366ZM166.348 44.8966C163.804 44.8966 161.578 44.4196 159.67 43.4656C157.788 42.4851 156.317 41.1601 155.257 39.4906C154.224 37.7946 153.707 35.8733 153.707 33.7268C153.707 31.5803 154.211 29.6723 155.218 28.0028C156.251 26.3068 157.669 24.9951 159.471 24.0676C161.273 23.1136 163.3 22.6366 165.553 22.6366C167.673 22.6366 169.607 23.0738 171.356 23.9483C173.105 24.7963 174.496 26.0551 175.53 27.7246C176.563 29.3941 177.08 31.4213 177.08 33.8063C177.08 34.0713 177.067 34.3761 177.04 34.7206C177.014 35.0651 176.987 35.3831 176.961 35.6746H159.908V31.6996H172.946L170.084 32.8126C170.111 31.8321 169.925 30.9841 169.528 30.2686C169.157 29.5531 168.627 28.9966 167.938 28.5991C167.275 28.2016 166.493 28.0028 165.592 28.0028C164.691 28.0028 163.896 28.2016 163.207 28.5991C162.545 28.9966 162.028 29.5663 161.657 30.3083C161.286 31.0238 161.101 31.8718 161.101 32.8523V34.0051C161.101 35.0651 161.313 35.9793 161.737 36.7478C162.187 37.5163 162.823 38.1126 163.645 38.5366C164.466 38.9341 165.447 39.1328 166.586 39.1328C167.646 39.1328 168.547 38.9871 169.289 38.6956C170.058 38.3776 170.813 37.9006 171.555 37.2646L175.53 41.3986C174.496 42.5381 173.224 43.4126 171.714 44.0221C170.203 44.6051 168.415 44.8966 166.348 44.8966ZM191.573 44.8966C189.188 44.8966 187.055 44.4196 185.173 43.4656C183.318 42.5116 181.861 41.1998 180.801 39.5303C179.741 37.8343 179.211 35.8998 179.211 33.7268C179.211 31.5538 179.741 29.6326 180.801 27.9631C181.861 26.2936 183.318 24.9951 185.173 24.0676C187.055 23.1136 189.188 22.6366 191.573 22.6366C194.011 22.6366 196.118 23.1533 197.893 24.1868C199.669 25.2203 200.927 26.6778 201.669 28.5593L195.826 31.5406C195.323 30.5336 194.7 29.8048 193.958 29.3543C193.216 28.8773 192.408 28.6388 191.533 28.6388C190.659 28.6388 189.864 28.8376 189.148 29.2351C188.433 29.6326 187.863 30.2156 187.439 30.9841C187.041 31.7261 186.843 32.6403 186.843 33.7268C186.843 34.8398 187.041 35.7806 187.439 36.5491C187.863 37.3176 188.433 37.9006 189.148 38.2981C189.864 38.6956 190.659 38.8943 191.533 38.8943C192.408 38.8943 193.216 38.6691 193.958 38.2186C194.7 37.7416 195.323 36.9996 195.826 35.9926L201.669 38.9738C200.927 40.8553 199.669 42.3128 197.893 43.3463C196.118 44.3798 194.011 44.8966 191.573 44.8966ZM210.716 40.5638L210.915 31.5406L219.699 22.9943H228.643L218.904 33.0511L215.049 36.1516L210.716 40.5638ZM204.435 44.5388V15.0443H211.988V44.5388H204.435ZM220.256 44.5388L213.657 36.2708L218.348 30.4673L229.398 44.5388H220.256ZM238.779 44.8966C236.951 44.8966 235.162 44.6846 233.413 44.2606C231.69 43.8366 230.299 43.3066 229.239 42.6706L231.505 37.5031C232.512 38.1126 233.691 38.6028 235.043 38.9738C236.394 39.3183 237.719 39.4906 239.018 39.4906C240.29 39.4906 241.164 39.3581 241.641 39.0931C242.145 38.8281 242.396 38.4703 242.396 38.0198C242.396 37.5958 242.158 37.2911 241.681 37.1056C241.23 36.8936 240.621 36.7346 239.852 36.6286C239.11 36.5226 238.289 36.4033 237.388 36.2708C236.487 36.1383 235.573 35.9661 234.645 35.7541C233.744 35.5156 232.909 35.1711 232.141 34.7206C231.399 34.2436 230.803 33.6076 230.352 32.8126C229.902 32.0176 229.676 31.0106 229.676 29.7916C229.676 28.4136 230.074 27.1946 230.869 26.1346C231.69 25.0481 232.883 24.2001 234.446 23.5906C236.01 22.9546 237.918 22.6366 240.17 22.6366C241.681 22.6366 243.205 22.7956 244.742 23.1136C246.305 23.4051 247.617 23.8556 248.677 24.4651L246.411 29.5928C245.351 28.9833 244.291 28.5726 243.231 28.3606C242.171 28.1221 241.164 28.0028 240.21 28.0028C238.938 28.0028 238.037 28.1486 237.507 28.4401C237.004 28.7316 236.752 29.0893 236.752 29.5133C236.752 29.9373 236.977 30.2686 237.428 30.5071C237.878 30.7191 238.474 30.8913 239.216 31.0238C239.985 31.1298 240.82 31.2491 241.721 31.3816C242.622 31.4876 243.523 31.6598 244.424 31.8983C245.351 32.1368 246.186 32.4946 246.928 32.9716C247.696 33.4221 248.306 34.0448 248.756 34.8398C249.207 35.6083 249.432 36.6021 249.432 37.8211C249.432 39.1461 249.021 40.3386 248.2 41.3986C247.405 42.4586 246.212 43.3066 244.622 43.9426C243.059 44.5786 241.111 44.8966 238.779 44.8966Z" fill="#0B0949"/>
|
|
4
|
+
<line x1="4.12208" y1="16.7834" x2="4.12208" y2="44.4612" stroke="white" stroke-width="0.588889"/>
|
|
5
|
+
<line x1="5.88868" y1="16.7834" x2="5.88868" y2="44.4612" stroke="white" stroke-width="0.588889"/>
|
|
6
|
+
<line x1="7.65577" y1="16.7834" x2="7.65577" y2="44.4612" stroke="white" stroke-width="0.588889"/>
|
|
7
|
+
</svg>
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
<svg width="2448" height="2453" viewBox="0 0 2448 2453" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
2
|
+
<g clip-path="url(#clip0_549_6)">
|
|
3
|
+
<path fill-rule="evenodd" clip-rule="evenodd" d="M897.4 0C762.1 0.1 652.6 109.9 652.7 245.2C652.6 380.5 762.2 490.3 897.5 490.4H1142.3V245.3C1142.4 110 1032.8 0.2 897.4 0C897.5 0 897.5 0 897.4 0ZM897.4 654H244.8C109.5 654.1 -0.100215 763.9 -0.000214994 899.2C-0.200215 1034.5 109.4 1144.3 244.7 1144.5H897.4C1032.7 1144.4 1142.3 1034.6 1142.2 899.3C1142.3 763.9 1032.7 654.1 897.4 654Z" fill="white"/>
|
|
4
|
+
<path fill-rule="evenodd" clip-rule="evenodd" d="M2447.6 899.2C2447.7 763.9 2338.1 654.1 2202.8 654C2067.5 654.1 1957.9 763.9 1958 899.2V1144.5H2202.8C2338.1 1144.4 2447.7 1034.6 2447.6 899.2ZM1794.9 899.2V245.2C1795 110 1685.5 0.2 1550.2 0C1414.9 0.1 1305.3 109.9 1305.4 245.2V899.2C1305.2 1034.5 1414.8 1144.3 1550.1 1144.5C1685.4 1144.4 1795 1034.6 1794.9 899.2Z" fill="white"/>
|
|
5
|
+
<path fill-rule="evenodd" clip-rule="evenodd" d="M1550.1 2452.5C1685.4 2452.4 1795 2342.6 1794.9 2207.3C1795 2072 1685.4 1962.2 1550.1 1962.1H1305.3V2207.3C1305.2 2342.5 1414.8 2452.3 1550.1 2452.5ZM1550.1 1798.4H2202.8C2338.1 1798.3 2447.7 1688.5 2447.6 1553.2C2447.8 1417.9 2338.2 1308.1 2202.9 1307.9H1550.2C1414.9 1308 1305.3 1417.8 1305.4 1553.1C1305.3 1688.5 1414.8 1798.3 1550.1 1798.4Z" fill="white"/>
|
|
6
|
+
<path fill-rule="evenodd" clip-rule="evenodd" d="M-0.000419905 1553.2C-0.10042 1688.5 109.5 1798.3 244.8 1798.4C380.1 1798.3 489.7 1688.5 489.6 1553.2V1308H244.8C109.5 1308.1 -0.10042 1417.9 -0.000419905 1553.2ZM652.7 1553.2V2207.2C652.5 2342.5 762.1 2452.3 897.4 2452.5C1032.7 2452.4 1142.3 2342.6 1142.2 2207.3V1553.4C1142.4 1418.1 1032.8 1308.3 897.5 1308.1C762.1 1308.1 652.6 1417.9 652.7 1553.2Z" fill="white"/>
|
|
7
|
+
</g>
|
|
8
|
+
<defs>
|
|
9
|
+
<clipPath id="clip0_549_6">
|
|
10
|
+
<rect width="2447.6" height="2452.5" fill="white"/>
|
|
11
|
+
</clipPath>
|
|
12
|
+
</defs>
|
|
13
|
+
</svg>
|