### Install Python API using setup.py Source: https://github.com/shotgunsoftware/python-api/blob/master/docs/installation.rst Installs the Python API from a local copy of the repository by running the setup.py script. This copies the package into your Python site-packages directory. It may generate syntax errors during byte-compilation due to bundled Python 2 code, but the library remains functional. ```bash python setup.py install ``` -------------------------------- ### Install Python API via Pip (Specific Version) Source: https://github.com/shotgunsoftware/python-api/blob/master/docs/installation.rst Installs a specific tagged version of the Python API from GitHub using pip. Replace 'v3.0.26' with the desired version tag. ```bash pip install git+https://github.com/shotgunsoftware/python-api.git@v3.0.26 ``` -------------------------------- ### Install Python API via Pip (Master Branch) Source: https://github.com/shotgunsoftware/python-api/blob/master/docs/installation.rst Installs the latest revisions of the Python API directly from the GitHub master branch using pip. Note that this branch is not an official packaged release but is generally stable. ```bash pip install git+https://github.com/shotgunsoftware/python-api.git ``` -------------------------------- ### Add Python API to requirements.txt Source: https://github.com/shotgunsoftware/python-api/blob/master/docs/installation.rst Specifies the Python API installation from GitHub for use with pip's requirements.txt file. ```plaintext git+https://github.com/shotgunsoftware/python-api.git ``` -------------------------------- ### Example Local File Data Structure Source: https://github.com/shotgunsoftware/python-api/blob/master/docs/cookbook/attachments.rst Provides a concrete example of the data structure representing a local file link, including all relevant fields and their typical values. ```python { 'content_type': 'video/quicktime', 'link_type': 'local', 'name': 'my_test_movie.mov', 'local_path': '/Users/kp/Movies/testing/test_movie_002.mov', 'local_path_linux': '/home/users/macusers/kp/Movies/testing/test_movie_002.mov', 'local_path_mac': '/Users/kp/Movies/testing/test_movie_002.mov', 'local_path_windows': 'M:\\macusers\\kp\\Movies\\testing\\test_movie_002.mov', 'local_storage': {'id': 1, 'name': 'Dailies Directories', 'type': 'LocalStorage'}, 'url': 'file:///Users/kp/Movies/testing/test_movie_002.mov' } ``` -------------------------------- ### API - Schema Field Read with Localization Example Source: https://github.com/shotgunsoftware/python-api/blob/master/docs/reference.rst Shows an example of using schema_field_read and enabling localization to get localized display names. ```APIDOC >>> sg = Shotgun(site_name, script_name, script_key) >>> sg.config.localized False >>> sg.schema_field_read('Shot') { 'sg_vendor_groups': { 'mandatory': {'editable': False, 'value': False}, 'name': {'editable': True, 'value': 'Vendor Groups'}, ... }, ... } >>> sg.config.localized = True >>> sg.schema_field_read('Shot') { # The 'value' field for 'name' will now be localized if available. 'sg_vendor_groups': { 'mandatory': {'editable': False, 'value': False}, 'name': {'editable': True, 'value': 'Vendor Groups (Localized)'}, ... }, ... } ``` -------------------------------- ### Shotgun API Initialization and Action Handling Source: https://github.com/shotgunsoftware/python-api/blob/master/docs/cookbook/examples/ami_version_packager.rst Initializes the Shotgun API connection and processes actions based on command-line arguments. Handles potential errors during initialization and action parsing. ```python import sys import os # Assuming ShotgunAction, init_log, logger, ShotgunException, packageFilesForClient, and Shotgun are defined elsewhere # from your_module import ShotgunAction, init_log, logger, ShotgunException, packageFilesForClient, Shotgun # Placeholder for shotgun_conf and convert_tz shotgun_conf = { 'url': 'YOUR_SHOTGUN_URL', 'name': 'YOUR_SCRIPT_NAME', 'key': 'YOUR_API_KEY' } convert_tz = True logfile = 'shotgun_action.log' class ShotgunAction: def __init__(self, action_str): self.action = action_str class ShotgunException(Exception): pass def init_log(logfile): # Placeholder for logging initialization pass class logger: @staticmethod def info(message): print(f"INFO: {message}") class Shotgun: def __init__(self, url, name, key, convert_datetimes_to_utc): print(f"Connecting to Shotgun: {url}") pass def packageFilesForClient(client_type, file_path): print(f"Packaging files for client: {client_type} from {file_path}") return True if __name__ == "__main__": init_log(logfile) try: # Simulate command line arguments for demonstration # sys.argv = ['script_name.py', 'package4client'] if len(sys.argv) < 2: raise IndexError("No action provided") sa = ShotgunAction(sys.argv[1]) logger.info("Firing... %s" % (sys.argv[1]) ) except IndexError as e: raise ShotgunException("Missing POST arguments") sg = Shotgun(shotgun_conf['url'], shotgun_conf['name'], shotgun_conf['key'], convert_datetimes_to_utc=convert_tz) if sa.action == 'package4client': result = packageFilesForClient('sg_qt','/Users/kp/Documents/shotgun/dev/api/files/') else: raise ShotgunException("Unknown action... :%s" % sa.action) print("\nVersion Packager done!") ``` -------------------------------- ### Complete Shot Creation Script Source: https://github.com/shotgunsoftware/python-api/blob/master/docs/cookbook/examples/basic_create_shot.rst A full Python script demonstrating the initialization of the Shotgun API connection and the creation of a Shot entity. This includes setting up credentials and printing the result. ```python #!/usr/bin/env python # -------------------------------------- # Imports # -------------------------------------- import shotgun_api3 from pprint import pprint # useful for debugging # -------------------------------------- # Globals # -------------------------------------- # make sure to change this to match your Flow Production Tracking server and auth credentials. SERVER_PATH = "https://my-site.shotgrid.autodesk.com" SCRIPT_NAME = 'my_script' SCRIPT_KEY = '27b65d7063f46b82e670fe807bd2b6f3fd1676c1' # -------------------------------------- # Main # -------------------------------------- if __name__ == '__main__': sg = shotgun_api3.Shotgun(SERVER_PATH, SCRIPT_NAME, SCRIPT_KEY) # -------------------------------------- # Create a Shot with data # -------------------------------------- data = { 'project': {"type":"Project","id": 4}, 'code': '100_010', 'description': 'Open on a beautiful field with fuzzy bunnies', 'sg_status_list': 'ip' } result = sg.create('Shot', data) pprint(result) print("The id of the {} is {}.".format(result['type'], result['id'])) ``` -------------------------------- ### Compress Files Source: https://github.com/shotgunsoftware/python-api/blob/master/docs/cookbook/examples/ami_version_packager.rst Compresses a list of files into a single .tar.gz archive. It prepares the command string for the `tar` utility, logs the command being executed, and handles potential errors during the compression process. Returns the path to the created archive. ```python def compress_files(files,destination_filename): destination_filename += ".tar.gz" files = [path.lstrip("/") for path in files] squish_me = compress_cmd % (destination_filename, " ".join(files) ) logger.info("Compressing %s files..." % len(files)) logger.info("Running command: %s" % squish_me) try: output = subprocess.Popen(squish_me, shell=True, stdout=subprocess.PIPE).stdout.read() logger.info('tar/gzip command returned: %s' % output) except e: raise ShotgunException("unable compress files: %s"% e) logger.info("compressed files to: %s" % destination_filename) return destination_filename ``` -------------------------------- ### Documentation Updates and Fixes Source: https://github.com/shotgunsoftware/python-api/blob/master/HISTORY.rst Various documentation updates, including adding setup guides, fixing issues with filter prototypes, updating badges, and correcting hints and typos. ```python Minor fixes on unit tests and documentation. Documentation update Documentation: Fix issue regarding "in" filter prototype Documentation: Travis badge image is no working anymore Documentation: Add "Setting Up Your Environment with the Python API" to Python Docs (python-api docs). [Python API Documentation] Update Python version requirements. Update docs for entity fields. Fix typo. Fix incorrect hint. Reformat code examples to prevent text overflow. ``` -------------------------------- ### Fix Git Protocol for Installation Source: https://github.com/shotgunsoftware/python-api/blob/master/HISTORY.rst Correction of the git protocol used for installation. ```python Fixes git protocol for the installation. ``` -------------------------------- ### Updating Raw Fields Example Source: https://github.com/shotgunsoftware/python-api/blob/master/docs/cookbook/smart_cut_fields.rst Example of how to update 'raw' fields through the Shotgun Python API. This demonstrates the recommended approach for working with cut data. ```python from shotgun_api3 import Shotgun sg = Shotgun("your_sg_url", "your_script_user", "your_api_key") # Example: Update a cut field for a specific entity entity_type = "Shot" entity_id = 123 update_data = { "cut_in": "00:00:10:00", "cut_out": "00:00:20:00", "cut_duration": "00:00:10:00" } result = sg.update(entity_type, entity_id, update_data) print(f"Update result: {result}") ``` -------------------------------- ### Create Shotgun API Instance Source: https://github.com/shotgunsoftware/python-api/blob/master/docs/cookbook/examples/basic_sg_instance.rst Establishes a connection to the Flow Production Tracking API using server path, script name, and script key for authentication. It then prints available properties and methods on the connection object. ```python import pprint import shotgun_api3 SERVER_PATH = "https://my-site.shotgrid.autodesk.com" SCRIPT_NAME = 'my_script' SCRIPT_KEY = '27b65d7063f46b82e670fe807bd2b6f3fd1676c1' sg = shotgun_api3.Shotgun(SERVER_PATH, SCRIPT_NAME, SCRIPT_KEY) pprint.pprint([symbol for symbol in sorted(dir(sg)) if not symbol.startswith('_')]) ``` -------------------------------- ### Package Files for Client Source: https://github.com/shotgunsoftware/python-api/blob/master/docs/cookbook/examples/ami_version_packager.rst Orchestrates the process of packaging files for a client. It queries Shotgun for entities, downloads associated attachments, compresses them into a tar.gz archive, removes the temporary downloaded files, and finally copies the archive to a destination directory. It dynamically generates the archive filename based on project name and timestamp. ```python def packageFilesForClient(file_field,destination_dir): # get entities matching the selected ids logger.info("Querying Shotgun for %s %ss" % (len(sa.selected_ids_filter), sa.params['entity_type'])) entities = sg.find(sa.params['entity_type'],sa.selected_ids_filter,['id','code',file_field],filter_operator='any') # download the attachments for each entity, zip them, and copy to destination directory files = [] for e in entities: if not e[file_field]: logger.info("%s #%s: No file exists. Skippinsa." % (sa.params['entity_type'], e['id'])) else: logger.info("%s #%s: %s" % (sa.params['entity_type'], e['id'], e[file_field])) path_to_file = file_dir+"/"+re.sub(r"\s+", '_', e[file_field]['name']) result = download_attachment_to_disk(e[file_field], path_to_file ) # only include attachments. urls won't return true if result: files.append(path_to_file) # compress files # create a nice valid destination filename project_name = '' if 'project_name' in sa.params: project_name = re.sub(r"\s+", '_', sa.params['project_name'])+'_' dest_filename = project_name+datetime.today().strftime('%Y-%m-%d-%H%M%S')+"_"+sa.params['user_login'] archive = compress_files(files,file_dir+"/"+dest_filename) # now that we have the archive, remove the downloads r = remove_downloaded_files(files) # copy to directory result = copy_files([archive],destination_dir) ``` -------------------------------- ### API Error Example: Split Gap Violation Source: https://github.com/shotgunsoftware/python-api/blob/master/docs/cookbook/tasks/split_tasks.rst Provides an example of an API error raised when the gap between task splits is less than one calendar day, violating the rule that splits must be separated by at least one working day. ```python >>> sg.update('Task', 2088, {'splits':[{'start':'2012-12-10', 'end':'2012-12-11'}, {'start':'2012-12-12', 'end':'2012-12-14'}, {'start':'2012-12-19', 'end':'2012-12-20'}]}) Traceback (most recent call last): File "", line 1, in File "/shotgun/src/python-api/shotgun_api3/shotgun.py", line 600, in update record = self._call_rpc("update", params) File "/shotgun/src/python-api/shotgun_api3/shotgun.py", line 1239, in _call_rpc self._response_errors(response) File "/shotgun/src/python-api/shotgun_api3/shotgun.py", line 1435, in _response_errors "Unknown Error")) shotgun_api3.shotgun.Fault: API update() CRUD ERROR #5: Update failed for [Task.splits]: (task.rb) The start date in split segment 2 is only one calendar day away from the end date of the previous segment. There must be calendar days between split segments. ``` -------------------------------- ### Version Packager Script Source: https://github.com/shotgunsoftware/python-api/blob/master/docs/cookbook/examples/ami_version_packager.rst A Python script designed to be launched from a Flow Production Tracking ActionMenuItem. It downloads attachments from specified fields for selected entities, creates a compressed archive of these files, and copies the archive to a user-defined directory. The script utilizes the `ShotgunAction` class for parsing POST variables from the ActionMenuItem and connects to Flow Production Tracking to fetch file data. It includes logging and error handling for robustness. ```python #!/usr/bin/env python # encoding: utf-8 """ version_packager.py This example script is meant to be run from an ActionMenuItem in Flow Production Tracking. The menu item uses a custom protocol in order to launch this script, and is followed by the action 'package4client'. So the full url would be something like launchme://package4client?.... See: https://developer.shotgridsoftware.com/python-api/cookbook/examples/ami_handler.html It uses the example ActionMenu Python class also located in our docs for parsing the ActionMenuItem POST variables. For more information about it and accessing the variables in the ActionMenuItem POST request, See: http://developer.shotgridsoftware.com/python-api/examples/ami_handler The purpose of this script is to download attachment files from Flow Production Tracking, create an archive of them and copy them to a specified directory. You can invoke it with the following minimal example to connect to Flow Production Tracking, download any file that exists in the specified field ('sg_qt') for each selected_id passed from the ActionMenu. Then it will create a single archive of the files and move it to the specified directory ('/path/where/i/want/to/put/the/archive/'). The archive is named with the Project Name, timestamp, and user login who ran the ActionMenuItem ('Demo_Project_2010-04-29-172210_kp.tar.gz'): sa = ShotgunAction(sys.argv[1]) sg = shotgun_connect() if sa.action == 'package4client': r = packageFilesForClient('sg_qt','/path/where/i/want/to/put/the/archive/') """ # --------------------------------------------------------------------------------------------- # Imports # --------------------------------------------------------------------------------------------- import sys, os import logging as logger import subprocess import re from datetime import datetime from shotgun_api3 import Shotgun from shotgun_action import ShotgunAction from pprint import pprint # --------------------------------------------------------------------------------------------- # Variables # --------------------------------------------------------------------------------------------- # Flow Production Tracking server auth info shotgun_conf = { 'url':'https://my-site.shotgrid.autodesk.com', 'name':'YOUR_SCRIPT_NAME_HERE', 'key':'YOUR_SCRIPT_KEY_HERE' } # location to write logfile for this script logfile = os.path.dirname(sys.argv[0])+"/version_packager.log" # temporary directory to download movie files to and create thumbnail files in file_dir = os.path.dirname(sys.argv[0])+"/tmp" # compress command # tar czf /home/user/backup_www.tar.gz -C / var/www/html compress_cmd = "tar czf %s -C / %s" # ---------------------------------------------- # Generic Flow Production Tracking Exception Class # ---------------------------------------------- class ShotgunException(Exception): pass # ---------------------------------------------- # Set up logging # ---------------------------------------------- def init_log(filename="version_packager.log"): try: logger.basicConfig(level=logger.DEBUG, format='%(asctime)s %(levelname)-8s %(message)s', datefmt='%Y-%b-%d %H:%M:%s', filename=filename, filemode='w+') except IOError, e: raise ShotgunException ("Unable to open logfile for writing: %s" % e) logger.info("Version Packager logging started.") return logger # ---------------------------------------------- # Extract Attachment id from entity field # ---------------------------------------------- def extract_attachment_id(attachment): # extract the Attachment id from the url location attachment_id = attachment['url'].rsplit('/',1)[1] try: attachment_id = int(attachment_id) except: # not an integer. return None # raise ShotgunException("invalid Attachment id returned. Expected an integer: %s " % attachment_id) return attachment_id ``` -------------------------------- ### Shotgun Constructor and Configuration Source: https://github.com/shotgunsoftware/python-api/blob/master/docs/reference.rst Demonstrates initializing the Shotgun API client and configuring retry intervals and localization. ```python sg = Shotgun(site_name, script_name, script_key) sg.config.rpc_attempt_interval = 1000 # adjusting default interval sg.config.localized = True ``` -------------------------------- ### Moving Task Start Date with Splits Source: https://github.com/shotgunsoftware/python-api/blob/master/docs/cookbook/tasks/split_tasks.rst Illustrates how changing the 'start_date' of a task that has splits affects the splits. The first split is adjusted to the new start date, and subsequent splits are moved accordingly, maintaining gap lengths and workday rules. ```python sg.update('Task', 2088, { 'start_date': '2012-12-10' }) ``` -------------------------------- ### Subversion Post-Commit Hook Example (Unix Shell) Source: https://github.com/shotgunsoftware/python-api/blob/master/docs/cookbook/examples/svn_integration.rst An example of a Unix shell script for a Subversion post-commit hook. It exports repository and revision information, and then calls a Python script to interact with the Flow Production Tracking API. This script assumes a Unix-like environment. ```sh #!/bin/sh # POST-COMMIT HOOK REPOS="$1" REV="$2" export AUTHOR="$(svnlook author $REPOS --revision $REV)" export COMMENT="$(svnlook log $REPOS --revision $REV)" /Absolute/path/to/shotgun_api_script.py ``` -------------------------------- ### Certificate Content Example Source: https://github.com/shotgunsoftware/python-api/blob/master/shotgun_api3/lib/httplib2/python3/cacerts.txt This snippet shows the PEM-encoded content of a digital certificate, including the BEGIN and END CERTIFICATE markers. ```APIDOC -----BEGIN CERTIFICATE----- MIIEHjCCAwagAwIBAgIBATANBgkqhkiG9w0BAQUFADBnMQswCQYDVQQGEwJTRTEU MBIGA1UEChMLQWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFkZFRydXN0IFRUUCBOZXR3 b3JrMSMwIQYDVQQDExpBZGRUcnVzdCBRdWFsaWZpZWQgQ0EgUm9vdDAeFw0wMDA1 MzAxMDQ0NTBaFw0yMDA1MzAxMDQ0NTBaMGcxCzAJBgNVBAYTAlNFMRQwEgYDVQQK EwtBZGRUcnVzdCBBQjEdMBsGA1UECxMUQWRkVHJ1c3QgVFRQIE5ldHdvcmsxIzAh BgNVBAMTGkFkZFRydXN0IFF1YWxpZmllZCBDQSBSb290MIIBIjANBgkqhkiG9w0B AQEFAAOCAQ8AMIIBCgKCAQEA5B6a/twJWoekn0e+EV+vhDTbYjx5eLfpMLXsDBwq xBb/4Oxx64r1EW7tTw2R0hIYLUkVAcKkIhPHEWT/IhKauY5cLwjPcWqzZwFZ8V1G 87B4pfYOQnrjfxvM0PC3KP0q6p6zsLkEqv32x7SxuCqg+1jxGaBvcCV+PmlKfw8i 2O+tCBGaKZnhqkRFmhJePp1tUvznoD1oL/BLcHwTOK28FSXx1s6rosAx1i+f4P8U WfyEk9mHfExUE+uf0S0R+Bg6Ot4l2ffTQO2kBhLEO+GRwVY18BTcZTYJbqukB8c1 0cIDMzZbdSZtQvESa0NvS3GU+jQd7RNuyoB/mC9suWXY6QIDAQABo4HUMIHRMB0G A1UdDgQWBBQ5lYtii1zJ1IC6WA+XPxUIQ8yYpzALBgNVHQ8EBAMCAQYwDwYDVR0T AQH/BAUwAwEB/zCBkQYDVR0jBIGJMIGGgBQ5lYtii1zJ1IC6WA+XPxUIQ8yYp6Fr pGkwZzELMAkGA1UEBhMCU0UxFDASBgNVBAoTC0FkZFRydXN0IEFCMR0wGwYDVQQL ExRBZGRUcnVzdCBUVFAgTmV0d29yazEjMCEGA1UEAxMaQWRkVHJ1c3QgUXVhbGlm aWVkIENBIFJvb3SCAQEwDQYJKoZIhvcNAQEFBQADggEBABmrder4i2VhlRO6aQTv hsoToMeqT2QbPxj2qC0sVY8FtzDqQmodwCVRLae/DLPt7wh/bDxGGuoYQ992zPlm hpwsaPXpF/gxsxjE1kh9I0xowX67ARRvxdlu3rsEQmr49lx95dr6h+sNNVJn0J6X dgWTP5XHAeZpVTh/EGGZyeNfpso+gmNIquIISD6q8rKFYqa0p9m9N5xotS1WfbC3 P6CxB9bpT9zeRXEwMn8bLgn5v1Kh7sKAPgZcLlVAwRv1cEWw3F369nJad9Jjzc9Y iQBCYz95OdBEsIJuQRno3eDBiFrRHnGTHyQwdOUeqN48Jzd/g66ed8/wMLH/S5no xqE= -----END CERTIFICATE----- ``` -------------------------------- ### Include Data Files in py2app Setup Source: https://github.com/shotgunsoftware/python-api/blob/master/docs/advanced/packaging.rst This snippet demonstrates how to configure the `setup.py` file for py2app to include external data files, such as `cacerts.txt`, which are necessary for the application's functionality (e.g., HTTPS validation). The `DATA_FILES` variable specifies the source path and the destination path within the application bundle. ```python DATA_FILES = [ ('shotgun_api3', ['/shotgun/src/python-api/shotgun_api3/lib/httplib2/cacerts.txt']) ] ``` -------------------------------- ### Certificate Content Example Source: https://github.com/shotgunsoftware/python-api/blob/master/shotgun_api3/lib/httplib2/cacerts.txt This snippet shows the PEM-encoded content of a digital certificate, including the BEGIN and END CERTIFICATE markers. ```APIDOC -----BEGIN CERTIFICATE----- MIIEHjCCAwagAwIBAgIBATANBgkqhkiG9w0BAQUFADBnMQswCQYDVQQGEwJTRTEU MBIGA1UEChMLQWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFkZFRydXN0IFRUUCBOZXR3 b3JrMSMwIQYDVQQDExpBZGRUcnVzdCBRdWFsaWZpZWQgQ0EgUm9vdDAeFw0wMDA1 MzAxMDQ0NTBaFw0yMDA1MzAxMDQ0NTBaMGcxCzAJBgNVBAYTAlNFMRQwEgYDVQQK EwtBZGRUcnVzdCBBQjEdMBsGA1UECxMUQWRkVHJ1c3QgVFRQIE5ldHdvcmsxIzAh BgNVBAMTGkFkZFRydXN0IFF1YWxpZmllZCBDQSBSb290MIIBIjANBgkqhkiG9w0B AQEFAAOCAQ8AMIIBCgKCAQEA5B6a/twJWoekn0e+EV+vhDTbYjx5eLfpMLXsDBwq xBb/4Oxx64r1EW7tTw2R0hIYLUkVAcKkIhPHEWT/IhKauY5cLwjPcWqzZwFZ8V1G 87B4pfYOQnrjfxvM0PC3KP0q6p6zsLkEqv32x7SxuCqg+1jxGaBvcCV+PmlKfw8i 2O+tCBGaKZnhqkRFmhJePp1tUvznoD1oL/BLcHwTOK28FSXx1s6rosAx1i+f4P8U WfyEk9mHfExUE+uf0S0R+Bg6Ot4l2ffTQO2kBhLEO+GRwVY18BTcZTYJbqukB8c1 0cIDMzZbdSZtQvESa0NvS3GU+jQd7RNuyoB/mC9suWXY6QIDAQABo4HUMIHRMB0G A1UdDgQWBBQ5lYtii1zJ1IC6WA+XPxUIQ8yYpzALBgNVHQ8EBAMCAQYwDwYDVR0T AQH/BAUwAwEB/zCBkQYDVR0jBIGJMIGGgBQ5lYtii1zJ1IC6WA+XPxUIQ8yYp6Fr pGkwZzELMAkGA1UEBhMCU0UxFDASBgNVBAoTC0FkZFRydXN0IEFCMR0wGwYDVQQL ExRBZGRUcnVzdCBUVFAgTmV0d29yazEjMCEGA1UEAxMaQWRkVHJ1c3QgUXVhbGlm aWVkIENBIFJvb3SCAQEwDQYJKoZIhvcNAQEFBQADggEBABmrder4i2VhlRO6aQTv hsoToMeqT2QbPxj2qC0sVY8FtzDqQmodwCVRLae/DLPt7wh/bDxGGuoYQ992zPlm hpwsaPXpF/gxsxjE1kh9I0xowX67ARRvxdlu3rsEQmr49lx95dr6h+sNNVJn0J6X dgWTP5XHAeZpVTh/EGGZyeNfpso+gmNIquIISD6q8rKFYqa0p9m9N5xotS1WfbC3 P6CxB9bpT9zeRXEwMn8bLgn5v1Kh7sKAPgZcLlVAwRv1cEWw3F369nJad9Jjzc9Y iQBCYz95OdBEsIJuQRno3eDBiFrRHnGTHyQwdOUeqN48Jzd/g66ed8/wMLH/S5no xqE= -----END CERTIFICATE----- ```