diff --git a/103120/examples/FooServiceSchema.xsd b/103120/examples/FooServiceSchema.xsd
new file mode 100644
index 0000000000000000000000000000000000000000..56573942c2bd501476e3876d6039bbdb905e97cd
--- /dev/null
+++ b/103120/examples/FooServiceSchema.xsd
@@ -0,0 +1,27 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/103120/examples/example.key b/103120/examples/example.key
new file mode 100644
index 0000000000000000000000000000000000000000..b5959e7f2fa859401c0543f1038599b31600b37c
--- /dev/null
+++ b/103120/examples/example.key
@@ -0,0 +1,28 @@
+-----BEGIN PRIVATE KEY-----
+MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDc9UQSsRmchhOC
+ixyrHvmjmDFeIApVlfTfVV5RJL/280wDlAYymhAcEcvMOyvBCHq4c3M8hBxt9zKD
+mV+NbcDqXyblt8rVpjzbggn3Ch2dMJ/kLNO+O+WJSl3Jpyx3b4r8IVoUDXai2sjX
+8jLNYI4TC673X3xX1VikzcGwFjt2zbL+WLHEnvUVeG/8FJfRl2ttWlSFMA2252ak
+OwtAPF4AKJBW5pXSeILA+K32bf+Y5JMODWwI+njylAafTFV1eM/dTOSEKYCHVCN0
+cxiO6KCC2GSzLeQEGWmh/C+uyhSlLW/6EyEHJcLdi6eTPunYJGanai6PLLr5zNWX
+lvcj/YbZAgMBAAECggEAbm1BPRo3U4uKWpaNmFPdrU3VdlYK9CUCgU8X2PPF4HRN
+TAiBZG6smGqocIQt5MYJFv/T2q2ny6lcHHrdT0BHxpoRRYMqIsZ26bk+o7DxheqU
+LiPdGtiyaX+6CZq71WDwk/tTGmx0GwW+lHXdv9h+iLQxGD4nVXoxWAPgxdEGnONY
+gSYbOhXz+MEFZaW8HnVPfoA+RR9Hg59gnmBCZlhbahqf3WnjAwgS0nsbSUN57wVi
+FcWHWLyzv94bQHcTgalXqVakQv5+ymJKF4ImiYUP2rLPQ8ubqwmdQ6xI8Gp3AGCr
+FY5koP3JT2mMY+aZJEEGWE3U4JRDyrkOpI34No8iEQKBgQD6niFOopCjE2k7eIFr
+c+s5Khp3ITmcgV4tycxngXOQw8GnPEzzZUW7xodTiMPLYz/8lFbJvCAWCeQpmVWX
+U8OX9anzY0U0ILbolXpdpGdZkBHbKWtAVBNOZ/lY0SAmt6/ZWf/EcqpMm/fH+iph
+aqafwQuX4qhy9HlwY2qwyj5y5QKBgQDhtBH9/9Hy0X2HI+uzNRaU0y1BqvuqjHOf
+1v57DM5uYF0MAp1SAfAJcx+jUXdf28Nr4GlxBIvQumq6rsvfKhqBINsKgJf/4+PA
+Lv+fofeUEEqrGHuecB4NbdHP5XIIiuyyuOtRhGq/sclOQSZAa1kxajGvDI1AVHL4
+LCwcy9HA5QKBgQDIq+2HhWvC6DwOvoMCgyMJ9siSMyxqQLwkdb0R8/mRJO3e9s22
+5pRbsq+RF6WPKb2GhVCo39XhT7I+DOUX8p5fAvo+RHKZNsi+m1ILwSRv9ogVsKiM
+LcX3thFWKL1RwysvIn1F03rBNPHGUm206yzYJj8eMwMmaNMERtabEJXIcQKBgHct
+Kvbwlr5daafrCrDkzlilLVdoXlzOrtrung8BUxsrHNaTptg/l6yVslX9VUgzdXvH
+0kVP/jenx2VtmM7sn3Qhkid4gUon3gGDj4yN7HmtJJA1bEjbsLKsk0XwRIdIO/We
++PphLjCsQrxkYDtRs5YJGdTxjsAyF0b9pAlMgiQVAoGBAK/NGV5+IPDHEmz0CNJN
+ApaA2jG8KrsIPWNpgOC3CxPMT3kWYK601y0CLw8ZpUnVTMfPkKMSOVsqaOpHV6eP
+Oecq3bP1CiNunro+j3EOIDIST2ttrlNuKIBaiz63ZMNDbs/DyaGL8Zf688OJCXsb
+yCWSJh8NbrNblNfI0jaMoTGw
+-----END PRIVATE KEY-----
diff --git a/103120/examples/example.pem b/103120/examples/example.pem
new file mode 100644
index 0000000000000000000000000000000000000000..2aa1eaca4fc4ca1cb9d727356fefedb84b9dfade
--- /dev/null
+++ b/103120/examples/example.pem
@@ -0,0 +1,19 @@
+-----BEGIN CERTIFICATE-----
+MIIC/zCCAeegAwIBAgIUUOGdj0hEfnnW9gqIOCTJ9EUocnMwDQYJKoZIhvcNAQEL
+BQAwDzENMAsGA1UEAwwEdGVzdDAeFw0yMTA2MjUwNzIyMDlaFw0yNDAzMjEwNzIy
+MDlaMA8xDTALBgNVBAMMBHRlc3QwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK
+AoIBAQDc9UQSsRmchhOCixyrHvmjmDFeIApVlfTfVV5RJL/280wDlAYymhAcEcvM
+OyvBCHq4c3M8hBxt9zKDmV+NbcDqXyblt8rVpjzbggn3Ch2dMJ/kLNO+O+WJSl3J
+pyx3b4r8IVoUDXai2sjX8jLNYI4TC673X3xX1VikzcGwFjt2zbL+WLHEnvUVeG/8
+FJfRl2ttWlSFMA2252akOwtAPF4AKJBW5pXSeILA+K32bf+Y5JMODWwI+njylAaf
+TFV1eM/dTOSEKYCHVCN0cxiO6KCC2GSzLeQEGWmh/C+uyhSlLW/6EyEHJcLdi6eT
+PunYJGanai6PLLr5zNWXlvcj/YbZAgMBAAGjUzBRMB0GA1UdDgQWBBSFT3NqexF1
+LcYkjqUr9MMTIFp/ATAfBgNVHSMEGDAWgBSFT3NqexF1LcYkjqUr9MMTIFp/ATAP
+BgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQCzwydpNgq680qWmd0D
+4ya9fHUopeX7LBSYOU7NU3CagjXnUMwaCmSpokkH0Wvn1UtXDUF+slA9bEeXkfZm
+70YW8msIEt1mljDi4CBI+MvaJ40OJkXwkQUE3dhj9LJl5Nv0UBEyv7k/a/6+eO9K
+OQoHIVqXwrWs9JHTW6T4diN1w7xcgvSXhlcOySHjfNzFzferqx8i0/Wz6jD/7YSC
+FOEaUrXbeFS3asRoZRLW6uXgfDJ7qfCmUZZ853OF3MN63OwWjPGxtFmeZAqMS/K0
+FKgwMCrmZlVq6Fx87E+sc3eppXIceCau/+CHG91mRvMSha6jQD7jLMT9xjND5Dob
+/scV
+-----END CERTIFICATE-----
diff --git a/103120/examples/mutliple-auth-example-request.xml b/103120/examples/mutliple-auth-example-request.xml
index 5e5f226800ba796c704d3f2075b837b783dc7cb1..8fd893c24d5aec216cb2197368892483015204f0 100644
--- a/103120/examples/mutliple-auth-example-request.xml
+++ b/103120/examples/mutliple-auth-example-request.xml
@@ -12,7 +12,7 @@
d442c58c-d5e1-4fd9-90ec-9c228ad947f1
2020-09-22T08:06:17.025833Z
- V1.8.1
+ V1.10.1
XX
v1.1.1
diff --git a/103120/examples/request1.xml b/103120/examples/request1.xml
index d0b64ee67b2950ceab226b9730c4e6d9abd34d87..a5e40d645c53e549c6002e105a5352b44dbbec47 100644
--- a/103120/examples/request1.xml
+++ b/103120/examples/request1.xml
@@ -12,7 +12,7 @@
c02358b2-76cf-4ba4-a8eb-f6436ccaea2e
2015-09-01T12:00:00.000000Z
- V1.8.1
+ V1.10.1
XX
v1.0
diff --git a/103120/examples/request2.xml b/103120/examples/request2.xml
index 67cbefd85d9617fe8c574c0bd449694b2dbcdc8f..2b1d012346c37b7d0b5689aa2fe895b1fa5c393e 100644
--- a/103120/examples/request2.xml
+++ b/103120/examples/request2.xml
@@ -12,7 +12,7 @@
45002c1e-dc4a-470a-9152-8e752638c86c
2015-09-01T12:01:00.000000Z
- V1.8.1
+ V1.10.1
XX
v1.0
diff --git a/103120/examples/request3.xml b/103120/examples/request3.xml
index c93bb7ad67a126019a17d1f5b959309548db46e1..dce66207fc39648701cd1673074b547fb02ca5bd 100644
--- a/103120/examples/request3.xml
+++ b/103120/examples/request3.xml
@@ -12,7 +12,7 @@
69353ac0-9582-4c71-b162-86259c99de20
2015-09-01T12:02:00.000000Z
- V1.8.1
+ V1.10.1
XX
v1.0
diff --git a/103120/examples/request4.xml b/103120/examples/request4.xml
index 6296da5a3153a1f53ddb1b248a462c2f75c48c07..73d6c07783352e8bfe3bd8327c2b261196de5e10 100644
--- a/103120/examples/request4.xml
+++ b/103120/examples/request4.xml
@@ -12,7 +12,7 @@
c02358b2-76cf-4ba4-a8eb-f6436ccaea2e
2019-09-30T13:37:00.000000Z
- V1.8.1
+ V1.10.1
XX
v1.0
diff --git a/103120/examples/request5-Binary-Delivery.xml b/103120/examples/request5-Binary-Delivery.xml
index 7d5170752e0475762923ed6fbdcc9282801b8114..2a13dfbbe6b9ad652b8dd8cb82195d8757a49267 100644
--- a/103120/examples/request5-Binary-Delivery.xml
+++ b/103120/examples/request5-Binary-Delivery.xml
@@ -12,7 +12,7 @@
8854cfad-44ac-43b8-99ae-530b690b43da
2019-09-30T13:37:37.000000Z
- V1.8.1
+ V1.10.1
XX
v1.0
diff --git a/103120/examples/request5-XML-Delivery.xml b/103120/examples/request5-XML-Delivery.xml
index f9314cdd3f3719b3d67dd0ba88122e0071a905d4..c345dbbe507c78e3c2b581f5410b964232920437 100644
--- a/103120/examples/request5-XML-Delivery.xml
+++ b/103120/examples/request5-XML-Delivery.xml
@@ -12,7 +12,7 @@
8854cfad-44ac-43b8-99ae-530b690b43da
2019-09-30T13:37:37.000000Z
- V1.8.1
+ V1.10.1
XX
v1.0
diff --git a/103120/examples/request6_signed.xml b/103120/examples/request6_signed.xml
new file mode 100644
index 0000000000000000000000000000000000000000..2bc0404ef924498e7280669c399ac4c430873787
--- /dev/null
+++ b/103120/examples/request6_signed.xml
@@ -0,0 +1,118 @@
+
+
+
+ XX
+ ACTOR01
+
+
+ XX
+ ACTOR02
+
+ 9964584e-c1a5-4ffa-b949-d9da504c4efb
+ 2021-06-25T12:00:00.000000Z
+
+ V1.9.1
+ XX
+ v1.0
+
+
+
+
+
+
+ 0
+
+
+ 68c78910-c922-45f2-aeb3-017eb958bb05
+ XX
+ ACTOR01
+ W000001
+
+ 2021-06-25T12:00:00Z
+ 2021-09-01T12:00:00Z
+
+
+
+
+
+ 1
+
+
+ 4d8127db-e8bc-4a69-9378-457f0424ec2c
+ XX
+ ACTOR01
+
+ 68c78910-c922-45f2-aeb3-017eb958bb05
+
+ LIID1
+
+
+
+
+ ETSI
+ InternationalizedEmailAddress
+
+ Όνομα.παραδείγματος@example.com
+
+
+
+
+ ETSI
+ TaskDeliveryType
+ IRIandCC
+
+
+
+
+ 192.0.2.0
+
+
+
+
+ XX
+ RECVER01
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ kARbaz+wH6oJWSvmy6Fk4vTQ7t4m3Y16IiNNdDO08/I=
+
+
+ DdT9ie03Z9O47sN8ad9gsfuhZhchtNhtvTyNhtiHKuqgNCt696tDH2c68tVqr+iJ3WpCn0gWJHKnYeniTwVPj6fxDh2RbCqk5SVHvdggZjCv3BInNH0ZfOrlvuArJS3UP/gifYXlT5s59Seze1nSjZDNeC25o9WRxNy0krGrhbqIFjxTHDilR40cmKq2SI1540yM3rsc+5D3hgsxGu7ly2dg7qtiFGQIQaFJi8twrViQUnOyDZ63yJHhWeLVU+2FvIuBZh3orDc3VipKsbqrjrDqdfi8qfYEHHPp25DfTpHXnCuhD/3hOwcxvhVJ4+47R8ysO9qMTvGRCUNptgskhQ==
+
+
+ MIIC/zCCAeegAwIBAgIUUOGdj0hEfnnW9gqIOCTJ9EUocnMwDQYJKoZIhvcNAQEL
+BQAwDzENMAsGA1UEAwwEdGVzdDAeFw0yMTA2MjUwNzIyMDlaFw0yNDAzMjEwNzIy
+MDlaMA8xDTALBgNVBAMMBHRlc3QwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK
+AoIBAQDc9UQSsRmchhOCixyrHvmjmDFeIApVlfTfVV5RJL/280wDlAYymhAcEcvM
+OyvBCHq4c3M8hBxt9zKDmV+NbcDqXyblt8rVpjzbggn3Ch2dMJ/kLNO+O+WJSl3J
+pyx3b4r8IVoUDXai2sjX8jLNYI4TC673X3xX1VikzcGwFjt2zbL+WLHEnvUVeG/8
+FJfRl2ttWlSFMA2252akOwtAPF4AKJBW5pXSeILA+K32bf+Y5JMODWwI+njylAaf
+TFV1eM/dTOSEKYCHVCN0cxiO6KCC2GSzLeQEGWmh/C+uyhSlLW/6EyEHJcLdi6eT
+PunYJGanai6PLLr5zNWXlvcj/YbZAgMBAAGjUzBRMB0GA1UdDgQWBBSFT3NqexF1
+LcYkjqUr9MMTIFp/ATAfBgNVHSMEGDAWgBSFT3NqexF1LcYkjqUr9MMTIFp/ATAP
+BgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQCzwydpNgq680qWmd0D
+4ya9fHUopeX7LBSYOU7NU3CagjXnUMwaCmSpokkH0Wvn1UtXDUF+slA9bEeXkfZm
+70YW8msIEt1mljDi4CBI+MvaJ40OJkXwkQUE3dhj9LJl5Nv0UBEyv7k/a/6+eO9K
+OQoHIVqXwrWs9JHTW6T4diN1w7xcgvSXhlcOySHjfNzFzferqx8i0/Wz6jD/7YSC
+FOEaUrXbeFS3asRoZRLW6uXgfDJ7qfCmUZZ853OF3MN63OwWjPGxtFmeZAqMS/K0
+FKgwMCrmZlVq6Fx87E+sc3eppXIceCau/+CHG91mRvMSha6jQD7jLMT9xjND5Dob
+/scV
+
+
+
+
+
\ No newline at end of file
diff --git a/103120/examples/response1.xml b/103120/examples/response1.xml
index 25aa22c9fee5e4873142b34d7aff30c82e25021e..54fad1cea1741d9c2d3fd9e8fac21816b4206551 100644
--- a/103120/examples/response1.xml
+++ b/103120/examples/response1.xml
@@ -12,7 +12,7 @@
c02358b2-76cf-4ba4-a8eb-f6436ccaea2e
2015-09-01T12:00:01.000000Z
- V1.8.1
+ V1.10.1
XX
v1.0
diff --git a/103120/examples/response2.xml b/103120/examples/response2.xml
index 3f3e55018f9770ac70dd24f0d3c3d876166a1d3e..104a76f5455b7625ca859d4e5cb919d9d6a40b57 100644
--- a/103120/examples/response2.xml
+++ b/103120/examples/response2.xml
@@ -12,7 +12,7 @@
45002c1e-dc4a-470a-9152-8e752638c86c
2015-09-01T12:01:00.000000Z
- V1.8.1
+ V1.10.1
XX
v1.0
diff --git a/103120/examples/response3.xml b/103120/examples/response3.xml
index e3b1537dce4c53c395ef3c1adc6090af76661793..445187d48fdb19f46e96cfb813f467c9190d9b01 100644
--- a/103120/examples/response3.xml
+++ b/103120/examples/response3.xml
@@ -12,7 +12,7 @@
69353ac0-9582-4c71-b162-86259c99de20
2015-09-01T12:02:00.000000Z
- V1.8.1
+ V1.10.1
XX
v1.0
diff --git a/103120/examples/response4.xml b/103120/examples/response4.xml
index a8dc811c0046124966418f8127ad3b8affd9f312..3ca45c26bb40c2ab11ec4c7dda7a2490639ad354 100644
--- a/103120/examples/response4.xml
+++ b/103120/examples/response4.xml
@@ -12,7 +12,7 @@
c02358b2-76cf-4ba4-a8eb-f6436ccaea2e
2019-09-30T13:37:01.000000Z
- V1.8.1
+ V1.10.1
XX
v1.0
diff --git a/103120/examples/response5.xml b/103120/examples/response5.xml
index 32bfcd1db455e85b29aca6b2f4c436a7a3e1e321..d02dff5149c3ae24115c323f76194bfa70b93677 100644
--- a/103120/examples/response5.xml
+++ b/103120/examples/response5.xml
@@ -17,7 +17,7 @@
8854cfad-44ac-43b8-99ae-530b690b43da
2019-09-30T13:37:37.000000Z
- V1.8.1
+ V1.10.1
XX
v1.0
diff --git a/testing/check_xsd.py b/testing/check_xsd.py
index db4ee8c7b34ffaae13ec9e522a503bd2ec344a17..816e3898aa2305c476a665b32c14237c82c22c3d 100644
--- a/testing/check_xsd.py
+++ b/testing/check_xsd.py
@@ -11,7 +11,6 @@ from lxml import etree
from xml.etree.ElementTree import ParseError
from xmlschema import XMLSchema, XMLSchemaParseError
-
def BuildSchemaDictonary (fileList):
if len(fileList) == 0:
logging.info("No schema files provided")
@@ -22,7 +21,7 @@ def BuildSchemaDictonary (fileList):
for schemaFile in fileList:
try:
xs = XMLSchema(schemaFile, validation='skip')
- schemaLocations.append((xs.default_namespace, str(Path(schemaFile).resolve())))
+ schemaLocations.append((xs.target_namespace, str(Path(schemaFile).resolve())))
logging.info(" [ {0} -> {1} ]".format(xs.default_namespace, schemaFile))
except ParseError as ex:
logging.warning (" [ {0} failed to parse: {1} ]".format(schemaFile, ex))
@@ -53,6 +52,7 @@ def ValidateXSDFiles (fileList):
schemaLocations = BuildSchemaDictonary(fileList)
errors = {}
+ schemaDictionary = {}
logging.info("Schema validation:")
for schemaFile in fileList:
@@ -60,6 +60,7 @@ def ValidateXSDFiles (fileList):
schema = XMLSchema(schemaFile, locations = schemaLocations)
logging.info(schemaFile + ": OK")
errors[schemaFile] = []
+ schemaDictionary[schema.target_namespace] = schema
except XMLSchemaParseError as ex:
if (ex.schema_url) and (ex.schema_url != ex.origin_url):
logging.info(" Error {1} comes from {0}, suppressing".format(ex.schema_url, ex.message))
@@ -67,7 +68,7 @@ def ValidateXSDFiles (fileList):
else:
logging.warning(schemaFile + ": Failed validation ({0})".format(ex))
errors[schemaFile] = [ex.message]
- return errors
+ return errors, schemaDictionary
def ValidateInstanceDocuments (coreFile, supportingSchemas, instanceDocs):
@@ -91,6 +92,7 @@ if __name__ == '__main__':
parser = argparse.ArgumentParser()
parser.add_argument("-v", "--verbosity", help="verbosity level", action="count", default=0)
parser.add_argument("input", help="include a directory or file", action="append", nargs="+")
+ parser.add_argument("-p", "--primaryNamespace", help="Primary schema namespace for instance doc validation")
args = parser.parse_args()
logging.getLogger().setLevel(logging.WARNING)
@@ -100,8 +102,10 @@ if __name__ == '__main__':
logging.getLogger().setLevel(logging.DEBUG)
logging.debug("Very verbose selected")
+
logging.debug(f"Path: {args.input}")
includeFileList = []
+ includeInstanceDocList = []
for path in args.input[0]:
p = Path(path)
if not p.exists():
@@ -112,12 +116,25 @@ if __name__ == '__main__':
for g in glob.glob(os.path.join(str(p), "*.xsd")):
logging.info(f">Including {g}")
includeFileList.append(g)
+ for g in glob.glob(os.path.join(str(p), "*.xml")):
+ logging.info(f">Including instance doc {g}")
+ includeInstanceDocList.append(g)
else:
- logging.info(f"Including {p.absolute()}")
- includeFileList.append(p.absolute())
+ logging.info(f">Including {p.absolute()}")
+ if str(p.absolute()).endswith('.xml'):
+ includeInstanceDocList.append(str(p.absolute()))
+ elif str(p.absolute()).endswith('.xsd'):
+ includeFileList.append(str(p.absolute()))
+ else:
+ logging.warning(f'Ignoring file {p.absolute()}')
+ if len(includeInstanceDocList) and (args.primaryNamespace is None):
+ print("Cannot validate instance documents without specifying a primary namespace (use -h for usage guidelines)")
+ exit(-1)
+
syntaxErrors = 0
+ print ("=============================")
print ("XSD syntax checks:")
print ("-----------------------------")
for file in includeFileList:
@@ -132,9 +149,12 @@ if __name__ == '__main__':
if (syntaxErrors > 0):
print (f"{syntaxErrors} syntax errors detected")
exit(syntaxErrors)
+ else:
+ print ("0 syntax errors detected")
- results = ValidateXSDFiles(includeFileList)
+ results, schemaDict = ValidateXSDFiles(includeFileList)
+ print ("=============================")
print ("XSD build checks:")
print ("-----------------------------")
errorCount = 0
@@ -152,4 +172,23 @@ if __name__ == '__main__':
print ("-----------------------------")
print (f"{errorCount} build errors detected")
- exit(errorCount)
\ No newline at end of file
+ if (errorCount > 0):
+ exit(errorCount)
+
+ print ("=============================")
+ print ("Instance document checks")
+ print ("-----------------------------")
+ errorCount = 0
+
+ primarySchema = schemaDict[args.primaryNamespace]
+ for instanceDoc in includeInstanceDocList:
+ try:
+ results = primarySchema.validate(instanceDoc)
+ print (f" {instanceDoc} : OK")
+ except Exception as ex:
+ errorCount += 1
+ print (f" {instanceDoc} : {str(ex)}")
+ print ("-----------------------------")
+ print (f"{errorCount} instance doc errors detected")
+ print ("=============================")
+ exit(errorCount)
diff --git a/testing/deps/xmldsig/xmldsig-core-schema.xsd b/testing/deps/xmldsig/xmldsig-core-schema.xsd
new file mode 100644
index 0000000000000000000000000000000000000000..df126b30e684091b32a748cd2e408f5fb9d651a9
--- /dev/null
+++ b/testing/deps/xmldsig/xmldsig-core-schema.xsd
@@ -0,0 +1,318 @@
+
+
+
+
+
+ ]>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+