Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Updates library versions and tests #1884

Merged
merged 7 commits into from
Dec 4, 2018
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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-----
9 changes: 8 additions & 1 deletion 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 Expand Up @@ -206,7 +213,7 @@ def parse_command_line_args():
parser.add_argument(
'--mqtt_bridge_port',
choices=(8883, 443),
default=8883,
default=443,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

shouldn't 8883 be the default (and 443 be backup for firewall issues/testing)?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It'd appeared that the tests were failing because of the default port, updating test / fixing.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm seeing the issue again now.

type=int,
help='MQTT bridge port.')
parser.add_argument(
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-----