From 682f2e775effd7f5b294b9897ca4628fa28aa1dd Mon Sep 17 00:00:00 2001 From: Utz-Uwe Haus <uhaus@cray.com> Date: Fri, 24 Apr 2020 17:38:00 +0200 Subject: [PATCH] Implement attribute default value handling not fully working --- attributes/ecmwf-yaml.h | 61 ++- attributes/ecmwf.yaml | 4 +- attributes/maestro-core-yaml.h | 550 +++++++++++++------------- attributes/maestro-core.yaml | 57 +-- attributes/maestro-schema.c | 703 ++++++++++++++++++++------------- attributes/symtab.c | 2 +- 6 files changed, 770 insertions(+), 607 deletions(-) diff --git a/attributes/ecmwf-yaml.h b/attributes/ecmwf-yaml.h index f8198d00..08c42fe0 100644 --- a/attributes/ecmwf-yaml.h +++ b/attributes/ecmwf-yaml.h @@ -124,36 +124,35 @@ unsigned char ecmwf_yaml[] = { 0x3d, 0x31, 0x2c, 0x20, 0x6d, 0x61, 0x78, 0x3d, 0x35, 0x30, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x64, 0x3a, 0x20, 0x46, 0x61, 0x6c, 0x73, 0x65, 0x0a, 0x20, 0x20, 0x20, 0x20, - 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x3a, 0x20, 0x46, 0x61, 0x6c, - 0x73, 0x65, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x64, 0x6f, 0x63, 0x75, 0x6d, - 0x65, 0x6e, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x20, 0x4e, 0x75, - 0x6d, 0x62, 0x65, 0x72, 0x20, 0x69, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, - 0x65, 0x6e, 0x73, 0x65, 0x6d, 0x62, 0x6c, 0x65, 0x20, 0x73, 0x65, 0x74, - 0x2e, 0x0a, 0x0a, 0x20, 0x20, 0x2d, 0x20, 0x6b, 0x65, 0x79, 0x3a, 0x20, - 0x22, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x69, 0x73, 0x74, 0x22, 0x0a, 0x20, - 0x20, 0x20, 0x20, 0x74, 0x79, 0x70, 0x65, 0x3a, 0x20, 0x69, 0x6e, 0x74, - 0x28, 0x6d, 0x69, 0x6e, 0x3d, 0x31, 0x2c, 0x20, 0x6d, 0x61, 0x78, 0x3d, - 0x31, 0x33, 0x37, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x71, - 0x75, 0x69, 0x72, 0x65, 0x64, 0x3a, 0x20, 0x46, 0x61, 0x6c, 0x73, 0x65, - 0x0a, 0x20, 0x20, 0x20, 0x20, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, - 0x3a, 0x20, 0x46, 0x61, 0x6c, 0x73, 0x65, 0x0a, 0x20, 0x20, 0x20, 0x20, - 0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x61, 0x74, 0x69, 0x6f, - 0x6e, 0x3a, 0x20, 0x56, 0x65, 0x72, 0x74, 0x69, 0x63, 0x61, 0x6c, 0x20, - 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x20, 0x69, 0x66, 0x20, 0x74, 0x68, 0x65, - 0x72, 0x65, 0x20, 0x69, 0x73, 0x20, 0x6f, 0x6e, 0x65, 0x20, 0x61, 0x73, - 0x73, 0x6f, 0x63, 0x69, 0x61, 0x74, 0x65, 0x64, 0x20, 0x77, 0x69, 0x74, - 0x68, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x20, - 0x74, 0x79, 0x70, 0x65, 0x2e, 0x0a, 0x0a, 0x20, 0x20, 0x2d, 0x20, 0x6b, - 0x65, 0x79, 0x3a, 0x20, 0x22, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x22, 0x0a, - 0x20, 0x20, 0x20, 0x20, 0x74, 0x79, 0x70, 0x65, 0x3a, 0x20, 0x69, 0x6e, - 0x74, 0x28, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x71, 0x75, - 0x69, 0x72, 0x65, 0x64, 0x3a, 0x20, 0x54, 0x72, 0x75, 0x65, 0x0a, 0x20, + 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x3a, 0x20, 0x30, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x61, - 0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x20, 0x55, 0x6e, 0x69, 0x71, 0x65, 0x20, - 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x20, 0x66, - 0x6f, 0x72, 0x20, 0x74, 0x68, 0x65, 0x20, 0x66, 0x69, 0x65, 0x6c, 0x64, - 0x20, 0x61, 0x73, 0x20, 0x61, 0x20, 0x6d, 0x65, 0x74, 0x65, 0x6f, 0x72, - 0x6f, 0x6c, 0x6f, 0x67, 0x69, 0x63, 0x61, 0x6c, 0x20, 0x71, 0x75, 0x61, - 0x6e, 0x74, 0x69, 0x74, 0x79, 0x2e, 0x0a + 0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x20, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, + 0x20, 0x69, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x65, 0x6e, 0x73, 0x65, + 0x6d, 0x62, 0x6c, 0x65, 0x20, 0x73, 0x65, 0x74, 0x2e, 0x0a, 0x0a, 0x20, + 0x20, 0x2d, 0x20, 0x6b, 0x65, 0x79, 0x3a, 0x20, 0x22, 0x6c, 0x65, 0x76, + 0x65, 0x6c, 0x69, 0x73, 0x74, 0x22, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x74, + 0x79, 0x70, 0x65, 0x3a, 0x20, 0x69, 0x6e, 0x74, 0x28, 0x6d, 0x69, 0x6e, + 0x3d, 0x31, 0x2c, 0x20, 0x6d, 0x61, 0x78, 0x3d, 0x31, 0x33, 0x37, 0x29, + 0x0a, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, + 0x64, 0x3a, 0x20, 0x46, 0x61, 0x6c, 0x73, 0x65, 0x0a, 0x20, 0x20, 0x20, + 0x20, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x3a, 0x20, 0x30, 0x0a, + 0x20, 0x20, 0x20, 0x20, 0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x20, 0x56, 0x65, 0x72, 0x74, 0x69, + 0x63, 0x61, 0x6c, 0x20, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x20, 0x69, 0x66, + 0x20, 0x74, 0x68, 0x65, 0x72, 0x65, 0x20, 0x69, 0x73, 0x20, 0x6f, 0x6e, + 0x65, 0x20, 0x61, 0x73, 0x73, 0x6f, 0x63, 0x69, 0x61, 0x74, 0x65, 0x64, + 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6c, 0x65, + 0x76, 0x65, 0x6c, 0x20, 0x74, 0x79, 0x70, 0x65, 0x2e, 0x0a, 0x0a, 0x20, + 0x20, 0x2d, 0x20, 0x6b, 0x65, 0x79, 0x3a, 0x20, 0x22, 0x70, 0x61, 0x72, + 0x61, 0x6d, 0x22, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x74, 0x79, 0x70, 0x65, + 0x3a, 0x20, 0x69, 0x6e, 0x74, 0x28, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, + 0x72, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x64, 0x3a, 0x20, 0x54, 0x72, + 0x75, 0x65, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x64, 0x6f, 0x63, 0x75, 0x6d, + 0x65, 0x6e, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x20, 0x55, 0x6e, + 0x69, 0x71, 0x65, 0x20, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, + 0x65, 0x72, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x74, 0x68, 0x65, 0x20, 0x66, + 0x69, 0x65, 0x6c, 0x64, 0x20, 0x61, 0x73, 0x20, 0x61, 0x20, 0x6d, 0x65, + 0x74, 0x65, 0x6f, 0x72, 0x6f, 0x6c, 0x6f, 0x67, 0x69, 0x63, 0x61, 0x6c, + 0x20, 0x71, 0x75, 0x61, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x2e, 0x0a }; -const unsigned int ecmwf_yaml_len = 1867; +const unsigned int ecmwf_yaml_len = 1859; diff --git a/attributes/ecmwf.yaml b/attributes/ecmwf.yaml index a3163b1a..36105026 100644 --- a/attributes/ecmwf.yaml +++ b/attributes/ecmwf.yaml @@ -62,13 +62,13 @@ maestro-attributes: - key: "number" type: int(min=1, max=50) required: False - default: False + default: 0 documentation: Number in the ensemble set. - key: "levelist" type: int(min=1, max=137) required: False - default: False + default: 0 documentation: Vertical level if there is one associated with the level type. - key: "param" diff --git a/attributes/maestro-core-yaml.h b/attributes/maestro-core-yaml.h index ad8278f6..487865da 100644 --- a/attributes/maestro-core-yaml.h +++ b/attributes/maestro-core-yaml.h @@ -23,297 +23,305 @@ unsigned char maestro_core_yaml[] = { 0x0a, 0x23, 0x20, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x20, 0x70, 0x65, 0x72, 0x6d, 0x69, 0x74, 0x74, 0x65, 0x64, 0x20, 0x69, 0x6e, 0x20, 0x75, 0x73, 0x65, 0x72, 0x2d, 0x64, 0x65, 0x66, 0x69, 0x6e, 0x65, 0x64, 0x20, - 0x74, 0x79, 0x70, 0x65, 0x73, 0x20, 0x75, 0x73, 0x65, 0x64, 0x0a, 0x73, - 0x63, 0x68, 0x65, 0x6d, 0x61, 0x2d, 0x74, 0x79, 0x70, 0x65, 0x2d, 0x76, - 0x61, 0x6c, 0x75, 0x65, 0x73, 0x3a, 0x0a, 0x20, 0x20, 0x23, 0x20, 0x76, + 0x74, 0x79, 0x70, 0x65, 0x73, 0x20, 0x75, 0x73, 0x65, 0x64, 0x0a, 0x23, + 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x2d, 0x74, 0x79, 0x70, 0x65, 0x2d, + 0x76, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x3a, 0x0a, 0x20, 0x20, 0x23, 0x20, + 0x46, 0x49, 0x58, 0x4d, 0x45, 0x3a, 0x20, 0x75, 0x73, 0x65, 0x72, 0x2d, + 0x64, 0x65, 0x66, 0x69, 0x6e, 0x65, 0x64, 0x20, 0x74, 0x79, 0x70, 0x65, + 0x73, 0x20, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x6c, 0x79, 0x20, + 0x62, 0x72, 0x6f, 0x6b, 0x65, 0x6e, 0x0a, 0x20, 0x20, 0x23, 0x20, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x20, 0x6f, 0x63, 0x63, 0x75, 0x72, 0x69, 0x6e, 0x67, 0x20, 0x69, 0x6e, 0x20, 0x6c, 0x69, 0x66, 0x65, 0x74, 0x69, 0x6d, 0x65, 0x2d, 0x73, 0x74, 0x72, 0x69, 0x63, 0x74, 0x6e, 0x65, 0x73, - 0x73, 0x20, 0x66, 0x6c, 0x61, 0x67, 0x0a, 0x20, 0x20, 0x2d, 0x20, 0x26, - 0x6c, 0x69, 0x66, 0x65, 0x74, 0x69, 0x6d, 0x65, 0x2d, 0x73, 0x74, 0x72, - 0x69, 0x63, 0x74, 0x6e, 0x65, 0x73, 0x73, 0x2d, 0x76, 0x61, 0x6c, 0x75, - 0x65, 0x73, 0x20, 0x65, 0x6e, 0x75, 0x6d, 0x28, 0x27, 0x6f, 0x70, 0x74, - 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x27, 0x2c, 0x20, 0x27, 0x72, 0x65, 0x71, - 0x75, 0x69, 0x72, 0x65, 0x64, 0x27, 0x29, 0x0a, 0x20, 0x20, 0x23, 0x20, - 0x76, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x20, 0x6f, 0x63, 0x63, 0x75, 0x72, - 0x69, 0x6e, 0x67, 0x20, 0x69, 0x6e, 0x20, 0x6c, 0x69, 0x66, 0x65, 0x74, - 0x69, 0x6d, 0x65, 0x2d, 0x73, 0x74, 0x72, 0x69, 0x63, 0x74, 0x6e, 0x65, - 0x73, 0x73, 0x20, 0x66, 0x6c, 0x61, 0x67, 0x0a, 0x20, 0x20, 0x2d, 0x20, - 0x26, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x2d, 0x6d, 0x6f, 0x64, 0x65, - 0x2d, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x20, 0x65, 0x6e, 0x75, 0x6d, - 0x28, 0x27, 0x72, 0x77, 0x27, 0x2c, 0x20, 0x27, 0x72, 0x27, 0x29, 0x0a, - 0x0a, 0x23, 0x20, 0x75, 0x73, 0x65, 0x72, 0x2d, 0x64, 0x65, 0x66, 0x69, - 0x6e, 0x65, 0x64, 0x20, 0x74, 0x79, 0x70, 0x65, 0x73, 0x20, 0x75, 0x73, - 0x65, 0x64, 0x20, 0x69, 0x6e, 0x20, 0x74, 0x68, 0x69, 0x73, 0x20, 0x73, - 0x63, 0x68, 0x65, 0x6d, 0x61, 0x0a, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, - 0x2d, 0x74, 0x79, 0x70, 0x65, 0x73, 0x3a, 0x0a, 0x20, 0x20, 0x0a, 0x20, - 0x20, 0x2d, 0x20, 0x20, 0x74, 0x79, 0x70, 0x65, 0x6e, 0x61, 0x6d, 0x65, - 0x3a, 0x20, 0x6c, 0x69, 0x66, 0x65, 0x74, 0x69, 0x6d, 0x65, 0x2d, 0x69, - 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x0a, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x74, 0x79, 0x70, 0x65, 0x73, 0x70, 0x65, 0x63, 0x3a, 0x20, 0x6d, - 0x61, 0x70, 0x28, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x64, 0x6f, - 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x3a, - 0x20, 0x43, 0x44, 0x4f, 0x20, 0x6c, 0x69, 0x66, 0x65, 0x74, 0x69, 0x6d, - 0x65, 0x20, 0x74, 0x79, 0x70, 0x65, 0x0a, 0x0a, 0x20, 0x20, 0x2d, 0x20, + 0x73, 0x20, 0x66, 0x6c, 0x61, 0x67, 0x0a, 0x20, 0x20, 0x23, 0x20, 0x2d, + 0x20, 0x26, 0x6c, 0x69, 0x66, 0x65, 0x74, 0x69, 0x6d, 0x65, 0x2d, 0x73, + 0x74, 0x72, 0x69, 0x63, 0x74, 0x6e, 0x65, 0x73, 0x73, 0x2d, 0x76, 0x61, + 0x6c, 0x75, 0x65, 0x73, 0x20, 0x65, 0x6e, 0x75, 0x6d, 0x28, 0x27, 0x6f, + 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x27, 0x2c, 0x20, 0x27, 0x72, + 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x64, 0x27, 0x29, 0x0a, 0x20, 0x20, + 0x23, 0x20, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x20, 0x6f, 0x63, 0x63, + 0x75, 0x72, 0x69, 0x6e, 0x67, 0x20, 0x69, 0x6e, 0x20, 0x6c, 0x69, 0x66, + 0x65, 0x74, 0x69, 0x6d, 0x65, 0x2d, 0x73, 0x74, 0x72, 0x69, 0x63, 0x74, + 0x6e, 0x65, 0x73, 0x73, 0x20, 0x66, 0x6c, 0x61, 0x67, 0x0a, 0x20, 0x20, + 0x23, 0x2d, 0x20, 0x26, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x2d, 0x6d, + 0x6f, 0x64, 0x65, 0x2d, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x20, 0x65, + 0x6e, 0x75, 0x6d, 0x28, 0x27, 0x72, 0x77, 0x27, 0x2c, 0x20, 0x27, 0x72, + 0x27, 0x29, 0x0a, 0x0a, 0x23, 0x20, 0x75, 0x73, 0x65, 0x72, 0x2d, 0x64, + 0x65, 0x66, 0x69, 0x6e, 0x65, 0x64, 0x20, 0x74, 0x79, 0x70, 0x65, 0x73, + 0x20, 0x75, 0x73, 0x65, 0x64, 0x20, 0x69, 0x6e, 0x20, 0x74, 0x68, 0x69, + 0x73, 0x20, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x0a, 0x23, 0x73, 0x63, + 0x68, 0x65, 0x6d, 0x61, 0x2d, 0x74, 0x79, 0x70, 0x65, 0x73, 0x3a, 0x0a, + 0x20, 0x20, 0x0a, 0x20, 0x20, 0x23, 0x20, 0x2d, 0x20, 0x20, 0x74, 0x79, + 0x70, 0x65, 0x6e, 0x61, 0x6d, 0x65, 0x3a, 0x20, 0x6c, 0x69, 0x66, 0x65, + 0x74, 0x69, 0x6d, 0x65, 0x2d, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, + 0x6c, 0x0a, 0x20, 0x20, 0x23, 0x20, 0x20, 0x20, 0x20, 0x74, 0x79, 0x70, + 0x65, 0x73, 0x70, 0x65, 0x63, 0x3a, 0x20, 0x6d, 0x61, 0x70, 0x28, 0x29, + 0x0a, 0x20, 0x20, 0x23, 0x20, 0x20, 0x20, 0x20, 0x64, 0x6f, 0x63, 0x75, + 0x6d, 0x65, 0x6e, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x20, 0x43, + 0x44, 0x4f, 0x20, 0x6c, 0x69, 0x66, 0x65, 0x74, 0x69, 0x6d, 0x65, 0x20, + 0x74, 0x79, 0x70, 0x65, 0x0a, 0x0a, 0x20, 0x20, 0x23, 0x20, 0x2d, 0x20, 0x20, 0x74, 0x79, 0x70, 0x65, 0x6e, 0x61, 0x6d, 0x65, 0x3a, 0x20, 0x6c, 0x69, 0x66, 0x65, 0x74, 0x69, 0x6d, 0x65, 0x2d, 0x73, 0x74, 0x72, 0x69, - 0x63, 0x74, 0x6e, 0x65, 0x73, 0x73, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x74, 0x79, 0x70, 0x65, 0x73, 0x70, 0x65, 0x63, 0x3a, 0x20, 0x2a, 0x6c, - 0x69, 0x66, 0x65, 0x74, 0x69, 0x6d, 0x65, 0x2d, 0x73, 0x74, 0x72, 0x69, - 0x63, 0x74, 0x6e, 0x65, 0x73, 0x73, 0x2d, 0x76, 0x61, 0x6c, 0x75, 0x65, - 0x73, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x64, 0x6f, 0x63, 0x75, 0x6d, - 0x65, 0x6e, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x20, 0x43, 0x44, - 0x4f, 0x20, 0x6c, 0x69, 0x66, 0x65, 0x74, 0x69, 0x6d, 0x65, 0x20, 0x73, - 0x70, 0x65, 0x63, 0x69, 0x66, 0x69, 0x65, 0x72, 0x20, 0x69, 0x6e, 0x74, - 0x65, 0x72, 0x70, 0x72, 0x65, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x0a, - 0x0a, 0x20, 0x20, 0x2d, 0x20, 0x20, 0x74, 0x79, 0x70, 0x65, 0x6e, 0x61, - 0x6d, 0x65, 0x3a, 0x20, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x2d, 0x6d, - 0x6f, 0x64, 0x65, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x74, 0x79, 0x70, - 0x65, 0x73, 0x70, 0x65, 0x63, 0x3a, 0x20, 0x2a, 0x61, 0x63, 0x63, 0x65, - 0x73, 0x73, 0x2d, 0x6d, 0x6f, 0x64, 0x65, 0x2d, 0x76, 0x61, 0x6c, 0x75, - 0x65, 0x73, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x64, 0x6f, 0x63, 0x75, - 0x6d, 0x65, 0x6e, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x20, 0x43, - 0x44, 0x4f, 0x20, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x20, 0x6d, 0x6f, - 0x64, 0x65, 0x0a, 0x0a, 0x23, 0x20, 0x49, 0x6e, 0x64, 0x69, 0x76, 0x69, - 0x64, 0x75, 0x61, 0x6c, 0x20, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, - 0x74, 0x65, 0x20, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, - 0x6f, 0x6e, 0x73, 0x0a, 0x6d, 0x61, 0x65, 0x73, 0x74, 0x72, 0x6f, 0x2d, - 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x3a, 0x0a, - 0x20, 0x20, 0x23, 0x23, 0x20, 0x54, 0x4f, 0x50, 0x4c, 0x45, 0x56, 0x45, - 0x4c, 0x20, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, - 0x0a, 0x0a, 0x20, 0x20, 0x2d, 0x20, 0x6b, 0x65, 0x79, 0x3a, 0x20, 0x22, - 0x2e, 0x6d, 0x61, 0x65, 0x73, 0x74, 0x72, 0x6f, 0x2e, 0x63, 0x6f, 0x72, - 0x65, 0x2e, 0x63, 0x64, 0x6f, 0x2e, 0x6e, 0x61, 0x6d, 0x65, 0x22, 0x20, - 0x23, 0x20, 0x6e, 0x6f, 0x74, 0x65, 0x3a, 0x20, 0x74, 0x68, 0x69, 0x73, - 0x20, 0x69, 0x73, 0x20, 0x61, 0x6e, 0x20, 0x61, 0x62, 0x73, 0x6f, 0x6c, - 0x75, 0x74, 0x65, 0x20, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, - 0x65, 0x20, 0x6e, 0x61, 0x6d, 0x65, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x74, - 0x79, 0x70, 0x65, 0x3a, 0x20, 0x73, 0x74, 0x72, 0x28, 0x29, 0x0a, 0x20, - 0x20, 0x20, 0x20, 0x72, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x64, 0x3a, - 0x20, 0x54, 0x72, 0x75, 0x65, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x64, 0x6f, - 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x3a, - 0x20, 0x54, 0x68, 0x65, 0x20, 0x75, 0x6e, 0x69, 0x71, 0x75, 0x65, 0x20, - 0x6e, 0x61, 0x6d, 0x65, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, - 0x43, 0x44, 0x4f, 0x0a, 0x0a, 0x20, 0x20, 0x23, 0x20, 0x6e, 0x6f, 0x74, - 0x65, 0x3a, 0x20, 0x74, 0x68, 0x65, 0x20, 0x49, 0x44, 0x20, 0x69, 0x73, - 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x75, 0x73, 0x65, 0x72, 0x2d, 0x76, 0x69, - 0x73, 0x69, 0x62, 0x6c, 0x65, 0x3b, 0x20, 0x69, 0x74, 0x27, 0x73, 0x20, - 0x73, 0x79, 0x6e, 0x74, 0x68, 0x65, 0x74, 0x69, 0x7a, 0x65, 0x64, 0x20, - 0x64, 0x75, 0x72, 0x69, 0x6e, 0x67, 0x20, 0x61, 0x20, 0x77, 0x6f, 0x72, - 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x0a, 0x0a, 0x20, 0x20, 0x2d, 0x20, 0x6b, - 0x65, 0x79, 0x3a, 0x20, 0x22, 0x63, 0x64, 0x6f, 0x2e, 0x61, 0x6c, 0x6c, - 0x6f, 0x63, 0x61, 0x74, 0x65, 0x2d, 0x6e, 0x6f, 0x77, 0x22, 0x20, 0x23, - 0x20, 0x6e, 0x6f, 0x74, 0x65, 0x3a, 0x20, 0x74, 0x68, 0x69, 0x73, 0x20, - 0x69, 0x73, 0x20, 0x61, 0x20, 0x72, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x76, + 0x63, 0x74, 0x6e, 0x65, 0x73, 0x73, 0x0a, 0x20, 0x20, 0x23, 0x20, 0x20, + 0x20, 0x20, 0x74, 0x79, 0x70, 0x65, 0x73, 0x70, 0x65, 0x63, 0x3a, 0x20, + 0x2a, 0x6c, 0x69, 0x66, 0x65, 0x74, 0x69, 0x6d, 0x65, 0x2d, 0x73, 0x74, + 0x72, 0x69, 0x63, 0x74, 0x6e, 0x65, 0x73, 0x73, 0x2d, 0x76, 0x61, 0x6c, + 0x75, 0x65, 0x73, 0x0a, 0x20, 0x20, 0x23, 0x20, 0x20, 0x20, 0x20, 0x64, + 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x3a, 0x20, 0x43, 0x44, 0x4f, 0x20, 0x6c, 0x69, 0x66, 0x65, 0x74, 0x69, + 0x6d, 0x65, 0x20, 0x73, 0x70, 0x65, 0x63, 0x69, 0x66, 0x69, 0x65, 0x72, + 0x20, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x70, 0x72, 0x65, 0x74, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x0a, 0x0a, 0x20, 0x20, 0x23, 0x20, 0x2d, 0x20, 0x20, + 0x74, 0x79, 0x70, 0x65, 0x6e, 0x61, 0x6d, 0x65, 0x3a, 0x20, 0x61, 0x63, + 0x63, 0x65, 0x73, 0x73, 0x2d, 0x6d, 0x6f, 0x64, 0x65, 0x0a, 0x20, 0x20, + 0x23, 0x20, 0x20, 0x20, 0x20, 0x74, 0x79, 0x70, 0x65, 0x73, 0x70, 0x65, + 0x63, 0x3a, 0x20, 0x2a, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x2d, 0x6d, + 0x6f, 0x64, 0x65, 0x2d, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x0a, 0x20, + 0x20, 0x23, 0x20, 0x20, 0x20, 0x20, 0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65, + 0x6e, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x20, 0x43, 0x44, 0x4f, + 0x20, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x20, 0x6d, 0x6f, 0x64, 0x65, + 0x0a, 0x0a, 0x23, 0x20, 0x49, 0x6e, 0x64, 0x69, 0x76, 0x69, 0x64, 0x75, + 0x61, 0x6c, 0x20, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, + 0x20, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, + 0x73, 0x0a, 0x6d, 0x61, 0x65, 0x73, 0x74, 0x72, 0x6f, 0x2d, 0x61, 0x74, + 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x3a, 0x0a, 0x20, 0x20, + 0x23, 0x23, 0x20, 0x54, 0x4f, 0x50, 0x4c, 0x45, 0x56, 0x45, 0x4c, 0x20, + 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x0a, 0x0a, + 0x20, 0x20, 0x2d, 0x20, 0x6b, 0x65, 0x79, 0x3a, 0x20, 0x22, 0x2e, 0x6d, + 0x61, 0x65, 0x73, 0x74, 0x72, 0x6f, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, + 0x63, 0x64, 0x6f, 0x2e, 0x6e, 0x61, 0x6d, 0x65, 0x22, 0x20, 0x23, 0x20, + 0x6e, 0x6f, 0x74, 0x65, 0x3a, 0x20, 0x74, 0x68, 0x69, 0x73, 0x20, 0x69, + 0x73, 0x20, 0x61, 0x6e, 0x20, 0x61, 0x62, 0x73, 0x6f, 0x6c, 0x75, 0x74, 0x65, 0x20, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x20, 0x6e, 0x61, 0x6d, 0x65, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x74, 0x79, 0x70, - 0x65, 0x3a, 0x20, 0x62, 0x6f, 0x6f, 0x6c, 0x28, 0x29, 0x0a, 0x20, 0x20, - 0x20, 0x20, 0x72, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x64, 0x3a, 0x20, - 0x46, 0x61, 0x6c, 0x73, 0x65, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x64, 0x65, - 0x66, 0x61, 0x75, 0x6c, 0x74, 0x3a, 0x20, 0x46, 0x61, 0x6c, 0x73, 0x65, - 0x0a, 0x20, 0x20, 0x20, 0x20, 0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, - 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x20, 0x50, 0x65, 0x72, 0x66, - 0x6f, 0x72, 0x6d, 0x20, 0x69, 0x6d, 0x6d, 0x65, 0x64, 0x69, 0x61, 0x74, - 0x65, 0x20, 0x61, 0x6c, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, - 0x20, 0x66, 0x6f, 0x72, 0x20, 0x74, 0x68, 0x65, 0x20, 0x43, 0x44, 0x4f, - 0x0a, 0x0a, 0x20, 0x20, 0x2d, 0x20, 0x6b, 0x65, 0x79, 0x3a, 0x20, 0x22, - 0x63, 0x64, 0x6f, 0x2e, 0x70, 0x65, 0x72, 0x73, 0x69, 0x73, 0x74, 0x22, - 0x0a, 0x20, 0x20, 0x20, 0x20, 0x74, 0x79, 0x70, 0x65, 0x3a, 0x20, 0x62, - 0x6f, 0x6f, 0x6c, 0x28, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, - 0x71, 0x75, 0x69, 0x72, 0x65, 0x64, 0x3a, 0x20, 0x46, 0x61, 0x6c, 0x73, - 0x65, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, - 0x74, 0x3a, 0x20, 0x46, 0x61, 0x6c, 0x73, 0x65, 0x0a, 0x20, 0x20, 0x20, - 0x20, 0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x61, 0x74, 0x69, - 0x6f, 0x6e, 0x3a, 0x20, 0x45, 0x6e, 0x73, 0x75, 0x72, 0x65, 0x20, 0x61, - 0x20, 0x70, 0x65, 0x72, 0x73, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x74, 0x20, + 0x65, 0x3a, 0x20, 0x73, 0x74, 0x72, 0x28, 0x29, 0x0a, 0x20, 0x20, 0x20, + 0x20, 0x72, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x64, 0x3a, 0x20, 0x54, + 0x72, 0x75, 0x65, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x64, 0x6f, 0x63, 0x75, + 0x6d, 0x65, 0x6e, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x20, 0x54, + 0x68, 0x65, 0x20, 0x75, 0x6e, 0x69, 0x71, 0x75, 0x65, 0x20, 0x6e, 0x61, + 0x6d, 0x65, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x43, 0x44, + 0x4f, 0x0a, 0x0a, 0x20, 0x20, 0x23, 0x20, 0x6e, 0x6f, 0x74, 0x65, 0x3a, + 0x20, 0x74, 0x68, 0x65, 0x20, 0x49, 0x44, 0x20, 0x69, 0x73, 0x20, 0x6e, + 0x6f, 0x74, 0x20, 0x75, 0x73, 0x65, 0x72, 0x2d, 0x76, 0x69, 0x73, 0x69, + 0x62, 0x6c, 0x65, 0x3b, 0x20, 0x69, 0x74, 0x27, 0x73, 0x20, 0x73, 0x79, + 0x6e, 0x74, 0x68, 0x65, 0x74, 0x69, 0x7a, 0x65, 0x64, 0x20, 0x64, 0x75, + 0x72, 0x69, 0x6e, 0x67, 0x20, 0x61, 0x20, 0x77, 0x6f, 0x72, 0x6b, 0x66, + 0x6c, 0x6f, 0x77, 0x0a, 0x0a, 0x20, 0x20, 0x2d, 0x20, 0x6b, 0x65, 0x79, + 0x3a, 0x20, 0x22, 0x63, 0x64, 0x6f, 0x2e, 0x61, 0x6c, 0x6c, 0x6f, 0x63, + 0x61, 0x74, 0x65, 0x2d, 0x6e, 0x6f, 0x77, 0x22, 0x20, 0x23, 0x20, 0x6e, + 0x6f, 0x74, 0x65, 0x3a, 0x20, 0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, + 0x20, 0x61, 0x20, 0x72, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x76, 0x65, 0x20, + 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x20, 0x6e, 0x61, + 0x6d, 0x65, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x74, 0x79, 0x70, 0x65, 0x3a, + 0x20, 0x62, 0x6f, 0x6f, 0x6c, 0x28, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, + 0x72, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x64, 0x3a, 0x20, 0x46, 0x61, + 0x6c, 0x73, 0x65, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x64, 0x65, 0x66, 0x61, + 0x75, 0x6c, 0x74, 0x3a, 0x20, 0x46, 0x61, 0x6c, 0x73, 0x65, 0x0a, 0x20, + 0x20, 0x20, 0x20, 0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x20, 0x50, 0x65, 0x72, 0x66, 0x6f, 0x72, + 0x6d, 0x20, 0x69, 0x6d, 0x6d, 0x65, 0x64, 0x69, 0x61, 0x74, 0x65, 0x20, + 0x61, 0x6c, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x66, + 0x6f, 0x72, 0x20, 0x74, 0x68, 0x65, 0x20, 0x43, 0x44, 0x4f, 0x0a, 0x0a, + 0x20, 0x20, 0x2d, 0x20, 0x6b, 0x65, 0x79, 0x3a, 0x20, 0x22, 0x63, 0x64, + 0x6f, 0x2e, 0x70, 0x65, 0x72, 0x73, 0x69, 0x73, 0x74, 0x22, 0x0a, 0x20, + 0x20, 0x20, 0x20, 0x74, 0x79, 0x70, 0x65, 0x3a, 0x20, 0x62, 0x6f, 0x6f, + 0x6c, 0x28, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x71, 0x75, + 0x69, 0x72, 0x65, 0x64, 0x3a, 0x20, 0x46, 0x61, 0x6c, 0x73, 0x65, 0x0a, + 0x20, 0x20, 0x20, 0x20, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x3a, + 0x20, 0x46, 0x61, 0x6c, 0x73, 0x65, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x64, + 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x3a, 0x20, 0x45, 0x6e, 0x73, 0x75, 0x72, 0x65, 0x20, 0x61, 0x20, 0x70, + 0x65, 0x72, 0x73, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x74, 0x20, 0x63, 0x6f, + 0x70, 0x79, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x43, 0x44, + 0x4f, 0x20, 0x69, 0x73, 0x20, 0x70, 0x72, 0x65, 0x73, 0x65, 0x72, 0x76, + 0x65, 0x64, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x77, 0x68, + 0x65, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6c, 0x61, 0x73, 0x74, 0x20, 0x63, 0x6f, 0x70, 0x79, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, - 0x43, 0x44, 0x4f, 0x20, 0x69, 0x73, 0x20, 0x70, 0x72, 0x65, 0x73, 0x65, - 0x72, 0x76, 0x65, 0x64, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x77, 0x68, 0x65, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6c, 0x61, 0x73, - 0x74, 0x20, 0x63, 0x6f, 0x70, 0x79, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, - 0x65, 0x20, 0x43, 0x44, 0x4f, 0x20, 0x69, 0x73, 0x20, 0x57, 0x49, 0x54, - 0x48, 0x44, 0x52, 0x41, 0x57, 0x4e, 0x20, 0x66, 0x72, 0x6f, 0x6d, 0x20, - 0x74, 0x68, 0x65, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x70, - 0x6f, 0x6f, 0x6c, 0x2e, 0x20, 0x28, 0x4e, 0x6f, 0x74, 0x65, 0x20, 0x74, - 0x68, 0x65, 0x20, 0x6e, 0x6f, 0x6e, 0x2d, 0x74, 0x72, 0x69, 0x76, 0x69, - 0x61, 0x6c, 0x20, 0x73, 0x65, 0x6d, 0x61, 0x6e, 0x74, 0x69, 0x63, 0x20, - 0x69, 0x6e, 0x74, 0x65, 0x72, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x0a, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, - 0x74, 0x68, 0x65, 0x20, 0x63, 0x64, 0x6f, 0x2e, 0x64, 0x65, 0x73, 0x69, - 0x73, 0x74, 0x20, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, - 0x2e, 0x29, 0x0a, 0x0a, 0x20, 0x20, 0x2d, 0x20, 0x6b, 0x65, 0x79, 0x3a, - 0x20, 0x22, 0x63, 0x64, 0x6f, 0x2e, 0x64, 0x65, 0x73, 0x69, 0x73, 0x74, - 0x22, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x74, 0x79, 0x70, 0x65, 0x3a, 0x20, - 0x62, 0x6f, 0x6f, 0x6c, 0x28, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x72, - 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x64, 0x3a, 0x20, 0x46, 0x61, 0x6c, - 0x73, 0x65, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x64, 0x65, 0x66, 0x61, 0x75, - 0x6c, 0x74, 0x3a, 0x20, 0x54, 0x72, 0x75, 0x65, 0x0a, 0x20, 0x20, 0x20, - 0x20, 0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x61, 0x74, 0x69, - 0x6f, 0x6e, 0x3a, 0x20, 0x45, 0x6e, 0x73, 0x75, 0x72, 0x65, 0x20, 0x74, - 0x68, 0x61, 0x74, 0x20, 0x61, 0x6c, 0x6c, 0x20, 0x70, 0x65, 0x72, 0x73, - 0x69, 0x73, 0x74, 0x65, 0x6e, 0x74, 0x20, 0x63, 0x6f, 0x70, 0x69, 0x65, - 0x73, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x43, 0x44, 0x4f, - 0x20, 0x61, 0x72, 0x65, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x43, 0x44, 0x4f, 0x20, 0x69, 0x73, 0x20, 0x57, 0x49, 0x54, 0x48, 0x44, + 0x52, 0x41, 0x57, 0x4e, 0x20, 0x66, 0x72, 0x6f, 0x6d, 0x20, 0x74, 0x68, + 0x65, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x70, 0x6f, 0x6f, + 0x6c, 0x2e, 0x20, 0x28, 0x4e, 0x6f, 0x74, 0x65, 0x20, 0x74, 0x68, 0x65, + 0x20, 0x6e, 0x6f, 0x6e, 0x2d, 0x74, 0x72, 0x69, 0x76, 0x69, 0x61, 0x6c, + 0x20, 0x73, 0x65, 0x6d, 0x61, 0x6e, 0x74, 0x69, 0x63, 0x20, 0x69, 0x6e, + 0x74, 0x65, 0x72, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x72, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x64, 0x20, 0x66, 0x72, 0x6f, 0x6d, - 0x20, 0x70, 0x65, 0x72, 0x73, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x74, 0x20, - 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x20, 0x77, 0x68, 0x65, 0x6e, - 0x20, 0x74, 0x68, 0x65, 0x20, 0x6c, 0x61, 0x73, 0x74, 0x0a, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x74, 0x68, + 0x65, 0x20, 0x63, 0x64, 0x6f, 0x2e, 0x64, 0x65, 0x73, 0x69, 0x73, 0x74, + 0x20, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x2e, 0x29, + 0x0a, 0x0a, 0x20, 0x20, 0x2d, 0x20, 0x6b, 0x65, 0x79, 0x3a, 0x20, 0x22, + 0x63, 0x64, 0x6f, 0x2e, 0x64, 0x65, 0x73, 0x69, 0x73, 0x74, 0x22, 0x0a, + 0x20, 0x20, 0x20, 0x20, 0x74, 0x79, 0x70, 0x65, 0x3a, 0x20, 0x62, 0x6f, + 0x6f, 0x6c, 0x28, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x71, + 0x75, 0x69, 0x72, 0x65, 0x64, 0x3a, 0x20, 0x46, 0x61, 0x6c, 0x73, 0x65, + 0x0a, 0x20, 0x20, 0x20, 0x20, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, + 0x3a, 0x20, 0x54, 0x72, 0x75, 0x65, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x64, + 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x3a, 0x20, 0x45, 0x6e, 0x73, 0x75, 0x72, 0x65, 0x20, 0x74, 0x68, 0x61, + 0x74, 0x20, 0x61, 0x6c, 0x6c, 0x20, 0x70, 0x65, 0x72, 0x73, 0x69, 0x73, + 0x74, 0x65, 0x6e, 0x74, 0x20, 0x63, 0x6f, 0x70, 0x69, 0x65, 0x73, 0x20, + 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x43, 0x44, 0x4f, 0x20, 0x61, + 0x72, 0x65, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, + 0x6d, 0x6f, 0x76, 0x65, 0x64, 0x20, 0x66, 0x72, 0x6f, 0x6d, 0x20, 0x70, + 0x65, 0x72, 0x73, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x74, 0x20, 0x73, 0x74, + 0x6f, 0x72, 0x61, 0x67, 0x65, 0x20, 0x77, 0x68, 0x65, 0x6e, 0x20, 0x74, + 0x68, 0x65, 0x20, 0x6c, 0x61, 0x73, 0x74, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, - 0x63, 0x65, 0x20, 0x74, 0x6f, 0x20, 0x74, 0x68, 0x65, 0x20, 0x43, 0x44, - 0x4f, 0x20, 0x69, 0x73, 0x20, 0x57, 0x49, 0x54, 0x48, 0x44, 0x52, 0x41, - 0x57, 0x6e, 0x20, 0x66, 0x72, 0x6f, 0x6d, 0x20, 0x74, 0x68, 0x65, 0x0a, + 0x20, 0x20, 0x20, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, + 0x20, 0x74, 0x6f, 0x20, 0x74, 0x68, 0x65, 0x20, 0x43, 0x44, 0x4f, 0x20, + 0x69, 0x73, 0x20, 0x57, 0x49, 0x54, 0x48, 0x44, 0x52, 0x41, 0x57, 0x6e, + 0x20, 0x66, 0x72, 0x6f, 0x6d, 0x20, 0x74, 0x68, 0x65, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x70, 0x6f, 0x6f, 0x6c, 0x2e, - 0x20, 0x28, 0x4e, 0x6f, 0x74, 0x65, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6e, - 0x6f, 0x6e, 0x2d, 0x74, 0x72, 0x69, 0x76, 0x69, 0x61, 0x6c, 0x20, 0x73, - 0x65, 0x6d, 0x61, 0x6e, 0x74, 0x69, 0x63, 0x20, 0x69, 0x6e, 0x74, 0x65, - 0x72, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x0a, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x70, 0x6f, 0x6f, 0x6c, 0x2e, 0x20, 0x28, + 0x4e, 0x6f, 0x74, 0x65, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6e, 0x6f, 0x6e, + 0x2d, 0x74, 0x72, 0x69, 0x76, 0x69, 0x61, 0x6c, 0x20, 0x73, 0x65, 0x6d, + 0x61, 0x6e, 0x74, 0x69, 0x63, 0x20, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x61, + 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x74, 0x68, 0x65, 0x20, - 0x63, 0x64, 0x6f, 0x2e, 0x64, 0x65, 0x73, 0x69, 0x73, 0x74, 0x20, 0x61, - 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x2e, 0x29, 0x0a, 0x0a, - 0x20, 0x20, 0x2d, 0x20, 0x6b, 0x65, 0x79, 0x3a, 0x20, 0x22, 0x63, 0x64, - 0x6f, 0x2e, 0x6d, 0x61, 0x65, 0x73, 0x74, 0x72, 0x6f, 0x2d, 0x70, 0x72, - 0x6f, 0x76, 0x69, 0x64, 0x65, 0x64, 0x2d, 0x73, 0x74, 0x6f, 0x72, 0x61, - 0x67, 0x65, 0x22, 0x20, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x74, 0x79, 0x70, - 0x65, 0x3a, 0x20, 0x62, 0x6f, 0x6f, 0x6c, 0x28, 0x29, 0x0a, 0x20, 0x20, - 0x20, 0x20, 0x72, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x64, 0x3a, 0x20, - 0x46, 0x61, 0x6c, 0x73, 0x65, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x64, 0x65, - 0x66, 0x61, 0x75, 0x6c, 0x74, 0x3a, 0x20, 0x46, 0x61, 0x6c, 0x73, 0x65, - 0x0a, 0x20, 0x20, 0x20, 0x20, 0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, - 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x20, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x2f, 0x61, 0x64, 0x76, 0x69, 0x73, 0x65, 0x20, 0x6d, - 0x61, 0x65, 0x73, 0x74, 0x72, 0x6f, 0x20, 0x73, 0x74, 0x6f, 0x72, 0x61, - 0x67, 0x65, 0x20, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, - 0x74, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x74, 0x68, 0x65, 0x0a, 0x20, 0x20, + 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x64, + 0x6f, 0x2e, 0x64, 0x65, 0x73, 0x69, 0x73, 0x74, 0x20, 0x61, 0x74, 0x74, + 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x2e, 0x29, 0x0a, 0x0a, 0x20, 0x20, + 0x2d, 0x20, 0x6b, 0x65, 0x79, 0x3a, 0x20, 0x22, 0x63, 0x64, 0x6f, 0x2e, + 0x6d, 0x61, 0x65, 0x73, 0x74, 0x72, 0x6f, 0x2d, 0x70, 0x72, 0x6f, 0x76, + 0x69, 0x64, 0x65, 0x64, 0x2d, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, + 0x22, 0x20, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x74, 0x79, 0x70, 0x65, 0x3a, + 0x20, 0x62, 0x6f, 0x6f, 0x6c, 0x28, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, + 0x72, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x64, 0x3a, 0x20, 0x46, 0x61, + 0x6c, 0x73, 0x65, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x64, 0x65, 0x66, 0x61, + 0x75, 0x6c, 0x74, 0x3a, 0x20, 0x46, 0x61, 0x6c, 0x73, 0x65, 0x0a, 0x20, + 0x20, 0x20, 0x20, 0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x20, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x2f, 0x61, 0x64, 0x76, 0x69, 0x73, 0x65, 0x20, 0x6d, 0x61, 0x65, + 0x73, 0x74, 0x72, 0x6f, 0x20, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, + 0x20, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x20, + 0x66, 0x6f, 0x72, 0x20, 0x74, 0x68, 0x65, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x43, 0x44, 0x4f, 0x20, 0x28, 0x6e, 0x6f, - 0x20, 0x52, 0x41, 0x57, 0x2d, 0x50, 0x54, 0x52, 0x20, 0x77, 0x69, 0x6c, - 0x6c, 0x20, 0x62, 0x65, 0x20, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, - 0x64, 0x20, 0x6f, 0x72, 0x20, 0x63, 0x61, 0x6e, 0x20, 0x62, 0x65, 0x20, - 0x6f, 0x62, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x64, 0x29, 0x0a, 0x0a, 0x20, + 0x20, 0x20, 0x20, 0x43, 0x44, 0x4f, 0x20, 0x28, 0x6e, 0x6f, 0x20, 0x52, + 0x41, 0x57, 0x2d, 0x50, 0x54, 0x52, 0x20, 0x77, 0x69, 0x6c, 0x6c, 0x20, + 0x62, 0x65, 0x20, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x64, 0x20, + 0x6f, 0x72, 0x20, 0x63, 0x61, 0x6e, 0x20, 0x62, 0x65, 0x20, 0x6f, 0x62, + 0x74, 0x61, 0x69, 0x6e, 0x65, 0x64, 0x29, 0x0a, 0x0a, 0x20, 0x20, 0x23, 0x20, 0x2d, 0x20, 0x6b, 0x65, 0x79, 0x3a, 0x20, 0x22, 0x63, 0x64, 0x6f, 0x2e, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x2d, 0x6d, 0x6f, 0x64, 0x65, - 0x22, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x74, 0x79, 0x70, 0x65, 0x3a, 0x20, - 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x2d, 0x6d, 0x6f, 0x64, 0x65, 0x0a, - 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x64, - 0x3a, 0x20, 0x46, 0x61, 0x6c, 0x73, 0x65, 0x0a, 0x20, 0x20, 0x20, 0x20, - 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x3a, 0x20, 0x2a, 0x61, 0x63, - 0x63, 0x65, 0x73, 0x73, 0x2d, 0x6d, 0x6f, 0x64, 0x65, 0x2d, 0x76, 0x61, - 0x6c, 0x75, 0x65, 0x73, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x64, 0x6f, 0x63, - 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x20, - 0x49, 0x6e, 0x64, 0x69, 0x63, 0x61, 0x74, 0x65, 0x73, 0x20, 0x68, 0x6f, - 0x77, 0x20, 0x74, 0x68, 0x65, 0x20, 0x43, 0x44, 0x4f, 0x20, 0x77, 0x69, - 0x6c, 0x6c, 0x20, 0x62, 0x65, 0x20, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, - 0x65, 0x64, 0x20, 0x62, 0x79, 0x20, 0x74, 0x68, 0x65, 0x20, 0x75, 0x73, - 0x65, 0x72, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x28, 0x72, - 0x65, 0x61, 0x64, 0x2d, 0x77, 0x72, 0x69, 0x74, 0x65, 0x2c, 0x20, 0x72, - 0x65, 0x61, 0x64, 0x2d, 0x6f, 0x6e, 0x6c, 0x79, 0x2c, 0x20, 0x65, 0x74, - 0x63, 0x2e, 0x29, 0x2e, 0x0a, 0x0a, 0x20, 0x20, 0x2d, 0x20, 0x6b, 0x65, - 0x79, 0x3a, 0x20, 0x22, 0x63, 0x64, 0x6f, 0x2e, 0x74, 0x72, 0x61, 0x6e, - 0x73, 0x66, 0x65, 0x72, 0x2d, 0x61, 0x73, 0x61, 0x70, 0x22, 0x0a, 0x20, - 0x20, 0x20, 0x20, 0x74, 0x79, 0x70, 0x65, 0x3a, 0x20, 0x62, 0x6f, 0x6f, - 0x6c, 0x28, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x71, 0x75, + 0x22, 0x0a, 0x20, 0x20, 0x23, 0x20, 0x20, 0x20, 0x74, 0x79, 0x70, 0x65, + 0x3a, 0x20, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x2d, 0x6d, 0x6f, 0x64, + 0x65, 0x0a, 0x20, 0x20, 0x23, 0x20, 0x20, 0x20, 0x72, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x64, 0x3a, 0x20, 0x46, 0x61, 0x6c, 0x73, 0x65, 0x0a, - 0x20, 0x20, 0x20, 0x20, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x3a, - 0x20, 0x46, 0x61, 0x6c, 0x73, 0x65, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x64, - 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, - 0x3a, 0x20, 0x49, 0x6e, 0x64, 0x69, 0x63, 0x61, 0x74, 0x65, 0x73, 0x20, - 0x74, 0x68, 0x61, 0x74, 0x20, 0x74, 0x68, 0x65, 0x20, 0x43, 0x44, 0x4f, - 0x20, 0x6d, 0x75, 0x73, 0x74, 0x20, 0x62, 0x65, 0x20, 0x74, 0x72, 0x61, - 0x6e, 0x73, 0x66, 0x65, 0x72, 0x65, 0x64, 0x20, 0x61, 0x73, 0x20, 0x73, - 0x6f, 0x6f, 0x6e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x61, - 0x73, 0x20, 0x70, 0x6f, 0x73, 0x73, 0x69, 0x62, 0x6c, 0x65, 0x2e, 0x0a, - 0x0a, 0x20, 0x20, 0x2d, 0x20, 0x6b, 0x65, 0x79, 0x3a, 0x20, 0x22, 0x63, - 0x64, 0x6f, 0x2e, 0x6e, 0x65, 0x76, 0x65, 0x72, 0x2d, 0x70, 0x6f, 0x6f, - 0x6c, 0x65, 0x64, 0x22, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x74, 0x79, 0x70, - 0x65, 0x3a, 0x20, 0x62, 0x6f, 0x6f, 0x6c, 0x28, 0x29, 0x0a, 0x20, 0x20, - 0x20, 0x20, 0x72, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x64, 0x3a, 0x20, - 0x46, 0x61, 0x6c, 0x73, 0x65, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x64, 0x65, - 0x66, 0x61, 0x75, 0x6c, 0x74, 0x3a, 0x20, 0x46, 0x61, 0x6c, 0x73, 0x65, - 0x0a, 0x20, 0x20, 0x20, 0x20, 0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, + 0x20, 0x20, 0x23, 0x20, 0x20, 0x20, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, + 0x74, 0x3a, 0x20, 0x2a, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x2d, 0x6d, + 0x6f, 0x64, 0x65, 0x2d, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x0a, 0x20, + 0x20, 0x23, 0x20, 0x20, 0x20, 0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x20, 0x49, 0x6e, 0x64, 0x69, - 0x63, 0x61, 0x74, 0x65, 0x73, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x74, - 0x68, 0x65, 0x20, 0x43, 0x44, 0x4f, 0x20, 0x77, 0x69, 0x6c, 0x6c, 0x20, - 0x62, 0x65, 0x20, 0x6e, 0x65, 0x76, 0x65, 0x72, 0x20, 0x62, 0x65, 0x20, - 0x75, 0x73, 0x65, 0x64, 0x20, 0x69, 0x6e, 0x0a, 0x20, 0x20, 0x20, 0x20, + 0x63, 0x61, 0x74, 0x65, 0x73, 0x20, 0x68, 0x6f, 0x77, 0x20, 0x74, 0x68, + 0x65, 0x20, 0x43, 0x44, 0x4f, 0x20, 0x77, 0x69, 0x6c, 0x6c, 0x20, 0x62, + 0x65, 0x20, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x65, 0x64, 0x20, 0x62, + 0x79, 0x20, 0x74, 0x68, 0x65, 0x20, 0x75, 0x73, 0x65, 0x72, 0x0a, 0x20, + 0x20, 0x23, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x28, 0x72, 0x65, 0x61, + 0x64, 0x2d, 0x77, 0x72, 0x69, 0x74, 0x65, 0x2c, 0x20, 0x72, 0x65, 0x61, + 0x64, 0x2d, 0x6f, 0x6e, 0x6c, 0x79, 0x2c, 0x20, 0x65, 0x74, 0x63, 0x2e, + 0x29, 0x2e, 0x0a, 0x0a, 0x20, 0x20, 0x2d, 0x20, 0x6b, 0x65, 0x79, 0x3a, + 0x20, 0x22, 0x63, 0x64, 0x6f, 0x2e, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x66, + 0x65, 0x72, 0x2d, 0x61, 0x73, 0x61, 0x70, 0x22, 0x0a, 0x20, 0x20, 0x20, + 0x20, 0x74, 0x79, 0x70, 0x65, 0x3a, 0x20, 0x62, 0x6f, 0x6f, 0x6c, 0x28, + 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x71, 0x75, 0x69, 0x72, + 0x65, 0x64, 0x3a, 0x20, 0x46, 0x61, 0x6c, 0x73, 0x65, 0x0a, 0x20, 0x20, + 0x20, 0x20, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x3a, 0x20, 0x46, + 0x61, 0x6c, 0x73, 0x65, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x64, 0x6f, 0x63, + 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x20, + 0x49, 0x6e, 0x64, 0x69, 0x63, 0x61, 0x74, 0x65, 0x73, 0x20, 0x74, 0x68, + 0x61, 0x74, 0x20, 0x74, 0x68, 0x65, 0x20, 0x43, 0x44, 0x4f, 0x20, 0x6d, + 0x75, 0x73, 0x74, 0x20, 0x62, 0x65, 0x20, 0x74, 0x72, 0x61, 0x6e, 0x73, + 0x66, 0x65, 0x72, 0x65, 0x64, 0x20, 0x61, 0x73, 0x20, 0x73, 0x6f, 0x6f, + 0x6e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x61, 0x73, 0x20, + 0x70, 0x6f, 0x73, 0x73, 0x69, 0x62, 0x6c, 0x65, 0x2e, 0x0a, 0x0a, 0x20, + 0x20, 0x2d, 0x20, 0x6b, 0x65, 0x79, 0x3a, 0x20, 0x22, 0x63, 0x64, 0x6f, + 0x2e, 0x6e, 0x65, 0x76, 0x65, 0x72, 0x2d, 0x70, 0x6f, 0x6f, 0x6c, 0x65, + 0x64, 0x22, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x74, 0x79, 0x70, 0x65, 0x3a, + 0x20, 0x62, 0x6f, 0x6f, 0x6c, 0x28, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, + 0x72, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x64, 0x3a, 0x20, 0x46, 0x61, + 0x6c, 0x73, 0x65, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x64, 0x65, 0x66, 0x61, + 0x75, 0x6c, 0x74, 0x3a, 0x20, 0x46, 0x61, 0x6c, 0x73, 0x65, 0x0a, 0x20, + 0x20, 0x20, 0x20, 0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x20, 0x49, 0x6e, 0x64, 0x69, 0x63, 0x61, + 0x74, 0x65, 0x73, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x74, 0x68, 0x65, + 0x20, 0x43, 0x44, 0x4f, 0x20, 0x77, 0x69, 0x6c, 0x6c, 0x20, 0x62, 0x65, + 0x20, 0x6e, 0x65, 0x76, 0x65, 0x72, 0x20, 0x62, 0x65, 0x20, 0x75, 0x73, + 0x65, 0x64, 0x20, 0x69, 0x6e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x4f, 0x46, 0x46, 0x45, 0x52, 0x2f, 0x44, 0x45, 0x4d, - 0x41, 0x4e, 0x44, 0x2c, 0x20, 0x77, 0x68, 0x69, 0x63, 0x68, 0x20, 0x70, - 0x6f, 0x74, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x6c, 0x79, 0x20, 0x70, - 0x65, 0x72, 0x6d, 0x69, 0x74, 0x73, 0x20, 0x65, 0x78, 0x74, 0x72, 0x61, - 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x70, 0x65, 0x72, 0x66, - 0x6f, 0x72, 0x6d, 0x61, 0x6e, 0x63, 0x65, 0x20, 0x6f, 0x70, 0x74, 0x69, - 0x6d, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x0a, 0x0a, - 0x20, 0x20, 0x23, 0x23, 0x20, 0x4c, 0x69, 0x66, 0x65, 0x74, 0x69, 0x6d, - 0x65, 0x20, 0x72, 0x65, 0x6c, 0x61, 0x74, 0x65, 0x64, 0x0a, 0x20, 0x20, + 0x20, 0x4f, 0x46, 0x46, 0x45, 0x52, 0x2f, 0x44, 0x45, 0x4d, 0x41, 0x4e, + 0x44, 0x2c, 0x20, 0x77, 0x68, 0x69, 0x63, 0x68, 0x20, 0x70, 0x6f, 0x74, + 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x6c, 0x79, 0x20, 0x70, 0x65, 0x72, + 0x6d, 0x69, 0x74, 0x73, 0x20, 0x65, 0x78, 0x74, 0x72, 0x61, 0x0a, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x70, 0x65, 0x72, 0x66, 0x6f, 0x72, + 0x6d, 0x61, 0x6e, 0x63, 0x65, 0x20, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x69, + 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x0a, 0x0a, 0x20, 0x20, + 0x23, 0x23, 0x20, 0x4c, 0x69, 0x66, 0x65, 0x74, 0x69, 0x6d, 0x65, 0x20, + 0x72, 0x65, 0x6c, 0x61, 0x74, 0x65, 0x64, 0x0a, 0x20, 0x20, 0x23, 0x20, 0x2d, 0x20, 0x6b, 0x65, 0x79, 0x3a, 0x20, 0x22, 0x63, 0x64, 0x6f, 0x2e, 0x6c, 0x69, 0x66, 0x65, 0x74, 0x69, 0x6d, 0x65, 0x22, 0x0a, 0x20, 0x20, - 0x20, 0x20, 0x74, 0x79, 0x70, 0x65, 0x3a, 0x20, 0x6c, 0x69, 0x66, 0x65, - 0x74, 0x69, 0x6d, 0x65, 0x2d, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, - 0x6c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x71, 0x75, 0x69, 0x72, + 0x23, 0x20, 0x20, 0x20, 0x74, 0x79, 0x70, 0x65, 0x3a, 0x20, 0x6c, 0x69, + 0x66, 0x65, 0x74, 0x69, 0x6d, 0x65, 0x2d, 0x69, 0x6e, 0x74, 0x65, 0x72, + 0x76, 0x61, 0x6c, 0x0a, 0x20, 0x20, 0x23, 0x20, 0x20, 0x20, 0x72, 0x65, + 0x71, 0x75, 0x69, 0x72, 0x65, 0x64, 0x3a, 0x20, 0x46, 0x61, 0x6c, 0x73, + 0x65, 0x0a, 0x20, 0x20, 0x23, 0x20, 0x20, 0x20, 0x64, 0x6f, 0x63, 0x75, + 0x6d, 0x65, 0x6e, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x20, 0x43, + 0x44, 0x4f, 0x20, 0x6c, 0x69, 0x66, 0x65, 0x74, 0x69, 0x6d, 0x65, 0x20, + 0x73, 0x70, 0x65, 0x63, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x2e, 0x0a, 0x20, 0x20, 0x23, 0x20, 0x2d, 0x20, 0x6b, 0x65, 0x79, + 0x3a, 0x20, 0x22, 0x63, 0x64, 0x6f, 0x2e, 0x6c, 0x69, 0x66, 0x65, 0x74, + 0x69, 0x6d, 0x65, 0x2d, 0x73, 0x74, 0x72, 0x69, 0x63, 0x74, 0x6e, 0x65, + 0x73, 0x73, 0x22, 0x0a, 0x20, 0x20, 0x23, 0x20, 0x20, 0x20, 0x74, 0x79, + 0x70, 0x65, 0x3a, 0x20, 0x6c, 0x69, 0x66, 0x65, 0x74, 0x69, 0x6d, 0x65, + 0x2d, 0x73, 0x74, 0x72, 0x69, 0x63, 0x74, 0x6e, 0x65, 0x73, 0x73, 0x0a, + 0x20, 0x20, 0x23, 0x20, 0x20, 0x20, 0x72, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x64, 0x3a, 0x20, 0x46, 0x61, 0x6c, 0x73, 0x65, 0x0a, 0x20, 0x20, + 0x23, 0x20, 0x20, 0x20, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x3a, + 0x20, 0x2a, 0x6c, 0x69, 0x66, 0x65, 0x74, 0x69, 0x6d, 0x65, 0x2d, 0x73, + 0x74, 0x72, 0x69, 0x63, 0x74, 0x6e, 0x65, 0x73, 0x73, 0x2d, 0x76, 0x61, + 0x6c, 0x75, 0x65, 0x73, 0x0a, 0x20, 0x20, 0x23, 0x20, 0x20, 0x20, 0x64, + 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x3a, 0x20, 0x43, 0x44, 0x4f, 0x20, 0x6c, 0x69, 0x66, 0x65, 0x74, 0x69, + 0x6d, 0x65, 0x20, 0x73, 0x70, 0x65, 0x63, 0x69, 0x66, 0x69, 0x63, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x0a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x0a, + 0x20, 0x20, 0x23, 0x23, 0x20, 0x53, 0x43, 0x4f, 0x50, 0x45, 0x20, 0x72, + 0x65, 0x6c, 0x61, 0x74, 0x65, 0x64, 0x0a, 0x20, 0x20, 0x2d, 0x20, 0x6b, + 0x65, 0x79, 0x3a, 0x20, 0x22, 0x63, 0x64, 0x6f, 0x2e, 0x73, 0x63, 0x6f, + 0x70, 0x65, 0x2e, 0x73, 0x69, 0x7a, 0x65, 0x22, 0x0a, 0x20, 0x20, 0x20, + 0x20, 0x74, 0x79, 0x70, 0x65, 0x3a, 0x20, 0x69, 0x6e, 0x74, 0x28, 0x6d, + 0x69, 0x6e, 0x3d, 0x2d, 0x31, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x72, + 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x64, 0x3a, 0x20, 0x46, 0x61, 0x6c, + 0x73, 0x65, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x64, 0x65, 0x66, 0x61, 0x75, + 0x6c, 0x74, 0x3a, 0x20, 0x2d, 0x31, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x64, + 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x3a, 0x20, 0x54, 0x68, 0x65, 0x20, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x20, + 0x73, 0x69, 0x7a, 0x65, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, + 0x43, 0x44, 0x4f, 0x2e, 0x20, 0x2d, 0x31, 0x20, 0x69, 0x6e, 0x64, 0x69, + 0x63, 0x61, 0x74, 0x65, 0x73, 0x20, 0x55, 0x6e, 0x6b, 0x6e, 0x6f, 0x77, + 0x6e, 0x2f, 0x55, 0x6e, 0x61, 0x6c, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x65, + 0x64, 0x2e, 0x0a, 0x0a, 0x20, 0x20, 0x2d, 0x20, 0x6b, 0x65, 0x79, 0x3a, + 0x20, 0x22, 0x63, 0x64, 0x6f, 0x2e, 0x73, 0x63, 0x6f, 0x70, 0x65, 0x2e, + 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x2d, 0x73, 0x69, 0x7a, 0x65, 0x22, 0x0a, + 0x20, 0x20, 0x20, 0x20, 0x74, 0x79, 0x70, 0x65, 0x3a, 0x20, 0x69, 0x6e, + 0x74, 0x28, 0x6d, 0x69, 0x6e, 0x3d, 0x2d, 0x31, 0x29, 0x0a, 0x20, 0x20, + 0x20, 0x20, 0x72, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x64, 0x3a, 0x20, + 0x46, 0x61, 0x6c, 0x73, 0x65, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x64, 0x65, + 0x66, 0x61, 0x75, 0x6c, 0x74, 0x3a, 0x20, 0x2d, 0x31, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x61, 0x74, - 0x69, 0x6f, 0x6e, 0x3a, 0x20, 0x43, 0x44, 0x4f, 0x20, 0x6c, 0x69, 0x66, - 0x65, 0x74, 0x69, 0x6d, 0x65, 0x20, 0x73, 0x70, 0x65, 0x63, 0x69, 0x66, - 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x0a, 0x20, 0x20, 0x2d, - 0x20, 0x6b, 0x65, 0x79, 0x3a, 0x20, 0x22, 0x63, 0x64, 0x6f, 0x2e, 0x6c, - 0x69, 0x66, 0x65, 0x74, 0x69, 0x6d, 0x65, 0x2d, 0x73, 0x74, 0x72, 0x69, - 0x63, 0x74, 0x6e, 0x65, 0x73, 0x73, 0x22, 0x0a, 0x20, 0x20, 0x20, 0x20, - 0x74, 0x79, 0x70, 0x65, 0x3a, 0x20, 0x6c, 0x69, 0x66, 0x65, 0x74, 0x69, - 0x6d, 0x65, 0x2d, 0x73, 0x74, 0x72, 0x69, 0x63, 0x74, 0x6e, 0x65, 0x73, - 0x73, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x71, 0x75, 0x69, 0x72, - 0x65, 0x64, 0x3a, 0x20, 0x46, 0x61, 0x6c, 0x73, 0x65, 0x0a, 0x20, 0x20, - 0x20, 0x20, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x3a, 0x20, 0x2a, - 0x6c, 0x69, 0x66, 0x65, 0x74, 0x69, 0x6d, 0x65, 0x2d, 0x73, 0x74, 0x72, - 0x69, 0x63, 0x74, 0x6e, 0x65, 0x73, 0x73, 0x2d, 0x76, 0x61, 0x6c, 0x75, - 0x65, 0x73, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x64, 0x6f, 0x63, 0x75, 0x6d, - 0x65, 0x6e, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x20, 0x43, 0x44, - 0x4f, 0x20, 0x6c, 0x69, 0x66, 0x65, 0x74, 0x69, 0x6d, 0x65, 0x20, 0x73, - 0x70, 0x65, 0x63, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, - 0x2e, 0x0a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x0a, 0x20, 0x20, 0x23, 0x23, - 0x20, 0x53, 0x43, 0x4f, 0x50, 0x45, 0x20, 0x72, 0x65, 0x6c, 0x61, 0x74, - 0x65, 0x64, 0x0a, 0x20, 0x20, 0x2d, 0x20, 0x6b, 0x65, 0x79, 0x3a, 0x20, - 0x22, 0x63, 0x64, 0x6f, 0x2e, 0x73, 0x63, 0x6f, 0x70, 0x65, 0x2e, 0x73, - 0x69, 0x7a, 0x65, 0x22, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x74, 0x79, 0x70, - 0x65, 0x3a, 0x20, 0x69, 0x6e, 0x74, 0x28, 0x6d, 0x69, 0x6e, 0x3d, 0x2d, - 0x31, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x71, 0x75, 0x69, - 0x72, 0x65, 0x64, 0x3a, 0x20, 0x46, 0x61, 0x6c, 0x73, 0x65, 0x0a, 0x20, - 0x20, 0x20, 0x20, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x3a, 0x20, - 0x2d, 0x31, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x64, 0x6f, 0x63, 0x75, 0x6d, - 0x65, 0x6e, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x20, 0x54, 0x68, - 0x65, 0x20, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x20, 0x73, 0x69, 0x7a, 0x65, - 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x43, 0x44, 0x4f, 0x2e, - 0x20, 0x2d, 0x31, 0x20, 0x69, 0x6e, 0x64, 0x69, 0x63, 0x61, 0x74, 0x65, - 0x73, 0x20, 0x55, 0x6e, 0x6b, 0x6e, 0x6f, 0x77, 0x6e, 0x2f, 0x55, 0x6e, - 0x61, 0x6c, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x65, 0x64, 0x2e, 0x0a, 0x0a, - 0x20, 0x20, 0x2d, 0x20, 0x6b, 0x65, 0x79, 0x3a, 0x20, 0x22, 0x63, 0x64, - 0x6f, 0x2e, 0x73, 0x63, 0x6f, 0x70, 0x65, 0x2e, 0x6c, 0x6f, 0x63, 0x61, - 0x6c, 0x2d, 0x73, 0x69, 0x7a, 0x65, 0x22, 0x0a, 0x20, 0x20, 0x20, 0x20, - 0x74, 0x79, 0x70, 0x65, 0x3a, 0x20, 0x69, 0x6e, 0x74, 0x28, 0x6d, 0x69, - 0x6e, 0x3d, 0x2d, 0x31, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, - 0x71, 0x75, 0x69, 0x72, 0x65, 0x64, 0x3a, 0x20, 0x46, 0x61, 0x6c, 0x73, - 0x65, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, - 0x74, 0x3a, 0x20, 0x2d, 0x31, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x64, 0x6f, - 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x3a, - 0x20, 0x54, 0x68, 0x65, 0x20, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x73, - 0x69, 0x7a, 0x65, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x43, - 0x44, 0x4f, 0x2e, 0x20, 0x2d, 0x31, 0x20, 0x69, 0x6e, 0x64, 0x69, 0x63, - 0x61, 0x74, 0x65, 0x73, 0x20, 0x55, 0x6e, 0x6b, 0x6e, 0x6f, 0x77, 0x6e, - 0x2f, 0x55, 0x6e, 0x61, 0x6c, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x65, 0x64, - 0x2e, 0x0a, 0x0a, 0x20, 0x20, 0x23, 0x20, 0x4c, 0x61, 0x79, 0x6f, 0x75, - 0x74, 0x73, 0x0a, 0x20, 0x20, 0x23, 0x20, 0x44, 0x69, 0x73, 0x74, 0x72, - 0x69, 0x62, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x0a, 0x0a, 0x0a, 0x23, - 0x20, 0x28, 0x65, 0x6e, 0x64, 0x20, 0x6f, 0x66, 0x20, 0x6d, 0x61, 0x65, - 0x73, 0x74, 0x72, 0x6f, 0x2d, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x79, 0x61, - 0x6d, 0x6c, 0x29, 0x0a, 0x0a + 0x69, 0x6f, 0x6e, 0x3a, 0x20, 0x54, 0x68, 0x65, 0x20, 0x6c, 0x6f, 0x63, + 0x61, 0x6c, 0x20, 0x73, 0x69, 0x7a, 0x65, 0x20, 0x6f, 0x66, 0x20, 0x74, + 0x68, 0x65, 0x20, 0x43, 0x44, 0x4f, 0x2e, 0x20, 0x2d, 0x31, 0x20, 0x69, + 0x6e, 0x64, 0x69, 0x63, 0x61, 0x74, 0x65, 0x73, 0x20, 0x55, 0x6e, 0x6b, + 0x6e, 0x6f, 0x77, 0x6e, 0x2f, 0x55, 0x6e, 0x61, 0x6c, 0x6c, 0x6f, 0x63, + 0x61, 0x74, 0x65, 0x64, 0x2e, 0x0a, 0x0a, 0x20, 0x20, 0x23, 0x20, 0x4c, + 0x61, 0x79, 0x6f, 0x75, 0x74, 0x73, 0x0a, 0x20, 0x20, 0x23, 0x20, 0x44, + 0x69, 0x73, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x73, + 0x0a, 0x0a, 0x0a, 0x23, 0x20, 0x28, 0x65, 0x6e, 0x64, 0x20, 0x6f, 0x66, + 0x20, 0x6d, 0x61, 0x65, 0x73, 0x74, 0x72, 0x6f, 0x2d, 0x63, 0x6f, 0x72, + 0x65, 0x2e, 0x79, 0x61, 0x6d, 0x6c, 0x29, 0x0a, 0x0a }; -const unsigned int maestro_core_yaml_len = 3785; +const unsigned int maestro_core_yaml_len = 3885; diff --git a/attributes/maestro-core.yaml b/attributes/maestro-core.yaml index c497681a..7a23acc3 100644 --- a/attributes/maestro-core.yaml +++ b/attributes/maestro-core.yaml @@ -7,26 +7,27 @@ schema-version: 0 schema-namespace: ".maestro.core." # Values permitted in user-defined types used -schema-type-values: +#schema-type-values: + # FIXME: user-defined types currently broken # values occuring in lifetime-strictness flag - - &lifetime-strictness-values enum('optional', 'required') + # - &lifetime-strictness-values enum('optional', 'required') # values occuring in lifetime-strictness flag - - &access-mode-values enum('rw', 'r') + #- &access-mode-values enum('rw', 'r') # user-defined types used in this schema -schema-types: +#schema-types: - - typename: lifetime-interval - typespec: map() - documentation: CDO lifetime type + # - typename: lifetime-interval + # typespec: map() + # documentation: CDO lifetime type - - typename: lifetime-strictness - typespec: *lifetime-strictness-values - documentation: CDO lifetime specifier interpretation + # - typename: lifetime-strictness + # typespec: *lifetime-strictness-values + # documentation: CDO lifetime specifier interpretation - - typename: access-mode - typespec: *access-mode-values - documentation: CDO access mode + # - typename: access-mode + # typespec: *access-mode-values + # documentation: CDO access mode # Individual attribute descriptions maestro-attributes: @@ -71,12 +72,12 @@ maestro-attributes: documentation: Request/advise maestro storage management for the CDO (no RAW-PTR will be provided or can be obtained) - - key: "cdo.access-mode" - type: access-mode - required: False - default: *access-mode-values - documentation: Indicates how the CDO will be accessed by the user - (read-write, read-only, etc.). + # - key: "cdo.access-mode" + # type: access-mode + # required: False + # default: *access-mode-values + # documentation: Indicates how the CDO will be accessed by the user + # (read-write, read-only, etc.). - key: "cdo.transfer-asap" type: bool() @@ -94,15 +95,15 @@ maestro-attributes: performance optimizations. ## Lifetime related - - key: "cdo.lifetime" - type: lifetime-interval - required: False - documentation: CDO lifetime specification. - - key: "cdo.lifetime-strictness" - type: lifetime-strictness - required: False - default: *lifetime-strictness-values - documentation: CDO lifetime specification. + # - key: "cdo.lifetime" + # type: lifetime-interval + # required: False + # documentation: CDO lifetime specification. + # - key: "cdo.lifetime-strictness" + # type: lifetime-strictness + # required: False + # default: *lifetime-strictness-values + # documentation: CDO lifetime specification. ## SCOPE related diff --git a/attributes/maestro-schema.c b/attributes/maestro-schema.c index b9d6138d..11f50beb 100644 --- a/attributes/maestro-schema.c +++ b/attributes/maestro-schema.c @@ -102,9 +102,6 @@ struct mstro_schema_type_ { char *documentation; /**< "documentation: str()" */ struct mstro_stp_val *parsed_type; /**< parsed type handle */ - /* A closure each for parser, serializer, deserializer. May be - * NULL. Main use: instantiated regex parser automaton for string-ish types */ - void *parser_closure; }; @@ -131,9 +128,19 @@ csv_schema_type_entry = { csf_schema_type_mapping), }; +struct mstro_schema_attribute_type_parse_closure { + struct mstro_stp_val *info; +}; + /** attribute entry data structure */ struct mstro_schema_attribute_ { + /* not set by CYAML parse: */ UT_hash_handle hh; /**< hashable by key_symbol */ + void *defaultval; /**< parsed defaultval_string */ + size_t defaultval_size; /**< size of defaultval */ + mstro_symbol key_symbol; /**< symbol for key; key in the hash table */ + struct mstro_schema_attribute_type_parse_closure type_parse_closure; /**< information for parsing values of this type */ + /* these slots get filled by CYAML parse */ char *key; /**< key: regex('(^(\.[^\s\.]+)+$)|(^[^\s\.]+(\.[^\s\.]+)*$)', required=False, none=False, multiline=False, @@ -141,16 +148,13 @@ struct mstro_schema_attribute_ { #define ATTRIBUTE_KEY_PATTERN "(^(\\.[^[:space:].]+)+$)|(^[^[:space:].]+(\\.[^[:space:].]+)*$)" #define ATTRIBUTE_KEY_PATTERN_CFLAGS (REG_EXTENDED|REG_ICASE) #define ATTRIBUTE_KEY_PATTERN_EFLAGS 0 - - mstro_symbol key_symbol; /**< symbol for key; key in the hash table */ char *typespec; /**< type: include('maestro-user-typespec') */ - bool required; /**< required: bool() */ - struct mstro_schema_type_val *defaultval; /**< Any(include('maestro-builtin-typeval'), - include('maestro-user-typeval'), - required=False, none=False) */ - + /* struct mstro_schema_type_val *defaultval; /\**< Any(include('maestro-builtin-typeval'), */ + /* include('maestro-user-typeval'), */ + /* required=False, none=False) *\/ */ + char * defaultval_string; /**< string form of default value */ char *documentation; /**< documentation: str(multiline=True) */ }; @@ -165,9 +169,11 @@ csf_schema_attribute_mapping[] = { CYAML_FIELD_BOOL("required", CYAML_FLAG_DEFAULT, struct mstro_schema_attribute_, required), + /* because we're lazy we store it as a string currently and parse it at instantiation time + It's actually easier that way, since complicated user-defined types' values can't be parsed by cyaml */ CYAML_FIELD_STRING_PTR("default", CYAML_FLAG_DEFAULT|CYAML_FLAG_OPTIONAL, - struct mstro_schema_attribute_, defaultval, 0, CYAML_UNLIMITED), + struct mstro_schema_attribute_, defaultval_string, 0, CYAML_UNLIMITED), CYAML_FIELD_STRING_PTR("documentation", CYAML_FLAG_DEFAULT, struct mstro_schema_attribute_, documentation, 0, CYAML_UNLIMITED), @@ -266,13 +272,8 @@ mstro_schema_name(mstro_schema sch) { if(sch==NULL) return "(null)"; - else { - if(sch->next!=NULL) { - /* FIXME: */ - WARN("schema has merged content, name not reflecting this\n"); - } + else return sch->schema_name; - } } /** Return the version of a schema. */ @@ -399,7 +400,7 @@ mstro_schema__validate_namespace(const char *string) s, mstro_status_description(s)); return s; } - bool namespace_ok; + //bool namespace_ok; s = mstro_schema__check_regex(string, namespace_regex, NAMESPACE_PATTERN_EFLAGS); @@ -470,7 +471,7 @@ mstro_schema__validate_attribute_key(const char *string) s, mstro_status_description(s)); return s; } - bool attribute_key_ok; + //bool attribute_key_ok; s = mstro_schema__check_regex(string, attribute_key_regex, ATTRIBUTE_KEY_PATTERN_EFLAGS); @@ -501,6 +502,317 @@ mstro_cyaml_config = { +/* look at the typespec string and parse it; fill in information that + * helps us parse values of this type whenever needed later */ +static inline +mstro_status +mstro_schema_attribute__install_type_parser(struct mstro_schema_attribute_ *attr) +{ + mstro_status s = mstro_schema_type_parse(attr->typespec, &attr->type_parse_closure.info); + if(s!=MSTRO_OK) { + if(attr->type_parse_closure.info && attr->type_parse_closure.info->kind == MSTRO_STP_ERROR) { + ERR("Error parsing type |%s|, error message %s\n", + attr->typespec, attr->type_parse_closure.info->errmsg); + } else { + ERR("error parsing built-in type: %d (no parser error message available)\n", + s); + } + } + return s; +} + +/* compute the space needed to store the value of STP_VAL arising from +* parsing STRING or inspecting VAL. Only one of the two may ne +* non-NULL. */ +static inline +mstro_status +mstro_attribute_val__compute_size(enum mstro_stp_val_kind kind, + const char *string, + void *val, + size_t *val_size) +{ + if(kind==MSTRO_STP_ERROR) { + ERR("Invalid stp val\n"); + return MSTRO_INVARG; + } + if(string==NULL && val==NULL) { + ERR("not both src args may be NULL\n"); + return MSTRO_INVARG; + } + if(string!=NULL && val!=NULL) { + ERR("not both src args may be non-NULL\n"); + return MSTRO_INVARG; + } + if(val_size==NULL) { + ERR("Invalid output destination\n"); + return MSTRO_INVOUT; + } + + mstro_status status = MSTRO_OK; + + switch(kind) { + case MSTRO_STP_BOOL: + *val_size = sizeof(bool); break; + case MSTRO_STP_UINT: + *val_size = sizeof(uint64_t); break; + case MSTRO_STP_INT: + *val_size = sizeof(int64_t); break; + case MSTRO_STP_FLOAT: + *val_size = sizeof(float); break; + case MSTRO_STP_DOUBLE: + *val_size = sizeof(double); break; + case MSTRO_STP_STR: + case MSTRO_STP_REGEX: + if(string) + *val_size = strlen(string)+1; + else + *val_size = strlen((char*)val)+1; + break; + case MSTRO_STP_TIMESTAMP: + *val_size = sizeof(mstro_timestamp); + break; + case MSTRO_STP_BLOB: + if(string!=NULL) { + /* FIXME: could be base64 encoded */ + ERR("Cannot parse external-representation of BLOB (FIXME)\n"); + status=MSTRO_UNIMPL; + } else { + *val_size = ((mstro_blob*)val)->len; + } + break; + default: + ERR("Unexpected parsed type %d\n", kind); + status=MSTRO_UNIMPL; + } + return status; +} + +/* parse a string according to type specification of the attribute. + * Store freshly-allocated value in **val_p, and the size in *val_size. + */ +static inline +mstro_status +mstro_attribute_val_parse(const struct mstro_stp_val *parsed_type, const char *string, + void **val_p, size_t *val_size) +{ + if(parsed_type==NULL ||string==NULL) { + ERR("Invalid input args\n"); + return MSTRO_INVARG; + } + if(val_p==NULL||val_size==NULL) { + ERR("Invalid output args\n"); + return MSTRO_INVOUT; + } + + mstro_status s=MSTRO_OK; + + + s =mstro_attribute_val__compute_size(parsed_type->kind, string, NULL, val_size); + if(s!=MSTRO_OK) { + ERR("Failed to compute value size\n"); + return s; + } + + /* all built-ins recognized by built-in regexps for now */ + size_t num_re; + if(parsed_type->kind == MSTRO_STP_REGEX) { + num_re = parsed_type->regex_numpatterns; + } else { + num_re = 1; + } + regex_t regex[num_re]; + int err=0; + bool need_regmatch = true; /* except for BLOB we need it */ + size_t val_len = strlen(string); + size_t minlen =0, maxlen=val_len; /* might be changed for strings */ + + switch(parsed_type->kind) { + case MSTRO_STP_BOOL: { + err = regcomp(&(regex[0]), "1|0|On|Off|True|False",REG_ICASE|REG_NOSUB|REG_EXTENDED); + break; + } + case MSTRO_STP_UINT: { + err = regcomp(&(regex[0]), "[+]?[[:blank:]]*[0-9]+",REG_EXTENDED|REG_NOSUB); + WARN("Not checking numeric bounds on types\n"); + break; + } + case MSTRO_STP_INT: { + err = regcomp(&(regex[0]), "[-+]?[[:blank:]]*[0-9]+",REG_EXTENDED|REG_NOSUB); + WARN("Not checking numeric bounds on types\n"); + break; + } + case MSTRO_STP_FLOAT: { + err = regcomp(&(regex[0]), "[-+]?[[:blank:]]*[0-9]*\\.?[0-9]+([eE][-+]?[0-9]+)?",REG_EXTENDED); + WARN("Not checking numeric bounds on types\n"); + break; + } + case MSTRO_STP_DOUBLE: { + err = regcomp(&(regex[0]), "[-+]?[[:blank:]]*[0-9]*\\.?[0-9]+([eE][-+]?[0-9]+)?",REG_EXTENDED); + WARN("Not checking numeric bounds on types\n"); + break; + } + case MSTRO_STP_STR: { + minlen = parsed_type->str_minlen; + maxlen = parsed_type->str_maxlen; + char *re; + if(parsed_type->str_excludedchars) { + size_t l = strlen(parsed_type->str_excludedchars)+strlen("[^]*") + 1; + re=malloc(sizeof(char)*l); + if(re) { + re[0]='['; re[1]='^'; + strcpy(re+2,parsed_type->str_excludedchars); + re[l-3] = ']'; re[l-2]='*'; re[l-1] = '\0'; + } + } else { + re = strdup(".*"); + } + if(re==NULL) { + ERR("Failed to allocate string regex\n"); + s=MSTRO_NOMEM; + goto BAILOUT; + } + err = regcomp(&(regex[0]), re, REG_NOSUB); + free(re); + break; + } + case MSTRO_STP_REGEX: + for(size_t i=0; i<num_re; i++) { + err |= regcomp(&(regex[i]), parsed_type->regex_patterns[i], + REG_EXTENDED|REG_NOSUB| (parsed_type->regex_ignorecase ? REG_ICASE : 0)); + } + break; + case MSTRO_STP_BLOB: + need_regmatch = false; + minlen = parsed_type->blob_minlen; + maxlen = parsed_type->blob_maxlen; + break; + case MSTRO_STP_TIMESTAMP: + err = regcomp(&(regex[0]), RFC3339_PATTERN, REG_EXTENDED); + break; + + default: + ERR("Unexpected parsed type %d\n", parsed_type->kind); + s=MSTRO_UNIMPL; + } + if(err) { + ERR("Failed to construct regex\n"); + // regerror ... + goto BAILOUT; + } + + if(! (minlen<=val_len && val_len <=maxlen)) { + ERR("Argument |%s| (strlen %zu) not within length bounds for type: min=%zu, max=%zu\n", + string, val_len, minlen, maxlen); + s=MSTRO_FAIL; + goto BAILOUT; + } + + s=MSTRO_OK; + if(need_regmatch) { + s=MSTRO_NOMATCH; + for(size_t i=0; i<num_re; i++) { + s = mstro_schema__check_regex(string, &(regex[i]), 0); + /* DEBUG("Checked regex against |%s|, result %d (%s)\n", val, s, mstro_status_description(s)); */ + if(s==MSTRO_OK) + break; + /* NOMATCH: try further */ + if(s==MSTRO_NOMATCH) { + continue; + } else { + break; + } + } + for(size_t i=0; i<num_re; i++) { + regfree(®ex[i]); + } + } + + *val_p = malloc(*val_size); + if(*val_p==NULL) { + ERR("Failed to allocate for attribute value\n"); + s=MSTRO_NOMEM; + goto BAILOUT; + } + + /* numeric bound checking should happen in this switch. All the info is in the stp_val */ + if(s==MSTRO_OK) { + switch(parsed_type->kind) { + case MSTRO_STP_BOOL: { + /* we are alredy checked by regex above */ + switch(tolower(string[0])) { + case 't': // TRUE + case '1': // 1 + case 'o': // ON + case 'y': // YES + **((bool**)(val_p)) = true; + break; + default: + *((bool**)(val_p)) = false; + break; + } + break; + } + case MSTRO_STP_UINT: + **((uint64_t**)(val_p)) = strtoumax((const char*)string, NULL, 10); + break; + + case MSTRO_STP_INT: + **((int64_t**)(val_p)) = strtoimax(string, NULL, 10); + break; + + case MSTRO_STP_FLOAT: + *((float*)(val_p)) = strtof(string, NULL); + break; + + case MSTRO_STP_DOUBLE: + **((double**)(val_p)) = strtod(string, NULL); + break; + + case MSTRO_STP_STR: + case MSTRO_STP_REGEX: + strcpy(*(char**)val_p, string); + (*(char**)(val_p))[(*val_size)-1] = '\0'; + break; + + case MSTRO_STP_BLOB: + memcpy(*(char**)val_p, string, *val_size); + break; + + case MSTRO_STP_TIMESTAMP: { + s=mstro_timestamp_parse(string, *val_size, *((mstro_timestamp**)val_p)); + if(s!=MSTRO_OK) { + ERR("Failed to parse timestamp value |%s| as rfc3339-timestamp\n"); + } + break; + } + + default: + ERR("Unexpected parsed type %d\n", parsed_type->kind); + s=MSTRO_UNIMPL; + } + } + +BAILOUT: + return s; +} + + +/* parse the defaultval_string and store it (in a fresh allocation) in the default slot */ +static inline +mstro_status +mstro_schema_attribute__parse_defaultval(struct mstro_schema_attribute_ *attr) +{ + assert(attr->type_parse_closure.info!=NULL); + if(attr->defaultval_string) + return mstro_attribute_val_parse(attr->type_parse_closure.info, attr->defaultval_string, + &attr->defaultval, &attr->defaultval_size); + else { + attr->defaultval = NULL; + attr->defaultval_size = 0; + return MSTRO_OK; + } +} + /** update ACC to VAL if that is greater */ #define SAVE_MAX(acc,val) (acc) = ((acc)<(val)? (val) : (acc)); @@ -625,14 +937,42 @@ mstro_schema_validate_and_instantiate(mstro_schema schema) ERR("Failed to intern attribute name |%s|\n", fqstr); goto BAILOUT; } + + s=mstro_schema_attribute__install_type_parser(current); + if(s!=MSTRO_OK) { + ERR("Failed to install type parser for %s (type %s)\n", + mstro_symbol_name(current->key_symbol), + current->typespec); + goto BAILOUT; + } + HASH_ADD(hh, schema->attribute_table, key_symbol, sizeof(mstro_symbol), current); + /* parse default value */ + if(!current->required) + if(current->defaultval_string==NULL) { + ERR("Attribute |%s| is optional, but schema provides no default value\n", + fqstr); + s=MSTRO_FAIL; + goto BAILOUT; + } + + DEBUG("Adding default value for %s\n", fqstr); + s = mstro_schema_attribute__parse_defaultval(current); + if(s!=MSTRO_OK) { + ERR("Failed to parse default value |%s| for attribute |%s|\n", + current->defaultval_string, fqstr); + goto BAILOUT; + } + /* check that attribute has value type */ - DEBUG("Attribute |%s| type |%s|, required %s, default %s\n", + DEBUG("Attribute |%s| type |%s|, required %s, default %s, doc: %s\n", mstro_symbol_name(current->key_symbol), current->typespec, current->required ? "YES" : "NO", - "?"//current->defaultval ? current->defaultval->val : "(none)" + //"?"// + current->defaultval_string ? current->defaultval_string : "(none)", + current->documentation ? current->documentation : "(none)" ); } @@ -751,6 +1091,18 @@ mstro_schema_merge(mstro_schema main, if(main==NULL || consumed==NULL) { return MSTRO_INVARG; } + char *tmpname = malloc(strlen(main->schema_name)+strlen(" + ")+strlen(consumed->schema_name)+1); + if(tmpname==NULL) { + ERR("Cannot allocate merged schema name\n"); + return MSTRO_NOMEM; + } + strcpy(tmpname,main->schema_name); + strcat(tmpname," + "); + strcat(tmpname,consumed->schema_name); + + free(main->schema_name); + + main->schema_name=tmpname; LL_APPEND(main,consumed); /* FIXME: we could copy entries from consumed into main, but until @@ -877,7 +1229,7 @@ mstro_schema_lookup_type__builtins( if(*result) { (*result)->typename = strdup(typename); (*result)->type_symbol = sym; - (*result)->unparsed_typespec = strdup("?"); + (*result)->unparsed_typespec = strdup(typename); (*result)->documentation = strdup("builtin type"); (*result)->parsed_type = parsed_type; HASH_ADD(hh, schema->type_table, type_symbol, sizeof(mstro_symbol), *result); @@ -942,7 +1294,7 @@ mstro_schema_lookup_symbol(mstro_schema schema, const char *fqkey, mstro_symbol for(mstro_schema schem = schema; schem!=NULL; schem=schem->next) { - DEBUG("Trying schema %s\n", mstro_schema_name(schem)); + //DEBUG("Trying schema %s\n", mstro_schema_name(schem)); status = mstro_symtab_lookup(schem->symtab, fqkey, sym); if(status!=MSTRO_OK) { return status; @@ -1037,251 +1389,10 @@ mstro_status mstro_attribute_entry__set_size(struct mstro_attribute_entry_ *entry, enum mstro_stp_val_kind kind) { - mstro_status status=MSTRO_OK; - switch(kind) { - case MSTRO_STP_BOOL: - entry->valsize = sizeof(bool); break; - case MSTRO_STP_UINT: - entry->valsize = sizeof(uint64_t); break; - case MSTRO_STP_INT: - entry->valsize = sizeof(int64_t); break; - case MSTRO_STP_FLOAT: - entry->valsize = sizeof(float); break; - case MSTRO_STP_DOUBLE: - entry->valsize = sizeof(double); break; - case MSTRO_STP_STR: - case MSTRO_STP_REGEX: - entry->valsize = strlen(entry->val)+1; - break; - case MSTRO_STP_BLOB: - entry->valsize = 0; /* FIXME: query a previously set key like 'strcat(fqkey,"_len")' ? */ - break; - case MSTRO_STP_TIMESTAMP: - entry->valsize = sizeof(mstro_timestamp); break; - - default: - ERR("Unexpected parsed type %d\n", kind); - status=MSTRO_UNIMPL; - } - return status; + return mstro_attribute_val__compute_size(kind, NULL, entry->val, &entry->valsize); } -/* parse VAL and fill in *entry */ -static inline -mstro_status -mstro_attributes_parse_val(mstro_schema schema, - struct mstro_schema_attribute_ *decl, - const unsigned char *val, size_t val_len, - struct mstro_attribute_entry_ *entry) -{ - const char *aname = mstro_symbol_name(decl->key_symbol); - const char *tname = decl->typespec; - DEBUG("Attribute |%s|, declared type |%s|\n", aname, tname); - /* fetch type declaration */ - - mstro_schema_type tdecl; - mstro_status s = mstro_schema_lookup_type(schema, tname, &tdecl); - - if(s!=MSTRO_OK) { - ERR("Failed to find type declaration for type |%s| (attribute |%s|)\n", - tname, aname); - return MSTRO_INVARG; - } else { - DEBUG("Found type declaration for type |%s| (attribute |%s|)\n", tname, aname); - } - /* FIXME: this could be handled better by pre-allocated parsers - * (needs to be reentrant!) built with a schema-typeval.peg */ - if(!tdecl->parsed_type) { - ERR("Parsed type not available\n"); - return MSTRO_UNIMPL; - } - - /* all built-ins recognized by built-in regexps for now */ - size_t num_re; - if(tdecl->parsed_type->kind == MSTRO_STP_REGEX) { - num_re = tdecl->parsed_type->regex_numpatterns; - } else { - num_re = 1; - } - regex_t regex[num_re]; - int err=0; - bool need_regmatch = true; /* except for BLOB we need it */ - size_t minlen =0, maxlen=val_len; /* might be changed for strings */ - - entry->kind = tdecl->parsed_type->kind; - s = mstro_attribute_entry__set_size(entry, entry->kind); - if(s!=MSTRO_OK) { - ERR("Failed to set entry value size\n"); - goto BAILOUT; - } - - switch(entry->kind) { - case MSTRO_STP_BOOL: { - err = regcomp(&(regex[0]), "1|0|On|Off|True|False",REG_ICASE|REG_NOSUB|REG_EXTENDED); - break; - } - case MSTRO_STP_UINT: { - err = regcomp(&(regex[0]), "[+]?[[:blank:]]*[0-9]+",REG_EXTENDED|REG_NOSUB); - WARN("Not checking numeric bounds on types\n"); - break; - } - case MSTRO_STP_INT: { - err = regcomp(&(regex[0]), "[-+]?[[:blank:]]*[0-9]+",REG_EXTENDED|REG_NOSUB); - WARN("Not checking numeric bounds on types\n"); - break; - } - case MSTRO_STP_FLOAT: { - err = regcomp(&(regex[0]), "[-+]?[[:blank:]]*[0-9]*\\.?[0-9]+([eE][-+]?[0-9]+)?",REG_EXTENDED); - WARN("Not checking numeric bounds on types\n"); - break; - } - case MSTRO_STP_DOUBLE: { - err = regcomp(&(regex[0]), "[-+]?[[:blank:]]*[0-9]*\\.?[0-9]+([eE][-+]?[0-9]+)?",REG_EXTENDED); - WARN("Not checking numeric bounds on types\n"); - break; - } - case MSTRO_STP_STR: { - minlen = tdecl->parsed_type->str_minlen; - maxlen = tdecl->parsed_type->str_maxlen; - char *re; - if(tdecl->parsed_type->str_excludedchars) { - size_t l = strlen(tdecl->parsed_type->str_excludedchars)+strlen("[^]*") + 1; - re=malloc(sizeof(char)*l); - if(re) { - re[0]='['; re[1]='^'; - strcpy(re+2,tdecl->parsed_type->str_excludedchars); - re[l-3] = ']'; re[l-2]='*'; re[l-1] = '\0'; - } - } else { - re = strdup(".*"); - } - if(re==NULL) { - ERR("Failed to allocate string regex\n"); - s=MSTRO_NOMEM; - goto BAILOUT; - } - err = regcomp(&(regex[0]), re, REG_NOSUB); - free(re); - break; - } - case MSTRO_STP_REGEX: - for(size_t i=0; i<num_re; i++) { - err |= regcomp(&(regex[i]), tdecl->parsed_type->regex_patterns[i], - REG_EXTENDED|REG_NOSUB| (tdecl->parsed_type->regex_ignorecase ? REG_ICASE : 0)); - } - break; - case MSTRO_STP_BLOB: - need_regmatch = false; - minlen = tdecl->parsed_type->blob_minlen; - maxlen = tdecl->parsed_type->blob_maxlen; - break; - case MSTRO_STP_TIMESTAMP: - err = regcomp(&(regex[0]), RFC3339_PATTERN, REG_EXTENDED); - break; - - default: - ERR("Unexpected parsed type %d\n", tdecl->parsed_type->kind); - s=MSTRO_UNIMPL; - } - if(err) { - ERR("Failed to construct regex\n"); - // regerror ... - goto BAILOUT; - } - if(! (minlen<=val_len && val_len <=maxlen)) { - ERR("Argument |%s| (len %zu, strlen %zu) not within length bounds for type: min=%zu, max=%zu\n", - val, val_len, strlen((const char*)val), minlen, maxlen); - s=MSTRO_FAIL; - goto BAILOUT; - } - - s=MSTRO_OK; - if(need_regmatch) { - s=MSTRO_NOMATCH; - for(size_t i=0; i<num_re; i++) { - s = mstro_schema__check_regex((const char*)val, &(regex[i]), 0); - /* DEBUG("Checked regex against |%s|, result %d (%s)\n", val, s, mstro_status_description(s)); */ - if(s==MSTRO_OK) - break; - /* NOMATCH: try further */ - if(s==MSTRO_NOMATCH) { - continue; - } else { - break; - } - } - for(size_t i=0; i<num_re; i++) { - regfree(®ex[i]); - } - } - - entry->val = malloc(entry->valsize); - if(entry->val==NULL) { - ERR("Failed to allocate for attribute value\n"); - s=MSTRO_NOMEM; - goto BAILOUT; - } - - if(s==MSTRO_OK) { - switch(entry->kind) { - case MSTRO_STP_BOOL: { - /* we are alredy checked by regex above */ - switch(tolower(val[0])) { - case 't': // TRUE - case '1': // 1 - case 'o': // ON - case 'y': // YES - *((bool*)(entry->val)) = true; - break; - default: - *((bool*)(entry->val)) = false; - break; - } - break; - } - case MSTRO_STP_UINT: - *((uint64_t*)(entry->val)) = strtoumax((const char*)val, NULL, 10); - break; - - case MSTRO_STP_INT: - *((int64_t*)(entry->val)) = strtoimax((const char*)val, NULL, 10); - break; - - case MSTRO_STP_FLOAT: - *((float*)(entry->val)) = strtof((const char*)val, NULL); - break; - - case MSTRO_STP_DOUBLE: - *((double*)(entry->val)) = strtod((const char*)val, NULL); - break; - case MSTRO_STP_STR: - case MSTRO_STP_REGEX: - strcpy((char*)entry->val, (const char*)val); - ((char*)(entry->val))[entry->valsize-1] = '\0'; - break; - - case MSTRO_STP_BLOB: - memcpy((char*)entry->val, val, val_len); - break; - - case MSTRO_STP_TIMESTAMP: { - s=mstro_timestamp_parse((const char*)val, val_len, ((mstro_timestamp*)entry->val)); - if(s!=MSTRO_OK) { - ERR("Failed to parse timestamp value |%s| as rfc3339-timestamp\n"); - } - break; - } - - default: - ERR("Unexpected parsed type %d\n", tdecl->parsed_type->kind); - s=MSTRO_UNIMPL; - } - } - -BAILOUT: - return s; -} static inline @@ -1525,7 +1636,9 @@ mstro_attributes__parse_helper(yaml_parser_t parser, goto BAILOUT; } - status = mstro_attributes_parse_val(schema, decl, val, val_len, entry); + status = mstro_attribute_val_parse(decl->type_parse_closure.info, + (char*)val, + &entry->val, &entry->valsize); if(status!=MSTRO_OK) { ERR("Failed to parse |%s| as value for attribute |%s|\n", val, mstro_symbol_name(decl->key_symbol)); @@ -1537,6 +1650,10 @@ mstro_attributes__parse_helper(yaml_parser_t parser, val, mstro_symbol_name(decl->key_symbol)); /* FIXME: describe_entry function call here */ } + entry->kind = decl->type_parse_closure.info->kind; + + assert(entry->kind!=MSTRO_STP_ERROR); + if(new_entry) HASH_ADD(hh, (*result)->dict, key, sizeof(mstro_symbol), entry); @@ -1790,12 +1907,21 @@ mstro_attribute_dict__insert_default(mstro_attribute_dict dict, bool must_insert=false; mstro_status status = MSTRO_OK; + DEBUG("schema dict insert default for key %s\n", mstro_symbol_name(key)); mstro_schema_attribute attr=NULL; status = mstro_schema_lookup_attribute(dict->schema, mstro_symbol_name(key), &attr); if(status!=MSTRO_OK) { ERR("Cannot find attribute in schema !? (should not happen here)\n"); goto BAILOUT; } + if(!attr->defaultval) { + /* schema instantiation should have parsed the defaultval_string for us */ + DEBUG("No default for |%s| in schema\n", mstro_symbol_name(key)); + return MSTRO_NOENT; + } + + assert(attr->defaultval!=NULL); + mstro_schema_type tdecl; status = mstro_schema_lookup_type(dict->schema, attr->typespec, &tdecl); if(status!=MSTRO_OK) { @@ -1809,8 +1935,8 @@ mstro_attribute_dict__insert_default(mstro_attribute_dict dict, ERR("Cannot allocate default entry\n"); goto BAILOUT; } + entry->kind=tdecl->parsed_type->kind; - status = mstro_attribute_entry__set_size(entry, entry->kind); if(status!=MSTRO_OK) { ERR("Cannot set entry size\n"); @@ -1853,7 +1979,7 @@ mstro_attribute_dict__insert_default(mstro_attribute_dict dict, status=MSTRO_UNIMPL; goto BAILOUT; } - + if(must_insert) { HASH_ADD(hh, dict->dict, key, sizeof(mstro_symbol), entry); } @@ -1918,6 +2044,10 @@ mstro_attribute_dict_get(mstro_attribute_dict dict, DEBUG("Key |%s| found, but no value in attribute dictionary at %p, fetching default\n", fqkey, dict); status = mstro_attribute_dict__insert_default(dict, sym); + if(status==MSTRO_NOENT) { + DEBUG("Key |%s| has no default value in schema\n", fqkey); + goto BAILOUT; + } if(status!=MSTRO_OK) { ERR("Failed to insert default value for attribute %s\n", fqkey); goto BAILOUT; @@ -1999,6 +2129,8 @@ mstro_attribute_dict_set(mstro_attribute_dict dict, const char *key, } fqkey = key; + DEBUG("Setting value for |%s|\n", fqkey); + status = mstro_schema_lookup_symbol(dict->schema, fqkey, &sym); if(sym==NULL) { DEBUG("Key |%s| not found in schema %s (V%zu)\n", @@ -2016,7 +2148,6 @@ mstro_attribute_dict_set(mstro_attribute_dict dict, const char *key, DEBUG("Key |%s| found, but no value in attribute dictionary at %p, adding it\n", fqkey, dict); /* lookup key in schema */ - /* FIXME: this should move to a 'ensure_default_entry' function that is shared */ struct mstro_schema_attribute_ *decl; status = mstro_schema_lookup_attribute(dict->schema, fqkey, &decl); if(status!=MSTRO_OK) { @@ -2043,21 +2174,24 @@ mstro_attribute_dict_set(mstro_attribute_dict dict, const char *key, * (needs to be reentrant!) built with a schema-typeval.peg */ if(!tdecl->parsed_type) { ERR("Parsed type not available\n"); - return MSTRO_UNIMPL; + return MSTRO_UNIMPL; } /* create fresh entry */ status = mstro_attribute_entry_create(decl->key_symbol, &entry); - if(status!=MSTRO_OK) + if(status!=MSTRO_OK) { + ERR("Failed to create new entry for |%s|\n", fqkey); goto BAILOUT; + } entry->kind = tdecl->parsed_type->kind; - status = mstro_attribute_entry__set_size(entry, entry->kind); - if(status!=MSTRO_OK) - goto BAILOUT; HASH_ADD(hh, dict->dict, key, sizeof(mstro_symbol), entry); + DEBUG("Added fresh entry for |%s|\n", fqkey); + } else { + DEBUG("Found existing entry for |%s|, updating\n", fqkey); } + /* some lax type checking */ if(valtype) { @@ -2113,6 +2247,27 @@ mstro_attribute_dict_set(mstro_attribute_dict dict, const char *key, entry->val = val; entry->user_owned_val = true; + status = mstro_attribute_entry__set_size(entry, entry->kind); + if(status!=MSTRO_OK) { + ERR("Failed to set entry size for |%s|\n", fqkey); + goto BAILOUT; + } + + DEBUG("Set value on entry |%s|\n", fqkey); + + switch(entry->kind) { + case MSTRO_STP_STR: + case MSTRO_STP_REGEX: + /* adjust value size */ + entry->valsize = strlen(entry->val); + break; + case MSTRO_STP_BLOB: + entry->valsize = ((mstro_blob*)entry->val)->len; + break; + default: + break; + } + status=MSTRO_OK; BAILOUT: diff --git a/attributes/symtab.c b/attributes/symtab.c index 265e873d..d2686731 100644 --- a/attributes/symtab.c +++ b/attributes/symtab.c @@ -32,7 +32,7 @@ struct mstro_symtab_entry_key { const void *permanent_address; /**< set to the address of constants * that get interned. NULL for 'not * permanent' */ - char fullname[0]; /**< the fully-qualified name; + char fullname[]; /**< the fully-qualified name; * auto-extended at mstro_intern * time */ }; -- GitLab