data tree FEATURE functions for creating and applying diff
diff --git a/models/yang@2017-02-20.h b/models/yang@2017-02-20.h
deleted file mode 100644
index 19b6430..0000000
--- a/models/yang@2017-02-20.h
+++ /dev/null
@@ -1,168 +0,0 @@
-unsigned char yang_2017_02_20_yang[] = {
-  0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x20, 0x79, 0x61, 0x6e, 0x67, 0x20,
-  0x7b, 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, 0x31, 0x22, 0x3b, 0x70, 0x72, 0x65, 0x66, 0x69,
-  0x78, 0x20, 0x79, 0x61, 0x6e, 0x67, 0x3b, 0x69, 0x6d, 0x70, 0x6f, 0x72,
-  0x74, 0x20, 0x69, 0x65, 0x74, 0x66, 0x2d, 0x79, 0x61, 0x6e, 0x67, 0x2d,
-  0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x20, 0x7b, 0x70, 0x72,
-  0x65, 0x66, 0x69, 0x78, 0x20, 0x6d, 0x64, 0x3b, 0x72, 0x65, 0x76, 0x69,
-  0x73, 0x69, 0x6f, 0x6e, 0x2d, 0x64, 0x61, 0x74, 0x65, 0x20, 0x32, 0x30,
-  0x31, 0x36, 0x2d, 0x30, 0x38, 0x2d, 0x30, 0x35, 0x3b, 0x7d, 0x6f, 0x72,
-  0x67, 0x61, 0x6e, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x22,
-  0x6c, 0x69, 0x62, 0x79, 0x61, 0x6e, 0x67, 0x22, 0x3b, 0x63, 0x6f, 0x6e,
-  0x74, 0x61, 0x63, 0x74, 0x0a, 0x22, 0x57, 0x65, 0x62, 0x3a, 0x20, 0x20,
-  0x20, 0x20, 0x3c, 0x68, 0x74, 0x74, 0x70, 0x73, 0x3a, 0x2f, 0x2f, 0x67,
-  0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x43, 0x45,
-  0x53, 0x4e, 0x45, 0x54, 0x2f, 0x6c, 0x69, 0x62, 0x79, 0x61, 0x6e, 0x67,
-  0x2f, 0x3e, 0x0a, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x3a, 0x20, 0x52,
-  0x61, 0x64, 0x65, 0x6b, 0x20, 0x4b, 0x72, 0x65, 0x6a, 0x63, 0x69, 0x20,
-  0x3c, 0x72, 0x6b, 0x72, 0x65, 0x6a, 0x63, 0x69, 0x40, 0x63, 0x65, 0x73,
-  0x6e, 0x65, 0x74, 0x2e, 0x63, 0x7a, 0x3e, 0x22, 0x3b, 0x64, 0x65, 0x73,
-  0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x0a, 0x22, 0x54, 0x68,
-  0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x61, 0x20, 0x6b, 0x69, 0x6e, 0x64,
-  0x20, 0x6f, 0x66, 0x20, 0x66, 0x61, 0x6b, 0x65, 0x20, 0x6d, 0x6f, 0x64,
-  0x65, 0x6c, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x6e, 0x6f, 0x20, 0x64,
-  0x61, 0x74, 0x61, 0x2c, 0x20, 0x74, 0x79, 0x70, 0x65, 0x64, 0x65, 0x66,
-  0x73, 0x20, 0x6f, 0x72, 0x20, 0x61, 0x6e, 0x79, 0x74, 0x68, 0x69, 0x6e,
-  0x67, 0x0a, 0x65, 0x6c, 0x73, 0x65, 0x2e, 0x20, 0x6c, 0x69, 0x62, 0x79,
-  0x61, 0x6e, 0x67, 0x20, 0x75, 0x73, 0x65, 0x73, 0x20, 0x74, 0x68, 0x69,
-  0x73, 0x20, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x20, 0x74, 0x6f, 0x20,
-  0x69, 0x6d, 0x70, 0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x20, 0x76, 0x61,
-  0x72, 0x69, 0x6f, 0x75, 0x73, 0x20, 0x59, 0x41, 0x4e, 0x47, 0x20, 0x61,
-  0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x0a, 0x64, 0x65,
-  0x66, 0x69, 0x6e, 0x65, 0x64, 0x20, 0x69, 0x6e, 0x20, 0x52, 0x46, 0x43,
-  0x20, 0x36, 0x30, 0x32, 0x30, 0x2e, 0x22, 0x3b, 0x72, 0x65, 0x76, 0x69,
-  0x73, 0x69, 0x6f, 0x6e, 0x20, 0x32, 0x30, 0x31, 0x37, 0x2d, 0x30, 0x32,
-  0x2d, 0x32, 0x30, 0x20, 0x7b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70,
-  0x74, 0x69, 0x6f, 0x6e, 0x0a, 0x22, 0x41, 0x64, 0x64, 0x65, 0x64, 0x20,
-  0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x20, 0x66, 0x6f, 0x72,
-  0x20, 0x4e, 0x45, 0x54, 0x43, 0x4f, 0x4e, 0x46, 0x27, 0x73, 0x20, 0x65,
-  0x64, 0x69, 0x74, 0x2d, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x20, 0x6d,
-  0x61, 0x6e, 0x69, 0x70, 0x75, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20,
-  0x77, 0x69, 0x74, 0x68, 0x20, 0x6f, 0x72, 0x64, 0x65, 0x72, 0x65, 0x64,
-  0x20, 0x0a, 0x6c, 0x69, 0x73, 0x74, 0x73, 0x20, 0x61, 0x6e, 0x64, 0x20,
-  0x6c, 0x65, 0x61, 0x66, 0x2d, 0x6c, 0x69, 0x73, 0x74, 0x73, 0x2e, 0x22,
-  0x3b, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x20, 0x22,
-  0x52, 0x46, 0x43, 0x20, 0x37, 0x39, 0x35, 0x30, 0x3a, 0x20, 0x54, 0x68,
-  0x65, 0x20, 0x59, 0x41, 0x4e, 0x47, 0x20, 0x31, 0x2e, 0x31, 0x20, 0x44,
-  0x61, 0x74, 0x61, 0x20, 0x4d, 0x6f, 0x64, 0x65, 0x6c, 0x69, 0x6e, 0x67,
-  0x20, 0x4c, 0x61, 0x6e, 0x67, 0x75, 0x61, 0x67, 0x65, 0x22, 0x3b, 0x7d,
-  0x72, 0x65, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x20, 0x32, 0x30, 0x31,
-  0x36, 0x2d, 0x30, 0x32, 0x2d, 0x31, 0x31, 0x20, 0x7b, 0x64, 0x65, 0x73,
-  0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x22, 0x49, 0x6e,
-  0x69, 0x74, 0x69, 0x61, 0x6c, 0x20, 0x72, 0x65, 0x76, 0x69, 0x73, 0x69,
-  0x6f, 0x6e, 0x22, 0x3b, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63,
-  0x65, 0x0a, 0x22, 0x52, 0x46, 0x43, 0x20, 0x36, 0x30, 0x32, 0x30, 0x3a,
-  0x20, 0x59, 0x41, 0x4e, 0x47, 0x20, 0x2d, 0x20, 0x41, 0x20, 0x44, 0x61,
-  0x74, 0x61, 0x20, 0x4d, 0x6f, 0x64, 0x65, 0x6c, 0x69, 0x6e, 0x67, 0x20,
-  0x4c, 0x61, 0x6e, 0x67, 0x75, 0x61, 0x67, 0x65, 0x20, 0x66, 0x6f, 0x72,
-  0x0a, 0x74, 0x68, 0x65, 0x20, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b,
-  0x20, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, 0x69,
-  0x6f, 0x6e, 0x20, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x20,
-  0x28, 0x4e, 0x45, 0x54, 0x43, 0x4f, 0x4e, 0x46, 0x29, 0x22, 0x3b, 0x7d,
-  0x6d, 0x64, 0x3a, 0x61, 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f,
-  0x6e, 0x20, 0x69, 0x6e, 0x73, 0x65, 0x72, 0x74, 0x20, 0x7b, 0x74, 0x79,
-  0x70, 0x65, 0x20, 0x65, 0x6e, 0x75, 0x6d, 0x65, 0x72, 0x61, 0x74, 0x69,
-  0x6f, 0x6e, 0x20, 0x7b, 0x65, 0x6e, 0x75, 0x6d, 0x20, 0x66, 0x69, 0x72,
-  0x73, 0x74, 0x3b, 0x65, 0x6e, 0x75, 0x6d, 0x20, 0x6c, 0x61, 0x73, 0x74,
-  0x3b, 0x65, 0x6e, 0x75, 0x6d, 0x20, 0x62, 0x65, 0x66, 0x6f, 0x72, 0x65,
-  0x3b, 0x65, 0x6e, 0x75, 0x6d, 0x20, 0x61, 0x66, 0x74, 0x65, 0x72, 0x3b,
-  0x7d, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x20, 0x22,
-  0x52, 0x46, 0x43, 0x37, 0x39, 0x35, 0x30, 0x20, 0x73, 0x65, 0x63, 0x74,
-  0x69, 0x6f, 0x6e, 0x20, 0x37, 0x2e, 0x38, 0x2e, 0x36, 0x2e, 0x20, 0x61,
-  0x6e, 0x64, 0x20, 0x73, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x37,
-  0x2e, 0x37, 0x2e, 0x39, 0x2e, 0x22, 0x3b, 0x64, 0x65, 0x73, 0x63, 0x72,
-  0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x0a, 0x22, 0x49, 0x6e, 0x20, 0x75,
-  0x73, 0x65, 0x72, 0x20, 0x6f, 0x72, 0x64, 0x65, 0x72, 0x65, 0x64, 0x20,
-  0x6c, 0x65, 0x61, 0x66, 0x2d, 0x6c, 0x69, 0x73, 0x74, 0x2c, 0x20, 0x74,
-  0x68, 0x65, 0x20, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65,
-  0x20, 0x63, 0x61, 0x6e, 0x20, 0x62, 0x65, 0x20, 0x75, 0x73, 0x65, 0x64,
-  0x20, 0x74, 0x6f, 0x20, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x0a,
-  0x77, 0x68, 0x65, 0x72, 0x65, 0x20, 0x69, 0x6e, 0x20, 0x74, 0x68, 0x65,
-  0x20, 0x6c, 0x65, 0x61, 0x66, 0x2d, 0x6c, 0x69, 0x73, 0x74, 0x20, 0x74,
-  0x68, 0x65, 0x20, 0x65, 0x6e, 0x74, 0x72, 0x79, 0x20, 0x69, 0x73, 0x20,
-  0x69, 0x6e, 0x73, 0x65, 0x72, 0x74, 0x65, 0x64, 0x2e, 0x20, 0x49, 0x74,
-  0x20, 0x63, 0x61, 0x6e, 0x20, 0x62, 0x65, 0x20, 0x75, 0x73, 0x65, 0x64,
-  0x20, 0x64, 0x75, 0x72, 0x69, 0x6e, 0x67, 0x0a, 0x74, 0x68, 0x65, 0x20,
-  0x4e, 0x45, 0x54, 0x43, 0x4f, 0x4e, 0x46, 0x20, 0x3c, 0x65, 0x64, 0x69,
-  0x74, 0x2d, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x3e, 0x20, 0x5c, 0x22,
-  0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x5c, 0x22, 0x20, 0x6f, 0x70, 0x65,
-  0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x20, 0x74, 0x6f, 0x20, 0x69,
-  0x6e, 0x73, 0x65, 0x72, 0x74, 0x20, 0x61, 0x20, 0x6e, 0x65, 0x77, 0x20,
-  0x6c, 0x69, 0x73, 0x74, 0x20, 0x6f, 0x72, 0x0a, 0x6c, 0x65, 0x61, 0x66,
-  0x2d, 0x6c, 0x69, 0x73, 0x74, 0x20, 0x65, 0x6e, 0x74, 0x72, 0x79, 0x2c,
-  0x20, 0x6f, 0x72, 0x20, 0x64, 0x75, 0x72, 0x69, 0x6e, 0x67, 0x20, 0x5c,
-  0x22, 0x6d, 0x65, 0x72, 0x67, 0x65, 0x5c, 0x22, 0x20, 0x6f, 0x72, 0x20,
-  0x5c, 0x22, 0x72, 0x65, 0x70, 0x6c, 0x61, 0x63, 0x65, 0x5c, 0x22, 0x20,
-  0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x20, 0x74,
-  0x6f, 0x20, 0x69, 0x6e, 0x73, 0x65, 0x72, 0x74, 0x0a, 0x61, 0x20, 0x6e,
-  0x65, 0x77, 0x20, 0x6c, 0x69, 0x73, 0x74, 0x20, 0x6f, 0x72, 0x20, 0x6c,
-  0x65, 0x61, 0x66, 0x2d, 0x6c, 0x69, 0x73, 0x74, 0x20, 0x65, 0x6e, 0x74,
-  0x72, 0x79, 0x20, 0x6f, 0x72, 0x20, 0x6d, 0x6f, 0x76, 0x65, 0x20, 0x61,
-  0x6e, 0x20, 0x65, 0x78, 0x69, 0x73, 0x74, 0x69, 0x6e, 0x67, 0x20, 0x6f,
-  0x6e, 0x65, 0x2e, 0x0a, 0x0a, 0x49, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20,
-  0x76, 0x61, 0x6c, 0x75, 0x65, 0x20, 0x69, 0x73, 0x20, 0x5c, 0x22, 0x62,
-  0x65, 0x66, 0x6f, 0x72, 0x65, 0x5c, 0x22, 0x20, 0x6f, 0x72, 0x20, 0x5c,
-  0x22, 0x61, 0x66, 0x74, 0x65, 0x72, 0x5c, 0x22, 0x2c, 0x20, 0x74, 0x68,
-  0x65, 0x20, 0x5c, 0x22, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x5c, 0x22, 0x2f,
-  0x5c, 0x22, 0x6b, 0x65, 0x79, 0x5c, 0x22, 0x20, 0x61, 0x74, 0x74, 0x72,
-  0x69, 0x62, 0x75, 0x74, 0x65, 0x0a, 0x4d, 0x55, 0x53, 0x54, 0x20, 0x61,
-  0x6c, 0x73, 0x6f, 0x20, 0x62, 0x65, 0x20, 0x75, 0x73, 0x65, 0x64, 0x20,
-  0x74, 0x6f, 0x20, 0x73, 0x70, 0x65, 0x63, 0x69, 0x66, 0x79, 0x20, 0x61,
-  0x6e, 0x20, 0x65, 0x78, 0x69, 0x73, 0x74, 0x69, 0x6e, 0x67, 0x20, 0x65,
-  0x6e, 0x74, 0x72, 0x79, 0x20, 0x69, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20,
-  0x6c, 0x69, 0x73, 0x74, 0x20, 0x6f, 0x72, 0x20, 0x6c, 0x65, 0x61, 0x66,
-  0x2d, 0x6c, 0x69, 0x73, 0x74, 0x2e, 0x0a, 0x0a, 0x49, 0x66, 0x20, 0x6e,
-  0x6f, 0x20, 0x5c, 0x22, 0x69, 0x6e, 0x73, 0x65, 0x72, 0x74, 0x5c, 0x22,
-  0x20, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x20, 0x69,
-  0x73, 0x20, 0x70, 0x72, 0x65, 0x73, 0x65, 0x6e, 0x74, 0x20, 0x69, 0x6e,
-  0x20, 0x74, 0x68, 0x65, 0x20, 0x5c, 0x22, 0x63, 0x72, 0x65, 0x61, 0x74,
-  0x65, 0x5c, 0x22, 0x20, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f,
-  0x6e, 0x2c, 0x20, 0x69, 0x74, 0x0a, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c,
-  0x74, 0x73, 0x20, 0x74, 0x6f, 0x20, 0x5c, 0x22, 0x6c, 0x61, 0x73, 0x74,
-  0x5c, 0x22, 0x2e, 0x22, 0x3b, 0x7d, 0x6d, 0x64, 0x3a, 0x61, 0x6e, 0x6e,
-  0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x76, 0x61, 0x6c, 0x75,
-  0x65, 0x20, 0x7b, 0x74, 0x79, 0x70, 0x65, 0x20, 0x73, 0x74, 0x72, 0x69,
-  0x6e, 0x67, 0x3b, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65,
-  0x20, 0x22, 0x52, 0x46, 0x43, 0x37, 0x39, 0x35, 0x30, 0x20, 0x73, 0x65,
-  0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x37, 0x2e, 0x37, 0x2e, 0x39, 0x2e,
-  0x22, 0x3b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f,
-  0x6e, 0x0a, 0x22, 0x49, 0x6e, 0x20, 0x75, 0x73, 0x65, 0x72, 0x20, 0x6f,
-  0x72, 0x64, 0x65, 0x72, 0x65, 0x64, 0x20, 0x6c, 0x65, 0x61, 0x66, 0x2d,
-  0x6c, 0x69, 0x73, 0x74, 0x2c, 0x20, 0x74, 0x68, 0x65, 0x20, 0x61, 0x74,
-  0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x20, 0x6d, 0x75, 0x73, 0x74,
-  0x20, 0x62, 0x65, 0x20, 0x75, 0x73, 0x65, 0x64, 0x20, 0x69, 0x66, 0x20,
-  0x74, 0x68, 0x65, 0x20, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74,
-  0x65, 0x0a, 0x69, 0x6e, 0x73, 0x65, 0x72, 0x74, 0x20, 0x69, 0x73, 0x20,
-  0x75, 0x73, 0x65, 0x64, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x73, 0x70, 0x65,
-  0x63, 0x69, 0x66, 0x69, 0x65, 0x73, 0x20, 0x62, 0x65, 0x66, 0x6f, 0x72,
-  0x65, 0x2f, 0x61, 0x66, 0x74, 0x65, 0x72, 0x20, 0x77, 0x68, 0x69, 0x63,
-  0x68, 0x20, 0x65, 0x78, 0x69, 0x73, 0x74, 0x69, 0x6e, 0x67, 0x20, 0x69,
-  0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x20, 0x74, 0x68, 0x65, 0x0a,
-  0x6e, 0x65, 0x77, 0x20, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65,
-  0x20, 0x73, 0x68, 0x6f, 0x75, 0x6c, 0x64, 0x20, 0x62, 0x65, 0x20, 0x69,
-  0x6e, 0x73, 0x65, 0x72, 0x74, 0x65, 0x64, 0x2e, 0x22, 0x3b, 0x7d, 0x6d,
-  0x64, 0x3a, 0x61, 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e,
-  0x20, 0x6b, 0x65, 0x79, 0x20, 0x7b, 0x74, 0x79, 0x70, 0x65, 0x20, 0x73,
-  0x74, 0x72, 0x69, 0x6e, 0x67, 0x3b, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65,
-  0x6e, 0x63, 0x65, 0x20, 0x22, 0x52, 0x46, 0x43, 0x37, 0x39, 0x35, 0x30,
-  0x20, 0x73, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x37, 0x2e, 0x38,
-  0x2e, 0x36, 0x2e, 0x22, 0x3b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70,
-  0x74, 0x69, 0x6f, 0x6e, 0x0a, 0x22, 0x49, 0x6e, 0x20, 0x75, 0x73, 0x65,
-  0x72, 0x20, 0x6f, 0x72, 0x64, 0x65, 0x72, 0x65, 0x64, 0x20, 0x6c, 0x69,
-  0x73, 0x74, 0x2c, 0x20, 0x74, 0x68, 0x65, 0x20, 0x61, 0x74, 0x74, 0x72,
-  0x69, 0x62, 0x75, 0x74, 0x65, 0x20, 0x6d, 0x75, 0x73, 0x74, 0x20, 0x62,
-  0x65, 0x20, 0x75, 0x73, 0x65, 0x64, 0x20, 0x69, 0x66, 0x20, 0x74, 0x68,
-  0x65, 0x20, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x0a,
-  0x69, 0x6e, 0x73, 0x65, 0x72, 0x74, 0x20, 0x69, 0x73, 0x20, 0x75, 0x73,
-  0x65, 0x64, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x73, 0x70, 0x65, 0x63, 0x69,
-  0x66, 0x69, 0x65, 0x73, 0x20, 0x62, 0x65, 0x66, 0x6f, 0x72, 0x65, 0x2f,
-  0x61, 0x66, 0x74, 0x65, 0x72, 0x20, 0x77, 0x68, 0x69, 0x63, 0x68, 0x20,
-  0x65, 0x78, 0x69, 0x73, 0x74, 0x69, 0x6e, 0x67, 0x20, 0x69, 0x6e, 0x73,
-  0x74, 0x61, 0x6e, 0x63, 0x65, 0x20, 0x74, 0x68, 0x65, 0x0a, 0x6e, 0x65,
-  0x77, 0x20, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x20, 0x73,
-  0x68, 0x6f, 0x75, 0x6c, 0x64, 0x20, 0x62, 0x65, 0x20, 0x69, 0x6e, 0x73,
-  0x65, 0x72, 0x74, 0x65, 0x64, 0x2e, 0x22, 0x3b, 0x7d, 0x7d, 0x00
-};
diff --git a/models/yang@2017-02-20.yang b/models/yang@2017-02-20.yang
deleted file mode 100644
index e2bff77..0000000
--- a/models/yang@2017-02-20.yang
+++ /dev/null
@@ -1,77 +0,0 @@
-module yang {
-  namespace "urn:ietf:params:xml:ns:yang:1";
-  prefix yang;
-
-  import ietf-yang-metadata {
-    prefix md;
-    revision-date 2016-08-05;
-  }
-
-  organization
-    "libyang";
-
-  contact
-    "Web:    <https://github.com/CESNET/libyang/>
-     Author: Radek Krejci <rkrejci@cesnet.cz>";
-
-  description
-    "This is a kind of fake model with no data, typedefs or anything
-     else. libyang uses this module to implement various YANG attributes
-     defined in RFC 6020.";
-
-  revision 2017-02-20 {
-    description
-      "Added metadata for NETCONF's edit-config manipulation with ordered
-       lists and leaf-lists.";
-    reference
-      "RFC 7950: The YANG 1.1 Data Modeling Language";
-  }
-
-  revision 2016-02-11 {
-    description
-      "Initial revision";
-    reference
-      "RFC 6020: YANG - A Data Modeling Language for
-       the Network Configuration Protocol (NETCONF)";
-  }
-
-  md:annotation insert {
-    type enumeration {
-      enum first;
-      enum last;
-      enum before;
-      enum after;
-    }
-    reference "RFC7950 section 7.8.6. and section 7.7.9.";
-    description
-      "In user ordered leaf-list, the attribute can be used to control
-       where in the leaf-list the entry is inserted. It can be used during
-       the NETCONF <edit-config> \"create\" operations to insert a new list or
-       leaf-list entry, or during \"merge\" or \"replace\" operations to insert
-       a new list or leaf-list entry or move an existing one.
-
-       If the value is \"before\" or \"after\", the \"value\"/\"key\" attribute
-       MUST also be used to specify an existing entry in the list or leaf-list.
-
-       If no \"insert\" attribute is present in the \"create\" operation, it
-       defaults to \"last\".";
-  }
-
-  md:annotation value {
-    type string;
-    reference "RFC7950 section 7.7.9.";
-    description
-      "In user ordered leaf-list, the attribute must be used if the attribute
-       insert is used and specifies before/after which existing instance the
-       new instance should be inserted.";
-  }
-
-  md:annotation key {
-    type string;
-    reference "RFC7950 section 7.8.6.";
-    description
-      "In user ordered list, the attribute must be used if the attribute
-       insert is used and specifies before/after which existing instance the
-       new instance should be inserted.";
-  }
-}
diff --git a/models/yang@2020-06-17.h b/models/yang@2020-06-17.h
new file mode 100644
index 0000000..4c5058e
--- /dev/null
+++ b/models/yang@2020-06-17.h
@@ -0,0 +1,377 @@
+unsigned char yang_2020_06_17_yang[] = {
+  0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x20, 0x79, 0x61, 0x6e, 0x67, 0x20,
+  0x7b, 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, 0x31, 0x22, 0x3b, 0x0a, 0x20,
+  0x20, 0x70, 0x72, 0x65, 0x66, 0x69, 0x78, 0x20, 0x79, 0x61, 0x6e, 0x67,
+  0x3b, 0x0a, 0x0a, 0x20, 0x20, 0x69, 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x20,
+  0x69, 0x65, 0x74, 0x66, 0x2d, 0x79, 0x61, 0x6e, 0x67, 0x2d, 0x6d, 0x65,
+  0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20,
+  0x20, 0x70, 0x72, 0x65, 0x66, 0x69, 0x78, 0x20, 0x6d, 0x64, 0x3b, 0x0a,
+  0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e,
+  0x2d, 0x64, 0x61, 0x74, 0x65, 0x20, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30,
+  0x38, 0x2d, 0x30, 0x35, 0x3b, 0x0a, 0x20, 0x20, 0x7d, 0x0a, 0x0a, 0x20,
+  0x20, 0x6f, 0x72, 0x67, 0x61, 0x6e, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f,
+  0x6e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x22, 0x6c, 0x69, 0x62, 0x79, 0x61,
+  0x6e, 0x67, 0x22, 0x3b, 0x0a, 0x0a, 0x20, 0x20, 0x63, 0x6f, 0x6e, 0x74,
+  0x61, 0x63, 0x74, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x22, 0x57, 0x65, 0x62,
+  0x3a, 0x20, 0x20, 0x20, 0x20, 0x3c, 0x68, 0x74, 0x74, 0x70, 0x73, 0x3a,
+  0x2f, 0x2f, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d,
+  0x2f, 0x43, 0x45, 0x53, 0x4e, 0x45, 0x54, 0x2f, 0x6c, 0x69, 0x62, 0x79,
+  0x61, 0x6e, 0x67, 0x2f, 0x3e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x41,
+  0x75, 0x74, 0x68, 0x6f, 0x72, 0x3a, 0x20, 0x52, 0x61, 0x64, 0x65, 0x6b,
+  0x20, 0x4b, 0x72, 0x65, 0x6a, 0x63, 0x69, 0x20, 0x3c, 0x72, 0x6b, 0x72,
+  0x65, 0x6a, 0x63, 0x69, 0x40, 0x63, 0x65, 0x73, 0x6e, 0x65, 0x74, 0x2e,
+  0x63, 0x7a, 0x3e, 0x22, 0x3b, 0x0a, 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, 0x69, 0x73, 0x20, 0x61, 0x20,
+  0x6b, 0x69, 0x6e, 0x64, 0x20, 0x6f, 0x66, 0x20, 0x66, 0x61, 0x6b, 0x65,
+  0x20, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20,
+  0x6e, 0x6f, 0x20, 0x64, 0x61, 0x74, 0x61, 0x2c, 0x20, 0x74, 0x79, 0x70,
+  0x65, 0x64, 0x65, 0x66, 0x73, 0x20, 0x6f, 0x72, 0x20, 0x61, 0x6e, 0x79,
+  0x74, 0x68, 0x69, 0x6e, 0x67, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x65,
+  0x6c, 0x73, 0x65, 0x2e, 0x20, 0x6c, 0x69, 0x62, 0x79, 0x61, 0x6e, 0x67,
+  0x20, 0x75, 0x73, 0x65, 0x73, 0x20, 0x74, 0x68, 0x69, 0x73, 0x20, 0x6d,
+  0x6f, 0x64, 0x75, 0x6c, 0x65, 0x20, 0x74, 0x6f, 0x20, 0x69, 0x6d, 0x70,
+  0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x20, 0x76, 0x61, 0x72, 0x69, 0x6f,
+  0x75, 0x73, 0x20, 0x59, 0x41, 0x4e, 0x47, 0x20, 0x61, 0x74, 0x74, 0x72,
+  0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20,
+  0x64, 0x65, 0x66, 0x69, 0x6e, 0x65, 0x64, 0x20, 0x69, 0x6e, 0x20, 0x52,
+  0x46, 0x43, 0x20, 0x36, 0x30, 0x32, 0x30, 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, 0x41,
+  0x64, 0x64, 0x65, 0x64, 0x20, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74,
+  0x61, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x64, 0x69, 0x66, 0x66, 0x2e, 0x22,
+  0x3b, 0x0a, 0x20, 0x20, 0x7d, 0x0a, 0x0a, 0x20, 0x20, 0x72, 0x65, 0x76,
+  0x69, 0x73, 0x69, 0x6f, 0x6e, 0x20, 0x32, 0x30, 0x31, 0x37, 0x2d, 0x30,
+  0x32, 0x2d, 0x32, 0x30, 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, 0x41, 0x64, 0x64, 0x65, 0x64, 0x20,
+  0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x20, 0x66, 0x6f, 0x72,
+  0x20, 0x4e, 0x45, 0x54, 0x43, 0x4f, 0x4e, 0x46, 0x27, 0x73, 0x20, 0x65,
+  0x64, 0x69, 0x74, 0x2d, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x20, 0x6d,
+  0x61, 0x6e, 0x69, 0x70, 0x75, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20,
+  0x77, 0x69, 0x74, 0x68, 0x20, 0x6f, 0x72, 0x64, 0x65, 0x72, 0x65, 0x64,
+  0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x69, 0x73, 0x74,
+  0x73, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x6c, 0x65, 0x61, 0x66, 0x2d, 0x6c,
+  0x69, 0x73, 0x74, 0x73, 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, 0x37, 0x39, 0x35,
+  0x30, 0x3a, 0x20, 0x54, 0x68, 0x65, 0x20, 0x59, 0x41, 0x4e, 0x47, 0x20,
+  0x31, 0x2e, 0x31, 0x20, 0x44, 0x61, 0x74, 0x61, 0x20, 0x4d, 0x6f, 0x64,
+  0x65, 0x6c, 0x69, 0x6e, 0x67, 0x20, 0x4c, 0x61, 0x6e, 0x67, 0x75, 0x61,
+  0x67, 0x65, 0x22, 0x3b, 0x0a, 0x20, 0x20, 0x7d, 0x0a, 0x0a, 0x20, 0x20,
+  0x72, 0x65, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x20, 0x32, 0x30, 0x31,
+  0x36, 0x2d, 0x30, 0x32, 0x2d, 0x31, 0x31, 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, 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, 0x36, 0x30, 0x32, 0x30, 0x3a, 0x20, 0x59,
+  0x41, 0x4e, 0x47, 0x20, 0x2d, 0x20, 0x41, 0x20, 0x44, 0x61, 0x74, 0x61,
+  0x20, 0x4d, 0x6f, 0x64, 0x65, 0x6c, 0x69, 0x6e, 0x67, 0x20, 0x4c, 0x61,
+  0x6e, 0x67, 0x75, 0x61, 0x67, 0x65, 0x20, 0x66, 0x6f, 0x72, 0x0a, 0x20,
+  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x74, 0x68, 0x65, 0x20, 0x4e, 0x65,
+  0x74, 0x77, 0x6f, 0x72, 0x6b, 0x20, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67,
+  0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x50, 0x72, 0x6f, 0x74,
+  0x6f, 0x63, 0x6f, 0x6c, 0x20, 0x28, 0x4e, 0x45, 0x54, 0x43, 0x4f, 0x4e,
+  0x46, 0x29, 0x22, 0x3b, 0x0a, 0x20, 0x20, 0x7d, 0x0a, 0x0a, 0x20, 0x20,
+  0x6d, 0x64, 0x3a, 0x61, 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f,
+  0x6e, 0x20, 0x69, 0x6e, 0x73, 0x65, 0x72, 0x74, 0x20, 0x7b, 0x0a, 0x20,
+  0x20, 0x20, 0x20, 0x74, 0x79, 0x70, 0x65, 0x20, 0x65, 0x6e, 0x75, 0x6d,
+  0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x7b, 0x0a, 0x20, 0x20,
+  0x20, 0x20, 0x20, 0x20, 0x65, 0x6e, 0x75, 0x6d, 0x20, 0x66, 0x69, 0x72,
+  0x73, 0x74, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x65, 0x6e,
+  0x75, 0x6d, 0x20, 0x6c, 0x61, 0x73, 0x74, 0x3b, 0x0a, 0x20, 0x20, 0x20,
+  0x20, 0x20, 0x20, 0x65, 0x6e, 0x75, 0x6d, 0x20, 0x62, 0x65, 0x66, 0x6f,
+  0x72, 0x65, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x65, 0x6e,
+  0x75, 0x6d, 0x20, 0x61, 0x66, 0x74, 0x65, 0x72, 0x3b, 0x0a, 0x20, 0x20,
+  0x20, 0x20, 0x7d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x66, 0x65,
+  0x72, 0x65, 0x6e, 0x63, 0x65, 0x20, 0x22, 0x52, 0x46, 0x43, 0x37, 0x39,
+  0x35, 0x30, 0x20, 0x73, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x37,
+  0x2e, 0x38, 0x2e, 0x36, 0x2e, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x73, 0x65,
+  0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x37, 0x2e, 0x37, 0x2e, 0x39, 0x2e,
+  0x22, 0x3b, 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, 0x20, 0x75, 0x73, 0x65, 0x72, 0x20, 0x6f, 0x72,
+  0x64, 0x65, 0x72, 0x65, 0x64, 0x20, 0x6c, 0x65, 0x61, 0x66, 0x2d, 0x6c,
+  0x69, 0x73, 0x74, 0x2c, 0x20, 0x74, 0x68, 0x65, 0x20, 0x61, 0x74, 0x74,
+  0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x20, 0x63, 0x61, 0x6e, 0x20, 0x62,
+  0x65, 0x20, 0x75, 0x73, 0x65, 0x64, 0x20, 0x74, 0x6f, 0x20, 0x63, 0x6f,
+  0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+  0x20, 0x77, 0x68, 0x65, 0x72, 0x65, 0x20, 0x69, 0x6e, 0x20, 0x74, 0x68,
+  0x65, 0x20, 0x6c, 0x65, 0x61, 0x66, 0x2d, 0x6c, 0x69, 0x73, 0x74, 0x20,
+  0x74, 0x68, 0x65, 0x20, 0x65, 0x6e, 0x74, 0x72, 0x79, 0x20, 0x69, 0x73,
+  0x20, 0x69, 0x6e, 0x73, 0x65, 0x72, 0x74, 0x65, 0x64, 0x2e, 0x20, 0x49,
+  0x74, 0x20, 0x63, 0x61, 0x6e, 0x20, 0x62, 0x65, 0x20, 0x75, 0x73, 0x65,
+  0x64, 0x20, 0x64, 0x75, 0x72, 0x69, 0x6e, 0x67, 0x0a, 0x20, 0x20, 0x20,
+  0x20, 0x20, 0x20, 0x20, 0x74, 0x68, 0x65, 0x20, 0x4e, 0x45, 0x54, 0x43,
+  0x4f, 0x4e, 0x46, 0x20, 0x3c, 0x65, 0x64, 0x69, 0x74, 0x2d, 0x63, 0x6f,
+  0x6e, 0x66, 0x69, 0x67, 0x3e, 0x20, 0x5c, 0x22, 0x63, 0x72, 0x65, 0x61,
+  0x74, 0x65, 0x5c, 0x22, 0x20, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69,
+  0x6f, 0x6e, 0x73, 0x20, 0x74, 0x6f, 0x20, 0x69, 0x6e, 0x73, 0x65, 0x72,
+  0x74, 0x20, 0x61, 0x20, 0x6e, 0x65, 0x77, 0x20, 0x6c, 0x69, 0x73, 0x74,
+  0x20, 0x6f, 0x72, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6c,
+  0x65, 0x61, 0x66, 0x2d, 0x6c, 0x69, 0x73, 0x74, 0x20, 0x65, 0x6e, 0x74,
+  0x72, 0x79, 0x2c, 0x20, 0x6f, 0x72, 0x20, 0x64, 0x75, 0x72, 0x69, 0x6e,
+  0x67, 0x20, 0x5c, 0x22, 0x6d, 0x65, 0x72, 0x67, 0x65, 0x5c, 0x22, 0x20,
+  0x6f, 0x72, 0x20, 0x5c, 0x22, 0x72, 0x65, 0x70, 0x6c, 0x61, 0x63, 0x65,
+  0x5c, 0x22, 0x20, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e,
+  0x73, 0x20, 0x74, 0x6f, 0x20, 0x69, 0x6e, 0x73, 0x65, 0x72, 0x74, 0x0a,
+  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x61, 0x20, 0x6e, 0x65, 0x77,
+  0x20, 0x6c, 0x69, 0x73, 0x74, 0x20, 0x6f, 0x72, 0x20, 0x6c, 0x65, 0x61,
+  0x66, 0x2d, 0x6c, 0x69, 0x73, 0x74, 0x20, 0x65, 0x6e, 0x74, 0x72, 0x79,
+  0x20, 0x6f, 0x72, 0x20, 0x6d, 0x6f, 0x76, 0x65, 0x20, 0x61, 0x6e, 0x20,
+  0x65, 0x78, 0x69, 0x73, 0x74, 0x69, 0x6e, 0x67, 0x20, 0x6f, 0x6e, 0x65,
+  0x2e, 0x0a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x49, 0x66,
+  0x20, 0x74, 0x68, 0x65, 0x20, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x20, 0x69,
+  0x73, 0x20, 0x5c, 0x22, 0x62, 0x65, 0x66, 0x6f, 0x72, 0x65, 0x5c, 0x22,
+  0x20, 0x6f, 0x72, 0x20, 0x5c, 0x22, 0x61, 0x66, 0x74, 0x65, 0x72, 0x5c,
+  0x22, 0x2c, 0x20, 0x74, 0x68, 0x65, 0x20, 0x5c, 0x22, 0x76, 0x61, 0x6c,
+  0x75, 0x65, 0x5c, 0x22, 0x2f, 0x5c, 0x22, 0x6b, 0x65, 0x79, 0x5c, 0x22,
+  0x20, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x0a, 0x20,
+  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x4d, 0x55, 0x53, 0x54, 0x20, 0x61,
+  0x6c, 0x73, 0x6f, 0x20, 0x62, 0x65, 0x20, 0x75, 0x73, 0x65, 0x64, 0x20,
+  0x74, 0x6f, 0x20, 0x73, 0x70, 0x65, 0x63, 0x69, 0x66, 0x79, 0x20, 0x61,
+  0x6e, 0x20, 0x65, 0x78, 0x69, 0x73, 0x74, 0x69, 0x6e, 0x67, 0x20, 0x65,
+  0x6e, 0x74, 0x72, 0x79, 0x20, 0x69, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20,
+  0x6c, 0x69, 0x73, 0x74, 0x20, 0x6f, 0x72, 0x20, 0x6c, 0x65, 0x61, 0x66,
+  0x2d, 0x6c, 0x69, 0x73, 0x74, 0x2e, 0x0a, 0x0a, 0x20, 0x20, 0x20, 0x20,
+  0x20, 0x20, 0x20, 0x49, 0x66, 0x20, 0x6e, 0x6f, 0x20, 0x5c, 0x22, 0x69,
+  0x6e, 0x73, 0x65, 0x72, 0x74, 0x5c, 0x22, 0x20, 0x61, 0x74, 0x74, 0x72,
+  0x69, 0x62, 0x75, 0x74, 0x65, 0x20, 0x69, 0x73, 0x20, 0x70, 0x72, 0x65,
+  0x73, 0x65, 0x6e, 0x74, 0x20, 0x69, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20,
+  0x5c, 0x22, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x5c, 0x22, 0x20, 0x6f,
+  0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2c, 0x20, 0x69, 0x74,
+  0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x64, 0x65, 0x66, 0x61,
+  0x75, 0x6c, 0x74, 0x73, 0x20, 0x74, 0x6f, 0x20, 0x5c, 0x22, 0x6c, 0x61,
+  0x73, 0x74, 0x5c, 0x22, 0x2e, 0x22, 0x3b, 0x0a, 0x20, 0x20, 0x7d, 0x0a,
+  0x0a, 0x20, 0x20, 0x6d, 0x64, 0x3a, 0x61, 0x6e, 0x6e, 0x6f, 0x74, 0x61,
+  0x74, 0x69, 0x6f, 0x6e, 0x20, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x20, 0x7b,
+  0x0a, 0x20, 0x20, 0x20, 0x20, 0x74, 0x79, 0x70, 0x65, 0x20, 0x73, 0x74,
+  0x72, 0x69, 0x6e, 0x67, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65,
+  0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x20, 0x22, 0x52, 0x46, 0x43,
+  0x37, 0x39, 0x35, 0x30, 0x20, 0x73, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e,
+  0x20, 0x37, 0x2e, 0x37, 0x2e, 0x39, 0x2e, 0x22, 0x3b, 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, 0x20,
+  0x75, 0x73, 0x65, 0x72, 0x20, 0x6f, 0x72, 0x64, 0x65, 0x72, 0x65, 0x64,
+  0x20, 0x6c, 0x65, 0x61, 0x66, 0x2d, 0x6c, 0x69, 0x73, 0x74, 0x2c, 0x20,
+  0x74, 0x68, 0x65, 0x20, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74,
+  0x65, 0x20, 0x6d, 0x75, 0x73, 0x74, 0x20, 0x62, 0x65, 0x20, 0x75, 0x73,
+  0x65, 0x64, 0x20, 0x69, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x61, 0x74,
+  0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x0a, 0x20, 0x20, 0x20, 0x20,
+  0x20, 0x20, 0x20, 0x69, 0x6e, 0x73, 0x65, 0x72, 0x74, 0x20, 0x69, 0x73,
+  0x20, 0x75, 0x73, 0x65, 0x64, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x73, 0x70,
+  0x65, 0x63, 0x69, 0x66, 0x69, 0x65, 0x73, 0x20, 0x62, 0x65, 0x66, 0x6f,
+  0x72, 0x65, 0x2f, 0x61, 0x66, 0x74, 0x65, 0x72, 0x20, 0x77, 0x68, 0x69,
+  0x63, 0x68, 0x20, 0x65, 0x78, 0x69, 0x73, 0x74, 0x69, 0x6e, 0x67, 0x20,
+  0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x20, 0x74, 0x68, 0x65,
+  0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6e, 0x65, 0x77, 0x20,
+  0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x20, 0x73, 0x68, 0x6f,
+  0x75, 0x6c, 0x64, 0x20, 0x62, 0x65, 0x20, 0x69, 0x6e, 0x73, 0x65, 0x72,
+  0x74, 0x65, 0x64, 0x2e, 0x22, 0x3b, 0x0a, 0x20, 0x20, 0x7d, 0x0a, 0x0a,
+  0x20, 0x20, 0x6d, 0x64, 0x3a, 0x61, 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74,
+  0x69, 0x6f, 0x6e, 0x20, 0x6b, 0x65, 0x79, 0x20, 0x7b, 0x0a, 0x20, 0x20,
+  0x20, 0x20, 0x74, 0x79, 0x70, 0x65, 0x20, 0x73, 0x74, 0x72, 0x69, 0x6e,
+  0x67, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x66, 0x65, 0x72,
+  0x65, 0x6e, 0x63, 0x65, 0x20, 0x22, 0x52, 0x46, 0x43, 0x37, 0x39, 0x35,
+  0x30, 0x20, 0x73, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x37, 0x2e,
+  0x38, 0x2e, 0x36, 0x2e, 0x22, 0x3b, 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, 0x20, 0x75, 0x73, 0x65,
+  0x72, 0x20, 0x6f, 0x72, 0x64, 0x65, 0x72, 0x65, 0x64, 0x20, 0x6c, 0x69,
+  0x73, 0x74, 0x2c, 0x20, 0x74, 0x68, 0x65, 0x20, 0x61, 0x74, 0x74, 0x72,
+  0x69, 0x62, 0x75, 0x74, 0x65, 0x20, 0x6d, 0x75, 0x73, 0x74, 0x20, 0x62,
+  0x65, 0x20, 0x75, 0x73, 0x65, 0x64, 0x20, 0x69, 0x66, 0x20, 0x74, 0x68,
+  0x65, 0x20, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x0a,
+  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x69, 0x6e, 0x73, 0x65, 0x72,
+  0x74, 0x20, 0x69, 0x73, 0x20, 0x75, 0x73, 0x65, 0x64, 0x20, 0x61, 0x6e,
+  0x64, 0x20, 0x73, 0x70, 0x65, 0x63, 0x69, 0x66, 0x69, 0x65, 0x73, 0x20,
+  0x62, 0x65, 0x66, 0x6f, 0x72, 0x65, 0x2f, 0x61, 0x66, 0x74, 0x65, 0x72,
+  0x20, 0x77, 0x68, 0x69, 0x63, 0x68, 0x20, 0x65, 0x78, 0x69, 0x73, 0x74,
+  0x69, 0x6e, 0x67, 0x20, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65,
+  0x20, 0x74, 0x68, 0x65, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+  0x6e, 0x65, 0x77, 0x20, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65,
+  0x20, 0x73, 0x68, 0x6f, 0x75, 0x6c, 0x64, 0x20, 0x62, 0x65, 0x20, 0x69,
+  0x6e, 0x73, 0x65, 0x72, 0x74, 0x65, 0x64, 0x2e, 0x22, 0x3b, 0x0a, 0x20,
+  0x20, 0x7d, 0x0a, 0x0a, 0x20, 0x20, 0x6d, 0x64, 0x3a, 0x61, 0x6e, 0x6e,
+  0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x6f, 0x70, 0x65, 0x72,
+  0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20,
+  0x74, 0x79, 0x70, 0x65, 0x20, 0x65, 0x6e, 0x75, 0x6d, 0x65, 0x72, 0x61,
+  0x74, 0x69, 0x6f, 0x6e, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20,
+  0x20, 0x65, 0x6e, 0x75, 0x6d, 0x20, 0x6e, 0x6f, 0x6e, 0x65, 0x20, 0x7b,
+  0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x64, 0x65, 0x73,
+  0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x0a, 0x20, 0x20, 0x20,
+  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x54, 0x68, 0x65, 0x20,
+  0x6e, 0x6f, 0x64, 0x65, 0x20, 0x65, 0x78, 0x69, 0x73, 0x74, 0x65, 0x64,
+  0x20, 0x69, 0x6e, 0x20, 0x62, 0x6f, 0x74, 0x68, 0x20, 0x64, 0x61, 0x74,
+  0x61, 0x20, 0x74, 0x72, 0x65, 0x65, 0x73, 0x20, 0x62, 0x75, 0x74, 0x20,
+  0x74, 0x68, 0x65, 0x72, 0x65, 0x20, 0x69, 0x73, 0x20, 0x61, 0x20, 0x6e,
+  0x65, 0x73, 0x74, 0x65, 0x64, 0x20, 0x6e, 0x6f, 0x64, 0x65, 0x0a, 0x20,
+  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x77, 0x69,
+  0x74, 0x68, 0x20, 0x61, 0x6e, 0x6f, 0x74, 0x68, 0x65, 0x72, 0x20, 0x6f,
+  0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x20, 0x49, 0x6e,
+  0x20, 0x63, 0x61, 0x73, 0x65, 0x20, 0x6f, 0x66, 0x20, 0x61, 0x20, 0x6c,
+  0x65, 0x61, 0x66, 0x2c, 0x20, 0x6f, 0x6e, 0x6c, 0x79, 0x20, 0x69, 0x74,
+  0x73, 0x20, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x0a, 0x20, 0x20,
+  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x66, 0x6c, 0x61,
+  0x67, 0x20, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x2e, 0x22, 0x3b,
+  0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7d, 0x0a, 0x20, 0x20, 0x20,
+  0x20, 0x20, 0x20, 0x65, 0x6e, 0x75, 0x6d, 0x20, 0x63, 0x72, 0x65, 0x61,
+  0x74, 0x65, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+  0x20, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e,
+  0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22,
+  0x54, 0x68, 0x65, 0x20, 0x6e, 0x6f, 0x64, 0x65, 0x20, 0x64, 0x69, 0x64,
+  0x20, 0x6e, 0x6f, 0x74, 0x20, 0x65, 0x78, 0x69, 0x73, 0x74, 0x20, 0x69,
+  0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x66, 0x69, 0x72, 0x73, 0x74, 0x20,
+  0x74, 0x72, 0x65, 0x65, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x77, 0x61, 0x73,
+  0x20, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x20, 0x69, 0x6e, 0x20,
+  0x74, 0x68, 0x65, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+  0x20, 0x20, 0x20, 0x73, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x20, 0x74, 0x72,
+  0x65, 0x65, 0x2e, 0x22, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+  0x7d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x65, 0x6e, 0x75, 0x6d,
+  0x20, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x20, 0x7b, 0x0a, 0x20, 0x20,
+  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69,
+  0x70, 0x74, 0x69, 0x6f, 0x6e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+  0x20, 0x20, 0x20, 0x20, 0x22, 0x54, 0x68, 0x65, 0x20, 0x6e, 0x6f, 0x64,
+  0x65, 0x20, 0x65, 0x78, 0x69, 0x73, 0x74, 0x65, 0x64, 0x20, 0x69, 0x6e,
+  0x20, 0x74, 0x68, 0x65, 0x20, 0x66, 0x69, 0x72, 0x73, 0x74, 0x20, 0x74,
+  0x72, 0x65, 0x65, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x77, 0x61, 0x73, 0x20,
+  0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x64, 0x20, 0x69, 0x6e, 0x20, 0x74,
+  0x68, 0x65, 0x20, 0x73, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x0a, 0x20, 0x20,
+  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x74, 0x72, 0x65,
+  0x65, 0x2e, 0x22, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7d,
+  0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x65, 0x6e, 0x75, 0x6d, 0x20,
+  0x72, 0x65, 0x70, 0x6c, 0x61, 0x63, 0x65, 0x20, 0x7b, 0x0a, 0x20, 0x20,
+  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69,
+  0x70, 0x74, 0x69, 0x6f, 0x6e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+  0x20, 0x20, 0x20, 0x20, 0x22, 0x54, 0x68, 0x65, 0x20, 0x6e, 0x6f, 0x64,
+  0x65, 0x20, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x20, 0x77, 0x61, 0x73, 0x20,
+  0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x20, 0x6f, 0x72, 0x20, 0x74,
+  0x68, 0x65, 0x20, 0x6e, 0x6f, 0x64, 0x65, 0x20, 0x77, 0x61, 0x73, 0x20,
+  0x6d, 0x6f, 0x76, 0x65, 0x64, 0x20, 0x66, 0x6f, 0x72, 0x0a, 0x20, 0x20,
+  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x65, 0x61,
+  0x76, 0x65, 0x73, 0x2f, 0x61, 0x6e, 0x79, 0x78, 0x6d, 0x6c, 0x2f, 0x61,
+  0x6e, 0x79, 0x64, 0x61, 0x74, 0x61, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x75,
+  0x73, 0x65, 0x72, 0x2d, 0x6f, 0x72, 0x64, 0x65, 0x72, 0x65, 0x64, 0x20,
+  0x6c, 0x69, 0x73, 0x74, 0x73, 0x2f, 0x6c, 0x65, 0x61, 0x66, 0x2d, 0x6c,
+  0x69, 0x73, 0x74, 0x73, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+  0x20, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x73, 0x70, 0x65, 0x63, 0x74,
+  0x69, 0x76, 0x65, 0x6c, 0x79, 0x2e, 0x22, 0x3b, 0x0a, 0x20, 0x20, 0x20,
+  0x20, 0x20, 0x20, 0x7d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x7d, 0x0a, 0x20,
+  0x20, 0x20, 0x20, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65,
+  0x20, 0x22, 0x52, 0x46, 0x43, 0x36, 0x32, 0x34, 0x31, 0x20, 0x73, 0x65,
+  0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x37, 0x2e, 0x32, 0x2e, 0x22, 0x3b,
+  0x0a, 0x20, 0x20, 0x20, 0x20, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70,
+  0x74, 0x69, 0x6f, 0x6e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22,
+  0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x6f, 0x66,
+  0x20, 0x61, 0x20, 0x6e, 0x6f, 0x64, 0x65, 0x20, 0x69, 0x6e, 0x20, 0x61,
+  0x20, 0x64, 0x69, 0x66, 0x66, 0x2e, 0x20, 0x49, 0x66, 0x20, 0x61, 0x20,
+  0x6e, 0x6f, 0x64, 0x65, 0x20, 0x68, 0x61, 0x73, 0x20, 0x6e, 0x6f, 0x20,
+  0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2c, 0x0a, 0x20,
+  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x69, 0x74, 0x20, 0x69, 0x73, 0x20,
+  0x69, 0x6e, 0x68, 0x65, 0x72, 0x69, 0x74, 0x65, 0x64, 0x20, 0x66, 0x72,
+  0x6f, 0x6d, 0x20, 0x69, 0x74, 0x73, 0x20, 0x6e, 0x65, 0x61, 0x72, 0x65,
+  0x73, 0x74, 0x20, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x20, 0x77, 0x69,
+  0x74, 0x68, 0x20, 0x61, 0x6e, 0x20, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74,
+  0x69, 0x6f, 0x6e, 0x2e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+  0x54, 0x6f, 0x70, 0x2d, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x20, 0x6e, 0x6f,
+  0x64, 0x65, 0x73, 0x20, 0x6d, 0x75, 0x73, 0x74, 0x20, 0x61, 0x6c, 0x77,
+  0x61, 0x79, 0x73, 0x20, 0x68, 0x61, 0x76, 0x65, 0x20, 0x61, 0x6e, 0x20,
+  0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x0a, 0x0a,
+  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x55, 0x73, 0x65, 0x72, 0x2d,
+  0x6f, 0x72, 0x64, 0x65, 0x72, 0x65, 0x64, 0x20, 0x6c, 0x69, 0x73, 0x74,
+  0x73, 0x2f, 0x6c, 0x65, 0x61, 0x66, 0x2d, 0x6c, 0x69, 0x73, 0x74, 0x73,
+  0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74,
+  0x69, 0x6f, 0x6e, 0x20, 0x27, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x27,
+  0x20, 0x61, 0x6e, 0x64, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+  0x27, 0x72, 0x65, 0x70, 0x6c, 0x61, 0x63, 0x65, 0x27, 0x20, 0x4d, 0x55,
+  0x53, 0x54, 0x20, 0x61, 0x6c, 0x73, 0x6f, 0x20, 0x68, 0x61, 0x76, 0x65,
+  0x20, 0x74, 0x68, 0x65, 0x20, 0x27, 0x6b, 0x65, 0x79, 0x27, 0x20, 0x6f,
+  0x72, 0x20, 0x27, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x27, 0x20, 0x6d, 0x65,
+  0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x20, 0x64, 0x65, 0x66, 0x69, 0x6e,
+  0x65, 0x64, 0x2e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x49,
+  0x74, 0x20, 0x73, 0x70, 0x65, 0x63, 0x69, 0x66, 0x69, 0x65, 0x73, 0x20,
+  0x74, 0x68, 0x65, 0x20, 0x73, 0x75, 0x63, 0x63, 0x65, 0x65, 0x64, 0x69,
+  0x6e, 0x67, 0x20, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x2e,
+  0x20, 0x49, 0x6e, 0x20, 0x63, 0x61, 0x73, 0x65, 0x20, 0x74, 0x68, 0x65,
+  0x20, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x20, 0x6f, 0x66, 0x0a, 0x20, 0x20,
+  0x20, 0x20, 0x20, 0x20, 0x20, 0x74, 0x68, 0x69, 0x73, 0x20, 0x6d, 0x65,
+  0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x20, 0x69, 0x73, 0x20, 0x65, 0x6d,
+  0x70, 0x74, 0x79, 0x2c, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6e, 0x6f, 0x64,
+  0x65, 0x20, 0x77, 0x61, 0x73, 0x20, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65,
+  0x64, 0x2f, 0x6d, 0x6f, 0x76, 0x65, 0x64, 0x20, 0x6f, 0x6e, 0x20, 0x74,
+  0x68, 0x65, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x61,
+  0x73, 0x74, 0x20, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x2e,
+  0x0a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x41, 0x6c, 0x6c,
+  0x20, 0x74, 0x68, 0x65, 0x20, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69,
+  0x6f, 0x6e, 0x73, 0x20, 0x6b, 0x65, 0x65, 0x70, 0x20, 0x74, 0x68, 0x65,
+  0x20, 0x6d, 0x65, 0x61, 0x6e, 0x69, 0x6e, 0x67, 0x20, 0x6f, 0x66, 0x20,
+  0x65, 0x64, 0x69, 0x74, 0x2d, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x20,
+  0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x0a, 0x20,
+  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x73,
+  0x69, 0x6d, 0x69, 0x6c, 0x61, 0x72, 0x20, 0x6e, 0x61, 0x6d, 0x65, 0x73,
+  0x20, 0x62, 0x75, 0x74, 0x20, 0x73, 0x6f, 0x6d, 0x65, 0x20, 0x61, 0x72,
+  0x65, 0x20, 0x66, 0x75, 0x72, 0x74, 0x68, 0x65, 0x72, 0x20, 0x72, 0x65,
+  0x73, 0x74, 0x72, 0x69, 0x63, 0x74, 0x65, 0x64, 0x2c, 0x20, 0x6d, 0x65,
+  0x61, 0x6e, 0x69, 0x6e, 0x67, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+  0x20, 0x74, 0x68, 0x65, 0x79, 0x20, 0x61, 0x72, 0x65, 0x20, 0x75, 0x73,
+  0x65, 0x64, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x6f, 0x6e, 0x6c, 0x79, 0x20,
+  0x61, 0x20, 0x73, 0x75, 0x62, 0x73, 0x65, 0x74, 0x20, 0x6f, 0x66, 0x20,
+  0x75, 0x73, 0x65, 0x2d, 0x63, 0x61, 0x73, 0x65, 0x73, 0x2e, 0x22, 0x3b,
+  0x0a, 0x20, 0x20, 0x7d, 0x0a, 0x0a, 0x20, 0x20, 0x6d, 0x64, 0x3a, 0x61,
+  0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x6f, 0x72,
+  0x69, 0x67, 0x2d, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x20, 0x7b,
+  0x0a, 0x20, 0x20, 0x20, 0x20, 0x74, 0x79, 0x70, 0x65, 0x20, 0x62, 0x6f,
+  0x6f, 0x6c, 0x65, 0x61, 0x6e, 0x3b, 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, 0x66, 0x6f, 0x72, 0x6d,
+  0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x61, 0x62, 0x6f, 0x75, 0x74, 0x20,
+  0x74, 0x68, 0x65, 0x20, 0x70, 0x72, 0x65, 0x76, 0x69, 0x6f, 0x75, 0x73,
+  0x20, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x20, 0x73, 0x74, 0x61,
+  0x74, 0x65, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6e, 0x6f,
+  0x64, 0x65, 0x2e, 0x22, 0x3b, 0x0a, 0x20, 0x20, 0x7d, 0x0a, 0x0a, 0x20,
+  0x20, 0x6d, 0x64, 0x3a, 0x61, 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x69,
+  0x6f, 0x6e, 0x20, 0x6f, 0x72, 0x69, 0x67, 0x2d, 0x76, 0x61, 0x6c, 0x75,
+  0x65, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x74, 0x79, 0x70, 0x65,
+  0x20, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x3b, 0x0a, 0x20, 0x20, 0x20,
+  0x20, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e,
+  0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x50, 0x72, 0x65, 0x76,
+  0x69, 0x6f, 0x75, 0x73, 0x20, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x20, 0x6f,
+  0x66, 0x20, 0x61, 0x20, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x20,
+  0x6c, 0x65, 0x61, 0x66, 0x2e, 0x20, 0x41, 0x6c, 0x74, 0x65, 0x72, 0x6e,
+  0x61, 0x74, 0x6c, 0x79, 0x2c, 0x20, 0x69, 0x74, 0x73, 0x20, 0x6d, 0x65,
+  0x61, 0x6e, 0x69, 0x6e, 0x67, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+  0x69, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 0x61, 0x6d, 0x65, 0x20,
+  0x61, 0x73, 0x20, 0x5c, 0x22, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x5c, 0x22,
+  0x20, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x20, 0x62,
+  0x75, 0x74, 0x20, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65,
+  0x73, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6f, 0x72, 0x69, 0x67, 0x69, 0x6e,
+  0x61, 0x6c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x65, 0x61,
+  0x66, 0x2d, 0x6c, 0x69, 0x73, 0x74, 0x20, 0x69, 0x6e, 0x73, 0x74, 0x61,
+  0x6e, 0x63, 0x65, 0x20, 0x72, 0x61, 0x74, 0x68, 0x65, 0x72, 0x20, 0x74,
+  0x68, 0x61, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6e, 0x65, 0x77, 0x20,
+  0x6f, 0x6e, 0x65, 0x2e, 0x22, 0x3b, 0x0a, 0x20, 0x20, 0x7d, 0x0a, 0x0a,
+  0x20, 0x20, 0x6d, 0x64, 0x3a, 0x61, 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74,
+  0x69, 0x6f, 0x6e, 0x20, 0x6f, 0x72, 0x69, 0x67, 0x2d, 0x6b, 0x65, 0x79,
+  0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x74, 0x79, 0x70, 0x65, 0x20,
+  0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x3b, 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, 0x74, 0x73, 0x20, 0x6d,
+  0x65, 0x61, 0x6e, 0x69, 0x6e, 0x67, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68,
+  0x65, 0x20, 0x73, 0x61, 0x6d, 0x65, 0x20, 0x61, 0x73, 0x20, 0x5c, 0x22,
+  0x6b, 0x65, 0x79, 0x5c, 0x22, 0x20, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62,
+  0x75, 0x74, 0x65, 0x20, 0x62, 0x75, 0x74, 0x20, 0x69, 0x64, 0x65, 0x6e,
+  0x74, 0x69, 0x66, 0x69, 0x65, 0x73, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20,
+  0x20, 0x74, 0x68, 0x65, 0x20, 0x6f, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x61,
+  0x6c, 0x20, 0x6c, 0x69, 0x73, 0x74, 0x20, 0x69, 0x6e, 0x73, 0x74, 0x61,
+  0x6e, 0x63, 0x65, 0x20, 0x72, 0x61, 0x74, 0x68, 0x65, 0x72, 0x20, 0x74,
+  0x68, 0x61, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6e, 0x65, 0x77, 0x20,
+  0x6f, 0x6e, 0x65, 0x2e, 0x22, 0x3b, 0x0a, 0x20, 0x20, 0x7d, 0x0a, 0x7d,
+  0x0a, 0x00
+};
diff --git a/models/yang@2020-06-17.yang b/models/yang@2020-06-17.yang
new file mode 100644
index 0000000..7e596b1
--- /dev/null
+++ b/models/yang@2020-06-17.yang
@@ -0,0 +1,145 @@
+module yang {
+  namespace "urn:ietf:params:xml:ns:yang:1";
+  prefix yang;
+
+  import ietf-yang-metadata {
+    prefix md;
+    revision-date 2016-08-05;
+  }
+
+  organization
+    "libyang";
+
+  contact
+    "Web:    <https://github.com/CESNET/libyang/>
+     Author: Radek Krejci <rkrejci@cesnet.cz>";
+
+  description
+    "This is a kind of fake model with no data, typedefs or anything
+     else. libyang uses this module to implement various YANG attributes
+     defined in RFC 6020.";
+
+  revision 2020-06-17 {
+    description
+      "Added metadata for diff.";
+  }
+
+  revision 2017-02-20 {
+    description
+      "Added metadata for NETCONF's edit-config manipulation with ordered
+       lists and leaf-lists.";
+    reference
+      "RFC 7950: The YANG 1.1 Data Modeling Language";
+  }
+
+  revision 2016-02-11 {
+    description
+      "Initial revision";
+    reference
+      "RFC 6020: YANG - A Data Modeling Language for
+       the Network Configuration Protocol (NETCONF)";
+  }
+
+  md:annotation insert {
+    type enumeration {
+      enum first;
+      enum last;
+      enum before;
+      enum after;
+    }
+    reference "RFC7950 section 7.8.6. and section 7.7.9.";
+    description
+      "In user ordered leaf-list, the attribute can be used to control
+       where in the leaf-list the entry is inserted. It can be used during
+       the NETCONF <edit-config> \"create\" operations to insert a new list or
+       leaf-list entry, or during \"merge\" or \"replace\" operations to insert
+       a new list or leaf-list entry or move an existing one.
+
+       If the value is \"before\" or \"after\", the \"value\"/\"key\" attribute
+       MUST also be used to specify an existing entry in the list or leaf-list.
+
+       If no \"insert\" attribute is present in the \"create\" operation, it
+       defaults to \"last\".";
+  }
+
+  md:annotation value {
+    type string;
+    reference "RFC7950 section 7.7.9.";
+    description
+      "In user ordered leaf-list, the attribute must be used if the attribute
+       insert is used and specifies before/after which existing instance the
+       new instance should be inserted.";
+  }
+
+  md:annotation key {
+    type string;
+    reference "RFC7950 section 7.8.6.";
+    description
+      "In user ordered list, the attribute must be used if the attribute
+       insert is used and specifies before/after which existing instance the
+       new instance should be inserted.";
+  }
+
+  md:annotation operation {
+    type enumeration {
+      enum none {
+        description
+          "The node existed in both data trees but there is a nested node
+           with another operation. In case of a leaf, only its default
+           flag changed.";
+      }
+      enum create {
+        description
+          "The node did not exist in the first tree and was created in the
+           second tree.";
+      }
+      enum delete {
+        description
+          "The node existed in the first tree and was deleted in the second
+           tree.";
+      }
+      enum replace {
+        description
+          "The node value was changed or the node was moved for
+           leaves/anyxml/anydata and user-ordered lists/leaf-lists,
+           respectively.";
+      }
+    }
+    reference "RFC6241 section 7.2.";
+    description
+      "Operation of a node in a diff. If a node has no operation,
+       it is inherited from its nearest parent with an operation.
+       Top-level nodes must always have an operation.
+
+       User-ordered lists/leaf-lists with operation 'create' and
+       'replace' MUST also have the 'key' or 'value' metadata defined.
+       It specifies the succeeding instance. In case the value of
+       this metadata is empty, the node was created/moved on the
+       last position.
+
+       All the operations keep the meaning of edit-config operations
+       with similar names but some are further restricted, meaning
+       they are used for only a subset of use-cases.";
+  }
+
+  md:annotation orig-default {
+    type boolean;
+    description
+      "Information about the previous default state of the node.";
+  }
+
+  md:annotation orig-value {
+    type string;
+    description
+      "Previous value of a changed leaf. Alternatly, its meaning
+       is the same as \"value\" attribute but identifies the original
+       leaf-list instance rather than the new one.";
+  }
+
+  md:annotation orig-key {
+    type string;
+    description
+      "Its meaning is the same as \"key\" attribute but identifies
+       the original list instance rather than the new one.";
+  }
+}
diff --git a/src/context.c b/src/context.c
index 9f18510..62f3de7 100644
--- a/src/context.c
+++ b/src/context.c
@@ -37,7 +37,7 @@
 #define LY_INTERNAL_MODS_COUNT 6
 
 #include "../models/ietf-yang-metadata@2016-08-05.h"
