PyFunceble-dev 4.2.6__py3-none-any.whl → 4.2.9__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.
- PyFunceble/__init__.py +1 -1
- PyFunceble/checker/__init__.py +1 -1
- PyFunceble/checker/availability/__init__.py +1 -1
- PyFunceble/checker/availability/base.py +17 -10
- PyFunceble/checker/availability/domain.py +1 -2
- PyFunceble/checker/availability/domain_and_ip.py +1 -1
- PyFunceble/checker/availability/extras/__init__.py +1 -1
- PyFunceble/checker/availability/extras/base.py +2 -3
- PyFunceble/checker/availability/extras/dns.py +1 -1
- PyFunceble/checker/availability/extras/etoxic.py +1 -1
- PyFunceble/checker/availability/extras/parked.py +1 -1
- PyFunceble/checker/availability/extras/rules.py +2 -2
- PyFunceble/checker/availability/extras/subject_switch.py +1 -1
- PyFunceble/checker/availability/ip.py +1 -2
- PyFunceble/checker/availability/params.py +1 -1
- PyFunceble/checker/availability/status.py +1 -1
- PyFunceble/checker/availability/url.py +1 -2
- PyFunceble/checker/base.py +1 -1
- PyFunceble/checker/complex_json_encoder.py +1 -1
- PyFunceble/checker/params_base.py +1 -1
- PyFunceble/checker/reputation/__init__.py +1 -1
- PyFunceble/checker/reputation/base.py +1 -2
- PyFunceble/checker/reputation/domain.py +1 -2
- PyFunceble/checker/reputation/domain_and_ip.py +1 -1
- PyFunceble/checker/reputation/ip.py +1 -2
- PyFunceble/checker/reputation/params.py +1 -1
- PyFunceble/checker/reputation/status.py +1 -1
- PyFunceble/checker/reputation/url.py +1 -2
- PyFunceble/checker/status_base.py +1 -1
- PyFunceble/checker/syntax/__init__.py +1 -1
- PyFunceble/checker/syntax/base.py +1 -1
- PyFunceble/checker/syntax/domain.py +1 -1
- PyFunceble/checker/syntax/domain_and_ip.py +1 -1
- PyFunceble/checker/syntax/domain_base.py +1 -1
- PyFunceble/checker/syntax/ip.py +1 -1
- PyFunceble/checker/syntax/ipv4.py +1 -1
- PyFunceble/checker/syntax/ipv6.py +1 -1
- PyFunceble/checker/syntax/params.py +1 -1
- PyFunceble/checker/syntax/second_lvl_domain.py +7 -3
- PyFunceble/checker/syntax/status.py +2 -1
- PyFunceble/checker/syntax/subdomain.py +4 -2
- PyFunceble/checker/syntax/url.py +1 -2
- PyFunceble/checker/utils/__init__.py +1 -1
- PyFunceble/checker/utils/whois.py +1 -1
- PyFunceble/cli/__init__.py +1 -1
- PyFunceble/cli/continuous_integration/__init__.py +1 -1
- PyFunceble/cli/continuous_integration/base.py +1 -1
- PyFunceble/cli/continuous_integration/exceptions.py +1 -1
- PyFunceble/cli/continuous_integration/github_actions.py +1 -1
- PyFunceble/cli/continuous_integration/gitlab_ci.py +1 -1
- PyFunceble/cli/continuous_integration/jenkins.py +1 -1
- PyFunceble/cli/continuous_integration/travis_ci.py +1 -1
- PyFunceble/cli/continuous_integration/utils.py +1 -1
- PyFunceble/cli/credential_loader.py +4 -4
- PyFunceble/cli/entry_points/__init__.py +1 -1
- PyFunceble/cli/entry_points/clean.py +1 -1
- PyFunceble/cli/entry_points/iana.py +1 -1
- PyFunceble/cli/entry_points/production.py +1 -1
- PyFunceble/cli/entry_points/public_suffix.py +1 -1
- PyFunceble/cli/entry_points/pyfunceble/__init__.py +1 -1
- PyFunceble/cli/entry_points/pyfunceble/argsparser.py +1 -1
- PyFunceble/cli/entry_points/pyfunceble/cli.py +1 -1
- PyFunceble/cli/execution_time.py +1 -1
- PyFunceble/cli/facility.py +1 -1
- PyFunceble/cli/factory.py +1 -1
- PyFunceble/cli/file_preloader.py +4 -4
- PyFunceble/cli/filesystem/__init__.py +1 -1
- PyFunceble/cli/filesystem/cleanup.py +1 -1
- PyFunceble/cli/filesystem/counter.py +1 -1
- PyFunceble/cli/filesystem/dir_base.py +1 -1
- PyFunceble/cli/filesystem/dir_structure/__init__.py +1 -1
- PyFunceble/cli/filesystem/dir_structure/backup.py +1 -1
- PyFunceble/cli/filesystem/dir_structure/base.py +1 -1
- PyFunceble/cli/filesystem/dir_structure/restore.py +1 -1
- PyFunceble/cli/filesystem/json_base.py +1 -1
- PyFunceble/cli/filesystem/printer/__init__.py +1 -1
- PyFunceble/cli/filesystem/printer/base.py +1 -1
- PyFunceble/cli/filesystem/printer/file.py +1 -1
- PyFunceble/cli/filesystem/printer/stdout.py +1 -1
- PyFunceble/cli/filesystem/registrar_counter.py +1 -1
- PyFunceble/cli/filesystem/status_file.py +1 -1
- PyFunceble/cli/migrators/__init__.py +1 -1
- PyFunceble/cli/migrators/alembic.py +1 -1
- PyFunceble/cli/migrators/base.py +1 -2
- PyFunceble/cli/migrators/csv_file/__init__.py +1 -1
- PyFunceble/cli/migrators/csv_file/base.py +1 -1
- PyFunceble/cli/migrators/csv_file/inactive_source_delete.py +1 -1
- PyFunceble/cli/migrators/csv_file/whois_registrar_add.py +1 -1
- PyFunceble/cli/migrators/db_base.py +1 -1
- PyFunceble/cli/migrators/file_cleanup/__init__.py +1 -1
- PyFunceble/cli/migrators/file_cleanup/base.py +1 -1
- PyFunceble/cli/migrators/file_cleanup/hashes_file.py +1 -1
- PyFunceble/cli/migrators/file_cleanup/mining_file.py +1 -1
- PyFunceble/cli/migrators/file_cleanup/production_config_file.py +1 -1
- PyFunceble/cli/migrators/json2csv/__init__.py +1 -1
- PyFunceble/cli/migrators/json2csv/base.py +1 -1
- PyFunceble/cli/migrators/json2csv/inactive.py +1 -1
- PyFunceble/cli/migrators/json2csv/whois.py +1 -1
- PyFunceble/cli/migrators/mariadb/__init__.py +1 -1
- PyFunceble/cli/migrators/mariadb/base.py +1 -1
- PyFunceble/cli/migrators/mariadb/file_and_status.py +1 -1
- PyFunceble/cli/migrators/mariadb/whois_record_idna_subject.py +1 -1
- PyFunceble/cli/processes/__init__.py +1 -1
- PyFunceble/cli/processes/base.py +1 -1
- PyFunceble/cli/processes/chancy_producer.py +1 -1
- PyFunceble/cli/processes/chancy_tester.py +1 -1
- PyFunceble/cli/processes/dir_files_sorter.py +1 -1
- PyFunceble/cli/processes/file_sorter.py +1 -1
- PyFunceble/cli/processes/migrator.py +1 -1
- PyFunceble/cli/processes/miner.py +1 -1
- PyFunceble/cli/processes/producer.py +1 -1
- PyFunceble/cli/processes/tester.py +1 -1
- PyFunceble/cli/processes/workers/__init__.py +1 -1
- PyFunceble/cli/processes/workers/base.py +4 -4
- PyFunceble/cli/processes/workers/chancy_producer.py +1 -1
- PyFunceble/cli/processes/workers/chancy_tester.py +1 -1
- PyFunceble/cli/processes/workers/dir_files_sorter.py +1 -1
- PyFunceble/cli/processes/workers/file_sorter.py +1 -1
- PyFunceble/cli/processes/workers/file_sorter_base.py +1 -1
- PyFunceble/cli/processes/workers/migrator.py +1 -1
- PyFunceble/cli/processes/workers/miner.py +1 -1
- PyFunceble/cli/processes/workers/producer.py +1 -1
- PyFunceble/cli/processes/workers/tester.py +1 -1
- PyFunceble/cli/scripts/__init__.py +1 -1
- PyFunceble/cli/scripts/iana.py +1 -1
- PyFunceble/cli/scripts/production.py +4 -5
- PyFunceble/cli/scripts/public_suffix.py +1 -1
- PyFunceble/cli/storage.py +6 -4
- PyFunceble/cli/storage_facility.py +1 -1
- PyFunceble/cli/system/__init__.py +1 -1
- PyFunceble/cli/system/base.py +1 -1
- PyFunceble/cli/system/integrator.py +1 -1
- PyFunceble/cli/system/launcher.py +1 -1
- PyFunceble/cli/utils/__init__.py +1 -1
- PyFunceble/cli/utils/ascii_logo.py +1 -1
- PyFunceble/cli/utils/sort.py +1 -1
- PyFunceble/cli/utils/stdout.py +1 -1
- PyFunceble/cli/utils/testing.py +2 -4
- PyFunceble/cli/utils/version.py +1 -1
- PyFunceble/config/__init__.py +1 -1
- PyFunceble/config/compare.py +1 -1
- PyFunceble/config/loader.py +1 -1
- PyFunceble/converter/__init__.py +1 -1
- PyFunceble/converter/adblock_input_line2subject.py +1 -1
- PyFunceble/converter/base.py +1 -1
- PyFunceble/converter/cidr2subject.py +1 -1
- PyFunceble/converter/input_line2subject.py +1 -1
- PyFunceble/converter/internal_url.py +1 -1
- PyFunceble/converter/rpz_input_line2subject.py +1 -1
- PyFunceble/converter/rpz_policy2subject.py +1 -1
- PyFunceble/converter/subject2complements.py +1 -1
- PyFunceble/converter/url2netloc.py +1 -1
- PyFunceble/converter/wildcard2subject.py +1 -1
- PyFunceble/data/alembic/__init__.py +1 -1
- PyFunceble/data/alembic/mysql/__init__.py +1 -1
- PyFunceble/data/alembic/mysql/env.py +1 -1
- PyFunceble/data/alembic/mysql/versions/35c79626ecb9_fix_some_columns.py +1 -0
- PyFunceble/data/alembic/mysql/versions/3a4c55a9320d_add_continue_table.py +1 -0
- PyFunceble/data/alembic/mysql/versions/3d6f4a33cdb2_add_inactive_table.py +1 -0
- PyFunceble/data/alembic/mysql/versions/45713fea8097_deletion_uneeded_columns_from_whois_.py +1 -0
- PyFunceble/data/alembic/mysql/versions/459a0d7b8f09_add_idna_subject_column_into_whois.py +1 -0
- PyFunceble/data/alembic/mysql/versions/6f4729deaf03_delete_inactive_source_column.py +1 -0
- PyFunceble/data/alembic/mysql/versions/7bcf7fa64ba1_rename_created_to_created_at_and.py +1 -0
- PyFunceble/data/alembic/mysql/versions/83ada95132bf_delete_the_file_table.py +1 -0
- PyFunceble/data/alembic/mysql/versions/912bbcb77a6c_add_registrar_column.py +1 -0
- PyFunceble/data/alembic/mysql/versions/95dc17ddd729_introduction_of_the_session_id_column.py +1 -0
- PyFunceble/data/alembic/mysql/versions/__init__.py +1 -1
- PyFunceble/data/alembic/mysql/versions/ade87195b0a0_base.py +1 -0
- PyFunceble/data/alembic/mysql/versions/bef7bcaac3f2_make_id_a_bigint.py +1 -0
- PyFunceble/data/alembic/mysql/versions/d8893cd406db_allow_whois_record_to_be_empty_null.py +1 -0
- PyFunceble/data/alembic/mysql/versions/e04e8301d1a2_deletion_of_the_mined_table.py +1 -0
- PyFunceble/data/alembic/postgresql/__init__.py +1 -1
- PyFunceble/data/alembic/postgresql/env.py +1 -1
- PyFunceble/data/alembic/postgresql/versions/__init__.py +1 -1
- PyFunceble/data/alembic/postgresql/versions/a32ac5d66eee_initial_version.py +1 -0
- PyFunceble/database/__init__.py +1 -1
- PyFunceble/database/credential/__init__.py +1 -1
- PyFunceble/database/credential/base.py +1 -1
- PyFunceble/database/credential/mariadb.py +1 -1
- PyFunceble/database/credential/mysql.py +1 -1
- PyFunceble/database/credential/postgresql.py +1 -1
- PyFunceble/database/schemas/__init__.py +1 -1
- PyFunceble/database/schemas/autocontinue.py +1 -1
- PyFunceble/database/schemas/inactive.py +1 -1
- PyFunceble/database/schemas/status.py +1 -1
- PyFunceble/database/schemas/whois_record.py +1 -1
- PyFunceble/database/session.py +1 -1
- PyFunceble/database/sqlalchemy/__init__.py +1 -1
- PyFunceble/database/sqlalchemy/all_schemas.py +1 -1
- PyFunceble/database/sqlalchemy/base_schema.py +1 -1
- PyFunceble/dataset/__init__.py +1 -1
- PyFunceble/dataset/autocontinue/__init__.py +1 -1
- PyFunceble/dataset/autocontinue/base.py +1 -1
- PyFunceble/dataset/autocontinue/csv.py +1 -1
- PyFunceble/dataset/autocontinue/sql.py +1 -1
- PyFunceble/dataset/base.py +1 -1
- PyFunceble/dataset/csv_base.py +1 -1
- PyFunceble/dataset/db_base.py +1 -1
- PyFunceble/dataset/iana.py +1 -1
- PyFunceble/dataset/inactive/__init__.py +1 -1
- PyFunceble/dataset/inactive/base.py +1 -1
- PyFunceble/dataset/inactive/csv.py +1 -1
- PyFunceble/dataset/inactive/sql.py +1 -1
- PyFunceble/dataset/ipv4_reputation.py +1 -1
- PyFunceble/dataset/public_suffix.py +1 -1
- PyFunceble/dataset/sql_base.py +1 -1
- PyFunceble/dataset/user_agent.py +51 -9
- PyFunceble/dataset/whois/__init__.py +1 -1
- PyFunceble/dataset/whois/base.py +1 -1
- PyFunceble/dataset/whois/csv.py +1 -1
- PyFunceble/dataset/whois/sql.py +1 -1
- PyFunceble/downloader/__init__.py +1 -1
- PyFunceble/downloader/base.py +1 -1
- PyFunceble/downloader/exceptions.py +1 -1
- PyFunceble/downloader/iana.py +1 -1
- PyFunceble/downloader/ipv4_reputation.py +1 -1
- PyFunceble/downloader/public_suffix.py +1 -1
- PyFunceble/downloader/user_agents.py +1 -1
- PyFunceble/exceptions.py +1 -1
- PyFunceble/facility.py +1 -1
- PyFunceble/factory.py +1 -1
- PyFunceble/helpers/__init__.py +1 -1
- PyFunceble/helpers/command.py +1 -1
- PyFunceble/helpers/dict.py +1 -1
- PyFunceble/helpers/directory.py +1 -1
- PyFunceble/helpers/download.py +1 -1
- PyFunceble/helpers/environment_variable.py +1 -1
- PyFunceble/helpers/exceptions.py +1 -1
- PyFunceble/helpers/file.py +1 -1
- PyFunceble/helpers/hash.py +1 -1
- PyFunceble/helpers/list.py +1 -1
- PyFunceble/helpers/merge.py +1 -1
- PyFunceble/helpers/regex.py +1 -1
- PyFunceble/logger.py +1 -1
- PyFunceble/query/__init__.py +1 -1
- PyFunceble/query/collection.py +222 -43
- PyFunceble/query/dns/__init__.py +1 -1
- PyFunceble/query/dns/nameserver.py +1 -1
- PyFunceble/query/dns/query_tool.py +1 -1
- PyFunceble/query/dns/resolver.py +1 -1
- PyFunceble/query/http_status_code.py +1 -1
- PyFunceble/query/netinfo/__init__.py +1 -1
- PyFunceble/query/netinfo/address.py +1 -1
- PyFunceble/query/netinfo/base.py +1 -1
- PyFunceble/query/netinfo/hostbyaddr.py +1 -1
- PyFunceble/query/record/__init__.py +1 -1
- PyFunceble/query/record/base.py +1 -1
- PyFunceble/query/record/dns.py +1 -1
- PyFunceble/query/record/whois.py +1 -1
- PyFunceble/query/requests/__init__.py +1 -1
- PyFunceble/query/requests/adapter/__init__.py +1 -1
- PyFunceble/query/requests/adapter/base.py +1 -1
- PyFunceble/query/requests/adapter/http.py +1 -1
- PyFunceble/query/requests/adapter/https.py +7 -7
- PyFunceble/query/requests/requester.py +1 -1
- PyFunceble/query/whois/__init__.py +1 -1
- PyFunceble/query/whois/converter/__init__.py +1 -1
- PyFunceble/query/whois/converter/base.py +1 -1
- PyFunceble/query/whois/converter/digit2digits.py +2 -1
- PyFunceble/query/whois/converter/expiration_date.py +1 -1
- PyFunceble/query/whois/converter/month2unified.py +1 -1
- PyFunceble/query/whois/converter/registrar.py +1 -1
- PyFunceble/query/whois/query_tool.py +1 -1
- PyFunceble/sessions.py +1 -1
- PyFunceble/storage.py +5 -3
- PyFunceble/storage_facility.py +1 -1
- PyFunceble/utils/__init__.py +1 -1
- PyFunceble/utils/platform.py +1 -1
- PyFunceble/utils/profile.py +1 -1
- PyFunceble/utils/version.py +1 -1
- {PyFunceble_dev-4.2.6.dist-info → PyFunceble_dev-4.2.9.dist-info}/LICENSE +1 -1
- {PyFunceble_dev-4.2.6.dist-info → PyFunceble_dev-4.2.9.dist-info}/METADATA +46 -46
- PyFunceble_dev-4.2.9.dist-info/RECORD +282 -0
- {PyFunceble_dev-4.2.6.dist-info → PyFunceble_dev-4.2.9.dist-info}/WHEEL +1 -1
- PyFunceble_dev-4.2.6.dist-info/RECORD +0 -282
- {PyFunceble_dev-4.2.6.dist-info → PyFunceble_dev-4.2.9.dist-info}/entry_points.txt +0 -0
- {PyFunceble_dev-4.2.6.dist-info → PyFunceble_dev-4.2.9.dist-info}/top_level.txt +0 -0
@@ -35,7 +35,7 @@ License:
|
|
35
35
|
::
|
36
36
|
|
37
37
|
|
38
|
-
Copyright 2017, 2018, 2019, 2020, 2022, 2023 Nissar Chababy
|
38
|
+
Copyright 2017, 2018, 2019, 2020, 2022, 2023, 2024 Nissar Chababy
|
39
39
|
|
40
40
|
Licensed under the Apache License, Version 2.0 (the "License");
|
41
41
|
you may not use this file except in compliance with the License.
|
PyFunceble/exceptions.py
CHANGED
@@ -36,7 +36,7 @@ License:
|
|
36
36
|
::
|
37
37
|
|
38
38
|
|
39
|
-
Copyright 2017, 2018, 2019, 2020, 2022, 2023 Nissar Chababy
|
39
|
+
Copyright 2017, 2018, 2019, 2020, 2022, 2023, 2024 Nissar Chababy
|
40
40
|
|
41
41
|
Licensed under the Apache License, Version 2.0 (the "License");
|
42
42
|
you may not use this file except in compliance with the License.
|
PyFunceble/facility.py
CHANGED
@@ -35,7 +35,7 @@ License:
|
|
35
35
|
::
|
36
36
|
|
37
37
|
|
38
|
-
Copyright 2017, 2018, 2019, 2020, 2022, 2023 Nissar Chababy
|
38
|
+
Copyright 2017, 2018, 2019, 2020, 2022, 2023, 2024 Nissar Chababy
|
39
39
|
|
40
40
|
Licensed under the Apache License, Version 2.0 (the "License");
|
41
41
|
you may not use this file except in compliance with the License.
|
PyFunceble/factory.py
CHANGED
@@ -35,7 +35,7 @@ License:
|
|
35
35
|
::
|
36
36
|
|
37
37
|
|
38
|
-
Copyright 2017, 2018, 2019, 2020, 2022, 2023 Nissar Chababy
|
38
|
+
Copyright 2017, 2018, 2019, 2020, 2022, 2023, 2024 Nissar Chababy
|
39
39
|
|
40
40
|
Licensed under the Apache License, Version 2.0 (the "License");
|
41
41
|
you may not use this file except in compliance with the License.
|
PyFunceble/helpers/__init__.py
CHANGED
@@ -35,7 +35,7 @@ License:
|
|
35
35
|
::
|
36
36
|
|
37
37
|
|
38
|
-
Copyright 2017, 2018, 2019, 2020, 2022, 2023 Nissar Chababy
|
38
|
+
Copyright 2017, 2018, 2019, 2020, 2022, 2023, 2024 Nissar Chababy
|
39
39
|
|
40
40
|
Licensed under the Apache License, Version 2.0 (the "License");
|
41
41
|
you may not use this file except in compliance with the License.
|
PyFunceble/helpers/command.py
CHANGED
@@ -35,7 +35,7 @@ License:
|
|
35
35
|
::
|
36
36
|
|
37
37
|
|
38
|
-
Copyright 2017, 2018, 2019, 2020, 2022, 2023 Nissar Chababy
|
38
|
+
Copyright 2017, 2018, 2019, 2020, 2022, 2023, 2024 Nissar Chababy
|
39
39
|
|
40
40
|
Licensed under the Apache License, Version 2.0 (the "License");
|
41
41
|
you may not use this file except in compliance with the License.
|
PyFunceble/helpers/dict.py
CHANGED
@@ -35,7 +35,7 @@ License:
|
|
35
35
|
::
|
36
36
|
|
37
37
|
|
38
|
-
Copyright 2017, 2018, 2019, 2020, 2022, 2023 Nissar Chababy
|
38
|
+
Copyright 2017, 2018, 2019, 2020, 2022, 2023, 2024 Nissar Chababy
|
39
39
|
|
40
40
|
Licensed under the Apache License, Version 2.0 (the "License");
|
41
41
|
you may not use this file except in compliance with the License.
|
PyFunceble/helpers/directory.py
CHANGED
@@ -35,7 +35,7 @@ License:
|
|
35
35
|
::
|
36
36
|
|
37
37
|
|
38
|
-
Copyright 2017, 2018, 2019, 2020, 2022, 2023 Nissar Chababy
|
38
|
+
Copyright 2017, 2018, 2019, 2020, 2022, 2023, 2024 Nissar Chababy
|
39
39
|
|
40
40
|
Licensed under the Apache License, Version 2.0 (the "License");
|
41
41
|
you may not use this file except in compliance with the License.
|
PyFunceble/helpers/download.py
CHANGED
@@ -35,7 +35,7 @@ License:
|
|
35
35
|
::
|
36
36
|
|
37
37
|
|
38
|
-
Copyright 2017, 2018, 2019, 2020, 2022, 2023 Nissar Chababy
|
38
|
+
Copyright 2017, 2018, 2019, 2020, 2022, 2023, 2024 Nissar Chababy
|
39
39
|
|
40
40
|
Licensed under the Apache License, Version 2.0 (the "License");
|
41
41
|
you may not use this file except in compliance with the License.
|
@@ -35,7 +35,7 @@ License:
|
|
35
35
|
::
|
36
36
|
|
37
37
|
|
38
|
-
Copyright 2017, 2018, 2019, 2020, 2022, 2023 Nissar Chababy
|
38
|
+
Copyright 2017, 2018, 2019, 2020, 2022, 2023, 2024 Nissar Chababy
|
39
39
|
|
40
40
|
Licensed under the Apache License, Version 2.0 (the "License");
|
41
41
|
you may not use this file except in compliance with the License.
|
PyFunceble/helpers/exceptions.py
CHANGED
@@ -36,7 +36,7 @@ License:
|
|
36
36
|
::
|
37
37
|
|
38
38
|
|
39
|
-
Copyright 2017, 2018, 2019, 2020, 2022, 2023 Nissar Chababy
|
39
|
+
Copyright 2017, 2018, 2019, 2020, 2022, 2023, 2024 Nissar Chababy
|
40
40
|
|
41
41
|
Licensed under the Apache License, Version 2.0 (the "License");
|
42
42
|
you may not use this file except in compliance with the License.
|
PyFunceble/helpers/file.py
CHANGED
@@ -35,7 +35,7 @@ License:
|
|
35
35
|
::
|
36
36
|
|
37
37
|
|
38
|
-
Copyright 2017, 2018, 2019, 2020, 2022, 2023 Nissar Chababy
|
38
|
+
Copyright 2017, 2018, 2019, 2020, 2022, 2023, 2024 Nissar Chababy
|
39
39
|
|
40
40
|
Licensed under the Apache License, Version 2.0 (the "License");
|
41
41
|
you may not use this file except in compliance with the License.
|
PyFunceble/helpers/hash.py
CHANGED
@@ -35,7 +35,7 @@ License:
|
|
35
35
|
::
|
36
36
|
|
37
37
|
|
38
|
-
Copyright 2017, 2018, 2019, 2020, 2022, 2023 Nissar Chababy
|
38
|
+
Copyright 2017, 2018, 2019, 2020, 2022, 2023, 2024 Nissar Chababy
|
39
39
|
|
40
40
|
Licensed under the Apache License, Version 2.0 (the "License");
|
41
41
|
you may not use this file except in compliance with the License.
|
PyFunceble/helpers/list.py
CHANGED
@@ -35,7 +35,7 @@ License:
|
|
35
35
|
::
|
36
36
|
|
37
37
|
|
38
|
-
Copyright 2017, 2018, 2019, 2020, 2022, 2023 Nissar Chababy
|
38
|
+
Copyright 2017, 2018, 2019, 2020, 2022, 2023, 2024 Nissar Chababy
|
39
39
|
|
40
40
|
Licensed under the Apache License, Version 2.0 (the "License");
|
41
41
|
you may not use this file except in compliance with the License.
|
PyFunceble/helpers/merge.py
CHANGED
@@ -35,7 +35,7 @@ License:
|
|
35
35
|
::
|
36
36
|
|
37
37
|
|
38
|
-
Copyright 2017, 2018, 2019, 2020, 2022, 2023 Nissar Chababy
|
38
|
+
Copyright 2017, 2018, 2019, 2020, 2022, 2023, 2024 Nissar Chababy
|
39
39
|
|
40
40
|
Licensed under the Apache License, Version 2.0 (the "License");
|
41
41
|
you may not use this file except in compliance with the License.
|
PyFunceble/helpers/regex.py
CHANGED
@@ -35,7 +35,7 @@ License:
|
|
35
35
|
::
|
36
36
|
|
37
37
|
|
38
|
-
Copyright 2017, 2018, 2019, 2020, 2022, 2023 Nissar Chababy
|
38
|
+
Copyright 2017, 2018, 2019, 2020, 2022, 2023, 2024 Nissar Chababy
|
39
39
|
|
40
40
|
Licensed under the Apache License, Version 2.0 (the "License");
|
41
41
|
you may not use this file except in compliance with the License.
|
PyFunceble/logger.py
CHANGED
@@ -35,7 +35,7 @@ License:
|
|
35
35
|
::
|
36
36
|
|
37
37
|
|
38
|
-
Copyright 2017, 2018, 2019, 2020, 2022, 2023 Nissar Chababy
|
38
|
+
Copyright 2017, 2018, 2019, 2020, 2022, 2023, 2024 Nissar Chababy
|
39
39
|
|
40
40
|
Licensed under the Apache License, Version 2.0 (the "License");
|
41
41
|
you may not use this file except in compliance with the License.
|
PyFunceble/query/__init__.py
CHANGED
@@ -36,7 +36,7 @@ License:
|
|
36
36
|
::
|
37
37
|
|
38
38
|
|
39
|
-
Copyright 2017, 2018, 2019, 2020, 2022, 2023 Nissar Chababy
|
39
|
+
Copyright 2017, 2018, 2019, 2020, 2022, 2023, 2024 Nissar Chababy
|
40
40
|
|
41
41
|
Licensed under the Apache License, Version 2.0 (the "License");
|
42
42
|
you may not use this file except in compliance with the License.
|
PyFunceble/query/collection.py
CHANGED
@@ -35,7 +35,7 @@ License:
|
|
35
35
|
::
|
36
36
|
|
37
37
|
|
38
|
-
Copyright 2017, 2018, 2019, 2020, 2022, 2023 Nissar Chababy
|
38
|
+
Copyright 2017, 2018, 2019, 2020, 2022, 2023, 2024 Nissar Chababy
|
39
39
|
|
40
40
|
Licensed under the Apache License, Version 2.0 (the "License");
|
41
41
|
you may not use this file except in compliance with the License.
|
@@ -51,8 +51,6 @@ License:
|
|
51
51
|
"""
|
52
52
|
|
53
53
|
import json
|
54
|
-
import logging
|
55
|
-
from datetime import datetime
|
56
54
|
from typing import List, Optional, Union
|
57
55
|
|
58
56
|
import requests
|
@@ -90,6 +88,7 @@ class CollectionQueryTool:
|
|
90
88
|
|
91
89
|
STD_URL_BASE: str = "http://localhost:8001"
|
92
90
|
STD_PREFERRED_STATUS_ORIGIN: str = "frequent"
|
91
|
+
STD_TIMEOUT: float = 5.0
|
93
92
|
|
94
93
|
_token: Optional[str] = None
|
95
94
|
"""
|
@@ -106,6 +105,16 @@ class CollectionQueryTool:
|
|
106
105
|
The preferred data origin
|
107
106
|
"""
|
108
107
|
|
108
|
+
_is_modern_api: Optional[bool] = None
|
109
|
+
"""
|
110
|
+
Whether we are working with the modern or legacy API.
|
111
|
+
"""
|
112
|
+
|
113
|
+
_timeout: float = 5.0
|
114
|
+
"""
|
115
|
+
The timeout to use while communicating with the API.
|
116
|
+
"""
|
117
|
+
|
109
118
|
session: Optional[requests.Session] = None
|
110
119
|
|
111
120
|
def __init__(
|
@@ -114,6 +123,7 @@ class CollectionQueryTool:
|
|
114
123
|
token: Optional[str] = None,
|
115
124
|
url_base: Optional[str] = None,
|
116
125
|
preferred_status_origin: Optional[str] = None,
|
126
|
+
timeout: Optional[float] = None,
|
117
127
|
) -> None:
|
118
128
|
if token is not None:
|
119
129
|
self.token = token
|
@@ -132,10 +142,16 @@ class CollectionQueryTool:
|
|
132
142
|
else:
|
133
143
|
self.guess_and_set_preferred_status_origin()
|
134
144
|
|
145
|
+
if timeout is not None:
|
146
|
+
self.timeout = timeout
|
147
|
+
else:
|
148
|
+
self.guess_and_set_timeout()
|
149
|
+
|
135
150
|
self.session = requests.Session()
|
136
151
|
self.session.headers.update(
|
137
152
|
{
|
138
153
|
"Authorization": f"Bearer {self.token}" if self.token else None,
|
154
|
+
"X-Pyfunceble-Version": PyFunceble.storage.PROJECT_VERSION,
|
139
155
|
"Content-Type": "application/json",
|
140
156
|
}
|
141
157
|
)
|
@@ -242,6 +258,80 @@ class CollectionQueryTool:
|
|
242
258
|
|
243
259
|
return self
|
244
260
|
|
261
|
+
@property
|
262
|
+
def is_modern_api(self) -> bool:
|
263
|
+
"""
|
264
|
+
Provides the value of the :code:`_is_modern_api` attribute.
|
265
|
+
"""
|
266
|
+
|
267
|
+
return self._is_modern_api
|
268
|
+
|
269
|
+
@is_modern_api.setter
|
270
|
+
def is_modern_api(self, value: bool) -> None:
|
271
|
+
"""
|
272
|
+
Sets the value of the :code:`_is_modern_api` attribute.
|
273
|
+
|
274
|
+
:param value:
|
275
|
+
The value to set.
|
276
|
+
|
277
|
+
:raise TypeError:
|
278
|
+
When the given :code:`value` is not a :py:class:`bool`.
|
279
|
+
"""
|
280
|
+
|
281
|
+
if not isinstance(value, bool):
|
282
|
+
raise TypeError(f"<value> should be {bool}, {type(value)} given.")
|
283
|
+
|
284
|
+
self._is_modern_api = value
|
285
|
+
|
286
|
+
def set_is_modern_api(self, value: bool) -> "CollectionQueryTool":
|
287
|
+
"""
|
288
|
+
Sets the value of the :code:`_is_modern_api` attribute.
|
289
|
+
|
290
|
+
:param value:
|
291
|
+
The value to set.
|
292
|
+
"""
|
293
|
+
|
294
|
+
self.is_modern_api = value
|
295
|
+
|
296
|
+
return self
|
297
|
+
|
298
|
+
@property
|
299
|
+
def timeout(self) -> float:
|
300
|
+
"""
|
301
|
+
Provides the value of the :code:`_timeout` attribute.
|
302
|
+
"""
|
303
|
+
|
304
|
+
return self._timeout
|
305
|
+
|
306
|
+
@timeout.setter
|
307
|
+
def timeout(self, value: float) -> None:
|
308
|
+
"""
|
309
|
+
Sets the value of the :code:`_timeout` attribute.
|
310
|
+
|
311
|
+
:param value:
|
312
|
+
The value to set.
|
313
|
+
|
314
|
+
:raise TypeError:
|
315
|
+
When the given :code:`value` is not a :py:class:`float`.
|
316
|
+
"""
|
317
|
+
|
318
|
+
if not isinstance(value, (int, float)):
|
319
|
+
raise TypeError(f"<value> should be {float}, {type(value)} given.")
|
320
|
+
|
321
|
+
self._timeout = value
|
322
|
+
|
323
|
+
def set_timeout(self, value: float) -> "CollectionQueryTool":
|
324
|
+
"""
|
325
|
+
Sets the value of the :code:`_timeout` attribute.
|
326
|
+
|
327
|
+
:param value:
|
328
|
+
The value to set.
|
329
|
+
"""
|
330
|
+
|
331
|
+
self.timeout = value
|
332
|
+
|
333
|
+
return self
|
334
|
+
|
245
335
|
def guess_and_set_url_base(self) -> "CollectionQueryTool":
|
246
336
|
"""
|
247
337
|
Try to guess the URL base to work with.
|
@@ -252,11 +342,37 @@ class CollectionQueryTool:
|
|
252
342
|
self.url_base = PyFunceble.storage.CONFIGURATION.collection.url_base
|
253
343
|
else:
|
254
344
|
self.url_base = self.STD_URL_BASE
|
345
|
+
elif EnvironmentVariableHelper("PYFUNCEBLE_COLLECTION_API_URL").exists():
|
346
|
+
self.url_base = EnvironmentVariableHelper(
|
347
|
+
"PYFUNCEBLE_COLLECTION_API_URL"
|
348
|
+
).get_value()
|
255
349
|
else:
|
256
350
|
self.url_base = self.STD_URL_BASE
|
257
351
|
|
258
352
|
return self
|
259
353
|
|
354
|
+
def guess_and_set_is_modern_api(self) -> "CollectionQueryTool":
|
355
|
+
"""
|
356
|
+
Try to guess if we are working with a legacy version.
|
357
|
+
"""
|
358
|
+
|
359
|
+
if self.token:
|
360
|
+
try:
|
361
|
+
response = self.session.get(
|
362
|
+
f"{self.url_base}/v1/stats/subject",
|
363
|
+
timeout=self.timeout,
|
364
|
+
)
|
365
|
+
|
366
|
+
response.raise_for_status()
|
367
|
+
|
368
|
+
self.is_modern_api = False
|
369
|
+
except (requests.RequestException, json.decoder.JSONDecodeError):
|
370
|
+
self.is_modern_api = True
|
371
|
+
else:
|
372
|
+
self.is_modern_api = False
|
373
|
+
|
374
|
+
return self
|
375
|
+
|
260
376
|
@property
|
261
377
|
def preferred_status_origin(self) -> Optional[str]:
|
262
378
|
"""
|
@@ -319,6 +435,33 @@ class CollectionQueryTool:
|
|
319
435
|
|
320
436
|
return self
|
321
437
|
|
438
|
+
def guess_and_set_timeout(self) -> "CollectionQueryTool":
|
439
|
+
"""
|
440
|
+
Try to guess the timeout to use.
|
441
|
+
"""
|
442
|
+
|
443
|
+
if PyFunceble.facility.ConfigLoader.is_already_loaded():
|
444
|
+
self.timeout = PyFunceble.storage.CONFIGURATION.lookup.timeout
|
445
|
+
else:
|
446
|
+
self.timeout = self.STD_TIMEOUT
|
447
|
+
|
448
|
+
return self
|
449
|
+
|
450
|
+
def ensure_is_modern_api_is_set(func): # pylint: disable=no-self-argument
|
451
|
+
"""
|
452
|
+
Ensures that the :code:`is_modern_api` attribute is set before running
|
453
|
+
the decorated method.
|
454
|
+
"""
|
455
|
+
|
456
|
+
def wrapper(self, *args, **kwargs):
|
457
|
+
if self.is_modern_api is None:
|
458
|
+
self.guess_and_set_is_modern_api()
|
459
|
+
|
460
|
+
return func(self, *args, **kwargs) # pylint: disable=not-callable
|
461
|
+
|
462
|
+
return wrapper
|
463
|
+
|
464
|
+
@ensure_is_modern_api_is_set
|
322
465
|
def pull(self, subject: str) -> Optional[dict]:
|
323
466
|
"""
|
324
467
|
Pulls all data related to the subject or :py:class:`None`
|
@@ -333,41 +476,51 @@ class CollectionQueryTool:
|
|
333
476
|
The response of the search.
|
334
477
|
"""
|
335
478
|
|
336
|
-
|
479
|
+
PyFunceble.facility.Logger.info("Starting to search subject: %r", subject)
|
337
480
|
|
338
481
|
if not isinstance(subject, str):
|
339
482
|
raise TypeError(f"<subject> should be {str}, {type(subject)} given.")
|
340
483
|
|
341
|
-
|
484
|
+
if self.is_modern_api:
|
485
|
+
if self.token:
|
486
|
+
url = f"{self.url_base}/v1/aggregation/subject/search"
|
487
|
+
else:
|
488
|
+
url = f"{self.url_base}/v1/hub/aggregation/subject/search"
|
489
|
+
else:
|
490
|
+
url = f"{self.url_base}/v1/subject/search"
|
342
491
|
|
343
492
|
try:
|
344
493
|
response = self.session.post(
|
345
494
|
url,
|
346
495
|
json={"subject": subject},
|
496
|
+
timeout=self.timeout,
|
347
497
|
)
|
348
498
|
|
349
499
|
response_json = response.json()
|
350
500
|
|
351
501
|
if response.status_code == 200:
|
352
|
-
|
502
|
+
PyFunceble.facility.Logger.debug(
|
353
503
|
"Successfully search subject: %r. Response: %r",
|
354
504
|
subject,
|
355
505
|
response_json,
|
356
506
|
)
|
357
507
|
|
358
|
-
|
508
|
+
PyFunceble.facility.Logger.info(
|
509
|
+
"Finished to search subject: %r", subject
|
510
|
+
)
|
359
511
|
|
360
512
|
return response_json
|
361
513
|
except (requests.RequestException, json.decoder.JSONDecodeError):
|
362
514
|
response_json = {}
|
363
515
|
|
364
|
-
|
516
|
+
PyFunceble.facility.Logger.debug(
|
365
517
|
"Failed to search subject: %r. Response: %r", subject, response_json
|
366
518
|
)
|
367
|
-
|
519
|
+
PyFunceble.facility.Logger.info("Finished to search subject: %r", subject)
|
368
520
|
|
369
521
|
return None
|
370
522
|
|
523
|
+
@ensure_is_modern_api_is_set
|
371
524
|
def push(
|
372
525
|
self,
|
373
526
|
checker_status: Union[
|
@@ -418,29 +571,15 @@ class CollectionQueryTool:
|
|
418
571
|
if checker_status.subject == "":
|
419
572
|
raise ValueError("<checker_status.subject> cannot be empty.")
|
420
573
|
|
421
|
-
status_to_subject = {
|
422
|
-
"status": checker_status.status,
|
423
|
-
"status_source": checker_status.status_source,
|
424
|
-
"tested_at": checker_status.tested_at.isoformat(),
|
425
|
-
"subject": checker_status.idna_subject,
|
426
|
-
}
|
427
|
-
|
428
574
|
if (
|
429
|
-
|
575
|
+
not self.is_modern_api
|
576
|
+
and hasattr(checker_status, "expiration_date")
|
430
577
|
and checker_status.expiration_date
|
431
578
|
):
|
432
|
-
self.__push_whois(
|
433
|
-
{
|
434
|
-
"subject": checker_status.idna_subject,
|
435
|
-
"expiration_date": datetime.strptime(
|
436
|
-
checker_status.expiration_date, "%d-%b-%Y"
|
437
|
-
).isoformat(),
|
438
|
-
"registrar": checker_status.registrar,
|
439
|
-
}
|
440
|
-
)
|
579
|
+
self.__push_whois(checker_status)
|
441
580
|
|
442
581
|
data = self.__push_status(
|
443
|
-
checker_status.checker_type.lower(),
|
582
|
+
checker_status.checker_type.lower(), checker_status.to_json()
|
444
583
|
)
|
445
584
|
|
446
585
|
return data
|
@@ -462,7 +601,9 @@ class CollectionQueryTool:
|
|
462
601
|
|
463
602
|
return self
|
464
603
|
|
465
|
-
def __push_status(
|
604
|
+
def __push_status(
|
605
|
+
self, checker_type: str, data: Union[dict, str]
|
606
|
+
) -> Optional[dict]:
|
466
607
|
"""
|
467
608
|
Submits the given status to the collection.
|
468
609
|
|
@@ -486,31 +627,60 @@ class CollectionQueryTool:
|
|
486
627
|
if checker_type not in self.SUPPORTED_CHECKERS:
|
487
628
|
raise ValueError(f"<checker_type> ({checker_type}) is not supported.")
|
488
629
|
|
489
|
-
|
630
|
+
PyFunceble.facility.Logger.info("Starting to submit status: %r", data)
|
490
631
|
|
491
|
-
|
632
|
+
if self.is_modern_api:
|
633
|
+
if not self.token:
|
634
|
+
url = f"{self.url_base}/v1/hub/status/{checker_type}"
|
635
|
+
else:
|
636
|
+
url = f"{self.url_base}/v1/contracts/self-delivery"
|
637
|
+
else:
|
638
|
+
url = f"{self.url_base}/v1/status/{checker_type}"
|
492
639
|
|
493
640
|
try:
|
494
|
-
|
495
|
-
|
496
|
-
|
497
|
-
|
641
|
+
if isinstance(data, dict):
|
642
|
+
response = self.session.post(
|
643
|
+
url,
|
644
|
+
json=data,
|
645
|
+
timeout=self.timeout,
|
646
|
+
)
|
647
|
+
elif isinstance(
|
648
|
+
data,
|
649
|
+
(
|
650
|
+
AvailabilityCheckerStatus,
|
651
|
+
SyntaxCheckerStatus,
|
652
|
+
ReputationCheckerStatus,
|
653
|
+
),
|
654
|
+
):
|
655
|
+
response = self.session.post(
|
656
|
+
url,
|
657
|
+
json=data.to_dict(),
|
658
|
+
timeout=self.timeout,
|
659
|
+
)
|
660
|
+
else:
|
661
|
+
response = self.session.post(
|
662
|
+
url,
|
663
|
+
data=data,
|
664
|
+
timeout=self.timeout,
|
665
|
+
)
|
498
666
|
|
499
667
|
response_json = response.json()
|
500
668
|
|
501
669
|
if response.status_code == 200:
|
502
|
-
|
670
|
+
PyFunceble.facility.Logger.debug(
|
671
|
+
"Successfully submitted data: %r to %s", data, url
|
672
|
+
)
|
503
673
|
|
504
|
-
|
674
|
+
PyFunceble.facility.Logger.info("Finished to submit status: %r", data)
|
505
675
|
return response_json
|
506
676
|
except (requests.RequestException, json.decoder.JSONDecodeError):
|
507
677
|
response_json = {}
|
508
678
|
|
509
|
-
|
679
|
+
PyFunceble.facility.Logger.debug(
|
510
680
|
"Failed to submit data: %r to %s. Response: %r", data, url, response_json
|
511
681
|
)
|
512
682
|
|
513
|
-
|
683
|
+
PyFunceble.facility.Logger.info("Finished to submit status: %r", data)
|
514
684
|
|
515
685
|
return None
|
516
686
|
|
@@ -535,10 +705,16 @@ class CollectionQueryTool:
|
|
535
705
|
if not self.token:
|
536
706
|
return None
|
537
707
|
|
708
|
+
if isinstance(
|
709
|
+
data,
|
710
|
+
(AvailabilityCheckerStatus, SyntaxCheckerStatus, ReputationCheckerStatus),
|
711
|
+
):
|
712
|
+
data = data.to_dict()
|
713
|
+
|
538
714
|
if not isinstance(data, dict): # pragma: no cover ## Should never happen
|
539
715
|
raise TypeError(f"<data> should be {dict}, {type(data)} given.")
|
540
716
|
|
541
|
-
|
717
|
+
PyFunceble.facility.Logger.info("Starting to submit WHOIS: %r", data)
|
542
718
|
|
543
719
|
url = f"{self.url_base}/v1/status/whois"
|
544
720
|
|
@@ -546,21 +722,24 @@ class CollectionQueryTool:
|
|
546
722
|
response = self.session.post(
|
547
723
|
url,
|
548
724
|
json=data,
|
725
|
+
timeout=self.timeout,
|
549
726
|
)
|
550
727
|
|
551
728
|
response_json = response.json()
|
552
729
|
|
553
730
|
if response.status_code == 200:
|
554
|
-
|
731
|
+
PyFunceble.facility.Logger.debug(
|
732
|
+
"Successfully submitted WHOIS data: %r to %s", data, url
|
733
|
+
)
|
555
734
|
|
556
|
-
|
735
|
+
PyFunceble.facility.Logger.info("Finished to submit WHOIS: %r", data)
|
557
736
|
return response_json
|
558
737
|
except (requests.RequestException, json.decoder.JSONDecodeError):
|
559
738
|
response_json = {}
|
560
739
|
|
561
|
-
|
740
|
+
PyFunceble.facility.Logger.debug(
|
562
741
|
"Failed to WHOIS data: %r to %s. Response: %r", data, url, response_json
|
563
742
|
)
|
564
743
|
|
565
|
-
|
744
|
+
PyFunceble.facility.Logger.info("Finished to submit WHOIS: %r", data)
|
566
745
|
return None
|
PyFunceble/query/dns/__init__.py
CHANGED
@@ -35,7 +35,7 @@ License:
|
|
35
35
|
::
|
36
36
|
|
37
37
|
|
38
|
-
Copyright 2017, 2018, 2019, 2020, 2022, 2023 Nissar Chababy
|
38
|
+
Copyright 2017, 2018, 2019, 2020, 2022, 2023, 2024 Nissar Chababy
|
39
39
|
|
40
40
|
Licensed under the Apache License, Version 2.0 (the "License");
|
41
41
|
you may not use this file except in compliance with the License.
|
@@ -35,7 +35,7 @@ License:
|
|
35
35
|
::
|
36
36
|
|
37
37
|
|
38
|
-
Copyright 2017, 2018, 2019, 2020, 2022, 2023 Nissar Chababy
|
38
|
+
Copyright 2017, 2018, 2019, 2020, 2022, 2023, 2024 Nissar Chababy
|
39
39
|
|
40
40
|
Licensed under the Apache License, Version 2.0 (the "License");
|
41
41
|
you may not use this file except in compliance with the License.
|
@@ -35,7 +35,7 @@ License:
|
|
35
35
|
::
|
36
36
|
|
37
37
|
|
38
|
-
Copyright 2017, 2018, 2019, 2020, 2022, 2023 Nissar Chababy
|
38
|
+
Copyright 2017, 2018, 2019, 2020, 2022, 2023, 2024 Nissar Chababy
|
39
39
|
|
40
40
|
Licensed under the Apache License, Version 2.0 (the "License");
|
41
41
|
you may not use this file except in compliance with the License.
|
PyFunceble/query/dns/resolver.py
CHANGED
@@ -35,7 +35,7 @@ License:
|
|
35
35
|
::
|
36
36
|
|
37
37
|
|
38
|
-
Copyright 2017, 2018, 2019, 2020, 2022, 2023 Nissar Chababy
|
38
|
+
Copyright 2017, 2018, 2019, 2020, 2022, 2023, 2024 Nissar Chababy
|
39
39
|
|
40
40
|
Licensed under the Apache License, Version 2.0 (the "License");
|
41
41
|
you may not use this file except in compliance with the License.
|
@@ -35,7 +35,7 @@ License:
|
|
35
35
|
::
|
36
36
|
|
37
37
|
|
38
|
-
Copyright 2017, 2018, 2019, 2020, 2022, 2023 Nissar Chababy
|
38
|
+
Copyright 2017, 2018, 2019, 2020, 2022, 2023, 2024 Nissar Chababy
|
39
39
|
|
40
40
|
Licensed under the Apache License, Version 2.0 (the "License");
|
41
41
|
you may not use this file except in compliance with the License.
|