Skip to content
39 changes: 34 additions & 5 deletions iot/api-client/manager/manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -490,6 +490,28 @@ def set_iam_permissions(
# [END iot_set_iam_policy]


def send_command(
service_account_json, project_id, cloud_region, registry_id, device_id,
command):
"""Send a command to a device."""
# [START iot_send_command]
print('Sending command to device')
client = get_client(service_account_json)
device_path = 'projects/{}/locations/{}/registries/{}/devices/{}'.format(
project_id, cloud_region, registry_id, device_id)

config_body = {
'binaryData': base64.urlsafe_b64encode(
command.encode('utf-8')).decode('ascii')
}

return client.projects(
).locations().registries(
).devices().sendCommandToDevice(
name=device_path, body=config_body).execute()
# [END iot_send_command]


def parse_command_line_args():
"""Parse command line arguments."""
default_registry = 'cloudiot_device_manager_example_registry_{}'.format(
Expand Down Expand Up @@ -546,6 +568,10 @@ def parse_command_line_args():
'--role',
default=None,
help='Role used for IAM commands.')
parser.add_argument(
'--send_command',
default='1',
help='The command sent to the device')

# Command subparser
command = parser.add_subparsers(dest='command')
Expand All @@ -566,6 +592,7 @@ def parse_command_line_args():
command.add_parser('list-registries', help=list_registries.__doc__)
command.add_parser('patch-es256', help=patch_es256_auth.__doc__)
command.add_parser('patch-rs256', help=patch_rsa256_auth.__doc__)
command.add_parser('send-command', help=send_command.__doc__)
command.add_parser('set-config', help=patch_rsa256_auth.__doc__)
command.add_parser('set-iam-permissions', help=set_iam_permissions.__doc__)

Expand Down Expand Up @@ -679,6 +706,12 @@ def run_command(args):
args.cloud_region, args.registry_id, args.device_id,
args.rsa_certificate_file)

elif args.command == 'send-command':
send_command(
args.service_account_json, args.project_id,
args.cloud_region, args.registry_id, args.device_id,
args.send_command)

elif args.command == 'set-iam-permissions':
if (args.member is None):
sys.exit('Error: specify --member')
Expand All @@ -699,10 +732,6 @@ def run_command(args):
args.version, args.config)


def main():
if __name__ == '__main__':
args = parse_command_line_args()
run_command(args)


if __name__ == '__main__':
main()
49 changes: 49 additions & 0 deletions iot/api-client/manager/manager_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,17 +13,23 @@
# limitations under the License.

import os
import sys
import time

# Add command receiver for bootstrapping device registry / device for testing
sys.path.append(os.path.join(os.path.dirname(__file__), '..', 'mqtt_example')) # noqa
from google.cloud import pubsub
import pytest

import manager
import cloudiot_mqtt_example

cloud_region = 'us-central1'
device_id_template = 'test-device-{}'
ca_cert_path = '../mqtt_example/resources/roots.pem'
es_cert_path = 'resources/ec_public.pem'
rsa_cert_path = 'resources/rsa_cert.pem'
rsa_private_path = 'resources/rsa_private.pem' # Must match rsa_cert
topic_id = 'test-device-events-{}'.format(int(time.time()))

project_id = os.environ['GCLOUD_PROJECT']
Expand Down Expand Up @@ -270,3 +276,46 @@ def test_add_patch_delete_es256(test_topic, capsys):

manager.delete_registry(
service_account_json, project_id, cloud_region, registry_id)


def test_send_command(test_topic, capsys):
device_id = device_id_template.format('RSA256')
manager.create_registry(
service_account_json, project_id, cloud_region, pubsub_topic,
registry_id)
manager.create_rs256_device(
service_account_json, project_id, cloud_region, registry_id,
device_id, rsa_cert_path)

# Exercize the functionality
client = cloudiot_mqtt_example.get_client(
project_id, cloud_region, registry_id, device_id,
rsa_private_path, 'RS256', ca_cert_path,
'mqtt.googleapis.com', 443)
client.loop_start()
out, _ = capsys.readouterr()

# Pre-process commands
for i in range(1, 5):
client.loop()
time.sleep(1)