-#include "../models/yang@2017-02-20.h"
+#include "../models/yang@2020-06-17.h"
 #include "../models/ietf-inet-types@2013-07-15.h"
 #include "../models/ietf-yang-types@2013-07-15.h"
 #include "../models/ietf-datastores@2018-02-14.h"
@@ -52,7 +52,7 @@
     LYS_INFORMAT format;
 } internal_modules[LY_INTERNAL_MODS_COUNT] = {
     {"ietf-yang-metadata", "2016-08-05", (const char*)ietf_yang_metadata_2016_08_05_yang, 1, LYS_IN_YANG},
-    {"yang", "2017-02-20", (const char*)yang_2017_02_20_yang, 1, LYS_IN_YANG},
+    {"yang", "2020-06-17", (const char*)yang_2020_06_17_yang, 1, LYS_IN_YANG},
     {"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-datastores and ietf-yang-library must be right here at the end of the list! */
diff --git a/src/tree_data.c b/src/tree_data.c
index 65a56fc..5942b09 100644
--- a/src/tree_data.c
+++ b/src/tree_data.c
@@ -46,6 +46,9 @@
 #include "xml.h"
 #include "xpath.h"
 
+static LY_ERR lyd_path_list_predicate(const struct lyd_node *node, char **buffer, size_t *buflen, size_t *bufused,
+                                      int is_static);
+
 LY_ERR
 lyd_value_parse(struct lyd_node_term *node, const char *value, size_t value_len, int *dynamic, int second,
                 ly_clb_resolve_prefix get_prefix, void *parser, LYD_FORMAT format, const struct lyd_node *tree)
@@ -2336,6 +2339,1022 @@
     return LY_SUCCESS;
 }
 
+struct lyd_diff_userord {
+    const struct lysc_node *schema; /**< User-ordered list/leaf-list schema node. */
+    uint64_t pos;                   /**< Current position in the second tree. */
+    const struct lyd_node **inst;   /**< Sized array of current instance order. */
+};
+
+enum lyd_diff_op {
+    LYD_DIFF_OP_CREATE,    /**< Subtree created. */
+    LYD_DIFF_OP_DELETE,    /**< Subtree deleted. */
+    LYD_DIFF_OP_REPLACE,   /**< Node value changed or (leaf-)list instance moved. */
+    LYD_DIFF_OP_NONE,      /**< No change of an existing inner node or default flag change of a term node. */
+};
+
+static const char *
+lyd_diff_op2str(enum lyd_diff_op op)
+{
+    switch (op) {
+    case LYD_DIFF_OP_CREATE:
+        return "create";
+    case LYD_DIFF_OP_DELETE:
+        return "delete";
+    case LYD_DIFF_OP_REPLACE:
+        return "replace";
+    case LYD_DIFF_OP_NONE:
+        return "none";
+    }
+
+    LOGINT(NULL);
+    return NULL;
+}
+
+/**
+ * @brief Add a new change into diff.
+ *
+ * @param[in] node Node (subtree) to add into diff.
+ * @param[in] op Operation to set.
+ * @param[in] orig_default Original default metadata to set.
+ * @param[in] orig_value Original value metadata to set.
+ * @param[in] key Key metadata to set.
+ * @param[in] value Value metadata to set.
+ * @param[in] orig_key Original key metadata to set.
+ * @param[in,out] diff Diff to append to.
+ * @return LY_ERR value.
+ */
+static LY_ERR
+lyd_diff_add(const struct lyd_node *node, enum lyd_diff_op op, const char *orig_default, const char *orig_value,
+             const char *key, const char *value, const char *orig_key, struct lyd_node **diff)
+{
+    struct lyd_node *dup, *siblings, *match = NULL, *diff_parent = NULL;
+    const struct lyd_node *parent = NULL;
+    const struct lys_module *yang_mod;
+
+    /* find the first existing parent */
+    siblings = *diff;
+    while (1) {
+        /* find next node parent */
+        parent = node;
+        while (parent->parent && (!diff_parent || (parent->parent->schema != diff_parent->schema))) {
+            parent = (struct lyd_node *)parent->parent;
+        }
+        if (parent == node) {
+            /* no more parents to find */
+            break;
+        }
+
+        /* check whether it exists in the diff */
+        if (lyd_find_sibling_first(siblings, parent, &match)) {
+            break;
+        }
+
+        /* another parent found */
+        diff_parent = match;
+
+        /* move down in the diff */
+        siblings = LYD_CHILD(match);
+    }
+
+    /* duplicate the subtree (and connect to the diff if possible) */
+    dup = lyd_dup(node, (struct lyd_node_inner *)diff_parent, LYD_DUP_RECURSIVE | LYD_DUP_NO_META | LYD_DUP_WITH_PARENTS);
+    LY_CHECK_RET(!dup, LY_EMEM);
+
+    /* find the first duplicated parent */
+    if (!diff_parent) {
+        diff_parent = (struct lyd_node *)dup->parent;
+        while (diff_parent && diff_parent->parent) {
+            diff_parent = (struct lyd_node *)diff_parent->parent;
+        }
+    } else {
+        diff_parent = (struct lyd_node *)dup;
+        while (diff_parent->parent && (diff_parent->parent->schema == parent->schema)) {
+            diff_parent = (struct lyd_node *)diff_parent->parent;
+        }
+    }
+
+    /* no parent existed, must be manually connected */
+    if (!diff_parent) {
+        /* there actually was no parent to duplicate */
+        if (*diff) {
+            lyd_insert_sibling(*diff, dup);
+        } else {
+            *diff = dup;
+        }
+    } else if (!diff_parent->parent) {
+        if (*diff) {
+            lyd_insert_sibling(*diff, diff_parent);
+        } else {
+            *diff = diff_parent;
+        }
+    }
+
+    /* get module with the operation metadata */
+    yang_mod = LYD_NODE_CTX(node)->list.objs[1];
+    assert(!strcmp(yang_mod->name, "yang"));
+
+    /* add parent operation, if any */
+    if (diff_parent && (diff_parent != dup) && !lyd_new_meta(diff_parent, yang_mod, "operation", "none")) {
+        return LY_EMEM;
+    }
+
+    /* add subtree operation */
+    if (!lyd_new_meta(dup, yang_mod, "operation", lyd_diff_op2str(op))) {
+        return LY_EMEM;
+    }
+
+    /* orig-default */
+    if (orig_default && !lyd_new_meta(dup, yang_mod, "orig-default", orig_default)) {
+        return LY_EMEM;
+    }
+
+    /* orig-value */
+    if (orig_value && !lyd_new_meta(dup, yang_mod, "orig-value", orig_value)) {
+        return LY_EMEM;
+    }
+
+    /* key */
+    if (key && !lyd_new_meta(dup, yang_mod, "key", key)) {
+        return LY_EMEM;
+    }
+
+    /* value */
+    if (value && !lyd_new_meta(dup, yang_mod, "value", value)) {
+        return LY_EMEM;
+    }
+
+    /* orig-key */
+    if (orig_key && !lyd_new_meta(dup, yang_mod, "orig-key", orig_key)) {
+        return LY_EMEM;
+    }
+
+    return LY_SUCCESS;
+}
+
+/**
+ * @brief Get a userord entry for a specific user-ordered list/leaf-list. Create if does not exist yet.
+ *
+ * @param[in] first
+ * @param[in] schema Schema node of the list/leaf-list.
+ * @param[in,out] userord Sized array of userord items.
+ * @return Userord item for all the user-ordered list/leaf-list instances.
+ */
+static struct lyd_diff_userord *
+lyd_diff_userord_get(const struct lyd_node *first, const struct lysc_node *schema, struct lyd_diff_userord **userord)
+{
+    struct lyd_diff_userord *item;
+    const struct lyd_node *iter, **node;
+    LY_ARRAY_SIZE_TYPE u;
+
+    LY_ARRAY_FOR(*userord, u) {
+        if ((*userord)[u].schema == schema) {
+            return &(*userord)[u];
+        }
+    }
+
+    /* it was not added yet, add it now */
+    LY_ARRAY_NEW_RET(schema->module->ctx, *userord, item, NULL);
+
+    item->schema = schema;
+    item->pos = 0;
+    item->inst = NULL;
+
+    /* store all the instance pointers in the current order */
+    if (first) {
+        if (first->parent) {
+            iter = first->parent->child;
+        } else {
+            for (iter = first; iter->prev->next; iter = iter->prev);
+        }
+        for (; iter; iter = iter->next) {
+            if (iter->schema == first->schema) {
+                LY_ARRAY_NEW_RET(schema->module->ctx, item->inst, node, NULL);
+                *node = iter;
+            }
+        }
+    }
+
+    return item;
+}
+
+/**
+ * @brief Get all the metadata to be stored in a diff for the 2 nodes. Can be used only for user-ordered
+ * lists/leaf-lists.
+ *
+ * @param[in] first Node from the first tree, can be NULL (on create).
+ * @param[in] second Node from the second tree, can be NULL (on delete).
+ * @param[in] options Diff options.
+ * @param[in,out] userord Sized array of userord items for keeping the current node order.
+ * @param[out] op Operation.
+ * @param[out] orig_default Original default metadata.
+ * @param[out] value Value metadata.
+ * @param[out] orig_value Original value metadata
+ * @param[out] key Key metadata.
+ * @param[out] orig_key Original key metadata.
+ * @return LY_SUCCESS on success,
+ * @return LY_ENOT if there is no change to be added into diff,
+ * @return LY_ERR value on other errors.
+ */
+static LY_ERR
+lyd_diff_userord_attrs(const struct lyd_node *first, const struct lyd_node *second, int options,
+                       struct lyd_diff_userord **userord, enum lyd_diff_op *op, const char **orig_default, char **value,
+                       char **orig_value, char **key, char **orig_key)
+{
+    const struct lysc_node *schema;
+    int dynamic;
+    size_t buflen, bufused, first_pos, second_pos;
+    struct lyd_diff_userord *userord_item;
+
+    assert(first || second);
+
+    *orig_default = NULL;
+    *value = NULL;
+    *orig_value = NULL;
+    *key = NULL;
+    *orig_key = NULL;
+
+    schema = first ? first->schema : second->schema;
+    assert(lysc_is_userordered(schema));
+
+    /* get userord entry */
+    userord_item = lyd_diff_userord_get(first, schema, userord);
+    LY_CHECK_RET(!userord_item, LY_EMEM);
+
+    /* prepare position of the next instance */
+    second_pos = userord_item->pos++;
+
+    /* find user-ordered first position */
+    if (first) {
+        for (first_pos = second_pos; first_pos < LY_ARRAY_SIZE(userord_item->inst); ++first_pos) {
+            if (userord_item->inst[first_pos] == first) {
+                break;
+            }
+        }
+        assert(first_pos < LY_ARRAY_SIZE(userord_item->inst));
+    }
+
+    /* learn operation first */
+    if (!second) {
+        *op = LYD_DIFF_OP_DELETE;
+    } else if (!first) {
+        *op = LYD_DIFF_OP_CREATE;
+    } else {
+        assert(schema->nodetype & (LYS_LIST | LYS_LEAFLIST));
+        if (lyd_compare(second, userord_item->inst[second_pos], 0)) {
+            /* in first, there is a different instance on the second position, we are going to move 'first' node */
+            *op = LYD_DIFF_OP_REPLACE;
+        } else if ((options & LYD_DIFF_WITHDEFAULTS) && ((first->flags & LYD_DEFAULT) != (second->flags & LYD_DEFAULT))) {
+            /* default flag change */
+            *op = LYD_DIFF_OP_NONE;
+        } else {
+            /* no changes */
+            return LY_ENOT;
+        }
+    }
+
+    /*
+     * set each attribute correctly based on the operation and node type
+     */
+
+    /* orig-default */
+    if ((options & LYD_DIFF_WITHDEFAULTS) && (schema->nodetype == LYS_LEAFLIST)
+            && ((*op == LYD_DIFF_OP_REPLACE) || (*op == LYD_DIFF_OP_NONE))) {
+        if (first->flags & LYD_DEFAULT) {
+            *orig_default = "true";
+        } else {
+            *orig_default = "false";
+        }
+    }
+
+    /* value */
+    if ((schema->nodetype == LYS_LEAFLIST) && ((*op == LYD_DIFF_OP_REPLACE) || (*op == LYD_DIFF_OP_CREATE))) {
+        if (second_pos) {
+            *value = (char *)lyd_value2str((struct lyd_node_term *)userord_item->inst[second_pos - 1], &dynamic);
+            if (!dynamic) {
+                *value = strdup(*value);
+                LY_CHECK_ERR_RET(!*value, LOGMEM(schema->module->ctx), LY_EMEM);
+            }
+        } else {
+            *value = strdup("");
+            LY_CHECK_ERR_RET(!*value, LOGMEM(schema->module->ctx), LY_EMEM);
+        }
+    }
+
+    /* orig-value */
+    if ((schema->nodetype == LYS_LEAFLIST) && ((*op == LYD_DIFF_OP_REPLACE) || (*op == LYD_DIFF_OP_DELETE))) {
+        if (first_pos) {
+            *orig_value = (char *)lyd_value2str((struct lyd_node_term *)userord_item->inst[first_pos - 1], &dynamic);
+            if (!dynamic) {
+                *orig_value = strdup(*orig_value);
+                LY_CHECK_ERR_RET(!*orig_value, LOGMEM(schema->module->ctx), LY_EMEM);
+            }
+        } else {
+            *orig_value = strdup("");
+            LY_CHECK_ERR_RET(!*orig_value, LOGMEM(schema->module->ctx), LY_EMEM);
+        }
+    }
+
+    /* key */
+    if ((schema->nodetype == LYS_LIST) && ((*op == LYD_DIFF_OP_REPLACE) || (*op ==LYD_DIFF_OP_CREATE))) {
+        if (second_pos) {
+            buflen = bufused = 0;
+            LY_CHECK_RET(lyd_path_list_predicate(userord_item->inst[second_pos - 1], key, &buflen, &bufused, 0));
+        } else {
+            *key = strdup("");
+            LY_CHECK_ERR_RET(!*key, LOGMEM(schema->module->ctx), LY_EMEM);
+        }
+    }
+
+    /* orig-key */
+    if ((schema->nodetype == LYS_LIST) && ((*op == LYD_DIFF_OP_REPLACE) || (*op == LYD_DIFF_OP_DELETE))) {
+        if (first_pos) {
+            buflen = bufused = 0;
+            LY_CHECK_RET(lyd_path_list_predicate(userord_item->inst[first_pos - 1], orig_key, &buflen, &bufused, 0));
+        } else {
+            *orig_key = strdup("");
+            LY_CHECK_ERR_RET(!*orig_key, LOGMEM(schema->module->ctx), LY_EMEM);
+        }
+    }
+
+    /*
+     * update our instances - apply the change
+     */
+    if (*op == LYD_DIFF_OP_CREATE) {
+        /* insert the instance */
+        LY_ARRAY_RESIZE_ERR_RET(schema->module->ctx, userord_item->inst, LY_ARRAY_SIZE(userord_item->inst) + 1,
+                                ;, LY_EMEM);
+        if (second_pos < LY_ARRAY_SIZE(userord_item->inst)) {
+            memmove(userord_item->inst + second_pos + 1, userord_item->inst + second_pos,
+                    (LY_ARRAY_SIZE(userord_item->inst) - second_pos) * sizeof *userord_item->inst);
+        }
+        LY_ARRAY_INCREMENT(userord_item->inst);
+        userord_item->inst[second_pos] = second;
+
+    } else if (*op == LYD_DIFF_OP_DELETE) {
+        /* remove the instance */
+        if (first_pos + 1 < LY_ARRAY_SIZE(userord_item->inst)) {
+            memmove(userord_item->inst + first_pos, userord_item->inst + first_pos + 1,
+                    (LY_ARRAY_SIZE(userord_item->inst) - first_pos - 1) * sizeof *userord_item->inst);
+        }
+        LY_ARRAY_DECREMENT(userord_item->inst);
+
+    } else if (*op == LYD_DIFF_OP_REPLACE) {
+        /* move the instances */
+        memmove(userord_item->inst + second_pos + 1, userord_item->inst + second_pos,
+                (first_pos - second_pos) * sizeof *userord_item->inst);
+        userord_item->inst[second_pos] = first;
+    }
+
+    return LY_SUCCESS;
+}
+
+/**
+ * @brief Get all the metadata to be stored in a diff for the 2 nodes. Cannot be used for user-ordered
+ * lists/leaf-lists.
+ *
+ * @param[in] first Node from the first tree, can be NULL (on create).
+ * @param[in] second Node from the second tree, can be NULL (on delete).
+ * @param[in] options Diff options.
+ * @param[out] op Operation.
+ * @param[out] orig_default Original default metadata.
+ * @param[out] orig_value Original value metadata.
+ * @return LY_SUCCESS on success,
+ * @return LY_ENOT if there is no change to be added into diff,
+ * @return LY_ERR value on other errors.
+ */
+static LY_ERR
+lyd_diff_attrs(const struct lyd_node *first, const struct lyd_node *second, int options, enum lyd_diff_op *op,
+               const char **orig_default, char **orig_value)
+{
+    const struct lysc_node *schema;
+    int dynamic;
+
+    assert(first || second);
+
+    *orig_default = NULL;
+    *orig_value = NULL;
+
+    schema = first ? first->schema : second->schema;
+    assert(!lysc_is_userordered(schema));
+
+    /* learn operation first */
+    if (!second) {
+        *op = LYD_DIFF_OP_DELETE;
+    } else if (!first) {
+        *op = LYD_DIFF_OP_CREATE;
+    } else {
+        switch (schema->nodetype) {
+        case LYS_CONTAINER:
+        case LYS_RPC:
+        case LYS_ACTION:
+        case LYS_NOTIF:
+            /* no changes */
+            return LY_ENOT;
+        case LYS_LIST:
+        case LYS_LEAFLIST:
+            if ((options & LYD_DIFF_WITHDEFAULTS) && ((first->flags & LYD_DEFAULT) != (second->flags & LYD_DEFAULT))) {
+                /* default flag change */
+                *op = LYD_DIFF_OP_NONE;
+            } else {
+                /* no changes */
+                return LY_ENOT;
+            }
+            break;
+        case LYS_LEAF:
+        case LYS_ANYXML:
+        case LYS_ANYDATA:
+            if (lyd_compare(first, second, 0)) {
+                /* different values */
+                *op = LYD_DIFF_OP_REPLACE;
+            } else if ((options & LYD_DIFF_WITHDEFAULTS) && ((first->flags & LYD_DEFAULT) != (second->flags & LYD_DEFAULT))) {
+                /* default flag change */
+                *op = LYD_DIFF_OP_NONE;
+            } else {
+                /* no changes */
+                return LY_ENOT;
+            }
+            break;
+        default:
+            LOGINT_RET(schema->module->ctx);
+        }
+    }
+
+    /*
+     * set each attribute correctly based on the operation and node type
+     */
+
+    /* orig-default */
+    if ((options & LYD_DIFF_WITHDEFAULTS) && (schema->nodetype & LYD_NODE_TERM)
+            && ((*op == LYD_DIFF_OP_REPLACE) || (*op == LYD_DIFF_OP_NONE))) {
+        if (first->flags & LYD_DEFAULT) {
+            *orig_default = "true";
+        } else {
+            *orig_default = "false";
+        }
+    }
+
+    /* orig-value */
+    if ((schema->nodetype == LYS_LEAF) && (*op == LYD_DIFF_OP_REPLACE)) {
+        /* leaf */
+        *orig_value = (char *)lyd_value2str((struct lyd_node_term *)first, &dynamic);
+        if (!dynamic) {
+            *orig_value = strdup(*orig_value);
+            LY_CHECK_ERR_RET(!*orig_value, LOGMEM(schema->module->ctx), LY_EMEM);
+        }
+    }
+
+    return LY_SUCCESS;
+}
+
+/**
+ * @brief Perform diff for all siblings at certain depth, recursively.
+ *
+ * For user-ordered lists/leaf-lists a specific structure is used for storing
+ * the current order. The idea is to apply all the generated diff changes
+ * virtually on the first tree so that we can continue to generate correct
+ * changes after some were already generated.
+ *
+ * The algorithm then uses second tree position-based changes with a before
+ * (preceding) item anchor.
+ *
+ * Example:
+ *
+ * Virtual first tree leaf-list order:
+ * 1 2 [3] 4 5
+ *
+ * Second tree leaf-list order:
+ * 1 2 [5] 3 4
+ *
+ * We are at the 3rd node now. We look at whether the nodes on the 3rd position
+ * match - they do not - move nodes so that the 3rd position node is final ->
+ * -> move node 5 to the 3rd position -> move node 5 after node 2.
+ *
+ * Required properties:
+ * Stored operations (move) should not be affected by later operations -
+ * - would cause a redundantly long list of operations, possibly inifinite.
+ *
+ * Implemenation justification:
+ * First, all delete operations and only then move/create operations are stored.
+ * Also, preceding anchor is used and after each iteration another node is
+ * at its final position. That results in the invariant that all preceding
+ * nodes are final and will not be changed by the later operations, meaning
+ * they can safely be used as anchors for the later operations.
+ *
+ * @param[in] first First tree first sibling.
+ * @param[in] second Second tree first sibling.
+ * @param[in] options Diff options.
+ * @param[in,out] diff Diff to append to.
+ * @return LY_ERR value.
+ */
+static LY_ERR
+lyd_diff_siblings_r(const struct lyd_node *first, const struct lyd_node *second, int options, struct lyd_node **diff)
+{
+    LY_ERR ret = LY_SUCCESS;
+    const struct lyd_node *iter_first, *iter_second;
+    struct lyd_node *match_second, *match_first;
+    int nosiblings = 0;
+    struct lyd_diff_userord *userord = NULL;
+    LY_ARRAY_SIZE_TYPE u;
+    enum lyd_diff_op op;
+    const char *orig_default;
+    char *orig_value, *key, *value, *orig_key;
+
+    if (options & LYD_DIFF_NOSIBLINGS) {
+        /* remember it for this function call only, should not be passed recursively */
+        nosiblings = 1;
+        options &= ~LYD_DIFF_NOSIBLINGS;
+    }
+
+    /* compare first tree to the second tree - delete, replace, none */
+    LY_LIST_FOR(first, iter_first) {
+        assert(!(iter_first->schema->flags & LYS_KEY));
+        if ((iter_first->flags & LYD_DEFAULT) && !(options & LYD_DIFF_WITHDEFAULTS)) {
+            /* skip default nodes */
+            continue;
+        }
+
+        if (iter_first->schema->nodetype & (LYS_LIST | LYS_LEAFLIST)) {
+            /* try to find the exact instance */
+            lyd_find_sibling_first(second, iter_first, &match_second);
+        } else {
+            /* try to simply find the node, there cannot be more instances */
+            lyd_find_sibling_val(second, iter_first->schema, NULL, 0, &match_second);
+        }
+
+        if (match_second && (match_second->flags & LYD_DEFAULT) && !(options & LYD_DIFF_WITHDEFAULTS)) {
+            /* ignore default nodes */
+            match_second = NULL;
+        }
+
+        if (lysc_is_userordered(iter_first->schema)) {
+            if (match_second) {
+                /* we are handling only user-ordered node delete now */
+                continue;
+            }
+
+            /* get all the attributes */
+            LY_CHECK_GOTO(lyd_diff_userord_attrs(iter_first, match_second, options, &userord, &op, &orig_default,
+                                                 &value, &orig_value, &key, &orig_key), cleanup);
+
+            /* there must be changes, it is deleted */
+            assert(op == LYD_DIFF_OP_DELETE);
+            ret = lyd_diff_add(iter_first, op, orig_default, orig_value, key, value, orig_key, diff);
+
+            free(orig_value);
+            free(key);
+            free(value);
+            free(orig_key);
+            LY_CHECK_GOTO(ret, cleanup);
+        } else {
+            /* get all the attributes */
+            ret = lyd_diff_attrs(iter_first, match_second, options, &op, &orig_default, &orig_value);
+
+            /* add into diff if there are any changes */
+            if (!ret) {
+                if (op == LYD_DIFF_OP_DELETE) {
+                    ret = lyd_diff_add(iter_first, op, orig_default, orig_value, NULL, NULL, NULL, diff);
+                } else {
+                    ret = lyd_diff_add(match_second, op, orig_default, orig_value, NULL, NULL, NULL, diff);
+                }
+
+                free(orig_value);
+                LY_CHECK_GOTO(ret, cleanup);
+            } else if (ret == LY_ENOT) {
+                ret = LY_SUCCESS;
+            } else {
+                goto cleanup;
+            }
+        }
+
+        /* check descendants, if any, recursively */
+        if (match_second) {
+            LY_CHECK_GOTO(lyd_diff_siblings_r(LYD_CHILD(iter_first), LYD_CHILD(match_second), options, diff), cleanup);
+        }
+
+        if (nosiblings) {
+            break;
+        }
+    }
+
+    /* reset all cached positions */
+    LY_ARRAY_FOR(userord, u) {
+        userord[u].pos = 0;
+    }
+
+    /* compare second tree to the first tree - create, user-ordered move */
+    LY_LIST_FOR(second, iter_second) {
+        assert(!(iter_second->schema->flags & LYS_KEY));
+        if ((iter_second->flags & LYD_DEFAULT) && !(options & LYD_DIFF_WITHDEFAULTS)) {
+            /* skip default nodes */
+            continue;
+        }
+
+        if (iter_second->schema->nodetype & (LYS_LIST | LYS_LEAFLIST)) {
+            lyd_find_sibling_first(first, iter_second, &match_first);
+        } else {
+            lyd_find_sibling_val(first, iter_second->schema, NULL, 0, &match_first);
+        }
+
+        if (match_first && (match_first->flags & LYD_DEFAULT) && !(options & LYD_DIFF_WITHDEFAULTS)) {
+            /* ignore default nodes */
+            match_first = NULL;
+        }
+
+        if (lysc_is_userordered(iter_second->schema)) {
+            /* get all the attributes */
+            ret = lyd_diff_userord_attrs(match_first, iter_second, options, &userord, &op, &orig_default,
+                                         &value, &orig_value, &key, &orig_key);
+
+            /* add into diff if there are any changes */
+            if (!ret) {
+                ret = lyd_diff_add(iter_second, op, orig_default, orig_value, key, value, orig_key, diff);
+
+                free(orig_value);
+                free(key);
+                free(value);
+                free(orig_key);
+                LY_CHECK_GOTO(ret, cleanup);
+            } else if (ret == LY_ENOT) {
+                ret = LY_SUCCESS;
+            } else {
+                goto cleanup;
+            }
+        } else if (!match_first) {
+            /* get all the attributes */
+            LY_CHECK_GOTO(lyd_diff_attrs(match_first, iter_second, options, &op, &orig_default, &orig_value), cleanup);
+
+            /* there must be changes, it is created */
+            assert(op == LYD_DIFF_OP_CREATE);
+            ret = lyd_diff_add(iter_second, op, orig_default, orig_value, NULL, NULL, NULL, diff);
+
+            free(orig_value);
+            LY_CHECK_GOTO(ret, cleanup);
+        } /* else was handled */
+
+        if (nosiblings) {
+            break;
+        }
+    }
+
+cleanup:
+    LY_ARRAY_FOR(userord, u) {
+        LY_ARRAY_FREE(userord[u].inst);
+    }
+    LY_ARRAY_FREE(userord);
+    return ret;
+}
+
+API LY_ERR
+lyd_diff(const struct lyd_node *first, const struct lyd_node *second, int options, struct lyd_node **diff)
+{
+    const struct ly_ctx *ctx;
+
+    LY_CHECK_ARG_RET(NULL, diff, LY_EINVAL);
+
+    if (first) {
+        ctx = LYD_NODE_CTX(first);
+    } else if (second) {
+        ctx = LYD_NODE_CTX(second);
+    } else {
+        ctx = NULL;
+    }
+
+    if (first && second && (lysc_data_parent(first->schema) != lysc_data_parent(second->schema))) {
+        LOGERR(ctx, LY_EINVAL, "Invalid arguments - cannot create diff for unrelated data (%s()).", __func__);
+        return LY_EINVAL;
+    }
+
+    *diff = NULL;
+
+    return lyd_diff_siblings_r(first, second, options, diff);
+}
+
+/**
+ * @brief Find a matching node in data tree for a diff node.
+ *
+ * @param[in] first_node First sibling in the data tree.
+ * @param[in] diff_node Diff node to match.
+ * @param[out] match_p Matching node.
+ * @return LY_ERR value.
+ */
+static LY_ERR
+lyd_diff_find_node(const struct lyd_node *first_node, const struct lyd_node *diff_node, struct lyd_node **match_p)
+{
+    if (diff_node->schema->nodetype & (LYS_LIST | LYS_LEAFLIST)) {
+        /* try to find the exact instance */
+        lyd_find_sibling_first(first_node, diff_node, match_p);
+    } else {
+        /* try to simply find the node, there cannot be more instances */
+        lyd_find_sibling_val(first_node, diff_node->schema, NULL, 0, match_p);
+    }
+    LY_CHECK_ERR_RET(!*match_p, LOGINT(LYD_NODE_CTX(diff_node)), LY_EINT);
+
+    return LY_SUCCESS;
+}
+
+/**
+ * @brief Learn operation of a diff node.
+ *
+ * @param[in] diff_node Diff node.
+ * @param[out] op Operation.
+ * @param[out] key_or_value Optional list instance keys predicate or leaf-list value for move operation.
+ * @return LY_ERR value.
+ */
+static LY_ERR
+lyd_diff_get_op(const struct lyd_node *diff_node, const char **op, const char **key_or_value)
+{
+    struct lyd_meta *meta = NULL;
+    const struct lyd_node *diff_parent;
+    const char *meta_name, *str;
+    int dynamic;
+
+    for (diff_parent = diff_node; diff_parent; diff_parent = (struct lyd_node *)diff_parent->parent) {
+        LY_LIST_FOR(diff_parent->meta, meta) {
+            if (!strcmp(meta->name, "operation") && !strcmp(meta->annotation->module->name, "yang")) {
+                str = lyd_meta2str(meta, &dynamic);
+                assert(!dynamic);
+                if ((str[0] == 'r') && (diff_parent != diff_node)) {
+                    /* we do not care about this operation if it's in our parent */
+                    continue;
+                }
+                *op = str;
+                break;
+            }
+        }
+        if (meta) {
+            break;
+        }
+    }
+    LY_CHECK_ERR_RET(!meta, LOGINT(LYD_NODE_CTX(diff_node)), LY_EINT);
+
+    *key_or_value = NULL;
+    if (lysc_is_userordered(diff_node->schema) && (((*op)[0] == 'c') || ((*op)[0] == 'r'))) {
+        if (diff_node->schema->nodetype == LYS_LIST) {
+            meta_name = "key";
+        } else {
+            meta_name = "value";
+        }
+
+        LY_LIST_FOR(diff_node->meta, meta) {
+            if (!strcmp(meta->name, meta_name) && !strcmp(meta->annotation->module->name, "yang")) {
+                str = lyd_meta2str(meta, &dynamic);
+                assert(!dynamic);
+                *key_or_value = str;
+                break;
+            }
+        }
+        LY_CHECK_ERR_RET(!meta, LOGINT(LYD_NODE_CTX(diff_node)), LY_EINT);
+    }
+
+    return LY_SUCCESS;
+}
+
+/**
+ * @brief Insert a diff node into a data tree.
+ *
+ * @param[in,out] first_node First sibling of the data tree.
+ * @param[in] parent_node Data tree sibling parent node.
+ * @param[in] new_node Node to insert.
+ * @param[in] keys_or_value Optional predicate of relative (leaf-)list instance. If not set, the user-ordered
+ * instance will be inserted at the first position.
+ * @return err_info, NULL on success.
+ */
+static LY_ERR
+lyd_diff_insert(struct lyd_node **first_node, struct lyd_node *parent_node, struct lyd_node *new_node,
+                const char *key_or_value)
+{
+    LY_ERR ret;
+    struct lyd_node *anchor;
+
+    assert(new_node);
+
+    if (!*first_node) {
+        if (!parent_node) {
+            /* no parent or siblings */
+            *first_node = new_node;
+            return LY_SUCCESS;
+        }
+
+        /* simply insert into parent, no other children */
+        if (key_or_value) {
+            LOGERR(LYD_NODE_CTX(new_node), LY_EINVAL, "Node \"%s\" instance to insert next to not found.",
+                   new_node->schema->name);
+            return LY_EINVAL;
+        }
+        return lyd_insert(parent_node, new_node);
+    }
+
+    assert(!(*first_node)->parent || ((struct lyd_node *)(*first_node)->parent == parent_node));
+
+    /* simple insert */
+    if (!lysc_is_userordered(new_node->schema)) {
+        /* insert at the end */
+        return lyd_insert_sibling(*first_node, new_node);
+    }
+
+    if (key_or_value) {
+        /* find the anchor sibling */
+        ret = lyd_find_sibling_val(*first_node, new_node->schema, key_or_value, 0, &anchor);
+        if (ret == LY_ENOTFOUND) {
+            LOGERR(LYD_NODE_CTX(new_node), LY_EINVAL, "Node \"%s\" instance to insert next to not found.",
+                   new_node->schema->name);
+            return LY_EINVAL;
+        } else if (ret) {
+            return ret;
+        }
+
+        /* insert after */
+        LY_CHECK_RET(lyd_insert_after(anchor, new_node));
+        assert(new_node->prev == anchor);
+        if (*first_node == new_node) {
+            *first_node = anchor;
+        }
+    } else {
+        if ((*first_node)->schema->flags & LYS_KEY) {
+            assert(parent_node && (parent_node->schema->nodetype == LYS_LIST));
+
+            /* find last key */
+            anchor = *first_node;
+            while (anchor->next && (anchor->next->schema->flags & LYS_KEY)) {
+                anchor = anchor->next;
+            }
+            /* insert after the last key */
+            LY_CHECK_RET(lyd_insert_after(anchor, new_node));
+        } else {
+            /* insert at the beginning */
+            LY_CHECK_RET(lyd_insert_before(*first_node, new_node));
+            *first_node = new_node;
+        }
+    }
+
+    return LY_SUCCESS;
+}
+
+/**
+ * @brief Apply diff subtree on data tree nodes, recursively.
+ *
+ * @param[in,out] first_node First sibling of the data tree.
+ * @param[in] parent_node Parent of the first sibling.
+ * @param[in] diff_node Current diff node.
+ * @return LY_ERR value.
+ */
+static LY_ERR
+lyd_diff_apply_r(struct lyd_node **first_node, struct lyd_node *parent_node, const struct lyd_node *diff_node,
+                 lyd_diff_cb diff_cb, void *cb_data)
+{
+    LY_ERR ret;
+    struct lyd_node *match, *diff_child;
+    const char *op, *key_or_value, *str_val;
+    int dynamic;
+    const struct ly_ctx *ctx = LYD_NODE_CTX(diff_node);
+
+    /* read all the valid attributes */
+    LY_CHECK_RET(lyd_diff_get_op(diff_node, &op, &key_or_value));
+
+    /* handle user-ordered (leaf-)lists separately */
+    if (key_or_value) {
+        assert((op[0] == 'c') || (op[0] == 'r'));
+        if (op[0] == 'r') {
+            /* find the node (we must have some siblings because the node was only moved) */
+            LY_CHECK_RET(lyd_diff_find_node(*first_node, diff_node, &match));
+        } else {
+            /* duplicate the node(s) */
+            match = lyd_dup(diff_node, NULL, LYD_DUP_NO_META);
+            LY_CHECK_RET(!match, LY_EMEM);
+        }
+
+        /* insert/move the node */
+        if (key_or_value[0]) {
+            ret = lyd_diff_insert(first_node, parent_node, match, key_or_value);
+        } else {
+            ret = lyd_diff_insert(first_node, parent_node, match, NULL);
+        }
+        if (ret) {
+            if (op[0] == 'c') {
+                lyd_free_tree(match);
+            }
+            return ret;
+        }
+
+        goto next_iter_r;
+    }
+
+    /* apply operation */
+    switch (op[0]) {
+    case 'n':
+        /* find the node */
+        LY_CHECK_RET(lyd_diff_find_node(*first_node, diff_node, &match));
+
+        if (match->schema->nodetype & LYD_NODE_TERM) {
+            /* special case of only dflt flag change */
+            if (diff_node->flags & LYD_DEFAULT) {
+                match->flags |= LYD_DEFAULT;
+            } else {
+                match->flags &= ~LYD_DEFAULT;
+            }
+        } else {
+            /* none operation on nodes without children is redundant and hence forbidden */
+            if (!LYD_CHILD(diff_node)) {
+                LOGINT_RET(ctx);
+            }
+        }
+        break;
+    case 'c':
+        /* duplicate the node */
+        match = lyd_dup(diff_node, NULL, LYD_DUP_NO_META);
+        LY_CHECK_RET(!match, LY_EMEM);
+
+        /* insert it at the end */
+        ret = 0;
+        if (*first_node) {
+            ret = lyd_insert_after((*first_node)->prev, match);
+        } else if (parent_node) {
+            ret = lyd_insert(parent_node, match);
+        } else {
+            *first_node = match;
+        }
+        if (ret) {
+            lyd_free_tree(match);
+            return ret;
+        }
+
+        break;
+    case 'd':
+        /* find the node */
+        LY_CHECK_RET(lyd_diff_find_node(*first_node, diff_node, &match));
+
+        /* remove it */
+        if ((match == *first_node) && !match->parent) {
+            assert(!parent_node);
+            /* we have removed the top-level node */
+            *first_node = (*first_node)->next;
+        }
+        lyd_free_tree(match);
+
+        /* we are not going recursively in this case, the whole subtree was already deleted */
+        return LY_SUCCESS;
+    case 'r':
+        LY_CHECK_ERR_RET(diff_node->schema->nodetype != LYS_LEAF, LOGINT(ctx), LY_EINT);
+
+        /* find the node */
+        LY_CHECK_RET(lyd_diff_find_node(*first_node, diff_node, &match));
+
+        /* update its value */
+        str_val = lyd_value2str((struct lyd_node_term *)diff_node, &dynamic);
+        ret = lyd_change_term(match, str_val);
+        if (dynamic) {
+            free((char *)str_val);
+        }
+        if (ret && (ret != LY_EEXIST)) {
+            LOGINT_RET(ctx);
+        }
+
+        /* with flags */
+        match->flags = diff_node->flags;
+        break;
+    default:
+        LOGINT_RET(ctx);
+    }
+
+next_iter_r:
+    if (diff_cb) {
+        /* call callback */
+        LY_CHECK_RET(diff_cb(diff_node, match, cb_data));
+    }
+
+    /* apply diff recursively */
+    LY_LIST_FOR(LYD_CHILD(diff_node), diff_child) {
+        LY_CHECK_RET(lyd_diff_apply_r(lyd_node_children_p(match), match, diff_child, diff_cb, cb_data));
+    }
+
+    return LY_SUCCESS;
+}
+
+API LY_ERR
+lyd_diff_apply_module(struct lyd_node **data, const struct lyd_node *diff, const struct lys_module *mod,
+                      lyd_diff_cb diff_cb, void *cb_data)
+{
+    const struct lyd_node *root;
+
+    LY_LIST_FOR(diff, root) {
+        if (mod && (lyd_owner_module(root) != mod)) {
+            /* skip data nodes from different modules */
+            continue;
+        }
+
+        /* apply relevant nodes from the diff datatree */
+        LY_CHECK_RET(lyd_diff_apply_r(data, NULL, root, diff_cb, cb_data));
+    }
+
+    return LY_SUCCESS;
+}
+
+API LY_ERR
+lyd_diff_apply(struct lyd_node **data, const struct lyd_node *diff)
+{
+    return lyd_diff_apply_module(data, diff, NULL, NULL, NULL);
+}
+
 static LY_ERR
 lyd_path_str_enlarge(char **buffer, size_t *buflen, size_t reqlen, int is_static)
 {
diff --git a/src/tree_data.h b/src/tree_data.h
index 5b1c159..c2ad770 100644
--- a/src/tree_data.h
+++ b/src/tree_data.h
@@ -1085,6 +1085,86 @@
 LY_ERR lyd_merge(struct lyd_node **target, const struct lyd_node *source, int options);
 
 /**
+ * @defgroup diffoptions Data diff options.
+ * @ingroup datatree
+ *
+ * Various options to change lyd_diff() behavior.
+ *
+ * Default behavior:
+ * - data trees are compared with all the siblings,
+ * - any default nodes are treated as non-existent and ignored.
+ * @{
+ */
+
+#define LYD_DIFF_NOSIBLINGS     0x01 /**< Only the single subtree is compared, no siblings. */
+#define LYD_DIFF_WITHDEFAULTS   0x02 /**< Default nodes in the trees are not ignored but treated similarly to explicit
+                                          nodes. Also, leaves and leaf-lists are added into diff even in case only their
+                                          default flag (state) was changed. */
+
+/** @} diffoptions */
+
+/**
+ * @brief Learn the differences between 2 data trees.
+ *
+ * The resulting diff is represented as a data tree with specific metadata from the internal 'yang'
+ * module. Most importantly, every node has an effective 'operation' metadata. If there is none
+ * defined on the node, it inherits the operation from the nearest parent. Top-level nodes must
+ * always have the 'operation' metadata defined. Additional metadata ('orig-default', 'value',
+ * 'orig-value', 'key', 'orig-key') are used for storing more information about the value in the first
+ * or the second tree.
+ *
+ * The diff tree is completely independent on the @p first and @p second trees, meaning all
+ * the information about the change is stored in the diff and the trees are not needed.
+ *
+ * !! Caution !!
+ * The diff tree should never be validated because it may easily not be valid! For example,
+ * when data from one case branch are deleted and data from another branch created - data from both
+ * branches are then stored in the diff tree simultaneously.
+ *
+ * @param[in] first First data tree.
+ * @param[in] second Second data tree.
+ * @param[in] options Bitmask of options flags, see @ref diffoptions.
+ * @param[out] diff Generated diff.
+ * @return LY_SUCCESS on success,
+ * @return LY_ERR on error.
+ */
+LY_ERR lyd_diff(const struct lyd_node *first, const struct lyd_node *second, int options, struct lyd_node **diff);
+
+/**
+ * @brief Callback for diff nodes.
+ *
+ * @param[in] diff_node Diff node.
+ * @param[in] data_node Matching node in data.
+ * @param[in] cb_data Arbitrary callback data.
+ * @return LY_ERR value.
+ */
+typedef LY_ERR (*lyd_diff_cb)(const struct lyd_node *diff_node, struct lyd_node *data_node, void *cb_data);
+
+/**
+ * @brief Apply a difference on a data tree but restrict the operation to one module.
+ *
+ * @param[in,out] data Data to apply the diff on.
+ * @param[in] diff Diff to apply.
+ * @param[in] mod Module, whose diff/data only to consider, NULL for all modules.
+ * @param[in] diff_cb Optional diff callback that will be called for every changed node.
+ * @param[in] cb_data Arbitrary callback data.
+ * @return LY_SUCCESS on success,
+ * @return LY_ERR on error.
+ */
+LY_ERR lyd_diff_apply_module(struct lyd_node **data, const struct lyd_node *diff, const struct lys_module *mod,
+                             lyd_diff_cb diff_cb, void *cb_data);
+
+/**
+ * @brief Apply a difference on a data tree.
+ *
+ * @param[in,out] data Data to apply the diff on.
+ * @param[in] diff Diff to apply.
+ * @return LY_SUCCESS on success,
+ * @return LY_ERR on error.
+ */
+LY_ERR lyd_diff_apply(struct lyd_node **data, const struct lyd_node *diff);
+
+/**
  * @brief Find the target in data of a compiled ly_path structure (instance-identifier).
  *
  * @param[in] path Compiled path structure.
diff --git a/tests/utests/CMakeLists.txt b/tests/utests/CMakeLists.txt
index 9d1836e..5c98b63 100644
--- a/tests/utests/CMakeLists.txt
+++ b/tests/utests/CMakeLists.txt
@@ -19,5 +19,6 @@
 ly_add_utest(NAME validation SOURCES data/test_validation.c)
 ly_add_utest(NAME types SOURCES data/test_types.c)
 ly_add_utest(NAME merge SOURCES data/test_merge.c)
+ly_add_utest(NAME diff SOURCES data/test_diff.c)
 ly_add_utest(NAME metadata SOURCES extensions/test_metadata.c)
 ly_add_utest(NAME nacm SOURCES extensions/test_nacm.c)
diff --git a/tests/utests/data/test_diff.c b/tests/utests/data/test_diff.c
new file mode 100644
index 0000000..5557dff
--- /dev/null
+++ b/tests/utests/data/test_diff.c
@@ -0,0 +1,687 @@
+/**
+ * @file test_diff.c
+ * @author Radek Krejci <rkrejci@cesnet.cz>
+ * @author Michal Vasko <mvasko@cesnet.cz>
+ * @brief tests for lyd_diff()
+ *
+ * Copyright (c) 2020 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 <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <setjmp.h>
+#include <cmocka.h>
+
+#include "libyang.h"
+#include "tests/config.h"
+
+struct state {
+    struct ly_ctx *ctx;
+    struct lyd_node *first;
+    struct lyd_node *second;
+    struct lyd_node *diff;
+    char *xml;
+    char *xml1;
+    char *xml2;
+};
+
+static int
+setup_f(void **state)
+{
+    struct state *st;
+    const char *schema =
+    "module defaults {"
+        "yang-version 1.1;"
+        "namespace \"urn:libyang:tests:defaults\";"
+        "prefix df;"
+
+        "feature unhide;"
+
+        "typedef defint32 {"
+            "type int32;"
+            "default \"42\";"
+        "}"
+
+        "leaf hiddenleaf {"
+            "if-feature \"unhide\";"
+            "type int32;"
+            "default \"42\";"
+        "}"
+
+        "container df {"
+            "leaf foo {"
+                "type defint32;"
+            "}"
+
+            "leaf hiddenleaf {"
+                "if-feature \"unhide\";"
+                "type int32;"
+                "default \"42\";"
+            "}"
+
+            "container bar {"
+                "presence \"\";"
+                "leaf hi {"
+                    "type int32;"
+                    "default \"42\";"
+                "}"
+
+                "leaf ho {"
+                    "type int32;"
+                    "mandatory true;"
+                "}"
+            "}"
+
+            "leaf-list llist {"
+                "type defint32;"
+                "ordered-by user;"
+            "}"
+
+            "leaf-list dllist {"
+                "type uint8;"
+                "default \"1\";"
+                "default \"2\";"
+                "default \"3\";"
+            "}"
+
+            "list list {"
+                "key \"name\";"
+                "leaf name {"
+                    "type string;"
+                "}"
+
+                "leaf value {"
+                    "type int32;"
+                    "default \"42\";"
+                "}"
+            "}"
+
+            "choice select {"
+                "default \"a\";"
+                "case a {"
+                    "choice a {"
+                        "leaf a1 {"
+                            "type int32;"
+                            "default \"42\";"
+                        "}"
+
+                        "leaf a2 {"
+                            "type int32;"
+                            "default \"24\";"
+                        "}"
+                    "}"
+                "}"
+
+                "leaf b {"
+                    "type string;"
+                "}"
+
+                "container c {"
+                    "presence \"\";"
+                    "leaf x {"
+                        "type int32;"
+                        "default \"42\";"
+                    "}"
+                "}"
+            "}"
+
+            "choice select2 {"
+                "default \"s2b\";"
+                "leaf s2a {"
+                    "type int32;"
+                    "default \"42\";"
+                "}"
+
+                "case s2b {"
+                    "choice s2b {"
+                        "default \"b1\";"
+                        "case b1 {"
+                            "leaf b1_1 {"
+                                "type int32;"
+                                "default \"42\";"
+                            "}"
+
+                            "leaf b1_2 {"
+                                "type string;"
+                            "}"
+
+                            "leaf b1_status {"
+                                "type int32;"
+                                "default \"42\";"
+                                "config false;"
+                            "}"
+                        "}"
+
+                        "leaf b2 {"
+                            "type int32;"
+                            "default \"42\";"
+                        "}"
+                    "}"
+                "}"
+            "}"
+        "}"
+
+        "container hidden {"
+            "leaf foo {"
+                "type int32;"
+                "default \"42\";"
+            "}"
+
+            "leaf baz {"
+                "type int32;"
+                "default \"42\";"
+            "}"
+
+            "leaf papa {"
+                "type int32;"
+                "default \"42\";"
+                "config false;"
+            "}"
+        "}"
+
+        "rpc rpc1 {"
+            "input {"
+                "leaf inleaf1 {"
+                    "type string;"
+                "}"
+
+                "leaf inleaf2 {"
+                    "type string;"
+                    "default \"def1\";"
+                "}"
+            "}"
+
+            "output {"
+                "leaf outleaf1 {"
+                    "type string;"
+                    "default \"def2\";"
+                "}"
+
+                "leaf outleaf2 {"
+                    "type string;"
+                "}"
+            "}"
+        "}"
+
+        "notification notif {"
+            "leaf ntfleaf1 {"
+                "type string;"
+                "default \"def3\";"
+            "}"
+
+            "leaf ntfleaf2 {"
+                "type string;"
+            "}"
+        "}"
+    "}";
+
+    (*state) = st = calloc(1, sizeof *st);
+    assert_non_null(st);
+    assert_int_equal(LY_SUCCESS, ly_ctx_new(TESTS_DIR_MODULES_YANG, 0, &st->ctx));
+    assert_non_null(ly_ctx_load_module(st->ctx, "ietf-netconf-acm", "2018-02-14"));
+    assert_non_null(lys_parse_mem(st->ctx, schema, LYS_IN_YANG));
+
+    return 0;
+}
+
+static int
+teardown_f(void **state)
+{
+    struct state *st = (*state);
+
+    lyd_free_siblings(st->first);
+    lyd_free_siblings(st->second);
+    lyd_free_siblings(st->diff);
+    ly_ctx_destroy(st->ctx, NULL);
+    free(st->xml);
+    free(st->xml1);
+    free(st->xml2);
+    free(st);
+    (*state) = NULL;
+
+    return 0;
+}
+
+static void
+test_invalid(void **state)
+{
+    struct state *st = (*state);
+    const char *xml = "<df xmlns=\"urn:libyang:tests:defaults\"><foo>42</foo></df>";
+
+    st->first = lyd_parse_mem(st->ctx, xml, LYD_XML, LYD_OPT_PARSE_ONLY);
+    assert_non_null(st->first);
+    st->second = NULL;
+
+    assert_int_equal(lyd_diff(st->first, lyd_node_children(st->first, 0), 0, &st->diff), LY_EINVAL);
+
+    assert_int_equal(lyd_diff(NULL, NULL, 0, NULL), LY_EINVAL);
+}
+
+static void
+test_same(void **state)
+{
+    struct state *st = (*state);
+    const char *xml = "<nacm xmlns=\"urn:ietf:params:xml:ns:yang:ietf-netconf-acm\">"
+                        "<enable-nacm>true</enable-nacm>"
+                        "<read-default>permit</read-default>"
+                        "<write-default>deny</write-default>"
+                        "<exec-default>permit</exec-default>"
+                        "<enable-external-groups>true</enable-external-groups>"
+                      "</nacm><df xmlns=\"urn:libyang:tests:defaults\">"
+                        "<foo>42</foo><b1_1>42</b1_1>"
+                      "</df><hidden xmlns=\"urn:libyang:tests:defaults\">"
+                        "<foo>42</foo><baz>42</baz></hidden>";
+
+    st->first = lyd_parse_mem(st->ctx, xml, LYD_XML, LYD_OPT_PARSE_ONLY);
+    assert_non_null(st->first);
+    st->second = lyd_parse_mem(st->ctx, xml, LYD_XML, LYD_OPT_PARSE_ONLY);
+    assert_non_null(st->second);
+
+    assert_int_equal(lyd_diff(st->first, st->second, 0, &st->diff), LY_SUCCESS);
+    assert_null(st->diff);
+
+    assert_int_equal(lyd_diff_apply(&st->first, st->diff), LY_SUCCESS);
+    lyd_print_mem(&st->xml1, st->first, LYD_XML, LYDP_WITHSIBLINGS);
+    lyd_print_mem(&st->xml2, st->second, LYD_XML, LYDP_WITHSIBLINGS);
+    assert_string_equal(st->xml1, st->xml2);
+}
+
+static void
+test_empty1(void **state)
+{
+    struct state *st = (*state);
+    const char *xml =
+        "<df xmlns=\"urn:libyang:tests:defaults\">"
+            "<foo>42</foo><b1_1>42</b1_1>"
+        "</df>"
+        "<hidden xmlns=\"urn:libyang:tests:defaults\">"
+            "<foo>42</foo><baz>42</baz>"
+        "</hidden>";
+
+    st->first = NULL;
+    st->second = lyd_parse_mem(st->ctx, xml, LYD_XML, LYD_OPT_PARSE_ONLY);
+    assert_non_null(st->second);
+
+    assert_int_equal(lyd_diff(st->first, st->second, 0, &st->diff), LY_SUCCESS);
+
+    assert_non_null(st->diff);
+    lyd_print_mem(&st->xml, st->diff, LYD_XML, LYDP_WITHSIBLINGS);
+    assert_string_equal(st->xml,
+        "<df xmlns=\"urn:libyang:tests:defaults\" xmlns:yang=\"urn:ietf:params:xml:ns:yang:1\" yang:operation=\"create\">"
+            "<foo>42</foo><b1_1>42</b1_1>"
+        "</df>"
+        "<hidden xmlns=\"urn:libyang:tests:defaults\" xmlns:yang=\"urn:ietf:params:xml:ns:yang:1\" yang:operation=\"create\">"
+            "<foo>42</foo><baz>42</baz>"
+        "</hidden>"
+    );
+
+    assert_int_equal(lyd_diff_apply(&st->first, st->diff), LY_SUCCESS);
+    lyd_print_mem(&st->xml1, st->first, LYD_XML, LYDP_WITHSIBLINGS);
+    lyd_print_mem(&st->xml2, st->second, LYD_XML, LYDP_WITHSIBLINGS);
+    assert_string_equal(st->xml1, st->xml2);
+}
+
+static void
+test_empty2(void **state)
+{
+    struct state *st = (*state);
+    const char *xml = "<df xmlns=\"urn:libyang:tests:defaults\">"
+                        "<foo>42</foo><b1_1>42</b1_1>"
+                      "</df><hidden xmlns=\"urn:libyang:tests:defaults\">"
+                        "<foo>42</foo><baz>42</baz></hidden>";
+
+    st->first = lyd_parse_mem(st->ctx, xml, LYD_XML, LYD_OPT_PARSE_ONLY);
+    assert_non_null(st->first);
+    st->second = NULL;
+
+    assert_int_equal(lyd_diff(st->first, st->second, 0, &st->diff), LY_SUCCESS);
+
+    assert_non_null(st->diff);
+    lyd_print_mem(&st->xml, st->diff, LYD_XML, LYDP_WITHSIBLINGS);
+    assert_string_equal(st->xml,
+        "<df xmlns=\"urn:libyang:tests:defaults\" xmlns:yang=\"urn:ietf:params:xml:ns:yang:1\" yang:operation=\"delete\">"
+            "<foo>42</foo><b1_1>42</b1_1>"
+        "</df>"
+        "<hidden xmlns=\"urn:libyang:tests:defaults\" xmlns:yang=\"urn:ietf:params:xml:ns:yang:1\" yang:operation=\"delete\">"
+            "<foo>42</foo><baz>42</baz>"
+        "</hidden>"
+    );
+
+    assert_int_equal(lyd_diff_apply(&st->first, st->diff), LY_SUCCESS);
+    assert_ptr_equal(st->first, st->second);
+}
+
+static void
+test_empty_nested(void **state)
+{
+    struct state *st = (*state);
+    const char *xml = "<df xmlns=\"urn:libyang:tests:defaults\"><foo>42</foo></df>";
+
+    st->first = lyd_parse_mem(st->ctx, xml, LYD_XML, LYD_OPT_PARSE_ONLY);
+    assert_non_null(st->first);
+    st->second = NULL;
+
+    assert_int_equal(lyd_diff(NULL, NULL, 0, &st->diff), LY_SUCCESS);
+    assert_null(st->diff);
+
+    assert_int_equal(lyd_diff(NULL, lyd_node_children(st->first, 0), 0, &st->diff), LY_SUCCESS);
+
+    assert_non_null(st->diff);
+    lyd_print_mem(&st->xml, st->diff, LYD_XML, LYDP_WITHSIBLINGS);
+    assert_string_equal(st->xml,
+        "<df xmlns=\"urn:libyang:tests:defaults\" xmlns:yang=\"urn:ietf:params:xml:ns:yang:1\" yang:operation=\"none\">"
+            "<foo yang:operation=\"create\">42</foo>"
+        "</df>"
+    );
+
+    free(st->xml);
+    lyd_free_siblings(st->diff);
+    assert_int_equal(lyd_diff(lyd_node_children(st->first, 0), NULL, 0, &st->diff), LY_SUCCESS);
+
+    assert_non_null(st->diff);
+    lyd_print_mem(&st->xml, st->diff, LYD_XML, LYDP_WITHSIBLINGS);
+    assert_string_equal(st->xml,
+        "<df xmlns=\"urn:libyang:tests:defaults\" xmlns:yang=\"urn:ietf:params:xml:ns:yang:1\" yang:operation=\"none\">"
+            "<foo yang:operation=\"delete\">42</foo>"
+        "</df>"
+    );
+}
+
+static void
+test_leaf(void **state)
+{
+    struct state *st = (*state);
+    const char *xml1 =
+        "<df xmlns=\"urn:libyang:tests:defaults\">"
+            "<foo>42</foo>"
+        "</df>"
+        "<hidden xmlns=\"urn:libyang:tests:defaults\">"
+            "<foo>42</foo><baz>42</baz>"
+        "</hidden>";
+    const char *xml2 =
+        "<df xmlns=\"urn:libyang:tests:defaults\">"
+            "<foo>41</foo><b1_1>42</b1_1>"
+        "</df>";
+
+    st->first = lyd_parse_mem(st->ctx, xml1, LYD_XML, LYD_OPT_PARSE_ONLY);
+    assert_non_null(st->first);
+    st->second = lyd_parse_mem(st->ctx, xml2, LYD_XML, LYD_OPT_PARSE_ONLY);
+    assert_non_null(st->second);
+
+    assert_int_equal(lyd_diff(st->first, st->second, 0, &st->diff), LY_SUCCESS);
+
+    assert_non_null(st->diff);
+    lyd_print_mem(&st->xml, st->diff, LYD_XML, LYDP_WITHSIBLINGS);
+    assert_string_equal(st->xml,
+        "<df xmlns=\"urn:libyang:tests:defaults\" xmlns:yang=\"urn:ietf:params:xml:ns:yang:1\" yang:operation=\"none\">"
+            "<foo yang:operation=\"replace\" yang:orig-value=\"42\">41</foo><b1_1 yang:operation=\"create\">42</b1_1>"
+        "</df>"
+        "<hidden xmlns=\"urn:libyang:tests:defaults\" xmlns:yang=\"urn:ietf:params:xml:ns:yang:1\" yang:operation=\"delete\">"
+            "<foo>42</foo><baz>42</baz>"
+        "</hidden>"
+    );
+
+    assert_int_equal(lyd_diff_apply(&st->first, st->diff), LY_SUCCESS);
+    lyd_print_mem(&st->xml1, st->first, LYD_XML, LYDP_WITHSIBLINGS);
+    lyd_print_mem(&st->xml2, st->second, LYD_XML, LYDP_WITHSIBLINGS);
+    assert_string_equal(st->xml1, st->xml2);
+}
+
+static void
+test_list(void **state)
+{
+    struct state *st = (*state);
+    const char *xml1 = "<df xmlns=\"urn:libyang:tests:defaults\">"
+                         "<list><name>a</name><value>1</value></list>"
+                         "<list><name>b</name><value>2</value></list>"
+                       "</df>";
+    const char *xml2 = "<df xmlns=\"urn:libyang:tests:defaults\">"
+                         "<list><name>b</name><value>-2</value></list>"
+                         "<list><name>c</name><value>3</value></list>"
+                       "</df>";
+
+    st->first = lyd_parse_mem(st->ctx, xml1, LYD_XML, LYD_OPT_PARSE_ONLY);
+    assert_non_null(st->first);
+    st->second = lyd_parse_mem(st->ctx, xml2, LYD_XML, LYD_OPT_PARSE_ONLY);
+    assert_non_null(st->second);
+
+    assert_int_equal(lyd_diff(st->first, st->second, 0, &st->diff), LY_SUCCESS);
+
+    assert_non_null(st->diff);
+    lyd_print_mem(&st->xml, st->diff, LYD_XML, LYDP_WITHSIBLINGS);
+    assert_string_equal(st->xml,
+        "<df xmlns=\"urn:libyang:tests:defaults\" xmlns:yang=\"urn:ietf:params:xml:ns:yang:1\" yang:operation=\"none\">"
+            "<list yang:operation=\"delete\"><name>a</name><value>1</value></list>"
+            "<list yang:operation=\"none\">"
+                "<name>b</name><value yang:operation=\"replace\" yang:orig-value=\"2\">-2</value>"
+            "</list>"
+            "<list yang:operation=\"create\"><name>c</name><value>3</value></list>"
+        "</df>"
+    );
+
+    assert_int_equal(lyd_diff_apply(&st->first, st->diff), LY_SUCCESS);
+    lyd_print_mem(&st->xml1, st->first, LYD_XML, LYDP_WITHSIBLINGS);
+    lyd_print_mem(&st->xml2, st->second, LYD_XML, LYDP_WITHSIBLINGS);
+    assert_string_equal(st->xml1, st->xml2);
+}
+
+static void
+test_userord_llist(void **state)
+{
+    struct state *st = (*state);
+    const char *xml1 = "<df xmlns=\"urn:libyang:tests:defaults\">"
+                         "<llist>1</llist>"
+                         "<llist>2</llist>"
+                         "<llist>3</llist>"
+                         "<llist>4</llist>"
+                         "<llist>5</llist>"
+                       "</df>";
+    const char *xml2 = "<df xmlns=\"urn:libyang:tests:defaults\">"
+                         "<llist>1</llist>"
+                         "<llist>4</llist>"
+                         "<llist>3</llist>"
+                         "<llist>2</llist>"
+                         "<llist>5</llist>"
+                       "</df>";
+
+    st->first = lyd_parse_mem(st->ctx, xml1, LYD_XML, LYD_OPT_PARSE_ONLY);
+    assert_non_null(st->first);
+    st->second = lyd_parse_mem(st->ctx, xml2, LYD_XML, LYD_OPT_PARSE_ONLY);
+    assert_non_null(st->second);
+
+    assert_int_equal(lyd_diff(st->first, st->second, 0, &st->diff), LY_SUCCESS);
+
+    assert_non_null(st->diff);
+    lyd_print_mem(&st->xml, st->diff, LYD_XML, LYDP_WITHSIBLINGS);
+    assert_string_equal(st->xml,
+        "<df xmlns=\"urn:libyang:tests:defaults\" xmlns:yang=\"urn:ietf:params:xml:ns:yang:1\" yang:operation=\"none\">"
+            "<llist yang:operation=\"replace\" yang:orig-value=\"3\" yang:value=\"1\">4</llist>"
+            "<llist yang:operation=\"replace\" yang:orig-value=\"2\" yang:value=\"4\">3</llist>"
+        "</df>"
+    );
+
+    assert_int_equal(lyd_diff_apply(&st->first, st->diff), LY_SUCCESS);
+    lyd_print_mem(&st->xml1, st->first, LYD_XML, LYDP_WITHSIBLINGS);
+    lyd_print_mem(&st->xml2, st->second, LYD_XML, LYDP_WITHSIBLINGS);
+    assert_string_equal(st->xml1, st->xml2);
+}
+
+static void
+test_userord_llist2(void **state)
+{
+    struct state *st = (*state);
+    const char *xml1 = "<df xmlns=\"urn:libyang:tests:defaults\">"
+                         "<llist>1</llist>"
+                         "<list><name>a</name><value>1</value></list>"
+                         "<llist>2</llist>"
+                         "<llist>3</llist>"
+                         "<llist>4</llist>"
+                       "</df>";
+    const char *xml2 = "<df xmlns=\"urn:libyang:tests:defaults\">"
+                         "<llist>1</llist>"
+                         "<list><name>a</name><value>1</value></list>"
+                         "<llist>2</llist>"
+                         "<llist>4</llist>"
+                         "<llist>3</llist>"
+                       "</df>";
+
+    st->first = lyd_parse_mem(st->ctx, xml1, LYD_XML, LYD_OPT_PARSE_ONLY);
+    assert_non_null(st->first);
+    st->second = lyd_parse_mem(st->ctx, xml2, LYD_XML, LYD_OPT_PARSE_ONLY);
+    assert_non_null(st->second);
+
+    assert_int_equal(lyd_diff(st->first, st->second, 0, &st->diff), LY_SUCCESS);
+
+    assert_non_null(st->diff);
+    lyd_print_mem(&st->xml, st->diff, LYD_XML, LYDP_WITHSIBLINGS);
+    assert_string_equal(st->xml,
+        "<df xmlns=\"urn:libyang:tests:defaults\" xmlns:yang=\"urn:ietf:params:xml:ns:yang:1\" yang:operation=\"none\">"
+            "<llist yang:operation=\"replace\" yang:orig-value=\"3\" yang:value=\"2\">4</llist>"
+        "</df>"
+    );
+
+    assert_int_equal(lyd_diff_apply(&st->first, st->diff), LY_SUCCESS);
+    lyd_print_mem(&st->xml1, st->first, LYD_XML, LYDP_WITHSIBLINGS);
+    lyd_print_mem(&st->xml2, st->second, LYD_XML, LYDP_WITHSIBLINGS);
+    assert_string_equal(st->xml1, st->xml2);
+}
+
+static void
+test_userord_mix(void **state)
+{
+    struct state *st = (*state);
+    const char *xml1 = "<df xmlns=\"urn:libyang:tests:defaults\">"
+                         "<llist>1</llist>"
+                         "<llist>2</llist>"
+                         "<llist>3</llist>"
+                       "</df>";
+    const char *xml2 = "<df xmlns=\"urn:libyang:tests:defaults\">"
+                         "<llist>3</llist>"
+                         "<llist>1</llist>"
+                       "</df>";
+
+    st->first = lyd_parse_mem(st->ctx, xml1, LYD_XML, LYD_OPT_PARSE_ONLY);
+    assert_non_null(st->first);
+    st->second = lyd_parse_mem(st->ctx, xml2, LYD_XML, LYD_OPT_PARSE_ONLY);
+    assert_non_null(st->second);
+
+    assert_int_equal(lyd_diff(st->first, st->second, 0, &st->diff), LY_SUCCESS);
+
+    assert_non_null(st->diff);
+    lyd_print_mem(&st->xml, st->diff, LYD_XML, LYDP_WITHSIBLINGS);
+    assert_string_equal(st->xml,
+        "<df xmlns=\"urn:libyang:tests:defaults\" xmlns:yang=\"urn:ietf:params:xml:ns:yang:1\" yang:operation=\"none\">"
+            "<llist yang:operation=\"delete\" yang:orig-value=\"1\">2</llist>"
+            "<llist yang:operation=\"replace\" yang:orig-value=\"1\" yang:value=\"\">3</llist>"
+        "</df>"
+    );
+
+    assert_int_equal(lyd_diff_apply(&st->first, st->diff), LY_SUCCESS);
+    lyd_print_mem(&st->xml1, st->first, LYD_XML, LYDP_WITHSIBLINGS);
+    lyd_print_mem(&st->xml2, st->second, LYD_XML, LYDP_WITHSIBLINGS);
+    assert_string_equal(st->xml1, st->xml2);
+}
+
+static void
+test_userord_mix2(void **state)
+{
+    struct state *st = (*state);
+    const char *xml1 = "<df xmlns=\"urn:libyang:tests:defaults\">"
+                         "<llist>1</llist>"
+                         "<llist>2</llist>"
+                         "<llist>3</llist>"
+                       "</df>";
+    const char *xml2 = "<df xmlns=\"urn:libyang:tests:defaults\">"
+                         "<llist>4</llist>"
+                         "<llist>3</llist>"
+                         "<llist>1</llist>"
+                       "</df>";
+
+    st->first = lyd_parse_mem(st->ctx, xml1, LYD_XML, LYD_OPT_PARSE_ONLY);
+    assert_non_null(st->first);
+    st->second = lyd_parse_mem(st->ctx, xml2, LYD_XML, LYD_OPT_PARSE_ONLY);
+    assert_non_null(st->second);
+
+    assert_int_equal(lyd_diff(st->first, st->second, 0, &st->diff), LY_SUCCESS);
+
+    assert_non_null(st->diff);
+    lyd_print_mem(&st->xml, st->diff, LYD_XML, LYDP_WITHSIBLINGS);
+    assert_string_equal(st->xml,
+        "<df xmlns=\"urn:libyang:tests:defaults\" xmlns:yang=\"urn:ietf:params:xml:ns:yang:1\" yang:operation=\"none\">"
+            "<llist yang:operation=\"delete\" yang:orig-value=\"1\">2</llist>"
+            "<llist yang:operation=\"create\" yang:value=\"\">4</llist>"
+            "<llist yang:operation=\"replace\" yang:orig-value=\"1\" yang:value=\"4\">3</llist>"
+        "</df>"
+    );
+
+    assert_int_equal(lyd_diff_apply(&st->first, st->diff), LY_SUCCESS);
+    lyd_print_mem(&st->xml1, st->first, LYD_XML, LYDP_WITHSIBLINGS);
+    lyd_print_mem(&st->xml2, st->second, LYD_XML, LYDP_WITHSIBLINGS);
+    assert_string_equal(st->xml1, st->xml2);
+}
+
+static void
+test_wd(void **state)
+{
+    struct state *st = (*state);
+    const struct lys_module *mod;
+    const char *xml = "<df xmlns=\"urn:libyang:tests:defaults\">"
+                        "<foo>41</foo><dllist>4</dllist>"
+                      "</df>";
+
+    mod = ly_ctx_get_module_implemented(st->ctx, "defaults");
+    assert_non_null(mod);
+
+    st->first = NULL;
+    assert_int_equal(lyd_validate_modules(&st->first, &mod, 1, 0), LY_SUCCESS);
+    assert_ptr_not_equal(st->first, NULL);
+    st->second = lyd_parse_mem(st->ctx, xml, LYD_XML, LYD_VALOPT_DATA_ONLY);
+    assert_non_null(st->second);
+
+    assert_int_equal(lyd_diff(st->first, st->second, LYD_DIFF_WITHDEFAULTS, &st->diff), LY_SUCCESS);
+
+    assert_non_null(st->diff);
+    lyd_print_mem(&st->xml, st->diff, LYD_XML, LYDP_WITHSIBLINGS);
+    assert_string_equal(st->xml,
+        "<df xmlns=\"urn:libyang:tests:defaults\" xmlns:yang=\"urn:ietf:params:xml:ns:yang:1\" yang:operation=\"none\">"
+            "<foo yang:operation=\"replace\" yang:orig-default=\"true\" yang:orig-value=\"42\">41</foo>"
+            "<dllist yang:operation=\"delete\">1</dllist>"
+            "<dllist yang:operation=\"delete\">2</dllist>"
+            "<dllist yang:operation=\"delete\">3</dllist>"
+            "<dllist yang:operation=\"create\">4</dllist>"
+        "</df>"
+    );
+
+    assert_int_equal(lyd_diff_apply(&st->first, st->diff), LY_SUCCESS);
+    lyd_print_mem(&st->xml1, st->first, LYD_XML, LYDP_WITHSIBLINGS);
+    lyd_print_mem(&st->xml2, st->second, LYD_XML, LYDP_WITHSIBLINGS);
+    /* TODO just an ordering problem
+    assert_string_equal(st->xml1, st->xml2);*/
+}
+
+int main(void)
+{
+    const struct CMUnitTest tests[] = {
+        cmocka_unit_test_setup_teardown(test_invalid, setup_f, teardown_f),
+        cmocka_unit_test_setup_teardown(test_same, setup_f, teardown_f),
+        cmocka_unit_test_setup_teardown(test_empty1, setup_f, teardown_f),
+        cmocka_unit_test_setup_teardown(test_empty2, setup_f, teardown_f),
+        cmocka_unit_test_setup_teardown(test_empty_nested, setup_f, teardown_f),
+        cmocka_unit_test_setup_teardown(test_leaf, setup_f, teardown_f),
+        cmocka_unit_test_setup_teardown(test_list, setup_f, teardown_f),
+        cmocka_unit_test_setup_teardown(test_userord_llist, setup_f, teardown_f),
+        cmocka_unit_test_setup_teardown(test_userord_llist2, setup_f, teardown_f),
+        cmocka_unit_test_setup_teardown(test_userord_mix, setup_f, teardown_f),
+        cmocka_unit_test_setup_teardown(test_userord_mix2, setup_f, teardown_f),
+        cmocka_unit_test_setup_teardown(test_wd, setup_f, teardown_f),
+    };
+
+    return cmocka_run_group_tests(tests, NULL, NULL);
+}