structure FEATURE support for ietf-yang-structure-ext
Only for the structure itself, no augment yet.
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 50783a2..faad765 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -151,6 +151,7 @@
src/plugins_exts/nacm.c
src/plugins_exts/yangdata.c
src/plugins_exts/schema_mount.c
+ src/plugins_exts/structure.c
src/xml.c
src/xpath.c
src/validation.c
diff --git a/README.md b/README.md
index e89fd27..05e55d2 100644
--- a/README.md
+++ b/README.md
@@ -43,6 +43,7 @@
* Support for YANG extensions.
* Support for YANG Metadata ([RFC 7952](https://tools.ietf.org/html/rfc7952)).
* Support for YANG Schema Mount ([RFC 8528](https://tools.ietf.org/html/rfc8528)).
+* Support for YANG Structure ([RFC 8791](https://tools.ietf.org/html/rfc8791)).
* [yanglint](#yanglint) - feature-rich YANG tool.
Current implementation covers YANG 1.0 ([RFC 6020](https://tools.ietf.org/html/rfc6020))
diff --git a/models/ietf-yang-structure-ext@2020-06-17.h b/models/ietf-yang-structure-ext@2020-06-17.h
new file mode 100644
index 0000000..f90d254
--- /dev/null
+++ b/models/ietf-yang-structure-ext@2020-06-17.h
@@ -0,0 +1,635 @@
+char ietf_yang_structure_ext_2020_06_17_yang[] = {
+ 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x20, 0x69, 0x65, 0x74, 0x66, 0x2d,
+ 0x79, 0x61, 0x6e, 0x67, 0x2d, 0x73, 0x74, 0x72, 0x75, 0x63, 0x74, 0x75,
+ 0x72, 0x65, 0x2d, 0x65, 0x78, 0x74, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x79,
+ 0x61, 0x6e, 0x67, 0x2d, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x20,
+ 0x31, 0x2e, 0x31, 0x3b, 0x0a, 0x20, 0x20, 0x6e, 0x61, 0x6d, 0x65, 0x73,
+ 0x70, 0x61, 0x63, 0x65, 0x20, 0x22, 0x75, 0x72, 0x6e, 0x3a, 0x69, 0x65,
+ 0x74, 0x66, 0x3a, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x3a, 0x78, 0x6d,
+ 0x6c, 0x3a, 0x6e, 0x73, 0x3a, 0x79, 0x61, 0x6e, 0x67, 0x3a, 0x69, 0x65,
+ 0x74, 0x66, 0x2d, 0x79, 0x61, 0x6e, 0x67, 0x2d, 0x73, 0x74, 0x72, 0x75,
+ 0x63, 0x74, 0x75, 0x72, 0x65, 0x2d, 0x65, 0x78, 0x74, 0x22, 0x3b, 0x0a,
+ 0x20, 0x20, 0x70, 0x72, 0x65, 0x66, 0x69, 0x78, 0x20, 0x73, 0x78, 0x3b,
+ 0x0a, 0x0a, 0x20, 0x20, 0x6f, 0x72, 0x67, 0x61, 0x6e, 0x69, 0x7a, 0x61,
+ 0x74, 0x69, 0x6f, 0x6e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x22, 0x49, 0x45,
+ 0x54, 0x46, 0x20, 0x4e, 0x45, 0x54, 0x4d, 0x4f, 0x44, 0x20, 0x28, 0x4e,
+ 0x45, 0x54, 0x43, 0x4f, 0x4e, 0x46, 0x20, 0x44, 0x61, 0x74, 0x61, 0x20,
+ 0x4d, 0x6f, 0x64, 0x65, 0x6c, 0x69, 0x6e, 0x67, 0x20, 0x4c, 0x61, 0x6e,
+ 0x67, 0x75, 0x61, 0x67, 0x65, 0x29, 0x20, 0x57, 0x6f, 0x72, 0x6b, 0x69,
+ 0x6e, 0x67, 0x20, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x22, 0x3b, 0x0a, 0x20,
+ 0x20, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x63, 0x74, 0x0a, 0x20, 0x20, 0x20,
+ 0x20, 0x22, 0x57, 0x47, 0x20, 0x57, 0x65, 0x62, 0x3a, 0x20, 0x20, 0x20,
+ 0x3c, 0x68, 0x74, 0x74, 0x70, 0x73, 0x3a, 0x2f, 0x2f, 0x64, 0x61, 0x74,
+ 0x61, 0x74, 0x72, 0x61, 0x63, 0x6b, 0x65, 0x72, 0x2e, 0x69, 0x65, 0x74,
+ 0x66, 0x2e, 0x6f, 0x72, 0x67, 0x2f, 0x77, 0x67, 0x2f, 0x6e, 0x65, 0x74,
+ 0x6d, 0x6f, 0x64, 0x2f, 0x3e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x57,
+ 0x47, 0x20, 0x4c, 0x69, 0x73, 0x74, 0x3a, 0x20, 0x20, 0x3c, 0x6d, 0x61,
+ 0x69, 0x6c, 0x74, 0x6f, 0x3a, 0x6e, 0x65, 0x74, 0x6d, 0x6f, 0x64, 0x40,
+ 0x69, 0x65, 0x74, 0x66, 0x2e, 0x6f, 0x72, 0x67, 0x3e, 0x0a, 0x0a, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x3a, 0x20,
+ 0x20, 0x20, 0x41, 0x6e, 0x64, 0x79, 0x20, 0x42, 0x69, 0x65, 0x72, 0x6d,
+ 0x61, 0x6e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3c, 0x6d, 0x61, 0x69, 0x6c, 0x74,
+ 0x6f, 0x3a, 0x61, 0x6e, 0x64, 0x79, 0x40, 0x79, 0x75, 0x6d, 0x61, 0x77,
+ 0x6f, 0x72, 0x6b, 0x73, 0x2e, 0x63, 0x6f, 0x6d, 0x3e, 0x0a, 0x0a, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x3a, 0x20,
+ 0x20, 0x20, 0x4d, 0x61, 0x72, 0x74, 0x69, 0x6e, 0x20, 0x42, 0x6a, 0x6f,
+ 0x72, 0x6b, 0x6c, 0x75, 0x6e, 0x64, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3c, 0x6d,
+ 0x61, 0x69, 0x6c, 0x74, 0x6f, 0x3a, 0x6d, 0x62, 0x6a, 0x2b, 0x69, 0x65,
+ 0x74, 0x66, 0x40, 0x34, 0x36, 0x36, 0x38, 0x2e, 0x73, 0x65, 0x3e, 0x0a,
+ 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72,
+ 0x3a, 0x20, 0x20, 0x20, 0x4b, 0x65, 0x6e, 0x74, 0x20, 0x57, 0x61, 0x74,
+ 0x73, 0x65, 0x6e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3c, 0x6d, 0x61, 0x69, 0x6c,
+ 0x74, 0x6f, 0x3a, 0x6b, 0x65, 0x6e, 0x74, 0x2b, 0x69, 0x65, 0x74, 0x66,
+ 0x40, 0x77, 0x61, 0x74, 0x73, 0x65, 0x6e, 0x2e, 0x6e, 0x65, 0x74, 0x3e,
+ 0x22, 0x3b, 0x0a, 0x20, 0x20, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70,
+ 0x74, 0x69, 0x6f, 0x6e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x22, 0x54, 0x68,
+ 0x69, 0x73, 0x20, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x20, 0x63, 0x6f,
+ 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x73, 0x20, 0x63, 0x6f, 0x6e, 0x63, 0x65,
+ 0x70, 0x74, 0x75, 0x61, 0x6c, 0x20, 0x59, 0x41, 0x4e, 0x47, 0x20, 0x73,
+ 0x70, 0x65, 0x63, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e,
+ 0x73, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x64, 0x65, 0x66, 0x69, 0x6e, 0x69,
+ 0x6e, 0x67, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x61, 0x62, 0x73, 0x74,
+ 0x72, 0x61, 0x63, 0x74, 0x20, 0x64, 0x61, 0x74, 0x61, 0x20, 0x73, 0x74,
+ 0x72, 0x75, 0x63, 0x74, 0x75, 0x72, 0x65, 0x73, 0x2e, 0x0a, 0x0a, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x54, 0x68, 0x65, 0x20, 0x6b, 0x65, 0x79, 0x20,
+ 0x77, 0x6f, 0x72, 0x64, 0x73, 0x20, 0x27, 0x4d, 0x55, 0x53, 0x54, 0x27,
+ 0x2c, 0x20, 0x27, 0x4d, 0x55, 0x53, 0x54, 0x20, 0x4e, 0x4f, 0x54, 0x27,
+ 0x2c, 0x20, 0x27, 0x52, 0x45, 0x51, 0x55, 0x49, 0x52, 0x45, 0x44, 0x27,
+ 0x2c, 0x20, 0x27, 0x53, 0x48, 0x41, 0x4c, 0x4c, 0x27, 0x2c, 0x20, 0x27,
+ 0x53, 0x48, 0x41, 0x4c, 0x4c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x4e,
+ 0x4f, 0x54, 0x27, 0x2c, 0x20, 0x27, 0x53, 0x48, 0x4f, 0x55, 0x4c, 0x44,
+ 0x27, 0x2c, 0x20, 0x27, 0x53, 0x48, 0x4f, 0x55, 0x4c, 0x44, 0x20, 0x4e,
+ 0x4f, 0x54, 0x27, 0x2c, 0x20, 0x27, 0x52, 0x45, 0x43, 0x4f, 0x4d, 0x4d,
+ 0x45, 0x4e, 0x44, 0x45, 0x44, 0x27, 0x2c, 0x20, 0x27, 0x4e, 0x4f, 0x54,
+ 0x20, 0x52, 0x45, 0x43, 0x4f, 0x4d, 0x4d, 0x45, 0x4e, 0x44, 0x45, 0x44,
+ 0x27, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x27, 0x4d, 0x41, 0x59,
+ 0x27, 0x2c, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x27, 0x4f, 0x50, 0x54, 0x49,
+ 0x4f, 0x4e, 0x41, 0x4c, 0x27, 0x20, 0x69, 0x6e, 0x20, 0x74, 0x68, 0x69,
+ 0x73, 0x20, 0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x20, 0x61,
+ 0x72, 0x65, 0x20, 0x74, 0x6f, 0x20, 0x62, 0x65, 0x20, 0x69, 0x6e, 0x74,
+ 0x65, 0x72, 0x70, 0x72, 0x65, 0x74, 0x65, 0x64, 0x20, 0x61, 0x73, 0x0a,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x62,
+ 0x65, 0x64, 0x20, 0x69, 0x6e, 0x20, 0x42, 0x43, 0x50, 0x20, 0x31, 0x34,
+ 0x20, 0x28, 0x52, 0x46, 0x43, 0x20, 0x32, 0x31, 0x31, 0x39, 0x29, 0x20,
+ 0x28, 0x52, 0x46, 0x43, 0x20, 0x38, 0x31, 0x37, 0x34, 0x29, 0x20, 0x77,
+ 0x68, 0x65, 0x6e, 0x2c, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x6f, 0x6e, 0x6c,
+ 0x79, 0x20, 0x77, 0x68, 0x65, 0x6e, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x74, 0x68, 0x65, 0x79, 0x20, 0x61, 0x70, 0x70, 0x65, 0x61, 0x72,
+ 0x20, 0x69, 0x6e, 0x20, 0x61, 0x6c, 0x6c, 0x20, 0x63, 0x61, 0x70, 0x69,
+ 0x74, 0x61, 0x6c, 0x73, 0x2c, 0x20, 0x61, 0x73, 0x20, 0x73, 0x68, 0x6f,
+ 0x77, 0x6e, 0x20, 0x68, 0x65, 0x72, 0x65, 0x2e, 0x0a, 0x0a, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x43, 0x6f, 0x70, 0x79, 0x72, 0x69, 0x67, 0x68, 0x74,
+ 0x20, 0x28, 0x63, 0x29, 0x20, 0x32, 0x30, 0x32, 0x30, 0x20, 0x49, 0x45,
+ 0x54, 0x46, 0x20, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, 0x61, 0x6e, 0x64,
+ 0x20, 0x74, 0x68, 0x65, 0x20, 0x70, 0x65, 0x72, 0x73, 0x6f, 0x6e, 0x73,
+ 0x20, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x64, 0x20,
+ 0x61, 0x73, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x61, 0x75, 0x74, 0x68,
+ 0x6f, 0x72, 0x73, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63,
+ 0x6f, 0x64, 0x65, 0x2e, 0x20, 0x20, 0x41, 0x6c, 0x6c, 0x20, 0x72, 0x69,
+ 0x67, 0x68, 0x74, 0x73, 0x20, 0x72, 0x65, 0x73, 0x65, 0x72, 0x76, 0x65,
+ 0x64, 0x2e, 0x0a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x52, 0x65, 0x64,
+ 0x69, 0x73, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x20,
+ 0x61, 0x6e, 0x64, 0x20, 0x75, 0x73, 0x65, 0x20, 0x69, 0x6e, 0x20, 0x73,
+ 0x6f, 0x75, 0x72, 0x63, 0x65, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x62, 0x69,
+ 0x6e, 0x61, 0x72, 0x79, 0x20, 0x66, 0x6f, 0x72, 0x6d, 0x73, 0x2c, 0x20,
+ 0x77, 0x69, 0x74, 0x68, 0x20, 0x6f, 0x72, 0x0a, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x77, 0x69, 0x74, 0x68, 0x6f, 0x75, 0x74, 0x20, 0x6d, 0x6f, 0x64,
+ 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2c, 0x20, 0x69,
+ 0x73, 0x20, 0x70, 0x65, 0x72, 0x6d, 0x69, 0x74, 0x74, 0x65, 0x64, 0x20,
+ 0x70, 0x75, 0x72, 0x73, 0x75, 0x61, 0x6e, 0x74, 0x20, 0x74, 0x6f, 0x2c,
+ 0x20, 0x61, 0x6e, 0x64, 0x20, 0x73, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74,
+ 0x20, 0x74, 0x6f, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x74, 0x68, 0x65,
+ 0x20, 0x6c, 0x69, 0x63, 0x65, 0x6e, 0x73, 0x65, 0x20, 0x74, 0x65, 0x72,
+ 0x6d, 0x73, 0x20, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x64,
+ 0x20, 0x69, 0x6e, 0x2c, 0x20, 0x74, 0x68, 0x65, 0x20, 0x53, 0x69, 0x6d,
+ 0x70, 0x6c, 0x69, 0x66, 0x69, 0x65, 0x64, 0x20, 0x42, 0x53, 0x44, 0x20,
+ 0x4c, 0x69, 0x63, 0x65, 0x6e, 0x73, 0x65, 0x20, 0x73, 0x65, 0x74, 0x0a,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x66, 0x6f, 0x72, 0x74, 0x68, 0x20, 0x69,
+ 0x6e, 0x20, 0x53, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x34, 0x2e,
+ 0x63, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x49, 0x45, 0x54,
+ 0x46, 0x20, 0x54, 0x72, 0x75, 0x73, 0x74, 0x27, 0x73, 0x20, 0x4c, 0x65,
+ 0x67, 0x61, 0x6c, 0x20, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f,
+ 0x6e, 0x73, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x52, 0x65, 0x6c, 0x61,
+ 0x74, 0x69, 0x6e, 0x67, 0x20, 0x74, 0x6f, 0x20, 0x49, 0x45, 0x54, 0x46,
+ 0x20, 0x44, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x0a, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x28, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f,
+ 0x74, 0x72, 0x75, 0x73, 0x74, 0x65, 0x65, 0x2e, 0x69, 0x65, 0x74, 0x66,
+ 0x2e, 0x6f, 0x72, 0x67, 0x2f, 0x6c, 0x69, 0x63, 0x65, 0x6e, 0x73, 0x65,
+ 0x2d, 0x69, 0x6e, 0x66, 0x6f, 0x29, 0x2e, 0x0a, 0x0a, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x54, 0x68, 0x69, 0x73, 0x20, 0x76, 0x65, 0x72, 0x73, 0x69,
+ 0x6f, 0x6e, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x69, 0x73, 0x20, 0x59,
+ 0x41, 0x4e, 0x47, 0x20, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x20, 0x69,
+ 0x73, 0x20, 0x70, 0x61, 0x72, 0x74, 0x20, 0x6f, 0x66, 0x20, 0x52, 0x46,
+ 0x43, 0x20, 0x38, 0x37, 0x39, 0x31, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x28, 0x68, 0x74, 0x74, 0x70, 0x73, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77,
+ 0x2e, 0x72, 0x66, 0x63, 0x2d, 0x65, 0x64, 0x69, 0x74, 0x6f, 0x72, 0x2e,
+ 0x6f, 0x72, 0x67, 0x2f, 0x69, 0x6e, 0x66, 0x6f, 0x2f, 0x72, 0x66, 0x63,
+ 0x38, 0x37, 0x39, 0x31, 0x29, 0x3b, 0x20, 0x73, 0x65, 0x65, 0x20, 0x74,
+ 0x68, 0x65, 0x20, 0x52, 0x46, 0x43, 0x20, 0x69, 0x74, 0x73, 0x65, 0x6c,
+ 0x66, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x66,
+ 0x75, 0x6c, 0x6c, 0x20, 0x6c, 0x65, 0x67, 0x61, 0x6c, 0x20, 0x6e, 0x6f,
+ 0x74, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x22, 0x3b, 0x0a, 0x0a, 0x20, 0x20,
+ 0x72, 0x65, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x20, 0x32, 0x30, 0x32,
+ 0x30, 0x2d, 0x30, 0x36, 0x2d, 0x31, 0x37, 0x20, 0x7b, 0x0a, 0x20, 0x20,
+ 0x20, 0x20, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f,
+ 0x6e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x49, 0x6e, 0x69,
+ 0x74, 0x69, 0x61, 0x6c, 0x20, 0x72, 0x65, 0x76, 0x69, 0x73, 0x69, 0x6f,
+ 0x6e, 0x2e, 0x22, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x66,
+ 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x22, 0x52, 0x46, 0x43, 0x20, 0x38, 0x37, 0x39, 0x31, 0x3a, 0x20,
+ 0x59, 0x41, 0x4e, 0x47, 0x20, 0x44, 0x61, 0x74, 0x61, 0x20, 0x53, 0x74,
+ 0x72, 0x75, 0x63, 0x74, 0x75, 0x72, 0x65, 0x20, 0x45, 0x78, 0x74, 0x65,
+ 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x22, 0x3b, 0x0a, 0x20, 0x20,
+ 0x7d, 0x0a, 0x0a, 0x20, 0x20, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69,
+ 0x6f, 0x6e, 0x20, 0x73, 0x74, 0x72, 0x75, 0x63, 0x74, 0x75, 0x72, 0x65,
+ 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x61, 0x72, 0x67, 0x75, 0x6d,
+ 0x65, 0x6e, 0x74, 0x20, 0x6e, 0x61, 0x6d, 0x65, 0x20, 0x7b, 0x0a, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x79, 0x69, 0x6e, 0x2d, 0x65, 0x6c, 0x65,
+ 0x6d, 0x65, 0x6e, 0x74, 0x20, 0x74, 0x72, 0x75, 0x65, 0x3b, 0x0a, 0x20,
+ 0x20, 0x20, 0x20, 0x7d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x64, 0x65, 0x73,
+ 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x0a, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x22, 0x54, 0x68, 0x69, 0x73, 0x20, 0x65, 0x78, 0x74,
+ 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x20, 0x69, 0x73, 0x20, 0x75, 0x73,
+ 0x65, 0x64, 0x20, 0x74, 0x6f, 0x20, 0x73, 0x70, 0x65, 0x63, 0x69, 0x66,
+ 0x79, 0x20, 0x61, 0x20, 0x59, 0x41, 0x4e, 0x47, 0x20, 0x64, 0x61, 0x74,
+ 0x61, 0x20, 0x73, 0x74, 0x72, 0x75, 0x63, 0x74, 0x75, 0x72, 0x65, 0x20,
+ 0x74, 0x68, 0x61, 0x74, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x72, 0x65, 0x70, 0x72, 0x65, 0x73, 0x65, 0x6e, 0x74, 0x73, 0x20, 0x63,
+ 0x6f, 0x6e, 0x63, 0x65, 0x70, 0x74, 0x75, 0x61, 0x6c, 0x20, 0x64, 0x61,
+ 0x74, 0x61, 0x20, 0x64, 0x65, 0x66, 0x69, 0x6e, 0x65, 0x64, 0x20, 0x69,
+ 0x6e, 0x20, 0x59, 0x41, 0x4e, 0x47, 0x2e, 0x20, 0x20, 0x49, 0x74, 0x20,
+ 0x69, 0x73, 0x20, 0x69, 0x6e, 0x74, 0x65, 0x6e, 0x64, 0x65, 0x64, 0x20,
+ 0x74, 0x6f, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x64, 0x65,
+ 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x20, 0x68, 0x69, 0x65, 0x72, 0x61,
+ 0x72, 0x63, 0x68, 0x69, 0x63, 0x61, 0x6c, 0x20, 0x64, 0x61, 0x74, 0x61,
+ 0x20, 0x69, 0x6e, 0x64, 0x65, 0x70, 0x65, 0x6e, 0x64, 0x65, 0x6e, 0x74,
+ 0x20, 0x6f, 0x66, 0x20, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c,
+ 0x20, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x20, 0x6f, 0x72, 0x0a,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x73, 0x70, 0x65, 0x63, 0x69,
+ 0x66, 0x69, 0x63, 0x20, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x20,
+ 0x65, 0x6e, 0x63, 0x6f, 0x64, 0x69, 0x6e, 0x67, 0x20, 0x66, 0x6f, 0x72,
+ 0x6d, 0x61, 0x74, 0x2e, 0x20, 0x20, 0x44, 0x61, 0x74, 0x61, 0x20, 0x64,
+ 0x65, 0x66, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x73, 0x74,
+ 0x61, 0x74, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x0a, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x77, 0x69, 0x74, 0x68, 0x69, 0x6e, 0x20, 0x61,
+ 0x20, 0x27, 0x73, 0x74, 0x72, 0x75, 0x63, 0x74, 0x75, 0x72, 0x65, 0x27,
+ 0x20, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x20, 0x73,
+ 0x74, 0x61, 0x74, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x20, 0x73, 0x70, 0x65,
+ 0x63, 0x69, 0x66, 0x79, 0x20, 0x74, 0x68, 0x65, 0x20, 0x67, 0x65, 0x6e,
+ 0x65, 0x72, 0x69, 0x63, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x73, 0x79, 0x6e, 0x74, 0x61, 0x78, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x74,
+ 0x68, 0x65, 0x20, 0x73, 0x70, 0x65, 0x63, 0x69, 0x66, 0x69, 0x63, 0x20,
+ 0x59, 0x41, 0x4e, 0x47, 0x20, 0x64, 0x61, 0x74, 0x61, 0x20, 0x73, 0x74,
+ 0x72, 0x75, 0x63, 0x74, 0x75, 0x72, 0x65, 0x2c, 0x20, 0x77, 0x68, 0x6f,
+ 0x73, 0x65, 0x20, 0x6e, 0x61, 0x6d, 0x65, 0x20, 0x69, 0x73, 0x20, 0x74,
+ 0x68, 0x65, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x61, 0x72,
+ 0x67, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68,
+ 0x65, 0x20, 0x27, 0x73, 0x74, 0x72, 0x75, 0x63, 0x74, 0x75, 0x72, 0x65,
+ 0x27, 0x20, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x20,
+ 0x73, 0x74, 0x61, 0x74, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x0a, 0x0a,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x4e, 0x6f, 0x74, 0x65, 0x20,
+ 0x74, 0x68, 0x61, 0x74, 0x20, 0x74, 0x68, 0x69, 0x73, 0x20, 0x65, 0x78,
+ 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x20, 0x64, 0x6f, 0x65, 0x73,
+ 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x64, 0x65, 0x66, 0x69, 0x6e, 0x65, 0x20,
+ 0x61, 0x20, 0x6d, 0x65, 0x64, 0x69, 0x61, 0x20, 0x74, 0x79, 0x70, 0x65,
+ 0x2e, 0x20, 0x20, 0x41, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x73, 0x70, 0x65, 0x63, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f,
+ 0x6e, 0x20, 0x75, 0x73, 0x69, 0x6e, 0x67, 0x20, 0x74, 0x68, 0x69, 0x73,
+ 0x20, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x20, 0x4d,
+ 0x55, 0x53, 0x54, 0x20, 0x73, 0x70, 0x65, 0x63, 0x69, 0x66, 0x79, 0x20,
+ 0x74, 0x68, 0x65, 0x20, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x0a,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x65, 0x6e, 0x63, 0x6f, 0x64,
+ 0x69, 0x6e, 0x67, 0x20, 0x72, 0x75, 0x6c, 0x65, 0x73, 0x2c, 0x20, 0x69,
+ 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x69, 0x6e, 0x67, 0x20, 0x74, 0x68, 0x65,
+ 0x20, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x20, 0x6d, 0x65, 0x64,
+ 0x69, 0x61, 0x20, 0x74, 0x79, 0x70, 0x65, 0x2c, 0x20, 0x69, 0x66, 0x0a,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69,
+ 0x63, 0x61, 0x62, 0x6c, 0x65, 0x2e, 0x0a, 0x0a, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x54, 0x68, 0x65, 0x20, 0x6d, 0x61, 0x6e, 0x64, 0x61,
+ 0x74, 0x6f, 0x72, 0x79, 0x20, 0x27, 0x6e, 0x61, 0x6d, 0x65, 0x27, 0x20,
+ 0x70, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x20, 0x76, 0x61,
+ 0x6c, 0x75, 0x65, 0x20, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69,
+ 0x65, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, 0x59, 0x41, 0x4e, 0x47, 0x20,
+ 0x64, 0x61, 0x74, 0x61, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x73, 0x74, 0x72, 0x75, 0x63, 0x74, 0x75, 0x72, 0x65, 0x20, 0x74, 0x68,
+ 0x61, 0x74, 0x20, 0x69, 0x73, 0x20, 0x62, 0x65, 0x69, 0x6e, 0x67, 0x20,
+ 0x64, 0x65, 0x66, 0x69, 0x6e, 0x65, 0x64, 0x2e, 0x0a, 0x0a, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x54, 0x68, 0x69, 0x73, 0x20, 0x65, 0x78,
+ 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x20, 0x69, 0x73, 0x20, 0x6f,
+ 0x6e, 0x6c, 0x79, 0x20, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x20, 0x61, 0x73,
+ 0x20, 0x61, 0x20, 0x74, 0x6f, 0x70, 0x2d, 0x6c, 0x65, 0x76, 0x65, 0x6c,
+ 0x20, 0x73, 0x74, 0x61, 0x74, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x2c, 0x20,
+ 0x69, 0x2e, 0x65, 0x2e, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x67, 0x69, 0x76, 0x65, 0x6e, 0x20, 0x61, 0x73, 0x20, 0x61, 0x20,
+ 0x73, 0x75, 0x62, 0x73, 0x74, 0x61, 0x74, 0x65, 0x6d, 0x65, 0x6e, 0x74,
+ 0x20, 0x74, 0x6f, 0x20, 0x27, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x27,
+ 0x20, 0x6f, 0x72, 0x20, 0x27, 0x73, 0x75, 0x62, 0x6d, 0x6f, 0x64, 0x75,
+ 0x6c, 0x65, 0x27, 0x2e, 0x0a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x54, 0x68, 0x65, 0x20, 0x73, 0x75, 0x62, 0x73, 0x74, 0x61, 0x74,
+ 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68,
+ 0x69, 0x73, 0x20, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e,
+ 0x20, 0x4d, 0x55, 0x53, 0x54, 0x20, 0x66, 0x6f, 0x6c, 0x6c, 0x6f, 0x77,
+ 0x20, 0x74, 0x68, 0x65, 0x20, 0x41, 0x42, 0x4e, 0x46, 0x0a, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x72, 0x75, 0x6c, 0x65, 0x73, 0x20, 0x62,
+ 0x65, 0x6c, 0x6f, 0x77, 0x2c, 0x20, 0x77, 0x68, 0x65, 0x72, 0x65, 0x20,
+ 0x74, 0x68, 0x65, 0x20, 0x72, 0x75, 0x6c, 0x65, 0x73, 0x20, 0x61, 0x72,
+ 0x65, 0x20, 0x64, 0x65, 0x66, 0x69, 0x6e, 0x65, 0x64, 0x20, 0x69, 0x6e,
+ 0x20, 0x52, 0x46, 0x43, 0x20, 0x37, 0x39, 0x35, 0x30, 0x3a, 0x0a, 0x0a,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x2a,
+ 0x6d, 0x75, 0x73, 0x74, 0x2d, 0x73, 0x74, 0x6d, 0x74, 0x0a, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x5b, 0x73, 0x74,
+ 0x61, 0x74, 0x75, 0x73, 0x2d, 0x73, 0x74, 0x6d, 0x74, 0x5d, 0x0a, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x5b, 0x64,
+ 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x2d, 0x73,
+ 0x74, 0x6d, 0x74, 0x5d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x5b, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e,
+ 0x63, 0x65, 0x2d, 0x73, 0x74, 0x6d, 0x74, 0x5d, 0x0a, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x2a, 0x28, 0x74, 0x79,
+ 0x70, 0x65, 0x64, 0x65, 0x66, 0x2d, 0x73, 0x74, 0x6d, 0x74, 0x20, 0x2f,
+ 0x20, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x69, 0x6e, 0x67, 0x2d, 0x73, 0x74,
+ 0x6d, 0x74, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x2a, 0x64, 0x61, 0x74, 0x61, 0x2d, 0x64, 0x65, 0x66,
+ 0x2d, 0x73, 0x74, 0x6d, 0x74, 0x0a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x41, 0x20, 0x59, 0x41, 0x4e, 0x47, 0x20, 0x64, 0x61, 0x74,
+ 0x61, 0x20, 0x73, 0x74, 0x72, 0x75, 0x63, 0x74, 0x75, 0x72, 0x65, 0x20,
+ 0x64, 0x65, 0x66, 0x69, 0x6e, 0x65, 0x64, 0x20, 0x77, 0x69, 0x74, 0x68,
+ 0x20, 0x74, 0x68, 0x69, 0x73, 0x20, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73,
+ 0x69, 0x6f, 0x6e, 0x20, 0x73, 0x74, 0x61, 0x74, 0x65, 0x6d, 0x65, 0x6e,
+ 0x74, 0x20, 0x69, 0x73, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x65, 0x6e, 0x63, 0x6f, 0x64, 0x65, 0x64, 0x20, 0x69, 0x6e, 0x20, 0x74,
+ 0x68, 0x65, 0x20, 0x73, 0x61, 0x6d, 0x65, 0x20, 0x77, 0x61, 0x79, 0x20,
+ 0x61, 0x73, 0x20, 0x61, 0x6e, 0x20, 0x27, 0x61, 0x6e, 0x79, 0x64, 0x61,
+ 0x74, 0x61, 0x27, 0x20, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x20, 0x20, 0x54,
+ 0x68, 0x69, 0x73, 0x20, 0x6d, 0x65, 0x61, 0x6e, 0x73, 0x0a, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x74, 0x68,
+ 0x65, 0x20, 0x6e, 0x61, 0x6d, 0x65, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68,
+ 0x65, 0x20, 0x73, 0x74, 0x72, 0x75, 0x63, 0x74, 0x75, 0x72, 0x65, 0x20,
+ 0x69, 0x73, 0x20, 0x65, 0x6e, 0x63, 0x6f, 0x64, 0x65, 0x64, 0x20, 0x61,
+ 0x73, 0x20, 0x61, 0x20, 0x27, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e,
+ 0x65, 0x72, 0x27, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x77, 0x69, 0x74, 0x68, 0x20, 0x74, 0x68, 0x65, 0x20, 0x69, 0x6e, 0x73,
+ 0x74, 0x61, 0x6e, 0x74, 0x69, 0x61, 0x74, 0x65, 0x64, 0x20, 0x63, 0x68,
+ 0x69, 0x6c, 0x64, 0x20, 0x73, 0x74, 0x61, 0x74, 0x65, 0x6d, 0x65, 0x6e,
+ 0x74, 0x73, 0x20, 0x65, 0x6e, 0x63, 0x6f, 0x64, 0x65, 0x64, 0x20, 0x61,
+ 0x73, 0x20, 0x63, 0x68, 0x69, 0x6c, 0x64, 0x20, 0x6e, 0x6f, 0x64, 0x65,
+ 0x73, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x74, 0x6f, 0x20,
+ 0x74, 0x68, 0x69, 0x73, 0x20, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x0a, 0x0a,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x54, 0x68, 0x65, 0x20, 0x6d,
+ 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x20, 0x6e, 0x61, 0x6d, 0x65, 0x20, 0x61,
+ 0x6e, 0x64, 0x20, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65,
+ 0x20, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x74,
+ 0x68, 0x65, 0x20, 0x59, 0x41, 0x4e, 0x47, 0x20, 0x6d, 0x6f, 0x64, 0x75,
+ 0x6c, 0x65, 0x20, 0x75, 0x73, 0x69, 0x6e, 0x67, 0x0a, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x74, 0x68, 0x65, 0x20, 0x65, 0x78, 0x74, 0x65,
+ 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x20, 0x73, 0x74, 0x61, 0x74, 0x65, 0x6d,
+ 0x65, 0x6e, 0x74, 0x20, 0x61, 0x72, 0x65, 0x20, 0x61, 0x73, 0x73, 0x69,
+ 0x67, 0x6e, 0x65, 0x64, 0x20, 0x74, 0x6f, 0x20, 0x65, 0x61, 0x63, 0x68,
+ 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x64, 0x61, 0x74, 0x61,
+ 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x64, 0x65, 0x66, 0x69,
+ 0x6e, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x73, 0x74, 0x61, 0x74, 0x65,
+ 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x20, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74,
+ 0x69, 0x6e, 0x67, 0x20, 0x66, 0x72, 0x6f, 0x6d, 0x20, 0x74, 0x68, 0x65,
+ 0x20, 0x59, 0x41, 0x4e, 0x47, 0x20, 0x64, 0x61, 0x74, 0x61, 0x20, 0x73,
+ 0x74, 0x72, 0x75, 0x63, 0x74, 0x75, 0x72, 0x65, 0x2e, 0x0a, 0x0a, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x54, 0x68, 0x65, 0x20, 0x58, 0x50,
+ 0x61, 0x74, 0x68, 0x20, 0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74,
+ 0x20, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x20, 0x69, 0x73, 0x20,
+ 0x74, 0x68, 0x65, 0x20, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f,
+ 0x6e, 0x20, 0x73, 0x74, 0x61, 0x74, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x20,
+ 0x69, 0x74, 0x73, 0x65, 0x6c, 0x66, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x73, 0x75, 0x63, 0x68, 0x20, 0x74, 0x68, 0x61, 0x74,
+ 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x68, 0x69, 0x6c, 0x64, 0x20, 0x6e,
+ 0x6f, 0x64, 0x65, 0x73, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20,
+ 0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x20, 0x65, 0x6c, 0x65,
+ 0x6d, 0x65, 0x6e, 0x74, 0x20, 0x61, 0x72, 0x65, 0x0a, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x70, 0x72, 0x65, 0x73, 0x65, 0x6e,
+ 0x74, 0x65, 0x64, 0x20, 0x62, 0x79, 0x20, 0x74, 0x68, 0x65, 0x20, 0x64,
+ 0x61, 0x74, 0x61, 0x2d, 0x64, 0x65, 0x66, 0x2d, 0x73, 0x74, 0x6d, 0x74,
+ 0x20, 0x73, 0x75, 0x62, 0x73, 0x74, 0x61, 0x74, 0x65, 0x6d, 0x65, 0x6e,
+ 0x74, 0x73, 0x20, 0x77, 0x69, 0x74, 0x68, 0x69, 0x6e, 0x20, 0x74, 0x68,
+ 0x69, 0x73, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x65, 0x78,
+ 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x2e, 0x20, 0x20, 0x54, 0x68,
+ 0x69, 0x73, 0x20, 0x63, 0x6f, 0x6e, 0x63, 0x65, 0x70, 0x74, 0x75, 0x61,
+ 0x6c, 0x20, 0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x20, 0x69,
+ 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x78,
+ 0x74, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x74, 0x68, 0x65, 0x0a, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x66, 0x6f, 0x6c, 0x6c, 0x6f, 0x77, 0x69,
+ 0x6e, 0x67, 0x20, 0x59, 0x41, 0x4e, 0x47, 0x20, 0x73, 0x74, 0x61, 0x74,
+ 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x3a, 0x0a, 0x0a, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x2d, 0x20, 0x6d, 0x75,
+ 0x73, 0x74, 0x2d, 0x73, 0x74, 0x6d, 0x74, 0x0a, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x2d, 0x20, 0x77, 0x68, 0x65,
+ 0x6e, 0x2d, 0x73, 0x74, 0x6d, 0x74, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x2d, 0x20, 0x70, 0x61, 0x74, 0x68,
+ 0x2d, 0x73, 0x74, 0x6d, 0x74, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x2d, 0x20, 0x6d, 0x69, 0x6e, 0x2d, 0x65,
+ 0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x2d, 0x73, 0x74, 0x6d, 0x74,
+ 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x2d, 0x20, 0x6d, 0x61, 0x78, 0x2d, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x6e,
+ 0x74, 0x73, 0x2d, 0x73, 0x74, 0x6d, 0x74, 0x0a, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x2d, 0x20, 0x6d, 0x61, 0x6e,
+ 0x64, 0x61, 0x74, 0x6f, 0x72, 0x79, 0x2d, 0x73, 0x74, 0x6d, 0x74, 0x0a,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x2d,
+ 0x20, 0x75, 0x6e, 0x69, 0x71, 0x75, 0x65, 0x2d, 0x73, 0x74, 0x6d, 0x74,
+ 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x2d, 0x20, 0x6f, 0x72, 0x64, 0x65, 0x72, 0x65, 0x64, 0x2d, 0x62, 0x79,
+ 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x2d, 0x20, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x2d, 0x69,
+ 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x20, 0x64, 0x61,
+ 0x74, 0x61, 0x20, 0x74, 0x79, 0x70, 0x65, 0x0a, 0x0a, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x54, 0x68, 0x65, 0x20, 0x66, 0x6f, 0x6c, 0x6c,
+ 0x6f, 0x77, 0x69, 0x6e, 0x67, 0x20, 0x64, 0x61, 0x74, 0x61, 0x2d, 0x64,
+ 0x65, 0x66, 0x2d, 0x73, 0x74, 0x6d, 0x74, 0x20, 0x73, 0x75, 0x62, 0x73,
+ 0x74, 0x61, 0x74, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x20, 0x61, 0x72,
+ 0x65, 0x20, 0x63, 0x6f, 0x6e, 0x73, 0x74, 0x72, 0x61, 0x69, 0x6e, 0x65,
+ 0x64, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x77, 0x68, 0x65,
+ 0x6e, 0x20, 0x75, 0x73, 0x65, 0x64, 0x20, 0x77, 0x69, 0x74, 0x68, 0x69,
+ 0x6e, 0x20, 0x61, 0x20, 0x27, 0x73, 0x74, 0x72, 0x75, 0x63, 0x74, 0x75,
+ 0x72, 0x65, 0x27, 0x20, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f,
+ 0x6e, 0x20, 0x73, 0x74, 0x61, 0x74, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x2e,
+ 0x0a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x2d, 0x20, 0x54, 0x68, 0x65, 0x20, 0x6c, 0x69, 0x73, 0x74, 0x2d, 0x73,
+ 0x74, 0x6d, 0x74, 0x20, 0x69, 0x73, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x72,
+ 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x64, 0x20, 0x74, 0x6f, 0x20, 0x68,
+ 0x61, 0x76, 0x65, 0x20, 0x61, 0x20, 0x6b, 0x65, 0x79, 0x2d, 0x73, 0x74,
+ 0x6d, 0x74, 0x20, 0x64, 0x65, 0x66, 0x69, 0x6e, 0x65, 0x64, 0x2e, 0x0a,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x2d, 0x20,
+ 0x54, 0x68, 0x65, 0x20, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2d, 0x73,
+ 0x74, 0x6d, 0x74, 0x20, 0x69, 0x73, 0x20, 0x69, 0x67, 0x6e, 0x6f, 0x72,
+ 0x65, 0x64, 0x20, 0x69, 0x66, 0x20, 0x70, 0x72, 0x65, 0x73, 0x65, 0x6e,
+ 0x74, 0x2e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x3b,
+ 0x0a, 0x20, 0x20, 0x7d, 0x0a, 0x0a, 0x20, 0x20, 0x65, 0x78, 0x74, 0x65,
+ 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x20, 0x61, 0x75, 0x67, 0x6d, 0x65, 0x6e,
+ 0x74, 0x2d, 0x73, 0x74, 0x72, 0x75, 0x63, 0x74, 0x75, 0x72, 0x65, 0x20,
+ 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x61, 0x72, 0x67, 0x75, 0x6d, 0x65,
+ 0x6e, 0x74, 0x20, 0x70, 0x61, 0x74, 0x68, 0x20, 0x7b, 0x0a, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x79, 0x69, 0x6e, 0x2d, 0x65, 0x6c, 0x65, 0x6d,
+ 0x65, 0x6e, 0x74, 0x20, 0x74, 0x72, 0x75, 0x65, 0x3b, 0x0a, 0x20, 0x20,
+ 0x20, 0x20, 0x7d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x64, 0x65, 0x73, 0x63,
+ 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x0a, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x22, 0x54, 0x68, 0x69, 0x73, 0x20, 0x65, 0x78, 0x74, 0x65,
+ 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x20, 0x69, 0x73, 0x20, 0x75, 0x73, 0x65,
+ 0x64, 0x20, 0x74, 0x6f, 0x20, 0x73, 0x70, 0x65, 0x63, 0x69, 0x66, 0x79,
+ 0x20, 0x61, 0x6e, 0x20, 0x61, 0x75, 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x61,
+ 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x74, 0x6f, 0x20, 0x61, 0x20, 0x59, 0x41,
+ 0x4e, 0x47, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x64, 0x61,
+ 0x74, 0x61, 0x20, 0x73, 0x74, 0x72, 0x75, 0x63, 0x74, 0x75, 0x72, 0x65,
+ 0x20, 0x64, 0x65, 0x66, 0x69, 0x6e, 0x65, 0x64, 0x20, 0x77, 0x69, 0x74,
+ 0x68, 0x20, 0x74, 0x68, 0x65, 0x20, 0x27, 0x73, 0x74, 0x72, 0x75, 0x63,
+ 0x74, 0x75, 0x72, 0x65, 0x27, 0x20, 0x73, 0x74, 0x61, 0x74, 0x65, 0x6d,
+ 0x65, 0x6e, 0x74, 0x2e, 0x20, 0x20, 0x49, 0x74, 0x20, 0x69, 0x73, 0x0a,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x69, 0x6e, 0x74, 0x65, 0x6e,
+ 0x64, 0x65, 0x64, 0x20, 0x74, 0x6f, 0x20, 0x64, 0x65, 0x73, 0x63, 0x72,
+ 0x69, 0x62, 0x65, 0x20, 0x68, 0x69, 0x65, 0x72, 0x61, 0x72, 0x63, 0x68,
+ 0x69, 0x63, 0x61, 0x6c, 0x20, 0x64, 0x61, 0x74, 0x61, 0x20, 0x69, 0x6e,
+ 0x64, 0x65, 0x70, 0x65, 0x6e, 0x64, 0x65, 0x6e, 0x74, 0x20, 0x6f, 0x66,
+ 0x20, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x0a, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74,
+ 0x20, 0x6f, 0x72, 0x20, 0x73, 0x70, 0x65, 0x63, 0x69, 0x66, 0x69, 0x63,
+ 0x20, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x20, 0x65, 0x6e, 0x63,
+ 0x6f, 0x64, 0x69, 0x6e, 0x67, 0x20, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74,
+ 0x2e, 0x0a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x54, 0x68,
+ 0x69, 0x73, 0x20, 0x73, 0x74, 0x61, 0x74, 0x65, 0x6d, 0x65, 0x6e, 0x74,
+ 0x20, 0x68, 0x61, 0x73, 0x20, 0x61, 0x6c, 0x6d, 0x6f, 0x73, 0x74, 0x20,
+ 0x74, 0x68, 0x65, 0x20, 0x73, 0x61, 0x6d, 0x65, 0x20, 0x73, 0x74, 0x72,
+ 0x75, 0x63, 0x74, 0x75, 0x72, 0x65, 0x20, 0x61, 0x73, 0x20, 0x74, 0x68,
+ 0x65, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x27, 0x61, 0x75,
+ 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x2d, 0x73, 0x74, 0x6d, 0x74, 0x27, 0x2e,
+ 0x20, 0x20, 0x44, 0x61, 0x74, 0x61, 0x20, 0x64, 0x65, 0x66, 0x69, 0x6e,
+ 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x73, 0x74, 0x61, 0x74, 0x65, 0x6d,
+ 0x65, 0x6e, 0x74, 0x73, 0x20, 0x77, 0x69, 0x74, 0x68, 0x69, 0x6e, 0x20,
+ 0x74, 0x68, 0x69, 0x73, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x73, 0x74, 0x61, 0x74, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x20, 0x73, 0x70,
+ 0x65, 0x63, 0x69, 0x66, 0x79, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 0x65,
+ 0x6d, 0x61, 0x6e, 0x74, 0x69, 0x63, 0x73, 0x20, 0x61, 0x6e, 0x64, 0x20,
+ 0x67, 0x65, 0x6e, 0x65, 0x72, 0x69, 0x63, 0x20, 0x73, 0x79, 0x6e, 0x74,
+ 0x61, 0x78, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x74, 0x68, 0x65, 0x0a, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x61, 0x64, 0x64, 0x69, 0x74, 0x69,
+ 0x6f, 0x6e, 0x61, 0x6c, 0x20, 0x64, 0x61, 0x74, 0x61, 0x20, 0x74, 0x6f,
+ 0x20, 0x62, 0x65, 0x20, 0x61, 0x64, 0x64, 0x65, 0x64, 0x20, 0x74, 0x6f,
+ 0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 0x70, 0x65, 0x63, 0x69, 0x66, 0x69,
+ 0x63, 0x20, 0x59, 0x41, 0x4e, 0x47, 0x20, 0x64, 0x61, 0x74, 0x61, 0x0a,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x73, 0x74, 0x72, 0x75, 0x63,
+ 0x74, 0x75, 0x72, 0x65, 0x2c, 0x20, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69,
+ 0x66, 0x69, 0x65, 0x64, 0x20, 0x62, 0x79, 0x20, 0x74, 0x68, 0x65, 0x20,
+ 0x27, 0x70, 0x61, 0x74, 0x68, 0x27, 0x20, 0x61, 0x72, 0x67, 0x75, 0x6d,
+ 0x65, 0x6e, 0x74, 0x2e, 0x0a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x54, 0x68, 0x65, 0x20, 0x6d, 0x61, 0x6e, 0x64, 0x61, 0x74, 0x6f,
+ 0x72, 0x79, 0x20, 0x27, 0x70, 0x61, 0x74, 0x68, 0x27, 0x20, 0x70, 0x61,
+ 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x20, 0x76, 0x61, 0x6c, 0x75,
+ 0x65, 0x20, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x73,
+ 0x20, 0x74, 0x68, 0x65, 0x20, 0x59, 0x41, 0x4e, 0x47, 0x0a, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x63, 0x6f, 0x6e, 0x63, 0x65, 0x70, 0x74,
+ 0x75, 0x61, 0x6c, 0x20, 0x64, 0x61, 0x74, 0x61, 0x20, 0x6e, 0x6f, 0x64,
+ 0x65, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x69, 0x73, 0x20, 0x62, 0x65,
+ 0x69, 0x6e, 0x67, 0x20, 0x61, 0x75, 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x65,
+ 0x64, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x69, 0x73, 0x0a, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x70, 0x72, 0x65, 0x73, 0x65, 0x6e,
+ 0x74, 0x65, 0x64, 0x20, 0x61, 0x73, 0x20, 0x61, 0x6e, 0x20, 0x61, 0x62,
+ 0x73, 0x6f, 0x6c, 0x75, 0x74, 0x65, 0x2d, 0x73, 0x63, 0x68, 0x65, 0x6d,
+ 0x61, 0x2d, 0x6e, 0x6f, 0x64, 0x65, 0x69, 0x64, 0x20, 0x73, 0x74, 0x72,
+ 0x69, 0x6e, 0x67, 0x2c, 0x20, 0x77, 0x68, 0x65, 0x72, 0x65, 0x20, 0x74,
+ 0x68, 0x65, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x66, 0x69,
+ 0x72, 0x73, 0x74, 0x20, 0x6e, 0x6f, 0x64, 0x65, 0x20, 0x69, 0x6e, 0x20,
+ 0x74, 0x68, 0x65, 0x20, 0x61, 0x62, 0x73, 0x6f, 0x6c, 0x75, 0x74, 0x65,
+ 0x2d, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x2d, 0x6e, 0x6f, 0x64, 0x65,
+ 0x69, 0x64, 0x20, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x20, 0x69, 0x64,
+ 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x73, 0x20, 0x74, 0x68, 0x65,
+ 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x59, 0x41, 0x4e, 0x47,
+ 0x20, 0x64, 0x61, 0x74, 0x61, 0x20, 0x73, 0x74, 0x72, 0x75, 0x63, 0x74,
+ 0x75, 0x72, 0x65, 0x20, 0x74, 0x6f, 0x20, 0x61, 0x75, 0x67, 0x6d, 0x65,
+ 0x6e, 0x74, 0x2c, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x74, 0x68, 0x65, 0x20,
+ 0x72, 0x65, 0x73, 0x74, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20,
+ 0x6e, 0x6f, 0x64, 0x65, 0x73, 0x20, 0x69, 0x6e, 0x0a, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 0x74, 0x72, 0x69,
+ 0x6e, 0x67, 0x20, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65,
+ 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6e, 0x6f, 0x64, 0x65, 0x20, 0x77,
+ 0x69, 0x74, 0x68, 0x69, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x59, 0x41,
+ 0x4e, 0x47, 0x20, 0x73, 0x74, 0x72, 0x75, 0x63, 0x74, 0x75, 0x72, 0x65,
+ 0x20, 0x74, 0x6f, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x61,
+ 0x75, 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x0a, 0x0a, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x54, 0x68, 0x69, 0x73, 0x20, 0x65, 0x78, 0x74,
+ 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x20, 0x69, 0x73, 0x20, 0x6f, 0x6e,
+ 0x6c, 0x79, 0x20, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x20, 0x61, 0x73, 0x20,
+ 0x61, 0x20, 0x74, 0x6f, 0x70, 0x2d, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x20,
+ 0x73, 0x74, 0x61, 0x74, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x2c, 0x20, 0x69,
+ 0x2e, 0x65, 0x2e, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x67, 0x69, 0x76, 0x65, 0x6e, 0x20, 0x61, 0x73, 0x20, 0x61, 0x20, 0x73,
+ 0x75, 0x62, 0x73, 0x74, 0x61, 0x74, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x20,
+ 0x74, 0x6f, 0x20, 0x27, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x27, 0x20,
+ 0x6f, 0x72, 0x20, 0x27, 0x73, 0x75, 0x62, 0x6d, 0x6f, 0x64, 0x75, 0x6c,
+ 0x65, 0x27, 0x2e, 0x0a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x54, 0x68, 0x65, 0x20, 0x73, 0x75, 0x62, 0x73, 0x74, 0x61, 0x74, 0x65,
+ 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x69,
+ 0x73, 0x20, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x20,
+ 0x4d, 0x55, 0x53, 0x54, 0x20, 0x66, 0x6f, 0x6c, 0x6c, 0x6f, 0x77, 0x20,
+ 0x74, 0x68, 0x65, 0x20, 0x41, 0x42, 0x4e, 0x46, 0x0a, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x72, 0x75, 0x6c, 0x65, 0x73, 0x20, 0x62, 0x65,
+ 0x6c, 0x6f, 0x77, 0x2c, 0x20, 0x77, 0x68, 0x65, 0x72, 0x65, 0x20, 0x74,
+ 0x68, 0x65, 0x20, 0x72, 0x75, 0x6c, 0x65, 0x73, 0x20, 0x61, 0x72, 0x65,
+ 0x20, 0x64, 0x65, 0x66, 0x69, 0x6e, 0x65, 0x64, 0x20, 0x69, 0x6e, 0x20,
+ 0x52, 0x46, 0x43, 0x20, 0x37, 0x39, 0x35, 0x30, 0x3a, 0x0a, 0x0a, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x5b, 0x73,
+ 0x74, 0x61, 0x74, 0x75, 0x73, 0x2d, 0x73, 0x74, 0x6d, 0x74, 0x5d, 0x0a,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x5b,
+ 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x2d,
+ 0x73, 0x74, 0x6d, 0x74, 0x5d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x5b, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65,
+ 0x6e, 0x63, 0x65, 0x2d, 0x73, 0x74, 0x6d, 0x74, 0x5d, 0x0a, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x31, 0x2a, 0x28,
+ 0x64, 0x61, 0x74, 0x61, 0x2d, 0x64, 0x65, 0x66, 0x2d, 0x73, 0x74, 0x6d,
+ 0x74, 0x20, 0x2f, 0x20, 0x63, 0x61, 0x73, 0x65, 0x2d, 0x73, 0x74, 0x6d,
+ 0x74, 0x29, 0x0a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x54,
+ 0x68, 0x65, 0x20, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x20, 0x6e, 0x61,
+ 0x6d, 0x65, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x6e, 0x61, 0x6d, 0x65, 0x73,
+ 0x70, 0x61, 0x63, 0x65, 0x20, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x20, 0x66,
+ 0x6f, 0x72, 0x20, 0x74, 0x68, 0x65, 0x20, 0x59, 0x41, 0x4e, 0x47, 0x20,
+ 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x20, 0x75, 0x73, 0x69, 0x6e, 0x67,
+ 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x74, 0x68, 0x65, 0x20,
+ 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x20, 0x73, 0x74,
+ 0x61, 0x74, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x20, 0x61, 0x72, 0x65, 0x20,
+ 0x61, 0x73, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x20, 0x74, 0x6f, 0x20,
+ 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x20, 0x64, 0x6f, 0x63,
+ 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x20, 0x64, 0x61, 0x74, 0x61, 0x0a, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x63, 0x6f, 0x6e, 0x66, 0x6f, 0x72,
+ 0x6d, 0x69, 0x6e, 0x67, 0x20, 0x74, 0x6f, 0x20, 0x74, 0x68, 0x65, 0x20,
+ 0x64, 0x61, 0x74, 0x61, 0x20, 0x64, 0x65, 0x66, 0x69, 0x6e, 0x69, 0x74,
+ 0x69, 0x6f, 0x6e, 0x20, 0x73, 0x74, 0x61, 0x74, 0x65, 0x6d, 0x65, 0x6e,
+ 0x74, 0x73, 0x20, 0x77, 0x69, 0x74, 0x68, 0x69, 0x6e, 0x20, 0x74, 0x68,
+ 0x69, 0x73, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x65, 0x78,
+ 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x2e, 0x0a, 0x0a, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x54, 0x68, 0x65, 0x20, 0x58, 0x50, 0x61,
+ 0x74, 0x68, 0x20, 0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x20,
+ 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x20, 0x69, 0x73, 0x20, 0x74,
+ 0x68, 0x65, 0x20, 0x61, 0x75, 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x65, 0x64,
+ 0x20, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x0a, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x73, 0x74, 0x61, 0x74, 0x65, 0x6d,
+ 0x65, 0x6e, 0x74, 0x20, 0x69, 0x74, 0x73, 0x65, 0x6c, 0x66, 0x2c, 0x20,
+ 0x73, 0x75, 0x63, 0x68, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x74, 0x68,
+ 0x65, 0x20, 0x63, 0x68, 0x69, 0x6c, 0x64, 0x20, 0x6e, 0x6f, 0x64, 0x65,
+ 0x73, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x64, 0x6f, 0x63,
+ 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x20, 0x61, 0x72, 0x65,
+ 0x20, 0x72, 0x65, 0x70, 0x72, 0x65, 0x73, 0x65, 0x6e, 0x74, 0x65, 0x64,
+ 0x20, 0x62, 0x79, 0x20, 0x74, 0x68, 0x65, 0x20, 0x64, 0x61, 0x74, 0x61,
+ 0x2d, 0x64, 0x65, 0x66, 0x2d, 0x73, 0x74, 0x6d, 0x74, 0x20, 0x73, 0x75,
+ 0x62, 0x73, 0x74, 0x61, 0x74, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x0a,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x77, 0x69, 0x74, 0x68, 0x69,
+ 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x61, 0x75, 0x67, 0x6d, 0x65, 0x6e,
+ 0x74, 0x65, 0x64, 0x20, 0x27, 0x73, 0x74, 0x72, 0x75, 0x63, 0x74, 0x75,
+ 0x72, 0x65, 0x27, 0x20, 0x73, 0x74, 0x61, 0x74, 0x65, 0x6d, 0x65, 0x6e,
+ 0x74, 0x2e, 0x0a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x54,
+ 0x68, 0x65, 0x20, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x20, 0x6e,
+ 0x6f, 0x64, 0x65, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x27,
+ 0x61, 0x75, 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x2d, 0x73, 0x74, 0x72, 0x75,
+ 0x63, 0x74, 0x75, 0x72, 0x65, 0x27, 0x20, 0x73, 0x74, 0x61, 0x74, 0x65,
+ 0x6d, 0x65, 0x6e, 0x74, 0x20, 0x69, 0x73, 0x0a, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x64, 0x65, 0x72, 0x69, 0x76, 0x65, 0x64, 0x20, 0x69,
+ 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 0x61, 0x6d, 0x65, 0x20, 0x77,
+ 0x61, 0x79, 0x20, 0x61, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, 0x27, 0x61,
+ 0x75, 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x27, 0x20, 0x73, 0x74, 0x61, 0x74,
+ 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x2c, 0x20, 0x61, 0x73, 0x20, 0x64, 0x65,
+ 0x66, 0x69, 0x6e, 0x65, 0x64, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x69, 0x6e, 0x20, 0x53, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20,
+ 0x36, 0x2e, 0x34, 0x2e, 0x31, 0x20, 0x6f, 0x66, 0x20, 0x5b, 0x52, 0x46,
+ 0x43, 0x37, 0x39, 0x35, 0x30, 0x5d, 0x2e, 0x20, 0x54, 0x68, 0x69, 0x73,
+ 0x20, 0x63, 0x6f, 0x6e, 0x63, 0x65, 0x70, 0x74, 0x75, 0x61, 0x6c, 0x20,
+ 0x6e, 0x6f, 0x64, 0x65, 0x20, 0x69, 0x73, 0x0a, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x63, 0x6f, 0x6e, 0x73, 0x69, 0x64, 0x65, 0x72, 0x65,
+ 0x64, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x78,
+ 0x74, 0x20, 0x6e, 0x6f, 0x64, 0x65, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x74,
+ 0x68, 0x65, 0x20, 0x66, 0x6f, 0x6c, 0x6c, 0x6f, 0x77, 0x69, 0x6e, 0x67,
+ 0x20, 0x59, 0x41, 0x4e, 0x47, 0x20, 0x73, 0x74, 0x61, 0x74, 0x65, 0x6d,
+ 0x65, 0x6e, 0x74, 0x73, 0x3a, 0x0a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x2d, 0x20, 0x6d, 0x75, 0x73, 0x74,
+ 0x2d, 0x73, 0x74, 0x6d, 0x74, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x2d, 0x20, 0x77, 0x68, 0x65, 0x6e, 0x2d,
+ 0x73, 0x74, 0x6d, 0x74, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x2d, 0x20, 0x70, 0x61, 0x74, 0x68, 0x2d, 0x73,
+ 0x74, 0x6d, 0x74, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x2d, 0x20, 0x6d, 0x69, 0x6e, 0x2d, 0x65, 0x6c, 0x65,
+ 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x2d, 0x73, 0x74, 0x6d, 0x74, 0x0a, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x2d, 0x20,
+ 0x6d, 0x61, 0x78, 0x2d, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x73,
+ 0x2d, 0x73, 0x74, 0x6d, 0x74, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x2d, 0x20, 0x6d, 0x61, 0x6e, 0x64, 0x61,
+ 0x74, 0x6f, 0x72, 0x79, 0x2d, 0x73, 0x74, 0x6d, 0x74, 0x0a, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x2d, 0x20, 0x75,
+ 0x6e, 0x69, 0x71, 0x75, 0x65, 0x2d, 0x73, 0x74, 0x6d, 0x74, 0x0a, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x2d, 0x20,
+ 0x6f, 0x72, 0x64, 0x65, 0x72, 0x65, 0x64, 0x2d, 0x62, 0x79, 0x0a, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x2d, 0x20,
+ 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x2d, 0x69, 0x64, 0x65,
+ 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x20, 0x64, 0x61, 0x74, 0x61,
+ 0x20, 0x74, 0x79, 0x70, 0x65, 0x0a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x54, 0x68, 0x65, 0x20, 0x66, 0x6f, 0x6c, 0x6c, 0x6f, 0x77,
+ 0x69, 0x6e, 0x67, 0x20, 0x64, 0x61, 0x74, 0x61, 0x2d, 0x64, 0x65, 0x66,
+ 0x2d, 0x73, 0x74, 0x6d, 0x74, 0x20, 0x73, 0x75, 0x62, 0x73, 0x74, 0x61,
+ 0x74, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x20, 0x61, 0x72, 0x65, 0x20,
+ 0x63, 0x6f, 0x6e, 0x73, 0x74, 0x72, 0x61, 0x69, 0x6e, 0x65, 0x64, 0x0a,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x77, 0x68, 0x65, 0x6e, 0x20,
+ 0x75, 0x73, 0x65, 0x64, 0x20, 0x77, 0x69, 0x74, 0x68, 0x69, 0x6e, 0x20,
+ 0x61, 0x6e, 0x20, 0x27, 0x61, 0x75, 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x2d,
+ 0x73, 0x74, 0x72, 0x75, 0x63, 0x74, 0x75, 0x72, 0x65, 0x27, 0x20, 0x65,
+ 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x20, 0x73, 0x74, 0x61,
+ 0x74, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x0a, 0x0a, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x2d, 0x20, 0x54, 0x68,
+ 0x65, 0x20, 0x6c, 0x69, 0x73, 0x74, 0x2d, 0x73, 0x74, 0x6d, 0x74, 0x20,
+ 0x69, 0x73, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x72, 0x65, 0x71, 0x75, 0x69,
+ 0x72, 0x65, 0x64, 0x20, 0x74, 0x6f, 0x20, 0x68, 0x61, 0x76, 0x65, 0x20,
+ 0x61, 0x20, 0x6b, 0x65, 0x79, 0x2d, 0x73, 0x74, 0x6d, 0x74, 0x20, 0x64,
+ 0x65, 0x66, 0x69, 0x6e, 0x65, 0x64, 0x2e, 0x0a, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x2d, 0x20, 0x54, 0x68, 0x65,
+ 0x20, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2d, 0x73, 0x74, 0x6d, 0x74,
+ 0x20, 0x69, 0x73, 0x20, 0x69, 0x67, 0x6e, 0x6f, 0x72, 0x65, 0x64, 0x20,
+ 0x69, 0x66, 0x20, 0x70, 0x72, 0x65, 0x73, 0x65, 0x6e, 0x74, 0x2e, 0x0a,
+ 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x45, 0x78, 0x61, 0x6d,
+ 0x70, 0x6c, 0x65, 0x3a, 0x0a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x20,
+ 0x66, 0x6f, 0x6f, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x69, 0x6d, 0x70,
+ 0x6f, 0x72, 0x74, 0x20, 0x69, 0x65, 0x74, 0x66, 0x2d, 0x79, 0x61, 0x6e,
+ 0x67, 0x2d, 0x73, 0x74, 0x72, 0x75, 0x63, 0x74, 0x75, 0x72, 0x65, 0x2d,
+ 0x65, 0x78, 0x74, 0x20, 0x7b, 0x20, 0x70, 0x72, 0x65, 0x66, 0x69, 0x78,
+ 0x20, 0x73, 0x78, 0x3b, 0x20, 0x7d, 0x0a, 0x0a, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x73,
+ 0x78, 0x3a, 0x73, 0x74, 0x72, 0x75, 0x63, 0x74, 0x75, 0x72, 0x65, 0x20,
+ 0x66, 0x6f, 0x6f, 0x2d, 0x64, 0x61, 0x74, 0x61, 0x20, 0x7b, 0x0a, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x20,
+ 0x66, 0x6f, 0x6f, 0x2d, 0x63, 0x6f, 0x6e, 0x20, 0x7b, 0x20, 0x7d, 0x0a,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x7d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x7d, 0x0a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65,
+ 0x20, 0x62, 0x61, 0x72, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x69, 0x6d,
+ 0x70, 0x6f, 0x72, 0x74, 0x20, 0x69, 0x65, 0x74, 0x66, 0x2d, 0x79, 0x61,
+ 0x6e, 0x67, 0x2d, 0x73, 0x74, 0x72, 0x75, 0x63, 0x74, 0x75, 0x72, 0x65,
+ 0x2d, 0x65, 0x78, 0x74, 0x20, 0x7b, 0x20, 0x70, 0x72, 0x65, 0x66, 0x69,
+ 0x78, 0x20, 0x73, 0x78, 0x3b, 0x20, 0x7d, 0x0a, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x69,
+ 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x20, 0x66, 0x6f, 0x6f, 0x20, 0x7b, 0x20,
+ 0x70, 0x72, 0x65, 0x66, 0x69, 0x78, 0x20, 0x66, 0x6f, 0x6f, 0x3b, 0x20,
+ 0x7d, 0x0a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x73, 0x78, 0x3a, 0x61, 0x75, 0x67,
+ 0x6d, 0x65, 0x6e, 0x74, 0x2d, 0x73, 0x74, 0x72, 0x75, 0x63, 0x74, 0x75,
+ 0x72, 0x65, 0x20, 0x2f, 0x66, 0x6f, 0x6f, 0x3a, 0x66, 0x6f, 0x6f, 0x2d,
+ 0x64, 0x61, 0x74, 0x61, 0x2f, 0x66, 0x6f, 0x6f, 0x3a, 0x66, 0x6f, 0x6f,
+ 0x2d, 0x63, 0x6f, 0x6e, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x65,
+ 0x61, 0x66, 0x20, 0x61, 0x64, 0x64, 0x2d, 0x6c, 0x65, 0x61, 0x66, 0x31,
+ 0x20, 0x7b, 0x20, 0x74, 0x79, 0x70, 0x65, 0x20, 0x69, 0x6e, 0x74, 0x33,
+ 0x32, 0x3b, 0x20, 0x7d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x65, 0x61, 0x66,
+ 0x20, 0x61, 0x64, 0x64, 0x2d, 0x6c, 0x65, 0x61, 0x66, 0x32, 0x20, 0x7b,
+ 0x20, 0x74, 0x79, 0x70, 0x65, 0x20, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67,
+ 0x3b, 0x20, 0x7d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7d, 0x0a, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7d, 0x0a, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x3b, 0x0a, 0x20, 0x20, 0x7d, 0x0a,
+ 0x7d, 0x0a, 0x00
+};
diff --git a/models/ietf-yang-structure-ext@2020-06-17.yang b/models/ietf-yang-structure-ext@2020-06-17.yang
new file mode 100644
index 0000000..e3452a4
--- /dev/null
+++ b/models/ietf-yang-structure-ext@2020-06-17.yang
@@ -0,0 +1,206 @@
+module ietf-yang-structure-ext {
+ yang-version 1.1;
+ namespace "urn:ietf:params:xml:ns:yang:ietf-yang-structure-ext";
+ prefix sx;
+
+ organization
+ "IETF NETMOD (NETCONF Data Modeling Language) Working Group";
+ contact
+ "WG Web: <https://datatracker.ietf.org/wg/netmod/>
+ WG List: <mailto:netmod@ietf.org>
+
+ Author: Andy Bierman
+ <mailto:andy@yumaworks.com>
+
+ Author: Martin Bjorklund
+ <mailto:mbj+ietf@4668.se>
+
+ Author: Kent Watsen
+ <mailto:kent+ietf@watsen.net>";
+ description
+ "This module contains conceptual YANG specifications for defining
+ abstract data structures.
+
+ The key words 'MUST', 'MUST NOT', 'REQUIRED', 'SHALL', 'SHALL
+ NOT', 'SHOULD', 'SHOULD NOT', 'RECOMMENDED', 'NOT RECOMMENDED',
+ 'MAY', and 'OPTIONAL' in this document are to be interpreted as
+ described in BCP 14 (RFC 2119) (RFC 8174) when, and only when,
+ they appear in all capitals, as shown here.
+
+ Copyright (c) 2020 IETF Trust and the persons identified as
+ authors of the code. All rights reserved.
+
+ Redistribution and use in source and binary forms, with or
+ without modification, is permitted pursuant to, and subject to
+ the license terms contained in, the Simplified BSD License set
+ forth in Section 4.c of the IETF Trust's Legal Provisions
+ Relating to IETF Documents
+ (http://trustee.ietf.org/license-info).
+
+ This version of this YANG module is part of RFC 8791
+ (https://www.rfc-editor.org/info/rfc8791); see the RFC itself
+ for full legal notices.";
+
+ revision 2020-06-17 {
+ description
+ "Initial revision.";
+ reference
+ "RFC 8791: YANG Data Structure Extensions.";
+ }
+
+ extension structure {
+ argument name {
+ yin-element true;
+ }
+ description
+ "This extension is used to specify a YANG data structure that
+ represents conceptual data defined in YANG. It is intended to
+ describe hierarchical data independent of protocol context or
+ specific message encoding format. Data definition statements
+ within a 'structure' extension statement specify the generic
+ syntax for the specific YANG data structure, whose name is the
+ argument of the 'structure' extension statement.
+
+ Note that this extension does not define a media type. A
+ specification using this extension MUST specify the message
+ encoding rules, including the content media type, if
+ applicable.
+
+ The mandatory 'name' parameter value identifies the YANG data
+ structure that is being defined.
+
+ This extension is only valid as a top-level statement, i.e.,
+ given as a substatement to 'module' or 'submodule'.
+
+ The substatements of this extension MUST follow the ABNF
+ rules below, where the rules are defined in RFC 7950:
+
+ *must-stmt
+ [status-stmt]
+ [description-stmt]
+ [reference-stmt]
+ *(typedef-stmt / grouping-stmt)
+ *data-def-stmt
+
+ A YANG data structure defined with this extension statement is
+ encoded in the same way as an 'anydata' node. This means
+ that the name of the structure is encoded as a 'container',
+ with the instantiated child statements encoded as child nodes
+ to this node.
+
+ The module name and namespace value for the YANG module using
+ the extension statement are assigned to each of the data
+ definition statements resulting from the YANG data structure.
+
+ The XPath document element is the extension statement itself,
+ such that the child nodes of the document element are
+ represented by the data-def-stmt substatements within this
+ extension. This conceptual document is the context for the
+ following YANG statements:
+
+ - must-stmt
+ - when-stmt
+ - path-stmt
+ - min-elements-stmt
+ - max-elements-stmt
+ - mandatory-stmt
+ - unique-stmt
+ - ordered-by
+ - instance-identifier data type
+
+ The following data-def-stmt substatements are constrained
+ when used within a 'structure' extension statement.
+
+ - The list-stmt is not required to have a key-stmt defined.
+ - The config-stmt is ignored if present.
+ ";
+ }
+
+ extension augment-structure {
+ argument path {
+ yin-element true;
+ }
+ description
+ "This extension is used to specify an augmentation to a YANG
+ data structure defined with the 'structure' statement. It is
+ intended to describe hierarchical data independent of protocol
+ context or specific message encoding format.
+
+ This statement has almost the same structure as the
+ 'augment-stmt'. Data definition statements within this
+ statement specify the semantics and generic syntax for the
+ additional data to be added to the specific YANG data
+ structure, identified by the 'path' argument.
+
+ The mandatory 'path' parameter value identifies the YANG
+ conceptual data node that is being augmented and is
+ represented as an absolute-schema-nodeid string, where the
+ first node in the absolute-schema-nodeid string identifies the
+ YANG data structure to augment, and the rest of the nodes in
+ the string identifies the node within the YANG structure to
+ augment.
+
+ This extension is only valid as a top-level statement, i.e.,
+ given as a substatement to 'module' or 'submodule'.
+
+ The substatements of this extension MUST follow the ABNF
+ rules below, where the rules are defined in RFC 7950:
+
+ [status-stmt]
+ [description-stmt]
+ [reference-stmt]
+ 1*(data-def-stmt / case-stmt)
+
+ The module name and namespace value for the YANG module using
+ the extension statement are assigned to instance document data
+ conforming to the data definition statements within this
+ extension.
+
+ The XPath document element is the augmented extension
+ statement itself, such that the child nodes of the document
+ element are represented by the data-def-stmt substatements
+ within the augmented 'structure' statement.
+
+ The context node of the 'augment-structure' statement is
+ derived in the same way as the 'augment' statement, as defined
+ in Section 6.4.1 of [RFC7950]. This conceptual node is
+ considered the context node for the following YANG statements:
+
+ - must-stmt
+ - when-stmt
+ - path-stmt
+ - min-elements-stmt
+ - max-elements-stmt
+ - mandatory-stmt
+ - unique-stmt
+ - ordered-by
+ - instance-identifier data type
+
+ The following data-def-stmt substatements are constrained
+ when used within an 'augment-structure' extension statement.
+
+ - The list-stmt is not required to have a key-stmt defined.
+ - The config-stmt is ignored if present.
+
+ Example:
+
+ module foo {
+ import ietf-yang-structure-ext { prefix sx; }
+
+ sx:structure foo-data {
+ container foo-con { }
+ }
+ }
+
+ module bar {
+ import ietf-yang-structure-ext { prefix sx; }
+ import foo { prefix foo; }
+
+ sx:augment-structure /foo:foo-data/foo:foo-con {
+ leaf add-leaf1 { type int32; }
+ leaf add-leaf2 { type string; }
+ }
+ }
+ ";
+ }
+}
diff --git a/src/context.c b/src/context.c
index d703ed2..735f589 100644
--- a/src/context.c
+++ b/src/context.c
@@ -53,6 +53,7 @@
#include "../models/ietf-yang-library@2019-01-04.h"
#include "../models/ietf-yang-metadata@2016-08-05.h"
#include "../models/ietf-yang-schema-mount@2019-01-14.h"
+#include "../models/ietf-yang-structure-ext@2020-06-17.h"
#include "../models/ietf-yang-types@2013-07-15.h"
#include "../models/yang@2022-06-16.h"
#define IETF_YANG_LIB_REV "2019-01-04"
@@ -69,6 +70,7 @@
{"ietf-inet-types", "2013-07-15", (const char *)ietf_inet_types_2013_07_15_yang, 0, LYS_IN_YANG},
{"ietf-yang-types", "2013-07-15", (const char *)ietf_yang_types_2013_07_15_yang, 0, LYS_IN_YANG},
{"ietf-yang-schema-mount", "2019-01-14", (const char *)ietf_yang_schema_mount_2019_01_14_yang, 1, LYS_IN_YANG},
+ {"ietf-yang-structure-ext", "2020-06-17", (const char *)ietf_yang_structure_ext_2020_06_17_yang, 0, LYS_IN_YANG},
/* ietf-datastores and ietf-yang-library must be right here at the end of the list! */
{"ietf-datastores", "2018-02-14", (const char *)ietf_datastores_2018_02_14_yang, 1, LYS_IN_YANG},
{"ietf-yang-library", IETF_YANG_LIB_REV, (const char *)ietf_yang_library_2019_01_04_yang, 1, LYS_IN_YANG}
diff --git a/src/plugins.c b/src/plugins.c
index 70b23b8..28fcd0e 100644
--- a/src/plugins.c
+++ b/src/plugins.c
@@ -84,6 +84,7 @@
extern struct lyplg_ext_record plugins_nacm[];
extern struct lyplg_ext_record plugins_yangdata[];
extern struct lyplg_ext_record plugins_schema_mount[];
+extern struct lyplg_ext_record plugins_structure[];
static pthread_mutex_t plugins_guard = PTHREAD_MUTEX_INITIALIZER;
@@ -469,6 +470,7 @@
LY_CHECK_GOTO(ret = plugins_insert(LYPLG_EXTENSION, plugins_nacm), error);
LY_CHECK_GOTO(ret = plugins_insert(LYPLG_EXTENSION, plugins_yangdata), error);
LY_CHECK_GOTO(ret = plugins_insert(LYPLG_EXTENSION, plugins_schema_mount), error);
+ LY_CHECK_GOTO(ret = plugins_insert(LYPLG_EXTENSION, plugins_structure), error);
#ifndef STATIC
/* external types */
diff --git a/src/plugins_exts/structure.c b/src/plugins_exts/structure.c
new file mode 100644
index 0000000..781cde0
--- /dev/null
+++ b/src/plugins_exts/structure.c
@@ -0,0 +1,214 @@
+/**
+ * @file structure.c
+ * @author Michal Vasko <mvasko@cesnet.cz>
+ * @brief libyang extension plugin - strcture (RFC 8791)
+ *
+ * Copyright (c) 2022 CESNET, z.s.p.o.
+ *
+ * This source code is licensed under BSD 3-Clause License (the "License").
+ * You may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://opensource.org/licenses/BSD-3-Clause
+ */
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "libyang.h"
+#include "plugins_exts.h"
+
+struct lysc_ext_instance_structure {
+ struct lysc_must *musts;
+ uint16_t flags;
+ const char *dsc;
+ const char *ref;
+ struct lysp_tpdf *typedefs;
+ struct lysp_node_grp *groupings;
+ struct lysc_node *child;
+};
+
+/**
+ * @brief Compile structure extension instances.
+ *
+ * Implementation of ::lyplg_ext_compile_clb callback set as lyext_plugin::compile.
+ */
+static LY_ERR
+structure_compile(struct lysc_ctx *cctx, const struct lysp_ext_instance *p_ext, struct lysc_ext_instance *c_ext)
+{
+ LY_ERR ret;
+ LY_ARRAY_COUNT_TYPE u;
+ struct lysc_module *mod_c;
+ const struct lysc_node *child;
+ struct lysc_ext_instance_structure *struct_ext;
+ uint32_t prev_options = *lysc_ctx_get_options(cctx);
+
+ /* structure can appear only at the top level of a YANG module or submodule */
+ if ((c_ext->parent_stmt != LY_STMT_MODULE) && (c_ext->parent_stmt != LY_STMT_SUBMODULE)) {
+ lyplg_ext_log(c_ext, LY_LLERR, LY_EVALID, lysc_ctx_get_path(cctx),
+ "Extension %s must not be used as a non top-level statement in \"%s\" statement.",
+ p_ext->name, ly_stmt2str(c_ext->parent_stmt));
+ return LY_EVALID;
+ }
+
+ mod_c = (struct lysc_module *)c_ext->parent;
+
+ /* check identifier namespace */
+ LY_ARRAY_FOR(mod_c->exts, u) {
+ if ((&mod_c->exts[u] != c_ext) && (mod_c->exts[u].def == c_ext->def) && !strcmp(mod_c->exts[u].argument, c_ext->argument)) {
+ /* duplication of the same structure extension in a single module */
+ lyplg_ext_log(c_ext, LY_LLERR, LY_EVALID, lysc_ctx_get_path(cctx), "Extension %s is instantiated multiple times.", p_ext->name);
+ return LY_EVALID;
+ }
+ }
+ LY_LIST_FOR(mod_c->data, child) {
+ if (!strcmp(child->name, c_ext->argument)) {
+ /* identifier collision */
+ lyplg_ext_log(c_ext, LY_LLERR, LY_EVALID, lysc_ctx_get_path(cctx), "Extension %s collides "
+ "with a %s with the same identifier.", p_ext->name, lys_nodetype2str(child->nodetype));
+ return LY_EVALID;
+ }
+ }
+
+ /* allocate the storage */
+ struct_ext = calloc(1, sizeof *struct_ext);
+ if (!struct_ext) {
+ goto emem;
+ }
+ c_ext->data = struct_ext;
+
+ /* compile substatements */
+ LY_ARRAY_CREATE_GOTO(cctx->ctx, c_ext->substmts, 14, ret, emem);
+ LY_ARRAY_INCREMENT(c_ext->substmts);
+ c_ext->substmts[0].stmt = LY_STMT_MUST;
+ c_ext->substmts[0].cardinality = LY_STMT_CARD_ANY;
+ c_ext->substmts[0].storage = &struct_ext->musts;
+
+ LY_ARRAY_INCREMENT(c_ext->substmts);
+ c_ext->substmts[1].stmt = LY_STMT_STATUS;
+ c_ext->substmts[1].cardinality = LY_STMT_CARD_OPT;
+ c_ext->substmts[1].storage = &struct_ext->flags;
+
+ LY_ARRAY_INCREMENT(c_ext->substmts);
+ c_ext->substmts[2].stmt = LY_STMT_DESCRIPTION;
+ c_ext->substmts[2].cardinality = LY_STMT_CARD_OPT;
+ c_ext->substmts[2].storage = &struct_ext->dsc;
+
+ LY_ARRAY_INCREMENT(c_ext->substmts);
+ c_ext->substmts[3].stmt = LY_STMT_REFERENCE;
+ c_ext->substmts[3].cardinality = LY_STMT_CARD_OPT;
+ c_ext->substmts[3].storage = &struct_ext->ref;
+
+ LY_ARRAY_INCREMENT(c_ext->substmts);
+ c_ext->substmts[4].stmt = LY_STMT_TYPEDEF;
+ c_ext->substmts[4].cardinality = LY_STMT_CARD_ANY;
+ c_ext->substmts[4].storage = &struct_ext->typedefs;
+
+ LY_ARRAY_INCREMENT(c_ext->substmts);
+ c_ext->substmts[5].stmt = LY_STMT_GROUPING;
+ c_ext->substmts[5].cardinality = LY_STMT_CARD_ANY;
+ c_ext->substmts[5].storage = &struct_ext->groupings;
+
+ /* data-def-stmt */
+ LY_ARRAY_INCREMENT(c_ext->substmts);
+ c_ext->substmts[6].stmt = LY_STMT_CONTAINER;
+ c_ext->substmts[6].cardinality = LY_STMT_CARD_ANY;
+ c_ext->substmts[6].storage = &struct_ext->child;
+
+ LY_ARRAY_INCREMENT(c_ext->substmts);
+ c_ext->substmts[7].stmt = LY_STMT_LEAF;
+ c_ext->substmts[7].cardinality = LY_STMT_CARD_ANY;
+ c_ext->substmts[7].storage = &struct_ext->child;
+
+ LY_ARRAY_INCREMENT(c_ext->substmts);
+ c_ext->substmts[8].stmt = LY_STMT_LEAF_LIST;
+ c_ext->substmts[8].cardinality = LY_STMT_CARD_ANY;
+ c_ext->substmts[8].storage = &struct_ext->child;
+
+ LY_ARRAY_INCREMENT(c_ext->substmts);
+ c_ext->substmts[9].stmt = LY_STMT_LIST;
+ c_ext->substmts[9].cardinality = LY_STMT_CARD_ANY;
+ c_ext->substmts[9].storage = &struct_ext->child;
+
+ LY_ARRAY_INCREMENT(c_ext->substmts);
+ c_ext->substmts[10].stmt = LY_STMT_CHOICE;
+ c_ext->substmts[10].cardinality = LY_STMT_CARD_ANY;
+ c_ext->substmts[10].storage = &struct_ext->child;
+
+ LY_ARRAY_INCREMENT(c_ext->substmts);
+ c_ext->substmts[11].stmt = LY_STMT_ANYDATA;
+ c_ext->substmts[11].cardinality = LY_STMT_CARD_ANY;
+ c_ext->substmts[11].storage = &struct_ext->child;
+
+ LY_ARRAY_INCREMENT(c_ext->substmts);
+ c_ext->substmts[12].stmt = LY_STMT_ANYXML;
+ c_ext->substmts[12].cardinality = LY_STMT_CARD_ANY;
+ c_ext->substmts[12].storage = &struct_ext->child;
+
+ LY_ARRAY_INCREMENT(c_ext->substmts);
+ c_ext->substmts[13].stmt = LY_STMT_USES;
+ c_ext->substmts[13].cardinality = LY_STMT_CARD_ANY;
+ c_ext->substmts[13].storage = &struct_ext->child;
+
+ *lysc_ctx_get_options(cctx) |= LYS_COMPILE_NO_CONFIG | LYS_COMPILE_NO_DISABLED;
+ ret = lys_compile_extension_instance(cctx, p_ext, c_ext);
+ *lysc_ctx_get_options(cctx) = prev_options;
+ if (ret) {
+ return ret;
+ }
+
+ return LY_SUCCESS;
+
+emem:
+ lyplg_ext_log(c_ext, LY_LLERR, LY_EMEM, lysc_ctx_get_path(cctx), "Memory allocation failed (%s()).", __func__);
+ return LY_EMEM;
+}
+
+/**
+ * @brief INFO printer
+ *
+ * Implementation of ::lyplg_ext_schema_printer_clb set as ::lyext_plugin::sprinter
+ */
+static LY_ERR
+structure_schema_printer(struct lyspr_ctx *ctx, struct lysc_ext_instance *ext, ly_bool *flag)
+{
+ lysc_print_extension_instance(ctx, ext, flag);
+ return LY_SUCCESS;
+}
+
+/**
+ * @brief Free structure extension instances' data.
+ *
+ * Implementation of ::lyplg_clb_free_clb callback set as lyext_plugin::free.
+ */
+static void
+structure_free(struct ly_ctx *ctx, struct lysc_ext_instance *ext)
+{
+ lyplg_ext_instance_substatements_free(ctx, ext->substmts);
+ free(ext->data);
+}
+
+/**
+ * @brief Plugin descriptions for the structure extension
+ *
+ * Note that external plugins are supposed to use:
+ *
+ * LYPLG_EXTENSIONS = {
+ */
+const struct lyplg_ext_record plugins_structure[] = {
+ {
+ .module = "ietf-yang-structure-ext",
+ .revision = "2020-06-17",
+ .name = "structure",
+
+ .plugin.id = "libyang 2 - structure, version 1",
+ .plugin.compile = structure_compile,
+ .plugin.sprinter = structure_schema_printer,
+ .plugin.free = structure_free,
+ .plugin.node = NULL,
+ .plugin.snode = NULL,
+ .plugin.validate = NULL
+ },
+ {0} /* terminating zeroed record */
+};
diff --git a/src/plugins_types.c b/src/plugins_types.c
index 67f1cdd..5ffbc6d 100644
--- a/src/plugins_types.c
+++ b/src/plugins_types.c
@@ -1,9 +1,10 @@
/**
* @file plugins_types.c
* @author Radek Krejci <rkrejci@cesnet.cz>
+ * @author Michal Vasko <mvasko@cesnet.cz>
* @brief Built-in types plugins and interface for user types plugins.
*
- * Copyright (c) 2019 CESNET, z.s.p.o.
+ * Copyright (c) 2019 - 2022 CESNET, z.s.p.o.
*
* This source code is licensed under BSD 3-Clause License (the "License").
* You may not use this file except in compliance with the License.
diff --git a/src/printer_yang.c b/src/printer_yang.c
index 21515b5..329c712 100644
--- a/src/printer_yang.c
+++ b/src/printer_yang.c
@@ -1,6 +1,7 @@
/**
* @file printer_yang.c
* @author Radek Krejci <rkrejci@cesnet.cz>
+ * @author Michal Vasko <mvasko@cesnet.cz>
* @brief YANG printer
*
* Copyright (c) 2015 - 2022 CESNET, z.s.p.o.
@@ -2459,20 +2460,49 @@
{
struct lys_ypr_ctx *pctx = (struct lys_ypr_ctx *)ctx_generic;
LY_ARRAY_COUNT_TYPE u, v;
+ ly_bool data_printed = 0;
LY_ARRAY_FOR(ext->substmts, u) {
switch (ext->substmts[u].stmt) {
+ case LY_STMT_ACTION:
+ case LY_STMT_CONTAINER:
case LY_STMT_CHOICE:
- case LY_STMT_CONTAINER: {
+ case LY_STMT_LEAF:
+ case LY_STMT_LEAF_LIST:
+ case LY_STMT_LIST:
+ case LY_STMT_NOTIFICATION:
+ case LY_STMT_RPC:
+ case LY_STMT_ANYXML:
+ case LY_STMT_ANYDATA: {
const struct lysc_node *node;
+ if (data_printed) {
+ break;
+ }
+
LY_LIST_FOR(*(const struct lysc_node **)ext->substmts[u].storage, node) {
ypr_open(pctx->out, flag);
- yprc_node(pctx, node);
+ if ((ext->substmts[u].stmt == LY_STMT_ACTION) || (ext->substmts[u].stmt == LY_STMT_RPC)) {
+ yprc_action(pctx, (struct lysc_node_action *)node);
+ } else if (ext->substmts[u].stmt == LY_STMT_NOTIFICATION) {
+ yprc_notification(pctx, (struct lysc_node_notif *)node);
+ } else {
+ yprc_node(pctx, node);
+ }
}
+
+ /* all data nodes are stored in a linked list so all were printed */
+ data_printed = 1;
break;
}
+ case LY_STMT_CONTACT:
case LY_STMT_DESCRIPTION:
+ case LY_STMT_ERROR_APP_TAG:
+ case LY_STMT_ERROR_MESSAGE:
+ case LY_STMT_KEY:
+ case LY_STMT_NAMESPACE:
+ case LY_STMT_ORGANIZATION:
+ case LY_STMT_PRESENCE:
case LY_STMT_REFERENCE:
case LY_STMT_UNITS:
if (ext->substmts[u].cardinality < LY_STMT_CARD_SOME) {
@@ -2489,7 +2519,18 @@
}
}
break;
+ case LY_STMT_MUST: {
+ const struct lysc_must *musts = *(struct lysc_must **)ext->substmts[u].storage;
+
+ LY_ARRAY_FOR(musts, v) {
+ yprc_must(pctx, &musts[v], flag);
+ }
+ break;
+ }
case LY_STMT_IF_FEATURE:
+ case LY_STMT_USES:
+ case LY_STMT_GROUPING:
+ case LY_STMT_TYPEDEF:
/* nothing to do */
break;
case LY_STMT_STATUS:
diff --git a/src/schema_compile.c b/src/schema_compile.c
index c02e628..54428f8 100644
--- a/src/schema_compile.c
+++ b/src/schema_compile.c
@@ -4,7 +4,7 @@
* @author Michal Vasko <mvasko@cesnet.cz>
* @brief Schema compilation.
*
- * Copyright (c) 2015 - 2021 CESNET, z.s.p.o.
+ * Copyright (c) 2015 - 2022 CESNET, z.s.p.o.
*
* This source code is licensed under BSD 3-Clause License (the "License").
* You may not use this file except in compliance with the License.
@@ -285,7 +285,7 @@
if (!ctx_sc) {
if (parsed_mod) {
- LYSC_CTX_INIT_PMOD(cctx, parsed_mod);
+ LYSC_CTX_INIT_PMOD(cctx, parsed_mod, NULL);
} else {
LYSC_CTX_INIT_CTX(cctx, ctx);
}
@@ -486,24 +486,227 @@
return LY_SUCCESS;
}
-static void *
-lys_compile_extension_instance_storage(enum ly_stmt stmt, struct lysc_ext_substmt *substmts)
+const void *
+lys_compile_ext_instance_get_storage(const struct lysc_ext_instance *ext, enum ly_stmt stmt)
{
- for (LY_ARRAY_COUNT_TYPE u = 0; substmts[u].stmt; ++u) {
- if (substmts[u].stmt == stmt) {
- return substmts[u].storage;
+ LY_ARRAY_COUNT_TYPE u;
+
+ LY_ARRAY_FOR(ext->substmts, u) {
+ if (ext->substmts[u].stmt == stmt) {
+ return ext->substmts[u].storage;
}
}
return NULL;
}
+/**
+ * @brief Store (parse/compile) an instance extension statement.
+ *
+ * @param[in] ctx Compile context.
+ * @param[in] ext_p Parsed ext instance.
+ * @param[in] ext Compiled ext instance.
+ * @param[in] substmt Compled ext instance substatement info.
+ * @param[in] stmt Parsed statement to process.
+ * @return LY_ERR value.
+ */
+static LY_ERR
+lys_compile_ext_instance_stmt(struct lysc_ctx *ctx, const struct lysp_ext_instance *ext_p, struct lysc_ext_instance *ext,
+ struct lysc_ext_substmt *substmt, struct lysp_stmt *stmt)
+{
+ LY_ERR rc = LY_SUCCESS;
+ struct lysf_ctx fctx = {.ctx = ctx->ctx};
+ struct lysp_restr *restrs = NULL;
+ struct lysp_qname *qname = NULL;
+ struct lysp_type *ptype = NULL;
+
+ if (!substmt->storage) {
+ /* nothing to store (parse/compile) */
+ goto cleanup;
+ }
+
+ switch (stmt->kw) {
+ case LY_STMT_ACTION:
+ case LY_STMT_ANYDATA:
+ case LY_STMT_ANYXML:
+ case LY_STMT_CONTAINER:
+ case LY_STMT_CHOICE:
+ case LY_STMT_LEAF:
+ case LY_STMT_LEAF_LIST:
+ case LY_STMT_LIST:
+ case LY_STMT_NOTIFICATION:
+ case LY_STMT_RPC:
+ case LY_STMT_USES: {
+ struct lysp_node **pnodes_p, *pnode = NULL;
+ const uint16_t *flags = lys_compile_ext_instance_get_storage(ext, LY_STMT_STATUS);
+
+ /* parse the node */
+ LY_CHECK_GOTO(rc = lysp_stmt_parse(ctx, stmt, (void **)&pnode, NULL), cleanup);
+
+ /* store it together with all the parsed schema nodes */
+ pnodes_p = &((struct lysp_ext_instance *)ext_p)->parsed;
+ while (*pnodes_p) {
+ pnodes_p = &(*pnodes_p)->next;
+ }
+ *pnodes_p = pnode;
+
+ /* compile, ctx->ext substatement storage is used as the document root */
+ LY_CHECK_GOTO(rc = lys_compile_node(ctx, pnode, NULL, flags, NULL), cleanup);
+ break;
+ }
+ case LY_STMT_GROUPING: {
+ struct lysp_node_grp **groupings_p, *grp = NULL;
+
+ /* parse the grouping */
+ LY_CHECK_GOTO(rc = lysp_stmt_parse(ctx, stmt, (void **)&grp, NULL), cleanup);
+
+ /* store it with all the other groupings */
+ groupings_p = substmt->storage;
+ while (*groupings_p) {
+ groupings_p = &(*groupings_p)->next;
+ }
+ *groupings_p = grp;
+ break;
+ }
+ case LY_STMT_CONTACT:
+ case LY_STMT_DESCRIPTION:
+ case LY_STMT_ERROR_APP_TAG:
+ case LY_STMT_ERROR_MESSAGE:
+ case LY_STMT_KEY:
+ case LY_STMT_NAMESPACE:
+ case LY_STMT_ORGANIZATION:
+ case LY_STMT_PRESENCE:
+ case LY_STMT_REFERENCE:
+ case LY_STMT_UNITS: {
+ const char ***strs_p, **str_p;
+
+ if (substmt->cardinality < LY_STMT_CARD_SOME) {
+ /* single item */
+ str_p = substmt->storage;
+ if (*str_p) {
+ LOGVAL(ctx->ctx, LY_VCODE_DUPSTMT, stmt->stmt);
+ rc = LY_EVALID;
+ goto cleanup;
+ }
+ } else {
+ /* sized array */
+ strs_p = substmt->storage;
+ LY_ARRAY_NEW_GOTO(ctx->ctx, *strs_p, str_p, rc, cleanup);
+ }
+
+ /* called instead of lysp_stmt_parse() to skip validation and not parse nested ext instances */
+ LY_CHECK_GOTO(rc = lydict_insert(ctx->ctx, stmt->arg, 0, str_p), cleanup);
+ break;
+ }
+ case LY_STMT_MUST: {
+ struct lysc_must **musts_p, **must_p, *must;
+
+ /* parse */
+ LY_CHECK_GOTO(rc = lysp_stmt_parse(ctx, stmt, (void **)&restrs, NULL), cleanup);
+
+ if (substmt->cardinality < LY_STMT_CARD_SOME) {
+ /* single item */
+ must_p = substmt->storage;
+ if (*must_p) {
+ LOGVAL(ctx->ctx, LY_VCODE_DUPSTMT, stmt->stmt);
+ rc = LY_EVALID;
+ goto cleanup;
+ }
+ *must_p = calloc(1, sizeof **must_p);
+ must = *must_p;
+ } else {
+ /* sized array */
+ musts_p = substmt->storage;
+ LY_ARRAY_NEW_GOTO(ctx->ctx, *musts_p, must, rc, cleanup);
+ }
+
+ /* compile */
+ LY_CHECK_GOTO(rc = lys_compile_must(ctx, restrs, must), cleanup);
+ break;
+ }
+ case LY_STMT_IF_FEATURE: {
+ ly_bool enabled;
+
+ LY_CHECK_GOTO(rc = lysp_stmt_parse(ctx, stmt, (void **)&qname, NULL), cleanup);
+ LY_CHECK_GOTO(rc = lys_eval_iffeatures(ctx->ctx, qname, &enabled), cleanup);
+ if (!enabled) {
+ /* it is disabled, remove the whole extension instance */
+ return LY_ENOT;
+ }
+ break;
+ }
+ case LY_STMT_STATUS:
+ if (substmt->cardinality > LY_STMT_CARD_MAND) {
+ /* only cardinality 0..1 and 1 */
+ goto not_supported;
+ }
+ /* result needs to be a pointer to pointer */
+ LY_CHECK_GOTO(rc = lysp_stmt_parse(ctx, stmt, &substmt->storage, NULL), cleanup);
+ break;
+
+ case LY_STMT_TYPEDEF:
+ if (substmt->cardinality < LY_STMT_CARD_SOME) {
+ /* single item */
+ if (*(struct lysp_tpdf **)substmt->storage) {
+ LOGVAL(ctx->ctx, LY_VCODE_DUPSTMT, stmt->stmt);
+ rc = LY_EVALID;
+ goto cleanup;
+ }
+ } /* else sized array */
+
+ /* parse */
+ LY_CHECK_GOTO(rc = lysp_stmt_parse(ctx, stmt, substmt->storage, NULL), cleanup);
+ break;
+
+ case LY_STMT_TYPE: {
+ struct lysc_type ***types_p, **type_p;
+ const uint16_t *flags = lys_compile_ext_instance_get_storage(ext, LY_STMT_STATUS);
+ const char **units = (void *)lys_compile_ext_instance_get_storage(ext, LY_STMT_UNITS);
+
+ if (substmt->cardinality < LY_STMT_CARD_SOME) {
+ /* single item */
+ type_p = substmt->storage;
+ if (*type_p) {
+ LOGVAL(ctx->ctx, LY_VCODE_DUPSTMT, stmt->stmt);
+ rc = LY_EVALID;
+ goto cleanup;
+ }
+ } else {
+ /* sized array of pointers */
+ types_p = substmt->storage;
+ LY_ARRAY_NEW_GOTO(ctx->ctx, *types_p, type_p, rc, cleanup);
+ }
+
+ LY_CHECK_GOTO(rc = lysp_stmt_parse(ctx, stmt, (void **)&ptype, NULL), cleanup);
+ LY_CHECK_GOTO(rc = lys_compile_type(ctx, NULL, flags ? *flags : 0, ext_p->name, ptype, type_p,
+ (units && !*units) ? units : NULL, NULL), cleanup);
+ break;
+ }
+ /* TODO support other substatements (parse stmt to lysp and then compile lysp to lysc),
+ * also note that in many statements their extensions are not taken into account */
+ default:
+not_supported:
+ LOGVAL(ctx->ctx, LYVE_SYNTAX_YANG, "Statement \"%s\" in cardinality %s is not supported as an extension "
+ "(found in \"%s%s%s\") substatement.", stmt->stmt, ly_cardinality2str(substmt->cardinality),
+ ext_p->name, ext_p->argument ? " " : "", ext_p->argument ? ext_p->argument : "");
+ rc = LY_EVALID;
+ goto cleanup;
+ }
+
+cleanup:
+ FREE_ARRAY(&fctx, restrs, lysp_restr_free);
+ FREE_ARRAY(ctx->ctx, qname, lysp_qname_free);
+ lysp_type_free(&ctx->free_ctx, ptype);
+ free(ptype);
+ return rc;
+}
+
LIBYANG_API_DEF LY_ERR
lys_compile_extension_instance(struct lysc_ctx *ctx, const struct lysp_ext_instance *ext_p, struct lysc_ext_instance *ext)
{
- LY_ERR rc = LY_SUCCESS, r;
+ LY_ERR rc = LY_SUCCESS;
LY_ARRAY_COUNT_TYPE u;
struct lysp_stmt *stmt;
- void *parsed = NULL, **compiled = NULL;
+ uint64_t stmt_counter;
/* check for invalid substatements */
for (stmt = ext_p->child; stmt; stmt = stmt->next) {
@@ -532,141 +735,21 @@
* the order is important for some of the statements depending on others (e.g. type needs status and units) */
LY_ARRAY_FOR(ext->substmts, u) {
- uint64_t stmt_counter = 0;
+ stmt_counter = 0;
for (stmt = ext_p->child; stmt; stmt = stmt->next) {
if (ext->substmts[u].stmt != stmt->kw) {
continue;
}
- parsed = NULL;
stmt_counter++;
- if (ext->substmts[u].storage) {
- switch (stmt->kw) {
- case LY_STMT_ACTION:
- case LY_STMT_ANYDATA:
- case LY_STMT_ANYXML:
- case LY_STMT_CONTAINER:
- case LY_STMT_CHOICE:
- case LY_STMT_LEAF:
- case LY_STMT_LEAF_LIST:
- case LY_STMT_LIST:
- case LY_STMT_NOTIFICATION:
- case LY_STMT_RPC:
- case LY_STMT_USES:
- if (!ext_p->parsed) {
- LY_CHECK_GOTO(rc = lysp_stmt_parse(ctx, stmt, &parsed, NULL), cleanup);
- ((struct lysp_ext_instance *)ext_p)->parsed = parsed;
- } else {
- struct lysp_node *node, *last_node = NULL;
-
- /* get last parsed node */
- LY_LIST_FOR(ext_p->parsed, node) {
- last_node = node;
- }
- /* create and link sibling */
- LY_CHECK_GOTO(rc = lysp_stmt_parse(ctx, stmt, &parsed, NULL), cleanup);
- last_node->next = parsed;
- }
-
- /* set storage as an alternative document root in the compile context */
- LY_CHECK_GOTO(rc = lys_compile_node(ctx, parsed, NULL, 0, NULL), cleanup);
- break;
- case LY_STMT_CONTACT:
- case LY_STMT_DESCRIPTION:
- case LY_STMT_ERROR_APP_TAG:
- case LY_STMT_ERROR_MESSAGE:
- case LY_STMT_KEY:
- case LY_STMT_NAMESPACE:
- case LY_STMT_ORGANIZATION:
- case LY_STMT_PRESENCE:
- case LY_STMT_REFERENCE:
- case LY_STMT_UNITS: {
- const char **str_p;
-
- if (ext->substmts[u].cardinality < LY_STMT_CARD_SOME) {
- /* single item */
- if (*((const char **)ext->substmts[u].storage)) {
- LOGVAL(ctx->ctx, LY_VCODE_DUPSTMT, stmt->stmt);
- rc = LY_EVALID;
- goto cleanup;
- }
- str_p = (const char **)ext->substmts[u].storage;
- } else {
- /* sized array */
- const char ***strings_array = (const char ***)ext->substmts[u].storage;
-
- LY_ARRAY_NEW_GOTO(ctx->ctx, *strings_array, str_p, rc, cleanup);
- }
-
- /* called instead of lysp_stmt_parse() to skip validation and not parse nested ext instances */
- LY_CHECK_GOTO(rc = lydict_insert(ctx->ctx, stmt->arg, 0, str_p), cleanup);
- break;
- }
- case LY_STMT_IF_FEATURE: {
- ly_bool enabled;
-
- LY_CHECK_GOTO(rc = lysp_stmt_parse(ctx, stmt, &parsed, NULL), cleanup);
-
- r = lys_eval_iffeatures(ctx->ctx, parsed, &enabled);
- FREE_ARRAY(ctx->ctx, (struct lysp_qname *)parsed, lysp_qname_free);
- LY_CHECK_ERR_GOTO(r, rc = r, cleanup);
- if (!enabled) {
- /* it is disabled, remove the whole extension instance */
- return LY_ENOT;
- }
- break;
- }
- case LY_STMT_STATUS:
- if (ext->substmts[u].cardinality > LY_STMT_CARD_MAND) {
- /* only cardinality 0..1 and 1 */
- goto not_supported;
- }
- /* result needs to be a pointer to pointer */
- LY_CHECK_GOTO(rc = lysp_stmt_parse(ctx, stmt, &ext->substmts[u].storage, NULL), cleanup);
- break;
- case LY_STMT_TYPE: {
- uint16_t *flags = lys_compile_extension_instance_storage(LY_STMT_STATUS, ext->substmts);
- const char **units = lys_compile_extension_instance_storage(LY_STMT_UNITS, ext->substmts);
-
- if (ext->substmts[u].cardinality < LY_STMT_CARD_SOME) {
- /* single item */
- if (*(struct lysc_type **)ext->substmts[u].storage) {
- LOGVAL(ctx->ctx, LY_VCODE_DUPSTMT, stmt->stmt);
- rc = LY_EVALID;
- goto cleanup;
- }
- compiled = ext->substmts[u].storage;
- } else {
- /* sized array */
- struct lysc_type ***types = (struct lysc_type ***)ext->substmts[u].storage, **type = NULL;
-
- LY_ARRAY_NEW_GOTO(ctx->ctx, *types, type, rc, cleanup);
- compiled = (void *)type;
- }
-
- LY_CHECK_GOTO(rc = lysp_stmt_parse(ctx, stmt, &parsed, NULL), cleanup);
- r = lys_compile_type(ctx, NULL, flags ? *flags : 0, ext_p->name, parsed, (struct lysc_type **)compiled,
- (units && !*units) ? units : NULL, NULL);
- lysp_type_free(&ctx->free_ctx, parsed);
- free(parsed);
- LY_CHECK_ERR_GOTO(r, rc = r, cleanup);
- break;
- }
- /* TODO support other substatements (parse stmt to lysp and then compile lysp to lysc),
- * also note that in many statements their extensions are not taken into account */
- default:
-not_supported:
- LOGVAL(ctx->ctx, LYVE_SYNTAX_YANG, "Statement \"%s\" in cardinality %s is not supported as an extension "
- "(found in \"%s%s%s\") substatement.", stmt->stmt, ly_cardinality2str(ext->substmts[u].cardinality),
- ext_p->name, ext_p->argument ? " " : "", ext_p->argument ? ext_p->argument : "");
- rc = LY_EVALID;
- goto cleanup;
- }
+ if ((rc = lys_compile_ext_instance_stmt(ctx, ext_p, ext, &ext->substmts[u], stmt))) {
+ goto cleanup;
}
}
- if (((ext->substmts[u].cardinality == LY_STMT_CARD_MAND) || (ext->substmts[u].cardinality == LY_STMT_CARD_SOME)) && !stmt_counter) {
+ if (((ext->substmts[u].cardinality == LY_STMT_CARD_MAND) || (ext->substmts[u].cardinality == LY_STMT_CARD_SOME)) &&
+ !stmt_counter) {
LOGVAL(ctx->ctx, LYVE_SYNTAX_YANG, "Missing mandatory keyword \"%s\" as a child of \"%s%s%s\".",
ly_stmt2str(ext->substmts[u].stmt), ext_p->name, ext_p->argument ? " " : "",
ext_p->argument ? ext_p->argument : "");
@@ -1112,7 +1195,7 @@
LY_CHECK_RET(lys_compile_expr_implement(ctx->ctx, lref->path, LY_VALUE_SCHEMA_RESOLVED, lref->prefixes, 1, unres, NULL));
/* try to find the target, current module is that of the context node (RFC 7950 6.4.1 second bullet) */
- LY_CHECK_RET(ly_path_compile_leafref(ctx->ctx, node, NULL, lref->path,
+ LY_CHECK_RET(ly_path_compile_leafref(ctx->ctx, node, ctx->ext, lref->path,
(node->flags & LYS_IS_OUTPUT) ? LY_PATH_OPER_OUTPUT : LY_PATH_OPER_INPUT, LY_PATH_TARGET_MANY,
LY_VALUE_SCHEMA_RESOLVED, lref->prefixes, &p));
@@ -1393,7 +1476,7 @@
/* remember index, it can change before we get to free this item */
i = ds_unres->disabled_leafrefs.count - 1;
l = ds_unres->disabled_leafrefs.objs[i];
- LYSC_CTX_INIT_PMOD(cctx, l->node->module->parsed);
+ LYSC_CTX_INIT_PMOD(cctx, l->node->module->parsed, l->ext);
LOG_LOCSET(l->node, NULL, NULL, NULL);
v = 0;
@@ -1408,7 +1491,7 @@
for (i = processed_leafrefs; i < ds_unres->leafrefs.count; ++i) {
l = ds_unres->leafrefs.objs[i];
- LYSC_CTX_INIT_PMOD(cctx, l->node->module->parsed);
+ LYSC_CTX_INIT_PMOD(cctx, l->node->module->parsed, l->ext);
LOG_LOCSET(l->node, NULL, NULL, NULL);
v = 0;
@@ -1443,7 +1526,7 @@
while (ds_unres->whens.count) {
i = ds_unres->whens.count - 1;
node = ds_unres->whens.objs[i];
- LYSC_CTX_INIT_PMOD(cctx, node->module->parsed);
+ LYSC_CTX_INIT_PMOD(cctx, node->module->parsed, NULL);
LOG_LOCSET(node, NULL, NULL, NULL);
ret = lys_compile_unres_when(&cctx, node, unres);
@@ -1457,7 +1540,7 @@
while (ds_unres->musts.count) {
i = ds_unres->musts.count - 1;
m = ds_unres->musts.objs[i];
- LYSC_CTX_INIT_PMOD(cctx, m->node->module->parsed);
+ LYSC_CTX_INIT_PMOD(cctx, m->node->module->parsed, m->ext);
LOG_LOCSET(m->node, NULL, NULL, NULL);
ret = lys_compile_unres_must(&cctx, m->node, m->local_mods, unres);
@@ -1472,7 +1555,7 @@
while (ds_unres->disabled_bitenums.count) {
i = ds_unres->disabled_bitenums.count - 1;
node = ds_unres->disabled_bitenums.objs[i];
- LYSC_CTX_INIT_PMOD(cctx, node->module->parsed);
+ LYSC_CTX_INIT_PMOD(cctx, node->module->parsed, NULL);
LOG_LOCSET(node, NULL, NULL, NULL);
ret = lys_compile_unres_disabled_bitenum(&cctx, (struct lysc_node_leaf *)node);
@@ -1486,7 +1569,7 @@
while (ds_unres->dflts.count) {
i = ds_unres->dflts.count - 1;
r = ds_unres->dflts.objs[i];
- LYSC_CTX_INIT_PMOD(cctx, r->leaf->module->parsed);
+ LYSC_CTX_INIT_PMOD(cctx, r->leaf->module->parsed, NULL);
LOG_LOCSET(&r->leaf->node, NULL, NULL, NULL);
if (r->leaf->nodetype == LYS_LEAF) {
@@ -1517,7 +1600,7 @@
ret = LY_EVALID;
goto cleanup;
}
- LYSC_CTX_INIT_PMOD(cctx, node->module->parsed);
+ LYSC_CTX_INIT_PMOD(cctx, node->module->parsed, NULL);
lysc_node_free(&cctx.free_ctx, node, 1);
}
@@ -1525,11 +1608,11 @@
/* also check if the leafref target has not been disabled */
for (i = 0; i < ds_unres->leafrefs.count; ++i) {
l = ds_unres->leafrefs.objs[i];
- LYSC_CTX_INIT_PMOD(cctx, l->node->module->parsed);
+ LYSC_CTX_INIT_PMOD(cctx, l->node->module->parsed, l->ext);
v = 0;
while ((lref = lys_type_leafref_next(l->node, &v))) {
- ret = ly_path_compile_leafref(cctx.ctx, l->node, NULL, lref->path,
+ ret = ly_path_compile_leafref(cctx.ctx, l->node, cctx.ext, lref->path,
(l->node->flags & LYS_IS_OUTPUT) ? LY_PATH_OPER_OUTPUT : LY_PATH_OPER_INPUT, LY_PATH_TARGET_MANY,
LY_VALUE_SCHEMA_RESOLVED, lref->prefixes, &path);
ly_path_free(l->node->module->ctx, path);
@@ -1778,7 +1861,7 @@
assert(mod->implemented && mod->to_compile);
sp = mod->parsed;
- LYSC_CTX_INIT_PMOD(ctx, sp);
+ LYSC_CTX_INIT_PMOD(ctx, sp, NULL);
ctx.unres = unres;
++mod->ctx->change_count;
@@ -1899,7 +1982,7 @@
}
/* prepare context */
- LYSC_CTX_INIT_PMOD(ctx, mod->parsed);
+ LYSC_CTX_INIT_PMOD(ctx, mod->parsed, NULL);
if (mod->parsed->identities) {
rc = lys_compile_identities_derived(&ctx, mod->parsed->identities, &mod->identities);
diff --git a/src/schema_compile.h b/src/schema_compile.h
index c68fd43..919a994 100644
--- a/src/schema_compile.h
+++ b/src/schema_compile.h
@@ -77,12 +77,14 @@
*
* @param[out] CCTX Compile context.
* @param[in] PMOD Parsed module.
+ * @param[in] EXT Ancestor extension instance.
*/
-#define LYSC_CTX_INIT_PMOD(CCTX, PMOD) \
+#define LYSC_CTX_INIT_PMOD(CCTX, PMOD, EXT) \
memset(&(CCTX), 0, sizeof (CCTX)); \
(CCTX).ctx = (PMOD)->mod->ctx; \
(CCTX).cur_mod = (PMOD)->mod; \
(CCTX).pmod = (PMOD); \
+ (CCTX).ext = (EXT); \
(CCTX).path_len = 1; \
(CCTX).path[0] = '/'; \
(CCTX).free_ctx.ctx = (PMOD)->mod->ctx
@@ -119,16 +121,18 @@
* @brief Structure for storing schema nodes with must expressions and local module for each of them.
*/
struct lysc_unres_must {
- struct lysc_node *node; /**< node with the must expression(s) */
+ struct lysc_node *node; /**< node with the must expression(s) */
const struct lysp_module **local_mods; /**< sized array of local modules for must(s) */
+ struct lysc_ext_instance *ext; /**< ancestor extension instance of the must(s) */
};
/**
* @brief Structure for storing leafref node and its local module.
*/
struct lysc_unres_leafref {
- struct lysc_node *node; /**< leaf/leaf-list node with leafref type */
+ struct lysc_node *node; /**< leaf/leaf-list node with leafref type */
const struct lysp_module *local_mod; /**< local module of the leafref type */
+ struct lysc_ext_instance *ext; /**< ancestor extension instance of the leafref */
};
/**
@@ -241,6 +245,15 @@
struct lysc_ident *ident, struct lysc_ident ***bases);
/**
+ * @brief Get compiled ext instance storage for a specific statement.
+ *
+ * @param[in] ext Compiled ext instance.
+ * @param[in] stmt Stored statement.
+ * @return Compiled ext instance substatement storage, NULL if substaement not supported or not stored.
+ */
+const void *lys_compile_ext_instance_get_storage(const struct lysc_ext_instance *ext, enum ly_stmt stmt);
+
+/**
* @brief Perform a complet compilation of identites in a module and all its submodules.
*
* @param[in] mod Module to process.
diff --git a/src/schema_compile_amend.c b/src/schema_compile_amend.c
index bab8ba3..66d2005 100644
--- a/src/schema_compile_amend.c
+++ b/src/schema_compile_amend.c
@@ -2222,7 +2222,7 @@
struct ly_set mod_set = {0}, set = {0};
mod_p = mod->parsed;
- LYSC_CTX_INIT_PMOD(ctx, mod_p);
+ LYSC_CTX_INIT_PMOD(ctx, mod_p, NULL);
LY_LIST_FOR(mod_p->augments, aug) {
/* get target module */
diff --git a/src/schema_compile_node.c b/src/schema_compile_node.c
index 881759e..9263c95 100644
--- a/src/schema_compile_node.c
+++ b/src/schema_compile_node.c
@@ -95,6 +95,9 @@
LY_ARRAY_INCREMENT(m->local_mods);
}
+ /* store ext */
+ m->ext = ctx->ext;
+
LY_CHECK_ERR_GOTO(ly_set_add(&ctx->unres->musts, m, 1, NULL), ret = LY_EMEM, error);
return LY_SUCCESS;
@@ -144,6 +147,7 @@
l->node = &leaf->node;
l->local_mod = local_mod;
+ l->ext = ctx->ext;
LY_CHECK_ERR_RET(ly_set_add(leafrefs_set, l, 1, NULL), free(l); LOGMEM(ctx->ctx), LY_EMEM);
}
@@ -462,14 +466,7 @@
return LY_SUCCESS;
}
-/**
- * @brief Compile information from the must statement
- * @param[in] ctx Compile context.
- * @param[in] must_p The parsed must statement structure.
- * @param[in,out] must Prepared (empty) compiled must structure to fill.
- * @return LY_ERR value.
- */
-static LY_ERR
+LY_ERR
lys_compile_must(struct lysc_ctx *ctx, struct lysp_restr *must_p, struct lysc_must *must)
{
LY_ERR ret = LY_SUCCESS;
@@ -1972,9 +1969,9 @@
tctx = calloc(1, sizeof *tctx);
LY_CHECK_ERR_RET(!tctx, LOGMEM(ctx->ctx), LY_EMEM);
- for (ret = lysp_type_find(type_p->name, context_pnode, type_p->pmod, &basetype, &tctx->tpdf, &tctx->node);
+ for (ret = lysp_type_find(type_p->name, context_pnode, type_p->pmod, ctx->ext, &basetype, &tctx->tpdf, &tctx->node);
ret == LY_SUCCESS;
- ret = lysp_type_find(tctx_prev->tpdf->type.name, tctx_prev->node, tctx_prev->tpdf->type.pmod,
+ ret = lysp_type_find(tctx_prev->tpdf->type.name, tctx_prev->node, tctx_prev->tpdf->type.pmod, ctx->ext,
&basetype, &tctx->tpdf, &tctx->node)) {
if (basetype) {
break;
@@ -2515,20 +2512,22 @@
*
* @param[in] ctx Compile context.
* @param[in] node Compiled node where the flags will be set.
- * @param[in] uses_status If the node is being placed instead of uses, here we have the uses's status value (as node's flags).
- * Zero means no uses, non-zero value with no status bit set mean the default status.
+ * @param[in] inherited_status Explicitly inherited status (from uses/extension instance), if any.
*/
static LY_ERR
-lys_compile_node_flags(struct lysc_ctx *ctx, struct lysc_node *node, uint16_t uses_status)
+lys_compile_node_flags(struct lysc_ctx *ctx, struct lysc_node *node, const uint16_t *inherited_status)
{
+ uint16_t parent_flags;
+ const char *parent_name;
+
/* inherit config flags */
LY_CHECK_RET(lys_compile_config(ctx, node));
/* status - it is not inherited by specification, but it does not make sense to have
* current in deprecated or deprecated in obsolete, so we do print warning and inherit status */
- LY_CHECK_RET(lys_compile_status(ctx, &node->flags, node->name, uses_status ? uses_status :
- (node->parent ? node->parent->flags : 0), uses_status ? "<uses>" : (node->parent ? node->parent->name : NULL),
- !uses_status));
+ parent_flags = inherited_status ? *inherited_status : (node->parent ? node->parent->flags : 0);
+ parent_name = inherited_status ? "<schema-only-node>" : (node->parent ? node->parent->name : NULL);
+ LY_CHECK_RET(lys_compile_status(ctx, &node->flags, node->name, parent_flags, parent_name, inherited_status ? 1 : 0));
/* other flags */
if ((ctx->compile_opts & LYS_IS_INPUT) && (node->nodetype != LYS_INPUT)) {
@@ -2542,8 +2541,8 @@
return LY_SUCCESS;
}
-LY_ERR
-lys_compile_node_(struct lysc_ctx *ctx, struct lysp_node *pnode, struct lysc_node *parent, uint16_t uses_status,
+static LY_ERR
+lys_compile_node_(struct lysc_ctx *ctx, struct lysp_node *pnode, struct lysc_node *parent, const uint16_t *inherited_status,
LY_ERR (*node_compile_spec)(struct lysc_ctx *, struct lysp_node *, struct lysc_node *),
struct lysc_node *node, struct ly_set *child_set)
{
@@ -2583,7 +2582,7 @@
}
/* config, status and other flags */
- ret = lys_compile_node_flags(ctx, node, uses_status);
+ ret = lys_compile_node_flags(ctx, node, inherited_status);
LY_CHECK_GOTO(ret, error);
/* list ordering */
@@ -3584,6 +3583,7 @@
/**
* @brief Compile parsed anydata or anyxml node information.
+ *
* @param[in] ctx Compile context
* @param[in] pnode Parsed anydata or anyxml node.
* @param[in,out] node Pre-prepared structure from lys_compile_node() with filled generic node information
@@ -3676,19 +3676,18 @@
/**
* @brief Get the grouping with the specified name from given groupings sized array.
- * @param[in] grps Linked list of groupings.
+ *
+ * @param[in] node Linked list of nodes with groupings.
* @param[in] name Name of the grouping to find,
* @return NULL when there is no grouping with the specified name
* @return Pointer to the grouping of the specified @p name.
*/
static struct lysp_node_grp *
-match_grouping(struct lysp_node_grp *grps, const char *name)
+match_grouping(const struct lysp_node_grp *node, const char *name)
{
- struct lysp_node_grp *grp;
-
- LY_LIST_FOR(grps, grp) {
- if (!strcmp(grp->name, name)) {
- return grp;
+ LY_LIST_FOR(node, node) {
+ if ((node->nodetype == LYS_GROUPING) && !strcmp(node->name, name)) {
+ return (struct lysp_node_grp *)node;
}
}
@@ -3710,6 +3709,7 @@
{
struct lysp_node *pnode;
struct lysp_node_grp *grp;
+ struct lysp_node_grp * const *ext_grp;
LY_ARRAY_COUNT_TYPE u;
const char *id, *name, *prefix, *local_pref;
size_t prefix_len, name_len;
@@ -3727,11 +3727,19 @@
/* current module, search local groupings first */
pmod = ctx->pmod->mod->parsed; /* make sure that we will start in main_module, not submodule */
for (pnode = uses_p->parent; !found && pnode; pnode = pnode->parent) {
- if ((grp = match_grouping((struct lysp_node_grp *)lysp_node_groupings(pnode), name))) {
+ if ((grp = match_grouping(lysp_node_groupings(pnode), name))) {
found = ctx->pmod;
break;
}
}
+
+ /* if in an extension, search possible groupings in it */
+ if (ctx->ext) {
+ ext_grp = lys_compile_ext_instance_get_storage(ctx->ext, LY_STMT_GROUPING);
+ if (ext_grp && (grp = match_grouping(*ext_grp, name))) {
+ found = ctx->pmod;
+ }
+ }
} else {
/* foreign module, find it first */
mod = ly_resolve_prefix(ctx->ctx, prefix, prefix_len, LY_VALUE_SCHEMA, ctx->pmod);
@@ -3778,7 +3786,7 @@
*
* @param[in] ctx Compile context.
* @param[in] uses_p Parsed uses.
- * @param[in] uses_flags Special uses flags to use.
+ * @param[in] parent_status Parent status flags to inherit.
* @param[in] child First grouping child to compile.
* @param[in] grp_mod Grouping parsed module.
* @param[in] parent Uses compiled parent, may be NULL if top-level.
@@ -3788,8 +3796,9 @@
* @return LY_EVALID on failure.
*/
static LY_ERR
-lys_compile_uses_children(struct lysc_ctx *ctx, struct lysp_node_uses *uses_p, uint16_t uses_flags, struct lysp_node *child,
- struct lysp_module *grp_mod, struct lysc_node *parent, struct ly_set *child_set, ly_bool child_unres_disabled)
+lys_compile_uses_children(struct lysc_ctx *ctx, struct lysp_node_uses *uses_p, uint16_t parent_status,
+ struct lysp_node *child, struct lysp_module *grp_mod, struct lysc_node *parent, struct ly_set *child_set,
+ ly_bool child_unres_disabled)
{
LY_ERR rc = LY_SUCCESS;
struct lysp_module *mod_old = ctx->pmod;
@@ -3805,7 +3814,7 @@
LY_LIST_FOR(child, pnode) {
/* compile the nodes with their parsed (grouping) module */
ctx->pmod = grp_mod;
- LY_CHECK_GOTO(rc = lys_compile_node(ctx, pnode, parent, uses_flags, child_set), cleanup);
+ LY_CHECK_GOTO(rc = lys_compile_node(ctx, pnode, parent, &parent_status, child_set), cleanup);
/* eval if-features again for the rest of this node processing */
LY_CHECK_GOTO(rc = lys_eval_iffeatures(ctx->ctx, pnode->iffeatures, &enabled), cleanup);
@@ -3823,7 +3832,7 @@
if (uses_p->when) {
/* pass uses when to all the children */
- rc = lys_compile_when(ctx, uses_p->when, uses_flags, parent, lysc_data_node(parent), node, &when_shared);
+ rc = lys_compile_when(ctx, uses_p->when, parent_status, parent, lysc_data_node(parent), node, &when_shared);
LY_CHECK_GOTO(rc, cleanup);
}
@@ -3846,11 +3855,6 @@
}
/**
- * @brief Special bits combination marking the uses_status value and propagated by ::lys_compile_uses() function.
- */
-#define LYS_STATUS_USES LYS_CONFIG_MASK
-
-/**
* @brief Compile parsed uses statement - resolve target grouping and connect its content into parent.
* If present, also apply uses's modificators.
*
@@ -3859,17 +3863,20 @@
* @param[in] parent Compiled parent node where the content of the referenced grouping is supposed to be connected. It is
* NULL for top-level nodes, in such a case the module where the node will be connected is taken from
* the compile context.
+ * @param[in] inherited_status Explicitly inherited status (from uses/extension instance), if any.
* @param[in] child_set Optional set of all the compiled children.
* @return LY_ERR value - LY_SUCCESS or LY_EVALID.
*/
static LY_ERR
-lys_compile_uses(struct lysc_ctx *ctx, struct lysp_node_uses *uses_p, struct lysc_node *parent, struct ly_set *child_set)
+lys_compile_uses(struct lysc_ctx *ctx, struct lysp_node_uses *uses_p, struct lysc_node *parent,
+ const uint16_t *inherited_status, struct ly_set *child_set)
{
LY_ERR rc = LY_SUCCESS;
ly_bool enabled, child_unres_disabled = 0;
uint32_t i, grp_stack_count, opt_prev = ctx->compile_opts;
struct lysp_node_grp *grp = NULL;
- uint16_t uses_flags;
+ uint16_t uses_flags, parent_flags;
+ const char *parent_name;
struct lysp_module *grp_mod;
struct ly_set uses_child_set = {0};
@@ -3912,9 +3919,10 @@
/* compile special uses status flags */
uses_flags = uses_p->flags;
- rc = lys_compile_status(ctx, &uses_flags, "<uses>", parent ? parent->flags : 0, parent ? parent->name : NULL, 0);
+ parent_flags = inherited_status ? *inherited_status : (parent ? parent->flags : 0);
+ parent_name = inherited_status ? "<schema-only-node>" : (parent ? parent->name : NULL);
+ rc = lys_compile_status(ctx, &uses_flags, "<uses>", parent_flags, parent_name, inherited_status ? 1 : 0);
LY_CHECK_GOTO(rc, cleanup);
- uses_flags |= LYS_STATUS_USES;
/* uses if-features */
LY_CHECK_GOTO(rc = lys_eval_iffeatures(ctx->ctx, uses_p->iffeatures, &enabled), cleanup);
@@ -4072,7 +4080,7 @@
lysc_update_path(ctx, NULL, "{grouping}");
lysc_update_path(ctx, NULL, grp->name);
- ret = lys_compile_uses(ctx, &fake_uses, &fake_container.node, NULL);
+ ret = lys_compile_uses(ctx, &fake_uses, &fake_container.node, NULL, NULL);
lysc_update_path(ctx, NULL, NULL);
lysc_update_path(ctx, NULL, NULL);
@@ -4086,7 +4094,7 @@
}
LY_ERR
-lys_compile_node(struct lysc_ctx *ctx, struct lysp_node *pnode, struct lysc_node *parent, uint16_t uses_status,
+lys_compile_node(struct lysc_ctx *ctx, struct lysp_node *pnode, struct lysc_node *parent, const uint16_t *inherited_status,
struct ly_set *child_set)
{
LY_ERR ret = LY_SUCCESS;
@@ -4156,7 +4164,7 @@
ctx->compile_opts |= LYS_COMPILE_NOTIFICATION;
break;
case LYS_USES:
- ret = lys_compile_uses(ctx, (struct lysp_node_uses *)pnode, parent, child_set);
+ ret = lys_compile_uses(ctx, (struct lysp_node_uses *)pnode, parent, inherited_status, child_set);
lysc_update_path(ctx, NULL, NULL);
lysc_update_path(ctx, NULL, NULL);
return ret;
@@ -4166,7 +4174,7 @@
}
LY_CHECK_ERR_RET(!node, LOGMEM(ctx->ctx), LY_EMEM);
- ret = lys_compile_node_(ctx, pnode, parent, uses_status, node_compile_spec, node, child_set);
+ ret = lys_compile_node_(ctx, pnode, parent, inherited_status, node_compile_spec, node, child_set);
ctx->compile_opts = prev_opts;
lysc_update_path(ctx, NULL, NULL);
diff --git a/src/schema_compile_node.h b/src/schema_compile_node.h
index 7a57da5..3b1eb6b 100644
--- a/src/schema_compile_node.h
+++ b/src/schema_compile_node.h
@@ -45,6 +45,16 @@
struct lysc_when **when_c);
/**
+ * @brief Compile information from the must statement
+ *
+ * @param[in] ctx Compile context.
+ * @param[in] must_p The parsed must statement structure.
+ * @param[in,out] must Prepared (empty) compiled must structure to fill.
+ * @return LY_ERR value.
+ */
+LY_ERR lys_compile_must(struct lysc_ctx *ctx, struct lysp_restr *must_p, struct lysc_must *must);
+
+/**
* @brief Checks pattern syntax.
*
* @param[in] ctx Context.
@@ -56,6 +66,7 @@
/**
* @brief Compile parsed pattern restriction in conjunction with the patterns from base type.
+ *
* @param[in] ctx Compile context.
* @param[in] patterns_p Array of parsed patterns from the current type to compile.
* @param[in] base_patterns Compiled patterns from the type from which the current type is derived.
@@ -128,12 +139,11 @@
* @param[in] parent Compiled parent node where the current node is supposed to be connected. It is
* NULL for top-level nodes, in such a case the module where the node will be connected is taken from
* the compile context.
- * @param[in] uses_status If the node is being placed instead of uses, here we have the uses's status value (as node's flags).
- * Zero means no uses, non-zero value with no status bit set mean the default status.
+ * @param[in] inherited_status Explicitly inherited status (from uses/extension instance), if any.
* @param[in,out] child_set Optional set to add all the compiled nodes into (can be more in case of uses).
* @return LY_ERR value - LY_SUCCESS or LY_EVALID.
*/
-LY_ERR lys_compile_node(struct lysc_ctx *ctx, struct lysp_node *pnode, struct lysc_node *parent, uint16_t uses_status,
- struct ly_set *child_set);
+LY_ERR lys_compile_node(struct lysc_ctx *ctx, struct lysp_node *pnode, struct lysc_node *parent,
+ const uint16_t *inherited_status, struct ly_set *child_set);
#endif /* LY_SCHEMA_COMPILE_NODE_H_ */
diff --git a/src/tree_schema.h b/src/tree_schema.h
index 32044a8..892bb81 100644
--- a/src/tree_schema.h
+++ b/src/tree_schema.h
@@ -1,9 +1,10 @@
/**
* @file tree_schema.h
* @author Radek Krejci <rkrejci@cesnet.cz>
+ * @author Michal Vasko <mvasko@cesnet.cz>
* @brief libyang representation of YANG schema trees.
*
- * Copyright (c) 2015 - 2018 CESNET, z.s.p.o.
+ * Copyright (c) 2015 - 2022 CESNET, z.s.p.o.
*
* This source code is licensed under BSD 3-Clause License (the "License").
* You may not use this file except in compliance with the License.
@@ -274,10 +275,11 @@
* This macro matches a subset of schema nodes that maps to common ::lysc_node or ::lysp_node structures. To match all
* such nodes, use ::LY_STMT_IS_NODE()
*
- * This macro matches anydata, anyxml, augment, case, choice, container, grouping, leaf, leaf-list, list and uses. Note
- * that the list of statements that can appear in parsed or compiled schema trees differs (e.g. no uses in compiled tree).
+ * This macro matches anydata, anyxml, case, choice, container, leaf, leaf-list, and list.
*/
-#define LY_STMT_IS_DATA_NODE(STMT) (((STMT) >= LY_STMT_ANYDATA) && ((STMT) <= LY_STMT_LIST))
+#define LY_STMT_IS_DATA_NODE(STMT) (((STMT) == LY_STMT_ANYDATA) || ((STMT) == LY_STMT_ANYXML) || \
+ ((STMT) == LY_STMT_CASE) || ((STMT) == LY_STMT_CHOICE) || ((STMT) == LY_STMT_CONTAINER) || \
+ ((STMT) == LY_STMT_LEAF) || ((STMT) == LY_STMT_LEAF_LIST) || ((STMT) == LY_STMT_LIST))
/**
* @brief Generic test for any schema node that maps to common ::lysc_node or ::lysp_node structures.
@@ -302,16 +304,12 @@
data definition nodes as it is done in generic structures of libyang. */
LY_STMT_INPUT,
LY_STMT_OUTPUT,
-
-/* LY_STMT_IS_OP */
LY_STMT_ACTION, /**< in ::lysc_ext_substmt.storage stored as a pointer to linked list of `struct lysc_node_action *`.
The RPCs/Actions and Notifications are expected in a separated lists than the rest of
data definition nodes as it is done in generic structures of libyang. */
LY_STMT_RPC, /**< in ::lysc_ext_substmt.storage stored as a pointer to linked list of `struct lysc_node_action *`.
The RPCs/Actions and Notifications are expected in a separated lists than the rest of
data definition nodes as it is done in generic structures of libyang. */
-
-/* LY_STMT_IS_DATA_NODE */
LY_STMT_ANYDATA, /**< in ::lysc_ext_substmt.storage stored as a pointer to linked list of `struct lysc_node *`.
Note that due to ::lysc_node compatibility the anydata is expected to be actually
mixed in the linked list with other ::lysc_node based nodes. The RPCs/Actions and
@@ -352,7 +350,6 @@
of libyang. */
LY_STMT_USES,
-/* rest */
LY_STMT_ARGUMENT,
LY_STMT_BASE,
LY_STMT_BELONGS_TO,
@@ -537,7 +534,7 @@
const char *argument; /**< optional value of the extension's argument */
LY_VALUE_FORMAT format; /**< prefix format of the extension name/argument (::LY_VALUE_XML is YIN format) */
struct lysp_node *parsed; /**< Simply parsed (unresolved) YANG schema tree serving as a cache.
- Only lys_compile_extension_instance() can set this. */
+ Only ::lys_compile_extension_instance() can set this. */
void *prefix_data; /**< Format-specific data for prefix resolution
(see ly_resolve_prefix()) */
diff --git a/src/tree_schema_common.c b/src/tree_schema_common.c
index 2dc47c8..fe7b741 100644
--- a/src/tree_schema_common.c
+++ b/src/tree_schema_common.c
@@ -125,39 +125,36 @@
}
}
-static const struct lysp_tpdf *
-lysp_type_match(const char *name, struct lysp_node *node)
+LY_ERR
+lysp_check_enum_name(struct lys_parser_ctx *ctx, const char *name, size_t name_len)
{
- const struct lysp_tpdf *typedefs;
- LY_ARRAY_COUNT_TYPE u;
-
- typedefs = lysp_node_typedefs(node);
- LY_ARRAY_FOR(typedefs, u) {
- if (!strcmp(name, typedefs[u].name)) {
- /* match */
- return &typedefs[u];
+ if (!name_len) {
+ LOGVAL_PARSER(ctx, LYVE_SYNTAX_YANG, "Enum name must not be zero-length.");
+ return LY_EVALID;
+ } else if (isspace(name[0]) || isspace(name[name_len - 1])) {
+ LOGVAL_PARSER(ctx, LYVE_SYNTAX_YANG, "Enum name must not have any leading or trailing whitespaces (\"%.*s\").",
+ (int)name_len, name);
+ return LY_EVALID;
+ } else {
+ for (size_t u = 0; u < name_len; ++u) {
+ if (iscntrl(name[u])) {
+ LOGWRN(PARSER_CTX(ctx), "Control characters in enum name should be avoided (\"%.*s\", character number %d).",
+ (int)name_len, name, u + 1);
+ break;
+ }
}
}
- return NULL;
+ return LY_SUCCESS;
}
-static const struct lysp_node_grp *
-lysp_grouping_match(const char *name, struct lysp_node *node)
-{
- const struct lysp_node_grp *groupings, *grp_iter;
-
- groupings = lysp_node_groupings(node);
- LY_LIST_FOR(groupings, grp_iter) {
- if (!strcmp(name, grp_iter->name)) {
- /* match */
- return grp_iter;
- }
- }
-
- return NULL;
-}
-
+/**
+ * @brief Learn built-in type from its name.
+ *
+ * @param[in] name Type name.
+ * @param[in] len Length of @p name.
+ * @return Built-in data type, ::LY_TYPE_UNKNOWN if none matches.
+ */
static LY_DATA_TYPE
lysp_type_str2builtin(const char *name, size_t len)
{
@@ -232,12 +229,34 @@
return LY_TYPE_UNKNOWN;
}
+/**
+ * @brief Find a typedef in a sized array.
+ *
+ * @param[in] name Typedef name.
+ * @param[in] typedefs Sized array of typedefs.
+ * @return Found typedef, NULL if none.
+ */
+static const struct lysp_tpdf *
+lysp_typedef_match(const char *name, const struct lysp_tpdf *typedefs)
+{
+ LY_ARRAY_COUNT_TYPE u;
+
+ LY_ARRAY_FOR(typedefs, u) {
+ if (!strcmp(name, typedefs[u].name)) {
+ /* match */
+ return &typedefs[u];
+ }
+ }
+ return NULL;
+}
+
LY_ERR
lysp_type_find(const char *id, struct lysp_node *start_node, const struct lysp_module *start_module,
- LY_DATA_TYPE *type, const struct lysp_tpdf **tpdf, struct lysp_node **node)
+ const struct lysc_ext_instance *ext, LY_DATA_TYPE *type, const struct lysp_tpdf **tpdf, struct lysp_node **node)
{
const char *str, *name;
struct lysp_tpdf *typedefs;
+ const struct lysp_tpdf **ext_typedefs;
const struct lys_module *mod;
const struct lysp_module *local_module;
LY_ARRAY_COUNT_TYPE u, v;
@@ -267,16 +286,25 @@
}
LY_CHECK_RET(!local_module, LY_ENOTFOUND);
- if (start_node && (local_module == start_module)) {
- /* search typedefs in parent's nodes */
- *node = start_node;
- while (*node) {
- *tpdf = lysp_type_match(name, *node);
- if (*tpdf) {
+ if (local_module == start_module) {
+ if (start_node) {
+ /* search typedefs in parent's nodes */
+ for (*node = start_node; *node; *node = (*node)->parent) {
+ *tpdf = lysp_typedef_match(name, lysp_node_typedefs(*node));
+ if (*tpdf) {
+ /* match */
+ return LY_SUCCESS;
+ }
+ }
+ }
+
+ if (ext) {
+ /* search typedefs directly in the extension */
+ ext_typedefs = (void *)lys_compile_ext_instance_get_storage(ext, LY_STMT_TYPEDEF);
+ if (ext_typedefs && (*tpdf = lysp_typedef_match(name, *ext_typedefs))) {
/* match */
return LY_SUCCESS;
}
- *node = (*node)->parent;
}
}
@@ -309,29 +337,6 @@
return LY_ENOTFOUND;
}
-LY_ERR
-lysp_check_enum_name(struct lys_parser_ctx *ctx, const char *name, size_t name_len)
-{
- if (!name_len) {
- LOGVAL_PARSER(ctx, LYVE_SYNTAX_YANG, "Enum name must not be zero-length.");
- return LY_EVALID;
- } else if (isspace(name[0]) || isspace(name[name_len - 1])) {
- LOGVAL_PARSER(ctx, LYVE_SYNTAX_YANG, "Enum name must not have any leading or trailing whitespaces (\"%.*s\").",
- (int)name_len, name);
- return LY_EVALID;
- } else {
- for (size_t u = 0; u < name_len; ++u) {
- if (iscntrl(name[u])) {
- LOGWRN(PARSER_CTX(ctx), "Control characters in enum name should be avoided (\"%.*s\", character number %d).",
- (int)name_len, name, u + 1);
- break;
- }
- }
- }
-
- return LY_SUCCESS;
-}
-
/**
* @brief Insert @p name to hash table and if @p name has already
* been added, then log an error.
@@ -415,7 +420,7 @@
}
/* search typedefs in parent's nodes */
for (parent = node->parent; parent; parent = parent->parent) {
- if (lysp_type_match(name, parent)) {
+ if (lysp_typedef_match(name, lysp_node_typedefs(parent))) {
LOGVAL_PARSER(ctx, LYVE_SYNTAX_YANG,
"Duplicate identifier \"%s\" of typedef statement - name collision with another scoped type.", name);
return LY_EVALID;
@@ -491,6 +496,22 @@
return ret;
}
+static const struct lysp_node_grp *
+lysp_grouping_match(const char *name, struct lysp_node *node)
+{
+ const struct lysp_node_grp *groupings, *grp_iter;
+
+ groupings = lysp_node_groupings(node);
+ LY_LIST_FOR(groupings, grp_iter) {
+ if (!strcmp(name, grp_iter->name)) {
+ /* match */
+ return grp_iter;
+ }
+ }
+
+ return NULL;
+}
+
/**
* @brief Check name of a new grouping to avoid name collisions.
*
@@ -1838,17 +1859,6 @@
}
}
-struct lys_module *
-lysp_find_module(struct ly_ctx *ctx, const struct lysp_module *mod)
-{
- for (uint32_t u = 0; u < ctx->list.count; ++u) {
- if (((struct lys_module *)ctx->list.objs[u])->parsed == mod) {
- return (struct lys_module *)ctx->list.objs[u];
- }
- }
- return NULL;
-}
-
enum ly_stmt
lysp_match_kw(struct ly_in *in, uint64_t *indent)
{
diff --git a/src/tree_schema_free.c b/src/tree_schema_free.c
index 1716869..34f1a22 100644
--- a/src/tree_schema_free.c
+++ b/src/tree_schema_free.c
@@ -247,6 +247,10 @@
void
lysp_type_free(struct lysf_ctx *ctx, struct lysp_type *type)
{
+ if (!type) {
+ return;
+ }
+
lydict_remove(ctx->ctx, type->name);
FREE_MEMBER(ctx, type->range, lysp_restr_free);
FREE_MEMBER(ctx, type->length, lysp_restr_free);
@@ -703,6 +707,10 @@
static void
lysc_must_free(struct lysf_ctx *ctx, struct lysc_must *must)
{
+ if (!must) {
+ return;
+ }
+
lyxp_expr_free(ctx->ctx, must->cond);
ly_free_prefix_data(LY_VALUE_SCHEMA_RESOLVED, must->prefixes);
lydict_remove(ctx->ctx, must->emsg);
@@ -1366,15 +1374,24 @@
case LY_STMT_LEAF_LIST:
case LY_STMT_LIST:
case LY_STMT_NOTIFICATION:
- case LY_STMT_RPC:
- case LY_STMT_USES: {
+ case LY_STMT_RPC: {
struct lysc_node *child, *child_next;
LY_LIST_FOR_SAFE(*((struct lysc_node **)substmts[u].storage), child_next, child) {
lysc_node_free_(&fctx, child);
}
+ *((struct lysc_node **)substmts[u].storage) = NULL;
break;
}
+ case LY_STMT_GROUPING: {
+ struct lysp_node_grp *grp, *grp_next;
+
+ LY_LIST_FOR_SAFE(*((struct lysp_node_grp **)substmts[u].storage), grp_next, grp) {
+ lysp_node_free(&fctx, &grp->node);
+ }
+ break;
+ }
+ case LY_STMT_USES:
case LY_STMT_CONFIG:
case LY_STMT_STATUS:
/* nothing to do */
@@ -1393,20 +1410,28 @@
/* single item */
const char *str = *((const char **)substmts[u].storage);
- if (!str) {
- break;
- }
lydict_remove(ctx, str);
} else {
/* multiple items */
const char **strs = *((const char ***)substmts[u].storage);
- if (!strs) {
- break;
- }
FREE_STRINGS(ctx, strs);
}
break;
+ case LY_STMT_MUST:
+ if (substmts[u].cardinality < LY_STMT_CARD_SOME) {
+ /* single item */
+ struct lysc_must *must = *((struct lysc_must **)substmts[u].storage);
+
+ lysc_must_free(&fctx, must);
+ free(must);
+ } else {
+ /* multiple items */
+ struct lysc_must *musts = *((struct lysc_must **)substmts[u].storage);
+
+ FREE_ARRAY(&fctx, musts, lysc_must_free);
+ }
+ break;
case LY_STMT_IF_FEATURE: {
struct lysc_iffeature *iff = *((struct lysc_iffeature **)substmts[u].storage);
@@ -1423,6 +1448,16 @@
}
break;
}
+ case LY_STMT_TYPEDEF: {
+ struct lysp_tpdf *tpdf = *((struct lysp_tpdf **)substmts[u].storage);
+
+ if (!tpdf) {
+ break;
+ }
+ /* always an array */
+ FREE_ARRAY(&fctx, tpdf, lysp_tpdf_free);
+ break;
+ }
case LY_STMT_TYPE:
if (substmts[u].cardinality < LY_STMT_CARD_SOME) {
/* single item */
diff --git a/src/tree_schema_internal.h b/src/tree_schema_internal.h
index 94205d6..e90920a 100644
--- a/src/tree_schema_internal.h
+++ b/src/tree_schema_internal.h
@@ -237,6 +237,21 @@
LY_ERR lysp_check_date(struct lys_parser_ctx *ctx, const char *date, size_t date_len, const char *stmt);
/**
+ * @brief Find type specified type definition.
+ *
+ * @param[in] id Name of the type including possible prefix. Module where the prefix is being searched is start_module.
+ * @param[in] start_node Context node where the type is being instantiated to be able to search typedefs in parents.
+ * @param[in] start_module Module where the type is being instantiated for search for typedefs.
+ * @param[in] ext Extension where the type is being instantiated, if any.
+ * @param[out] type Built-in type identifier of the id. If #LY_TYPE_UNKNOWN, tpdf is expected to contain found YANG schema typedef statement.
+ * @param[out] tpdf Found type definition.
+ * @param[out] node Node where the found typedef is defined, NULL in case of a top-level typedef.
+ * @return LY_ERR value.
+ */
+LY_ERR lysp_type_find(const char *id, struct lysp_node *start_node, const struct lysp_module *start_module,
+ const struct lysc_ext_instance *ext, LY_DATA_TYPE *type, const struct lysp_tpdf **tpdf, struct lysp_node **node);
+
+/**
* @brief Check names of typedefs in the parsed module to detect collisions.
*
* @param[in] ctx Parser context for logging and to maintain tpdfs_nodes
@@ -279,19 +294,6 @@
void lysp_sort_revisions(struct lysp_revision *revs);
/**
- * @brief Find type specified type definition.
- *
- * @param[in] id Name of the type including possible prefix. Module where the prefix is being searched is start_module.
- * @param[in] start_node Context node where the type is being instantiated to be able to search typedefs in parents.
- * @param[in] start_module Module where the type is being instantiated for search for typedefs.
- * @param[out] type Built-in type identifier of the id. If #LY_TYPE_UNKNOWN, tpdf is expected to contain found YANG schema typedef statement.
- * @param[out] tpdf Found type definition.
- * @param[out] node Node where the found typedef is defined, NULL in case of a top-level typedef.
- */
-LY_ERR lysp_type_find(const char *id, struct lysp_node *start_node, const struct lysp_module *start_module,
- LY_DATA_TYPE *type, const struct lysp_tpdf **tpdf, struct lysp_node **node);
-
-/**
* @brief Validate enum name.
*
* @param[in] ctx yang parser context for logging.
@@ -495,16 +497,8 @@
LY_ARRAY_COUNT_TYPE lysp_ext_instance_iter(struct lysp_ext_instance *ext, LY_ARRAY_COUNT_TYPE index, enum ly_stmt substmt);
/**
- * @brief Get the covering schema module structure for the given parsed module structure.
- *
- * @param[in] ctx libyang context to search.
- * @param[in] mod Parsed schema structure.
- * @return Corresponding lys_module structure for the given parsed schema structure.
- */
-struct lys_module *lysp_find_module(struct ly_ctx *ctx, const struct lysp_module *mod);
-
-/**
* @brief Stringify YANG built-in type.
+ *
* @param[in] basetype Built-in type ID to stringify.
* @return Constant string with the name of the built-in type.
*/
diff --git a/tests/utests/CMakeLists.txt b/tests/utests/CMakeLists.txt
index 5bdbd0c..ac47611 100644
--- a/tests/utests/CMakeLists.txt
+++ b/tests/utests/CMakeLists.txt
@@ -74,3 +74,4 @@
ly_add_utest(NAME nacm SOURCES extensions/test_nacm.c)
ly_add_utest(NAME yangdata SOURCES extensions/test_yangdata.c)
ly_add_utest(NAME schema_mount SOURCES extensions/test_schema_mount.c)
+ly_add_utest(NAME structure SOURCES extensions/test_structure.c)
diff --git a/tests/utests/basic/test_context.c b/tests/utests/basic/test_context.c
index bf7d203..2340d1e 100644
--- a/tests/utests/basic/test_context.c
+++ b/tests/utests/basic/test_context.c
@@ -440,7 +440,7 @@
unsigned int index = 0;
const char *names[] = {
"ietf-yang-metadata", "yang", "ietf-inet-types", "ietf-yang-types", "ietf-yang-schema-mount",
- "ietf-datastores", "ietf-yang-library", "a", "a", "a"
+ "ietf-yang-structure-ext", "ietf-datastores", "ietf-yang-library", "a", "a", "a"
};
assert_int_equal(LY_SUCCESS, ly_in_new_memory(str0, &in0));
@@ -508,7 +508,7 @@
while ((mod = (struct lys_module *)ly_ctx_get_module_iter(UTEST_LYCTX, &index))) {
assert_string_equal(names[index - 1], mod->name);
}
- assert_int_equal(10, index);
+ assert_int_equal(11, index);
/* cleanup */
ly_in_free(in0, 0);
diff --git a/tests/utests/extensions/test_structure.c b/tests/utests/extensions/test_structure.c
new file mode 100644
index 0000000..9ceab20
--- /dev/null
+++ b/tests/utests/extensions/test_structure.c
@@ -0,0 +1,192 @@
+/**
+ * @file test_structure.c
+ * @author Michal Vasko <mvasko@cesnet.cz>
+ * @brief unit tests for structure extensions support
+ *
+ * Copyright (c) 2022 CESNET, z.s.p.o.
+ *
+ * This source code is licensed under BSD 3-Clause License (the "License").
+ * You may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://opensource.org/licenses/BSD-3-Clause
+ */
+#define _UTEST_MAIN_
+#include "utests.h"
+
+#include "libyang.h"
+
+static void
+test_schema(void **state)
+{
+ struct lys_module *mod;
+ struct lysc_ext_instance *e;
+ char *printed = NULL;
+ const char *data = "module a {yang-version 1.1; namespace urn:tests:extensions:structure:a; prefix self;"
+ "import ietf-yang-structure-ext {prefix sx;}"
+ "sx:structure struct {"
+ " must \"/n2/l\";"
+ " status deprecated;"
+ " description desc;"
+ " reference no-ref;"
+ " typedef my-type {type string;}"
+ " grouping my-grp {leaf gl {type my-type;}}"
+ " grouping my-grp2 {leaf gl-obs {type uint16;}}"
+ " container n1 {leaf l {config false; type uint32;}}"
+ " list n2 {leaf l {type leafref {path /n1/l;}}}"
+ " uses my-grp;"
+ " uses my-grp2 {status obsolete;}"
+ "}}";
+ const char *info = "module a {\n"
+ " namespace \"urn:tests:extensions:structure:a\";\n"
+ " prefix self;\n"
+ "\n"
+ " ietf-yang-structure-ext:structure \"struct\" {\n"
+ " must \"/n2/l\";\n"
+ " status deprecated;\n"
+ " description\n"
+ " \"desc\";\n"
+ " reference\n"
+ " \"no-ref\";\n"
+ " container n1 {\n"
+ " status deprecated;\n"
+ " leaf l {\n"
+ " type uint32;\n"
+ " status deprecated;\n"
+ " }\n"
+ " }\n"
+ " list n2 {\n"
+ " min-elements 0;\n"
+ " max-elements 4294967295;\n"
+ " ordered-by user;\n"
+ " status deprecated;\n"
+ " leaf l {\n"
+ " type leafref {\n"
+ " path \"/n1/l\";\n"
+ " require-instance true;\n"
+ " type uint32;\n"
+ " }\n"
+ " status deprecated;\n"
+ " }\n"
+ " }\n"
+ " leaf gl {\n"
+ " type string;\n"
+ " status deprecated;\n"
+ " }\n"
+ " leaf gl-obs {\n"
+ " type uint16;\n"
+ " status obsolete;\n"
+ " }\n"
+ " }\n"
+ "}\n";
+
+ /* valid data */
+ assert_int_equal(LY_SUCCESS, lys_parse_mem(UTEST_LYCTX, data, LYS_IN_YANG, &mod));
+ assert_non_null(e = mod->compiled->exts);
+ assert_int_equal(LY_ARRAY_COUNT(mod->compiled->exts), 1);
+ assert_int_equal(LY_SUCCESS, lys_print_mem(&printed, mod, LYS_OUT_YANG_COMPILED, 0));
+ assert_string_equal(printed, info);
+ free(printed);
+
+ /* no substatements */
+ data = "module b {yang-version 1.1; namespace urn:tests:extensions:structure:b; prefix self;"
+ "import ietf-yang-structure-ext {prefix sx;}"
+ "sx:structure struct;}";
+ info = "module b {\n"
+ " namespace \"urn:tests:extensions:structure:b\";\n"
+ " prefix self;\n"
+ "\n"
+ " ietf-yang-structure-ext:structure \"struct\";\n"
+ "}\n";
+ assert_int_equal(LY_SUCCESS, lys_parse_mem(UTEST_LYCTX, data, LYS_IN_YANG, &mod));
+ assert_non_null(e = mod->compiled->exts);
+ assert_int_equal(LY_ARRAY_COUNT(mod->compiled->exts), 1);
+ assert_int_equal(LY_SUCCESS, lys_print_mem(&printed, mod, LYS_OUT_YANG_COMPILED, 0));
+ assert_string_equal(printed, info);
+ free(printed);
+}
+
+static void
+test_schema_invalid(void **state)
+{
+ const char *data;
+
+ data = "module a {yang-version 1.1; namespace urn:tests:extensions:structure:a; prefix self;"
+ "import ietf-yang-structure-ext {prefix sx;}"
+ "sx:structure struct {import yang;}}";
+ assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, data, LYS_IN_YANG, NULL));
+ CHECK_LOG_CTX("Invalid keyword \"import\" as a child of \"sx:structure struct\" extension instance.",
+ "/a:{extension='sx:structure'}/struct");
+
+ data = "module a {yang-version 1.1; namespace urn:tests:extensions:structure:a; prefix self;"
+ "import ietf-yang-structure-ext {prefix sx;}"
+ "container b { sx:structure struct { container x { leaf x {type string;}}}}}";
+ assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, data, LYS_IN_YANG, NULL));
+ CHECK_LOG_CTX("Extension plugin \"libyang 2 - structure, version 1\": "
+ "Extension sx:structure must not be used as a non top-level statement in \"container\" statement.",
+ "/a:b/{extension='sx:structure'}/struct");
+
+ data = "module a {yang-version 1.1; namespace urn:tests:extensions:structure:a; prefix self;"
+ "import ietf-yang-structure-ext {prefix sx;}"
+ "sx:structure { container x { leaf x {type string;}}}}";
+ assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, data, LYS_IN_YANG, NULL));
+ CHECK_LOG_CTX("Extension instance \"sx:structure\" misses argument element \"name\".",
+ "/a:{extension='sx:structure'}");
+
+ data = "module a {yang-version 1.1; namespace urn:tests:extensions:structure:a; prefix self;"
+ "import ietf-yang-structure-ext {prefix sx;}"
+ "sx:structure struct { container x { leaf x {type string;}}}"
+ "sx:structure struct { container y { leaf y {type string;}}}}";
+ assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, data, LYS_IN_YANG, NULL));
+ CHECK_LOG_CTX("Extension plugin \"libyang 2 - structure, version 1\": "
+ "Extension sx:structure is instantiated multiple times.",
+ "/a:{extension='sx:structure'}/struct");
+
+ data = "module a {yang-version 1.1; namespace urn:tests:extensions:structure:a; prefix self;"
+ "import ietf-yang-structure-ext {prefix sx;}"
+ "sx:structure struct { container x { leaf x {type string;}}}"
+ "choice struct { container y { leaf y {type string;}}}}";
+ assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, data, LYS_IN_YANG, NULL));
+ CHECK_LOG_CTX("Extension plugin \"libyang 2 - structure, version 1\": "
+ "Extension sx:structure collides with a choice with the same identifier.",
+ "/a:{extension='sx:structure'}/struct");
+}
+
+static void
+test_parse(void **state)
+{
+ struct lys_module *mod;
+ struct lysc_ext_instance *e;
+ struct lyd_node *tree = NULL;
+ const char *schema = "module a {yang-version 1.1; namespace urn:tests:extensions:structure:a; prefix self;"
+ "import ietf-yang-structure-ext {prefix sx;}"
+ "sx:structure struct { container x { leaf x { type string;}}}}";
+ const char *xml = "<x xmlns=\"urn:tests:extensions:structure:a\"><x>test</x></x>";
+ const char *json = "{\"a:x\":{\"x\":\"test\"}}";
+
+ assert_int_equal(LY_SUCCESS, lys_parse_mem(UTEST_LYCTX, schema, LYS_IN_YANG, &mod));
+ assert_non_null(e = mod->compiled->exts);
+
+ assert_int_equal(LY_SUCCESS, ly_in_new_memory(xml, &UTEST_IN));
+ assert_int_equal(LY_SUCCESS, lyd_parse_ext_data(e, NULL, UTEST_IN, LYD_XML, 0, LYD_VALIDATE_PRESENT, &tree));
+ CHECK_LYD_STRING_PARAM(tree, xml, LYD_XML, LYD_PRINT_SHRINK | LYD_PRINT_WITHSIBLINGS);
+ lyd_free_all(tree);
+
+ ly_in_memory(UTEST_IN, json);
+ assert_int_equal(LY_SUCCESS, lyd_parse_ext_data(e, NULL, UTEST_IN, LYD_JSON, 0, LYD_VALIDATE_PRESENT, &tree));
+ CHECK_LYD_STRING_PARAM(tree, json, LYD_JSON, LYD_PRINT_SHRINK | LYD_PRINT_WITHSIBLINGS);
+
+ lyd_free_all(tree);
+}
+
+int
+main(void)
+{
+ const struct CMUnitTest tests[] = {
+ UTEST(test_schema),
+ UTEST(test_schema_invalid),
+ UTEST(test_parse),
+ };
+
+ return cmocka_run_group_tests(tests, NULL, NULL);
+}
diff --git a/tests/utests/schema/test_tree_schema_compile.c b/tests/utests/schema/test_tree_schema_compile.c
index ace8c77..4a11755 100644
--- a/tests/utests/schema/test_tree_schema_compile.c
+++ b/tests/utests/schema/test_tree_schema_compile.c
@@ -2536,7 +2536,7 @@
assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, "module ee {namespace urn:ee;prefix ee;grouping grp {leaf l {type string; status deprecated;}}"
"uses grp {status obsolete;}}", LYS_IN_YANG, &mod));
- CHECK_LOG_CTX("Status \"deprecated\" of \"l\" is in conflict with the \"obsolete\" status of parent \"<uses>\".",
+ CHECK_LOG_CTX("Status \"deprecated\" of \"l\" is in conflict with the \"obsolete\" status of parent \"<schema-only-node>\".",
"/ee:{uses='grp'}/ee:l");
assert_int_equal(LY_EEXIST, lys_parse_mem(UTEST_LYCTX, "module ff {namespace urn:ff;prefix ff;grouping grp {leaf l {type string;}}"
@@ -2706,7 +2706,7 @@
assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, "module ii {namespace urn:ii;prefix ii;grouping grp {leaf l {type string; status deprecated;}}"
"uses grp {status obsolete;}}", LYS_IN_YANG, &mod));
- CHECK_LOG_CTX("Status \"deprecated\" of \"l\" is in conflict with the \"obsolete\" status of parent \"<uses>\".",
+ CHECK_LOG_CTX("Status \"deprecated\" of \"l\" is in conflict with the \"obsolete\" status of parent \"<schema-only-node>\".",
"/ii:{uses='grp'}/ii:l");
assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, "module jj {namespace urn:jj;prefix jj;import grp {prefix g;}"
diff --git a/tools/lint/tests/expect/list.exp b/tools/lint/tests/expect/list.exp
index 41f62bd..4264cfd 100755
--- a/tools/lint/tests/expect/list.exp
+++ b/tools/lint/tests/expect/list.exp
@@ -12,7 +12,7 @@
expect_output "> "
-expect_command "list" 1 "List of the loaded models:\r\n *i ietf-yang-metadata@2016-08-05\r\n *I yang@2022-06-16\r\n *i ietf-inet-types@2013-07-15\r\n *i ietf-yang-types@2013-07-15\r\n *I ietf-yang-schema-mount@2019-01-14\r\n> "
+expect_command "list" 1 "List of the loaded models:\r\n *i ietf-yang-metadata@2016-08-05\r\n *I yang@2022-06-16\r\n *i ietf-inet-types@2013-07-15\r\n *i ietf-yang-types@2013-07-15\r\n *I ietf-yang-schema-mount@2019-01-14\r\n *i ietf-yang-structure-ext@2020-06-17\r\n> "
send -- "exit\r"
diff --git a/tools/lint/tests/shunit2/list.sh b/tools/lint/tests/shunit2/list.sh
index 41d3805..d64503a 100755
--- a/tools/lint/tests/shunit2/list.sh
+++ b/tools/lint/tests/shunit2/list.sh
@@ -5,7 +5,8 @@
I yang@2022-06-16
i ietf-inet-types@2013-07-15
i ietf-yang-types@2013-07-15
- I ietf-yang-schema-mount@2019-01-14"
+ I ietf-yang-schema-mount@2019-01-14
+ i ietf-yang-structure-ext@2020-06-17"
testListEmptyContext() {
output=`${YANGLINT} -l`
@@ -18,7 +19,8 @@
I yang@2022-06-16
I ietf-inet-types@2013-07-15
I ietf-yang-types@2013-07-15
- I ietf-yang-schema-mount@2019-01-14"
+ I ietf-yang-schema-mount@2019-01-14
+ I ietf-yang-structure-ext@2020-06-17"
output=`${YANGLINT} -lii`
assertEquals "Unexpected list of modules in empty context with -ii." "${LIST_BASE_ALLIMPLEMENTED}" "${output}"
}