manager.send_command(
service_account_json, project_id, cloud_region, registry_id,
device_id, 'me want cookies')
out, _ = capsys.readouterr()

# Process commands
for i in range(1, 5):
client.loop()
time.sleep(1)

# Clean up
manager.delete_device(
service_account_json, project_id, cloud_region, registry_id,
device_id)
manager.delete_registry(
service_account_json, project_id, cloud_region, registry_id)

assert 'Sending command to device' in out
assert '400' not in out
8 changes: 6 additions & 2 deletions iot/api-client/manager/requirements.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
google-api-python-client==1.7.4
cryptography==2.4.2
google-api-python-client==1.7.5
google-auth-httplib2==0.0.3
google-auth==1.6.1
google-cloud-pubsub==0.38.0
google-cloud-pubsub==0.39.0
oauth2client==4.1.3
paho-mqtt==1.4.0
pyjwt==1.6.4
33 changes: 16 additions & 17 deletions iot/api-client/manager/resources/rsa_cert.pem
Original file line number Diff line number Diff line change
@@ -1,19 +1,18 @@
-----BEGIN CERTIFICATE-----
MIIDFzCCAf+gAwIBAgIJALsqlqk6FkVjMA0GCSqGSIb3DQEBBQUAMBExDzANBgNV
BAMTBnVudXNlZDAeFw0xNzEyMDYyMjQwNDRaFw0yNzEyMDQyMjQwNDRaMBExDzAN
BgNVBAMTBnVudXNlZDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALZg
rgM97eLsTl3ul4m07pVHE/g9f0VP6/MDQcAjqj9kRmg5XMo/E6eRbNcIVwKEGHwC
SuSvGO/j7reYN4cbjvBqimc8asecg5rtXjaDBm66feB/ktOjASSfGfuN79JOJf+r
/BNcCrs8qWa1FSPEnQO7VTTUstkDKB8uvBFPOiPNVw438KM2lId2G/i63soMes0m
9RjPdXbRqJI39WdMVDYXIqLSVIX11xOXvroetwDPkHIi4Tjzus1T6KMjwKD3f3sm
DeUJeu4f1ZV4LPhhW62O9fkKeGy55LglfqOmWusySdOoNgEocN4V3iDQmJ7QOEXw
yPX+ZhhPHuptDwBTWJcCAwEAAaNyMHAwHQYDVR0OBBYEFD7D1XyWbYOiMWDgDyBs
po+JmlViMEEGA1UdIwQ6MDiAFD7D1XyWbYOiMWDgDyBspo+JmlVioRWkEzARMQ8w
DQYDVQQDEwZ1bnVzZWSCCQC7KpapOhZFYzAMBgNVHRMEBTADAQH/MA0GCSqGSIb3
DQEBBQUAA4IBAQAlq4QHt5yqCBhhLsMNnTDmg6ev7lxXKnb+JRMm3Op0rgBDe4sQ
U3Hxrhma+55f2rx32kwpcMQr4WWp0tUKL0OpWrNqdJc4oGFftLDqzKxXyT1nN5PH
1p9HCkHHwxmGZ60fxKb64yu9PTgsZS64l21CWlNFEiC8IULa5HV/O0ZZdPuAZVv0
hzmkalP/7uPqJ+z2tBEADQOjrU7SiB8uM+q1BLN9vnZrjo7CsXNwIiQ8N8eXpzsX
did5acwQdAt67uNx9e/YXLMvuAn+qVN+crS4IliBiikMZiUkug5yBDsLySFwXsZg
MGkUkV28QlgT4wzSQJ52yGtYCauqO2qU4zZg
MIIC+DCCAeCgAwIBAgIJALt7HnuYGgVcMA0GCSqGSIb3DQEBCwUAMBExDzANBgNV
BAMMBnVudXNlZDAeFw0xODEyMDMwMDE2MjNaFw0yODExMzAwMDE2MjNaMBExDzAN
BgNVBAMMBnVudXNlZDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAOrA
b+5XMIgwyl6+CkdJkKKp4f+2hHAOoSqQroj2MR/i41YysUbKCk8KdQSZqTBtIvrY
df7s6zDV3zmi3LBBHX6MGnz/1j5YIXlujBhsnQTRbTuUjjDx96ik2C2rR1w7okA7
MmBsdVzRe8g5pfNQGdV0l15UaZK+qFlLg0xzasPPKmYFFUbKXeWPaKJmtw9d/l6a
8jb87fwI3LTWjZr6Bk7L4Zf1TDlTDroMvNlkW9Z9xSkcgC77EjMtC7RYxxbelaxd
qI9IdxIpmExg6pKMJEvJNA11GYhTlAxkJNh7gd0WlYvQlwDI7D6NJPbCmm4ac1P2
AA1MFHVgxoKAFk/8V38CAwEAAaNTMFEwHQYDVR0OBBYEFC5Dlz2bTWzaJO6i1Qn8
lTdDAigCMB8GA1UdIwQYMBaAFC5Dlz2bTWzaJO6i1Qn8lTdDAigCMA8GA1UdEwEB
/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBANmnnBQaWPhJne5kOjMe+SEsdLbG
OD9L8RmokOsRPXJbj2KoM07UUXMgUe57daYm72wDfKZpvG5qwybkkym+NnahJY+C
u9FX1dTBjM/TqPWKI817mDp5W31a+q6DXdggG+Yf6pz0dMXGGzRtSTEpLKsKtXqe
Y9f7266JCx9V5QFK14SmpIdBF38G0bcNPEvRJ6uKaVKBnU4+7o4YlQLuDczT29Tp
CXL0egUViNT9kv03Pj9iSPR6EGcmOjnSZe1SFVg9OeCauF1wuuFCxUuCkWSEkEm7
laNke9PHHTe9BoBxKMsTFEPivhVaAf9fUp+NQxZNmdgbux9AAlJgiyU0sFg=
-----END CERTIFICATE-----
28 changes: 28 additions & 0 deletions iot/api-client/manager/resources/rsa_private.pem
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
-----BEGIN PRIVATE KEY-----
MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDqwG/uVzCIMMpe
vgpHSZCiqeH/toRwDqEqkK6I9jEf4uNWMrFGygpPCnUEmakwbSL62HX+7Osw1d85
otywQR1+jBp8/9Y+WCF5bowYbJ0E0W07lI4w8feopNgtq0dcO6JAOzJgbHVc0XvI
OaXzUBnVdJdeVGmSvqhZS4NMc2rDzypmBRVGyl3lj2iiZrcPXf5emvI2/O38CNy0
1o2a+gZOy+GX9Uw5Uw66DLzZZFvWfcUpHIAu+xIzLQu0WMcW3pWsXaiPSHcSKZhM
YOqSjCRLyTQNdRmIU5QMZCTYe4HdFpWL0JcAyOw+jST2wppuGnNT9gANTBR1YMaC
gBZP/Fd/AgMBAAECggEBAOevf4kColJ3nPM+qlRLJaV09yjyUOlrduLUon1oRXmL
6wUCyPXtp5j04CLnKRUzUUezZVlxKHotSr/OnfKSgXKJAgeGVEN5paf8U+YzJBFC
RIV+C4wA84WNFBKWrbo43Nx50DFcOcSet4UYaFGoJ6cFB/PAaeW7p9lhbreAXcnb
g2z4SBsGGO2ZKZkSOcXg39GKX5S0bsEhHzIOFvPBdDQpaVAx/Bq76iBzVz1bRwGp
A3SjJn0g4V+3TcTrpRzgtCRRNPM48JeLHw6/mdVSk6gIoEbg+WTB92Z7BlTbjqhI
LPoMx3wQkg7J2gRrT0rPJIMkgdK9Q8RyWaulsRAn+gECgYEA/jfisAhn7IAPBXKz
ED56NSr174qX97SO2JrB7PO614BV8lHSoV4QI+nQCBkNVhL/SuWvqB3naImo+UOX
Smo6fmh78X+yIXKKhj9qY01jxRGcrnhA25L9gk7TFSNm7XaV2HxHq+TW6tvkL0uO
jXSH3D+u8/f+5ZCt/egNq3eU4n8CgYEA7GWgBLq8jmiz/VVLYboJ0YcJVZ5XAjfJ
vgzxdzX9hIkq5Cpt1ZpO9zE3IXClVvfECXcLpEzoHbiJkEve4dDqbSe4T4JPmpRx
BKRPWFJvTieLA912UmHRBDTrQSA/nZ5zxHsXYmN52femqCwbPWYu5czoqud+GcNq
ghj4oF9UCwECgYEAzpaHx1ntakne6yR807SSB2b0GUfdm1TFyMxqz655pesK7TMF
IlGYeDbn8cy6A7rIcAsbplk21sMX6Ai/h5+wDU3He0e0cG3umI4sXKpla56WX0om
Gsnm7eA0tTbhzBPUTeshK1V6Ob2cP7r9C4MpbRjriiN8pv3eBzpu8WrqOO0CgYAB
8bgGMe75EN1iGQB8tkX8ZirqfFnk18ad/IdD3rrOCz7CD6NFnXZGzC3S5ZVGiNUg
6sy6tjM2g10GRcl4e/phmXEHnl+/OrdPPXa1mD/4GZUoG/ssJEfOzAyfRX+gcTws
goKnuX+4DjRdr7ctoxiBpVTIiwzbc2L93Oy2jPIpAQKBgGzaYhfOlB3SWo+iSKcb
Vx++0gXru1Sgeo42TIn+6adO6DYfwVtfaScVL+Jcg7MZYY+94gnPCp+/ohVTJTvQ
JZdI9Czem64VUtSvc0DCji5gPqvgsO5YgBQrGJJrbmVwu0A6RlNbDwxCdkqHuYk4
7vsxlbXvNufb0LjnNN0lSUU2
-----END PRIVATE KEY-----
7 changes: 7 additions & 0 deletions iot/api-client/mqtt_example/cloudiot_mqtt_example.py
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,13 @@ def get_client(
# Subscribe to the config topic.
client.subscribe(mqtt_config_topic, qos=1)

# The topic that the device will receive commands on.
mqtt_command_topic = '/devices/{}/commands/#'.format(device_id)

# Subscribe to the commands topic, QoS 1 enables message acknowledgement.
print('Subscribing to {}'.format(mqtt_command_topic))
client.subscribe(mqtt_command_topic, qos=0)

return client
# [END iot_mqtt_config]

Expand Down
42 changes: 42 additions & 0 deletions iot/api-client/mqtt_example/cloudiot_mqtt_example_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -176,3 +176,45 @@ def test_config(test_topic, capsys):
out, _ = capsys.readouterr()
assert "Received message" in out
assert '/devices/{}/config'.format(device_id) in out


def test_receive_command(capsys):
device_id = device_id_template.format('RSA256')
manager.create_registry(
service_account_json, project_id, cloud_region, pubsub_topic,
registry_id)
manager.create_rs256_device(
service_account_json, project_id, cloud_region, registry_id,
device_id, rsa_cert_path)

# Exercize the functionality
client = cloudiot_mqtt_example.get_client(
project_id, cloud_region, registry_id, device_id,
rsa_private_path, 'RS256', ca_cert_path,
'mqtt.googleapis.com', 443)
client.loop_start()

# Pre-process commands
for i in range(1, 3):
client.loop()
time.sleep(1)

manager.send_command(
service_account_json, project_id, cloud_region, registry_id,
device_id, 'me want cookies')

# Process commands
for i in range(1, 3):
client.loop()
time.sleep(1)

# Clean up
manager.delete_device(
service_account_json, project_id, cloud_region, registry_id,
device_id)
manager.delete_registry(
service_account_json, project_id, cloud_region, registry_id)

out, _ = capsys.readouterr()
assert 'on_connect' in out # Verify can connect
assert '\'me want cookies\'' in out # Verify can receive command
4 changes: 2 additions & 2 deletions iot/api-client/mqtt_example/requirements.txt
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
google-api-python-client==1.7.4
google-api-python-client==1.7.5
google-auth-httplib2==0.0.3
google-auth==1.6.1
google-cloud-pubsub==0.38.0
google-cloud-pubsub==0.39.0
cryptography==2.4.2
pyjwt==1.6.4
paho-mqtt==1.4.0
32 changes: 16 additions & 16 deletions iot/api-client/mqtt_example/resources/rsa_cert.pem
Original file line number Diff line number Diff line change
@@ -1,18 +1,18 @@
-----BEGIN CERTIFICATE-----
MIIC9TCCAd2gAwIBAgIJALM44e3ivEWkMA0GCSqGSIb3DQEBCwUAMBExDzANBgNV
BAMMBnVudXNlZDAeFw0xNzEyMDcwMDQ1MjdaFw0yNzEyMDUwMDQ1MjdaMBExDzAN
BgNVBAMMBnVudXNlZDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAL4w
BxHuEyYdbiwKiD8yXY7vYpcygeOQ4/ZdEg3wCB2OuYcaFRcCuqLcTLMnuzdcL+y3
HBjWkrRW658cg3NG93Vj0iwSrga6u24CGBNYV+h8MBvwaDxk+uubnd5M/Q2OyL1J
GiMxQ1blR/71Hr5hhqaQZ2+qOF6kuf1m9rLUtMUJwOKp/PjPDmy654ZGsFWFSZmy
eRpNzmGU+KJg0o+Qf+sm75a8gQZ8AsrqveW0S/8o+zAjD0SkPcd01QBmYzQhjbi/
LGGITrzbaB3ld9umJBIcXfnYPYisJfwSsT/jFwiXhrhpxNNaIaKlTzlQIt5l8bSs
HXzJBbuIg5Jb/SyIEpkCAwEAAaNQME4wHQYDVR0OBBYEFOfaQTUVAoNb6fc7qzzl
uKyHGrCYMB8GA1UdIwQYMBaAFOfaQTUVAoNb6fc7qzzluKyHGrCYMAwGA1UdEwQF
MAMBAf8wDQYJKoZIhvcNAQELBQADggEBALKKDtiV1YV8k0YsNdiIXRlS3jsuoGuI
VVBrvDGz5Hel0rH9YmmfPS/Yn08kk3DF8Uynr4Xo1Zt9hmhgoq3ZoWm7MIP1+a9s
WyACyEMhVQSCzQrexRvG5ElpHx/vNjbcwiBkE5urlIvMBVt+BRRNKMNWq6F9ae63
FxRp7CtNFSbibtLJuPgCs6qoNs0nlt2FPsNvs7jpPipj69o+egVckvQjAyppirWO
+jO5hCLy7EahLz2wCn90z0Xf9lhOZni9meaV1Vy3CHHg6jwIB8/XlRaHFrOGMGXg
h8eQqsmpk9/3o8pv00yj6Hkq+swVg7Rg9FZaUiOv/HO/J7stWU7qPbI=
MIIC+DCCAeCgAwIBAgIJALt7HnuYGgVcMA0GCSqGSIb3DQEBCwUAMBExDzANBgNV
BAMMBnVudXNlZDAeFw0xODEyMDMwMDE2MjNaFw0yODExMzAwMDE2MjNaMBExDzAN
BgNVBAMMBnVudXNlZDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAOrA
b+5XMIgwyl6+CkdJkKKp4f+2hHAOoSqQroj2MR/i41YysUbKCk8KdQSZqTBtIvrY
df7s6zDV3zmi3LBBHX6MGnz/1j5YIXlujBhsnQTRbTuUjjDx96ik2C2rR1w7okA7
MmBsdVzRe8g5pfNQGdV0l15UaZK+qFlLg0xzasPPKmYFFUbKXeWPaKJmtw9d/l6a
8jb87fwI3LTWjZr6Bk7L4Zf1TDlTDroMvNlkW9Z9xSkcgC77EjMtC7RYxxbelaxd
qI9IdxIpmExg6pKMJEvJNA11GYhTlAxkJNh7gd0WlYvQlwDI7D6NJPbCmm4ac1P2
AA1MFHVgxoKAFk/8V38CAwEAAaNTMFEwHQYDVR0OBBYEFC5Dlz2bTWzaJO6i1Qn8
lTdDAigCMB8GA1UdIwQYMBaAFC5Dlz2bTWzaJO6i1Qn8lTdDAigCMA8GA1UdEwEB
/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBANmnnBQaWPhJne5kOjMe+SEsdLbG
OD9L8RmokOsRPXJbj2KoM07UUXMgUe57daYm72wDfKZpvG5qwybkkym+NnahJY+C
u9FX1dTBjM/TqPWKI817mDp5W31a+q6DXdggG+Yf6pz0dMXGGzRtSTEpLKsKtXqe
Y9f7266JCx9V5QFK14SmpIdBF38G0bcNPEvRJ6uKaVKBnU4+7o4YlQLuDczT29Tp
CXL0egUViNT9kv03Pj9iSPR6EGcmOjnSZe1SFVg9OeCauF1wuuFCxUuCkWSEkEm7
laNke9PHHTe9BoBxKMsTFEPivhVaAf9fUp+NQxZNmdgbux9AAlJgiyU0sFg=
-----END CERTIFICATE-----
52 changes: 26 additions & 26 deletions iot/api-client/mqtt_example/resources/rsa_private.pem
Original file line number Diff line number Diff line change
@@ -1,28 +1,28 @@
-----BEGIN PRIVATE KEY-----
MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQC+MAcR7hMmHW4s
Cog/Ml2O72KXMoHjkOP2XRIN8AgdjrmHGhUXArqi3EyzJ7s3XC/stxwY1pK0Vuuf
HINzRvd1Y9IsEq4GurtuAhgTWFfofDAb8Gg8ZPrrm53eTP0Njsi9SRojMUNW5Uf+
9R6+YYamkGdvqjhepLn9Zvay1LTFCcDiqfz4zw5suueGRrBVhUmZsnkaTc5hlPii
YNKPkH/rJu+WvIEGfALK6r3ltEv/KPswIw9EpD3HdNUAZmM0IY24vyxhiE6822gd
5XfbpiQSHF352D2IrCX8ErE/4xcIl4a4acTTWiGipU85UCLeZfG0rB18yQW7iIOS
W/0siBKZAgMBAAECggEAfwLmBdRfl2m6JNFX0hSZpJY72kuRsN8XTnUzVHmDgfHJ
9u61POvGpnLHCjIzdjIrk0NqETBjQup1aooJQ1gWdKAYQPSsobPc7geZ+nlaI9mj
61Su1/58EBKZ6Faz/HTpnHeQbAY/OW3fmeYrBOtumBgB6/HauWH7D77Oa/lfS+Ij
4f6OVAxevsi6PUtNmNtBwk5S0lZl9SFcKeHurVindquX9vWZjBEEFtNXazJttIJS
z9KX29VYwoLfflIKaUKckn8X+wYc+3u3BvH8zJpd60yQ6MSo7Sb1XkxT9549m+JW
Cb+i1K7MC/yQo4mvDtAQIVBh8p8qpd4VjpBwMuUbgQKBgQDexuAaLO3adSYFXGwW
nom6Mz/ImYcpxYo0ouAR1talbmF5/oKl9Tcwh7l1eDHfe70gfeP+g4uwAcc1hx3a
ZtXusrJFBktFezlFQnZXaE5ppryrFWeu0he0RYLAVxnL6IlP9dYQhVsTZm+7uX5d
UP7aZtmOU9ZTEsAoqvjJQXvaCQKBgQDajPebXOxIUj8ffGTeiPZczTwXux04caDC
eFKSCbAlHWgG7mR4P3fQONfEGWNHF0CxBSrew9CHmKdPyiISaExCfUaUWDDCPQCp
UE5VAHPdjSlb4lqi+cyNVlJxBJGONtyYkbQNd6N9GHMnBS8jZi7zf8VzIXpeExA4
n79Aml/YEQKBgDFrGId19AWD+z0xNWEHJjJB8CJFvHANvAzVHLOYXuEvzTvMs5qw
/N8tHHzsftO+lUPB6XOqJrCSlGhRYtPx//8FcPpS3Ru6rAerKKlXIB3buPqSsv9a
55s72DdmmvhayysLs8LSclOpY5vXGCsHLqGwMw6Zlm+zNyFOXAX5GspRAoGAaJMx
W68ABK8OM0OzhGQm9kriKTzIg5yjXspyQBzQo0HJ6B8kBgHgk8rPO68mOPsgYlPl
qogp/OgHjv9ahFJRwzLslckJM7g628loYfYAew+zrZrG4dsDjNG0Sw3zlAgeUAbQ
D+2iVhZf61josFiRuMP3t9paEi+vAFk4C3KSz/ECgYBpi1akpIzsYehW5uOL7Jhw
Hay5eshQ4vmHYuhDnn3gtT3h6J7TMwWs9pOygBG1I1b7GJ+tp4BZWJ2PmI7P8s45
jdI99WODHwv03lAzjLwigoqDUDduaYqXcGghcGht5Sknkl2uYDChwLtI5JdBZ9/x
8h9dE9oAiH/KTzhPmK1E1Q==
MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDqwG/uVzCIMMpe
vgpHSZCiqeH/toRwDqEqkK6I9jEf4uNWMrFGygpPCnUEmakwbSL62HX+7Osw1d85
otywQR1+jBp8/9Y+WCF5bowYbJ0E0W07lI4w8feopNgtq0dcO6JAOzJgbHVc0XvI
OaXzUBnVdJdeVGmSvqhZS4NMc2rDzypmBRVGyl3lj2iiZrcPXf5emvI2/O38CNy0
1o2a+gZOy+GX9Uw5Uw66DLzZZFvWfcUpHIAu+xIzLQu0WMcW3pWsXaiPSHcSKZhM
YOqSjCRLyTQNdRmIU5QMZCTYe4HdFpWL0JcAyOw+jST2wppuGnNT9gANTBR1YMaC
gBZP/Fd/AgMBAAECggEBAOevf4kColJ3nPM+qlRLJaV09yjyUOlrduLUon1oRXmL
6wUCyPXtp5j04CLnKRUzUUezZVlxKHotSr/OnfKSgXKJAgeGVEN5paf8U+YzJBFC
RIV+C4wA84WNFBKWrbo43Nx50DFcOcSet4UYaFGoJ6cFB/PAaeW7p9lhbreAXcnb
g2z4SBsGGO2ZKZkSOcXg39GKX5S0bsEhHzIOFvPBdDQpaVAx/Bq76iBzVz1bRwGp
A3SjJn0g4V+3TcTrpRzgtCRRNPM48JeLHw6/mdVSk6gIoEbg+WTB92Z7BlTbjqhI
LPoMx3wQkg7J2gRrT0rPJIMkgdK9Q8RyWaulsRAn+gECgYEA/jfisAhn7IAPBXKz
ED56NSr174qX97SO2JrB7PO614BV8lHSoV4QI+nQCBkNVhL/SuWvqB3naImo+UOX
Smo6fmh78X+yIXKKhj9qY01jxRGcrnhA25L9gk7TFSNm7XaV2HxHq+TW6tvkL0uO
jXSH3D+u8/f+5ZCt/egNq3eU4n8CgYEA7GWgBLq8jmiz/VVLYboJ0YcJVZ5XAjfJ
vgzxdzX9hIkq5Cpt1ZpO9zE3IXClVvfECXcLpEzoHbiJkEve4dDqbSe4T4JPmpRx
BKRPWFJvTieLA912UmHRBDTrQSA/nZ5zxHsXYmN52femqCwbPWYu5czoqud+GcNq
ghj4oF9UCwECgYEAzpaHx1ntakne6yR807SSB2b0GUfdm1TFyMxqz655pesK7TMF
IlGYeDbn8cy6A7rIcAsbplk21sMX6Ai/h5+wDU3He0e0cG3umI4sXKpla56WX0om
Gsnm7eA0tTbhzBPUTeshK1V6Ob2cP7r9C4MpbRjriiN8pv3eBzpu8WrqOO0CgYAB
8bgGMe75EN1iGQB8tkX8ZirqfFnk18ad/IdD3rrOCz7CD6NFnXZGzC3S5ZVGiNUg
6sy6tjM2g10GRcl4e/phmXEHnl+/OrdPPXa1mD/4GZUoG/ssJEfOzAyfRX+gcTws
goKnuX+4DjRdr7ctoxiBpVTIiwzbc2L93Oy2jPIpAQKBgGzaYhfOlB3SWo+iSKcb
Vx++0gXru1Sgeo42TIn+6adO6DYfwVtfaScVL+Jcg7MZYY+94gnPCp+/ohVTJTvQ
JZdI9Czem64VUtSvc0DCji5gPqvgsO5YgBQrGJJrbmVwu0A6RlNbDwxCdkqHuYk4
7vsxlbXvNufb0LjnNN0lSUU2
-----END PRIVATE KEY-----