diff --git a/.gitignore b/.gitignore index df677f0..43a3458 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,5 @@ target/ logging_folder +.vscode/launch.json +json/.DS_Store +.DS_Store diff --git a/Cargo.lock b/Cargo.lock index a506994..6de34f6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -17,6 +17,12 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" +[[package]] +name = "adler2" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" + [[package]] name = "ahash" version = "0.8.11" @@ -139,6 +145,74 @@ version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" +[[package]] +name = "axum" +version = "0.7.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "504e3947307ac8326a5437504c517c4b56716c9d98fac0028c2acc7ca47d70ae" +dependencies = [ + "async-trait", + "axum-core", + "axum-macros", + "bytes", + "futures-util", + "http 1.1.0", + "http-body 1.0.1", + "http-body-util", + "hyper 1.5.0", + "hyper-util", + "itoa", + "matchit", + "memchr", + "mime", + "multer", + "percent-encoding", + "pin-project-lite", + "rustversion", + "serde", + "serde_json", + "serde_path_to_error", + "serde_urlencoded", + "sync_wrapper 1.0.1", + "tokio", + "tower", + "tower-layer", + "tower-service", + "tracing", +] + +[[package]] +name = "axum-core" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09f2bd6146b97ae3359fa0cc6d6b376d9539582c7b4220f041a33ec24c226199" +dependencies = [ + "async-trait", + "bytes", + "futures-util", + "http 1.1.0", + "http-body 1.0.1", + "http-body-util", + "mime", + "pin-project-lite", + "rustversion", + "sync_wrapper 1.0.1", + "tower-layer", + "tower-service", + "tracing", +] + +[[package]] +name = "axum-macros" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57d123550fa8d071b7255cb0cc04dc302baa6c8c4a79f55701552684d8399bce" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "backtrace" version = "0.3.71" @@ -149,7 +223,7 @@ dependencies = [ "cc", "cfg-if", "libc", - "miniz_oxide", + "miniz_oxide 0.7.4", "object", "rustc-demangle", ] @@ -160,6 +234,12 @@ version = "0.21.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" +[[package]] +name = "base64" +version = "0.22.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" + [[package]] name = "bit-set" version = "0.5.3" @@ -227,11 +307,17 @@ version = "0.6.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5ce89b21cab1437276d2650d57e971f9d548a2d9037cc231abdc0562b97498ce" +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + [[package]] name = "bytes" -version = "1.6.0" +version = "1.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "514de17de45fdb8dc022b1a7975556c53c86f9f0aa5f534b98977b171857c2c9" +checksum = "428d9aa8fbc0670b7b8d6030a7fadd0f86151cae55e4dbbece15f3780a3dfaf3" [[package]] name = "cassowary" @@ -275,6 +361,28 @@ dependencies = [ "windows-targets 0.52.5", ] +[[package]] +name = "chrono-tz" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93698b29de5e97ad0ae26447b344c482a7284c737d9ddc5f9e52b74a336671bb" +dependencies = [ + "chrono", + "chrono-tz-build", + "phf", +] + +[[package]] +name = "chrono-tz-build" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c088aee841df9c3041febbb73934cfc39708749bf96dc827e3359cd39ef11b1" +dependencies = [ + "parse-zoneinfo", + "phf", + "phf_codegen", +] + [[package]] name = "clap" version = "4.5.7" @@ -315,6 +423,42 @@ version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4b82cf0babdbd58558212896d1a4272303a57bdb245c2bf1147185fb45640e70" +[[package]] +name = "codes-agency" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "809a7790247f949cc35a1f9b497fd13a79ee330e34f049c6e837685363d20faf" +dependencies = [ + "codes-common", + "serde", +] + +[[package]] +name = "codes-common" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2b16b1037e7111ea4a4bd4a2b48733b990a76ecc321539858a5ab534792b287" +dependencies = [ + "csv", + "tera", + "tracing", +] + +[[package]] +name = "codes-iso-3166" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4d9f6ddc6481f15051ec704400c275b5135896006edd9342db7d0a116c70fb4a" +dependencies = [ + "codes-agency", + "codes-common", + "csv", + "lazy_static", + "regex", + "serde", + "tera", +] + [[package]] name = "color-eyre" version = "0.6.3" @@ -435,18 +579,31 @@ dependencies = [ "libc", ] +[[package]] +name = "crc32fast" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a97769d94ddab943e4510d138150169a2758b5ef3eb191a9ee688de3e23ef7b3" +dependencies = [ + "cfg-if", +] + [[package]] name = "credential-converter" version = "0.1.0" dependencies = [ "anyhow", + "axum", + "base64 0.21.7", "clap", + "codes-iso-3166", "color-eyre", "config", "crossterm", "csv", "digital-credential-data-models", "directories", + "eyre", "jsonpath-rust", "jsonschema", "lazy_static", @@ -460,9 +617,11 @@ dependencies = [ "serde_path_to_error", "strum", "tokio", + "tower-http", "tracing", "tracing-error", "tracing-subscriber", + "ureq", ] [[package]] @@ -562,6 +721,12 @@ dependencies = [ "serde", ] +[[package]] +name = "deunicode" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "339544cc9e2c4dc3fc7149fd630c5f22263a4fdf18a98afd0075784968b5cf00" + [[package]] name = "digest" version = "0.10.7" @@ -662,6 +827,16 @@ dependencies = [ "regex", ] +[[package]] +name = "flate2" +version = "1.0.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c936bfdafb507ebbf50b8074c54fa31c5be9a1e7e5f467dd659697041407d07c" +dependencies = [ + "crc32fast", + "miniz_oxide 0.8.0", +] + [[package]] name = "fluent-uri" version = "0.2.0-alpha.5" @@ -804,6 +979,17 @@ dependencies = [ "walkdir", ] +[[package]] +name = "globwalk" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0bf760ebf69878d9fd8f110c89703d90ce35095324d1f1edcb595c63945ee757" +dependencies = [ + "bitflags 2.6.0", + "ignore", + "walkdir", +] + [[package]] name = "h2" version = "0.3.26" @@ -815,7 +1001,7 @@ dependencies = [ "futures-core", "futures-sink", "futures-util", - "http", + "http 0.2.12", "indexmap 2.2.6", "slab", "tokio", @@ -868,6 +1054,17 @@ dependencies = [ "itoa", ] +[[package]] +name = "http" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21b9ddb458710bc376481b842f5da65cdf31522de232c1ca8146abce2a358258" +dependencies = [ + "bytes", + "fnv", + "itoa", +] + [[package]] name = "http-body" version = "0.4.6" @@ -875,7 +1072,30 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7ceab25649e9960c0311ea418d17bee82c0dcec1bd053b5f9a66e265a693bed2" dependencies = [ "bytes", - "http", + "http 0.2.12", + "pin-project-lite", +] + +[[package]] +name = "http-body" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" +dependencies = [ + "bytes", + "http 1.1.0", +] + +[[package]] +name = "http-body-util" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "793429d76616a256bcb62c2a2ec2bed781c8307e797e2598c50010f2bee2544f" +dependencies = [ + "bytes", + "futures-util", + "http 1.1.0", + "http-body 1.0.1", "pin-project-lite", ] @@ -891,6 +1111,15 @@ version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" +[[package]] +name = "humansize" +version = "2.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6cb51c9a029ddc91b07a787f1d86b53ccfa49b0e86688c946ebe8d3555685dd7" +dependencies = [ + "libm", +] + [[package]] name = "hyper" version = "0.14.29" @@ -902,8 +1131,8 @@ dependencies = [ "futures-core", "futures-util", "h2", - "http", - "http-body", + "http 0.2.12", + "http-body 0.4.6", "httparse", "httpdate", "itoa", @@ -915,6 +1144,41 @@ dependencies = [ "want", ] +[[package]] +name = "hyper" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbbff0a806a4728c99295b254c8838933b5b082d75e3cb70c8dab21fdfbcfa9a" +dependencies = [ + "bytes", + "futures-channel", + "futures-util", + "http 1.1.0", + "http-body 1.0.1", + "httparse", + "httpdate", + "itoa", + "pin-project-lite", + "smallvec", + "tokio", +] + +[[package]] +name = "hyper-util" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41296eb09f183ac68eec06e03cdbea2e759633d4067b2f6552fc2e009bcad08b" +dependencies = [ + "bytes", + "futures-util", + "http 1.1.0", + "http-body 1.0.1", + "hyper 1.5.0", + "pin-project-lite", + "tokio", + "tower-service", +] + [[package]] name = "iana-time-zone" version = "0.1.60" @@ -1078,7 +1342,7 @@ checksum = "2a071f4f7efc9a9118dfb627a0a94ef247986e1ab8606a4c806ae2b3aa3b6978" dependencies = [ "ahash", "anyhow", - "base64", + "base64 0.21.7", "bytecount", "clap", "fancy-regex", @@ -1112,6 +1376,12 @@ version = "0.2.155" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c" +[[package]] +name = "libm" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8355be11b20d696c8f18f6cc018c4e372165b1fa8126cef092399c9951984ffa" + [[package]] name = "libredox" version = "0.1.3" @@ -1173,6 +1443,12 @@ dependencies = [ "regex-automata 0.1.10", ] +[[package]] +name = "matchit" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e7465ac9959cc2b1404e8e2367b43684a6d13790fe23056cc8c6c5a6b7bcb94" + [[package]] name = "memchr" version = "2.7.4" @@ -1200,6 +1476,15 @@ dependencies = [ "adler", ] +[[package]] +name = "miniz_oxide" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2d80299ef12ff69b16a84bb182e3b9df68b5a91574d3d4fa6e41b65deec4df1" +dependencies = [ + "adler2", +] + [[package]] name = "mio" version = "0.8.11" @@ -1212,6 +1497,23 @@ dependencies = [ "windows-sys 0.48.0", ] +[[package]] +name = "multer" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83e87776546dc87511aa5ee218730c92b666d7264ab6ed41f9d215af9cd5224b" +dependencies = [ + "bytes", + "encoding_rs", + "futures-util", + "http 1.1.0", + "httparse", + "memchr", + "mime", + "spin", + "version_check", +] + [[package]] name = "nom" version = "7.1.3" @@ -1422,6 +1724,15 @@ dependencies = [ "windows-targets 0.52.5", ] +[[package]] +name = "parse-zoneinfo" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f2a05b18d44e2957b88f96ba460715e295bc1d7510468a2f3d3b44535d26c24" +dependencies = [ + "regex", +] + [[package]] name = "paste" version = "1.0.15" @@ -1485,6 +1796,44 @@ dependencies = [ "sha2", ] +[[package]] +name = "phf" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd6780a80ae0c52cc120a26a1a42c1ae51b247a253e4e06113d23d2c2edd078" +dependencies = [ + "phf_shared", +] + +[[package]] +name = "phf_codegen" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aef8048c789fa5e851558d709946d6d79a8ff88c0440c587967f8e94bfb1216a" +dependencies = [ + "phf_generator", + "phf_shared", +] + +[[package]] +name = "phf_generator" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c80231409c20246a13fddb31776fb942c38553c51e871f8cbd687a4cfb5843d" +dependencies = [ + "phf_shared", + "rand", +] + +[[package]] +name = "phf_shared" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67eabc2ef2a60eb7faa00097bd1ffdb5bd28e62bf39990626a582201b7a754e5" +dependencies = [ + "siphasher", +] + [[package]] name = "pin-project-lite" version = "0.2.14" @@ -1503,6 +1852,15 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" +[[package]] +name = "ppv-lite86" +version = "0.2.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04" +dependencies = [ + "zerocopy", +] + [[package]] name = "proc-macro2" version = "1.0.86" @@ -1530,6 +1888,36 @@ dependencies = [ "proc-macro2", ] +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom", +] + [[package]] name = "ratatui" version = "0.26.3" @@ -1641,15 +2029,15 @@ version = "0.11.27" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dd67538700a17451e7cba03ac727fb961abb7607553461627b97de0b89cf4a62" dependencies = [ - "base64", + "base64 0.21.7", "bytes", "encoding_rs", "futures-core", "futures-util", "h2", - "http", - "http-body", - "hyper", + "http 0.2.12", + "http-body 0.4.6", + "hyper 0.14.29", "ipnet", "js-sys", "log", @@ -1660,7 +2048,7 @@ dependencies = [ "serde", "serde_json", "serde_urlencoded", - "sync_wrapper", + "sync_wrapper 0.1.2", "system-configuration", "tokio", "tower-service", @@ -1671,13 +2059,28 @@ dependencies = [ "winreg", ] +[[package]] +name = "ring" +version = "0.17.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c17fa4cb658e3583423e915b9f3acc01cceaee1860e33d59ebae66adc3a2dc0d" +dependencies = [ + "cc", + "cfg-if", + "getrandom", + "libc", + "spin", + "untrusted", + "windows-sys 0.52.0", +] + [[package]] name = "ron" version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b91f7eff05f748767f183df4320a63d6936e9c6107d97c9e6bdd9784f4289c94" dependencies = [ - "base64", + "base64 0.21.7", "bitflags 2.6.0", "serde", "serde_derive", @@ -1689,7 +2092,7 @@ version = "3.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9dcd94370631e5658a0a23635f7f47e43d06a00ad948e0bb5de79b00d85b880c" dependencies = [ - "globwalk", + "globwalk 0.8.1", "once_cell", "regex", "rust-i18n-macro", @@ -1721,7 +2124,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "399801f4d955abf1c3ce3ce2215dc76bd40beb4ae39e3a84936b21a79ce2caa5" dependencies = [ "arc-swap", - "globwalk", + "globwalk 0.8.1", "lazy_static", "normpath", "once_cell", @@ -1750,6 +2153,38 @@ version = "0.1.24" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" +[[package]] +name = "rustls" +version = "0.23.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5065c3f250cbd332cd894be57c40fa52387247659b14a2d6041d121547903b1b" +dependencies = [ + "log", + "once_cell", + "ring", + "rustls-pki-types", + "rustls-webpki", + "subtle", + "zeroize", +] + +[[package]] +name = "rustls-pki-types" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16f1201b3c9a7ee8039bcadc17b7e605e2945b27eee7631788c1bd2b0643674b" + +[[package]] +name = "rustls-webpki" +version = "0.102.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64ca1bc8749bd4cf37b5ce386cc146580777b4e8572c7b97baf22c83f444bee9" +dependencies = [ + "ring", + "rustls-pki-types", + "untrusted", +] + [[package]] name = "rustversion" version = "1.0.17" @@ -1911,6 +2346,12 @@ dependencies = [ "libc", ] +[[package]] +name = "siphasher" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56199f7ddabf13fe5074ce809e7d3f42b42ae711800501b5b16ea82ad029c39d" + [[package]] name = "slab" version = "0.4.9" @@ -1920,6 +2361,16 @@ dependencies = [ "autocfg", ] +[[package]] +name = "slug" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "882a80f72ee45de3cc9a5afeb2da0331d58df69e4e7d8eeb5d3c7784ae67e724" +dependencies = [ + "deunicode", + "wasm-bindgen", +] + [[package]] name = "smallvec" version = "1.13.2" @@ -1936,6 +2387,12 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "spin" +version = "0.9.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" + [[package]] name = "stability" version = "0.2.0" @@ -1999,6 +2456,12 @@ dependencies = [ "syn", ] +[[package]] +name = "subtle" +version = "2.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" + [[package]] name = "syn" version = "2.0.68" @@ -2016,6 +2479,12 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160" +[[package]] +name = "sync_wrapper" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7065abeca94b6a8a577f9bd45aa0867a2238b74e8eb67cf10d492bc39351394" + [[package]] name = "system-configuration" version = "0.5.1" @@ -2037,6 +2506,28 @@ dependencies = [ "libc", ] +[[package]] +name = "tera" +version = "1.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab9d851b45e865f178319da0abdbfe6acbc4328759ff18dafc3a41c16b4cd2ee" +dependencies = [ + "chrono", + "chrono-tz", + "globwalk 0.9.1", + "humansize", + "lazy_static", + "percent-encoding", + "pest", + "pest_derive", + "rand", + "regex", + "serde", + "serde_json", + "slug", + "unic-segment", +] + [[package]] name = "thiserror" version = "1.0.63" @@ -2225,11 +2716,50 @@ dependencies = [ "winnow 0.6.13", ] +[[package]] +name = "tower" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2873938d487c3cfb9aed7546dc9f2711d867c9f90c46b889989a2cb84eba6b4f" +dependencies = [ + "futures-core", + "futures-util", + "pin-project-lite", + "sync_wrapper 0.1.2", + "tokio", + "tower-layer", + "tower-service", + "tracing", +] + +[[package]] +name = "tower-http" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8437150ab6bbc8c5f0f519e3d5ed4aa883a83dd4cdd3d1b21f9482936046cb97" +dependencies = [ + "bitflags 2.6.0", + "bytes", + "http 1.1.0", + "http-body 1.0.1", + "http-body-util", + "pin-project-lite", + "tower-layer", + "tower-service", + "tracing", +] + +[[package]] +name = "tower-layer" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "121c2a6cda46980bb0fcd1647ffaf6cd3fc79a013de288782836f6df9c48780e" + [[package]] name = "tower-service" -version = "0.3.2" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52" +checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" [[package]] name = "tracing" @@ -2237,6 +2767,7 @@ version = "0.1.40" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" dependencies = [ + "log", "pin-project-lite", "tracing-attributes", "tracing-core", @@ -2372,6 +2903,56 @@ version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed646292ffc8188ef8ea4d1e0e0150fb15a5c2e12ad9b8fc191ae7a8a7f3c4b9" +[[package]] +name = "unic-char-property" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8c57a407d9b6fa02b4795eb81c5b6652060a15a7903ea981f3d723e6c0be221" +dependencies = [ + "unic-char-range", +] + +[[package]] +name = "unic-char-range" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0398022d5f700414f6b899e10b8348231abf9173fa93144cbc1a43b9793c1fbc" + +[[package]] +name = "unic-common" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "80d7ff825a6a654ee85a63e80f92f054f904f21e7d12da4e22f9834a4aaa35bc" + +[[package]] +name = "unic-segment" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e4ed5d26be57f84f176157270c112ef57b86debac9cd21daaabbe56db0f88f23" +dependencies = [ + "unic-ucd-segment", +] + +[[package]] +name = "unic-ucd-segment" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2079c122a62205b421f499da10f3ee0f7697f012f55b675e002483c73ea34700" +dependencies = [ + "unic-char-property", + "unic-char-range", + "unic-ucd-version", +] + +[[package]] +name = "unic-ucd-version" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96bd2f2237fe450fcd0a1d2f5f4e91711124f7857ba2e964247776ebeeb7b0c4" +dependencies = [ + "unic-common", +] + [[package]] name = "unicode-bidi" version = "0.3.15" @@ -2415,6 +2996,31 @@ version = "0.1.13" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0336d538f7abc86d282a4189614dfaa90810dfc2c6f6427eaf88e16311dd225d" +[[package]] +name = "untrusted" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" + +[[package]] +name = "ureq" +version = "2.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02d1a66277ed75f640d608235660df48c8e3c19f3b4edb6a263315626cc3c01d" +dependencies = [ + "base64 0.22.1", + "encoding_rs", + "flate2", + "log", + "once_cell", + "rustls", + "rustls-pki-types", + "serde", + "serde_json", + "url", + "webpki-roots", +] + [[package]] name = "url" version = "2.5.2" @@ -2551,6 +3157,15 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "webpki-roots" +version = "0.26.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d642ff16b7e79272ae451b7322067cdc17cadf68c23264be9d94a32319efe7e" +dependencies = [ + "rustls-pki-types", +] + [[package]] name = "winapi" version = "0.3.9" @@ -2773,6 +3388,7 @@ version = "0.7.34" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ae87e3fcd617500e5d106f0380cf7b77f3c6092aae37191433159dda23cfb087" dependencies = [ + "byteorder", "zerocopy-derive", ] @@ -2786,3 +3402,9 @@ dependencies = [ "quote", "syn", ] + +[[package]] +name = "zeroize" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde" diff --git a/Cargo.toml b/Cargo.toml index 3016520..0bc3755 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,9 +4,12 @@ version = "0.1.0" edition = "2021" [dependencies] +codes-iso-3166 = {version="0.1.5", features =["alpha_3_code", "full_name"]} clap = { version = "4", features = ["derive"] } jsonschema = "0.17" tokio = { version = "1", features = ["full"] } +ureq = { version = "*", features = ["json", "charset"] } +base64 = "0.21" serde = { version = "1", features = ["serde_derive", "derive"] } serde_json = "1" anyhow = "1.0" @@ -28,3 +31,6 @@ jsonpath-rust = "0.5" strum = "0.26.2" digital-credential-data-models = { git = "https://github.com/impierce/digital-credential-data-models.git", rev = "9f16c27" } csv = "1.3.0" +axum = { version = "0.7.7", features = ["macros", "multipart"] } +eyre = "0.6.8" +tower-http = { version = "0.6.1", features = ["limit", "trace"] } diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..3040142 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,31 @@ +FROM rust:1.82 AS build + +# 1. create a workdir to start working from +WORKDIR /credential-converter +# 2. Copy our manifests +COPY ./Cargo.lock ./Cargo.lock +COPY ./Cargo.toml ./Cargo.toml + +# # 3. build depedencies for the project +# RUN cargo build --release + +# 4. copy over the origninal source and reference files +COPY ./src ./src +COPY ./json ./json + +# 5. build the project +RUN cargo build --release + + + +# our final base +FROM rust:1.82-slim + +# copy the build artifact from the build stage +COPY --from=build /credential-converter/target/release/credential-converter . +COPY --from=build /credential-converter/json ./json + +# set the startup command to run your binary +CMD ["./credential-converter", "-w", "0.0.0.0:3000"] + +EXPOSE 3000 diff --git a/README.md b/README.md index f8c7ef3..ef2be23 100644 --- a/README.md +++ b/README.md @@ -39,7 +39,7 @@ cargo run -- -h example: ```sh -cargo run -- -i example.json -o example_123.json -m example_mapping.json -c o-bv3-to-elm +cargo run -- -i ./test/OBv3_example.json -o ./test/ELM_export_example.json -m ./json/mapping/custom_mapping_example_OB2ELM.json -c OBv3toELM ``` Or find the executable in the `/target/debug` folder named after the repo name `credential-converter`. @@ -47,12 +47,45 @@ Or find the executable in the `/target/debug` folder named after the repo name ` ./target/debug/credential-converter ``` ```sh -./target/debug/credential-converter -i example.json -o example_123.json -m example_mapping.json -c o-bv3-to-elm +./target/debug/credential-converter -i example.json -o example_123.json -m example_mapping.json -c OBv3toELM ``` +*Warning: the ratatui library does not seem to handle different color settings in your terminal perfectly. This causes the colors to differ slightly between builds in different terminals. For reference please continue reading the readme, colors will be explained accompanied by screenshots.* +## Setup webservice +For headless/webservice execution: -*Warning: the ratatui library does not seem to handle different color settings in your terminal perfectly. This causes the colors to differ slightly between builds in different terminals. For reference please continue reading the readme, colors will be explained accompanied by screenshots.* +Run with -w +The default address and port for the application are 127.0.0.1:3000 but you can also specify the address and port yourself + +```sh +cargo run -- -w +``` +example for running on 192.168.1.1:5000 +```sh +cargo run -- -w 192.168.1.1:5000 +``` + +## Usage of webservice (client-side) +A webpage displaying a form can be found at the root of the project a webservice api can be found at /translate_file +you could use the website to translate the files by surfing to 127.0.0.1:3000/translate_file and providing information in the form presented. + +An other option is POSTING to the page directly in a multipart format: +```curl 127.0.0.1:3000/translate_file -F translation=OBv3ToELM -F input_file=@test/OBv3_example.json``` + +There is also the option to POST direclty in json format: +```curl 127.0.0.1:3000/api -H "Content-Type: application/json" --data @test/encoded_test.json``` + +The data format for this json is: +```json +{ + "From": {"Name": "OB", "Version": "3.0"}, + "To": {"Name": "elm", "Version": "3.2"}, + "Parameters": { "PreferredLanguages": ["en", "sv"]}, + "Content": "Base 64 encoded content in From format" +} + +``` ## Usage @@ -80,7 +113,7 @@ On the bottom you'll find a bar explaining the basic keys as well. `res/output_credential.json`: Example output file for the converted JSON. `res/custom_mapping.json`: Example custom mapping file. -Logs are kept in `logging_folder/credential-converter.log`. This file is overwritten upon each startup of the program. +Logs are kept in `logging_folder/credential-converter.log`. This file is overwritten upon each startup of the program. Use the macro `trace_dbg!()` to add debug messages in the code. To remove the default file paths remove lines 34 - 38 from the `main.rs`: ```sh diff --git a/docker-compose.yaml b/docker-compose.yaml new file mode 100644 index 0000000..0e8860a --- /dev/null +++ b/docker-compose.yaml @@ -0,0 +1,10 @@ +services: + credential-converter: + container_name: credential-converter + image: credential-converter:latest + build: . + ports: + - 3000:3000 + expose: + - 3000 + diff --git a/json/ebsi-elm/validation-schema-ELM3.2/README.md b/json/ebsi-elm/validation-schema-ELM3.2/README.md new file mode 100644 index 0000000..6510d9a --- /dev/null +++ b/json/ebsi-elm/validation-schema-ELM3.2/README.md @@ -0,0 +1,12 @@ +# Schema as proposed to use in the DC4EU project. + +> The schema defines a generic structure for used within EBSI-related Verifiable Credentials according ELM +> This schema is also used to validate DC4EU + +The schema is published to the [Trusted Schemas Registry](https://hub.ebsi.eu/apis/pilot/trusted-schemas-registry) with the IDs: + +- `0xbe77a21356835dc09d3d8149ea832ae0a4bae0ae9c869d18219ef8f4a74b4644` (hexadecimal) + +# validation of the outcomes of the converter can be done by importing this schema into on-line tools like: +[json schema validator](https://www.jsonschemavalidator.net/) + diff --git a/json/ebsi-elm/validation-schema-ELM3.2/schema.json b/json/ebsi-elm/validation-schema-ELM3.2/schema.json new file mode 100644 index 0000000..48e9f54 --- /dev/null +++ b/json/ebsi-elm/validation-schema-ELM3.2/schema.json @@ -0,0 +1,2998 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "title": "Europass EDC credential", + "description": "Schema for EDC credential based on ELM 3.2", + "type": "object", + "allOf": [ + { + "$ref": "https://api-pilot.ebsi.eu/trusted-schemas-registry/v3/schemas/0xbe77a21356835dc09d3d8149ea832ae0a4bae0ae9c869d18219ef8f4a74b4644" + }, + { + "$ref": "#/$defs/EuropeanDigitalCredentialType" + } + ], + "$defs": { + "CredentialSubjectType": { + "$ref": "#/$defs/AgentOrPersonOrOrganisationType" + }, + "IntegerType": { + "type": "integer" + }, + "PositiveIntegerType": { + "type": "integer", + "minimum": 0 + }, + "PercentageIntegerType": { + "type": "integer", + "minimum": 0, + "maximum": 100 + }, + "DecimalType": { + "type": "number" + }, + "BooleanType": { + "type": "boolean" + }, + "IRIType": { + "type": "string" + }, + "URIType": { + "type": "string", + "format": "uri" + }, + "Many!HTMLType": { + "anyOf": [ + { + "$ref": "#/$defs/HTMLType" + }, + { + "type": "array", + "items": { + "$ref": "#/$defs/HTMLType" + } + } + ] + }, + "HTMLType": { + "type": "string" + }, + "DateTimeType": { + "type": "string", + "format": "date-time" + }, + "EmailType": { + "type": "string", + "anyOf": [ + { + "format": "email" + }, + { + "format": "uri", + "pattern": "^mailto:[^@]*[^\\.]@[^\\.]($|[^@]*[^\\.]$)" + } + ] + }, + "DurationType": { + "type": "string", + "format": "duration" + }, + "Many!PeriodOfTimeType": { + "anyOf": [ + { + "$ref": "#/$defs/PeriodOfTimeType" + }, + { + "type": "array", + "items": { + "$ref": "#/$defs/PeriodOfTimeType" + } + } + ] + }, + "PeriodOfTimeType": { + "type": "object", + "additionalProperties": false, + "properties": { + "id": { + "$ref": "#/$defs/GenericIdType" + }, + "type": { + "const": "PeriodOfTime" + }, + "startDate": { + "$ref": "#/$defs/DateTimeType" + }, + "endDate": { + "$ref": "#/$defs/DateTimeType" + }, + "prefLabel": { + "$ref": "#/$defs/Many!LangStringType" + } + }, + "required": [] + }, + "Many!StringType": { + "anyOf": [ + { + "$ref": "#/$defs/StringType" + }, + { + "type": "array", + "items": { + "$ref": "#/$defs/StringType" + } + } + ] + }, + "StringType": { + "type": "string" + }, + "GenericIdType": { + "$ref": "#/$defs/URIType" + }, + "LiteralType": { + "$ref": "#/$defs/StringType" + }, + "Many!AgentType": { + "anyOf": [ + { + "$ref": "#/$defs/AgentType" + }, + { + "type": "array", + "items": { + "$ref": "#/$defs/AgentType" + } + } + ] + }, + "AgentType": { + "type": "object", + "additionalProperties": false, + "properties": { + "id": { + "$ref": "#/$defs/GenericIdType" + }, + "type": { + "const": "Agent" + }, + "identifier": { + "$ref": "#/$defs/Many!IdentifierOrLegalIdentifierType" + }, + "altLabel": { + "$ref": "#/$defs/Many!LangStringType" + }, + "prefLabel": { + "$ref": "#/$defs/Many!LangStringType" + }, + "location": { + "$ref": "#/$defs/Many!LocationType" + }, + "contactPoint": { + "$ref": "#/$defs/Many!ContactPointType" + }, + "additionalNote": { + "$ref": "#/$defs/Many!NoteType" + }, + "groupMemberOf": { + "$ref": "#/$defs/Many!GroupType" + }, + "dateModified": { + "$ref": "#/$defs/DateTimeType" + } + }, + "required": [] + }, + "Many!PersonType": { + "anyOf": [ + { + "$ref": "#/$defs/PersonType" + }, + { + "type": "array", + "items": { + "$ref": "#/$defs/PersonType" + } + } + ] + }, + "PersonType": { + "type": "object", + "additionalProperties": false, + "properties": { + "id": { + "$ref": "#/$defs/GenericIdType" + }, + "type": { + "const": "Person" + }, + "identifier": { + "$ref": "#/$defs/Many!IdentifierOrLegalIdentifierType" + }, + "location": { + "$ref": "#/$defs/LocationType" + }, + "nationalID": { + "$ref": "#/$defs/LegalIdentifierType" + }, + "fullName": { + "$ref": "#/$defs/LangStringType" + }, + "givenName": { + "$ref": "#/$defs/LangStringType" + }, + "familyName": { + "$ref": "#/$defs/LangStringType" + }, + "birthName": { + "$ref": "#/$defs/Many!LangStringType" + }, + "patronymicName": { + "$ref": "#/$defs/Many!LangStringType" + }, + "memberOf": { + "$ref": "#/$defs/Many!OrganisationType" + }, + "dateOfBirth": { + "$ref": "#/$defs/DateTimeType" + }, + "placeOfBirth": { + "$ref": "#/$defs/LocationType" + }, + "citizenshipCountry": { + "$ref": "#/$defs/Many!ConceptType" + }, + "gender": { + "$ref": "#/$defs/ConceptType" + }, + "contactPoint": { + "$ref": "#/$defs/Many!ContactPointType" + }, + "groupMemberOf": { + "$ref": "#/$defs/Many!GroupType" + }, + "dateModified": { + "$ref": "#/$defs/DateTimeType" + }, + "hasCredential": { + "$ref": "#/$defs/Many!EuropeanDigitalCredentialType" + }, + "hasClaim": { + "$ref": "#/$defs/Many!ClaimNodeType" + } + }, + "required": [] + }, + "Many!EuropeanDigitalCredentialType": { + "anyOf": [ + { + "$ref": "#/$defs/EuropeanDigitalCredentialType" + }, + { + "type": "array", + "items": { + "$ref": "#/$defs/EuropeanDigitalCredentialType" + } + } + ] + }, + "Many!ClaimNodeType": { + "anyOf": [ + { + "$ref": "#/$defs/ClaimNodeType" + }, + { + "type": "array", + "items": { + "$ref": "#/$defs/ClaimNodeType" + } + } + ] + }, + "ClaimNodeType": { + "anyOf": [ + { + "$ref": "#/$defs/LearningAchievementType" + }, + { + "$ref": "#/$defs/LearningActivityType" + }, + { + "$ref": "#/$defs/LearningAssessmentType" + }, + { + "$ref": "#/$defs/LearningEntitlementType" + }, + { + "$ref": "#/$defs/ClaimTypeNodeType" + } + ] + }, + "Many!OrganisationType": { + "anyOf": [ + { + "$ref": "#/$defs/OrganisationType" + }, + { + "type": "array", + "items": { + "$ref": "#/$defs/OrganisationType" + } + } + ] + }, + "OrganisationType": { + "type": "object", + "additionalProperties": false, + "properties": { + "id": { + "$ref": "#/$defs/GenericIdType" + }, + "type": { + "const": "Organisation" + }, + "dcType": { + "$ref": "#/$defs/Many!ConceptType" + }, + "identifier": { + "$ref": "#/$defs/Many!IdentifierOrLegalIdentifierType" + }, + "altLabel": { + "$ref": "#/$defs/Many!LangStringType" + }, + "homepage": { + "$ref": "#/$defs/Many!WebResourceType" + }, + "additionalNote": { + "$ref": "#/$defs/Many!NoteType" + }, + "location": { + "$ref": "#/$defs/Many!LocationType" + }, + "accreditation": { + "$ref": "#/$defs/Many!AccreditationType" + }, + "eIDASIdentifier": { + "$ref": "#/$defs/LegalIdentifierType" + }, + "registration": { + "$ref": "#/$defs/LegalIdentifierType" + }, + "legalName": { + "$ref": "#/$defs/Many!LangStringType" + }, + "vatIdentifier": { + "$ref": "#/$defs/Many!LegalIdentifierType" + }, + "taxIdentifier": { + "$ref": "#/$defs/Many!LegalIdentifierType" + }, + "logo": { + "$ref": "#/$defs/MediaObjectType" + }, + "hasSubOrganization": { + "$ref": "#/$defs/Many!OrganisationType" + }, + "subOrganizationOf": { + "$ref": "#/$defs/OrganisationType" + }, + "hasMember": { + "$ref": "#/$defs/Many!PersonType" + }, + "groupMemberOf": { + "$ref": "#/$defs/Many!GroupType" + }, + "contactPoint": { + "$ref": "#/$defs/Many!ContactPointType" + }, + "dateModified": { + "$ref": "#/$defs/DateTimeType" + } + }, + "required": ["legalName", "location"] + }, + "MediaObjectType": { + "type": "object", + "additionalProperties": false, + "properties": { + "id": { + "$ref": "#/$defs/GenericIdType" + }, + "type": { + "const": "MediaObject" + }, + "title": { + "$ref": "#/$defs/Many!LangStringType" + }, + "description": { + "$ref": "#/$defs/Many!LangStringType" + }, + "contentType": { + "$ref": "#/$defs/ConceptType" + }, + "attachmentType": { + "$ref": "#/$defs/ConceptType" + }, + "contentEncoding": { + "$ref": "#/$defs/ConceptType" + }, + "contentSize": { + "$ref": "#/$defs/IntegerType" + }, + "content": { + "$ref": "#/$defs/StringType" + }, + "contentURL": { + "$ref": "#/$defs/URIType" + } + }, + "required": ["contentType", "contentEncoding", "content"] + }, + "Many!AccreditationType": { + "anyOf": [ + { + "$ref": "#/$defs/AccreditationType" + }, + { + "type": "array", + "items": { + "$ref": "#/$defs/AccreditationType" + } + } + ] + }, + "Many!IssuerNodeType": { + "anyOf": [ + { + "$ref": "#/$defs/IssuerNodeType" + }, + { + "type": "array", + "items": { + "$ref": "#/$defs/IssuerNodeType" + } + } + ] + }, + "IssuerNodeType": { + "type": "object", + "additionalProperties": false, + "properties": { + "id": { + "$ref": "#/$defs/GenericIdType" + }, + "type": { + "const": "IssuerNode" + }, + "eidasLegalIdentifier": { + "$ref": "#/$defs/LegalIdentifierType" + } + }, + "required": ["eidasLegalIdentifier"] + }, + "AccreditationType": { + "type": "object", + "additionalProperties": false, + "properties": { + "id": { + "$ref": "#/$defs/GenericIdType" + }, + "type": { + "const": "Accreditation" + }, + "dcType": { + "$ref": "#/$defs/ConceptType" + }, + "identifier": { + "$ref": "#/$defs/IdentifierOrLegalIdentifierType" + }, + "title": { + "$ref": "#/$defs/Many!LangStringType" + }, + "description": { + "$ref": "#/$defs/Many!LangStringType" + }, + "homepage": { + "$ref": "#/$defs/Many!WebResourceType" + }, + "dateIssued": { + "$ref": "#/$defs/DateTimeType" + }, + "additionalNote": { + "$ref": "#/$defs/Many!NoteType" + }, + "supplementaryDocument": { + "$ref": "#/$defs/Many!WebResourceType" + }, + "decision": { + "$ref": "#/$defs/ConceptType" + }, + "report": { + "$ref": "#/$defs/WebResourceType" + }, + "organisation": { + "$ref": "#/$defs/Many!OrganisationType" + }, + "limitQualification": { + "$ref": "#/$defs/QualificationType" + }, + "limitField": { + "$ref": "#/$defs/Many!ConceptType" + }, + "limitEQFLevel": { + "$ref": "#/$defs/Many!ConceptType" + }, + "limitJurisdiction": { + "$ref": "#/$defs/Many!ConceptType" + }, + "limitCredentialType": { + "$ref": "#/$defs/Many!ConceptType" + }, + "accreditingAgent": { + "$ref": "#/$defs/OrganisationType" + }, + "reviewDate": { + "$ref": "#/$defs/DateTimeType" + }, + "expiryDate": { + "$ref": "#/$defs/DateTimeType" + }, + "landingPage": { + "$ref": "#/$defs/Many!WebResourceType" + }, + "status": { + "$ref": "#/$defs/StringType" + }, + "dateModified": { + "$ref": "#/$defs/DateTimeType" + } + }, + "required": ["title", "accreditingAgent", "dcType"] + }, + "Many!QualificationType": { + "anyOf": [ + { + "$ref": "#/$defs/QualificationType" + }, + { + "type": "array", + "items": { + "$ref": "#/$defs/QualificationType" + } + } + ] + }, + "QualificationType": { + "type": "object", + "additionalProperties": false, + "properties": { + "id": { + "$ref": "#/$defs/GenericIdType" + }, + "type": { + "const": "Qualification" + }, + "dcType": { + "$ref": "#/$defs/Many!ConceptType" + }, + "identifier": { + "$ref": "#/$defs/IdentifierOrLegalIdentifierType" + }, + "title": { + "$ref": "#/$defs/Many!LangStringType" + }, + "description": { + "$ref": "#/$defs/Many!LangStringType" + }, + "additionalNote": { + "$ref": "#/$defs/Many!NoteType" + }, + "supplementaryDocument": { + "$ref": "#/$defs/Many!WebResourceType" + }, + "homepage": { + "$ref": "#/$defs/Many!WebResourceType" + }, + "altLabel": { + "$ref": "#/$defs/Many!LangStringType" + }, + "category": { + "$ref": "#/$defs/Many!LangStringType" + }, + "dateModified": { + "$ref": "#/$defs/DateTimeType" + }, + "language": { + "$ref": "#/$defs/Many!ConceptType" + }, + "volumeOfLearning": { + "$ref": "#/$defs/DurationType" + }, + "mode": { + "$ref": "#/$defs/Many!ConceptType" + }, + "learningOutcomeSummary": { + "$ref": "#/$defs/NoteType" + }, + "thematicArea": { + "$ref": "#/$defs/Many!ConceptType" + }, + "educationSubject": { + "$ref": "#/$defs/Many!ConceptType" + }, + "creditPoint": { + "$ref": "#/$defs/Many!CreditPointType" + }, + "educationLevel": { + "$ref": "#/$defs/Many!ConceptType" + }, + "learningSetting": { + "$ref": "#/$defs/ConceptType" + }, + "maximumDuration": { + "$ref": "#/$defs/DurationType" + }, + "targetGroup": { + "$ref": "#/$defs/Many!ConceptType" + }, + "entryRequirement": { + "$ref": "#/$defs/NoteType" + }, + "learningOutcome": { + "$ref": "#/$defs/Many!LearningOutcomeType" + }, + "influencedBy": { + "$ref": "#/$defs/Many!LearningActivitySpecificationType" + }, + "provenBy": { + "$ref": "#/$defs/Many!LearningAssessmentSpecificationType" + }, + "entitlesTo": { + "$ref": "#/$defs/Many!LearningEntitlementSpecificationType" + }, + "awardingOpportunity": { + "$ref": "#/$defs/Many!AwardingOpportunityType" + }, + "hasPart": { + "$ref": "#/$defs/Many!QualificationType" + }, + "isPartOf": { + "$ref": "#/$defs/Many!QualificationType" + }, + "specialisationOf": { + "$ref": "#/$defs/Many!QualificationType" + }, + "generalisationOf": { + "$ref": "#/$defs/Many!QualificationType" + }, + "isPartialQualification": { + "$ref": "#/$defs/BooleanType" + }, + "eqfLevel": { + "$ref": "#/$defs/ConceptType" + }, + "nqfLevel": { + "$ref": "#/$defs/Many!ConceptType" + }, + "accreditation": { + "$ref": "#/$defs/Many!AccreditationType" + }, + "qualificationCode": { + "$ref": "#/$defs/Many!ConceptType" + }, + "status": { + "$ref": "#/$defs/StringType" + } + }, + "required": ["title"] + }, + "Many!LearningOutcomeType": { + "anyOf": [ + { + "$ref": "#/$defs/LearningOutcomeType" + }, + { + "type": "array", + "items": { + "$ref": "#/$defs/LearningOutcomeType" + } + } + ] + }, + "LearningOutcomeType": { + "type": "object", + "additionalProperties": false, + "properties": { + "id": { + "$ref": "#/$defs/GenericIdType" + }, + "type": { + "const": "LearningOutcome" + }, + "dcType": { + "$ref": "#/$defs/ConceptType" + }, + "identifier": { + "$ref": "#/$defs/IdentifierOrLegalIdentifierType" + }, + "title": { + "$ref": "#/$defs/Many!LangStringType" + }, + "additionalNote": { + "$ref": "#/$defs/Many!NoteType" + }, + "reusabilityLevel": { + "$ref": "#/$defs/ConceptType" + }, + "relatedSkill": { + "$ref": "#/$defs/Many!ConceptType" + }, + "relatedESCOSkill": { + "$ref": "#/$defs/Many!ConceptType" + } + }, + "required": ["title"] + }, + "Many!ContactPointType": { + "anyOf": [ + { + "$ref": "#/$defs/ContactPointType" + }, + { + "type": "array", + "items": { + "$ref": "#/$defs/ContactPointType" + } + } + ] + }, + "ContactPointType": { + "type": "object", + "additionalProperties": false, + "properties": { + "id": { + "$ref": "#/$defs/GenericIdType" + }, + "type": { + "const": "ContactPoint" + }, + "additionalNote": { + "$ref": "#/$defs/Many!NoteType" + }, + "description": { + "$ref": "#/$defs/Many!LangStringType" + }, + "address": { + "$ref": "#/$defs/Many!AddressType" + }, + "phone": { + "$ref": "#/$defs/Many!PhoneType" + }, + "emailAddress": { + "$ref": "#/$defs/Many!MailboxType" + }, + "contactForm": { + "$ref": "#/$defs/Many!WebResourceType" + } + }, + "required": [] + }, + "Many!NoteType": { + "anyOf": [ + { + "$ref": "#/$defs/NoteType" + }, + { + "type": "array", + "items": { + "$ref": "#/$defs/NoteType" + } + } + ] + }, + "NoteType": { + "type": "object", + "additionalProperties": false, + "properties": { + "id": { + "$ref": "#/$defs/GenericIdType" + }, + "type": { + "const": "Note" + }, + "noteLiteral": { + "$ref": "#/$defs/Many!LangStringType" + }, + "subject": { + "$ref": "#/$defs/ConceptType" + }, + "noteFormat": { + "$ref": "#/$defs/ConceptType" + } + }, + "required": ["noteLiteral"] + }, + "Many!AddressType": { + "anyOf": [ + { + "$ref": "#/$defs/AddressType" + }, + { + "type": "array", + "items": { + "$ref": "#/$defs/AddressType" + } + } + ] + }, + "AddressType": { + "type": "object", + "additionalProperties": false, + "properties": { + "id": { + "$ref": "#/$defs/GenericIdType" + }, + "type": { + "const": "Address" + }, + "identifier": { + "$ref": "#/$defs/IdentifierOrLegalIdentifierType" + }, + "fullAddress": { + "$ref": "#/$defs/NoteType" + }, + "countryCode": { + "$ref": "#/$defs/ConceptType" + } + }, + "required": ["countryCode"] + }, + "Many!PhoneType": { + "anyOf": [ + { + "$ref": "#/$defs/PhoneType" + }, + { + "type": "array", + "items": { + "$ref": "#/$defs/PhoneType" + } + } + ] + }, + "PhoneType": { + "type": "object", + "additionalProperties": false, + "properties": { + "id": { + "$ref": "#/$defs/GenericIdType" + }, + "type": { + "const": "Phone" + }, + "phoneNumber": { + "$ref": "#/$defs/StringType" + }, + "countryDialing": { + "$ref": "#/$defs/StringType" + }, + "areaDialing": { + "$ref": "#/$defs/StringType" + }, + "dialNumber": { + "$ref": "#/$defs/StringType" + } + }, + "required": [] + }, + "Many!MailboxType": { + "anyOf": [ + { + "$ref": "#/$defs/MailboxType" + }, + { + "type": "array", + "items": { + "$ref": "#/$defs/MailboxType" + } + } + ] + }, + "MailboxType": { + "type": "object", + "additionalProperties": false, + "properties": { + "id": { + "$ref": "#/$defs/EmailType" + }, + "type": { + "const": "Mailbox" + } + }, + "required": [] + }, + "Many!WebResourceType": { + "anyOf": [ + { + "$ref": "#/$defs/WebResourceType" + }, + { + "type": "array", + "items": { + "$ref": "#/$defs/WebResourceType" + } + } + ] + }, + "WebResourceType": { + "type": "object", + "additionalProperties": false, + "properties": { + "id": { + "$ref": "#/$defs/GenericIdType" + }, + "type": { + "const": "WebResource" + }, + "title": { + "$ref": "#/$defs/Many!LangStringType" + }, + "language": { + "$ref": "#/$defs/ConceptType" + }, + "contentURL": { + "$ref": "#/$defs/URIType" + } + }, + "required": ["contentURL"] + }, + "Many!ConceptType": { + "anyOf": [ + { + "$ref": "#/$defs/ConceptType" + }, + { + "type": "array", + "items": { + "$ref": "#/$defs/ConceptType" + } + } + ] + }, + "Single!ConceptType": { + "anyOf": [ + { + "$ref": "#/$defs/ConceptType" + }, + { + "type": "array", + "items": { + "$ref": "#/$defs/ConceptType" + }, + "minItems": 1, + "maxItems": 1 + } + ] + }, + "ConceptType": { + "type": "object", + "additionalProperties": false, + "properties": { + "id": { + "$ref": "#/$defs/GenericIdType" + }, + "type": { + "const": "Concept" + }, + "prefLabel": { + "$ref": "#/$defs/Many!LangStringType" + }, + "notation": { + "$ref": "#/$defs/LiteralType" + }, + "inScheme": { + "$ref": "#/$defs/ConceptSchemeType" + }, + "definition": { + "$ref": "#/$defs/Many!LangStringType" + } + }, + "required": [] + }, + "ConceptSchemeType": { + "type": "object", + "additionalProperties": false, + "properties": { + "id": { + "$ref": "#/$defs/GenericIdType" + }, + "type": { + "const": "ConceptScheme" + } + }, + "required": [] + }, + "Many!LocationType": { + "anyOf": [ + { + "$ref": "#/$defs/LocationType" + }, + { + "type": "array", + "items": { + "$ref": "#/$defs/LocationType" + } + } + ] + }, + "LocationType": { + "type": "object", + "additionalProperties": false, + "properties": { + "id": { + "$ref": "#/$defs/GenericIdType" + }, + "type": { + "const": "Location" + }, + "identifier": { + "$ref": "#/$defs/IdentifierOrLegalIdentifierType" + }, + "description": { + "$ref": "#/$defs/Many!LangStringType" + }, + "address": { + "$ref": "#/$defs/Many!AddressType" + }, + "geographicName": { + "$ref": "#/$defs/Many!AddressType" + }, + "spatialCode": { + "$ref": "#/$defs/Many!ConceptType" + }, + "geometry": { + "$ref": "#/$defs/Many!GeometryType" + } + }, + "required": ["address"] + }, + "Many!GeometryType": { + "anyOf": [ + { + "$ref": "#/$defs/GeometryType" + }, + { + "type": "array", + "items": { + "$ref": "#/$defs/GeometryType" + } + } + ] + }, + "GeometryType": { + "type": "object", + "additionalProperties": false, + "properties": { + "id": { + "$ref": "#/$defs/GenericIdType" + }, + "type": { + "const": "Geometry" + }, + "longitude": { + "$ref": "#/$defs/StringType" + }, + "latitude": { + "$ref": "#/$defs/StringType" + } + }, + "required": [] + }, + "Many!GroupType": { + "anyOf": [ + { + "$ref": "#/$defs/GroupType" + }, + { + "type": "array", + "items": { + "$ref": "#/$defs/GroupType" + } + } + ] + }, + "GroupType": { + "type": "object", + "additionalProperties": false, + "properties": { + "id": { + "$ref": "#/$defs/GenericIdType" + }, + "type": { + "const": "Group" + }, + "prefLabel": { + "$ref": "#/$defs/Many!LangStringType" + }, + "altLabel": { + "$ref": "#/$defs/Many!LangStringType" + }, + "additionalNote": { + "$ref": "#/$defs/Many!NoteType" + }, + "location": { + "$ref": "#/$defs/Many!LocationType" + }, + "contactPoint": { + "$ref": "#/$defs/Many!ContactPointType" + }, + "member": { + "$ref": "#/$defs/Many!AgentOrPersonOrOrganisationType" + } + }, + "required": ["prefLabel"] + }, + "Many!AgentOrPersonOrOrganisationType": { + "anyOf": [ + { + "$ref": "#/$defs/AgentOrPersonOrOrganisationType" + }, + { + "type": "array", + "items": { + "$ref": "#/$defs/AgentOrPersonOrOrganisationType" + } + } + ] + }, + "AgentOrPersonOrOrganisationType": { + "anyOf": [ + { + "$ref": "#/$defs/AgentType" + }, + { + "$ref": "#/$defs/PersonType" + }, + { + "$ref": "#/$defs/OrganisationType" + } + ] + }, + "LearningAchievementSpecificationOrSpecificationType": { + "anyOf": [ + { + "$ref": "#/$defs/LearningAchievementSpecificationType" + }, + { + "$ref": "#/$defs/QualificationType" + } + ] + }, + "IdentifierOrLegalIdentifierType": { + "anyOf": [ + { + "$ref": "#/$defs/IdentifierType" + }, + { + "$ref": "#/$defs/LegalIdentifierType" + } + ] + }, + "Many!IdentifierType": { + "anyOf": [ + { + "$ref": "#/$defs/IdentifierType" + }, + { + "type": "array", + "items": { + "$ref": "#/$defs/IdentifierType" + } + } + ] + }, + "IdentifierType": { + "type": "object", + "additionalProperties": false, + "properties": { + "id": { + "$ref": "#/$defs/GenericIdType" + }, + "type": { + "const": "Identifier" + }, + "dcType": { + "$ref": "#/$defs/Many!ConceptType" + }, + "notation": { + "$ref": "#/$defs/LiteralType" + }, + "schemeAgency": { + "$ref": "#/$defs/LangStringType" + }, + "creator": { + "$ref": "#/$defs/IRIType" + }, + "dateIssued": { + "$ref": "#/$defs/DateTimeType" + }, + "schemeName": { + "$ref": "#/$defs/StringType" + }, + "schemeVersion": { + "$ref": "#/$defs/StringType" + }, + "schemeId": { + "$ref": "#/$defs/URIType" + } + }, + "required": ["notation"] + }, + "Many!LegalIdentifierType": { + "anyOf": [ + { + "$ref": "#/$defs/LegalIdentifierType" + }, + { + "type": "array", + "items": { + "$ref": "#/$defs/LegalIdentifierType" + } + } + ] + }, + "LegalIdentifierType": { + "type": "object", + "additionalProperties": false, + "properties": { + "id": { + "$ref": "#/$defs/GenericIdType" + }, + "type": { + "const": "LegalIdentifier" + }, + "dcType": { + "$ref": "#/$defs/Many!ConceptType" + }, + "notation": { + "$ref": "#/$defs/LiteralType" + }, + "schemeAgency": { + "$ref": "#/$defs/LangStringType" + }, + "creator": { + "$ref": "#/$defs/IRIType" + }, + "dateIssued": { + "$ref": "#/$defs/DateTimeType" + }, + "schemeName": { + "$ref": "#/$defs/StringType" + }, + "schemeVersion": { + "$ref": "#/$defs/StringType" + }, + "schemeId": { + "$ref": "#/$defs/URIType" + }, + "spatial": { + "$ref": "#/$defs/ConceptType" + } + }, + "required": ["notation", "spatial"] + }, + "Many!CreditPointType": { + "anyOf": [ + { + "$ref": "#/$defs/CreditPointType" + }, + { + "type": "array", + "items": { + "$ref": "#/$defs/CreditPointType" + } + } + ] + }, + "CreditPointType": { + "type": "object", + "additionalProperties": false, + "properties": { + "id": { + "$ref": "#/$defs/GenericIdType" + }, + "type": { + "const": "CreditPoint" + }, + "framework": { + "$ref": "#/$defs/ConceptType" + }, + "point": { + "$ref": "#/$defs/StringType" + } + }, + "required": ["framework", "point"] + }, + "AmountType": { + "type": "object", + "additionalProperties": false, + "properties": { + "id": { + "$ref": "#/$defs/GenericIdType" + }, + "type": { + "const": "Amount" + }, + "unit": { + "$ref": "#/$defs/ConceptType" + }, + "value": { + "$ref": "#/$defs/DecimalType" + } + }, + "required": ["unit", "value"] + }, + "Many!LangStringType": { + "type": "object", + "propertyNames": { + "pattern": "^(aa|ab|ae|af|ak|am|an|ar|as|av|ay|az|ba|be|bg|bh|bi|bm|bn|bo|br|bs|ca|ce|ch|co|cr|cs|cu|cv|cy|da|de|dv|dz|ee|el|en|eo|es|et|eu|fa|ff|fi|fj|fo|fr|fy|ga|gd|gl|gn|gu|gv|ha|he|hi|ho|hr|ht|hu|hy|hz|ia|id|ie|ig|ii|ik|in|io|is|it|iu|iw|ja|ji|jv|jw|ka|kg|ki|kj|kk|kl|km|kn|ko|kr|ks|ku|kv|kw|ky|la|lb|lg|li|ln|lo|lt|lu|lv|mg|mh|mi|mk|ml|mn|mo|mr|ms|mt|my|na|nb|nd|ne|ng|nl|nn|no|nr|nv|ny|oc|oj|om|or|os|pa|pi|pl|ps|pt|qu|rm|rn|ro|ru|rw|sa|sc|sd|se|sg|sh|si|sk|sl|sm|sn|so|sq|sr|ss|st|su|sv|sw|ta|te|tg|th|ti|tk|tl|tn|to|tr|ts|tt|tw|ty|ug|uk|ur|uz|ve|vi|vo|wa|wo|xh|yi|yo|za|zh|zu)$" + }, + "minProperties": 1 + }, + "LangStringType": { + "allOf": [ + { + "$ref": "#/$defs/Many!LangStringType" + }, + { + "type": "object", + "maxProperties": 1 + } + ] + }, + "Many!LearningAchievementType": { + "anyOf": [ + { + "$ref": "#/$defs/LearningAchievementType" + }, + { + "type": "array", + "items": { + "$ref": "#/$defs/LearningAchievementType" + } + } + ] + }, + "LearningAchievementType": { + "type": "object", + "additionalProperties": false, + "properties": { + "id": { + "$ref": "#/$defs/GenericIdType" + }, + "type": { + "const": "LearningAchievement" + }, + "dcType": { + "$ref": "#/$defs/Many!ConceptType" + }, + "title": { + "$ref": "#/$defs/Many!LangStringType" + }, + "description": { + "$ref": "#/$defs/Many!LangStringType" + }, + "identifier": { + "$ref": "#/$defs/IdentifierOrLegalIdentifierType" + }, + "additionalNote": { + "$ref": "#/$defs/Many!NoteType" + }, + "supplementaryDocument": { + "$ref": "#/$defs/Many!WebResourceType" + }, + "learningOpportunity": { + "$ref": "#/$defs/LearningOpportunityType" + }, + "creditReceived": { + "$ref": "#/$defs/Many!CreditPointType" + }, + "provenBy": { + "$ref": "#/$defs/Many!LearningAssessmentType" + }, + "influencedBy": { + "$ref": "#/$defs/Many!LearningActivityType" + }, + "awardedBy": { + "$ref": "#/$defs/AwardingProcessType" + }, + "entitlesTo": { + "$ref": "#/$defs/Many!LearningEntitlementType" + }, + "specifiedBy": { + "$ref": "#/$defs/LearningAchievementSpecificationOrQualificationType" + }, + "hasPart": { + "$ref": "#/$defs/Many!LearningAchievementType" + }, + "isPartOf": { + "$ref": "#/$defs/Many!LearningAchievementType" + } + }, + "required": ["title", "awardedBy"] + }, + "Many!LearningAchievementSpecificationType": { + "anyOf": [ + { + "$ref": "#/$defs/LearningAchievementSpecificationType" + }, + { + "type": "array", + "items": { + "$ref": "#/$defs/LearningAchievementSpecificationType" + } + } + ] + }, + "LearningAchievementSpecificationType": { + "type": "object", + "additionalProperties": false, + "properties": { + "id": { + "$ref": "#/$defs/GenericIdType" + }, + "type": { + "const": "LearningAchievementSpecification" + }, + "dcType": { + "$ref": "#/$defs/Many!ConceptType" + }, + "identifier": { + "$ref": "#/$defs/IdentifierOrLegalIdentifierType" + }, + "title": { + "$ref": "#/$defs/Many!LangStringType" + }, + "description": { + "$ref": "#/$defs/Many!LangStringType" + }, + "additionalNote": { + "$ref": "#/$defs/Many!NoteType" + }, + "supplementaryDocument": { + "$ref": "#/$defs/Many!WebResourceType" + }, + "homepage": { + "$ref": "#/$defs/Many!WebResourceType" + }, + "altLabel": { + "$ref": "#/$defs/Many!LangStringType" + }, + "category": { + "$ref": "#/$defs/Many!LangStringType" + }, + "dateModified": { + "$ref": "#/$defs/DateTimeType" + }, + "language": { + "$ref": "#/$defs/Many!ConceptType" + }, + "volumeOfLearning": { + "$ref": "#/$defs/DurationType" + }, + "mode": { + "$ref": "#/$defs/Many!ConceptType" + }, + "learningOutcomeSummary": { + "$ref": "#/$defs/NoteType" + }, + "thematicArea": { + "$ref": "#/$defs/Many!ConceptType" + }, + "educationSubject": { + "$ref": "#/$defs/Many!ConceptType" + }, + "creditPoint": { + "$ref": "#/$defs/Many!CreditPointType" + }, + "educationLevel": { + "$ref": "#/$defs/Many!ConceptType" + }, + "learningSetting": { + "$ref": "#/$defs/ConceptType" + }, + "maximumDuration": { + "$ref": "#/$defs/DurationType" + }, + "targetGroup": { + "$ref": "#/$defs/Many!ConceptType" + }, + "entryRequirement": { + "$ref": "#/$defs/NoteType" + }, + "learningOutcome": { + "$ref": "#/$defs/Many!LearningOutcomeType" + }, + "influencedBy": { + "$ref": "#/$defs/Many!LearningActivitySpecificationType" + }, + "provenBy": { + "$ref": "#/$defs/Many!LearningAssessmentSpecificationType" + }, + "entitlesTo": { + "$ref": "#/$defs/Many!LearningEntitlementSpecificationType" + }, + "awardingOpportunity": { + "$ref": "#/$defs/Many!AwardingOpportunityType" + }, + "hasPart": { + "$ref": "#/$defs/Many!LearningAchievementSpecificationOrQualificationType" + }, + "isPartOf": { + "$ref": "#/$defs/Many!LearningAchievementSpecificationOrQualificationType" + }, + "specialisationOf": { + "$ref": "#/$defs/Many!LearningAchievementSpecificationOrQualificationType" + }, + "generalisationOf": { + "$ref": "#/$defs/Many!LearningAchievementSpecificationOrQualificationType" + }, + "status": { + "$ref": "#/$defs/StringType" + } + }, + "required": ["title"] + }, + "Many!LearningActivityType": { + "anyOf": [ + { + "$ref": "#/$defs/LearningActivityType" + }, + { + "type": "array", + "items": { + "$ref": "#/$defs/LearningActivityType" + } + } + ] + }, + "LearningActivityType": { + "type": "object", + "additionalProperties": false, + "properties": { + "id": { + "$ref": "#/$defs/GenericIdType" + }, + "type": { + "const": "LearningActivity" + }, + "dcType": { + "$ref": "#/$defs/Many!ConceptType" + }, + "title": { + "$ref": "#/$defs/Many!LangStringType" + }, + "description": { + "$ref": "#/$defs/Many!LangStringType" + }, + "identifier": { + "$ref": "#/$defs/Many!IdentifierOrLegalIdentifierType" + }, + "additionalNote": { + "$ref": "#/$defs/Many!NoteType" + }, + "supplementaryDocument": { + "$ref": "#/$defs/Many!WebResourceType" + }, + "temporal": { + "$ref": "#/$defs/Many!PeriodOfTimeType" + }, + "location": { + "$ref": "#/$defs/Many!LocationType" + }, + "learningOpportunity": { + "$ref": "#/$defs/LearningOpportunityType" + }, + "workload": { + "$ref": "#/$defs/DurationType" + }, + "directedBy": { + "$ref": "#/$defs/Many!AgentOrPersonOrOrganisationType" + }, + "awardedBy": { + "$ref": "#/$defs/AwardingProcessType" + }, + "influences": { + "$ref": "#/$defs/Many!LearningAchievementType" + }, + "specifiedBy": { + "$ref": "#/$defs/LearningActivitySpecificationType" + }, + "hasPart": { + "$ref": "#/$defs/Many!LearningActivityType" + }, + "isPartOf": { + "$ref": "#/$defs/Many!LearningActivityType" + }, + "levelOfCompletion": { + "$ref": "#/$defs/PercentageIntegerType" + } + }, + "required": ["title", "awardedBy"] + }, + "Many!LearningActivitySpecificationType": { + "anyOf": [ + { + "$ref": "#/$defs/LearningActivitySpecificationType" + }, + { + "type": "array", + "items": { + "$ref": "#/$defs/LearningActivitySpecificationType" + } + } + ] + }, + "LearningActivitySpecificationType": { + "type": "object", + "additionalProperties": false, + "properties": { + "id": { + "$ref": "#/$defs/GenericIdType" + }, + "type": { + "const": "LearningActivitySpecification" + }, + "dcType": { + "$ref": "#/$defs/Many!ConceptType" + }, + "identifier": { + "$ref": "#/$defs/Many!IdentifierOrLegalIdentifierType" + }, + "title": { + "$ref": "#/$defs/Many!LangStringType" + }, + "description": { + "$ref": "#/$defs/Many!LangStringType" + }, + "additionalNote": { + "$ref": "#/$defs/Many!NoteType" + }, + "supplementaryDocument": { + "$ref": "#/$defs/Many!WebResourceType" + }, + "homepage": { + "$ref": "#/$defs/Many!WebResourceType" + }, + "altLabel": { + "$ref": "#/$defs/Many!LangStringType" + }, + "category": { + "$ref": "#/$defs/Many!LangStringType" + }, + "dateModified": { + "$ref": "#/$defs/DateTimeType" + }, + "language": { + "$ref": "#/$defs/Many!ConceptType" + }, + "volumeOfLearning": { + "$ref": "#/$defs/DurationType" + }, + "contactHour": { + "$ref": "#/$defs/Many!StringType" + }, + "mode": { + "$ref": "#/$defs/Many!ConceptType" + }, + "influences": { + "$ref": "#/$defs/Many!LearningAchievementSpecificationOrQualificationType" + }, + "hasPart": { + "$ref": "#/$defs/Many!LearningActivitySpecificationType" + }, + "isPartOf": { + "$ref": "#/$defs/Many!LearningActivitySpecificationType" + }, + "specialisationOf": { + "$ref": "#/$defs/Many!LearningActivitySpecificationType" + }, + "generalisationOf": { + "$ref": "#/$defs/Many!LearningActivitySpecificationType" + }, + "status": { + "$ref": "#/$defs/StringType" + } + }, + "required": ["title"] + }, + "Many!LearningAssessmentType": { + "anyOf": [ + { + "$ref": "#/$defs/LearningAssessmentType" + }, + { + "type": "array", + "items": { + "$ref": "#/$defs/LearningAssessmentType" + } + } + ] + }, + "LearningAssessmentType": { + "type": "object", + "additionalProperties": false, + "properties": { + "id": { + "$ref": "#/$defs/GenericIdType" + }, + "type": { + "const": "LearningAssessment" + }, + "dcType": { + "$ref": "#/$defs/Many!ConceptType" + }, + "title": { + "$ref": "#/$defs/Many!LangStringType" + }, + "description": { + "$ref": "#/$defs/Many!LangStringType" + }, + "identifier": { + "$ref": "#/$defs/Many!IdentifierOrLegalIdentifierType" + }, + "additionalNote": { + "$ref": "#/$defs/Many!NoteType" + }, + "supplementaryDocument": { + "$ref": "#/$defs/Many!WebResourceType" + }, + "dateIssued": { + "$ref": "#/$defs/DateTimeType" + }, + "location": { + "$ref": "#/$defs/LocationType" + }, + "grade": { + "$ref": "#/$defs/NoteType" + }, + "gradeStatus": { + "$ref": "#/$defs/ConceptType" + }, + "shortenedGrading": { + "$ref": "#/$defs/ShortenedGradingType" + }, + "resultDistribution": { + "$ref": "#/$defs/ResultDistributionType" + }, + "idVerification": { + "$ref": "#/$defs/ConceptType" + }, + "awardedBy": { + "$ref": "#/$defs/AwardingProcessType" + }, + "assessedBy": { + "$ref": "#/$defs/Many!AgentOrPersonOrOrganisationType" + }, + "proves": { + "$ref": "#/$defs/Many!LearningAchievementType" + }, + "hasPart": { + "$ref": "#/$defs/Many!LearningAssessmentType" + }, + "isPartOf": { + "$ref": "#/$defs/Many!LearningAssessmentType" + }, + "specifiedBy": { + "$ref": "#/$defs/Many!LearningAssessmentSpecificationType" + } + }, + "required": ["title", "grade", "awardedBy"] + }, + "Many!LearningAssessmentSpecificationType": { + "anyOf": [ + { + "$ref": "#/$defs/LearningAssessmentSpecificationType" + }, + { + "type": "array", + "items": { + "$ref": "#/$defs/LearningAssessmentSpecificationType" + } + } + ] + }, + "LearningAssessmentSpecificationType": { + "type": "object", + "additionalProperties": false, + "properties": { + "id": { + "$ref": "#/$defs/GenericIdType" + }, + "type": { + "const": "LearningAssessmentSpecification" + }, + "dcType": { + "$ref": "#/$defs/ConceptType" + }, + "identifier": { + "$ref": "#/$defs/Many!IdentifierOrLegalIdentifierType" + }, + "title": { + "$ref": "#/$defs/Many!LangStringType" + }, + "description": { + "$ref": "#/$defs/Many!LangStringType" + }, + "additionalNote": { + "$ref": "#/$defs/Many!NoteType" + }, + "supplementaryDocument": { + "$ref": "#/$defs/Many!WebResourceType" + }, + "homepage": { + "$ref": "#/$defs/Many!WebResourceType" + }, + "altLabel": { + "$ref": "#/$defs/Many!LangStringType" + }, + "category": { + "$ref": "#/$defs/Many!LangStringType" + }, + "dateModified": { + "$ref": "#/$defs/DateTimeType" + }, + "language": { + "$ref": "#/$defs/Many!ConceptType" + }, + "mode": { + "$ref": "#/$defs/Many!ConceptType" + }, + "gradingScheme": { + "$ref": "#/$defs/GradingSchemeType" + }, + "proves": { + "$ref": "#/$defs/Many!LearningAchievementSpecificationOrQualificationType" + }, + "hasPart": { + "$ref": "#/$defs/Many!LearningAssessmentSpecificationType" + }, + "isPartOf": { + "$ref": "#/$defs/Many!LearningAssessmentSpecificationType" + }, + "specialisationOf": { + "$ref": "#/$defs/Many!LearningAssessmentSpecificationType" + }, + "generalisationOf": { + "$ref": "#/$defs/Many!LearningAssessmentSpecificationType" + }, + "status": { + "$ref": "#/$defs/StringType" + } + }, + "required": ["title"] + }, + "Many!LearningEntitlementType": { + "anyOf": [ + { + "$ref": "#/$defs/LearningEntitlementType" + }, + { + "type": "array", + "items": { + "$ref": "#/$defs/LearningEntitlementType" + } + } + ] + }, + "LearningEntitlementType": { + "type": "object", + "additionalProperties": false, + "properties": { + "id": { + "$ref": "#/$defs/GenericIdType" + }, + "type": { + "const": "LearningEntitlement" + }, + "dcType": { + "$ref": "#/$defs/Many!ConceptType" + }, + "title": { + "$ref": "#/$defs/Many!LangStringType" + }, + "description": { + "$ref": "#/$defs/Many!LangStringType" + }, + "identifier": { + "$ref": "#/$defs/Many!IdentifierOrLegalIdentifierType" + }, + "additionalNote": { + "$ref": "#/$defs/Many!NoteType" + }, + "supplementaryDocument": { + "$ref": "#/$defs/Many!WebResourceType" + }, + "dateIssued": { + "$ref": "#/$defs/DateTimeType" + }, + "expiryDate": { + "$ref": "#/$defs/DateTimeType" + }, + "awardedBy": { + "$ref": "#/$defs/AwardingProcessType" + }, + "entitledBy": { + "$ref": "#/$defs/Many!LearningAchievementType" + }, + "hasPart": { + "$ref": "#/$defs/Many!LearningEntitlementType" + }, + "isPartOf": { + "$ref": "#/$defs/Many!LearningEntitlementType" + }, + "specifiedBy": { + "$ref": "#/$defs/Many!LearningEntitlementSpecificationType" + } + }, + "required": ["title", "awardedBy"] + }, + "Many!LearningEntitlementSpecificationType": { + "anyOf": [ + { + "$ref": "#/$defs/LearningEntitlementSpecificationType" + }, + { + "type": "array", + "items": { + "$ref": "#/$defs/LearningEntitlementSpecificationType" + } + } + ] + }, + "LearningEntitlementSpecificationType": { + "type": "object", + "additionalProperties": false, + "properties": { + "id": { + "$ref": "#/$defs/GenericIdType" + }, + "type": { + "const": "LearningEntitlementSpecification" + }, + "dcType": { + "$ref": "#/$defs/Single!ConceptType" + }, + "identifier": { + "$ref": "#/$defs/Many!IdentifierOrLegalIdentifierType" + }, + "title": { + "$ref": "#/$defs/Many!LangStringType" + }, + "description": { + "$ref": "#/$defs/Many!LangStringType" + }, + "additionalNote": { + "$ref": "#/$defs/Many!NoteType" + }, + "supplementaryDocument": { + "$ref": "#/$defs/Many!WebResourceType" + }, + "homepage": { + "$ref": "#/$defs/Many!WebResourceType" + }, + "altLabel": { + "$ref": "#/$defs/Many!LangStringType" + }, + "category": { + "$ref": "#/$defs/Many!LangStringType" + }, + "dateModified": { + "$ref": "#/$defs/DateTimeType" + }, + "entitlementStatus": { + "$ref": "#/$defs/ConceptType" + }, + "limitOrganisation": { + "$ref": "#/$defs/Many!OrganisationType" + }, + "limitJurisdiction": { + "$ref": "#/$defs/Many!ConceptType" + }, + "limitOccupation": { + "$ref": "#/$defs/Many!ConceptType" + }, + "limitNationalOccupation": { + "$ref": "#/$defs/Many!ConceptType" + }, + "entitledBy": { + "$ref": "#/$defs/Many!LearningAchievementSpecificationOrQualificationType" + }, + "hasPart": { + "$ref": "#/$defs/Many!LearningEntitlementSpecificationType" + }, + "isPartOf": { + "$ref": "#/$defs/Many!LearningEntitlementSpecificationType" + }, + "specialisationOf": { + "$ref": "#/$defs/Many!LearningEntitlementSpecificationType" + }, + "generalisationOf": { + "$ref": "#/$defs/Many!LearningEntitlementSpecificationType" + }, + "status": { + "$ref": "#/$defs/StringType" + } + }, + "required": ["title", "entitlementStatus", "dcType"] + }, + "Many!LearningOpportunityType": { + "anyOf": [ + { + "$ref": "#/$defs/LearningOpportunityType" + }, + { + "type": "array", + "items": { + "$ref": "#/$defs/LearningOpportunityType" + } + } + ] + }, + "LearningOpportunityType": { + "type": "object", + "additionalProperties": false, + "properties": { + "id": { + "$ref": "#/$defs/GenericIdType" + }, + "type": { + "const": "LearningOpportunity" + }, + "dcType": { + "$ref": "#/$defs/Many!ConceptType" + }, + "identifier": { + "$ref": "#/$defs/Many!IdentifierOrLegalIdentifierType" + }, + "title": { + "$ref": "#/$defs/Many!LangStringType" + }, + "description": { + "$ref": "#/$defs/Many!LangStringType" + }, + "additionalNote": { + "$ref": "#/$defs/Many!NoteType" + }, + "homepage": { + "$ref": "#/$defs/Many!WebResourceType" + }, + "supplementaryDocument": { + "$ref": "#/$defs/Many!WebResourceType" + }, + "temporal": { + "$ref": "#/$defs/PeriodOfTimeType" + }, + "duration": { + "$ref": "#/$defs/DurationType" + }, + "mode": { + "$ref": "#/$defs/Many!ConceptType" + }, + "learningSchedule": { + "$ref": "#/$defs/ConceptType" + }, + "scheduleInformation": { + "$ref": "#/$defs/NoteType" + }, + "admissionProcedure": { + "$ref": "#/$defs/NoteType" + }, + "priceDetail": { + "$ref": "#/$defs/Many!PriceDetailType" + }, + "providedBy": { + "$ref": "#/$defs/OrganisationType" + }, + "grant": { + "$ref": "#/$defs/Many!GrantType" + }, + "location": { + "$ref": "#/$defs/Many!LocationType" + }, + "learningAchievementSpecification": { + "$ref": "#/$defs/LearningAchievementSpecificationOrQualificationType" + }, + "learningActivitySpecification": { + "$ref": "#/$defs/LearningActivitySpecificationType" + }, + "hasPart": { + "$ref": "#/$defs/Many!LearningOpportunityType" + }, + "isPartOf": { + "$ref": "#/$defs/Many!LearningOpportunityType" + }, + "bannerImage": { + "$ref": "#/$defs/MediaObjectType" + }, + "applicationDeadline": { + "$ref": "#/$defs/Many!DateTimeType" + }, + "defaultLanguage": { + "$ref": "#/$defs/ConceptType" + }, + "descriptionHtml": { + "$ref": "#/$defs/Many!HTMLType" + }, + "dateModified": { + "$ref": "#/$defs/DateTimeType" + }, + "status": { + "$ref": "#/$defs/StringType" + } + }, + "required": ["title"] + }, + "Many!PriceDetailType": { + "anyOf": [ + { + "$ref": "#/$defs/PriceDetailType" + }, + { + "type": "array", + "items": { + "$ref": "#/$defs/PriceDetailType" + } + } + ] + }, + "PriceDetailType": { + "type": "object", + "additionalProperties": false, + "properties": { + "id": { + "$ref": "#/$defs/GenericIdType" + }, + "type": { + "const": "PriceDetail" + }, + "identifier": { + "$ref": "#/$defs/Many!IdentifierOrLegalIdentifierType" + }, + "prefLabel": { + "$ref": "#/$defs/Many!LangStringType" + }, + "description": { + "$ref": "#/$defs/Many!LangStringType" + }, + "additionalNote": { + "$ref": "#/$defs/Many!NoteType" + }, + "amount": { + "$ref": "#/$defs/AmountType" + } + }, + "required": [] + }, + "Many!ResultCategoryType": { + "anyOf": [ + { + "$ref": "#/$defs/ResultCategoryType" + }, + { + "type": "array", + "items": { + "$ref": "#/$defs/ResultCategoryType" + } + } + ] + }, + "ResultCategoryType": { + "type": "object", + "additionalProperties": false, + "properties": { + "id": { + "$ref": "#/$defs/GenericIdType" + }, + "type": { + "const": "ResultCategory" + }, + "label": { + "$ref": "#/$defs/StringType" + }, + "score": { + "$ref": "#/$defs/StringType" + }, + "maximumScore": { + "$ref": "#/$defs/StringType" + }, + "minimumScore": { + "$ref": "#/$defs/StringType" + }, + "count": { + "$ref": "#/$defs/PositiveIntegerType" + } + }, + "required": ["label", "count"] + }, + "Many!ResultDistributionType": { + "anyOf": [ + { + "$ref": "#/$defs/ResultDistributionType" + }, + { + "type": "array", + "items": { + "$ref": "#/$defs/ResultDistributionType" + } + } + ] + }, + "ResultDistributionType": { + "type": "object", + "additionalProperties": false, + "properties": { + "id": { + "$ref": "#/$defs/GenericIdType" + }, + "type": { + "const": "ResultDistribution" + }, + "description": { + "$ref": "#/$defs/Many!LangStringType" + }, + "resultCategory": { + "$ref": "#/$defs/Many!ResultCategoryType" + } + }, + "required": [] + }, + "Many!ShortenedGradingType": { + "anyOf": [ + { + "$ref": "#/$defs/ShortenedGradingType" + }, + { + "type": "array", + "items": { + "$ref": "#/$defs/ShortenedGradingType" + } + } + ] + }, + "ShortenedGradingType": { + "type": "object", + "additionalProperties": false, + "properties": { + "id": { + "$ref": "#/$defs/GenericIdType" + }, + "type": { + "const": "ShortenedGrading" + }, + "percentageLower": { + "$ref": "#/$defs/IntegerType" + }, + "percentageEqual": { + "$ref": "#/$defs/IntegerType" + }, + "percentageHigher": { + "$ref": "#/$defs/IntegerType" + } + }, + "required": ["percentageLower", "percentageEqual", "percentageHigher"] + }, + "Many!VerificationCheckType": { + "anyOf": [ + { + "$ref": "#/$defs/VerificationCheckType" + }, + { + "type": "array", + "items": { + "$ref": "#/$defs/VerificationCheckType" + } + } + ] + }, + "VerificationCheckType": { + "type": "object", + "additionalProperties": false, + "properties": { + "id": { + "$ref": "#/$defs/GenericIdType" + }, + "type": { + "const": "VerificationCheck" + }, + "dcType": { + "$ref": "#/$defs/ConceptType" + }, + "description": { + "$ref": "#/$defs/Many!LangStringType" + }, + "verificationStatus": { + "$ref": "#/$defs/ConceptType" + }, + "elmSubject": { + "$ref": "#/$defs/EuropeanDigitalCredentialType" + } + }, + "required": ["verificationStatus", "subject", "dcType"] + }, + "Many!EvidenceType": { + "anyOf": [ + { + "$ref": "#/$defs/EvidenceType" + }, + { + "type": "array", + "items": { + "$ref": "#/$defs/EvidenceType" + } + } + ] + }, + "EvidenceType": { + "type": "object", + "additionalProperties": false, + "properties": { + "id": { + "$ref": "#/$defs/GenericIdType" + }, + "type": { + "const": "Evidence" + }, + "evidenceStatement": { + "$ref": "#/$defs/StringType" + }, + "evidenceTarget": { + "$ref": "#/$defs/AgentOrPersonOrOrganisationType" + }, + "embeddedEvidence": { + "$ref": "#/$defs/Many!MediaObjectType" + }, + "accreditation": { + "$ref": "#/$defs/AccreditationType" + }, + "dcType": { + "$ref": "#/$defs/ConceptType" + } + }, + "required": [] + }, + "Many!TermsOfUseType": { + "anyOf": [ + { + "$ref": "#/$defs/TermsOfUseType" + }, + { + "type": "array", + "items": { + "$ref": "#/$defs/TermsOfUseType" + } + } + ] + }, + "TermsOfUseType": { + "type": "object", + "additionalProperties": false, + "properties": { + "id": { + "$ref": "#/$defs/GenericIdType" + }, + "type": { + "const": "TermsOfUse" + } + }, + "required": [] + }, + "Many!ProofType": { + "anyOf": [ + { + "$ref": "#/$defs/ProofType" + }, + { + "type": "array", + "items": { + "$ref": "#/$defs/ProofType" + } + } + ] + }, + "ProofType": { + "type": "object", + "additionalProperties": false, + "properties": { + "id": { + "$ref": "#/$defs/GenericIdType" + }, + "type": { + "const": "Proof" + } + }, + "required": [] + }, + "Many!CredentialStatusType": { + "anyOf": [ + { + "$ref": "#/$defs/CredentialStatusType" + }, + { + "type": "array", + "items": { + "$ref": "#/$defs/CredentialStatusType" + } + } + ] + }, + "CredentialStatusType": { + "type": "object", + "additionalProperties": false, + "properties": { + "id": { + "$ref": "#/$defs/GenericIdType" + }, + "type": { + "type": "string", + "enum": ["StatusList2021Entry"] + } + }, + "required": [] + }, + "Many!CredentialSchemaType": { + "anyOf": [ + { + "$ref": "#/$defs/CredentialSchemaType" + }, + { + "type": "array", + "items": { + "$ref": "#/$defs/CredentialSchemaType" + } + } + ] + }, + "CredentialSchemaType": { + "type": "object", + "additionalProperties": false, + "properties": { + "id": { + "$ref": "#/$defs/GenericIdType" + }, + "type": { + "type": "string", + "enum": ["ShaclValidator2017", "JsonSchema"] + } + }, + "required": [] + }, + "Many!AmountType": { + "anyOf": [ + { + "$ref": "#/$defs/AmountType" + }, + { + "type": "array", + "items": { + "$ref": "#/$defs/AmountType" + } + } + ] + }, + "Many!AwardingProcessType": { + "anyOf": [ + { + "$ref": "#/$defs/AwardingProcessType" + }, + { + "type": "array", + "items": { + "$ref": "#/$defs/AwardingProcessType" + } + } + ] + }, + "AwardingProcessType": { + "type": "object", + "additionalProperties": false, + "properties": { + "id": { + "$ref": "#/$defs/GenericIdType" + }, + "type": { + "const": "AwardingProcess" + }, + "identifier": { + "$ref": "#/$defs/Many!IdentifierOrLegalIdentifierType" + }, + "description": { + "$ref": "#/$defs/Many!LangStringType" + }, + "location": { + "$ref": "#/$defs/LocationType" + }, + "additionalNote": { + "$ref": "#/$defs/Many!NoteType" + }, + "used": { + "$ref": "#/$defs/Many!LearningAssessmentType" + }, + "awards": { + "$ref": "#/$defs/Many!ClaimNodeType" + }, + "awardingBody": { + "$ref": "#/$defs/Many!AgentOrPersonOrOrganisationType" + }, + "awardingDate": { + "$ref": "#/$defs/DateTimeType" + }, + "educationalSystemNote": { + "$ref": "#/$defs/ConceptType" + } + }, + "required": ["awardingBody"] + }, + "Many!DisplayParameterType": { + "anyOf": [ + { + "$ref": "#/$defs/DisplayParameterType" + }, + { + "type": "array", + "items": { + "$ref": "#/$defs/DisplayParameterType" + } + } + ] + }, + "DisplayParameterType": { + "type": "object", + "additionalProperties": false, + "properties": { + "id": { + "$ref": "#/$defs/GenericIdType" + }, + "type": { + "const": "DisplayParameter" + }, + "title": { + "$ref": "#/$defs/Many!LangStringType" + }, + "description": { + "$ref": "#/$defs/Many!LangStringType" + }, + "language": { + "$ref": "#/$defs/Many!ConceptType" + }, + "primaryLanguage": { + "$ref": "#/$defs/ConceptType" + }, + "summaryDisplay": { + "$ref": "#/$defs/StringType" + }, + "individualDisplay": { + "$ref": "#/$defs/Many!IndividualDisplayType" + } + }, + "required": ["title", "language", "primaryLanguage", "individualDisplay"] + }, + "Many!IndividualDisplayType": { + "anyOf": [ + { + "$ref": "#/$defs/IndividualDisplayType" + }, + { + "type": "array", + "items": { + "$ref": "#/$defs/IndividualDisplayType" + } + } + ] + }, + "IndividualDisplayType": { + "type": "object", + "additionalProperties": false, + "properties": { + "id": { + "$ref": "#/$defs/GenericIdType" + }, + "type": { + "const": "IndividualDisplay" + }, + "language": { + "$ref": "#/$defs/ConceptType" + }, + "displayDetail": { + "$ref": "#/$defs/Many!DisplayDetailType" + } + }, + "required": ["language", "displayDetail"] + }, + "Many!DisplayDetailType": { + "anyOf": [ + { + "$ref": "#/$defs/DisplayDetailType" + }, + { + "type": "array", + "items": { + "$ref": "#/$defs/DisplayDetailType" + } + } + ] + }, + "DisplayDetailType": { + "type": "object", + "additionalProperties": false, + "properties": { + "id": { + "$ref": "#/$defs/GenericIdType" + }, + "type": { + "const": "DisplayDetail" + }, + "image": { + "$ref": "#/$defs/MediaObjectType" + }, + "page": { + "$ref": "#/$defs/PositiveIntegerType" + } + }, + "required": ["image", "page"] + }, + "Many!EuropeanDigitalPresentationType": { + "anyOf": [ + { + "$ref": "#/$defs/EuropeanDigitalPresentationType" + }, + { + "type": "array", + "items": { + "$ref": "#/$defs/EuropeanDigitalPresentationType" + } + } + ] + }, + "EuropeanDigitalPresentationType": { + "type": "object", + "additionalProperties": false, + "properties": { + "id": { + "$ref": "#/$defs/GenericIdType" + }, + "type": { + "const": "EuropeanDigitalPresentation" + }, + "verifiableCredential": { + "$ref": "#/$defs/Many!EuropeanDigitalCredentialType" + }, + "verificationCheck": { + "$ref": "#/$defs/Many!VerificationCheckType" + }, + "holder": { + "$ref": "#/$defs/Many!AgentOrPersonOrOrganisationType" + }, + "proof": { + "$ref": "#/$defs/Many!ProofType" + } + }, + "required": [] + }, + "Many!GradingSchemeType": { + "anyOf": [ + { + "$ref": "#/$defs/GradingSchemeType" + }, + { + "type": "array", + "items": { + "$ref": "#/$defs/GradingSchemeType" + } + } + ] + }, + "GradingSchemeType": { + "type": "object", + "additionalProperties": false, + "properties": { + "id": { + "$ref": "#/$defs/GenericIdType" + }, + "type": { + "const": "GradingScheme" + }, + "identifier": { + "$ref": "#/$defs/Many!IdentifierOrLegalIdentifierType" + }, + "title": { + "$ref": "#/$defs/Many!LangStringType" + }, + "description": { + "$ref": "#/$defs/Many!LangStringType" + }, + "supplementaryDocument": { + "$ref": "#/$defs/Many!WebResourceType" + } + }, + "required": ["title"] + }, + "Many!GrantType": { + "anyOf": [ + { + "$ref": "#/$defs/GrantType" + }, + { + "type": "array", + "items": { + "$ref": "#/$defs/GrantType" + } + } + ] + }, + "GrantType": { + "type": "object", + "additionalProperties": false, + "properties": { + "id": { + "$ref": "#/$defs/GenericIdType" + }, + "type": { + "const": "Grant" + }, + "dcType": { + "$ref": "#/$defs/ConceptType" + }, + "title": { + "$ref": "#/$defs/Many!LangStringType" + }, + "description": { + "$ref": "#/$defs/Many!LangStringType" + }, + "supplementaryDocument": { + "$ref": "#/$defs/Many!WebResourceType" + }, + "contentURL": { + "$ref": "#/$defs/URIType" + } + }, + "required": ["title"] + }, + "Many!ClaimTypeNodeType": { + "anyOf": [ + { + "$ref": "#/$defs/ClaimTypeNodeType" + }, + { + "type": "array", + "items": { + "$ref": "#/$defs/ClaimTypeNodeType" + } + } + ] + }, + "ClaimTypeNodeType": { + "type": "object", + "additionalProperties": false, + "properties": { + "id": { + "$ref": "#/$defs/GenericIdType" + }, + "type": { + "const": "ClaimTypeNode" + }, + "title": { + "$ref": "#/$defs/Many!LangStringType" + }, + "description": { + "$ref": "#/$defs/Many!LangStringType" + }, + "identifier": { + "$ref": "#/$defs/Many!IdentifierOrLegalIdentifierType" + }, + "additionalNote": { + "$ref": "#/$defs/Many!NoteType" + }, + "supplementaryDocument": { + "$ref": "#/$defs/Many!WebResourceType" + }, + "awardedBy": { + "$ref": "#/$defs/AwardingProcessType" + } + }, + "required": ["title", "awardedBy"] + }, + "EuropeanDigitalCredentialType": { + "type": "object", + "properties": { + "id": { + "$ref": "#/$defs/GenericIdType" + }, + "type": { + "type": "array", + "items": { + "type": "string", + "enum": [ + "VerifiableCredential", + "VerifiableAttestation", + "EuropeanDigitalCredential" + ] + }, + "minItems": 3, + "uniqueItems": true + }, + "identifier": { + "$ref": "#/$defs/Many!IdentifierOrLegalIdentifierType" + }, + "credentialProfiles": { + "$ref": "#/$defs/Many!ConceptType" + }, + "attachment": { + "$ref": "#/$defs/Many!MediaObjectType" + }, + "displayParameter": { + "$ref": "#/$defs/DisplayParameterType" + }, + "issuer": { + "anyOf": [ + { + "$ref": "#/$defs/AgentOrPersonOrOrganisationType" + }, + { + "$ref": "#/$defs/GenericIdType" + } + ] + }, + "credentialSubject": { + "$ref": "#/$defs/AgentOrPersonOrOrganisationType" + }, + "issuanceDate": { + "$ref": "#/$defs/DateTimeType" + }, + "issued": { + "$ref": "#/$defs/DateTimeType" + }, + "validFrom": { + "$ref": "#/$defs/DateTimeType" + }, + "expirationDate": { + "$ref": "#/$defs/Many!DateTimeType" + }, + "validUntil": { + "$ref": "#/$defs/DateTimeType" + }, + "proof": { + "$ref": "#/$defs/Many!ProofType" + }, + "evidence": { + "$ref": "#/$defs/Many!EvidenceType" + }, + "termsOfUse": { + "$ref": "#/$defs/Many!TermsOfUseType" + }, + "credentialSchema": { + "$ref": "#/$defs/Many!CredentialSchemaType" + }, + "credentialStatus": { + "$ref": "#/$defs/Many!CredentialStatusType" + }, + "holder": { + "$ref": "#/$defs/Many!AgentOrPersonOrOrganisationType" + } + }, + "required": [ + "credentialProfiles", + "displayParameter", + "issuer", + "credentialSubject", + "issued", + "validFrom", + "credentialSchema" + ] + }, + "Many!IdentifierOrLegalIdentifierType": { + "anyOf": [ + { + "$ref": "#/$defs/IdentifierOrLegalIdentifierType" + }, + { + "type": "array", + "items": { + "$ref": "#/$defs/IdentifierOrLegalIdentifierType" + } + } + ] + }, + "Many!MediaObjectType": { + "anyOf": [ + { + "$ref": "#/$defs/MediaObjectType" + }, + { + "type": "array", + "items": { + "$ref": "#/$defs/MediaObjectType" + } + } + ] + }, + "Many!DateTimeType": { + "anyOf": [ + { + "$ref": "#/$defs/DateTimeType" + }, + { + "type": "array", + "items": { + "$ref": "#/$defs/DateTimeType" + } + } + ] + }, + "Many!LearningAchievementSpecificationOrQualificationType": { + "anyOf": [ + { + "$ref": "#/$defs/LearningAchievementSpecificationOrQualificationType" + }, + { + "type": "array", + "items": { + "$ref": "#/$defs/LearningAchievementSpecificationOrQualificationType" + } + } + ] + }, + "LearningAchievementSpecificationOrQualificationType": { + "anyOf": [ + { + "$ref": "#/$defs/LearningAchievementSpecificationType" + }, + { + "$ref": "#/$defs/QualificationType" + } + ] + }, + "Many!AwardingOpportunityType": { + "anyOf": [ + { + "$ref": "#/$defs/AwardingOpportunityType" + }, + { + "type": "array", + "items": { + "$ref": "#/$defs/AwardingOpportunityType" + } + } + ] + }, + "AwardingOpportunityType": { + "type": "object", + "additionalProperties": false, + "properties": { + "id": { + "$ref": "#/$defs/GenericIdType" + }, + "type": { + "const": "AwardingOpportunity" + }, + "identifier": { + "$ref": "#/$defs/Many!IdentifierOrLegalIdentifierType" + }, + "location": { + "$ref": "#/$defs/LocationType" + }, + "temporal": { + "$ref": "#/$defs/PeriodOfTimeType" + }, + "awardingBody": { + "$ref": "#/$defs/Many!AgentOrPersonOrOrganisationType" + }, + "learningAchievementSpecification": { + "$ref": "#/$defs/LearningAchievementSpecificationOrQualificationType" + } + }, + "required": ["awardingBody"] + } + } + } + \ No newline at end of file diff --git a/json/ebsi-elm/vcdm2.0-europass-edc-schema/examples/DigiComp Generic.json b/json/ebsi-elm/vcdm2.0-europass-edc-schema/examples/DigiComp_Generic.json similarity index 99% rename from json/ebsi-elm/vcdm2.0-europass-edc-schema/examples/DigiComp Generic.json rename to json/ebsi-elm/vcdm2.0-europass-edc-schema/examples/DigiComp_Generic.json index 620a697..58b73f3 100644 --- a/json/ebsi-elm/vcdm2.0-europass-edc-schema/examples/DigiComp Generic.json +++ b/json/ebsi-elm/vcdm2.0-europass-edc-schema/examples/DigiComp_Generic.json @@ -452,7 +452,7 @@ "type": "Note", "noteLiteral": { "en": [ - "- Description of DigiCompCompetence\n- Description of DigiCompCompetence 2" + "De student heeft de eerste stap van transmutatie afgerond, waarbij katten zonder blijvende schade worden omgezet in keukenapparatuur." ] } }, diff --git a/json/ebsi-elm/vcdm2.0-europass-edc-schema/examples/DigiComp_Generic_test.json b/json/ebsi-elm/vcdm2.0-europass-edc-schema/examples/DigiComp_Generic_test.json new file mode 100644 index 0000000..8a499fe --- /dev/null +++ b/json/ebsi-elm/vcdm2.0-europass-edc-schema/examples/DigiComp_Generic_test.json @@ -0,0 +1,615 @@ +{ + "@context": [ + "https://www.w3.org/ns/credentials/v2", + "http://data.europa.eu/snb/model/context/edc-ap" + ], + "id": "urn:credential:dffc6c22-1421-4df2-b0e4-2b9d17aa0a6b", + "type": [ + "VerifiableCredential", + "VerifiableAttestation", + "EuropeanDigitalCredential" + ], + "credentialSchema": [ + { + "id": "http://data.europa.eu/snb/model/ap/edc-generic-full", + "type": "ShaclValidator2017" + }, + { + "id": "https://api-pilot.ebsi.eu/trusted-schemas-registry/v3/schemas/0x7ff3bc76bd5e37b3d29721b8698646a722a24a4f4ab0a0ba63d4bbbe0ef9758d", + "type": "JsonSchema" + } + ], + "credentialSubject": { + "id": "did:key:afsdlkj34134", + "type": "Person", + "identifier": [ + { + "id": "urn:epass:identifier:2", + "type": "Identifier", + "notation": "545465468", + "schemeName": "Student ID" + } + ], + "givenName": { + "en": ["David"] + }, + "familyName": { + "en": ["Smith"] + }, + "fullName": { + "en": ["David Smith"] + }, + "hasClaim": [ + { + "id": "urn:epass:learningAchievement:2", + "type": "LearningAchievement", + "awardedBy": { + "id": "urn:epass:awardingProcess:1", + "type": "AwardingProcess", + "awardingBody": [ + { + "id": "urn:epass:org:1", + "type": "Organisation", + "location": [ + { + "id": "urn:epass:location:1", + "type": "Location", + "address": [ + { + "id": "urn:epass:address:1", + "type": "Address", + "countryCode": { + "id": "http://publications.europa.eu/resource/authority/country/BEL", + "type": "Concept", + "inScheme": { + "id": "http://publications.europa.eu/resource/authority/country", + "type": "ConceptScheme" + }, + "prefLabel": { + "en": ["Belgium"] + }, + "notation": "country" + }, + "fullAddress": { + "id": "urn:epass:note:1", + "type": "Note", + "noteLiteral": { + "en": ["Here"] + } + } + } + ], + "description": { + "en": ["The Address"] + } + } + ], + "legalName": { + "en": ["University of Life"] + }, + "registration": { + "id": "urn:epass:legalIdentifier:2", + "type": "LegalIdentifier", + "notation": "987654321", + "spatial": { + "id": "http://publications.europa.eu/resource/authority/country/BEL", + "type": "Concept", + "inScheme": { + "id": "http://publications.europa.eu/resource/authority/country", + "type": "ConceptScheme" + }, + "prefLabel": { + "en": ["Belgium"] + }, + "notation": "country" + } + } + } + ] + }, + "title": { + "en": ["TITLE OF PROGRAMME"] + }, + "hasPart": [ + { + "id": "urn:epass:learningAchievement:1", + "type": "LearningAchievement", + "awardedBy": { + "id": "urn:epass:awardingProcess:1", + "type": "AwardingProcess", + "awardingBody": [ + { + "id": "urn:epass:org:1", + "type": "Organisation", + "location": [ + { + "id": "urn:epass:location:1", + "type": "Location", + "address": [ + { + "id": "urn:epass:address:1", + "type": "Address", + "countryCode": { + "id": "http://publications.europa.eu/resource/authority/country/BEL", + "type": "Concept", + "inScheme": { + "id": "http://publications.europa.eu/resource/authority/country", + "type": "ConceptScheme" + }, + "prefLabel": { + "en": ["Belgium"] + }, + "notation": "country" + }, + "fullAddress": { + "id": "urn:epass:note:1", + "type": "Note", + "noteLiteral": { + "en": ["Here"] + } + } + } + ], + "description": { + "en": ["The Address"] + } + } + ], + "legalName": { + "en": ["University of Life"] + }, + "registration": { + "id": "urn:epass:legalIdentifier:2", + "type": "LegalIdentifier", + "notation": "987654321", + "spatial": { + "id": "http://publications.europa.eu/resource/authority/country/BEL", + "type": "Concept", + "inScheme": { + "id": "http://publications.europa.eu/resource/authority/country", + "type": "ConceptScheme" + }, + "prefLabel": { + "en": ["Belgium"] + }, + "notation": "country" + } + } + } + ] + }, + "title": { + "en": ["Topic #1"] + }, + "specifiedBy": { + "id": "urn:epass:learningAchievementSpec:1", + "type": "LearningAchievementSpecification", + "title": { + "en": ["Topic #1"] + }, + "learningOutcome": [ + { + "id": "urn:epass:learningOutcome:1", + "type": "LearningOutcome", + "relatedSkill": [ + { + "id": "http://data.europa.eu/snb/dcf/860966ekgo", + "type": "Concept", + "inScheme": { + "id": "https://publications.europa.eu/resource/authority/snb/dcf/25831c2", + "type": "ConceptScheme" + }, + "prefLabel": { + "en": ["5.4 Identifying digital competence gaps"] + } + } + ], + "title": { + "en": ["Name of DigiComp Competence"] + } + } + ] + } + }, + { + "id": "urn:epass:learningAchievement:1", + "type": "LearningAchievement", + "awardedBy": { + "id": "urn:epass:awardingProcess:1", + "type": "AwardingProcess", + "awardingBody": [ + { + "id": "urn:epass:org:1", + "type": "Organisation", + "location": [ + { + "id": "urn:epass:location:1", + "type": "Location", + "address": [ + { + "id": "urn:epass:address:1", + "type": "Address", + "countryCode": { + "id": "http://publications.europa.eu/resource/authority/country/BEL", + "type": "Concept", + "inScheme": { + "id": "http://publications.europa.eu/resource/authority/country", + "type": "ConceptScheme" + }, + "prefLabel": { + "en": ["Belgium"] + }, + "notation": "country" + }, + "fullAddress": { + "id": "urn:epass:note:1", + "type": "Note", + "noteLiteral": { + "en": ["Here"] + } + } + } + ], + "description": { + "en": ["The Address"] + } + } + ], + "legalName": { + "en": ["University of Life"] + }, + "registration": { + "id": "urn:epass:legalIdentifier:2", + "type": "LegalIdentifier", + "notation": "987654321", + "spatial": { + "id": "http://publications.europa.eu/resource/authority/country/BEL", + "type": "Concept", + "inScheme": { + "id": "http://publications.europa.eu/resource/authority/country", + "type": "ConceptScheme" + }, + "prefLabel": { + "en": ["Belgium"] + }, + "notation": "country" + } + } + } + ] + }, + "title": { + "en": ["Topic #1"] + }, + "specifiedBy": { + "id": "urn:epass:learningAchievementSpec:1", + "type": "LearningAchievementSpecification", + "title": { + "en": ["Topic #1"] + }, + "learningOutcome": [ + { + "id": "urn:epass:learningOutcome:1", + "type": "LearningOutcome", + "relatedSkill": [ + { + "id": "http://data.europa.eu/snb/dcf/860966ekgo", + "type": "Concept", + "inScheme": { + "id": "https://publications.europa.eu/resource/authority/snb/dcf/25831c2", + "type": "ConceptScheme" + }, + "prefLabel": { + "en": ["5.4 Identifying digital competence gaps"] + } + } + ], + "title": { + "en": ["Name of DigiComp Competence"] + } + } + ] + } + } + ], + "provenBy": [ + { + "id": "urn:epass:learningAssessment:1", + "type": "LearningAssessment", + "awardedBy": { + "id": "urn:epass:awardingProcess:1", + "type": "AwardingProcess", + "awardingBody": [ + { + "id": "urn:epass:org:1", + "type": "Organisation", + "location": [ + { + "id": "urn:epass:location:1", + "type": "Location", + "address": [ + { + "id": "urn:epass:address:1", + "type": "Address", + "countryCode": { + "id": "http://publications.europa.eu/resource/authority/country/BEL", + "type": "Concept", + "inScheme": { + "id": "http://publications.europa.eu/resource/authority/country", + "type": "ConceptScheme" + }, + "prefLabel": { + "en": ["Belgium"] + }, + "notation": "country" + }, + "fullAddress": { + "id": "urn:epass:note:1", + "type": "Note", + "noteLiteral": { + "en": ["Here"] + } + } + } + ], + "description": { + "en": ["The Address"] + } + } + ], + "legalName": { + "en": ["University of Life"] + }, + "registration": { + "id": "urn:epass:legalIdentifier:2", + "type": "LegalIdentifier", + "notation": "987654321", + "spatial": { + "id": "http://publications.europa.eu/resource/authority/country/BEL", + "type": "Concept", + "inScheme": { + "id": "http://publications.europa.eu/resource/authority/country", + "type": "ConceptScheme" + }, + "prefLabel": { + "en": ["Belgium"] + }, + "notation": "country" + } + } + } + ] + }, + "title": { + "en": ["Overall Diploma Assessment"] + }, + "grade": { + "id": "urn:epass:note:2", + "type": "Note", + "noteLiteral": { + "en": ["10"] + } + }, + "specifiedBy": { + "id": "urn:epass:learningAssessmentSpec:1", + "type": "LearningAssessmentSpecification", + "title": { + "en": ["Overall Diploma Assessment"] + } + } + } + ], + "specifiedBy": { + "id": "urn:epass:qualification:1", + "type": "Qualification", + "title": { + "en": ["Title of Achievement"] + }, + "learningOutcome": [ + { + "id": "urn:epass:learningOutcome:2", + "type": "LearningOutcome", + "relatedSkill": [ + { + "id": "https://publications.europa.eu/resource/authority/snb/dcf/860966ekgo", + "type": "Concept", + "inScheme": { + "id": "https://publications.europa.eu/resource/authority/snb/dcf/25831c2", + "type": "ConceptScheme" + }, + "prefLabel": { + "en": ["5.4 Identifying digital competence gaps"] + } + } + ], + "title": { + "en": ["Name of DigiComp Competence"] + } + }, + { + "id": "urn:epass:learningOutcome:3", + "type": "LearningOutcome", + "relatedSkill": [ + { + "id": "http://data.europa.eu/snb/dcf/34v10n662m", + "type": "Concept", + "inScheme": { + "id": "https://publications.europa.eu/resource/authority/snb/dcf/25831c2", + "type": "ConceptScheme" + }, + "prefLabel": { + "en": ["3.1 Proficiency Level Foundation 2"] + } + } + ], + "title": { + "en": ["Name of DigiComp Competence 2"] + } + } + ], + "learningOutcomeSummary": { + "id": "urn:epass:note:3", + "type": "Note", + "noteLiteral": { + "en": [ + "- Description of DigiCompCompetence\n- Description of DigiCompCompetence 2" + ] + } + }, + "eqfLevel": { + "id": "http://data.europa.eu/snb/eqf/5", + "type": "Concept", + "inScheme": { + "id": "http://data.europa.eu/snb/eqf/25831c2", + "type": "ConceptScheme" + }, + "prefLabel": { + "en": ["Level 5"] + } + } + } + } + ] + }, + "issuer": { + "id": "did:ebsi:org:12345689", + "type": "Organisation", + "location": [ + { + "id": "urn:epass:certificateLocation:1", + "type": "Location", + "address": { + "id": "urn:epass:certificateAddress:1", + "type": "Address", + "countryCode": { + "id": "http://publications.europa.eu/resource/authority/country/ESP", + "type": "Concept", + "inScheme": { + "id": "http://publications.europa.eu/resource/authority/country", + "type": "ConceptScheme" + }, + "notation": "country", + "prefLabel": { "en": "Spain" } + } + } + } + ], + "identifier": { + "id": "urn:epass:identifier:2", + "type": "Identifier", + "schemeName": "University Aliance ID", + "notation": "73737373" + }, + "legalName": { "en": "ORGANIZACION TEST" } + }, + "issuanceDate": "2024-03-26T16:06:50+01:00", + "issued": "2024-03-26T16:06:50+01:00", + "validFrom": "2019-09-20T00:00:00+02:00", + "credentialProfiles": [ + { + "id": "http://data.europa.eu/snb/credential/e34929035b", + "type": "Concept", + "inScheme": { + "id": "http://data.europa.eu/snb/credential/25831c2", + "type": "ConceptScheme" + }, + "prefLabel": { + "en": ["Generic"] + } + } + ], + "displayParameter": { + "id": "urn:epass:displayParameter:1", + "type": "DisplayParameter", + "language": [ + { + "id": "http://publications.europa.eu/resource/authority/language/ENG", + "type": "Concept", + "inScheme": { + "id": "http://publications.europa.eu/resource/authority/language", + "type": "ConceptScheme" + }, + "prefLabel": { + "en": ["English"] + }, + "notation": "language" + } + ], + "description": { + "en": [ + "EBSI Example https://github.com/Knowledge-Innovation-Centre/ESBI-JSON-schemas/blob/main/examples%20of%20credentials/DigiComp%20Generic.json" + ] + }, + "individualDisplay": [ + { + "id": "urn:epass:individualDisplay:c05743e7-9f9d-4e0b-899b-7ae6514c7a02", + "type": "IndividualDisplay", + "language": { + "id": "http://publications.europa.eu/resource/authority/language/ENG", + "type": "Concept", + "inScheme": { + "id": "http://publications.europa.eu/resource/authority/language", + "type": "ConceptScheme" + }, + "prefLabel": { + "en": ["English"] + }, + "notation": "language" + }, + "displayDetail": [ + { + "id": "urn:epass:displayDetail:2804bbf5-ab29-4972-9202-71af0f85316b", + "type": "DisplayDetail", + "image": { + "content": "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", + "contentEncoding": { + "id": "http://data.europa.eu/snb/encoding/6146cde7dd", + "inScheme": { + "id": "http://data.europa.eu/snb/encoding/25831c2", + "type": "ConceptScheme" + }, + "prefLabel": { + "en": [ + "base64" + ] + }, + "type": "Concept" + }, + "contentType": { + "id": "http://publications.europa.eu/resource/authority/file-type/PNG", + "inScheme": { + "id": "http://publications.europa.eu/resource/authority/file-type", + "type": "ConceptScheme" + }, + "notation": "file-type", + "prefLabel": { + "en": [ + "PNG" + ] + }, + "type": "Concept" + }, + "id": "urn:epass:mediaObject:https://avatars.githubusercontent.com/u/22613412?v=4", + "type": "MediaObject" + } + } + ] + } + ], + "primaryLanguage": { + "id": "http://publications.europa.eu/resource/authority/language/ENG", + "type": "Concept", + "inScheme": { + "id": "http://publications.europa.eu/resource/authority/language", + "type": "ConceptScheme" + }, + "prefLabel": { + "en": ["English"] + }, + "notation": "language" + }, + "title": { + "en": ["DigiComp Generic"] + } + } +} diff --git a/json/ebsi-elm/vcdm2.0-europass-edc-schema/examples/DigiComp_Generic_test_smaller.jsonld b/json/ebsi-elm/vcdm2.0-europass-edc-schema/examples/DigiComp_Generic_test_smaller.jsonld new file mode 100644 index 0000000..2cf81e9 --- /dev/null +++ b/json/ebsi-elm/vcdm2.0-europass-edc-schema/examples/DigiComp_Generic_test_smaller.jsonld @@ -0,0 +1,151 @@ +{ + "@context": [ + "https://www.w3.org/ns/credentials/v2", + "http://data.europa.eu/snb/model/context/edc-ap" + ], + "id": "urn:credential:dffc6c22-1421-4df2-b0e4-2b9d17aa0a6b", + "type": [ + "VerifiableCredential", + "VerifiableAttestation", + "EuropeanDigitalCredential" + ], + "credentialSchema": [ + { + "id": "http://data.europa.eu/snb/model/ap/edc-generic-full", + "type": "ShaclValidator2017" + }, + { + "id": "https://api-pilot.ebsi.eu/trusted-schemas-registry/v3/schemas/0x7ff3bc76bd5e37b3d29721b8698646a722a24a4f4ab0a0ba63d4bbbe0ef9758d", + "type": "JsonSchema" + } + ], + "credentialSubject": { + "id": "did:key:afsdlkj34134", + "type": "Person", + "identifier": [ + { + "id": "urn:epass:identifier:2", + "type": "Identifier", + "notation": "545465468", + "schemeName": "Student ID" + } + ], + + "fullName": { + "en": ["David Smith"] + }, + "hasClaim": [ + { + "id": "urn:epass:learningAchievement:2", + "type": "LearningAchievement", + "awardedBy": { + "id": "urn:epass:awardingProcess:1", + "type": "AwardingProcess", + "awardingBody": [ + { + "id": "urn:epass:org:1", + "type": "Organisation", + + "legalName": { + "en": ["University of Life"] + } + } + ] + }, + "title": { + "en": ["TITLE OF PROGRAMME"] + } + } + ] + }, + "issuer": { + "id": "did:ebsi:org:12345689", + "type": "Organisation", + "identifier": { + "id": "urn:epass:identifier:2", + "type": "Identifier", + "schemeName": "University Aliance ID", + "notation": "73737373" + }, + "legalName": { "en": "ORGANIZACION TEST" } + }, + "issuanceDate": "2024-03-26T16:06:50+01:00", + "issued": "2024-03-26T16:06:50+01:00", + "validFrom": "2019-09-20T00:00:00+02:00", + "credentialProfiles": [ + { + "id": "http://data.europa.eu/snb/credential/e34929035b", + "type": "Concept", + "inScheme": { + "id": "http://data.europa.eu/snb/credential/25831c2", + "type": "ConceptScheme" + }, + "prefLabel": { + "en": ["Generic"] + } + } + ], + "displayParameter": { + "id": "urn:epass:displayParameter:1", + "type": "DisplayParameter", + "language": [ + { + "id": "http://publications.europa.eu/resource/authority/language/ENG", + "type": "Concept", + "inScheme": { + "id": "http://publications.europa.eu/resource/authority/language", + "type": "ConceptScheme" + }, + "prefLabel": { + "en": ["English"] + }, + "notation": "language" + } + ], + "description": { + "en": [ + "EBSI Example https://github.com/Knowledge-Innovation-Centre/ESBI-JSON-schemas/blob/main/examples%20of%20credentials/DigiComp%20Generic.json" + ] + }, + "individualDisplay": [ + { + "id": "urn:epass:individualDisplay:c05743e7-9f9d-4e0b-899b-7ae6514c7a02", + "type": "IndividualDisplay", + "language": { + "id": "http://publications.europa.eu/resource/authority/language/ENG", + "type": "Concept", + "inScheme": { + "id": "http://publications.europa.eu/resource/authority/language", + "type": "ConceptScheme" + }, + "prefLabel": { + "en": ["English"] + }, + "notation": "language" + }, + "displayDetail": [ + { + "id": "urn:epass:displayDetail:2804bbf5-ab29-4972-9202-71af0f85316b", + "type": "DisplayDetail", + "image": {"content": "1"} + } + ] + } + ], + "primaryLanguage": { + "id": "http://publications.europa.eu/resource/authority/language/ENG", + "type": "Concept", + "inScheme": { + "id": "http://publications.europa.eu/resource/authority/language", + "type": "ConceptScheme" + }, + "prefLabel": { + "en": ["English"] + }, + "notation": "language" + }, + "title": { + "en": ["DigiComp Generic"] + } + } +} diff --git a/json/ebsi-elm/vcdm2.0-europass-edc-schema/examples/Microcredential - Data and software business.json b/json/ebsi-elm/vcdm2.0-europass-edc-schema/examples/Microcredential_Data_and_software_business.json similarity index 100% rename from json/ebsi-elm/vcdm2.0-europass-edc-schema/examples/Microcredential - Data and software business.json rename to json/ebsi-elm/vcdm2.0-europass-edc-schema/examples/Microcredential_Data_and_software_business.json diff --git a/json/mapping/custom_mapping.json b/json/mapping/custom_mapping.json deleted file mode 100644 index 0637a08..0000000 --- a/json/mapping/custom_mapping.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/json/mapping/custom_mapping_ELM_OBv3.json b/json/mapping/custom_mapping_ELM_OBv3.json new file mode 100644 index 0000000..46eccb3 --- /dev/null +++ b/json/mapping/custom_mapping_ELM_OBv3.json @@ -0,0 +1,310 @@ +[ + { + "type_": "copy", + "source": { + "format": "ELM", + "path": "$.credentialSchema" + }, + "destination": { + "format": "OBv3", + "path": "$.credentialschema" + } + }, + { + "type_": "copy", + "source": { + "format": "ELM", + "path": "$.credentialStatus" + }, + "destination": { + "format": "OBv3", + "path": "$.credentialstatus" + } + }, + { + "type_": "copy", + "source": { + "format": "ELM", + "path": "$.credentialSubject" + }, + "destination": { + "format": "OBv3", + "path": "$.credentialsubject" + } + }, + { + "type_": "copy", + "source": { + "format": "ELM", + "path": "$.evidence" + }, + "destination": { + "format": "OBv3", + "path": "$.evidence" + } + }, + { + "type_": "copy", + "source": { + "format": "ELM", + "path": "$.issuanceDate" + }, + "destination": { + "format": "OBv3", + "path": "$.issuancedate" + } + }, + { + "type_": "copy", + "source": { + "format": "ELM", + "path": "$.issuer" + }, + "destination": { + "format": "OBv3", + "path": "$.issuer" + } + }, + { + "type_": "copy", + "source": { + "format": "ELM", + "path": "$.proof" + }, + "destination": { + "format": "OBv3", + "path": "$.proof" + } + }, + { + "type_": "copy", + "source": { + "format": "ELM", + "path": "$.termsOfUse" + }, + "destination": { + "format": "OBv3", + "path": "$.termsofuse" + } + }, + { + "type_": "copy", + "source": { + "format": "ELM", + "path": "$.validFrom" + }, + "destination": { + "format": "OBv3", + "path": "$.awardeddate" + } + }, + { + "type_": "copy", + "source": { + "format": "ELM", + "path": "$.validUntil" + }, + "destination": { + "format": "OBv3", + "path": "$.expirationdate" + } + }, + { + "type_": "copy", + "source": { + "format": "ELM", + "path": "$.refreshService" + }, + "destination": { + "format": "OBv3", + "path": "$.refreshservice" + } + }, + { + "type_": "copy", + "source": { + "format": "ELM", + "path": "$.id" + }, + "destination": { + "format": "OBv3", + "path": "$.id" + } + }, + { + "type_": "copy", + "source": { + "format": "ELM", + "path": "$.@context" + }, + "destination": { + "format": "OBv3", + "path": "$.@context" + } + }, + { + "type_": "copy", + "source": { + "format": "ELM", + "path": "$.credentialSubject.id" + }, + "destination": { + "format": "OBv3", + "path": "$.credentialSubject.achievement.id" + } + }, + { + "type_": "copy", + "source": { + "format": "ELM", + "path": "$.credentialSubject.hasClaim" + }, + "destination": { + "format": "OBv3", + "path": "$.credentialSubject.achievement.description" + } + }, + { + "type_": "copy", + "source": { + "format": "ELM", + "path": "$.credentialSubject.fullName.en" + }, + "destination": { + "format": "OBv3", + "path": "$.credentialSubject.achievement.name" + } + }, + { + "type_": "copy", + "source": { + "format": "ELM", + "path": "$.credentialSubject.type" + }, + "destination": { + "format": "OBv3", + "path": "$.credentialSubject.achievement.type" + } + }, + { + "type_": "copy", + "source": { + "format": "ELM", + "path": "$.credentialSubject.identifier" + }, + "destination": { + "format": "OBv3", + "path": "$.credentialSubject.type" + } + }, + { + "type_": "copy", + "source": { + "format": "ELM", + "path": "$.credentialSubject.hasClaim" + }, + "destination": { + "format": "OBv3", + "path": "$.credentialSubject.achievement.criteria" + } + }, + { + "type_": "copy", + "source": { + "format": "ELM", + "path": "$.issuer.id" + }, + "destination": { + "format": "OBv3", + "path": "$.issuer" + } + }, + { + "type_": "copy", + "source": { + "format": "ELM", + "path": "$.issuer.identifier.type" + }, + "destination": { + "format": "OBv3", + "path": "$.type" + } + }, + { + "type_": "copy", + "source": { + "format": "ELM", + "path": "$.validFrom" + }, + "destination": { + "format": "OBv3", + "path": "$.validFrom" + } + }, + { + "type_": "copy", + "source": { + "format": "ELM", + "path": "$.credentialSchema" + }, + "destination": { + "format": "OBv3", + "path": "$.credentialSchema" + } + }, + { + "type_": "copy", + "source": { + "format": "ELM", + "path": "$.issuer.identifier.id" + }, + "destination": { + "format": "OBv3", + "path": "$.issuer" + } + }, + { + "type_": "copy", + "source": { + "format": "ELM", + "path": "$.type" + }, + "destination": { + "format": "OBv3", + "path": "$.type" + } + }, + { + "type_": "copy", + "source": { + "format": "ELM", + "path": "$.displayParameter.description.en" + }, + "destination": { + "format": "OBv3", + "path": "$.description" + } + }, + { + "type_": "copy", + "source": { + "format": "ELM", + "path": "$.displayParameter.description.en" + }, + "destination": { + "format": "OBv3", + "path": "$.description" + } + }, + { + "type_": "copy", + "source": { + "format": "ELM", + "path": "$.issuanceDate" + }, + "destination": { + "format": "OBv3", + "path": "$.awardedDate" + } + } +] \ No newline at end of file diff --git a/json/mapping/custom_mapping_ELM_OBv3_latest.json b/json/mapping/custom_mapping_ELM_OBv3_latest.json new file mode 100644 index 0000000..91b8bfe --- /dev/null +++ b/json/mapping/custom_mapping_ELM_OBv3_latest.json @@ -0,0 +1,286 @@ +[ + { + "type_": "copy", + "source": { + "format": "ELM", + "path": "$.@context" + }, + "destination": { + "format": "OBv3", + "path": "$.@context" + } + }, + { + "type_": "copy", + "source": { + "format": "ELM", + "path": "$.id" + }, + "destination": { + "format": "OBv3", + "path": "$.id" + } + }, + { + "type_": "stringit", + "source": { + "value": "VerifiableCredential" + }, + "destination": { + "format": "OBv3", + "path": "$.type[0]" + } + }, + { + "type_": "stringit", + "source": { + "value": "OpenBadgeCredential" + }, + "destination": { + "format": "OBv3", + "path": "$.type[1]" + } + }, + { + "type_": "copy", + "source": { + "format": "ELM", + "path": "$.issuer.id" + }, + "destination": { + "format": "OBv3", + "path": "$.issuer.id" + } + }, + { + "type_": "stringit", + "source": { + "value": "Profile" + }, + "destination": { + "format": "OBv3", + "path": "$.issuer.type[0]" + } + }, + { + "type_": "copy", + "source": { + "format": "ELM", + "path": "$.issuer.legalName.en" + }, + "destination": { + "format": "OBv3", + "path": "$.issuer.name" + } + }, + { + "type_": "copy", + "source": { + "format": "ELM", + "path": "$.issuer.location[0].address.fullAddress.noteLiteral.en" + }, + "destination": { + "format": "OBv3", + "path": "$.issuer.address.streetAddress" + } + }, + { + "type_": "copy", + "source": { + "format": "ELM", + "path": "$.issuer.location[0].address.countryCode.id" + }, + "destination": { + "format": "OBv3", + "path": "$.issuer.address.addressCountryCode" + } + }, + { + "type_": "copy", + "source": { + "format": "ELM", + "path": "$.credentialSubject.hasClaim[0].id" + }, + "destination": { + "format": "OBv3", + "path": "$.credentialSubject.achievement.id" + } + }, + { + "type_": "stringit", + "source": { + "value": "Achievement" + }, + "destination": { + "format": "OBv3", + "path": "$.credentialSubject.achievement.type[0]" + } + }, + { + "type_": "copy", + "source": { + "format": "ELM", + "path": "$.credentialSubject.hasClaim[0].id" + }, + "destination": { + "format": "OBv3", + "path": "$.credentialSubject.achievement.id" + } + }, + { + "type_": "copy", + "source": { + "format": "ELM", + "path": "$.credentialSubject.hasClaim[0].specifiedBy.title.*.[0]" + }, + "destination": { + "format": "OBv3", + "path": "$.credentialSubject.achievement.name" + } + }, + { + "type_": "copy", + "source": { + "format": "ELM", + "path": "$.validFrom" + }, + "destination": { + "format": "OBv3", + "path": "$.validFrom" + } + }, + { + "type_": "copy", + "source": { + "format": "ELM", + "path": "$.credentialSubject.hasClaim[0].title.en[0]" + }, + "destination": { + "format": "OBv3", + "path": "$.name" + } + }, + { + "type_": "copy", + "source": { + "format": "ELM", + "path": "$.credentialSubject.id" + }, + "destination": { + "format": "OBv3", + "path": "$.credentialSubject.id" + } + }, + { + "type_": "stringArrayIt", + "source": { + "value": ["AchievementSubject", "profile"] + }, + "destination": { + "format": "OBv3", + "path": "$.credentialSubject.type" + } + }, + { + "type_": "copy", + "source": { + "format": "ELM", + "path": "$.credentialSubject.id" + }, + "destination": { + "format": "OBv3", + "path": "$.credentialSubject.id" + } + }, + { + "type_": "copy", + "source": { + "format": "ELM", + "path": "$.proof" + }, + "destination": { + "format": "OBv3", + "path": "$.proof" + } + }, + { + "type_": "jsonToMarkdown", + "source": { + "format": "ELM", + "path": "$.credentialSubject.hasClaim[0].specifiedBy.learningOutcome[0]" + }, + "destination": { + "format": "OBv3", + "path": "$.credentialSubject.achievement.criteria.narrative" + } + }, + { + "type_": "copy", + "source": { + "format": "ELM", + "path": "$.credentialSchema" + }, + "destination": { + "format": "OBv3", + "path": "$.credentialSchema" + } + }, + { + "type_": "copy", + "source": { + "format": "ELM", + "path": "$.credentialStatus" + }, + "destination": { + "format": "OBv3", + "path": "$.credentialStatus" + } + }, + { + "type_": "addIdentifier", + "source": { + "format": "ELM", + "datatype": "ext:studentID", + "path": "$.credentialSubject.identifier[0].notation" + }, + "destination": { + "format": "OBv3", + "path": "$.credentialSubject.identifier[0]" + } + }, + { + "type_": "copy", + "source": { + "format": "ELM", + "path": "$.credentialSubject.givenName.en[0]" + }, + "destination": { + "format": "OBv3", + "path": "$.credentialSubject.givenName" + } + }, + { + "type_": "copy", + "source": { + "format": "ELM", + "path": "$.credentialSubject.familyName.en[0]" + }, + "destination": { + "format": "OBv3", + "path": "$.credentialSubject.familyName" + } + }, + { + "type_": "copy", + "source": { + "format": "ELM", + "path": "$.credentialSubject.fullName.en[0]" + }, + "destination": { + "format": "OBv3", + "path": "$.credentialSubject.fullName" + } + } + + +] \ No newline at end of file diff --git a/json/mapping/custom_mapping_ELM_OBv3_latest_copy.json b/json/mapping/custom_mapping_ELM_OBv3_latest_copy.json new file mode 100644 index 0000000..fe8456d --- /dev/null +++ b/json/mapping/custom_mapping_ELM_OBv3_latest_copy.json @@ -0,0 +1,187 @@ +[ + { + "type_": "copy", + "source": { + "format": "ELM", + "path": "$.@context" + }, + "destination": { + "format": "OBv3", + "path": "$.@context" + } + }, + { + "type_": "copy", + "source": { + "format": "ELM", + "path": "$.id" + }, + "destination": { + "format": "OBv3", + "path": "$.id" + } + }, + { + "type_": "copy", + "source": { + "format": "ELM", + "path": "$.type" + }, + "destination": { + "format": "OBv3", + "path": "$.type" + } + }, + { + "type_": "copy", + "source": { + "format": "ELM", + "path": "$.issuer.id" + }, + "destination": { + "format": "OBv3", + "path": "$.issuer.id" + } + }, + { + "type_": "stringit", + "source": { + "value": "Profile" + }, + "destination": { + "format": "OBv3", + "path": "$.issuer.type[]" + } + }, + { + "type_": "copy", + "source": { + "format": "ELM", + "path": "$.issuer.legalName.en" + }, + "destination": { + "format": "OBv3", + "path": "$.issuer.name" + } + }, + { + "type_": "copy", + "source": { + "format": "ELM", + "path": "$.credentialSubject.hasClaim[0].id" + }, + "destination": { + "format": "OBv3", + "path": "$.credentialSubject.achievement.id" + } + }, + { + "type_": "stringit", + "source": { + "value": "Achievement" + }, + "destination": { + "format": "OBv3", + "path": "$.credentialSubject.achievement.type[]" + } + }, + { + "type_": "copy", + "source": { + "format": "ELM", + "path": "$.credentialSubject.hasClaim[0].id" + }, + "destination": { + "format": "OBv3", + "path": "$.credentialSubject.achievement.id" + } + }, + { + "type_": "copy", + "source": { + "format": "ELM", + "path": "$.credentialSubject.hasClaim[0].specifiedBy.title[0]" + }, + "destination": { + "format": "OBv3", + "path": "$.credentialSubject.achievement.name" + } + }, + { + "type_": "copy", + "source": { + "format": "ELM", + "path": "$.credentialSubject.hasClaim[0].specifiedBy.learningOutcome" + }, + "destination": { + "format": "OBv3", + "path": "$.credentialSubject.achievement.criteria.narrative" + } + }, + { + "type_": "copy", + "source": { + "format": "ELM", + "path": "$.validFrom" + }, + "destination": { + "format": "OBv3", + "path": "$.validFrom" + } + }, + { + "type_": "copy", + "source": { + "format": "ELM", + "path": "$.credentialSubject.hasClaim[0].title.en[0]" + }, + "destination": { + "format": "OBv3", + "path": "$.name" + } + }, + { + "type_": "copy", + "source": { + "format": "ELM", + "path": "$.credentialSubject.id" + }, + "destination": { + "format": "OBv3", + "path": "$.credentialSubject.id" + } + }, + { + "type_": "stringit", + "source": { + "value": "AchievementSubject" + }, + "destination": { + "format": "OBv3", + "path": "$.credentialSubject.type[]" + } + }, + { + "type_": "copy", + "source": { + "format": "ELM", + "path": "$.credentialSubject.id" + }, + "destination": { + "format": "OBv3", + "path": "$.credentialSubject.id" + } + }, + { + "type_": "copy", + "source": { + "format": "ELM", + "path": "$.proof" + }, + "destination": { + "format": "OBv3", + "path": "$.proof" + } + } + +] \ No newline at end of file diff --git a/json/mapping/custom_mapping_OBv3_ELM_latest.json b/json/mapping/custom_mapping_OBv3_ELM_latest.json new file mode 100644 index 0000000..f8e50b8 --- /dev/null +++ b/json/mapping/custom_mapping_OBv3_ELM_latest.json @@ -0,0 +1,416 @@ +[ + { + "type_": "copy", + "source": { + "format": "OBv3", + "path": "$.@context" + }, + "destination": { + "format": "ELM", + "path": "$.@context" + } + }, + { + "type_": "copy", + "source": { + "format": "OBv3", + "path": "$.id" + }, + "destination": { + "format": "ELM", + "path": "$.id" + } + }, + { + "type_": "stringArrayIt", + "source": { + "value": ["VerifiableCredential", "VerifiableAttestation", "EuropeanDigitalCredential"] + }, + "destination": { + "format": "ELM", + "path": "$.type" + } + }, + { + "type_": "copy", + "source": { + "format": "OBv3", + "path": "$.issuer.id" + }, + "destination": { + "format": "ELM", + "path": "$.issuer.id" + } + }, + { + "type_": "stringit", + "source": { + "value": "Organisation" + }, + "destination": { + "format": "ELM", + "path": "$.issuer.type" + } + }, + { + "type_": "copy", + "source": { + "format": "OBv3", + "path": "$.issuer.name" + }, + "destination": { + "format": "ELM", + "path": "$.issuer.legalName.en" + } + }, + { + "type_": "addressToLocation", + "source": { + "format": "OBv3", + "path": "$.issuer.address" + }, + "destination": { + "format": "ELM", + "path": "$.issuer.location" + } + }, + { + "type_": "imageToMediaObject", + "source": { + "format": "OBv3", + "path": "$.issuer.image" + }, + "destination": { + "format": "ELM", + "path": "$.issuer.logo" + } + }, + + + + { + "type_": "copy", + "source": { + "format": "OBv3", + "path": "$.validFrom" + }, + "destination": { + "format": "ELM", + "path": "$.validFrom" + } + }, + { + "type_": "copy", + "source": { + "format": "OBv3", + "path": "$.validFrom" + }, + "destination": { + "format": "ELM", + "path": "$.issuanceDate" + } + }, + { + "type_": "copy", + "source": { + "format": "OBv3", + "path": "$.validFrom" + }, + "destination": { + "format": "ELM", + "path": "$.issued" + } + }, + + + { + "type_": "copy", + "source": { + "format": "OBv3", + "path": "$.credentialSubject.id" + }, + "destination": { + "format": "ELM", + "path": "$.credentialSubject.id" + } + }, + { + "type_": "stringit", + "source": { + "value": "Person" + }, + "destination": { + "format": "ELM", + "path": "$.credentialSubject.type" + } + }, + { + "type_": "identifierToObject", + "source": { + "format": "OBv3", + "datatype": "Student ID", + "path": "$.credentialSubject.identifier[0]" + }, + "destination": { + "format": "ELM", + "path": "$.credentialSubject.identifier" + } + }, + { + "type_": "identifierToObject", + "source": { + "format": "OBv3", + "datatype": "ext:fullName", + "path": "$.credentialSubject.identifier[0]" + }, + "destination": { + "format": "ELM", + "path": "$.credentialSubject.fullName.en[0]" + } + }, + + + + { + "type_": "imageToIndividualDisplay", + "source": { + "format": "OBv3", + "path": "$.credentialSubject.achievement.image" + }, + "destination": { + "format": "ELM", + "path": "$.displayParameter" + } + }, + { + "type_": "stringit", + "source": { + "value": "LearningAchievement" + }, + "destination": { + "format": "ELM", + "path": "$.credentialSubject.hasClaim[0].type" + } + }, + { + "type_": "stringit", + "source": { + "value": "urn:epass:awardingProcess:1" + }, + "destination": { + "format": "ELM", + "path": "$.credentialSubject.hasClaim[0].awardedBy.id" + } + }, + { + "type_": "stringit", + "source": { + "value": "AwardingProcess" + }, + "destination": { + "format": "ELM", + "path": "$.credentialSubject.hasClaim[0].awardedBy.type" + } + }, + { + "type_": "copy", + "source": { + "format": "OBv3", + "path": "$.issuer.id" + }, + "destination": { + "format": "ELM", + "path": "$.credentialSubject.hasClaim[0].awardedBy.awardingBody[0].id" + } + }, + { + "type_": "stringit", + "source": { + "value": "Organisation" + }, + "destination": { + "format": "ELM", + "path": "$.credentialSubject.hasClaim[0].awardedBy.awardingBody[0].type" + } + }, + { + "type_": "copy", + "source": { + "format": "OBv3", + "path": "$.issuer.name" + }, + "destination": { + "format": "ELM", + "path": "$.credentialSubject.hasClaim[0].awardedBy.awardingBody[0].legalName.en[0]" + } + }, + { + "type_": "addressToLocation", + "source": { + "format": "OBv3", + "path": "$.issuer.address" + }, + "destination": { + "format": "ELM", + "path": "$.credentialSubject.hasClaim[0].awardedBy.awardingBody[0].location" + } + }, + + { + "type_": "copy", + "source": { + "format": "OBv3", + "path": "$.credentialSubject.achievement.name" + }, + "destination": { + "format": "ELM", + "path": "$.credentialSubject.hasClaim[0].title.en[0]" + } + }, + { + "type_": "copy", + "source": { + "format": "OBv3", + "path": "$.credentialSubject.achievement.description" + }, + "destination": { + "format": "ELM", + "path": "$.credentialSubject.hasClaim[0].description.en[0]" + } + }, + + { + "type_": "copy", + "source": { + "format": "OBv3", + "path": "$.credentialSubject.achievement.id" + }, + "destination": { + "format": "ELM", + "path": "$.credentialSubject.hasClaim[0].id" + } + }, + { + "type_": "copy", + "source": { + "format": "OBv3", + "path": "$.credentialSchema" + }, + "destination": { + "format": "ELM", + "path": "$.credentialSchema" + } + }, + { + "type_": "titleToSpecifiedByObject", + "source": { + "format": "OBv3", + "path": "$.credentialSubject.achievement.name" + }, + "destination": { + "format": "ELM", + "path": "$.credentialSubject.hasClaim[0].specifiedBy" + } + }, + { + "type_": "creditToSpecifiedByObject", + "source": { + "format": "OBv3", + "path": "$.credentialSubject.achievement.creditsAvailable" + }, + "destination": { + "format": "ELM", + "path": "$.credentialSubject.hasClaim[0].specifiedBy.creditPoint[0]" + } + }, + { + "type_": "eqfToSpecifiedByQualification", + "source": { + "format": "OBv3", + "path": "$.credentialSubject.achievement.alignment" + }, + "destination": { + "format": "ELM", + "path": "$.credentialSubject.hasClaim[0].specifiedBy.eqfLevel" + } + }, + { + "type_": "translateLearningOutcome", + "source": { + "format": "OBv3", + "path": "$.credentialSubject.achievement.alignment" + }, + "destination": { + "format": "ELM", + "path": "$.credentialSubject.hasClaim[0].specifiedBy.learningOutcome" + } + }, + { + "type_": "createLearningOutcomeSummary", + "source": { + "format": "OBv3", + "path": "$.credentialSubject.achievement.criteria.narrative" + }, + "destination": { + "format": "ELM", + "path": "$.credentialSubject.hasClaim[0].specifiedBy.learningOutcomeSummary" + } + }, + + + { + "type_": "assessmentToProvenBy", + "source": { + "format": "OBv3", + "path": "$.credentialSubject.achievement.assessmentType" + }, + "destination": { + "format": "ELM", + "path": "$.credentialSubject.hasClaim[0].provenBy[0]" + } + }, + { + "type_": "addressToLocation", + "source": { + "format": "OBv3", + "path": "$.issuer.address" + }, + "destination": { + "format": "ELM", + "path": "$.credentialSubject.hasClaim[0].provenBy[0].awardedBy.awardingBody[0].location" + } + }, + { + "type_": "copy", + "source": { + "format": "OBv3", + "path": "$.issuer.name" + }, + "destination": { + "format": "ELM", + "path": "$.credentialSubject.hasClaim[0].provenBy[0].awardedBy.awardingBody[0].legalName.en[0]" + } + }, + { + "type_": "objectToNoteLiteral", + "source": { + "format": "OBv3", + "path": "$.credentialSubject.result" + }, + "destination": { + "format": "ELM", + "path": "$.credentialSubject.hasClaim[0].provenBy[0].grade.noteLiteral.en[0]" + } + }, + { + "type_": "learningSettingToSpecifiedByObject", + "source": { + "format": "OBv3", + "path": "$.credentialSubject.achievement.learningSetting" + }, + "destination": { + "format": "ELM", + "path": "$.credentialSubject.hasClaim[0].specifiedBy.learningSetting" + } + } +] \ No newline at end of file diff --git a/json/mapping/custom_mapping_OBv3_ELM_latest_copy.json b/json/mapping/custom_mapping_OBv3_ELM_latest_copy.json new file mode 100644 index 0000000..6e7047d --- /dev/null +++ b/json/mapping/custom_mapping_OBv3_ELM_latest_copy.json @@ -0,0 +1,135 @@ +[ + { + "type_": "copy", + "source": { + "format": "OBv3", + "path": "$.@context" + }, + "destination": { + "format": "ELM", + "path": "$.@context" + } + }, + { + "type_": "copy", + "source": { + "format": "OBv3", + "path": "$.id" + }, + "destination": { + "format": "ELM", + "path": "$.id" + } + }, + { + "type_": "copy", + "source": { + "format": "OBv3", + "path": "$.type" + }, + "destination": { + "format": "ELM", + "path": "$.type" + } + }, + { + "type_": "copy", + "source": { + "format": "OBv3", + "path": "$.issuer.id" + }, + "destination": { + "format": "ELM", + "path": "$.issuer.id" + } + }, + { + "type_": "copy", + "source": { + "format": "OBv3", + "path": "$.issuer.name" + }, + "destination": { + "format": "ELM", + "path": "$.issuer.legalName.en" + } + }, + { + "type_": "copy", + "source": { + "format": "OBv3", + "path": "$.credentialSubject.achievement.id" + }, + "destination": { + "format": "ELM", + "path": "$.credentialSubject.hasClaim[0].id" + } + }, + { + "type_": "copy", + "source": { + "format": "OBv3", + "path": "$.credentialSubject.achievement.name" + }, + "destination": { + "format": "ELM", + "path": "$.credentialSubject.hasClaim[0].specifiedBy.title.en[0]" + } + }, + { + "type_": "copy", + "source": { + "format": "OBv3", + "path": "$.validFrom" + }, + "destination": { + "format": "ELM", + "path": "$.validFrom" + } + }, + { + "type_": "copy", + "source": { + "format": "OBv3", + "path": "$.name" + }, + "destination": { + "format": "ELM", + "path": "$.credentialSubject.hasClaim[0].title.en[0]" + } + }, + { + "type_": "copy", + "source": { + "format": "OBv3", + "path": "$.credentialSubject.id" + }, + "destination": { + "format": "ELM", + "path": "$.credentialSubject.id" + } + }, + { + "type_": "copy", + "source": { + "format": "OBv3", + "path": "$.proof" + }, + "destination": { + "format": "ELM", + "path": "$.proof" + } + }, + { + "type_": "markdownToJson", + "source": { + "format": "OBv3", + "path": "$.credentialSubject.achievement.criteria.narrative" + }, + "destination": { + "format": "ELM", + "path": "$.credentialSubject.hasClaim[0].specifiedBy.learningOutcome[0]" + } + } + +] \ No newline at end of file diff --git a/json/mapping/custom_mapping_OBv3_ELM_org_250108.json b/json/mapping/custom_mapping_OBv3_ELM_org_250108.json new file mode 100644 index 0000000..589b00e --- /dev/null +++ b/json/mapping/custom_mapping_OBv3_ELM_org_250108.json @@ -0,0 +1,235 @@ +[ + { + "type_": "copy", + "source": { + "format": "OBv3", + "path": "$.@context" + }, + "destination": { + "format": "ELM", + "path": "$.@context" + } + }, + { + "type_": "copy", + "source": { + "format": "OBv3", + "path": "$.id" + }, + "destination": { + "format": "ELM", + "path": "$.id" + } + }, + { + "type_": "stringArrayIt", + "source": { + "value": ["VerifiableCredential", "VerifiableAttestation", "EuropeanDigitalCredential"] + }, + "destination": { + "format": "ELM", + "path": "$.type" + } + }, + { + "type_": "copy", + "source": { + "format": "OBv3", + "path": "$.issuer.id" + }, + "destination": { + "format": "ELM", + "path": "$.issuer.id" + } + }, + { + "type_": "copy", + "source": { + "format": "OBv3", + "path": "$.issuer.name" + }, + "destination": { + "format": "ELM", + "path": "$.issuer.legalName.en" + } + }, + { + "type_": "copy", + "source": { + "format": "OBv3", + "path": "$.validFrom" + }, + "destination": { + "format": "ELM", + "path": "$.validFrom" + } + }, + { + "type_": "copy", + "source": { + "format": "OBv3", + "path": "$.validFrom" + }, + "destination": { + "format": "ELM", + "path": "$.issuanceDate" + } + }, + { + "type_": "copy", + "source": { + "format": "OBv3", + "path": "$.validFrom" + }, + "destination": { + "format": "ELM", + "path": "$.issued" + } + }, + { + "type_": "copy", + "source": { + "format": "OBv3", + "path": "$.credentialSubject.id" + }, + "destination": { + "format": "ELM", + "path": "$.credentialSubject.id" + } + }, + { + "type_": "stringit", + "source": { + "value": "Person" + }, + "destination": { + "format": "ELM", + "path": "$.credentialSubject.type" + } + }, + { + "type_": "markdownToJson", + "source": { + "format": "OBv3", + "path": "$.credentialSubject.achievement.criteria.narrative" + }, + "destination": { + "format": "ELM", + "path": "$.credentialSubject.hasClaim[0].specifiedBy.learningOutcome[0]" + } + }, + { + "type_": "imageToIndividualDisplay", + "source": { + "format": "OBv3", + "path": "$.image" + }, + "destination": { + "format": "ELM", + "path": "$.displayParameter" + } + }, + { + "type_": "copy", + "source": { + "format": "OBv3", + "path": "$.name" + }, + "destination": { + "format": "ELM", + "path": "$.credentialSubject.hasClaim[0].title.en[0]" + } + }, + { + "type_": "copy", + "source": { + "format": "OBv3", + "path": "$.credentialSubject.achievement.id" + }, + "destination": { + "format": "ELM", + "path": "$.credentialSubject.hasClaim[0].id" + } + }, + { + "type_": "copy", + "source": { + "format": "OBv3", + "path": "$.credentialSubject.achievement.name" + }, + "destination": { + "format": "ELM", + "path": "$.credentialSubject.hasClaim[0].specifiedBy.title.en[0]" + } + }, + { + "type_": "copy", + "source": { + "format": "OBv3", + "path": "$.credentialSchema" + }, + "destination": { + "format": "ELM", + "path": "$.credentialSchema" + } + }, + { + "type_": "copy", + "source": { + "format": "OBv3", + "path": "$.credentialStatus" + }, + "destination": { + "format": "ELM", + "path": "$.credentialStatus" + } + }, + { + "type_": "identifierToObject", + "source": { + "format": "OBv3", + "datatype": "Student ID", + "path": "$.credentialSubject.identifier[0]" + }, + "destination": { + "format": "ELM", + "path": "$.credentialSubject.identifier" + } + }, + { + "type_": "identifierToObject", + "source": { + "format": "OBv3", + "datatype": "ext:givenName", + "path": "$.credentialSubject.identifier[1]" + }, + "destination": { + "format": "ELM", + "path": "$.credentialSubject.givenName.en[0]" + } + }, + { + "type_": "identifierToObject", + "source": { + "format": "OBv3", + "datatype": "ext:familyName", + "path": "$.credentialSubject.identifier[2]" + }, + "destination": { + "format": "ELM", + "path": "$.credentialSubject.givenName" + } + }, + { + "type_": "identifierToObject", + "source": { + "format": "OBv3", + "datatype": "ext:fullName", + "path": "$.credentialSubject.identifier[3]" + }, + "destination": { + "format": "ELM", + "path": "$.credentialSubject.fullName" + } + } +] \ No newline at end of file diff --git a/json/mapping/custom_mapping_example_OB2ELM.json b/json/mapping/custom_mapping_example_OB2ELM.json new file mode 100644 index 0000000..5c3edfe --- /dev/null +++ b/json/mapping/custom_mapping_example_OB2ELM.json @@ -0,0 +1,275 @@ +[ + { + "type_": "copy", + "source": { + "format": "OBv3", + "path": "$.@context" + }, + "destination": { + "format": "ELM", + "path": "$.@context" + } + }, + { + "type_": "copy", + "source": { + "format": "OBv3", + "path": "$.id" + }, + "destination": { + "format": "ELM", + "path": "$.id" + } + }, + { + "type_": "stringArrayIt", + "source": { + "value": ["VerifiableCredential", "VerifiableAttestation", "EuropeanDigitalCredential"] + }, + "destination": { + "format": "ELM", + "path": "$.type" + } + }, + { + "type_": "copy", + "source": { + "format": "OBv3", + "path": "$.issuer.id" + }, + "destination": { + "format": "ELM", + "path": "$.issuer.id" + } + }, + { + "type_": "copy", + "source": { + "format": "OBv3", + "path": "$.issuer.name" + }, + "destination": { + "format": "ELM", + "path": "$.issuer.legalName.en" + } + }, + { + "type_": "stringit", + "source": { + "value": "Organisation" + }, + "destination": { + "format": "ELM", + "path": "$.issuer.type" + } + }, + + { + "type_": "copy", + "source": { + "format": "OBv3", + "path": "$.validFrom" + }, + "destination": { + "format": "ELM", + "path": "$.validFrom" + } + }, + { + "type_": "copy", + "source": { + "format": "OBv3", + "path": "$.validFrom" + }, + "destination": { + "format": "ELM", + "path": "$.issuanceDate" + } + }, + { + "type_": "copy", + "source": { + "format": "OBv3", + "path": "$.validFrom" + }, + "destination": { + "format": "ELM", + "path": "$.issued" + } + }, + { + "type_": "copy", + "source": { + "format": "OBv3", + "path": "$.credentialSubject.id" + }, + "destination": { + "format": "ELM", + "path": "$.credentialSubject.id" + } + }, + { + "type_": "stringit", + "source": { + "value": "Person" + }, + "destination": { + "format": "ELM", + "path": "$.credentialSubject.type" + } + }, + { + "type_": "imageToIndividualDisplay", + "source": { + "format": "OBv3", + "path": "$.credentialSubject.achievement.image" + }, + "destination": { + "format": "ELM", + "path": "$.displayParameter" + } + }, + { + "type_": "stringit", + "source": { + "value": "LearningAchievement" + }, + "destination": { + "format": "ELM", + "path": "$.credentialSubject.hasClaim[0].type" + } + }, + { + "type_": "stringit", + "source": { + "value": "urn:epass:awardingProcess:1" + }, + "destination": { + "format": "ELM", + "path": "$.credentialSubject.hasClaim[0].awardedBy.id" + } + }, + { + "type_": "stringit", + "source": { + "value": "AwardingProcess" + }, + "destination": { + "format": "ELM", + "path": "$.credentialSubject.hasClaim[0].awardedBy.type" + } + }, + { + "type_": "copy", + "source": { + "format": "OBv3", + "path": "$.issuer.id" + }, + "destination": { + "format": "ELM", + "path": "$.credentialSubject.hasClaim[0].awardedBy.awardingBody[0].id" + } + }, + { + "type_": "stringit", + "source": { + "value": "Organisation" + }, + "destination": { + "format": "ELM", + "path": "$.credentialSubject.hasClaim[0].awardedBy.awardingBody[0].type" + } + }, + { + "type_": "copy", + "source": { + "format": "OBv3", + "path": "$.issuer.name" + }, + "destination": { + "format": "ELM", + "path": "$.credentialSubject.hasClaim[0].awardedBy.awardingBody[0].legalName.en[0]" + } + }, + { + "type_": "copy", + "source": { + "format": "OBv3", + "path": "$.name" + }, + "destination": { + "format": "ELM", + "path": "$.credentialSubject.hasClaim[0].title.en[0]" + } + }, + { + "type_": "copy", + "source": { + "format": "OBv3", + "path": "$.credentialSubject.achievement.id" + }, + "destination": { + "format": "ELM", + "path": "$.credentialSubject.hasClaim[0].id" + } + }, + { + "type_": "copy", + "source": { + "format": "OBv3", + "path": "$.credentialSchema" + }, + "destination": { + "format": "ELM", + "path": "$.credentialSchema" + } + }, + { + "type_": "identifierToObject", + "source": { + "format": "OBv3", + "datatype": "Student ID", + "path": "$.credentialSubject.identifier[0]" + }, + "destination": { + "format": "ELM", + "path": "$.credentialSubject.identifier" + } + }, + { + "type_": "identifierToObject", + "source": { + "format": "OBv3", + "datatype": "ext:givenName", + "path": "$.credentialSubject.identifier[1]" + }, + "destination": { + "format": "ELM", + "path": "$.credentialSubject.fullName.en[0]" + } + }, + { + "type_": "identifierToObject", + "source": { + "format": "OBv3", + "datatype": "ext:familyName", + "path": "$.credentialSubject.identifier[2]" + }, + "destination": { + "format": "ELM", + "path": "$.credentialSubject.fullName" + } + }, + { + "type_": "identifierToObject", + "source": { + "format": "OBv3", + "datatype": "ext:fullName", + "path": "$.credentialSubject.identifier[3]" + }, + "destination": { + "format": "ELM", + "path": "$.credentialSubject.fullName" + } + } +] \ No newline at end of file diff --git a/json/obv3/contexts/educredential.json b/json/obv3/contexts/educredential.json new file mode 100644 index 0000000..96fc98a --- /dev/null +++ b/json/obv3/contexts/educredential.json @@ -0,0 +1,88 @@ +{ + "@context": { + "@protected": true, + "id": "@id", + "type": "@type", + "EducredentialAchievement": { + "@id": "https://edubadges.nl/static/obv3-glossary.html#EducredentialAchievement", + "@context": { + "@protected": true, + "id": "@id", + "type": "@type", + "assessmentType": { + "@id": "https://edubadges.nl/static/obv3-glossary.html#assessmentType", + "@type": "@vocab", + "@context": { + "testing": "https://edubadges.nl/static/obv3-glossary.html#assessment-type-testing", + "application of a skill": "https://eduabages.nl/static/obv3-glossary.html#assessment-type-application-of-a-skill", + "portfolio": "https://eduabages.nl/static/obv3-glossary.html#assessment-type-portfolio", + "recognition of prior learning": "https://edubadges.nl/static/obv3-glossary.html#assessment-type-recognition-of-prior-learning" + } + }, + "identityChecked": { + "@id": "https://edubadges.nl/static/obv3-glossary.html#identityChecked", + "@type": "xsd:boolean" + }, + "participationType": { + "@id": "https://edubadges.nl/static/obv3-glossary.html#participationType", + "@type": "@vocab", + "@context": { + "online": "https://edubadges.nl/static/obv3-glossary.html#participation-type-online", + "onsite or blended": "https://edubadges.nl/static/obv3-glossary.html#participation-type-onsite-or-blended", + "volunteering": "https://edubadges.nl/static/obv3-glossary.html#participation-type-volunteering", + "work experience": "https://edubadges.nl/static/obv3-glossary.html#participation-type-work-experience", + "personalized learning activities": "https://edubadges.nl/static/obv3-glossary.html#participation-type-personalized-learning-activities" + } + }, + "supervisionType": { + "@id": "https://edubadges.nl/static/obv3-glossary.html#supervisionType", + "@type": "@vocab", + "context": { + "unsupervised with no identity verification": "https://edubadges.nl/static/obv3-glossary.html#supervision-type-unsupervised-with-no-identity-verification", + "supervised with no identity verification": "https://edubadges.nl/static/obv3-glossary.html#supervision-type-supervised-with-no-identity-verification", + "supervised online": "https://edubaadges.nl/static/obv3-glossary.html#supervision-type-supervised-online", + "onsite with identity verification": "https://edubadges.nl/static/obv3-glossary.html#supervision-type-onsite-with-identity-verification" + } + }, + "ECTS": { + "@id": "https://edubadges.nl/static/obv3-glossary.html#ects", + "@type": "xsd:integer" + }, + "timeInvestment": { + "@id": "https://edubadges.nl/static/obv3-glossary.html#timeInvestment", + "@type": "xsd:integer" + }, + "SBU": { + "@id": "https://edubadges.nl/static/obv3-glossary.html#sbu", + "@type": "xsd:integer" + }, + "educationProgramIdentifier": { + "@id": "https://edubadges.nl/static/obv3-glossary.html#educationProgramIdentifier", + "@type": "xsd:number" + }, + "learningOutcome": { + "@context": { + "@protected": true, + "id": "@id", + "type": "@type", + "relations": { + "@id": "https://purl.imsglobal.org/spec/vc/ob/vocab.html#alignment", + "@container": "@set" + } + } + }, + "FrameworkAlignment": { + "@context": { + "@protected": true, + "id": "@id", + "type": "@type", + "frameworkUrl": { + "@id": "https://schema.org/targetUrl", + "@type": "https://www.w3.org/2001/XMLSchema#anyURI" + } + } + } + } + } + } +} \ No newline at end of file diff --git a/json/obv3/examples/Complete_OpenBadgeCredential_image.json b/json/obv3/examples/Complete_OpenBadgeCredential_image.json new file mode 100644 index 0000000..82a627e --- /dev/null +++ b/json/obv3/examples/Complete_OpenBadgeCredential_image.json @@ -0,0 +1,663 @@ +{ + "@context": [ + "https://www.w3.org/ns/credentials/v2", + "https://purl.imsglobal.org/spec/ob/v3p0/context-3.0.3.json", + "https://purl.imsglobal.org/spec/ob/v3p0/extensions.json" + ], + "id": "http://1edtech.edu/credentials/3732", + "type": [ + "VerifiableCredential", + "OpenBadgeCredential" + ], + "name": "1EdTech University Degree for Example Student", + "description": "1EdTech University Degree Description", + "image": { + "id": "https://raw.githubusercontent.com/hamrt/credential-converter/refs/heads/image/test/1EDTECH_logo_100x100.png", + "type": "Image", + "caption": "1EdTech University Degree for Example Student" + }, + "credentialSubject": { + "id": "did:example:ebfeb1f712ebc6f1c276e12ec21", + "type": [ + "AchievementSubject" + ], + "activityEndDate": "2010-01-02T00:00:00Z", + "activityStartDate": "2010-01-01T00:00:00Z", + "creditsEarned": 42, + "licenseNumber": "A-9320041", + "role": "Major Domo", + "source": { + "id": "https://school.edu/issuers/201234", + "type": [ + "Profile" + ], + "name": "1EdTech College of Arts" + }, + "term": "Fall", + "identifier": [ + { + "type": "IdentityObject", + "identityHash": "student@1edtech.edu", + "identityType": "emailAddress", + "hashed": false, + "salt": "not-used" + }, + { + "type": "IdentityObject", + "identityHash": "somebody@gmail.com", + "identityType": "emailAddress", + "hashed": false, + "salt": "not-used" + } + ], + "achievement": { + "id": "https://1edtech.edu/achievements/degree", + "type": [ + "Achievement" + ], + "alignment": [ + { + "type": [ + "Alignment" + ], + "targetCode": "degree", + "targetDescription": "1EdTech University Degree programs.", + "targetName": "1EdTech University Degree", + "targetFramework": "1EdTech University Program and Course Catalog", + "targetType": "CFItem", + "targetUrl": "https://1edtech.edu/catalog/degree" + }, + { + "type": [ + "Alignment" + ], + "targetCode": "degree", + "targetDescription": "1EdTech University Degree programs.", + "targetName": "1EdTech University Degree", + "targetFramework": "1EdTech University Program and Course Catalog", + "targetType": "CTDL", + "targetUrl": "https://credentialengineregistry.org/resources/ce-98cb027b-95ef-4494-908d-6f7790ec6b6b" + } + ], + "achievementType": "Degree", + "creator": { + "id": "https://1edtech.edu/issuers/565049", + "type": [ + "Profile" + ], + "name": "1EdTech University", + "url": "https://1edtech.edu", + "phone": "1-222-333-4444", + "description": "1EdTech University provides online degree programs.", + "endorsement": [ + { + "@context": [ + "https://www.w3.org/ns/credentials/v2", + "https://purl.imsglobal.org/spec/ob/v3p0/context-3.0.3.json" + ], + "id": "http://1edtech.edu/endorsementcredential/3732", + "type": [ + "VerifiableCredential", + "EndorsementCredential" + ], + "name": "SDE endorsement", + "issuer": { + "id": "https://accrediter.edu/issuers/565049", + "type": [ + "Profile" + ], + "name": "Example Accrediting Agency" + }, + "validFrom": "2010-01-01T00:00:00Z", + "validUntil": "2020-01-01T00:00:00Z", + "credentialSubject": { + "id": "https://1edtech.edu/issuers/565049", + "type": [ + "EndorsementSubject" + ], + "endorsementComment": "1EdTech University is in good standing" + }, + "credentialSchema": [ + { + "id": "https://purl.imsglobal.org/spec/ob/v3p0/schema/json/ob_v3p0_endorsementcredential_schema.json", + "type": "1EdTechJsonSchemaValidator2019" + }, + { + "id": "https://accrediter.edu/schema/endorsementcredential.json", + "type": "1EdTechJsonSchemaValidator2019" + } + ], + "credentialStatus": { + "id": "https://1edtech.edu/credentials/3732/revocations", + "type": "1EdTechRevocationList" + }, + "refreshService": { + "id": "http://1edtech.edu/credentials/3732", + "type": "1EdTechCredentialRefresh" + }, + "proof": [ + { + "type": "DataIntegrityProof", + "cryptosuite": "eddsa-rdf-2022", + "created": "2022-05-26T18:17:08Z", + "verificationMethod": "https://accrediter.edu/issuers/565049#zvPkQiUFfJrgnCRhyPkTSkgrGXbnLR15pHH5HZVYNdM4TCAwQHqG7fMeMPLtYNRnEgoV1aJdR5E61eWu5sWRYgtA", + "proofPurpose": "assertionMethod", + "proofValue": "zvPkQiUFfJrgnCRhyPkTSkgrGXbnLR15pHH5HZVYNdM4TCAwQHqG7fMeMPLtYNRnEgoV1aJdR5E61eWu5sWRYgtA" + } + ] + }, + { + "@context": [ + "https://www.w3.org/ns/credentials/v2", + "https://purl.imsglobal.org/spec/ob/v3p0/context-3.0.3.json" + ], + "id": "http://1edtech.edu/endorsementcredential/3733", + "type": [ + "VerifiableCredential", + "EndorsementCredential" + ], + "name": "SDE endorsement", + "issuer": { + "id": "https://state.gov/issuers/565049", + "type": [ + "Profile" + ], + "name": "State Department of Education" + }, + "validFrom": "2010-01-01T00:00:00Z", + "validUntil": "2020-01-01T00:00:00Z", + "credentialSubject": { + "id": "https://1edtech.edu/issuers/565049", + "type": [ + "EndorsementSubject" + ], + "endorsementComment": "1EdTech University is in good standing" + }, + "credentialSchema": [ + { + "id": "https://purl.imsglobal.org/spec/ob/v3p0/schema/json/ob_v3p0_endorsementcredential_schema.json", + "type": "1EdTechJsonSchemaValidator2019" + }, + { + "id": "https://state.gov/schema/endorsementcredential.json", + "type": "1EdTechJsonSchemaValidator2019" + } + ], + "credentialStatus": { + "id": "https://state.gov/credentials/3732/revocations", + "type": "1EdTechRevocationList" + }, + "refreshService": { + "id": "http://state.gov/credentials/3732", + "type": "1EdTechCredentialRefresh" + }, + "proof": [ + { + "type": "DataIntegrityProof", + "cryptosuite": "eddsa-rdf-2022", + "created": "2022-05-26T18:25:59Z", + "verificationMethod": "https://accrediter.edu/issuers/565049#z5bDnmSgDczXwZGya6ZjxKaxkdKxzsCMiVSsgEVWxnaWK7ZqbKnzcCd7mUKE9DQaAL2QMXP5AquPeW6W2CWrZ7jNC", + "proofPurpose": "assertionMethod", + "proofValue": "z5bDnmSgDczXwZGya6ZjxKaxkdKxzsCMiVSsgEVWxnaWK7ZqbKnzcCd7mUKE9DQaAL2QMXP5AquPeW6W2CWrZ7jNC" + } + ] + } + ], + "image": { + "id": "https://1edtech.edu/logo.png", + "type": "Image", + "caption": "1EdTech University logo" + }, + "email": "registrar@1edtech.edu", + "address": { + "type": [ + "Address" + ], + "addressCountry": "USA", + "addressCountryCode": "US", + "addressRegion": "TX", + "addressLocality": "Austin", + "streetAddress": "123 First St", + "postOfficeBoxNumber": "1", + "postalCode": "12345", + "geo": { + "type": "GeoCoordinates", + "latitude": 1, + "longitude": 1 + } + }, + "otherIdentifier": [ + { + "type": "IdentifierEntry", + "identifier": "12345", + "identifierType": "sourcedId" + }, + { + "type": "IdentifierEntry", + "identifier": "67890", + "identifierType": "nationalIdentityNumber" + } + ], + "official": "Horace Mann", + "parentOrg": { + "id": "did:example:123456789", + "type": [ + "Profile" + ], + "name": "Universal Universities" + } + }, + "creditsAvailable": 36, + "criteria": { + "id": "https://1edtech.edu/achievements/degree", + "narrative": "# Degree Requirements\nStudents must complete..." + }, + "description": "1EdTech University Degree Description", + "endorsement": [ + { + "@context": [ + "https://www.w3.org/ns/credentials/v2", + "https://purl.imsglobal.org/spec/ob/v3p0/context-3.0.3.json" + ], + "id": "http://1edtech.edu/endorsementcredential/3734", + "type": [ + "VerifiableCredential", + "EndorsementCredential" + ], + "name": "EAA endorsement", + "issuer": { + "id": "https://accrediter.edu/issuers/565049", + "type": [ + "Profile" + ], + "name": "Example Accrediting Agency" + }, + "validFrom": "2010-01-01T00:00:00Z", + "validUntil": "2020-01-01T00:00:00Z", + "credentialSubject": { + "id": "https://1edtech.edu/issuers/565049", + "type": [ + "EndorsementSubject" + ], + "endorsementComment": "1EdTech University is in good standing" + }, + "credentialSchema": [ + { + "id": "https://purl.imsglobal.org/spec/ob/v3p0/schema/json/ob_v3p0_endorsementcredential_schema.json", + "type": "1EdTechJsonSchemaValidator2019" + }, + { + "id": "https://accrediter.edu/schema/endorsementcredential.json", + "type": "1EdTechJsonSchemaValidator2019" + } + ], + "credentialStatus": { + "id": "https://1edtech.edu/credentials/3732/revocations", + "type": "1EdTechRevocationList" + }, + "refreshService": { + "id": "http://1edtech.edu/credentials/3732", + "type": "1EdTechCredentialRefresh" + }, + "proof": [ + { + "type": "DataIntegrityProof", + "cryptosuite": "eddsa-rdf-2022", + "created": "2022-05-26T18:17:08Z", + "verificationMethod": "https://accrediter.edu/issuers/565049#zvPkQiUFfJrgnCRhyPkTSkgrGXbnLR15pHH5HZVYNdM4TCAwQHqG7fMeMPLtYNRnEgoV1aJdR5E61eWu5sWRYgtA", + "proofPurpose": "assertionMethod", + "proofValue": "zvPkQiUFfJrgnCRhyPkTSkgrGXbnLR15pHH5HZVYNdM4TCAwQHqG7fMeMPLtYNRnEgoV1aJdR5E61eWu5sWRYgtA" + } + ] + } + ], + "fieldOfStudy": "Research", + "humanCode": "R1", + "image": { + "id": "https://raw.githubusercontent.com/hamrt/credential-converter/refs/heads/image/test/1EDTECH_logo_100x100.png", + "type": "Image", + "caption": "1EdTech University Degree" + }, + "name": "1EdTech University Degree", + "otherIdentifier": [ + { + "type": "IdentifierEntry", + "identifier": "abde", + "identifierType": "identifier" + } + ], + "resultDescription": [ + { + "id": "urn:uuid:a70ddc6a-4c4a-4bd8-8277-cb97c79f40c5", + "type": [ + "ResultDescription" + ], + "name": "Final Project Grade", + "requiredLevel": "urn:uuid:d05a0867-d0ad-4b03-bdb5-28fb5d2aab7a", + "resultType": "RubricCriterionLevel", + "rubricCriterionLevel": [ + { + "id": "urn:uuid:d05a0867-d0ad-4b03-bdb5-28fb5d2aab7a", + "type": [ + "RubricCriterionLevel" + ], + "description": "The author demonstrated...", + "level": "Mastered", + "name": "Mastery", + "points": "4" + }, + { + "id": "urn:uuid:6b84b429-31ee-4dac-9d20-e5c55881f80e", + "type": [ + "RubricCriterionLevel" + ], + "alignment": [ + { + "type": [ + "Alignment" + ], + "targetCode": "project", + "targetDescription": "Project description", + "targetName": "Final Project", + "targetFramework": "1EdTech University Program and Course Catalog", + "targetType": "CFRubricCriterionLevel", + "targetUrl": "https://1edtech.edu/catalog/degree/project/rubric/levels/basic" + } + ], + "description": "The author demonstrated...", + "level": "Basic", + "name": "Basic", + "points": "4" + } + ] + }, + { + "id": "urn:uuid:b07c0387-f2d6-4b65-a3f4-f4e4302ea8f7", + "type": [ + "ResultDescription" + ], + "name": "Project Status", + "resultType": "Status" + } + ], + "specialization": "Computer Science Research", + "tag": [ + "research", + "computer science" + ] + }, + "image": { + "id": "https://1edtech.edu/credentials/3732/image", + "type": "Image", + "caption": "1EdTech University Degree for Example Student" + }, + "narrative": "There is a final project report and source code evidence.", + "result": [ + { + "type": [ + "Result" + ], + "alignment": [ + { + "type": [ + "Alignment" + ], + "targetCode": "project", + "targetDescription": "Project description", + "targetName": "Final Project", + "targetFramework": "1EdTech University Program and Course Catalog", + "targetType": "CFItem", + "targetUrl": "https://1edtech.edu/catalog/degree/project/result/1" + } + ], + "resultDescription": "urn:uuid:f6ab24cd-86e8-4eaf-b8c6-ded74e8fd41c", + "value": "A" + }, + { + "type": [ + "Result" + ], + "achievedLevel": "urn:uuid:d05a0867-d0ad-4b03-bdb5-28fb5d2aab7a", + "alignment": [ + { + "type": [ + "Alignment" + ], + "targetCode": "project", + "targetDescription": "Project description", + "targetName": "Final Project", + "targetFramework": "1EdTech University Program and Course Catalog", + "targetType": "CFItem", + "targetUrl": "https://1edtech.edu/catalog/degree/project/result/1" + } + ], + "resultDescription": "urn:uuid:f6ab24cd-86e8-4eaf-b8c6-ded74e8fd41c" + }, + { + "type": [ + "Result" + ], + "resultDescription": "urn:uuid:f6ab24cd-86e8-4eaf-b8c6-ded74e8fd41c", + "status": "Completed" + } + ] + }, + "endorsement": [ + { + "@context": [ + "https://www.w3.org/ns/credentials/v2", + "https://purl.imsglobal.org/spec/ob/v3p0/context-3.0.3.json" + ], + "id": "http://1edtech.edu/endorsementcredential/3735", + "type": [ + "VerifiableCredential", + "EndorsementCredential" + ], + "name": "EAA endorsement", + "issuer": { + "id": "https://accrediter.edu/issuers/565049", + "type": [ + "Profile" + ], + "name": "Example Accrediting Agency" + }, + "validFrom": "2010-01-01T00:00:00Z", + "validUntil": "2020-01-01T00:00:00Z", + "credentialSubject": { + "id": "https://1edtech.edu/issuers/565049", + "type": [ + "EndorsementSubject" + ], + "endorsementComment": "1EdTech University is in good standing" + }, + "credentialSchema": [ + { + "id": "https://purl.imsglobal.org/spec/ob/v3p0/schema/json/ob_v3p0_endorsementcredential_schema.json", + "type": "1EdTechJsonSchemaValidator2019" + }, + { + "id": "https://accrediter.edu/schema/endorsementcredential.json", + "type": "1EdTechJsonSchemaValidator2019" + } + ], + "credentialStatus": { + "id": "https://1edtech.edu/credentials/3732/revocations", + "type": "1EdTechRevocationList" + }, + "refreshService": { + "id": "http://1edtech.edu/credentials/3732", + "type": "1EdTechCredentialRefresh" + }, + "proof": [ + { + "type": "DataIntegrityProof", + "cryptosuite": "eddsa-rdf-2022", + "created": "2022-05-26T18:17:08Z", + "verificationMethod": "https://accrediter.edu/issuers/565049#zvPkQiUFfJrgnCRhyPkTSkgrGXbnLR15pHH5HZVYNdM4TCAwQHqG7fMeMPLtYNRnEgoV1aJdR5E61eWu5sWRYgtA", + "proofPurpose": "assertionMethod", + "proofValue": "zvPkQiUFfJrgnCRhyPkTSkgrGXbnLR15pHH5HZVYNdM4TCAwQHqG7fMeMPLtYNRnEgoV1aJdR5E61eWu5sWRYgtA" + } + ] + } + ], + "evidence": [ + { + "id": "https://1edtech.edu/credentials/3732/evidence/1", + "type": [ + "Evidence" + ], + "narrative": "# Final Project Report \n This project was ...", + "name": "Final Project Report", + "description": "This is the final project report.", + "genre": "Research", + "audience": "Department" + }, + { + "id": "https://github.com/somebody/project", + "type": [ + "Evidence" + ], + "name": "Final Project Code", + "description": "This is the source code for the final project app.", + "genre": "Research", + "audience": "Department" + } + ], + "issuer": { + "id": "https://1edtech.edu/issuers/565049", + "type": [ + "Profile" + ], + "name": "1EdTech University", + "url": "https://1edtech.edu", + "phone": "1-222-333-4444", + "description": "1EdTech University provides online degree programs.", + "endorsement": [ + { + "@context": [ + "https://www.w3.org/ns/credentials/v2", + "https://purl.imsglobal.org/spec/ob/v3p0/context-3.0.3.json" + ], + "id": "http://1edtech.edu/endorsementcredential/3736", + "type": [ + "VerifiableCredential", + "EndorsementCredential" + ], + "name": "EAA endorsement", + "issuer": { + "id": "https://accrediter.edu/issuers/565049", + "type": [ + "Profile" + ], + "name": "Example Accrediting Agency" + }, + "validFrom": "2010-01-01T00:00:00Z", + "validUntil": "2020-01-01T00:00:00Z", + "credentialSubject": { + "id": "https://1edtech.edu/issuers/565049", + "type": [ + "EndorsementSubject" + ], + "endorsementComment": "1EdTech University is in good standing" + }, + "credentialSchema": [ + { + "id": "https://purl.imsglobal.org/spec/ob/v3p0/schema/json/ob_v3p0_endorsementcredential_schema.json", + "type": "1EdTechJsonSchemaValidator2019" + }, + { + "id": "https://accrediter.edu/schema/endorsementcredential.json", + "type": "1EdTechJsonSchemaValidator2019" + } + ], + "credentialStatus": { + "id": "https://1edtech.edu/credentials/3732/revocations", + "type": "1EdTechRevocationList" + }, + "refreshService": { + "id": "http://1edtech.edu/credentials/3732", + "type": "1EdTechCredentialRefresh" + }, + "proof": [ + { + "type": "DataIntegrityProof", + "cryptosuite": "eddsa-rdf-2022", + "created": "2022-05-26T18:17:08Z", + "verificationMethod": "https://accrediter.edu/issuers/565049#zvPkQiUFfJrgnCRhyPkTSkgrGXbnLR15pHH5HZVYNdM4TCAwQHqG7fMeMPLtYNRnEgoV1aJdR5E61eWu5sWRYgtA", + "proofPurpose": "assertionMethod", + "proofValue": "zvPkQiUFfJrgnCRhyPkTSkgrGXbnLR15pHH5HZVYNdM4TCAwQHqG7fMeMPLtYNRnEgoV1aJdR5E61eWu5sWRYgtA" + } + ] + } + ], + "image": { + "id": "https://raw.githubusercontent.com/hamrt/credential-converter/refs/heads/image/test/1EDTECH_logo_100x100.png", + "type": "Image", + "caption": "1EdTech University logo" + }, + "email": "registrar@1edtech.edu", + "address": { + "type": [ + "Address" + ], + "addressCountry": "USA", + "addressCountryCode": "US", + "addressRegion": "TX", + "addressLocality": "Austin", + "streetAddress": "123 First St", + "postOfficeBoxNumber": "1", + "postalCode": "12345", + "geo": { + "type": "GeoCoordinates", + "latitude": 1, + "longitude": 1 + } + }, + "otherIdentifier": [ + { + "type": "IdentifierEntry", + "identifier": "12345", + "identifierType": "sourcedId" + }, + { + "type": "IdentifierEntry", + "identifier": "67890", + "identifierType": "nationalIdentityNumber" + } + ], + "official": "Horace Mann", + "parentOrg": { + "id": "did:example:123456789", + "type": [ + "Profile" + ], + "name": "Universal Universities" + } + }, + "validFrom": "2010-01-01T00:00:00Z", + "validUntil": "2030-01-01T00:00:00Z", + "credentialSchema": [ + { + "id": "https://purl.imsglobal.org/spec/ob/v3p0/schema/json/ob_v3p0_achievementcredential_schema.json", + "type": "1EdTechJsonSchemaValidator2019" + } + ], + "credentialStatus": { + "id": "https://1edtech.edu/credentials/3732/revocations", + "type": "1EdTechRevocationList" + }, + "refreshService": { + "id": "http://1edtech.edu/credentials/3732", + "type": "1EdTechCredentialRefresh" + }, + "proof": [ + { + "type": "DataIntegrityProof", + "created": "2024-05-31T14:05:25Z", + "verificationMethod": "https://1edtech.edu/issuers/565049#z6MkphU6QmojC6GdUBNYypgnGaiL2TLisLMxpE1oZcmKg7Ad", + "cryptosuite": "eddsa-rdfc-2022", + "proofPurpose": "assertionMethod", + "proofValue": "z5A4ZXLJa4dUArTmpdP9vnrYijMLCT1tR9KWaFmLT2PeQp3gSnGA9wrRJqrJ5Z8YnpVDxZQWRGjjWNbj2PKDJe7dt" + } + ] +} diff --git a/json/obv3/examples/mbob_eo_eov_extracurricular_full.json b/json/obv3/examples/mbob_eo_eov_extracurricular_full.json new file mode 100755 index 0000000..09ce3d8 --- /dev/null +++ b/json/obv3/examples/mbob_eo_eov_extracurricular_full.json @@ -0,0 +1,106 @@ +{ + "@context": [ + "https://www.w3.org/ns/credentials/v2", + "https://purl.imsglobal.org/spec/ob/v3p0/context-3.0.3.json", + "https://raw.githubusercontent.com/educredentials/obv3-examples/refs/heads/main/contexts/educredential.json" + ], + "id": "http://example.com/credentials/crd-A1B2C3", + "type": [ + "VerifiableCredential", + "OpenBadgeCredential" + ], + "issuer": { + "id": "https://example.com/issuers/iss-4B0B1A", + "type": [ + "Profile" + ], + "name": "MBO Beek", + "otherIdentifier": [ + { + "type": "IdentifierEntry", + "identifier": "4B0B1A", + "identifierType": "ext:BRIN" + }, + { + "type": "IdentifierEntry", + "identifier": "mbobeek.example.edu", + "identifierType": "name" + } + ] + }, + "validFrom": "2024-08-30T00:00:00Z", + "validUntil": "2029-08-30T00:00:00Z", + "name": "Extracurriculair Stage bij het luchtverkopersgilde", + "credentialSubject": { + "id": "https://example.com/credentials/stu-A1B2C3", + "type": [ + "AchievementSubject" + ], + "achievement": { + "id": "https://example.com/achievements/ach-33D4E5", + "type": [ + "Achievement", + "EducredentialAchievement" + ], + "criteria": { + "narrative": "De student leert de kunst van het verkopen van niet-bestaande producten en diensten." + }, + "description": "Leer hoe je iets verkoopt dat eigenlijk niet bestaat, met praktijkoefeningen in het verkopen van luchtkastelen, abonnementen op niets.", + "name": "Extracurriculair Stage bij het luchtverkopersgilde", + "image": { + "id": "https://static.example.com/luchtkastelen.jpg", + "type": "Image" + }, + "inLanguage": "nl-NL", + "educationProgramIdentifier": 20121344, + "SBU": 120, + "participationType": "onsite or blended", + "assessmentType": "application of a skill", + "supervisionType": "onsite with identity verification", + "identityChecked": false, + "alignment": [ + { + "type": [ + "Alignment" + ], + "targetType": "ext:EQF", + "targetName": "EQF level 3", + "targetCode": "3", + "targetUrl": "https://content.example.com/description-eqf-levels" + } + ], + "resultDescription": [ + { + "id": "https://example.com/results/ects-nl-NL-A1B2C3", + "type": [ + "ResultDescription" + ], + "valueMax": "10", + "valueMin": "1", + "name": "Final Project Grade", + "requiredValue": "6", + "resultType": "ext:ECTSGradeScore" + } + ] + }, + "result": [ + { + "type": [ + "Result" + ], + "resultDescription": "https://example.com/results/ects-nl-NL-A1B2C3", + "value": "7.5" + } + ] + }, + "credentialSchema": [ + { + "id": "https://purl.imsglobal.org/spec/ob/v3p0/schema/json/ob_v3p0_achievementcredential_schema.json", + "type": "1EdTechJsonSchemaValidator2019" + }, + { + "id": "https://raw.githubusercontent.com/educredentials/obv3-examples/refs/heads/main/schemas/extracurricular.json", + "type": "1EdTechJsonSchemaValidator2019" + } + ] +} diff --git a/json/obv3/examples/theed_regular_embedded_JPG_ho.json b/json/obv3/examples/theed_regular_embedded_JPG_ho.json new file mode 100644 index 0000000..a4e89fc --- /dev/null +++ b/json/obv3/examples/theed_regular_embedded_JPG_ho.json @@ -0,0 +1,115 @@ +{ + "@context": [ + "https://www.w3.org/ns/credentials/v2", + "https://purl.imsglobal.org/spec/ob/v3p0/context-3.0.3.json", + "https://raw.githubusercontent.com/educredentials/obv3-examples/refs/heads/main/contexts/educredential.json" + ], + "id": "http://example.com/credentials/crd-D4E5F6", + "type": [ + "VerifiableCredential", + "OpenBadgeCredential" + ], + "issuer": { + "id": "https://example.com/issuers/iss-9Z8Y7X", + "type": [ + "Profile" + ], + "name": "Naboo Theed University", + "otherIdentifier": [ + { + "type": "IdentifierEntry", + "identifier": "42NB", + "identifierType": "ext:BRIN" + }, + { + "type": "IdentifierEntry", + "identifier": "university.naboo", + "identifierType": "name" + } + ] + }, + "validFrom": "2014-06-01T00:00:00Z", + "name": "The Force and Its Applications", + "credentialSubject": { + "id": "did:example:ebfeb1f712ebc6f1c276e12ec21", + "type": [ + "AchievementSubject" + ], + "achievement": { + "id": "https://example.com/achievements/ach-77NPN", + "type": [ + "Achievement", + "EducredentialAchievement" + ], + "criteria": { + "narrative": "This badge is awarded for completing the course 'The Force and Its Applications'" + }, + "description": "This badge is awarded for completing the course 'The Force and Its Applications'", + "name": "The Force and Its Applications", + "image": { + "id": "data:image/jpeg;base64,/9j/4Q/+RXhpZgAATU0AKgAAAAgABgESAAMAAAABAAEAAAEaAAUAAAABAAAAVgEbAAUAAAABAAAAXgEoAAMAAAABAAIAAAITAAMAAAABAAEAAIdpAAQAAAABAAAAZgAAAAAAAABIAAAAAQAAAEgAAAABAAeQAAAHAAAABDAyMjGRAQAHAAAABAECAwCgAAAHAAAABDAxMDCgAQADAAAAAQABAACgAgAEAAAAAQAAAeCgAwAEAAAAAQAAASykBgADAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA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", + "type": "Image" + }, + "resultDescription": [ + { + "id": "https://example.com/results/ects-nl-NL-A1B2C3", + "type": [ + "ResultDescription" + ], + "valueMax": "10", + "valueMin": "1", + "name": "Final Project Grade", + "requiredValue": "6", + "resultType": "ext:ECTSGradeScore" + } + ], + "inLanguage": "en-EN", + "alignment": [ + { + "type": [ + "Alignment" + ], + "targetType": "ext:QualityAssurance", + "targetName": "M Philosophy of Science, Technology and Society", + "targetDescription": "Accreditatie bestaande opleiding", + "targetCode": "AV-2391", + "targetUrl": "https://data.example.com/decisions/AV-2391" + }, + { + "type": [ + "Alignment" + ], + "targetType": "ext:EQF", + "targetName": "EQF level 5", + "targetCode": "5", + "targetUrl": "https://content.example.com/description-eqf-levels" + } + ], + "educationProgramIdentifier": 133742, + "ECTS": 6.0 + }, + "result": [ + { + "type": [ + "Result" + ], + "resultDescription": "https://example.com/results/ects-nl-NL-D4E5F6", + "value": "8.0" + } + ] + }, + "credentialSchema": [ + { + "id": "https://purl.imsglobal.org/spec/ob/v3p0/schema/json/ob_v3p0_achievementcredential_schema.json", + "type": "1EdTechJsonSchemaValidator2019" + }, + { + "id": "https://raw.githubusercontent.com/educredentials/obv3-examples/refs/heads/main/schemas/regular.json", + "type": "1EdTechJsonSchemaValidator2019" + }, + { + "id": "https://raw.githubusercontent.com/educredentials/obv3-examples/refs/heads/main/schemas/regular_ects.json", + "type": "1EdTechJsonSchemaValidator2019" + } + ] +} diff --git a/json/obv3/examples/theed_regular_embedded_ho.json b/json/obv3/examples/theed_regular_embedded_ho.json new file mode 100644 index 0000000..01d465a --- /dev/null +++ b/json/obv3/examples/theed_regular_embedded_ho.json @@ -0,0 +1,115 @@ +{ + "@context": [ + "https://www.w3.org/ns/credentials/v2", + "https://purl.imsglobal.org/spec/ob/v3p0/context-3.0.3.json", + "https://raw.githubusercontent.com/educredentials/obv3-examples/refs/heads/main/contexts/educredential.json" + ], + "id": "http://example.com/credentials/crd-D4E5F6", + "type": [ + "VerifiableCredential", + "OpenBadgeCredential" + ], + "issuer": { + "id": "https://example.com/issuers/iss-9Z8Y7X", + "type": [ + "Profile" + ], + "name": "Naboo Theed University", + "otherIdentifier": [ + { + "type": "IdentifierEntry", + "identifier": "42NB", + "identifierType": "ext:BRIN" + }, + { + "type": "IdentifierEntry", + "identifier": "university.naboo", + "identifierType": "name" + } + ] + }, + "validFrom": "2014-06-01T00:00:00Z", + "name": "The Force and Its Applications", + "credentialSubject": { + "id": "did:example:ebfeb1f712ebc6f1c276e12ec21", + "type": [ + "AchievementSubject" + ], + "achievement": { + "id": "https://example.com/achievements/ach-77NPN", + "type": [ + "Achievement", + "EducredentialAchievement" + ], + "criteria": { + "narrative": "This badge is awarded for completing the course 'The Force and Its Applications'" + }, + "description": "This badge is awarded for completing the course 'The Force and Its Applications'", + "name": "The Force and Its Applications", + "image": { + "id": "data:image/jpeg;base64,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", + "type": "Image" + }, + "resultDescription": [ + { + "id": "https://example.com/results/ects-nl-NL-A1B2C3", + "type": [ + "ResultDescription" + ], + "valueMax": "10", + "valueMin": "1", + "name": "Final Project Grade", + "requiredValue": "6", + "resultType": "ext:ECTSGradeScore" + } + ], + "inLanguage": "en-EN", + "alignment": [ + { + "type": [ + "Alignment" + ], + "targetType": "ext:QualityAssurance", + "targetName": "M Philosophy of Science, Technology and Society", + "targetDescription": "Accreditatie bestaande opleiding", + "targetCode": "AV-2391", + "targetUrl": "https://data.example.com/decisions/AV-2391" + }, + { + "type": [ + "Alignment" + ], + "targetType": "ext:EQF", + "targetName": "EQF level 5", + "targetCode": "5", + "targetUrl": "https://content.example.com/description-eqf-levels" + } + ], + "educationProgramIdentifier": 133742, + "ECTS": 6.0 + }, + "result": [ + { + "type": [ + "Result" + ], + "resultDescription": "https://example.com/results/ects-nl-NL-D4E5F6", + "value": "8.0" + } + ] + }, + "credentialSchema": [ + { + "id": "https://purl.imsglobal.org/spec/ob/v3p0/schema/json/ob_v3p0_achievementcredential_schema.json", + "type": "1EdTechJsonSchemaValidator2019" + }, + { + "id": "https://raw.githubusercontent.com/educredentials/obv3-examples/refs/heads/main/schemas/regular.json", + "type": "1EdTechJsonSchemaValidator2019" + }, + { + "id": "https://raw.githubusercontent.com/educredentials/obv3-examples/refs/heads/main/schemas/regular_ects.json", + "type": "1EdTechJsonSchemaValidator2019" + } + ] +} diff --git a/json/output/example_ELM_to_OBv3.json b/json/output/example_ELM_to_OBv3.json new file mode 100644 index 0000000..b20d4a2 --- /dev/null +++ b/json/output/example_ELM_to_OBv3.json @@ -0,0 +1,59 @@ +{ + "@context": [ + "https://www.w3.org/ns/credentials/v2", + "https://purl.imsglobal.org/spec/ob/v3p0/context-3.0.3.json" + ], + "credentialSchema": [ + { + "id": "https://purl.imsglobal.org/spec/ob/v3p0/schema/json/ob_v3p0_endorsementcredential_schema.json", + "type": "1EdTechJsonSchemaValidator2019" + }, + { + "id": "https://accrediter.edu/schema/endorsementcredential.json", + "type": "1EdTechJsonSchemaValidator2019" + } + ], + "credentialSubject": { + "achievement": { + "id": "urn:epass:learningAchievement:6", + "name": "German International Abitur", + "type": [ + "Achievement" + ] + }, + "familyName": "Smith", + "fullName": "David Smith", + "givenName": "David", + "id": "did:key:afsdlkj34134", + "identifier": [ + { + "hashed": false, + "identityHash": "5547554", + "identityType": "ext:studentID", + "salt": "not-used", + "type": "IdentityObject" + } + ], + "type": [ + "AchievementSubject", + "profile" + ] + }, + "id": "urn:credential:87ddce4d-de74-4838-b7a4-1f14d9c614ec", + "issuer": { + "address": { + "addressCountryCode": "http://publications.europa.eu/resource/authority/country/ESP" + }, + "id": "did:ebsi:org:12345689", + "name": "ORGANIZACION TEST", + "type": [ + "Profile" + ] + }, + "name": "Higher Education Entrance Qualification - German International ABITUR School", + "type": [ + "VerifiableCredential", + "OpenBadgeCredential" + ], + "validFrom": "2020-07-20T00:00:00+02:00" +} \ No newline at end of file diff --git a/json/output/example_OBv3_to_ELM.json b/json/output/example_OBv3_to_ELM.json new file mode 100644 index 0000000..9bcbe97 --- /dev/null +++ b/json/output/example_OBv3_to_ELM.json @@ -0,0 +1,54 @@ +{ + "@context": [ + "https://www.w3.org/ns/credentials/v2", + "http://data.europa.eu/snb/model/context/edc-ap" + ], + "credentialSchema": [ + { + "id": "http://data.europa.eu/snb/model/ap/edc-generic-full", + "type": "ShaclValidator2017" + }, + { + "id": "https://api-pilot.ebsi.eu/trusted-schemas-registry/v3/schemas/0x7ff3bc76bd5e37b3d29721b8698646a722a24a4f4ab0a0ba63d4bbbe0ef9758d", + "type": "JsonSchema" + } + ], + "credentialSubject": { + "hasClaim": [ + { + "id": "urn:epass:learningAchievement:6", + "specifiedBy": { + "title": { + "en": [ + "German International Abitur" + ] + } + }, + "title": { + "en": [ + "Higher Education Entrance Qualification - German International ABITUR School" + ] + } + } + ], + "id": "did:key:afsdlkj34134", + "identifier": { + "id": "urn:epass:identifier:2", + "notation": "5547554", + "schemeName": "Student ID", + "type": "Identifier" + } + }, + "id": "urn:credential:87ddce4d-de74-4838-b7a4-1f14d9c614ec", + "issuer": { + "id": "did:ebsi:org:12345689", + "legalName": { + "en": "ORGANIZACION TEST" + } + }, + "type": [ + "VerifiableCredential", + "OpenBadgeCredential" + ], + "validFrom": "2020-07-20T00:00:00+02:00" +} \ No newline at end of file diff --git a/json/output/readme.md b/json/output/readme.md new file mode 100644 index 0000000..0c11ac0 --- /dev/null +++ b/json/output/readme.md @@ -0,0 +1,11 @@ +# ELM - OpenBadges v3 testing + +## Overview +To do a quick test of the translation run from the credential-converter directory + +cargo run -- -i ./json/ebsi-elm/vcdm2.0-europass-edc-schema/examples/DigiComp_Generic.json -o ./json/output/example_ELM_to_OBv3.json -m ./json/mapping/custom_mapping_ELM_OBv3_latest.json -c ELMtoOBv3 + +cargo run -- -i ./json/ebsi-elm/vcdm2.0-europass-edc-schema/examples/Bengales_highSchoolDiploma.json -o ./json/output/example_ELM_to_OBv3.json -m ./json/mapping/custom_mapping_ELM_OBv3_latest.json -c ELMtoOBv3 + + +cargo run -- -i ./json/output/example_ELM_to_OBv3.json -o ./json/output/example_OBv3_to_ELM.json -m ./json/mapping/custom_mapping_OBv3_ELM_latest.json -c OBv3toELM \ No newline at end of file diff --git a/json/output_credential.json b/json/output_credential.json index abeba65..022d047 100644 --- a/json/output_credential.json +++ b/json/output_credential.json @@ -1,6 +1,39 @@ { "@context": [ - "https://www.w3.org/ns/credentials/v2", - "http://data.europa.eu/snb/model/context/edc-ap" - ] + "https://www.w3.org/ns/credentials/v2" + ], + "Issuer": { + "id": "https://example.com/issuers/876543", + "name": "Example Corp", + "type": [ + "Profile" + ] + }, + "Proof": [ + { + "created": "2024-05-31T14:05:25Z", + "cryptosuite": "eddsa-rdfc-2022", + "proofPurpose": "assertionMethod", + "proofValue": "zJPcuWH556eQMEiPVd1Emp85PNTgsRyVYbMcxjsQXJ4MBQ2yEn83CQyJDjpvUSNx8GTSpiCC5pdYBou5gyTvnSwx", + "type": "DataIntegrityProof", + "verificationMethod": "https://example.com/issuers/876543#z6MksaRBVxaAjk4dNYcw5tReeHK6VAVVpjTyAzb4NofmhoGi" + } + ], + "credentialSubject": { + "achievement": { + "criteria": { + "narrative": "Team members are nominated for this badge by their peers and recognized upon review by Example Corp management." + }, + "description": "This badge recognizes the development of the capacity to collaborate within a group environment.", + "id": "https://example.com/achievements/21st-century-skills/teamwork", + "name": "Teamwork", + "type": [ + "Achievement" + ] + }, + "id": "did:example:ebfeb1f712ebc6f1c276e12ec21", + "type": [ + "AchievementSubject" + ] + } } \ No newline at end of file diff --git a/jsontest.json b/jsontest.json new file mode 100755 index 0000000..619c061 --- /dev/null +++ b/jsontest.json @@ -0,0 +1,61 @@ +{ + "@context": [ + "https://www.w3.org/ns/credentials/v2", + "http://data.europa.eu/snb/model/context/edc-ap" + ], + "credentialSchema": [ + { + "id": "http://data.europa.eu/snb/model/ap/edc-generic-full", + "type": "ShaclValidator2017" + }, + { + "id": "https://api-pilot.ebsi.eu/trusted-schemas-registry/v3/schemas/0x7ff3bc76bd5e37b3d29721b8698646a722a24a4f4ab0a0ba63d4bbbe0ef9758d", + "type": "JsonSchema" + } + ], + "credentialSubject": { + "hasClaim": [ + { + "id": "https://example.com/achievements/21st-century-skills/teamwork", + "specifiedBy": { + "learningOutcome": [ + "Team members are nominated for this badge by their peers and recognized upon review by Example Corp management." + ], + "title": { + "en": [ + "Teamwork" + ] + } + }, + "title": { + "en": [ + "Teamwork Badge" + ] + } + } + ], + "id": "did:example:ebfeb1f712ebc6f1c276e12ec21" + }, + "id": "http://example.com/credentials/3527", + "issuer": { + "id": "https://example.com/issuers/876543", + "legalName": { + "en": "Example Corp" + } + }, + "proof": [ + { + "created": "2024-05-31T14:05:25Z", + "cryptosuite": "eddsa-rdfc-2022", + "proofPurpose": "assertionMethod", + "proofValue": "zJPcuWH556eQMEiPVd1Emp85PNTgsRyVYbMcxjsQXJ4MBQ2yEn83CQyJDjpvUSNx8GTSpiCC5pdYBou5gyTvnSwx", + "type": "DataIntegrityProof", + "verificationMethod": "https://example.com/issuers/876543#z6MksaRBVxaAjk4dNYcw5tReeHK6VAVVpjTyAzb4NofmhoGi" + } + ], + "type": [ + "VerifiableCredential", + "OpenBadgeCredential" + ], + "validFrom": "2010-01-01T00:00:00Z" +} \ No newline at end of file diff --git a/outputs/translated_Bengales_highSchoolDiploma.json b/outputs/translated_Bengales_highSchoolDiploma.json new file mode 100755 index 0000000..b20d4a2 --- /dev/null +++ b/outputs/translated_Bengales_highSchoolDiploma.json @@ -0,0 +1,59 @@ +{ + "@context": [ + "https://www.w3.org/ns/credentials/v2", + "https://purl.imsglobal.org/spec/ob/v3p0/context-3.0.3.json" + ], + "credentialSchema": [ + { + "id": "https://purl.imsglobal.org/spec/ob/v3p0/schema/json/ob_v3p0_endorsementcredential_schema.json", + "type": "1EdTechJsonSchemaValidator2019" + }, + { + "id": "https://accrediter.edu/schema/endorsementcredential.json", + "type": "1EdTechJsonSchemaValidator2019" + } + ], + "credentialSubject": { + "achievement": { + "id": "urn:epass:learningAchievement:6", + "name": "German International Abitur", + "type": [ + "Achievement" + ] + }, + "familyName": "Smith", + "fullName": "David Smith", + "givenName": "David", + "id": "did:key:afsdlkj34134", + "identifier": [ + { + "hashed": false, + "identityHash": "5547554", + "identityType": "ext:studentID", + "salt": "not-used", + "type": "IdentityObject" + } + ], + "type": [ + "AchievementSubject", + "profile" + ] + }, + "id": "urn:credential:87ddce4d-de74-4838-b7a4-1f14d9c614ec", + "issuer": { + "address": { + "addressCountryCode": "http://publications.europa.eu/resource/authority/country/ESP" + }, + "id": "did:ebsi:org:12345689", + "name": "ORGANIZACION TEST", + "type": [ + "Profile" + ] + }, + "name": "Higher Education Entrance Qualification - German International ABITUR School", + "type": [ + "VerifiableCredential", + "OpenBadgeCredential" + ], + "validFrom": "2020-07-20T00:00:00+02:00" +} \ No newline at end of file diff --git a/outputs/translated_DigiComp_Generic.json b/outputs/translated_DigiComp_Generic.json new file mode 100755 index 0000000..c53be1b --- /dev/null +++ b/outputs/translated_DigiComp_Generic.json @@ -0,0 +1,67 @@ +{ + "@context": [ + "https://www.w3.org/ns/credentials/v2", + "https://purl.imsglobal.org/spec/ob/v3p0/context-3.0.3.json" + ], + "credentialSchema": [ + { + "id": "https://purl.imsglobal.org/spec/ob/v3p0/schema/json/ob_v3p0_endorsementcredential_schema.json", + "type": "1EdTechJsonSchemaValidator2019" + }, + { + "id": "https://accrediter.edu/schema/endorsementcredential.json", + "type": "1EdTechJsonSchemaValidator2019" + } + ], + "credentialSubject": { + "achievement": { + "criteria": { + "narrative": "**id**:\n urn:epass:learningOutcome:2\n**relatedSkill**:\n - **id**:\n https://publications.europa.eu/resource/authority/snb/dcf/860966ekgo\n **inScheme**:\n **id**:\n https://publications.europa.eu/resource/authority/snb/dcf/25831c2\n **type**:\n ConceptScheme\n **prefLabel**:\n **en**:\n - 5.4 Identifying digital competence gaps\n **type**:\n Concept\n**title**:\n **en**:\n - Name of DigiComp Competence\n**type**:\n LearningOutcome\n" + }, + "id": "urn:epass:learningAchievement:2", + "name": "Title of Achievement", + "type": [ + "Achievement" + ] + }, + "familyName": "Smith", + "fullName": "David Smith", + "givenName": "David", + "id": "did:key:afsdlkj34134", + "identifier": [ + { + "hashed": false, + "identityHash": "545465468", + "identityType": "ext:studentID", + "salt": "not-used", + "type": "IdentityObject" + } + ], + "type": [ + "AchievementSubject", + "profile" + ] + }, + "id": "urn:credential:dffc6c22-1421-4df2-b0e4-2b9d17aa0a6b", + "issuer": { + "address": { + "addressCountryCode": "http://publications.europa.eu/resource/authority/country/ESP" + }, + "id": "did:ebsi:org:12345689", + "name": "ORGANIZACION TEST", + "type": [ + "Profile" + ] + }, + "name": "TITLE OF PROGRAMME", + "image": { + "id": "https://raw.githubusercontent.com/hamrt/credential-converter/refs/heads/image/test/edubadges.png", + "type": "Image", + "caption": "1EdTech University Degree for Example Student" + }, + "type": [ + "VerifiableCredential", + "OpenBadgeCredential" + ], + "validFrom": "2019-09-20T00:00:00+02:00" +} \ No newline at end of file diff --git a/src/backend/base64_encode.rs b/src/backend/base64_encode.rs new file mode 100644 index 0000000..742cf3d --- /dev/null +++ b/src/backend/base64_encode.rs @@ -0,0 +1,512 @@ +use base64::{engine::general_purpose::STANDARD as Base64Engine, Engine}; +use regex::Regex; +use serde_json::Value; +use std::error::Error; +use std::io::Read; +use std::path::Path; +use ureq::get; + +/// Decode json input from Base64, and returns the byte array. +/// +/// # Arguments +/// - `string`: The string of the json to decode. +/// +/// # Returns +/// - `Ok(Byte)`: The Base64-encoded string of the json snippet if successful. +/// - `Err(Box)`: An error if the fetch or encoding fails. +pub fn decode_json(json: &str) -> Result, Box> { + // Decode the image bytes as a Base64 string + let conv_byte = Base64Engine.decode(json)?; + + Ok(conv_byte) +} + +/// Encode json input from Base64, and returns the byte array. +/// +/// # Arguments +/// - `string`: The string of the json to encode. +/// +/// # Returns +/// - `Ok(String)`: The Base64-encoded string of the json file. +/// - `Err(Box)`: An error if the fetch or encoding fails. +pub fn encode_json_file(json_file: Vec) -> Result> { + // Encode the image bytes as a Base64 string + let base64_string = Base64Engine.encode(json_file); + + Ok(base64_string) +} + +/// Fetches an image from the given URL, encodes it in Base64, and returns the encoded string. +/// +/// # Arguments +/// - `url`: The URL of the image to encode. +/// +/// # Returns +/// - `Ok(String)`: The Base64-encoded string of the image if successful. +/// - `Err(Box)`: An error if the fetch or encoding fails. +fn encode_image_from_url(url: &str) -> Result> { + let base64_string: String; + match get(url).call() { + Ok(resp) => { + assert!(resp.has("Content-Length")); + let len: usize = resp.header("Content-Length").unwrap().parse()?; + + let mut bytes: Vec = Vec::with_capacity(len); + resp.into_reader().take(10_000_000).read_to_end(&mut bytes)?; + + // Encode the image bytes as a Base64 string + base64_string = Base64Engine.encode(&bytes); + Ok(base64_string) + } + Err(e) => Err(Box::new(e)), + } +} + +/// Creates contentType object based on input type in string +/// +/// # Arguments +/// - `content_type`: The a type that is than rewritten into a serde Value object. +/// +/// # Returns +/// - `Ok(Value)`: The content value Object in ELM format if successful. +/// - `Err(Box)`: An error if the fetch or encoding fails. +fn set_content_type(content_type: &str) -> Result> { + let content_json = r#" + { + "id": "http://publications.europa.eu/resource/authority/file-type/PNG", + "type": "Concept", + "inScheme": { + "id": "http://publications.europa.eu/resource/authority/file-type", + "type": "ConceptScheme" + }, + "prefLabel": { + "en": ["PNG"] + }, + "notation": "file-type" + } + "#; + + let mut parsed_content_type_json: Value = serde_json::from_str(content_json).unwrap(); + + match content_type { + "PNG" => { + parsed_content_type_json["id"] = + Value::String("http://publications.europa.eu/resource/authority/file-type/PNG".to_string()); + parsed_content_type_json["prefLabel"]["en"][0] = Value::String("PNG".to_string()); + } + "JPG" | "JPEG" => { + parsed_content_type_json["id"] = + Value::String("http://publications.europa.eu/resource/authority/file-type/JPEG".to_string()); + parsed_content_type_json["prefLabel"]["en"][0] = Value::String("JPG".to_string()); + } + "SVG" => { + parsed_content_type_json["id"] = + Value::String("http://publications.europa.eu/resource/authority/file-type/SVG".to_string()); + parsed_content_type_json["prefLabel"]["en"][0] = Value::String("SVG".to_string()); + } + _ => { + // Handle other cases + return Err(Box::new(std::io::Error::new( + std::io::ErrorKind::InvalidInput, + "This file Type is not exporteswent wrong!", + ))); + } + } + Ok(parsed_content_type_json) +} + +/// Creates contentEncodingType object based on input type in string +/// +/// # Arguments +/// - `content_encoding_type`: The a type that is than rewritten into a serde Value object. +/// +/// # Returns +/// - `Ok(Value)`: The content value Object in ELM format if successful. +/// - `Err(Box)`: An error if the fetch or encoding fails. +fn set_content_enconding_type(content_encoding_type: &str) -> Result> { + let template_json = r#" + { + "id": "http://data.europa.eu/snb/encoding/6146cde7dd", + "type": "Concept", + "inScheme": { + "id": "http://data.europa.eu/snb/encoding/25831c2", + "type": "ConceptScheme" + }, + "prefLabel": { + "en": ["base64"] + } + } + "#; + + let mut parsed_content_encoding_type_json: Value = serde_json::from_str(template_json).unwrap(); + + match content_encoding_type { + "base64" => { + parsed_content_encoding_type_json["id"] = + Value::String("http://data.europa.eu/snb/encoding/6146cde7dd".to_string()); + parsed_content_encoding_type_json["prefLabel"]["en"][0] = Value::String("base64".to_string()); + } + _ => { + // Handle other cases + return Err(Box::new(std::io::Error::new( + std::io::ErrorKind::InvalidInput, + "This content encoding Type is not supported!", + ))); + } + } + Ok(parsed_content_encoding_type_json) +} + +/// Creates language object based on input type in string +/// +/// # Arguments +/// - `content_encoding_type`: The a type that is than rewritten into a serde Value object. +/// +/// # Returns +/// - `Ok(Value)`: The content value Object in ELM format if successful. +/// - `Err(Box)`: An error if the fetch or encoding fails. +fn set_language(language: &str) -> Result> { + let template_json = r#" + { + "id": "http://publications.europa.eu/resource/authority/language/ENG", + "type": "Concept", + "inScheme": { + "id": "http://publications.europa.eu/resource/authority/language", + "type": "ConceptScheme" + }, + "prefLabel": { + "en": ["English"] + }, + "notation": "language" + } + "#; + + let mut parsed_language_json: Value = serde_json::from_str(template_json).unwrap(); + + match language { + "ENG" => { + parsed_language_json["id"] = + Value::String("http://publications.europa.eu/resource/authority/language/ENG".to_string()); + parsed_language_json["prefLabel"]["en"][0] = Value::String("English".to_string()); + } + "NLD" => { + parsed_language_json["id"] = + Value::String("http://publications.europa.eu/resource/authority/language/NLD".to_string()); + parsed_language_json["prefLabel"]["en"][0] = Value::String("dutch".to_string()); + } + _ => { + // Handle other cases + return Err(Box::new(std::io::Error::new( + std::io::ErrorKind::InvalidInput, + "This language Type is not supported!", + ))); + } + } + Ok(parsed_language_json) +} + +pub fn image_to_elm_media_object(image_value: Value) -> Result { + //inspect the image object and re write it so it can be reused in ELM + + //we need to achieve the following structure into the indivudualDisplay array: + let json_data = r#" + { + "id": "urn:epass:mediaObject:https://avatars.githubusercontent.com/u/22613412?v=4", + "type": "MediaObject", + "content": "bas64content", + "contentEncoding": { + "id": "http://data.europa.eu/snb/encoding/6146cde7dd", + "type": "Concept", + "inScheme": { + "id": "http://data.europa.eu/snb/encoding/25831c2", + "type": "ConceptScheme" + }, + "prefLabel": { + "en": ["base64"] + } + }, + "contentType": { + "id": "http://publications.europa.eu/resource/authority/file-type/JPEG", + "type": "Concept", + "inScheme": { + "id": "http://publications.europa.eu/resource/authority/file-type", + "type": "ConceptScheme" + }, + "prefLabel": { + "en": ["JPG"] + }, + "notation": "file-type" + } + } + "#; + + let mut parsed_json: Value = serde_json::from_str(json_data).unwrap(); + + // OB usess the id field to point to an image or have the image encoded. + // Content type is also based on either URL or encoding in the id. + // Extract the `id` field + let encoded_string: String; + let mut file_type_sting = String::new(); + if let Some(id_value) = image_value.get("id") { + if let Some(ob3_image_id) = id_value.as_str() { + // Test if `id` is a URL + // println!("ob3_image_id value: {}", ob3_image_id); + let url_regex = Regex::new(r"^(https?://[^\s]+)$").unwrap(); + if url_regex.is_match(ob3_image_id) { + // println!("The `id` is a valid URL: {}", ob3_image_id); + // Directly mutate the `content` value + // first try to encode the image in the URL: + match encode_image_from_url(ob3_image_id) { + Ok(_encoded_image_string) => { + // println!("Successfully encoded the image."); + encoded_string = _encoded_image_string; // Assign the encoded string to the variable + + if let Some(extension) = Path::new(ob3_image_id).extension() { + // Convert the extension to a string + if let Some(ext) = extension.to_str() { + // println!("File extension: {}", ext); + file_type_sting = ext.to_ascii_uppercase().to_string(); + } else { + // println!("Could not convert extension to string."); + } + } else { + // println!("No file extension found."); + } + } + Err(_e) => { + return Err("encoding of url failed"); + } + }; + // } else if Base64Engine.decode(ob3_image_id).is_ok() { + } else if ob3_image_id.contains("data") { + // Test if `id` is Base64 encoded + // println!("The `id` is a Base64-encoded binary string."); + if let Some((mime_part, content_part)) = ob3_image_id.split_once(',') { + if let Some((_, type_and_enc)) = mime_part.split_once('/') { + if let Some((subtype, _)) = type_and_enc.split_once(';') { + file_type_sting = subtype.to_ascii_uppercase().to_string(); + } + } + encoded_string = content_part.to_string(); + } else { + // println!("Invalid data URI format."); + return Err("Invalid data URI format."); + } + } else { + // println!("The `id` is neither a URL nor a Base64-encoded string."); + return Err("The `id` is neither a URL nor a Base64-encoded string."); + } + } else { + // println!("The 'id' field is not a string."); + return Err("The 'id' field is not a string."); + } + } else { + // println!("The 'id' field does not exist."); + return Err("The 'id' field does not exist."); + } + + if let Some(_image_content) = parsed_json["content"].as_str() { + parsed_json["content"] = Value::String(encoded_string); + } else { + // println!("Key 'content' in 'image' not found."); + return Err("Key 'content' in 'image' not found."); + } + + // Directly mutate the `contentType` value of the image + // Set the contentType to a choosen value (currently default to PNG) + if file_type_sting.is_empty() { + file_type_sting = "PNG".to_string(); + } + // println!("fileTypoe string: {}", file_type_sting); + let encoded_content_type = match set_content_type(file_type_sting.as_str()) { + Ok(encoded_content_type) => { + // println!("Successfully added the contentType."); + encoded_content_type // Assign the encoded string to the variable + } + Err(e) => { + eprintln!("Error: {}", e); + return Err("conten_type not found"); // Assign an empty string or a default value in case of an error + } + }; + + if let Some(_content_type) = parsed_json.as_object() { + parsed_json["contentType"] = encoded_content_type; + } else { + // println!("Key 'contentType' in 'image' not found."); + return Err("Key 'contentType' in 'image' not found."); + } + + // Directly mutate the `encoding` value of the image + let encoding_value = match set_content_enconding_type("base64") { + Ok(encoding_value) => { + // println!("Successfully added encoding type to the image."); + encoding_value // Assign the encoded string to the variable + } + Err(_e) => { + //eprintln!("Error: {}", e); + return Err("encoding failed"); // Assign an empty string or a default value in case of an error + } + }; + + if let Some(_image_encoding) = parsed_json["contentEncoding"].as_object() { + parsed_json["contentEncoding"] = encoding_value; + } else { + // println!("Key 'contentEncoding' in 'image' not found."); + return Err("Key 'contentEncoding' in 'image' not found."); + } + + // println!("{:#?}", parsed_json); + Ok(parsed_json) +} + +pub fn image_to_individual_display(image_value: Value) -> Result { + //inspect the image object and re write it so it can be reused in ELM + + //we need to achieve the following structure into the indivudualDisplay array: + let json_data = r#" + { + "id": "urn:epass:individualDisplay:c05743e7-9f9d-4e0b-899b-7ae6514c7a02", + "type": "IndividualDisplay", + "language": { + "id": "http://publications.europa.eu/resource/authority/language/ENG", + "type": "Concept", + "inScheme": { + "id": "http://publications.europa.eu/resource/authority/language", + "type": "ConceptScheme" + }, + "prefLabel": { + "en": ["English"] + }, + "notation": "language" + }, + "displayDetail": [ + { + "id": "urn:epass:displayDetail:123", + "type": "DisplayDetail", + "image": {"object": "data"}, + "page": 1 + } + ] + } + "#; + + let mut parsed_json: Value = serde_json::from_str(json_data).unwrap(); + + // OB usess the id field to point to an image or have the image encoded. + // Content type is also based on either URL or encoding in the id. + // Extract the `id` field + // let image_object_value = image_to_elm_media_object(image_value); + // if let Some(_image_data) = parsed_json["displayDetail"][0]["image"].as_object() { + // parsed_json["displayDetail"][0]["image"] = image_object_value; + // } else { + // // println!("Key 'contentType' in 'image' not found."); + // return Value::Null; + // } + + let result = image_to_elm_media_object(image_value); + match result { + Ok(image_object_value) => { + parsed_json["displayDetail"][0]["image"] = image_object_value; + } + Err(_err) => { + return Err(_err); + } + } + + // Directly mutate the `language` value + let language_value = match set_language("ENG") { + Ok(language_value) => { + // println!("Successfully added language to the individual display properties."); + language_value // Assign the encoded string to the variable + } + Err(e) => { + eprintln!("Error: {}", e); + return Err("language value not set properly"); // Assign an empty string or a default value in case of an error + } + }; + + if let Some(_language) = parsed_json["language"].as_object() { + parsed_json["language"] = language_value; + } else { + // println!("Key 'language' in 'individualDisplay' not found."); + return Err("Key 'language' in 'individualDisplay' not found."); + } + + //println!("{:#?}", parsed_json); + Ok(parsed_json) +} + +pub fn create_display_parameter(image_value: Value) -> Result { + //inspect the image object and re write it so it can be reused in ELM + + //we need to achieve the following structure into the indivudualDisplay array: + let json_data = r#" + { + "id": "urn:epass:displayParameter:1", + "type": "DisplayParameter", + "language": [ + { + "id": "http://publications.europa.eu/resource/authority/language/ENG", + "type": "Concept", + "inScheme": { + "id": "http://publications.europa.eu/resource/authority/language", + "type": "ConceptScheme" + }, + "prefLabel": { + "en": ["English"] + }, + "notation": "language" + } + ], + "description": { + "en": [ + "EBSI Example https://github.com/Knowledge-Innovation-Centre/ESBI-JSON-schemas/blob/main/examples%20of%20credentials/DigiComp%20Generic.json" + ] + }, + "individualDisplay": [], + "primaryLanguage": { + "id": "http://publications.europa.eu/resource/authority/language/ENG", + "type": "Concept", + "inScheme": { + "id": "http://publications.europa.eu/resource/authority/language", + "type": "ConceptScheme" + }, + "prefLabel": { + "en": ["English"] + }, + "notation": "language" + }, + "title": { + "en": ["DigiComp Generic"] + } + } "#; + + let mut parsed_dp_json: Value = serde_json::from_str(json_data).unwrap(); + + // Add individual display value + // Set the contentType to a choosen value (currently default to PNG) + let result = image_to_individual_display(image_value); + match result { + Ok(individual_display_image) => { + parsed_dp_json["individualDisplay"] = Value::Array(vec![individual_display_image]); + } + Err(_err) => return Err(_err), + } + Ok(parsed_dp_json) + + // if let Some(id_value) = identity_value.get("identityHash") { + // if identity_type.eq(&"Student ID".to_string()) { + // let mut new_object = Map::new(); + // new_object.insert("id".to_string(), Value::String("urn:epass:identifier:2".to_string())); + // new_object.insert("type".to_string(), Value::String("Identifier".to_string())); + // new_object.insert("notation".to_string(), id_value.clone()); + // new_object.insert("schemeName".to_string(), Value::String(identity_type.to_string())); + // let _current_value = Value::Object(new_object); + // _current_value + // } else { + // id_value.clone() + // } + // } else { + // Value::String("".to_string()) + // } +} diff --git a/src/backend/candidate_value.rs b/src/backend/candidate_value.rs index 1163e40..f43853b 100644 --- a/src/backend/candidate_value.rs +++ b/src/backend/candidate_value.rs @@ -3,7 +3,7 @@ use regex::Regex; use crate::{ backend::{ jsonpointer::{JsonPath, JsonPointer}, - transformations::{DataLocation, OneToOne, Transformation}, + transformations::{DataLocation, OneToOne, StringToOne, StringValue, Transformation}, }, state::{AppState, Pages, Transformations}, trace_dbg, @@ -24,7 +24,7 @@ pub fn set_candidate_output_value(state: &mut AppState, push_transformation: boo // todo: Can we we just get the key pointed to instead of copynig the entire repository? let mut temp_repository = state.repository.clone(); - temp_repository.apply_transformation(transformation.clone(), state.mapping); + let _ = temp_repository.apply_transformation(transformation.clone(), state.mapping); let candidate_output_value = temp_repository .get(&state.mapping.output_format()) @@ -44,7 +44,7 @@ pub fn set_candidate_output_value(state: &mut AppState, push_transformation: boo pub fn define_transformation(state: &mut AppState, transformation: Transformations) -> Transformation { let (input_format, output_format) = (state.mapping.input_format(), state.mapping.output_format()); let source_pointer: JsonPath = JsonPointer(state.input_fields[state.selected_input_field].0.clone()).into(); - + let input_value: String = state.input_fields[state.selected_input_field].0.clone(); let destination_path: JsonPath = JsonPointer(state.output_pointer.clone()).into(); match transformation { @@ -98,6 +98,16 @@ pub fn define_transformation(state: &mut AppState, transformation: Transformatio }, // todo: This clippy warning is known, this body is for 'DirectCopy' and all others until they // get their own branches + Transformations::StringToOne => Transformation::StringToOne { + type_: StringToOne::stringit, + source: StringValue { + value: input_value.clone(), + }, + destination: DataLocation { + format: output_format.clone(), + path: destination_path.to_string(), + }, + }, Transformations::DirectCopy | _ => Transformation::OneToOne { type_: OneToOne::copy, source: DataLocation { diff --git a/src/backend/desm_mapping.rs b/src/backend/desm_mapping.rs index fe483de..3792ca8 100644 --- a/src/backend/desm_mapping.rs +++ b/src/backend/desm_mapping.rs @@ -29,13 +29,20 @@ pub fn apply_desm_mapping(state: &mut AppState) { trace_dbg!(&transformations); state.performed_mappings.extend(transformations.clone()); - let mut completed_fields = state.repository.apply_transformations(transformations, state.mapping); - for tuple in &mut completed_fields { - tuple.0 = tuple.0.trim_start_matches('$').replace('.', "/"); - tuple.1 = tuple.1.trim_start_matches('$').replace('.', "/"); + let result = state.repository.apply_transformations(transformations, state.mapping); + match result { + Ok(mut completed_fields) => { + for tuple in &mut completed_fields { + tuple.0 = tuple.0.trim_start_matches('$').replace('.', "/"); + tuple.1 = tuple.1.trim_start_matches('$').replace('.', "/"); + } + state.completed_fields.append(&mut completed_fields); + trace_dbg!(&state.completed_fields); + } + Err(_error) => { + //to handle + } } - state.completed_fields.append(&mut completed_fields); - trace_dbg!(&state.completed_fields); } pub fn desm_csv_parser(path: &str) -> Vec { diff --git a/src/backend/elm_mapping_helper.rs b/src/backend/elm_mapping_helper.rs new file mode 100644 index 0000000..7c90c01 --- /dev/null +++ b/src/backend/elm_mapping_helper.rs @@ -0,0 +1,507 @@ +use codes_iso_3166::part_1::CountryCode; +use serde_json::{json, Map, Value}; +use std::str::FromStr; + +/// Creates country code based on input type in string found in addressCountryCode +/// +/// # Arguments +/// - `country_code`: the code found in . +/// +/// # Returns +/// - Value: The content value Object in ELM format if successful. +pub fn address_to_location(address_value: Value) -> Value { + //inspect the address object (address as used in issuer for now) and re write it so it can be reused in ELM + //we need to achieve the following structure into the indivudualDisplay array: + let json_data = r#" + { + "id": "urn:epass:certificateLocation:1", + "type": "Location", + "address": { + "id": "urn:epass:certificateAddress:1", + "type": "Address", + "countryCode": { + "id": "http://publications.europa.eu/resource/authority/country/ESP", + "type": "Concept", + "inScheme": { + "id": "http://publications.europa.eu/resource/authority/country", + "type": "ConceptScheme" + }, + "notation": "country", + "prefLabel": { "en": "Spain" } + } + } + } + "#; + + let mut parsed_json: Value = serde_json::from_str(json_data).unwrap(); + + // set country code default to NL + let mut country = CountryCode::NL; + + // Directly mutate the `Location` value + // Access the "addressCountryCode" field + if let Some(country_code) = address_value.get("addressCountryCode") { + if let Some(country_code_str) = country_code.as_str() { + if country_code_str.is_empty() { + //println!("The addressCountryCode is empty."); + country = CountryCode::from_str("NLD").unwrap(); + } else { + country = CountryCode::from_str(country_code_str).unwrap(); + //println!("The addressCountryCode is: {}", country_code_str); + } + } else { + //println!("The addressCountryCode is not a string."); + } + } else { + //println!("The addressCountryCode field does not exist."); + } + + parsed_json["address"]["countryCode"]["id"] = Value::String(format!( + "http://publications.europa.eu/resource/authority/language/{}", + country.alpha_3_code().unwrap() + )); + parsed_json["address"]["countryCode"]["prefLabel"]["en"] = Value::String(country.full_name().unwrap().to_string()); + + //println!("{:#?}", parsed_json); + parsed_json +} + +/// Creates specifiedBy based on input type in string found title +/// +/// # Arguments +/// - `title`: the code found in . +/// +/// # Returns +/// - Value: The content value Object in ELM format if successful. +pub fn title_to_specifiedby(title: Value) -> Value { + //inspect the title object and re write it so it can be reused in ELM for building a Specification + //we need to achieve the following structure for a specification: + let json_data = r#" + { + "id": "urn:epass:learningAchievementSpec:1", + "type": "Qualification", + "title": { + "en": ["Data and software business"] + } + } + "#; + + let mut parsed_json: Value = serde_json::from_str(json_data).unwrap(); + + // Directly mutate the `Location` value + // Access the "addressCountryCode" field + if let Some(title_str) = title.as_str() { + if title_str.is_empty() { + return Value::Null; + } else { + parsed_json["title"]["en"][0] = Value::String(title_str.to_string()); + } + } else { + return Value::Null; + } + + //println!("{:#?}", parsed_json); + parsed_json +} + +/// Creates specifiedBy based on input type in string found title +/// +/// # Arguments +/// - `credits`: the ammount of credits for a credential +/// +/// # Returns +/// - Value: The creditpoint value Object in ELM format if successful. +pub fn credentialpoint_values_to_object(credits: Value) -> Value { + //inspect the title object and re write it so it can be reused in ELM for building a creditpoint that cn be used in Specification + //we need to achieve the following structure for a creditpoint: + let json_data = r#" + { + "id": "urn:epass:creditPoint:1", + "type": "CreditPoint", + "framework": { + "id": "http://data.europa.eu/snb/education-credit/6fcec5c5af", + "type": "Concept", + "inScheme": { + "id": "http://data.europa.eu/snb/education-credit/25831c2", + "type": "ConceptScheme" + }, + "prefLabel": { + "en": ["European Credit Transfer System"] + } + }, + "point": "5" + } + "#; + + let mut parsed_json: Value = serde_json::from_str(json_data).unwrap(); + + // Directly mutate the `Location` value + // Access the "addressCountryCode" field + match credits { + Value::String(_) => { + parsed_json["point"] = Value::String(credits.to_string()); + } + Value::Number(_) => { + parsed_json["point"] = Value::String(credits.to_string()); + } + _ => { + return Value::Null; + } + } + //println!("{:#?}", parsed_json); + parsed_json +} + +/// Creates EQF values in specifiedBy based on input type in string found title +/// +/// # Arguments +/// - `alignment`: an array that could be found in OBv3 but needs to be translated to fit the new structure of ELM. +/// +/// # Returns +/// - Value: The content value Object in ELM format if successful. +pub fn eqf_to_specifiedby_qualification(alignment: Value) -> Value { + //inspect the title object and re write it so it can be reused in ELM for building a creditpoint that cn be used in Specification + //we need to achieve the following structure for a creditpoint: + let json_data = r#" + { + "id": "http://data.europa.eu/snb/eqf/5", + "type": "Concept", + "inScheme": { + "id": "http://data.europa.eu/snb/eqf/25831c2", + "type": "ConceptScheme" + }, + "prefLabel": { + "en": ["Level 5"] + } + } + "#; + + let mut parsed_json: Value = serde_json::from_str(json_data).unwrap(); + //println!("{:#?}", alignment); + // Extract the array from the Value + if let Some(array) = alignment.as_array() { + // Find the targetCode where targetType == "ext:EQF" + if let Some(target_code) = array + .iter() + .find(|item| item.get("targetType").and_then(|v| v.as_str()) == Some("ext:EQF")) + .and_then(|item| item.get("targetCode").and_then(|v| v.as_str())) + { + parsed_json["id"] = Value::String(format!( + "http://publications.europa.eu/resource/authority/language/{}", + target_code + )); + parsed_json["prefLabel"]["en"] = Value::String(format!("Level {}", target_code)); + } else { + //println!("targetCode not found."); + return Value::Null; + } + } else { + //println!("Error: Data is not an array."); + return Value::Null; + } + + //println!("{:#?}", parsed_json); + parsed_json +} + +/// Creates specifiedBy based on input type in string found title +/// +/// # Arguments +/// - `assessment_type`: an array that could be found in OBv3 but needs to be translated to fit the new structure of ELM. +/// +/// # Returns +/// - Value: The specifiedBy object with dummies in ELM format if successful. +pub fn assessment_type_to_specifiedby_assesment(assessement_type: Value) -> Value { + //inspect the title object and re write it so it can be reused in ELM for building a creditpoint that cn be used in Specification + //we need to achieve the following structure for a creditpoint: + let json_data = r#" +{ + "id": "urn:epass:learningAssessment:1", + "type": "LearningAssessment", + "awardedBy": { + "id": "urn:epass:awardingProcess:1", + "type": "AwardingProcess", + "awardingBody": [ + { + "id": "urn:epass:org:1", + "type": "Organisation", + "location": [ {"address":"placeholder"} + ], + "legalName": { + "en": ["University of Life"] + } + } + ] + }, + "title": { + "en": ["AssessmentTypeValue"] + }, + "grade": { + "id": "urn:epass:note:1", + "type": "Note", + "noteLiteral": { + "en": ["0"] + } + } +} + +"#; + + let mut parsed_json: Value = serde_json::from_str(json_data).unwrap(); + + // Directly mutate the title value of the assessment + if let Some(assessement_type_str) = assessement_type.as_str() { + if assessement_type_str.is_empty() { + return Value::Null; + } else { + parsed_json["title"]["en"][0] = Value::String(assessement_type_str.to_string()); + } + } else { + return Value::Null; + } + + //println!("{:#?}", parsed_json); + parsed_json +} + +/// Creates specifiedBy based on input type in string found title +/// +/// # Arguments +/// - `assessment_type`: an array that could be found in OBv3 but needs to be translated to fit the new structure of ELM. +/// +/// # Returns +/// - Value: The specifiedBy object with dummies in ELM format if successful. +pub fn object_to_note_literal(any_object: Value) -> Value { + //inspect the title object and re write it so it can be reused in ELM for building a creditpoint that cn be used in Specification + //we need to achieve the following structure for a creditpoint: + + let str_array = handle_json_input(&any_object); + Value::String(str_array) +} + + +/// Creates learningOutcomes based on input type in outcome array +/// +/// # Arguments +/// - `learning_outcomes`: an array that could be found in OBv3 but needs to be translated to fit the new structure of ELM. +/// +/// # Returns +/// - Value: The specifiedBy object with dummies in ELM format if successful. +pub fn transform_alignment_to_learning_outcomes(json_obj: Value) -> Value { + if let Some(alignments) = json_obj.as_array() { + println!("{:#?}", alignments); + let mut results = Vec::new(); + + for alignment in alignments { + // Check if "type" array contains "LearningOutcome" + if let Some(types) = alignment.get("type").and_then(Value::as_array) { + if types.iter().any(|t| t == "LearningOutcome") { + let title = alignment + .get("targetName") + .and_then(Value::as_str) + .unwrap_or("Unknown Title"); + let description = alignment + .get("targetDescription") + .and_then(Value::as_str) + .unwrap_or("") + .to_string(); + let target_url = alignment.get("targetUrl").and_then(Value::as_str).unwrap_or(""); + // Separate ESCO relations from other relations + let mut esco_relations = Vec::new(); + let mut other_relations = Vec::new(); + + if let Some(relations) = alignment.get("relations").and_then(Value::as_array) { + for relation in relations { + if let Some(framework) = relation.get("targetFramework").and_then(Value::as_str) + { + let relation_object = json!({ + "id": relation.get("targetUrl").and_then(Value::as_str), + "type": "Concept", + "inScheme": { + "id": relation.get("frameworkUrl").and_then(Value::as_str), + "type": "ConceptScheme" + }, + "prefLabel": + { + "en": [relation.get("targetName").and_then(Value::as_str)] + }, + "notation": "Skill" + }); + + if framework == "ESCO" { + esco_relations.push(relation_object); + } else { + other_relations.push(relation_object); + } + } + } + + // **Use Map to construct the object dynamically** + let mut learning_outcome = Map::new(); + + learning_outcome.insert("title".to_string(), json!({"en": [title]})); + learning_outcome.insert("type".to_string(), Value::String("LearningOutcome".to_string())); + if !description.is_empty() { + learning_outcome.insert("additionalNote".to_string(), json!([{"id": "urn:epass:note:3", "type": "Note", "noteLiteral": {"en": [description]}}])); + } + learning_outcome.insert("id".to_string(), Value::String(target_url.to_string())); + + // **Only add arrays if they are NOT empty** + if !esco_relations.is_empty() { + learning_outcome.insert("relatedESCOSkill".to_string(), Value::Array(esco_relations)); + } + if !other_relations.is_empty() { + learning_outcome.insert("relatedSkill".to_string(), Value::Array(other_relations)); + } + results.push(Value::Object(learning_outcome)); + + } + } + + // println!("{:#?}", results); + } + } + + Value::Array(results) + } else { + Value::Null + } +} + +/// Creates a learning outcomes summary structure +/// +/// # Arguments +/// - `criteria`: Tekst as found in criteria in OBv3. +/// +/// # Returns +/// - Value: The learningOutcomeSummary object with dummies in ELM format if successful. +pub fn create_learning_outcome_summary(json_obj: Value) -> Value { + if let Some(outcome_sum_str) = json_obj.as_str() { + if outcome_sum_str.is_empty() { + Value::Null + } else { + let json_result = json!({ + "id": "urn:epass:note:3", + "type": "Note", + "noteLiteral": { + "en": [outcome_sum_str] + } + }); + json_result + } + } else { + Value::Null + } +} + +/// Creates learningSetting based on string provided by OBv3 string found in custom value learningSetting +/// Should land in specifiedBy +/// +/// # Arguments +/// - `alignment`: an array that could be found in OBv3 but needs to be translated to fit the new structure of ELM. +/// +/// # Returns +/// - Value: The content value Object in ELM format if successful. +pub fn transform_learning_setting(learning_setting: Value) -> Value { + //inspect the title object and re write it so it can be reused in ELM for building a creditpoint that cn be used in Specification + //we need to achieve the following structure for a creditpoint: + let json_data = r#" + { + "id": "http://data.europa.eu/snb/learning-setting/e207a81fc7", + "type": "Concept", + "inScheme": { + "id": "http://data.europa.eu/snb/learning-setting/25831c2", + "type": "ConceptScheme" + }, + "prefLabel": { + "en": ["non-formal"] + } + } + "#; + + let mut parsed_json: Value = serde_json::from_str(json_data).unwrap(); + //println!("{:#?}", alignment); + // Extract the array from the Value + if let Some(learning_setting_str) = learning_setting.as_str() { + match learning_setting_str { + "formal learning" | "formal" => { + parsed_json["id"] = Value::String("http://data.europa.eu/snb/learning-setting/6fd4685715".to_string()); + parsed_json["inScheme"]["id"] = + Value::String("http://data.europa.eu/snb/learning-setting/25831c2".to_string()); + parsed_json["prefLabel"]["en"][0] = Value::String("formal learning".to_string()); + } + "non-formal" | "nonformal" => { + parsed_json["id"] = Value::String("http://data.europa.eu/snb/learning-setting/6fd4685715".to_string()); + parsed_json["inScheme"]["id"] = + Value::String("http://data.europa.eu/snb/learning-setting/25831c2".to_string()); + parsed_json["prefLabel"]["en"][0] = Value::String("non-formal".to_string()); + } + _ => { + return Value::Null; + } + } + } else { + //println!("Error: Data is not an array."); + return Value::Null; + } + + //println!("{:#?}", parsed_json); + parsed_json +} + +// additional private helpers +// Function to handle both single object and array of objects +fn handle_json_input(json_obj: &Value) -> String { + if json_obj.is_array() { + // If it's an array, map each object to a string and join them + json_obj + .as_array() + .unwrap() + .iter() + .map(|obj| object_to_string(obj)) + .collect::>() + .join(" | ") // Separate objects with " | " + } else if json_obj.is_object() { + // If it's a single object, convert it directly + object_to_string(json_obj) + } else { + "Invalid JSON format".to_string() + } +} + +// Function to convert JSON object (with 1-level nesting) to a "key:value" string +fn object_to_string(json_obj: &Value) -> String { + if let Some(obj) = json_obj.as_object() { + obj.iter() + .flat_map(|(key, value)| { + match value { + Value::Object(nested_obj) => { + // Flatten nested objects: "key.nested_key:value" + nested_obj + .iter() + .map(|(nested_key, nested_value)| { + format!("{}.{}:{}", key, nested_key, value_to_string(nested_value)) + }) + .collect::>() + } + _ => vec![format!("{}:{}", key, value_to_string(value))], // Normal key:value + } + }) + .collect::>() + .join(", ") + } else { + "Invalid JSON object".to_string() + } +} + +// Converts JSON values to strings +fn value_to_string(value: &Value) -> String { + match value { + Value::String(s) => s.clone(), + Value::Number(n) => n.to_string(), + Value::Bool(b) => b.to_string(), + Value::Array(arr) => format!("[{}]", arr.iter().map(value_to_string).collect::>().join(", ")), + Value::Object(_) => "{...}".to_string(), // Shouldn't reach here due to flattening + Value::Null => "null".to_string(), + } +} diff --git a/src/backend/headless_cli.rs b/src/backend/headless_cli.rs index 3a76111..9cc7128 100644 --- a/src/backend/headless_cli.rs +++ b/src/backend/headless_cli.rs @@ -1,3 +1,4 @@ +use crate::backend::init_conversion::init_conversion; use crate::backend::init_conversion::load_mapping_file; use crate::p2_p3_common::create_output_files; use crate::state::{AppState, Mapping}; @@ -54,6 +55,7 @@ pub fn run_headless(cli_args: &mut Args, state: &mut AppState) -> Result<()> { pub fn load_files_apply_transformations(state: &mut AppState) { load_input_file(state, true); load_mapping_file(state); + init_conversion(state); create_output_files(state); } @@ -147,6 +149,9 @@ pub struct Args { #[arg(short, long, value_enum, required_if_eq_any = [("mapping_file", "Some"), ("input_file", "Some"), ("input_directory", "Some"), ("output_file", "Some"), ("output_directory", "Some")])] conversion: Option, + + #[arg(short, long)] + web_service: Option>, // #[arg(short, long)] // todo: nice feature for in the future // prefix_output: String, diff --git a/src/backend/init_conversion.rs b/src/backend/init_conversion.rs index b43bc67..f0d6061 100644 --- a/src/backend/init_conversion.rs +++ b/src/backend/init_conversion.rs @@ -15,7 +15,8 @@ pub fn init_conversion(state: &mut AppState) { load_input_file(state, false); load_mapping_file(state); enter_fixed_context_values(state); - + enter_fixed_schema_values(state); + enter_credential_profile_values(state); update_display_section(state, false); } @@ -78,11 +79,16 @@ pub fn load_mapping_file(state: &mut AppState) { } else { let rdr = std::fs::File::open(&state.mapping_path).unwrap(); let transformations: Vec = serde_json::from_reader(rdr).unwrap(); - trace_dbg!("Successfully loaded the mapping file"); - - state.repository.apply_transformations(transformations, state.mapping); + let result = state.repository.apply_transformations(transformations, state.mapping); + match result { + Ok(_value) => {} + Err(_error) => { + state.exit_warning = true; + } + } // todo: add applied transformation to completed fields + //println!("state: {:#?}", state.mapping); } } @@ -92,7 +98,10 @@ fn enter_fixed_context_values(state: &mut AppState) { let output_elm = state.repository.get_mut("ELM").unwrap().as_object_mut().unwrap(); output_elm.insert( "@context".to_string(), - Value::Array(vec![json!("https://www.w3.org/ns/credentials/v2")]), + Value::Array(vec![ + json!("https://www.w3.org/2018/credentials/v1"), + json!("http://data.europa.eu/snb/model/context/edc-ap"), + ]), ); } else if state.mapping.output_format() == "OBv3" { let output_obv3 = state.repository.get_mut("OBv3").unwrap().as_object_mut().unwrap(); @@ -106,6 +115,49 @@ fn enter_fixed_context_values(state: &mut AppState) { } } +/// Enter fixed values into '@context' field, as demanded by the respective json-schema +fn enter_fixed_schema_values(state: &mut AppState) { + if state.mapping.output_format() == "ELM" { + let output_elm = state.repository.get_mut("ELM").unwrap().as_object_mut().unwrap(); + output_elm.insert( + "credentialSchema".to_string(), + Value::Array(vec![ + json!({"id": "http://data.europa.eu/snb/model/ap/edc-generic-full","type": "ShaclValidator2017"}), + json!({"id": "https://api-pilot.ebsi.eu/trusted-schemas-registry/v3/schemas/0x7ff3bc76bd5e37b3d29721b8698646a722a24a4f4ab0a0ba63d4bbbe0ef9758d", + "type": "JsonSchema"})]), + ); + } else if state.mapping.output_format() == "OBv3" { + let output_obv3 = state.repository.get_mut("OBv3").unwrap().as_object_mut().unwrap(); + output_obv3.insert( + "credentialSchema".to_string(), + Value::Array(vec![ + json!({"id": "https://purl.imsglobal.org/spec/ob/v3p0/schema/json/ob_v3p0_endorsementcredential_schema.json", "type": "1EdTechJsonSchemaValidator2019"}), + json!({"id": "https://accrediter.edu/schema/endorsementcredential.json","type": "1EdTechJsonSchemaValidator2019"})]), + ); + } +} + +/// Enter fixed values into 'credentialProfile' field, as demanded by the respective json-schema +fn enter_credential_profile_values(state: &mut AppState) { + if state.mapping.output_format() == "ELM" { + let output_elm = state.repository.get_mut("ELM").unwrap().as_object_mut().unwrap(); + output_elm.insert( + "credentialProfiles".to_string(), + Value::Array(vec![ + json!({"id": "http://data.europa.eu/snb/credential/e34929035b","type": "Concept", + "inScheme": { + "id": "http://data.europa.eu/snb/credential/25831c2", + "type": "ConceptScheme" + }, + "prefLabel": {"en": ["Generic"]} + }), + ]), + ); + } else if state.mapping.output_format() == "OBv3" { + let _output_obv3 = state.repository.get_mut("OBv3").unwrap().as_object_mut().unwrap(); + } +} + //////// HELPERS //////// pub fn get_json(path: impl AsRef) -> Result diff --git a/src/backend/jsonpointer.rs b/src/backend/jsonpointer.rs index 1106077..15c6a52 100644 --- a/src/backend/jsonpointer.rs +++ b/src/backend/jsonpointer.rs @@ -1,5 +1,7 @@ use std::ops::Deref; +use regex::Regex; + #[derive(Debug)] // TODO: add validation pub struct JsonPath(pub String); @@ -33,6 +35,17 @@ impl TryFrom for JsonPointer { type Error = String; fn try_from(value: JsonPath) -> Result { - Ok(JsonPointer(value.0.trim_start_matches('$').replace('.', "/"))) + Ok(JsonPointer({ + let mut value = value.0.trim_start_matches('$').replace('.', "/"); + + // Check if the JsonPath contains arrays and convert them as well + let regx = Regex::new(r"\[(\d+)\]").unwrap(); + + while regx.is_match(&value) { + value = regx.replace(&value, "/$1").to_string(); + } + + value + })) } } diff --git a/src/backend/leaf_nodes.rs b/src/backend/leaf_nodes.rs index e9e38dd..e4b6bff 100644 --- a/src/backend/leaf_nodes.rs +++ b/src/backend/leaf_nodes.rs @@ -1,4 +1,4 @@ -use serde_json::Value; +use serde_json::{Map, Value}; use std::collections::HashMap; pub fn extract_leaf_nodes(json_object: &Value, path: String, result: &mut HashMap) { @@ -27,3 +27,33 @@ pub fn get_leaf_nodes(json_object: Value) -> HashMap { .map(|(key, value)| (format!("/{}", key), value)) .collect() } + +pub fn construct_leaf_node(path: &str) -> Value { + // Split the input string by '/' and filter out any empty parts + let parts: Vec<&str> = path.split('/').filter(|&s| !s.is_empty()).collect(); + + // Initialize the leaf_node value to Null, the actual value will be inserted later by the apply_transformation function + let mut current_value = Value::Null; + + // Iterate through the parts in reverse order to build the nested structure + for part in parts.into_iter().rev() { + // Check if the part is an array index + if part.chars().all(|c| c.is_numeric()) { + if let Ok(part_array_index) = part.parse::() { + let mut new_array = Vec::new(); + for i in 0..part_array_index { + new_array.insert(i, Value::Null); + } + + new_array.insert(part_array_index, current_value); + current_value = Value::Array(new_array); + } + } else { + let mut new_object = Map::new(); + new_object.insert(part.to_string(), current_value); + current_value = Value::Object(new_object); + } + } + + current_value +} diff --git a/src/backend/mod.rs b/src/backend/mod.rs index 6814f84..da4ad06 100644 --- a/src/backend/mod.rs +++ b/src/backend/mod.rs @@ -1,5 +1,7 @@ +pub mod base64_encode; pub mod candidate_value; pub mod desm_mapping; +pub mod elm_mapping_helper; pub mod getters_resolvers; pub mod headless_cli; pub mod init_conversion; @@ -7,5 +9,7 @@ pub mod jsonpointer; pub mod leaf_nodes; pub mod logging; pub mod repository; +pub mod routes; pub mod transformations; pub mod update_display; +pub mod web; diff --git a/src/backend/repository.rs b/src/backend/repository.rs index d602ead..9989f75 100644 --- a/src/backend/repository.rs +++ b/src/backend/repository.rs @@ -1,13 +1,19 @@ use crate::{ backend::{ + base64_encode::{create_display_parameter, image_to_elm_media_object}, + elm_mapping_helper::{ + address_to_location, assessment_type_to_specifiedby_assesment, create_learning_outcome_summary, credentialpoint_values_to_object, eqf_to_specifiedby_qualification, object_to_note_literal, title_to_specifiedby, transform_learning_setting, transform_alignment_to_learning_outcomes + }, jsonpointer::{JsonPath, JsonPointer}, - transformations::{DataLocation, Transformation}, + leaf_nodes::construct_leaf_node, + transformations::{DataLocation, DataTypeLocation, StringArrayValue, StringValue, Transformation}, }, state::{AppState, Mapping}, trace_dbg, }; use jsonpath_rust::JsonPathFinder; use serde_json::{json, Map, Value}; +//use tracing_subscriber::fmt::format; use std::{ collections::HashMap, ops::{Deref, DerefMut}, @@ -41,7 +47,7 @@ impl Repository { &mut self, transformation: Transformation, mapping: Mapping, - ) -> Option<(String, String)> { + ) -> Result, &'static str> { match transformation { Transformation::OneToOne { type_: transformation, @@ -57,7 +63,7 @@ impl Repository { }, } => { if source_format != mapping.input_format() || destination_format != mapping.output_format() { - return None; + return Ok(None); } let source_credential = self.get(&source_format).unwrap(); @@ -73,7 +79,580 @@ impl Repository { // todo: still need to investigate other find() return types Some(array) => array.first().unwrap().clone(), None => { - return None; + return Ok(None); + } + }; + + let destination_credential = self.entry(destination_format).or_insert(json!({})); // or_insert should never happen, since repository is initialized with all formats, incl empty json value when not present. + + let pointer = JsonPointer::try_from(JsonPath(destination_path.clone())).unwrap(); + + let mut leaf_node = construct_leaf_node(&pointer); + + if let Some(value) = leaf_node.pointer_mut(&pointer) { + *value = transformation.apply(source_value); + } + + merge(destination_credential, leaf_node); + + trace_dbg!("Successfully completed transformation"); + Ok(Some((destination_path, source_path))) + } + Transformation::ManyToOne { + type_: transformation, + sources, + destination, + } => { + if sources.iter().any(|source| source.format != mapping.input_format()) + || destination.format != mapping.output_format() + { + return Ok(None); + } + + let source_values = sources + .iter() + .map(|source| { + let source_credential = self.get(&source.format).unwrap(); + + let finder = JsonPathFinder::from_str(&source_credential.to_string(), &source.path).unwrap(); + finder.find().as_array().unwrap().first().unwrap().clone() + }) + .collect::>(); + + let destination_credential = self.entry(destination.format).or_insert(json!({})); + let pointer = JsonPointer::try_from(JsonPath(destination.path.clone())).unwrap(); + + let mut leaf_node = construct_leaf_node(&pointer); + + if let Some(value) = leaf_node.pointer_mut(&pointer) { + *value = transformation.apply(source_values); + } + + merge(destination_credential, leaf_node); + + trace_dbg!("Successfully completed transformation"); + Ok(None) // Todo: this is not implemented yet, so returns None for now + } + + Transformation::StringToOne { + type_: transformation, + source: StringValue { value: source_value }, + destination: + DataLocation { + format: destination_format, + path: destination_path, + }, + } => { + if destination_format != mapping.output_format() { + return Ok(None); + } + + let destination_credential = self.entry(destination_format).or_insert(json!({})); // or_insert should never happen, since repository is initialized with all formats, incl empty json value when not present. + let pointer = JsonPointer::try_from(JsonPath(destination_path)).unwrap(); + + let mut leaf_node = construct_leaf_node(&pointer); + if let Some(value) = leaf_node.pointer_mut(&pointer) { + *value = transformation.apply(source_value); + } + + merge(destination_credential, leaf_node); + Ok(None) + } + + Transformation::StringArrayToOne { + type_: transformation, + source: StringArrayValue { value: source_value }, + destination: + DataLocation { + format: destination_format, + path: destination_path, + }, + } => { + if destination_format != mapping.output_format() { + return Ok(None); + } + + let destination_credential = self.entry(destination_format).or_insert(json!({})); // or_insert should never happen, since repository is initialized with all formats, incl empty json value when not present. + let pointer = JsonPointer::try_from(JsonPath(destination_path)).unwrap(); + let mut leaf_node = construct_leaf_node(&pointer); + if let Some(value) = leaf_node.pointer_mut(&pointer) { + let json_value: Value = Value::Array( + source_value + .into_iter() + .map(Value::String) // Convert each String into serde_json::Value::String + .collect(), + ); + *value = transformation.apply(json_value); + } + + merge(destination_credential, leaf_node); + Ok(None) + } + + Transformation::JsonToMarkdown { + type_: transformation, + source: + DataLocation { + format: source_format, + path: source_path, + }, + destination: + DataLocation { + format: destination_format, + path: destination_path, + }, + } => { + if source_format != mapping.input_format() || destination_format != mapping.output_format() { + return Ok(None); + } + + let source_credential = self.get(&source_format).unwrap(); + + let finder = JsonPathFinder::from_str(&source_credential.to_string(), &source_path).unwrap(); + + let source_value = match finder.find().as_array() { + // todo: still need to investigate other find() return types + Some(array) => array.first().unwrap().clone(), + None => { + return Ok(None); + } + }; + + let destination_credential = self.entry(destination_format).or_insert(json!({})); // or_insert should never happen, since repository is initialized with all formats, incl empty json value when not present. + let pointer = JsonPointer::try_from(JsonPath(destination_path.clone())).unwrap(); + + let mut leaf_node = construct_leaf_node(&pointer); + + // run the source value through a markdown converter to fit the nested objects into a markdown string + let markdown_source_value = json!(json_to_markdown(&source_value, 0)); + + if let Some(value) = leaf_node.pointer_mut(&pointer) { + *value = transformation.apply(markdown_source_value); + } + + merge(destination_credential, leaf_node); + + trace_dbg!("Successfully completed transformation"); + Ok(Some((destination_path, source_path))) + } + + Transformation::MarkdownToJson { + type_: transformation, + source: + DataLocation { + format: source_format, + path: source_path, + }, + destination: + DataLocation { + format: destination_format, + path: destination_path, + }, + } => { + if source_format != mapping.input_format() || destination_format != mapping.output_format() { + return Ok(None); + } + + let source_credential = self.get(&source_format).unwrap(); + + let finder = JsonPathFinder::from_str(&source_credential.to_string(), &source_path).unwrap(); + + let source_value = match finder.find().as_array() { + // todo: still need to investigate other find() return types + Some(array) => array.first().unwrap().clone(), + None => { + return Ok(None); + } + }; + + let destination_credential = self.entry(destination_format).or_insert(json!({})); // or_insert should never happen, since repository is initialized with all formats, incl empty json value when not present. + let pointer = JsonPointer::try_from(JsonPath(destination_path.clone())).unwrap(); + + let mut leaf_node = construct_leaf_node(&pointer); + + if let Some(inner_string) = &source_value.as_str() { + let mut lines: Vec<&str> = inner_string.lines().collect(); + + lines.insert(0, ""); + + // Split the string by newlines and collect into Vec<&str> + let markdown_function_result = markdown_to_json(&lines); + + if let Some(value) = leaf_node.pointer_mut(&pointer) { + *value = transformation.apply(markdown_function_result); + } + } + + merge(destination_credential, leaf_node); + + trace_dbg!("Successfully completed transformation"); + Ok(Some((destination_path, source_path))) + } + + Transformation::AddIdentifier { + type_: transformation, + source: + DataTypeLocation { + format: source_format, + datatype: source_type, + path: source_path, + }, + destination: + DataLocation { + format: destination_format, + path: destination_path, + }, + } => { + if source_format != mapping.input_format() || destination_format != mapping.output_format() { + return Ok(None); + } + + let source_credential = self.get(&source_format).unwrap(); + + let finder = JsonPathFinder::from_str(&source_credential.to_string(), &source_path).unwrap(); + + let source_value = match finder.find().as_array() { + // todo: still need to investigate other find() return types + Some(array) => array.first().unwrap().clone(), + None => { + return Ok(None); + } + }; + + let destination_credential = self.entry(destination_format).or_insert(json!({})); // or_insert should never happen, since repository is initialized with all formats, incl empty json value when not present. + let pointer = JsonPointer::try_from(JsonPath(destination_path.clone())).unwrap(); + + let mut leaf_node = construct_leaf_node(&pointer); + let identifier_function_result = values_to_identity(&source_type, source_value); + + if let Some(value) = leaf_node.pointer_mut(&pointer) { + *value = transformation.apply(identifier_function_result); + } + + merge(destination_credential, leaf_node); + + trace_dbg!("Successfully completed transformation"); + Ok(Some((destination_path, source_path))) + } + + Transformation::IdentifierToObject { + type_: transformation, + source: + DataTypeLocation { + format: source_format, + datatype: source_type, + path: source_path, + }, + destination: + DataLocation { + format: destination_format, + path: destination_path, + }, + } => { + if source_format != mapping.input_format() || destination_format != mapping.output_format() { + return Ok(None); + } + + let source_credential = self.get(&source_format).unwrap(); + + let finder = JsonPathFinder::from_str(&source_credential.to_string(), &source_path).unwrap(); + + let source_value = match finder.find().as_array() { + // todo: still need to investigate other find() return types + Some(array) => array.first().unwrap().clone(), + None => { + return Ok(None); + } + }; + + let destination_credential = self.entry(destination_format).or_insert(json!({})); // or_insert should never happen, since repository is initialized with all formats, incl empty json value when not present. + let pointer = JsonPointer::try_from(JsonPath(destination_path.clone())).unwrap(); + + let mut leaf_node = construct_leaf_node(&pointer); + let identifier_function_result = identity_to_object(&source_type, source_value); + + if let Some(value) = leaf_node.pointer_mut(&pointer) { + *value = transformation.apply(identifier_function_result); + } + + merge(destination_credential, leaf_node); + + trace_dbg!("Successfully completed transformation"); + Ok(Some((destination_path, source_path))) + } + + Transformation::ImageToIndividualDisplay { + type_: transformation, + source: + DataLocation { + format: source_format, + path: source_path, + }, + destination: + DataLocation { + format: destination_format, + path: destination_path, + }, + } => { + if source_format != mapping.input_format() || destination_format != mapping.output_format() { + return Ok(None); + } + + let source_credential = self.get(&source_format).unwrap(); + + let finder = JsonPathFinder::from_str(&source_credential.to_string(), &source_path).unwrap(); + + let source_value = match finder.find().as_array() { + // todo: still need to investigate other find() return types + Some(array) => array.first().unwrap().clone(), + None => { + return Ok(None); + } + }; + + let destination_credential = self.entry(destination_format).or_insert(json!({})); // or_insert should never happen, since repository is initialized with all formats, incl empty json value when not present. + let pointer = JsonPointer::try_from(JsonPath(destination_path.clone())).unwrap(); + + let mut leaf_node = construct_leaf_node(&pointer); + + // run the source value through a markdown converter to fit the nested objects into a markdown string + // let image_individualdisplay_source = Value::Array(vec![json!(create_display_parameter(source_value))]); + let result = create_display_parameter(source_value); + match result { + Ok(image_individualdisplay_source) => { + if let Some(value) = leaf_node.pointer_mut(&pointer) { + *value = transformation.apply(image_individualdisplay_source); + } + } + Err(_error) => { + return Err(_error); + } + } + + merge(destination_credential, leaf_node); + + trace_dbg!("Successfully completed transformation"); + Ok(Some((destination_path, source_path))) + } + + Transformation::ImageToMediaObject { + type_: transformation, + source: + DataLocation { + format: source_format, + path: source_path, + }, + destination: + DataLocation { + format: destination_format, + path: destination_path, + }, + } => { + if source_format != mapping.input_format() || destination_format != mapping.output_format() { + return Ok(None); + } + + let source_credential = self.get(&source_format).unwrap(); + + let finder = JsonPathFinder::from_str(&source_credential.to_string(), &source_path).unwrap(); + + let source_value = match finder.find().as_array() { + // todo: still need to investigate other find() return types + Some(array) => array.first().unwrap().clone(), + None => { + return Ok(None); + } + }; + + let destination_credential = self.entry(destination_format).or_insert(json!({})); // or_insert should never happen, since repository is initialized with all formats, incl empty json value when not present. + let pointer = JsonPointer::try_from(JsonPath(destination_path.clone())).unwrap(); + + let mut leaf_node = construct_leaf_node(&pointer); + + // run the source value through a markdown converter to fit the nested objects into a markdown string + // let image_individualdisplay_source = Value::Array(vec![json!(create_display_parameter(source_value))]); + let result = image_to_elm_media_object(source_value); + match result { + Ok(image_media_object_source) => { + if let Some(value) = leaf_node.pointer_mut(&pointer) { + *value = transformation.apply(image_media_object_source); + } + } + Err(_error) => { + return Err(_error); + } + } + + merge(destination_credential, leaf_node); + + trace_dbg!("Successfully completed transformation"); + Ok(Some((destination_path, source_path))) + } + + Transformation::TitleToSpecifiedByObject { + type_: transformation, + source: + DataLocation { + format: source_format, + path: source_path, + }, + destination: + DataLocation { + format: destination_format, + path: destination_path, + }, + } => { + if source_format != mapping.input_format() || destination_format != mapping.output_format() { + return Ok(None); + } + + let source_credential = self.get(&source_format).unwrap(); + + let finder = JsonPathFinder::from_str(&source_credential.to_string(), &source_path).unwrap(); + + let source_value = match finder.find().as_array() { + // todo: still need to investigate other find() return types + Some(array) => array.first().unwrap().clone(), + None => { + return Ok(None); + } + }; + + let destination_credential = self.entry(destination_format).or_insert(json!({})); // or_insert should never happen, since repository is initialized with all formats, incl empty json value when not present. + let pointer = JsonPointer::try_from(JsonPath(destination_path.clone())).unwrap(); + + let mut leaf_node = construct_leaf_node(&pointer); + // run the source value through a speficfiedby converter to fit the nested objects into a markdown string + let specifiedby_source = json!(title_to_specifiedby(source_value)); + + if let Some(value) = leaf_node.pointer_mut(&pointer) { + *value = transformation.apply(specifiedby_source); + } + + merge(destination_credential, leaf_node); + + trace_dbg!("Successfully completed transformation"); + Ok(Some((destination_path, source_path))) + } + + Transformation::CreditToSpecifiedByObject { + type_: transformation, + source: + DataLocation { + format: source_format, + path: source_path, + }, + destination: + DataLocation { + format: destination_format, + path: destination_path, + }, + } => { + if source_format != mapping.input_format() || destination_format != mapping.output_format() { + return Ok(None); + } + + let source_credential = self.get(&source_format).unwrap(); + + let finder = JsonPathFinder::from_str(&source_credential.to_string(), &source_path).unwrap(); + + let source_value = match finder.find().as_array() { + // todo: still need to investigate other find() return types + Some(array) => array.first().unwrap().clone(), + None => { + return Ok(None); + } + }; + + let destination_credential = self.entry(destination_format).or_insert(json!({})); // or_insert should never happen, since repository is initialized with all formats, incl empty json value when not present. + let pointer = JsonPointer::try_from(JsonPath(destination_path.clone())).unwrap(); + + let mut leaf_node = construct_leaf_node(&pointer); + // run the source value through a speficfiedby converter to fit the nested objects into a markdown string + let cred_specifiedby_source = json!(credentialpoint_values_to_object(source_value)); + + if let Some(value) = leaf_node.pointer_mut(&pointer) { + *value = transformation.apply(cred_specifiedby_source); + } + + merge(destination_credential, leaf_node); + + trace_dbg!("Successfully completed transformation"); + Ok(Some((destination_path, source_path))) + } + + Transformation::EqfToSpecifiedByQualification { + type_: transformation, + source: + DataLocation { + format: source_format, + path: source_path, + }, + destination: + DataLocation { + format: destination_format, + path: destination_path, + }, + } => { + if source_format != mapping.input_format() || destination_format != mapping.output_format() { + return Ok(None); + } + + let source_credential = self.get(&source_format).unwrap(); + + let finder = JsonPathFinder::from_str(&source_credential.to_string(), &source_path).unwrap(); + + let source_value = match finder.find().as_array() { + // todo: still need to investigate other find() return types + Some(array) => array.first().unwrap().clone(), + None => { + return Ok(None); + } + }; + + let destination_credential = self.entry(destination_format).or_insert(json!({})); // or_insert should never happen, since repository is initialized with all formats, incl empty json value when not present. + let pointer = JsonPointer::try_from(JsonPath(destination_path.clone())).unwrap(); + + let mut leaf_node = construct_leaf_node(&pointer); + // run the source value through a speficfiedby converter to fit the nested objects into a markdown string + let cred_specifiedby_source = json!(eqf_to_specifiedby_qualification(source_value)); + + if let Some(value) = leaf_node.pointer_mut(&pointer) { + *value = transformation.apply(cred_specifiedby_source); + } + + merge(destination_credential, leaf_node); + + trace_dbg!("Successfully completed transformation"); + Ok(Some((destination_path, source_path))) + } + + Transformation::LearningSettingToSpecifiedByObject { + type_: transformation, + source: + DataLocation { + format: source_format, + path: source_path, + }, + destination: + DataLocation { + format: destination_format, + path: destination_path, + }, + } => { + if source_format != mapping.input_format() || destination_format != mapping.output_format() { + return Ok(None); + } + + let source_credential = self.get(&source_format).unwrap(); + + let finder = JsonPathFinder::from_str(&source_credential.to_string(), &source_path).unwrap(); + + let source_value = match finder.find().as_array() { + // todo: still need to investigate other find() return types + Some(array) => array.first().unwrap().clone(), + None => { + return Ok(None); } }; @@ -81,50 +660,244 @@ impl Repository { let pointer = JsonPointer::try_from(JsonPath(destination_path.clone())).unwrap(); let mut leaf_node = construct_leaf_node(&pointer); + // run the source value through a speficfiedby converter to fit the nested objects into a markdown string + let learning_setting_specifiedby_source = json!(transform_learning_setting(source_value)); if let Some(value) = leaf_node.pointer_mut(&pointer) { - *value = transformation.apply(source_value); + *value = transformation.apply(learning_setting_specifiedby_source); } merge(destination_credential, leaf_node); trace_dbg!("Successfully completed transformation"); - Some((destination_path, source_path)) + Ok(Some((destination_path, source_path))) } - Transformation::ManyToOne { + + Transformation::AssessmentToProvenBy { type_: transformation, - sources, - destination, + source: + DataLocation { + format: source_format, + path: source_path, + }, + destination: + DataLocation { + format: destination_format, + path: destination_path, + }, } => { - if sources.iter().any(|source| source.format != mapping.input_format()) - || destination.format != mapping.output_format() - { - return None; + if source_format != mapping.input_format() || destination_format != mapping.output_format() { + return Ok(None); } - let source_values = sources - .iter() - .map(|source| { - let source_credential = self.get(&source.format).unwrap(); + let source_credential = self.get(&source_format).unwrap(); - let finder = JsonPathFinder::from_str(&source_credential.to_string(), &source.path).unwrap(); - finder.find().as_array().unwrap().first().unwrap().clone() - }) - .collect::>(); + let finder = JsonPathFinder::from_str(&source_credential.to_string(), &source_path).unwrap(); - let destination_credential = self.entry(destination.format).or_insert(json!({})); - let pointer = JsonPointer::try_from(JsonPath(destination.path.clone())).unwrap(); + let source_value = match finder.find().as_array() { + // todo: still need to investigate other find() return types + Some(array) => array.first().unwrap().clone(), + None => { + return Ok(None); + } + }; + + let destination_credential = self.entry(destination_format).or_insert(json!({})); // or_insert should never happen, since repository is initialized with all formats, incl empty json value when not present. + let pointer = JsonPointer::try_from(JsonPath(destination_path.clone())).unwrap(); let mut leaf_node = construct_leaf_node(&pointer); + // run the source value through a speficfiedby converter to fit the nested objects into a markdown string + let assess_specifiedby_source = json!(assessment_type_to_specifiedby_assesment(source_value)); if let Some(value) = leaf_node.pointer_mut(&pointer) { - *value = transformation.apply(source_values); + *value = transformation.apply(assess_specifiedby_source); + } + + merge(destination_credential, leaf_node); + + trace_dbg!("Successfully completed transformation"); + Ok(Some((destination_path, source_path))) + } + + Transformation::ObjectToNoteLiteral { + type_: transformation, + source: + DataLocation { + format: source_format, + path: source_path, + }, + destination: + DataLocation { + format: destination_format, + path: destination_path, + }, + } => { + if source_format != mapping.input_format() || destination_format != mapping.output_format() { + return Ok(None); + } + + let source_credential = self.get(&source_format).unwrap(); + + let finder = JsonPathFinder::from_str(&source_credential.to_string(), &source_path).unwrap(); + let source_value = match finder.find().as_array() { + // todo: still need to investigate other find() return types + Some(array) => array.first().unwrap().clone(), + None => { + return Ok(None); + } + }; + + let destination_credential = self.entry(destination_format).or_insert(json!({})); // or_insert should never happen, since repository is initialized with all formats, incl empty json value when not present. + let pointer = JsonPointer::try_from(JsonPath(destination_path.clone())).unwrap(); + let mut leaf_node = construct_leaf_node(&pointer); + // run the source value through a speficfiedby converter to fit the nested objects into a markdown string + let object_source = json!(object_to_note_literal(source_value)); + + if let Some(value) = leaf_node.pointer_mut(&pointer) { + *value = transformation.apply(object_source); + } + + merge(destination_credential, leaf_node); + + trace_dbg!("Successfully completed transformation"); + Ok(Some((destination_path, source_path))) + } + + Transformation::TranslateLearningOutcome { + type_: transformation, + source: + DataLocation { + format: source_format, + path: source_path, + }, + destination: + DataLocation { + format: destination_format, + path: destination_path, + }, + } => { + if source_format != mapping.input_format() || destination_format != mapping.output_format() { + return Ok(None); + } + + let source_credential = self.get(&source_format).unwrap(); + + let finder = JsonPathFinder::from_str(&source_credential.to_string(), &source_path).unwrap(); + let source_value = match finder.find().as_array() { + // todo: still need to investigate other find() return types + Some(array) => array.first().unwrap().clone(), + None => { + return Ok(None); + } + }; + + let destination_credential = self.entry(destination_format).or_insert(json!({})); // or_insert should never happen, since repository is initialized with all formats, incl empty json value when not present. + let pointer = JsonPointer::try_from(JsonPath(destination_path.clone())).unwrap(); + let mut leaf_node = construct_leaf_node(&pointer); + // run the source value through a speficfiedby converter to fit the nested objects into a markdown string + // let learning_outcome_source = json!(transform_learning_outcomes(source_value)); + let learning_outcome_source = json!(transform_alignment_to_learning_outcomes(source_value)); + + if let Some(value) = leaf_node.pointer_mut(&pointer) { + *value = transformation.apply(learning_outcome_source); + } + + merge(destination_credential, leaf_node); + + trace_dbg!("Successfully completed transformation"); + Ok(Some((destination_path, source_path))) + } + + Transformation::CreateLearningOutcomeSummary { + type_: transformation, + source: + DataLocation { + format: source_format, + path: source_path, + }, + destination: + DataLocation { + format: destination_format, + path: destination_path, + }, + } => { + if source_format != mapping.input_format() || destination_format != mapping.output_format() { + return Ok(None); + } + + let source_credential = self.get(&source_format).unwrap(); + + let finder = JsonPathFinder::from_str(&source_credential.to_string(), &source_path).unwrap(); + let source_value = match finder.find().as_array() { + // todo: still need to investigate other find() return types + Some(array) => array.first().unwrap().clone(), + None => { + return Ok(None); + } + }; + + let destination_credential = self.entry(destination_format).or_insert(json!({})); // or_insert should never happen, since repository is initialized with all formats, incl empty json value when not present. + let pointer = JsonPointer::try_from(JsonPath(destination_path.clone())).unwrap(); + let mut leaf_node = construct_leaf_node(&pointer); + // run the source value through a speficfiedby converter to fit the nested objects into a markdown string + let learning_outcome_sum_source = json!(create_learning_outcome_summary(source_value)); + + if let Some(value) = leaf_node.pointer_mut(&pointer) { + *value = transformation.apply(learning_outcome_sum_source); + } + + merge(destination_credential, leaf_node); + + trace_dbg!("Successfully completed transformation"); + Ok(Some((destination_path, source_path))) + } + + Transformation::AddressToLocation { + type_: transformation, + source: + DataLocation { + format: source_format, + path: source_path, + }, + destination: + DataLocation { + format: destination_format, + path: destination_path, + }, + } => { + if source_format != mapping.input_format() || destination_format != mapping.output_format() { + return Ok(None); + } + + let source_credential = self.get(&source_format).unwrap(); + + let finder = JsonPathFinder::from_str(&source_credential.to_string(), &source_path).unwrap(); + + let source_value = match finder.find().as_array() { + // todo: still need to investigate other find() return types + Some(array) => array.first().unwrap().clone(), + None => { + return Ok(None); + } + }; + + let destination_credential = self.entry(destination_format).or_insert(json!({})); // or_insert should never happen, since repository is initialized with all formats, incl empty json value when not present. + let pointer = JsonPointer::try_from(JsonPath(destination_path.clone())).unwrap(); + + let mut leaf_node = construct_leaf_node(&pointer); + // run the source value through a markdown converter to fit the nested objects into a markdown string + // let image_individualdisplay_source = Value::Array(vec![json!(create_display_parameter(source_value))]); + let location_source = json!(address_to_location(source_value)); + // let markdown_source_value = json!(image_to_individual_display(source_value)); + + if let Some(value) = leaf_node.pointer_mut(&pointer) { + *value = transformation.apply(location_source); } merge(destination_credential, leaf_node); trace_dbg!("Successfully completed transformation"); - None // Todo: this is not implemented yet, so returns None for now + Ok(Some((destination_path, source_path))) } _ => todo!(), @@ -135,17 +908,22 @@ impl Repository { &mut self, transformations: Vec, mapping: Mapping, - ) -> Vec<(String, String)> { + ) -> Result, &'static str> { let mut completed_fields: Vec<(String, String)> = Vec::new(); - for transformation in transformations { - if let Some(completed_field) = self.apply_transformation(transformation, mapping) { - trace_dbg!(&completed_field); - completed_fields.push(completed_field); + let result = self.apply_transformation(transformation, mapping); + match result { + Ok(Some(completed_field)) => { + completed_fields.push(completed_field); + } + Ok(None) => {} // to do and check //println!("Ok(none)"); + Err(_error) => { + return Err(_error); + } } } - completed_fields + Ok(completed_fields) } pub fn clear_mapping(&mut self, mut output_pointer: String, mapping: Mapping) { @@ -158,32 +936,30 @@ impl Repository { } } -pub fn construct_leaf_node(path: &str) -> Value { - // Split the input string by '/' and filter out any empty parts - let parts: Vec<&str> = path.split('/').filter(|&s| !s.is_empty()).collect(); - - // Initialize the root of the JSON structure as null // todo: isn't this actually the value of the leaf node, not the root? - let mut current_value = Value::Null; - - // Iterate through the parts in reverse order to build the nested structure - for part in parts.into_iter().rev() { - let mut new_object = Map::new(); - new_object.insert(part.to_string(), current_value); - current_value = Value::Object(new_object); - } - - current_value -} - pub fn merge(a: &mut Value, b: Value) { - // todo: here anything non object is actually simply overwritten. So here we need to introduce type checking of the Value b. match (a, b) { (a @ &mut Value::Object(_), Value::Object(b)) => { let a = a.as_object_mut().unwrap(); for (k, v) in b { - merge(a.entry(k).or_insert(Value::Null), v); // + merge(a.entry(k).or_insert(Value::Null), v); + } + } + (a @ &mut Value::Array(_), Value::Array(b_arr)) => { + let a_arr = a.as_array_mut().unwrap(); + let a_len = a_arr.len(); + let b_iter = b_arr.into_iter(); + + for (i, b_val) in b_iter.enumerate() { + if i < a_len { + merge(&mut a_arr[i], b_val); + } else { + a_arr.push(b_val); + } } } + (_, Value::Null) => { + // If the incoming merge Json Value is `Value::Null`, do nothing to the existing Json Value,the current repository, `a` + } (a, b) => *a = b, } } @@ -224,3 +1000,318 @@ fn remove_key_recursive(current_json: &mut Value, keys: &[String]) -> bool { false } + +fn values_to_identity(identity_type: &str, identity_value: Value) -> Value { + //Create a new identity object that is fit for puprose in OBv3 (so not to lose information) + + let mut new_object = Map::new(); + new_object.insert("type".to_string(), Value::String("IdentityObject".to_string())); + new_object.insert("identityHash".to_string(), identity_value); + new_object.insert("identityType".to_string(), Value::String(identity_type.to_string())); + new_object.insert("hashed".to_string(), Value::Bool(false)); + new_object.insert("salt".to_string(), Value::String("not-used".to_string())); + // let _current_value = Value::Object(new_object); + Value::Array(vec![Value::Object(new_object)]) +} + +fn identity_to_object(identity_type: &str, identity_value: Value) -> Value { + //inspect the identity object and re write it so it can be reused in ELM + + //we need to achieve the followin structures: + // "identifier": [ + // { + // "id": "urn:epass:identifier:2", + // "type": "Identifier", + // "notation": "75541452", + // "schemeName": "Student ID" + // } + // ], + + // and for example + // "givenName": { + // "en": ["David"] + // }, + + if let Some(id_value) = identity_value.get("identityHash") { + if identity_type.eq(&"Student ID".to_string()) { + let mut new_object = Map::new(); + new_object.insert("id".to_string(), Value::String("urn:epass:identifier:2".to_string())); + new_object.insert("type".to_string(), Value::String("Identifier".to_string())); + new_object.insert("notation".to_string(), id_value.clone()); + new_object.insert("schemeName".to_string(), Value::String(identity_type.to_string())); + // return the value arrray + Value::Array(vec![Value::Object(new_object)]) + } else { + id_value.clone() + } + } else { + Value::String("".to_string()) + } +} + +fn json_to_markdown(json: &Value, indent_level: usize) -> String { + let mut markdown = String::new(); + let indent = " ".repeat(indent_level); + + match json { + // Handle JSON objects (key-value pairs) + Value::Object(map) => { + for (key, value) in map { + // Add the key as a bold label + markdown.push_str(&format!("{}**{}**:\n", indent, key)); + // Recursively handle the value + markdown.push_str(&json_to_markdown(value, indent_level + 1)); + } + } + + // Handle JSON arrays + Value::Array(array) => { + for item in array { + // Add each array item as a list item + markdown.push_str(&format!("{}- ", indent)); + markdown.push_str(&json_to_markdown(item, indent_level + 1)); + } + } + + // Handle primitive types: strings, numbers, booleans, and null + Value::String(s) => markdown.push_str(&format!("{}{}\n", indent, s)), + Value::Number(n) => markdown.push_str(&format!("{}{}\n", indent, n)), + Value::Bool(b) => markdown.push_str(&format!("{}{}\n", indent, b)), + Value::Null => markdown.push_str(&format!("{}null\n", indent)), + } + + markdown +} + +fn markdown_to_json(lines: &[&str]) -> Value { + // Recursively converts indented lines of Markdown into a JSON structure. + // 1. Parsing Markdown: + // • Headings (#): These are treated as keys in the resulting JSON object. + // • Bold Text (**): This is also treated as a key in the JSON object. + // • List Items (-): These are treated as elements in a JSON array. + // • Plain Text: If it’s not part of a list or a key, it’s treated as a value associated with the last key in the current JSON object. + // 2. Indentation Handling: + // • The code tracks the current indentation level of the Markdown. If the indentation increases, it means a new nested structure (object or array) is starting. If it decreases, the last completed structure is attached to the parent object or array. + // 3. Stack Management: + // • A stack is used to manage the nested structure. Each time a new nested object or array is detected, it’s pushed onto the stack. Once the nesting ends (indentation decreases), the structure is popped from the stack and integrated into the parent structure. + // 4. Regex Patterns: + // • heading_regex: Matches Markdown headings (e.g., # Title). + // • bold_regex: Matches bolded keys (e.g., **Key**:). + // • list_item_regex: Matches list items (e.g., - item). + + let mut i = 0; + let mut position: Vec = Vec::new(); + + //lets create a string to which we will concatenate new lines based on the markdown lines + position.insert(0, "".to_string()); + let mut json_string = String::from(""); + // evaluate if the input contains markdown or not + // if markdown is detected we will try to create json otherwise the value of the "markdown" will be put straight into the attribute + if !lines.contains(&"**") { + while i < lines.len() { + let line = lines[i]; + json_string.push_str(line); + i += 1; + } + let parsed_json: Value = serde_json::to_value(&json_string).unwrap(); + parsed_json + } else { + while i < lines.len() { + let line = lines[i]; + + // Handle key-value pairs (e.g., **key**: value) + let (obj_type, depth) = evaluate_line(line); + if obj_type == "E" && i == 0 { + // open a json object + json_string.push_str("{\n"); + } + + if obj_type == "O" { + while depth < position.len() - 1 { + // we need to close the positions + if let Some(last_value) = position.last() { + if last_value == "O" { + // The last value is O we can now close this object + if let Some(_last_value) = position.pop() { + json_string.pop(); + json_string = json_string.trim_end_matches(',').to_string(); + json_string.push_str("},\n"); + } + } else if last_value == "A" { + // close value A + if let Some(_last_value) = position.pop() { + json_string.push_str("]\n"); + } + } else if last_value == "OA" && depth < position.len() - 1 { + //The last value is OA + if let Some(_last_value) = position.pop() { + // first close the array + json_string.pop(); + json_string = json_string.trim_end_matches(',').to_string(); + json_string.push_str("],\n"); + if depth > 0 { + if let Some(_last_value) = position.pop() { + // then close the object + json_string.push_str("},\n"); + } + } else { + //"The vector was empty, nothing to remove."); + } + } else { + // ("The vector was empty, nothing to remove."); + } + } else { + // we have a different last value we will remove it from tha vector + if let Some(_last_value) = position.pop() { + // json_string.push_str("]\n"); + } + } + } else { + // println!("The vector is empty."); + } + } + + // setup the vector array for the right value and position + if depth >= position.len() - 1 && i > 0 { + //test previous line to see is we might have a nested object + let (last_obj_type, _new_depth) = evaluate_line(lines[i - 1]); + if last_obj_type == "O" { + json_string.push('{'); + json_string.push_str(&cleanup_string(line)); + json_string.push(':'); + position.insert(depth, "O".to_string()); + } else if let Some(last_value) = position.last() { + if last_value == "OA" && depth == position.len() - 1 { + json_string.push_str(&cleanup_string(line)); + json_string.push(':'); + } else if depth > position.len() - 1 { + json_string.push('{'); + json_string.push_str(&cleanup_string(line)); + json_string.push(':'); + position.insert(depth, "O".to_string()); + } else { + json_string.push_str(&cleanup_string(line)); + json_string.push(':'); + position[depth] = "O".to_string(); + } + } + } + } else if obj_type == "A" { + while depth < position.len() - 1 { + // we need to close the positions + if let Some(last_value) = position.last() { + if last_value == "O" { + if let Some(_last_value) = position.pop() { + json_string.push_str("},\n"); + } + } else if last_value == "A" { + if let Some(_last_value) = position.pop() { + json_string.push_str("]\n"); + } + } else { + // The last value is something leave it + } + } else { + // The vector is empty. + } + } + + // setup the vector array for the right value and position + if depth >= position.len() - 1 { + if let Some(last_value) = position.last() { + if last_value == "OA" { + json_string.push('['); + } else if last_value == "A" && depth == position.len() - 1 { + position.insert(depth, "A".to_string()); + } else { + position.insert(depth, "A".to_string()); + json_string.push('['); + } + } + json_string.push_str(&cleanup_string(line)); + } + } else if obj_type == "OA" { + while depth < position.len() - 1 { + // we need to close the positions + if let Some(last_value) = position.last() { + if last_value == "O" { + if let Some(_last_value) = position.pop() { + json_string.pop(); + json_string.pop(); + json_string.push_str("},\n"); + } + } else if last_value == "A" { + if let Some(_last_value) = position.pop() { + json_string.push_str("]\n"); + } else { + // The vector was empty, nothing to remove. + } + } else { + // The last value is something else leave it + } + } else { + // The vector is empty + } + } + + // we are creating a new array that will contain objects of the same type + json_string.push_str("[ \n {"); + json_string.push_str(&cleanup_string(line)); + json_string.push(':'); + // test if extra handling is needed for closing + position.insert(depth - 1, "OA".to_string()); + position.insert(depth, "O".to_string()); + } else if obj_type == "V" { + json_string.push_str(&cleanup_string(line)); + json_string.push_str(",\n"); + } + + i += 1; + } + + // Finalize the string to which we will concatenate new lines based on the markdown lines + json_string.pop(); + json_string = json_string.trim_end_matches(',').to_string(); + json_string.push_str("\n}"); + let parsed_json: Value = serde_json::from_str(&json_string).unwrap(); + parsed_json + } +} + +fn evaluate_line(line_to_test: &str) -> (String, usize) { + //test depth + let mut depth = line_to_test.chars().take_while(|c| c.is_whitespace()).count() / 2; + //test type + let line_type; + let trimmed = line_to_test.trim(); + if line_to_test.is_empty() { + // Handle list as object items of previous depth + line_type = "E"; + } else if trimmed.starts_with("-") && trimmed.ends_with("**:") { + // Handle list as object items of previous depth + line_type = "OA"; + depth += 1; + } else if trimmed.starts_with("**") { + // Handle list as object items of previous depth + line_type = "O"; + } else if trimmed.starts_with("-") { + // Handle as array items of previous depth + line_type = "A"; + } else { + // Handle value of previous depth + line_type = "V"; + } + + (line_type.to_string(), depth) +} + +fn cleanup_string(string_to_clean: &str) -> String { + //trim the string + let string_to_clean1 = string_to_clean.trim(); + let string_to_clean2 = string_to_clean1.replace("-", ""); + let string_to_clean3 = string_to_clean2.trim(); + let string_to_clean4 = string_to_clean3.replace("**:", ""); + let cleaned_string = string_to_clean4.trim().trim_matches('*').to_string(); + // Add quotes around the cleaned string + format!("\"{}\"", cleaned_string) +} diff --git a/src/backend/routes/api.rs b/src/backend/routes/api.rs new file mode 100644 index 0000000..0475b67 --- /dev/null +++ b/src/backend/routes/api.rs @@ -0,0 +1,205 @@ +use axum::{ + // routing::post, + // Router, + http::{header, HeaderMap, HeaderValue, StatusCode}, + response::IntoResponse, + Json, +}; +//use config::Value; +use serde_json::{json, Value}; + +use crate::backend::base64_encode::{decode_json, encode_json_file}; +use crate::backend::headless_cli::load_files_apply_transformations; +use crate::state::{AppState, Mapping}; +use std::{fs::File, io::Write, path::Path}; +use tokio::fs; + +pub async fn api(Json(input_json): Json) -> impl IntoResponse { + //test the input types for this API + // with JSON body: { + // "From": {"Name": "OB", "Version": "3.0"}, + // "To": {"Name": "elm", "Version": "3.2"}, + // "Parameters": { "PreferredLanguages": ["en", "sv"]}, + // "Content": "Base 64 encoded content in From format" + // } + + // Handle the file upload + let input_file_path; + let mapping_file_name; + let mapping_type; + + // Create directories for uploads and outputs if they don't exist + let upload_dir = "uploads"; + let output_dir = "outputs"; + let file_name = "export_file"; + let _ = fs::create_dir_all(upload_dir).await.map_err(|_| { + let error_json = json!({ + "error": "Internal Server Error", + "message" : "Failed to create upload directory"}); + (StatusCode::INTERNAL_SERVER_ERROR, Json(error_json)) + }); + let _ = fs::create_dir_all(output_dir).await.map_err(|_| { + let error_json = json!({ + "error": "Internal Server Error", + "message" : "Failed to create output directory"}); + (StatusCode::INTERNAL_SERVER_ERROR, Json(error_json)) + }); + + match input_json + .get("From") + .and_then(|v| v.get("Name")) + .and_then(|v| v.as_str()) + { + Some("OB") => { + mapping_file_name = "json/mapping/custom_mapping_OBv3_ELM_latest.json".to_string(); + mapping_type = Mapping::OBv3ToELM; + } + Some("ELM") => { + mapping_file_name = "json/mapping/custom_mapping_ELM_OBv3_latest.json".to_string(); + mapping_type = Mapping::ELMToOBv3; + } + Some(value) => { + let error_json = json!({ + "error": "Bad Request", + "message" : format!("Invalid translation value: {}", value)}); + return (StatusCode::BAD_REQUEST, Json(error_json)); + } + None => { + let error_json = json!({ + "error": "Bad Request", + "message" : "Invalid translation value: no key found"}); + return (StatusCode::BAD_REQUEST, Json(error_json)); + } + } + + match input_json.get("Content").and_then(|v| v.as_str()) { + Some(value) => { + input_file_path = format!("{}/{}", upload_dir, file_name); + let file = File::create(&input_file_path).map_err(|_| { + let error_json = json!({ + "error": "Internal Server Error", + "message" : "Failed to create file"}); + (StatusCode::INTERNAL_SERVER_ERROR, Json(error_json)) + }); + match decode_json(value) { + Ok(data) => { + match file { + Ok(mut file_found) => { + let _ = file_found.write_all(&data); + } + Err(file_error) => { + return file_error; + } // Err(file_error) => {let error_json = json!({ + // "error": "Internal Server Error", + // "message" : "Failed to write to file"}); + // return (StatusCode::INTERNAL_SERVER_ERROR, Json(error_json));} + } + } + Err(_decode_err) => { + let error_json = json!({ + "error": "Internal Server Error", + "message" : "Failed to read file data"}); + return (StatusCode::INTERNAL_SERVER_ERROR, Json(error_json)); + } + } + } + + None => { + let error_json = json!({ + "error": "Bad Request", + "message" : "Invalid data value: no key found"}); + return (StatusCode::BAD_REQUEST, Json(error_json)); + } + } + + // Define the output file path + let output_file_name = format!( + "translated_{}", + Path::new(&input_file_path).file_name().unwrap().to_str().unwrap() + ); + let output_file_path = format!("{}/{}", output_dir, output_file_name); + + // start mapping based on the input form the API + // 1 create a state needed for the mapping tool + // 2 load all hte state elements needed for mapping + + let mut state = AppState { + input_path: input_file_path, + output_path: output_file_path.clone(), + mapping_path: mapping_file_name, + mapping: mapping_type, + ..Default::default() + }; + // let mut state = AppState::default(); + // state.input_path = _input_file_path; + // state.output_path = output_file_path.clone(); + // state.mapping_path = _mapping_file_name; + // state.mapping = _mapping_type; + + load_files_apply_transformations(&mut state); + + // Return the translated file as a response + // 1 load file from fs into mem + // 2 remove file from fs + // 3 push mem to http output + + let output_file = fs::read(&output_file_path).await.map_err(|_| { + let error_json = json!({ + "error": "Internal Server Error", + "message" : "Failed to read output file"}); + (StatusCode::INTERNAL_SERVER_ERROR, Json(error_json)) + }); + let _ = fs::remove_file(state.input_path).await.map_err(|_| { + let error_json = json!({ + "error": "Internal Server Error", + "message" : "Failed to remove input file"}); + (StatusCode::INTERNAL_SERVER_ERROR, Json(error_json)) + }); + let _ = fs::remove_file(state.output_path).await.map_err(|_| { + let error_json = json!({ + "error": "Internal Server Error", + "message" : "Failed to remove output file"}); + (StatusCode::INTERNAL_SERVER_ERROR, Json(error_json)) + }); + + // Set the headers, including content disposition for download + let mut headers = HeaderMap::new(); + // For better integration into EDCI change the output_file_name from *.json to *.jsonld + headers.insert( + header::CONTENT_TYPE, + HeaderValue::from_static("application/application/json"), + ); + + //println!("state_exitwarning: {:#?}", state.exit_warning); + match state.exit_warning { + true => { + let error_json = json!({ + "error": "Internal Server Error", + "message" : "Failed to encode the json file"}); + return (StatusCode::INTERNAL_SERVER_ERROR, Json(error_json)); + } + false => {} + } + + match output_file { + Ok(content) => match encode_json_file(content) { + Ok(encoded_json) => { + let response_json = json!({"content": encoded_json}); + (StatusCode::OK, Json(response_json)) + } + Err(_enc_error) => { + let error_json = json!({ + "error": "Internal Server Error", + "message" : "Failed to encode the json file"}); + (StatusCode::INTERNAL_SERVER_ERROR, Json(error_json)) + } + }, + Err(status) => status, + } + // let encoded_json = encode_json_file(output_file)?; + + // // Return the file content along with the appropriate headers + // let response_json = json!({"content": encoded_json}); + // (StatusCode::OK, Json(response_json)) + // // Ok(output_file.into_response()) +} diff --git a/src/backend/routes/mod.rs b/src/backend/routes/mod.rs new file mode 100644 index 0000000..fa62726 --- /dev/null +++ b/src/backend/routes/mod.rs @@ -0,0 +1,20 @@ +pub mod api; +pub mod root; +pub mod translate_file; + +use axum::{extract::DefaultBodyLimit, routing::get, routing::post, Router}; +//use save_file::save_file; +use api::api; +use root::root; +use translate_file::translate_file; + +pub fn create_router() -> Router { + Router::new() + .route( + "/translate_file", + post(translate_file).route_layer(DefaultBodyLimit::max(135476000)), + ) + .route("/api", post(api).route_layer(DefaultBodyLimit::max(135476000))) + .route("/", get(root)) + // .layer(tower_http::trace::TraceLayer::new_for_http()) +} diff --git a/src/backend/routes/root.rs b/src/backend/routes/root.rs new file mode 100644 index 0000000..29f6f88 --- /dev/null +++ b/src/backend/routes/root.rs @@ -0,0 +1,44 @@ +use axum::{ + response::Html, + // routing::post, + // Router, +}; + +pub async fn root() -> Html<&'static str> { + Html( + r#" + + + Open Badges to ELM converter + +

Open Badges to ELM converter

+

+ This from is part of a service to translate Open Badges to ELM European Digital Credentials.
+ The code as two parts a webservice that is called through this form and a CLI.
+ The CLI can be found at the Educredentials github respository +

+
+ +

+ +

+ +

+

+ for testing of the created credential in ELM format check here +

+ + + "#, + ) +} diff --git a/src/backend/routes/translate_file.rs b/src/backend/routes/translate_file.rs new file mode 100644 index 0000000..c3aff61 --- /dev/null +++ b/src/backend/routes/translate_file.rs @@ -0,0 +1,177 @@ +use axum::extract::multipart::Field; +use axum::{ + extract::Multipart, + // routing::post, + // Router, + http::{header, HeaderMap, HeaderValue, StatusCode}, + response::{IntoResponse, Response}, +}; + +use crate::backend::headless_cli::load_files_apply_transformations; +use crate::state::{AppState, Mapping}; +use std::{fs::File, io::Write, path::Path}; +use tokio::fs; + +pub async fn translate_file(mut multipart: Multipart) -> Result { + // Create directories for uploads and outputs if they don't exist + let upload_dir = "uploads"; + let output_dir = "outputs"; + fs::create_dir_all(upload_dir).await.map_err(|_| { + ( + StatusCode::INTERNAL_SERVER_ERROR, + "Failed to create upload directory".to_string(), + ) + })?; + fs::create_dir_all(output_dir).await.map_err(|_| { + ( + StatusCode::INTERNAL_SERVER_ERROR, + "Failed to create output directory".to_string(), + ) + })?; + + // Handle the file upload + let mut input_file_path = String::new(); + let mut mapping_file_name = String::new(); + let mut mapping_type = Mapping::default(); + + while let Some(field) = multipart + .next_field() + .await + .map_err(|_| (StatusCode::BAD_REQUEST, "Failed to process uploaded file".to_string()))? + { + let name = field.name().unwrap().to_string(); + match name.as_str() { + "input_file" => match process_file_field(&field) { + Ok(file_name) => { + input_file_path = format!("{}/{}", upload_dir, file_name); + let mut file = File::create(&input_file_path) + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Failed to create file".to_string()))?; + let data = field.bytes().await.map_err(|_| { + ( + StatusCode::INTERNAL_SERVER_ERROR, + "Failed to read file data".to_string(), + ) + })?; + file.write_all(&data) + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Failed to write to file".to_string()))?; + } + Err(e) => eprintln!("Error: {}", e), + }, + "translation" => { + // Mapping::OBv3ToELM => "OBv3".to_string(), + // Mapping::ELMToOBv3 => "ELM".to_string(), + if let Ok(translation_value) = field.text().await { + // Match on the value of the text field and call different functions + match translation_value.as_str() { + "OBv3ToELM" => { + mapping_file_name = "json/mapping/custom_mapping_OBv3_ELM_latest.json".to_string(); + mapping_type = Mapping::OBv3ToELM; + } + "ELMToOBv3" => { + mapping_file_name = "json/mapping/custom_mapping_ELM_OBv3_latest.json".to_string(); + mapping_type = Mapping::ELMToOBv3; + } + _ => { + return Err(( + StatusCode::BAD_REQUEST, + format!("Invalid translation value: {}", translation_value), + )) + } + }; + } else { + // Handle the case where reading the field text fails + return Err((StatusCode::BAD_REQUEST, "Failed to read translation value".to_string())); + } + } + &_ => return Err((StatusCode::BAD_REQUEST, "Received unwanted values".to_string())), + } + } + + // Define the output file path + let output_file_name = format!( + "translated_{}", + Path::new(&input_file_path).file_name().unwrap().to_str().unwrap() + ); + let output_file_path = format!("{}/{}", output_dir, output_file_name); + + // start mapping based on the input form the API + // 1 create a state needed for the mapping tool + // 2 load all hte state elements needed for mapping + + //let mut state = AppState::default(); + let mut state = AppState { + input_path: input_file_path, + output_path: output_file_path.clone(), + mapping_path: mapping_file_name, + mapping: mapping_type, + ..Default::default() + }; + // state.input_path = input_file_path; + // state.output_path = output_file_path.clone(); + // state.mapping_path = mapping_file_name; + // state.mapping = mapping_type; + + load_files_apply_transformations(&mut state); + + // Return the translated file as a response + // 1 load file from fs into mem + // 2 remove file from fs + // 3 push mem to http output + + let output_file = fs::read(&output_file_path).await.map_err(|_| { + ( + StatusCode::INTERNAL_SERVER_ERROR, + "Failed to read output file".to_string(), + ) + })?; + fs::remove_file(state.input_path).await.map_err(|_| { + ( + StatusCode::INTERNAL_SERVER_ERROR, + "Failed to remove output file".to_string(), + ) + })?; + fs::remove_file(state.output_path).await.map_err(|_| { + ( + StatusCode::INTERNAL_SERVER_ERROR, + "Failed to remove output file".to_string(), + ) + })?; + + //println!("state_exitwarning: {:#?}", state.exit_warning); + if state.exit_warning { + return Err(( + StatusCode::INTERNAL_SERVER_ERROR, + "Failed to encode the json file".to_string(), + )); + } + // let error_json = json!({ + // "error": "Internal Server Error", + // "message" : "Failed to encode the json file"}); + // return (StatusCode::INTERNAL_SERVER_ERROR, Json(error_json)); + + // Set the headers, including content disposition for download + let mut headers = HeaderMap::new(); + // For better integration into EDCI change the output_file_name from *.json to *.jsonld + let mut long_output_file_name = output_file_name; + long_output_file_name.push_str("ld"); + headers.insert( + header::CONTENT_TYPE, + HeaderValue::from_static("application/octet-stream"), + ); + headers.insert( + header::CONTENT_DISPOSITION, + HeaderValue::from_str(&format!("attachment; filename=\"{}\"", long_output_file_name)).unwrap(), + ); + + // Return the file content along with the appropriate headers + Ok((headers, output_file).into_response()) + + // Ok(output_file.into_response()) +} + +fn process_file_field(field: &Field) -> Result { + match field.file_name() { + Some(file_name) => Ok(file_name.to_string()), + None => Err("No file name found in the field.".to_string()), + } +} diff --git a/src/backend/transformations.rs b/src/backend/transformations.rs index fca23ff..bdf2efe 100644 --- a/src/backend/transformations.rs +++ b/src/backend/transformations.rs @@ -95,6 +95,244 @@ impl ManyToOne { } } +#[allow(non_camel_case_types)] +#[derive(Serialize, Deserialize, Debug, Clone)] +pub enum StringToOne { + stringit, +} + +impl StringToOne { + pub fn apply(&self, value: String) -> Value { + match self { + StringToOne::stringit => Value::String(value), + } + } +} + +#[allow(non_camel_case_types)] +#[derive(Serialize, Deserialize, Debug, Clone)] +pub enum StringArrayToOne { + stringArrayIt, +} + +impl StringArrayToOne { + pub fn apply(&self, value: Value) -> Value { + match self { + StringArrayToOne::stringArrayIt => value, + } + } +} + +#[allow(non_camel_case_types)] +#[derive(Serialize, Deserialize, Debug, Clone)] +pub enum JsonToMarkdown { + jsonToMarkdown, +} + +impl JsonToMarkdown { + pub fn apply(&self, value: Value) -> Value { + match self { + JsonToMarkdown::jsonToMarkdown => value, + } + } +} + +#[allow(non_camel_case_types)] +#[derive(Serialize, Deserialize, Debug, Clone)] +pub enum MarkdownToJson { + markdownToJson, +} + +impl MarkdownToJson { + pub fn apply(&self, value: Value) -> Value { + match self { + MarkdownToJson::markdownToJson => value, + } + } +} + +#[allow(non_camel_case_types)] +#[derive(Serialize, Deserialize, Debug, Clone)] +pub enum AddIdentifier { + addIdentifier, +} + +impl AddIdentifier { + pub fn apply(&self, value: Value) -> Value { + match self { + AddIdentifier::addIdentifier => value, + } + } +} + +#[allow(non_camel_case_types)] +#[derive(Serialize, Deserialize, Debug, Clone)] +pub enum IdentifierToObject { + identifierToObject, +} + +impl IdentifierToObject { + pub fn apply(&self, value: Value) -> Value { + match self { + IdentifierToObject::identifierToObject => value, + } + } +} + +#[allow(non_camel_case_types)] +#[derive(Serialize, Deserialize, Debug, Clone)] +pub enum ImageToIndividualDisplay { + imageToIndividualDisplay, +} + +impl ImageToIndividualDisplay { + pub fn apply(&self, value: Value) -> Value { + match self { + ImageToIndividualDisplay::imageToIndividualDisplay => value, + } + } +} + +#[allow(non_camel_case_types)] +#[derive(Serialize, Deserialize, Debug, Clone)] +pub enum AssessmentToProvenBy { + assessmentToProvenBy, +} + +impl AssessmentToProvenBy { + pub fn apply(&self, value: Value) -> Value { + match self { + AssessmentToProvenBy::assessmentToProvenBy => value, + } + } +} + +#[allow(non_camel_case_types)] +#[derive(Serialize, Deserialize, Debug, Clone)] +pub enum ObjectToNoteLiteral { + objectToNoteLiteral, +} + +impl ObjectToNoteLiteral { + pub fn apply(&self, value: Value) -> Value { + match self { + ObjectToNoteLiteral::objectToNoteLiteral => value, + } + } +} + +#[allow(non_camel_case_types)] +#[derive(Serialize, Deserialize, Debug, Clone)] +pub enum TranslateLearningOutcome { + translateLearningOutcome, +} + +impl TranslateLearningOutcome { + pub fn apply(&self, value: Value) -> Value { + match self { + TranslateLearningOutcome::translateLearningOutcome => value, + } + } +} + +#[allow(non_camel_case_types)] +#[derive(Serialize, Deserialize, Debug, Clone)] +pub enum CreateLearningOutcomeSummary { + createLearningOutcomeSummary, +} + +impl CreateLearningOutcomeSummary { + pub fn apply(&self, value: Value) -> Value { + match self { + CreateLearningOutcomeSummary::createLearningOutcomeSummary => value, + } + } +} + +#[allow(non_camel_case_types)] +#[derive(Serialize, Deserialize, Debug, Clone)] +pub enum CreditToSpecifiedByObject { + creditToSpecifiedByObject, +} + +impl CreditToSpecifiedByObject { + pub fn apply(&self, value: Value) -> Value { + match self { + CreditToSpecifiedByObject::creditToSpecifiedByObject => value, + } + } +} + +#[allow(non_camel_case_types)] +#[derive(Serialize, Deserialize, Debug, Clone)] +pub enum EqfToSpecifiedByQualification { + eqfToSpecifiedByQualification, +} + +impl EqfToSpecifiedByQualification { + pub fn apply(&self, value: Value) -> Value { + match self { + EqfToSpecifiedByQualification::eqfToSpecifiedByQualification => value, + } + } +} + +#[allow(non_camel_case_types)] +#[derive(Serialize, Deserialize, Debug, Clone)] +pub enum LearningSettingToSpecifiedByObject { + learningSettingToSpecifiedByObject, +} + +impl LearningSettingToSpecifiedByObject { + pub fn apply(&self, value: Value) -> Value { + match self { + LearningSettingToSpecifiedByObject::learningSettingToSpecifiedByObject => value, + } + } +} + +#[allow(non_camel_case_types)] +#[derive(Serialize, Deserialize, Debug, Clone)] +pub enum TitleToSpecifiedByObject { + titleToSpecifiedByObject, +} + +impl TitleToSpecifiedByObject { + pub fn apply(&self, value: Value) -> Value { + match self { + TitleToSpecifiedByObject::titleToSpecifiedByObject => value, + } + } +} + +#[allow(non_camel_case_types)] +#[derive(Serialize, Deserialize, Debug, Clone)] +pub enum ImageToMediaObject { + imageToMediaObject, +} + +impl ImageToMediaObject { + pub fn apply(&self, value: Value) -> Value { + match self { + ImageToMediaObject::imageToMediaObject => value, + } + } +} + +#[allow(non_camel_case_types)] +#[derive(Serialize, Deserialize, Debug, Clone)] +pub enum AddressToLocation { + addressToLocation, +} + +impl AddressToLocation { + pub fn apply(&self, value: Value) -> Value { + match self { + AddressToLocation::addressToLocation => value, + } + } +} + #[derive(Serialize, Deserialize, Debug, Clone)] #[serde(untagged)] pub enum Transformation { @@ -103,6 +341,91 @@ pub enum Transformation { source: DataLocation, destination: DataLocation, }, + StringToOne { + type_: StringToOne, + source: StringValue, + destination: DataLocation, + }, + StringArrayToOne { + type_: StringArrayToOne, + source: StringArrayValue, + destination: DataLocation, + }, + MarkdownToJson { + type_: MarkdownToJson, + source: DataLocation, + destination: DataLocation, + }, + JsonToMarkdown { + type_: JsonToMarkdown, + source: DataLocation, + destination: DataLocation, + }, + AddIdentifier { + type_: AddIdentifier, + source: DataTypeLocation, + destination: DataLocation, + }, + IdentifierToObject { + type_: IdentifierToObject, + source: DataTypeLocation, + destination: DataLocation, + }, + ImageToIndividualDisplay { + type_: ImageToIndividualDisplay, + source: DataLocation, + destination: DataLocation, + }, + ImageToMediaObject { + type_: ImageToMediaObject, + source: DataLocation, + destination: DataLocation, + }, + TitleToSpecifiedByObject { + type_: TitleToSpecifiedByObject, + source: DataLocation, + destination: DataLocation, + }, + EqfToSpecifiedByQualification { + type_: EqfToSpecifiedByQualification, + source: DataLocation, + destination: DataLocation, + }, + LearningSettingToSpecifiedByObject { + type_: LearningSettingToSpecifiedByObject, + source: DataLocation, + destination: DataLocation, + }, + CreditToSpecifiedByObject { + type_: CreditToSpecifiedByObject, + source: DataLocation, + destination: DataLocation, + }, + AssessmentToProvenBy { + type_: AssessmentToProvenBy, + source: DataLocation, + destination: DataLocation, + }, + ObjectToNoteLiteral { + type_: ObjectToNoteLiteral, + source: DataLocation, + destination: DataLocation, + }, + TranslateLearningOutcome { + type_: TranslateLearningOutcome, + source: DataLocation, + destination: DataLocation, + }, + CreateLearningOutcomeSummary { + type_: CreateLearningOutcomeSummary, + source: DataLocation, + destination: DataLocation, + }, + AddressToLocation { + type_: AddressToLocation, + source: DataLocation, + destination: DataLocation, + }, OneToMany { type_: OneToMany, source: DataLocation, @@ -120,3 +443,20 @@ pub struct DataLocation { pub format: String, pub path: String, } + +#[derive(Serialize, Deserialize, Debug, Clone)] +pub struct DataTypeLocation { + pub format: String, + pub datatype: String, + pub path: String, +} + +#[derive(Serialize, Deserialize, Debug, Clone)] +pub struct StringValue { + pub value: String, +} + +#[derive(Serialize, Deserialize, Debug, Clone)] +pub struct StringArrayValue { + pub value: Vec, +} diff --git a/src/backend/web.rs b/src/backend/web.rs new file mode 100644 index 0000000..cf5e298 --- /dev/null +++ b/src/backend/web.rs @@ -0,0 +1,59 @@ +use crate::backend::routes::create_router; + +use eyre::Result; + +use std::net::{IpAddr, SocketAddr}; +use std::str::FromStr; + +pub struct Server { + address: IpAddr, + port: u16, +} + +impl Server { + pub fn new(address: Option) -> Self { + // Use default address if no input is provided + let default_address = "127.0.0.1".to_string(); + let default_port = 3000; + + // Parse the provided address and port or fall back to defaults + let address = address.unwrap_or(default_address); + let mut split = address.split(':'); + let ip_part = split.next().unwrap_or("127.0.0.1"); + let port_part = split.next().unwrap_or("3000"); + + let address: IpAddr = IpAddr::from_str(ip_part).unwrap_or_else(|_| IpAddr::from([127, 0, 0, 1])); + let port: u16 = port_part.parse().unwrap_or(default_port); + + Self { address, port } + } + + pub async fn run(&self) -> Result<()> { + let app = create_router(); + let address = SocketAddr::from((self.address, self.port)); + + tracing::info!("server running on port: {}", self.port); + + // run our app with hyper, listening globally on port 3000 + let listener = tokio::net::TcpListener::bind(address).await.unwrap(); + axum::serve(listener, app).await.unwrap(); + + Ok(()) + } +} + +impl Default for Server { + fn default() -> Self { + Self::new(None) + } +} + +#[tokio::main] +pub async fn api_service(address: Option) { + let server = Server::new(address); + + match server.run().await { + Ok(_) => println!("Server exited"), + Err(error) => panic!("Server exited with error: {error}"), + } +} diff --git a/src/lib_2.rs b/src/lib_2.rs new file mode 100755 index 0000000..04a09d6 --- /dev/null +++ b/src/lib_2.rs @@ -0,0 +1,41 @@ +use std::net::SocketAddr; + +use eyre::Result; +use routes::create_router; + +mod routes; + +pub struct Server { + address: [u8; 4], + port: u16, +} + +impl Server { + pub fn new() -> Self { + let address = [127, 0, 0, 1]; + let port = 3000; + + Self { address, port } + } + + pub async fn run(&self) -> Result<()> { + tracing_subscriber::fmt::init(); + + let app = create_router(); + let address = SocketAddr::from((self.address, self.port)); + + tracing::info!("server running on port: {}", self.port); + + // run our app with hyper, listening globally on port 3000 + let listener = tokio::net::TcpListener::bind(address).await.unwrap(); + axum::serve(listener, app).await.unwrap(); + + Ok(()) + } +} + +impl Default for Server { + fn default() -> Self { + Self::new() + } +} diff --git a/src/main.rs b/src/main.rs index c680df3..11e97b1 100644 --- a/src/main.rs +++ b/src/main.rs @@ -17,6 +17,7 @@ use crossterm::execute; use crossterm::terminal::{disable_raw_mode, enable_raw_mode, EnterAlternateScreen, LeaveAlternateScreen}; use ratatui::prelude::{CrosstermBackend, Terminal}; use std::io::{stdout, Result}; +use std::net::SocketAddr; // Load I18n macro, for allow you use `t!` macro in anywhere. #[macro_use] @@ -29,11 +30,27 @@ fn main() -> Result<()> { let mut state = AppState::default(); + // if arguments are passed we are working headless + // two options: + // 1. headless CLI (with arguments -o -i -m) + // 2. headless webservice (with argument -w) if std::env::args().len() > 1 { trace_dbg!("Arguments detected, running headless conversion"); - let mut cli_args = Args::parse(); - run_headless(&mut cli_args, &mut state)?; + println!("Arguments detected, running headless conversion"); + let args: Vec = std::env::args().collect(); + if args.contains(&"-w".to_string()) { + println!("Let's run the webservice!!!"); + if args[args.len() - 1].parse::().is_ok() { + println!("Let's use {}", args[2].clone()); + crate::backend::web::api_service(Some(args[args.len() - 1].clone())); + } else { + println!("The webservice runs default 127.0.0.1:3000"); + crate::backend::web::api_service(None); + } + } else { + run_headless(&mut cli_args, &mut state)?; + } } else { trace_dbg!("No arguments detected, starting the TUI"); diff --git a/src/render/mapping_bars.rs b/src/render/mapping_bars.rs index c338dda..01d91c5 100644 --- a/src/render/mapping_bars.rs +++ b/src/render/mapping_bars.rs @@ -38,6 +38,7 @@ pub fn render_mapping_bar(bottom: Rect, buf: &mut Buffer, state: &mut AppState, match state.mapping_option { MappingOptions::Transformations => render_transformations_bar(bottom, buf, state), MappingOptions::OneToMany => render_onetomany_bar(bottom, buf, state), + MappingOptions::StringToOne => render_onetomany_bar(bottom, buf, state), MappingOptions::ManyToOne => render_manytoone_bar(bottom, buf, state), MappingOptions::DirectCopy => {} } diff --git a/src/render/p2.rs b/src/render/p2.rs index 9414131..d3a32e2 100644 --- a/src/render/p2.rs +++ b/src/render/p2.rs @@ -165,6 +165,7 @@ pub fn render_required_data_p2(area: Rect, buf: &mut Buffer, state: &mut AppStat match state.mapping_option { MappingOptions::Transformations => render_popup_mapping(area, buf, state), MappingOptions::OneToMany => render_popup_mapping(area, buf, state), // todo + MappingOptions::StringToOne => render_popup_mapping(area, buf, state), // todo MappingOptions::ManyToOne => render_manytoone_bar(area, buf, state), // todo MappingOptions::DirectCopy => {} // DirectCopy } diff --git a/src/render/p3.rs b/src/render/p3.rs index aa6d4db..18aa967 100644 --- a/src/render/p3.rs +++ b/src/render/p3.rs @@ -165,6 +165,7 @@ pub fn render_optional_data_p3(area: Rect, buf: &mut Buffer, state: &mut AppStat match state.mapping_option { MappingOptions::Transformations => render_popup_mapping(area, buf, state), MappingOptions::OneToMany => render_popup_mapping(area, buf, state), //todo + MappingOptions::StringToOne => render_popup_mapping(area, buf, state), //todo MappingOptions::ManyToOne => render_manytoone_bar(area, buf, state), //todo MappingOptions::DirectCopy => {} // DirectCopy } diff --git a/src/state.rs b/src/state.rs index 5acd760..e69b054 100644 --- a/src/state.rs +++ b/src/state.rs @@ -182,6 +182,7 @@ pub enum MappingOptions { Transformations, OneToMany, ManyToOne, + StringToOne, } #[derive(Clone, Copy, FromRepr, Debug, Default, PartialEq, Display)] pub enum Transformations { @@ -192,6 +193,7 @@ pub enum Transformations { TakeIndex, // should be included in Slice Slice, // Slice should accept indexing singular points and ranges in the future, e.g. (9) or (1..9) Regex, + StringToOne, } #[derive(Clone, Copy, FromRepr, Debug, Default, PartialEq)] diff --git a/test/1EDTECH_logo_100x100.png b/test/1EDTECH_logo_100x100.png new file mode 100644 index 0000000..4535e66 Binary files /dev/null and b/test/1EDTECH_logo_100x100.png differ diff --git a/test/ELM_export_example.json b/test/ELM_export_example.json new file mode 100644 index 0000000..fc9c31c --- /dev/null +++ b/test/ELM_export_example.json @@ -0,0 +1,213 @@ +{ + "@context": [ + "https://www.w3.org/ns/credentials/v2", + "http://data.europa.eu/snb/model/context/edc-ap" + ], + "credentialProfiles": [ + { + "id": "http://data.europa.eu/snb/credential/e34929035b", + "inScheme": { + "id": "http://data.europa.eu/snb/credential/25831c2", + "type": "ConceptScheme" + }, + "prefLabel": { + "en": [ + "Generic" + ] + }, + "type": "Concept" + } + ], + "credentialSchema": [ + { + "id": "http://data.europa.eu/snb/model/ap/edc-generic-full", + "type": "ShaclValidator2017" + }, + { + "id": "https://api-pilot.ebsi.eu/trusted-schemas-registry/v3/schemas/0x7ff3bc76bd5e37b3d29721b8698646a722a24a4f4ab0a0ba63d4bbbe0ef9758d", + "type": "JsonSchema" + } + ], + "credentialSubject": { + "fullName": { + "en": [ + "somebody@gmail.com" + ] + }, + "hasClaim": [ + { + "awardedBy": { + "awardingBody": [ + { + "id": "https://1edtech.edu/issuers/565049", + "legalName": { + "en": [ + "1EdTech University" + ] + }, + "type": "Organisation" + } + ], + "id": "urn:epass:awardingProcess:1", + "type": "AwardingProcess" + }, + "id": "https://1edtech.edu/achievements/degree", + "title": { + "en": [ + "1EdTech University Degree for Example Student" + ] + }, + "type": "LearningAchievement" + } + ], + "id": "did:example:ebfeb1f712ebc6f1c276e12ec21", + "identifier": [ + { + "id": "urn:epass:identifier:2", + "notation": "student@1edtech.edu", + "schemeName": "Student ID", + "type": "Identifier" + } + ], + "type": "Person" + }, + "displayParameter": { + "description": { + "en": [ + "EBSI Example https://github.com/Knowledge-Innovation-Centre/ESBI-JSON-schemas/blob/main/examples%20of%20credentials/DigiComp%20Generic.json" + ] + }, + "id": "urn:epass:displayParameter:1", + "individualDisplay": [ + { + "displayDetail": [ + { + "id": "urn:epass:displayDetail:123", + "image": { + "content": "iVBORw0KGgoAAAANSUhEUgAAAGQAAABkCAYAAABw4pVUAAAAznpUWHRSYXcgcHJvZmlsZSB0eXBlIGV4aWYAAHjabVFBDgMhCLzzij5BGVR8jtvdJv1Bn19Uuq2bTuKAjBlB6Xg9H3TrYChJKpprzsEgVSo3SzRMtMExyOCBLK7FtU6nwFaCRcytZj//qcfTYIZmWfox0rsL2ypUv4D1YuQXoXfEluxuVN0IPIXoBq35KFXL7wjbEVboXNQJZXifJte9FHu9PVkRzAcigjGgswH0lQjNkjhY7WBAtVwsDvZR7EH+vVPoP+Pd0vIT+ApL3UFvDxlivyntNoEAAAGEaUNDUElDQyBwcm9maWxlAAB4nH2RPUjDUBSFT1PFIhUHO4g4ZGidLIiKONYqFKFCqBVadTB56R80aUhSXBwF14KDP4tVBxdnXR1cBUHwB8RdcFJ0kRLvSwotYrzhkY/z7jm8dx8gNKtMs3oSgKbbZiaVFHP5VbHvFQGE6IthQmaWMSdJafjW1z11U93FeZZ/3581oBYsBgRE4gQzTJt4g3hm0zY47xNHWFlWic+Jx006IPEj1xWP3ziXXBZ4ZsTMZuaJI8RiqYuVLmZlUyOeJo6qmk75Qs5jlfMWZ61aZ+1z8huGC/rKMtdpjSKFRSxBgggFdVRQhY04/XVSLGRoP+njH3H9ErkUclXAyLGAGjTIrh/8DX7P1ipOTXpJ4STQ++I4HzGgbxdoNRzn+9hxWidA8Bm40jv+WhOY/SS90dGiR8DgNnBx3dGUPeByBxh+MmRTdqUgLaFYBN7P6JnywNAt0L/mza29j9MHIEuzSt8AB4fAWImy133uHeqe27897fn9AJ6icrg0Y35bAAANemlUWHRYTUw6Y29tLmFkb2JlLnhtcAAAAAAAPD94cGFja2V0IGJlZ2luPSLvu78iIGlkPSJXNU0wTXBDZWhpSHpyZVN6TlRjemtjOWQiPz4KPHg6eG1wbWV0YSB4bWxuczp4PSJhZG9iZTpuczptZXRhLyIgeDp4bXB0az0iWE1QIENvcmUgNC40LjAtRXhpdjIiPgogPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4KICA8cmRmOkRlc2NyaXB0aW9uIHJkZjphYm91dD0iIgogICAgeG1sbnM6eG1wTU09Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9tbS8iCiAgICB4bWxuczpzdEV2dD0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL3NUeXBlL1Jlc291cmNlRXZlbnQjIgogICAgeG1sbnM6R0lNUD0iaHR0cDovL3d3dy5naW1wLm9yZy94bXAvIgogICAgeG1sbnM6ZGM9Imh0dHA6Ly9wdXJsLm9yZy9kYy9lbGVtZW50cy8xLjEvIgogICAgeG1sbnM6dGlmZj0iaHR0cDovL25zLmFkb2JlLmNvbS90aWZmLzEuMC8iCiAgICB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iCiAgIHhtcE1NOkRvY3VtZW50SUQ9ImdpbXA6ZG9jaWQ6Z2ltcDowNDE4ODNhMy0zYjAzLTQyNDctYjc2My05MDk4ODYxMGZiNjIiCiAgIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6ZWNiZWZmYTQtMmVmOS00M2FjLTkxOWUtNTE0MDE5NzBkMjVkIgogICB4bXBNTTpPcmlnaW5hbERvY3VtZW50SUQ9InhtcC5kaWQ6NGI1YmIyNmEtMDRiZi00NDFlLTljOGMtYzZiY2EwZmQ0YWJhIgogICBHSU1QOkFQST0iMi4wIgogICBHSU1QOlBsYXRmb3JtPSJNYWMgT1MiCiAgIEdJTVA6VGltZVN0YW1wPSIxNzM2MzI1NjUxMzI2NjIxIgogICBHSU1QOlZlcnNpb249IjIuMTAuMzgiCiAgIGRjOkZvcm1hdD0iaW1hZ2UvcG5nIgogICB0aWZmOk9yaWVudGF0aW9uPSIxIgogICB4bXA6Q3JlYXRvclRvb2w9IkdJTVAgMi4xMCIKICAgeG1wOk1ldGFkYXRhRGF0ZT0iMjAyNTowMTowOFQwOTo0MDo0MCswMTowMCIKICAgeG1wOk1vZGlmeURhdGU9IjIwMjU6MDE6MDhUMDk6NDA6NDArMDE6MDAiPgogICA8eG1wTU06SGlzdG9yeT4KICAgIDxyZGY6U2VxPgogICAgIDxyZGY6bGkKICAgICAgc3RFdnQ6YWN0aW9uPSJzYXZlZCIKICAgICAgc3RFdnQ6Y2hhbmdlZD0iLyIKICAgICAgc3RFdnQ6aW5zdGFuY2VJRD0ieG1wLmlpZDo3NzlmOWRkMy1kNzAxLTQ0ZGUtYmI2Ny1mYmMxZDkzYjIzYmQiCiAgICAgIHN0RXZ0OnNvZnR3YXJlQWdlbnQ9IkdpbXAgMi4xMCAoTWFjIE9TKSIKICAgICAgc3RFdnQ6d2hlbj0iMjAyNS0wMS0wOFQwOTo0MDo1MSswMTowMCIvPgogICAgPC9yZGY6U2VxPgogICA8L3htcE1NOkhpc3Rvcnk+CiAgPC9yZGY6RGVzY3JpcHRpb24+CiA8L3JkZjpSREY+CjwveDp4bXBtZXRhPgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgCjw/eHBhY2tldCBlbmQ9InciPz7aFa8HAAAABmJLR0QA/wD/AP+gvaeTAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH6QEICCgz6dV/sQAAIABJREFUeNrtnXmUXVWZ6H97n+nOt+akKnMqIQmZKgQkiYYxPgaBIPYKdtOI2srThrYbbEQE7QfKAhTxRX3oWqI+29Y8QSGMCi2BMIkQEhkyBypJkaEy1HSr6t57hr3fH/feU7dSVUlloJHV9a1Vqdxzz9ln728e9v4KRmAERmAERmAERmAERmAERmAERuADD0/+vZK//eSvxbE8a4yg78TBH6/dJs8+c5IwY2aDFUnmLvj893XTKXGeXb1q2GOIETQeH6z4txUinU8J18kgchMTuS7vRqGMa33cP8Tisa/1JsR2tu1i15gt6obvfEWPEOQ9gjeuf0Nu3rVFBuOqtdbOJJ3zrpaevNL18rVKKykQ2jadvG8Hj5tK/MQ7pebZt59t9RvHVYtP3dUUDDWuOYLaw8N/fOopaTVaYteLru588SV9a8+tGqBrrBkLGHORzPLFfK53kdBSukFOaIEQCDRa5PxsxAiMTwRC/o21tuOtaVXWQzG8/wu8A/AvN1wnFj3xdyJ1SVa0bmrSVz2UUgMkZOHChaKrq+u/veRccMH53H33dxXAyts21HW17KoTUadCmEajnRdLvHz+40LLuBvkVfEROeRgGq3R2jJsgdDKikRXB/j/GQTq1UhKtuc988DUyeMPnP5PY3pDxDc1NYm//OUvzJw50xFCJP87E8MwJB//5DIxM3rJUm9D+/XAJBPL0FoJP/CEF7gghDgOle9LIQ3bdJRAolBaaa/TTMbuMQGWLVsmNm/ebM2cOfNzQogbpJTp/94EEcSdhDj9rNGxVWv3SgTSFfk+5BeIcVjQWpfu7Uc1rTVCCFNpRc7LyqIEoQUpo8efYp511lli69atjlLqYSHEOVprIwgC/deOtFgshhACrTW9vb0ndGwhIJv18INAKKWENOQRn9FoylE/FM0OuS7Cf7WWjmVb5u7du3EcZ6nW+hyttVH8+q/ahmiticfjBYIAvdleOIEsJKSB8vIY0jiCMGikMA5BlybQquyKRggDWbyitEIPMlkBAknG3LJli541a9Y3tNbyg+AGW5ZFMpnk4YcfJhaL4Xo+Hz5jCX62c9CFHguYpkl3dzemHUHrgsQMxhS9Xg+7u7azt7uFXr8HQ5jUxEcxqeIk0pHqUGp2tG9lZ+c2QDO1ejZ1iQbQh0qLIOvQbU6bNi2itR5bEv8PEgghEIgTzkUCSU9vN5GUGNI2aK1YvvZr2NJEIkOq6YOa7nd6+czJ1zOhYgoaeKd9I2v2P42r8qQildTFGwZInpRSqPbug7K4MPFBI0T4u1w3nECSeHkXKeXQNkAIokYc0CgCOoNW2v0DIBQJK8qvNv+AbjdTtC6agAAftzDLQbAttECNTvRKPoAwhCSfUKba19ndF1mIoSyIQiDJ626+PG851zV9m0C5CMBVHezNtIQP63AcPZhMa0MaOnDd1g8kQY5AmBMwMHQf3I/hHIbKxXcLQKGxjQiVkRomJuag0Ehhk/V7EUIylAzrfirLwO4JOj/QBHmvNG2gFAcPduIDwjEQUhTwr3VIiEMtvUAghMCSTp93daj8iv6MJMr+L4XUgSPaP9AEKRpDkonYCVVYQRBw8OA+/CBHpMLEVz4duQMczO4j6/ceXlGKMs4XJSKC0H16q5yRhCg8oFDa8USH+UGXDK0VnntiA0M/8LFMj47OLqpPquDl3z3Hg83/G8dIEzESXDf/2wM9CDHU54LjoQVY0uHd7mbMfTZCFGg1vXYuUkid9/O6x+9s++Bne7XGzedO6JBKKRLJCl5/fQMnnzyH7M+yxM06TGESKJdAB0hhIBCooroKKaTLw+8+SyGRSGHyZtuLvHbwaUDTERzgmxX/QcxOaMMytk8e1dT2gVdZ74kaFKC05rHHnmDczFos00EZHgqFJRMY0gABgfLRWhFot88+oAm0T6C9grkRAo1GaY2nXTRgCgdLRInJqpK0CycSe/T8S+r0SD1kiDjEMAy2bdtAIF0WnXEWU3dOJ/ADYmYcISQSwf9suoWcn8UybByjYMwvmLKMM7zzEUKScirQWvHh8eexcOySMonpkyHHimpTmko54oEFa7ZHzVKE/gGLDd9zUErTfnAXzdt3MqGpFnevC1Z/hzXpVJB0KsPPWmuiVoyoFStZdIACsYyhkpEay7Q6bF9v+trP6rNyhBhDmSZFLJbiN/c/TN1J1Xgdfj8J0uVGo8zZ6IuN9GFjplJwaAhTK1P/btao2s5LXq3RIzbkMJDN5XjgNz/DqYFofRRhiAEIHW5sNMR1JaWRdUYl/+2l1eNFwfiPwGE9OAOfHS07mLNsEjooS53rUpZKD+D+8s+DfVe4VggyLdvaHLRn2q3IY3qEIMOAeLKKO+74AY2nNiBjFhJRlpfqkxR9iOoaSjKEEGH11zRsKePG7e35WPB3D12qYWTXyRHB81y2bFrN008/y6KrZvH8vW/2ZZsRw0zhDJLi1SgzYj39N3cveLCfyz3cJJ5hGNi2jRCCIAgIggClFKZphtePJ0kopcS2bQzDQCkVvqP8vccCpedt2x40nX64bIBt21iWRSpZx63/dhuRBotYfRQhy1VPWUyo9aBFMj0wjFe25XQbSftzj122rt+kzOFMzDAMstksjY2NnHzyyUyZMgXTNMlkMrz55pu8/fbbtLW1IaVEKXXUaRDLsujt7aWuro5JkyYxe/ZsYrEYPT09rF+/nvXr1+N5HoZhHBOxS8T0fX/YRFFKhevJ57P4QQ//7z9W8Ol/+jSP3PgnDEv2SxIOJim6VG7UOlRzAoEUQhmWsZy7Tm25CKmHTZDShC666CK+8IUvUF1djeM4IWK01vi+Ty6XY8uWLdx44420tbWRz+eHxdFCCKSUnHfeeXz2s59lzJgx4fglFzIIAnp7e2lubuaOO+5gx44dwyaE67rceeedLFlSCMoee+wxbrvtNizLOuyzjuOwYMECvvWtbwGwbt06PvOZz/LL3/yERWcuZsHV03nphxswonLQdZYUVHkxq2/NMojEok/XNMZvf/KrAu48BOeHE/UDBw5w7733cuuttzJ27Fii0egADjNNk0Qiwfz583n44YdZvHgxhmEcsVZhmib79+/nG9/4BrfffjtTp04lFov1k4KSdKZSKebMmcN9993H+eefPywpLBE0FouRTqdJp9PEYrFh1VCEEDiOQyqVoqKigng8jue5qEDw6c9fQ3pqnPpTqxCGGGrDwhCWRGvbcvYmZ1Qu2/6q8u66Uwx42BxKMgzD4PHHH2fevHnhIrZs2cK6devYvXs3PT091NTUMH78eJqamhgzZgzRaJS77rqL73//+/z7v//7YfW64zg88sgjnHrqqaHn0drayl/+8hdaWlrYu3cvpmkyduxYGhsbmTdvHvF4nK9+9atUVVUdEbH9dPwxBL+hOip7Lgh8UrE8t95+J7d//RZe+dU29r/VBgFHTP9rrVXEiR5wyVweeTjf/dn/XDIoV5lD2Yy77747JIbnefz4xz/mO9/5DqNGjeo3Sdd12bp1Ky+++CJz587Ftm2+9KUvsXr1anbv3o3neYNO8LrrruO0004L37lu3TouvPBCampqiEQi/e7dv38/M2bM4Ec/+hETJkzgH/7hH5BSvi8Zhmw2xyvP/YHbvhPj1htv4Mnb15LvyA8mDWXBo1ARO9Ju10Quer4989pVQxBjgMoqIf/yyy/nzDPPRGuNUop77rmHFStWkE6nyeVyZLPZ8CcIAqZOncqVV17JG2+8gRCCSCTC9ddfPygxIpEIp59+Opdddln4zhUrVvD5z3+euro6tNb9xs9msyQSCfbv388VV1zB5s2biUajA4j2XwluoHjxjyu55bb/xQXfOIUJZ9ejA90vWxK6xAhf2sY+lTY/Yk48bc29P/rYYfXtABvS3d3N0qVLQ+5buXIlv/rVr8hkMkMOEgQBtm1z0003kc1m0Vpz6qmnYllWP5sjpaS7u5svf/nLWJaFEIL29na+/e1vh+MMzZkF4lx77bX09PS8r1uWBIK8F/DCs09yzT9+mbkXT+Cki8bjZXzKSujKlKayHee1WDIxRz39+palV4sjTrofQeLxOIsXL2bKlCkIIejo6OB73/sepnnk+DEIApqbm2lra0MIQTqdZtmyZdi23U8f19fXM27cuNC1vO+++0KpOJKhzefztLa28otf/OKvYg+ZHyi2vL2WT171BWpOi/LRb8zHqXQgENq2nTZhye/2Vvof9WLRtivXfXFY8YAsV1fZbJbzzjsvJMCaNWtobW3F8zyklIf90VqTSqXYuHFjON6ZZ55JPp8PpSQIAubPn080GgWgo6ODBx54AKXUsN1kwzB44okncF33fSeKEILe3l72vbuJj5w6h9+vXcXSby5QjRfUb3SSTpPZvPPGlsjZ3X/7zdnBcMc0ywc/ePAgU6dODT93dXUxb9680ICWI6B/XVuH/vu+ffvC6w0NDWQyGdLpNL7vY5omM2bMCMfas2cPHR0dIYGGi4R3332X7u5uqqur/wqSKwLPzVNXP56f/PA7rH35Ra7952ufzNjNuy/87qc0T33qqEYzD41Oq6qqws+XXnopS5cuPWquKTfg5deEEDQ2NoZuaEtLC4lEAt/3hz1+EAT09PTQ2tr6V0KQPr8qn8/zp5ee5fnV/5mLxqPHNIo5WAxSHi8cjziXjHq5dJVsSskmHE1+qXyOh3MATgQcy7wK2kJhOxGix+gFmoNxYAl+//vfs27dumPy94UQZDIZHMfB9/1wjFwuF/4/Go0SBAFHu9G7pP7eKyQHQUAkEjnGOEegtUJK8/gJIqWko6MjnEhHRwe//vWvw8MxRwtKqQFplJ07d4YEaGhoIJvN4jjOUSE1kUhQW1s7bCKW5j5cgnieRyKReF8Un1lumGtra1m/fj0LFy5Ea83kyZPD4O941FcJKb7v88Ybb4SIHDt2LJWVlWHsMtyUxuTJk0mlUkd8XzkTKaWoqanBdV1s2z7ss93d3cyaNeuY1dZxqcryBUQiEf74xz+GbmhTUxONjY0kk8lhIyuTyfTLIx2aw3r99dfJ5/Ohm3zxxRdjmuawCFK656yzzhpWjcSyLHK5vk109fX1tLa2HhHRO3bsoKmp6ahLCSeUICXOeOmll3jrrbfQWmPbNrfddhvNzc1HXLwQAtM0+elPf8pXvvKVQT0nrTV79+5l27ZtYfxyzTXXYNs2sVjsiMSIRCI0NjZy9dVXD2txyWSSLVu2hPMbN24cl1122WHT747jsHz5csaNG/f+Skhp0qlUioceeii8tmDBApYvXx5W3AarEZcmfu6557J48WKuuuoqvva1rw1YuFKKWCzG9773PXzfR2tNRUUF//qv/4rrukMmDEvVxGQyyT333DNsm+Z5Hk899RSu64YSeskll+C67qDPG4ZBZ2cnF198cb9M8fATmQKNpJA/CY6PIOXpjccee4yVK1eGxvfyyy9n+fLlVFVVhUa19GMYBvl8nrvvvps777wTx3HQWjN+/Hiy2eyAhWSzWV555RVWrFgRXrvsssu4//77icfjhX21ZePH43Gy2SxLlizh/vvvZ+LEiWSzWfL5/LAI0tzczKpVq8I1Ll26lEsvvRStNYlEglgsRjweJxqNUltby6OPPsrEiRPp7OwMPc7SGo6sVnVxt6/mWPv6iGnTpkUsy9oHxIsHP8N6yM9//nOamprCiXR2dvLnP/+ZV199ldbWVtLpNIsWLWL+/PmMGjUqvK+5uZlly5bhed6g8YJhGOH4c+bMCa/39PSwceNGXnjhBZqbm7Ftm5kzZ3LGGWcwceLEMEXz4x//mCuuuIJkMonrunzkIx8J7dKhYNs2tbW1PPjgg6Fk+b7PmjVreOihh9i2bRsVFRUsWbKECy64gFQqhdaab33rW9x8882h3fvYxz5GOp0ejhpTUsq70un0zS+88II+IQQpESUajXLrrbdy9tln4zhOWGcezL0tIesPf/gDd9xxB5lMZshaSIko0WiUG264gaVLl2KaZuhMHCpVpetdXV388pe/5IEHHuDRRx8lHo/jui6LFy8ekiBaayzLYunSpdx8882hGi29o3zuWmtyuRz33nsvzz//PL/97W+RUrJ161bOOeccKioq3nOCmIeLIXK5HNdddx0LFy7kpptuCsu4h+a0PM9j586d3HfffaxcuZJYLHZYYpSCr97eXr7+9a/z9NNPc80119DY2EgkEhkwfm9vL5s2beLOO+9kx44dRCKRMAVfes9Q6qQkEY888ggtLS3ccsstjB8/PvTsSmrZ8zw2b97MLbfcwu7du4nH43R1dYUBqOd5/yUFsTIJ0XGtB9ZHSt5NW1sbU6ZM4eKLL2by5Mnhdp1NmzbxzDPPsHXrVioqKujp6TnqScRiMbq6upg0aRLnnHMO06dPxzRNgiBg48aNPP744+zfv59IJBJuoIhGo0fdySEajZLP55k7dy5Lliyhrq4OgL179/LEE0+wZs0aqqqqQvsUj8cLBSnXDZ2Q4cTDx6Wypk+bFjEsax+IOFrLoU4Xl0S15N6WJleaqBDiuPx2KWVY9ixPi5S7z+XjlweqR5PXKqkn0zT7qa3SFqFD31Fa51Gs7fhUlu63GVIjhURiEOgApYPi0V+B0AYCiadcPN/vO4Va1Pnl3FMYwywiuOAO+todfALCLu6PDVBaobTCD3wMChXFQAeDqorBiCAQGMIi0B6B9pHCwBAmIAi01w+x2ivf/imxhAMayvZT46tDay4aQ1igwcdFazClhcTovz4h4BiZ0zxUIiwRpSE2maSVImLFCse4dEC328me3l3syW3DkQ7ltcpDkWIJh9HRyViGTaB8ur0u9uWa+x8RLkKV3UDaqSRqxoiaMaQw8JVLxs2wp3cH+/LbsUUEiTFk6wyBwNceCs3k2HRqo3U4ZgxP5enMt9PS8zY5v7uAdAqdGmojE46gggQH3XfxyIXPeDpHxEgxMTGNikg1aMi4HSFeTGEWGEBrOMag0iynPmgWjPooH57wUQIVFDi8WLsvHBbV7O7ayfMtj7O9Z/OgO19cneeSiZ9hRs28IgILknfv2lvpDbpQOgilSGvNp2b/E0ZZZlSXzugJgdIB+3v28Oddq9jQuaa40XngOQuF4rTaJZzWcGYBUYWOYeH+tEAFvNn6Cn9o+TWWcLBliqvm/nN432BqWgjJM82P8nLrk0hRaAPzP8b+LfPqF2EW59u3MVHTkWvjuZYn2Nyx9kRF6iJEX6CCsvNzAUr7BKqwl3dUYgyfmP45kmZVsRNOf8ipHsalGvGUiyqqIYHk1FFnDeBAEKGaCn8ICLRfUJcaauP1XHTS3/OpGdcTaO+QneUSX3v83bR/5txJS0naaZQOCnMt/g5UgBSSuJ1EI4uoV4VzgMX7Su8ufC7NJSBmxQFBJujkb6ddy/yGjyCFDO8Nx0BTGa3GlpGiijxBqZMS1cs5Jh9k6Xa7Qs4UCAxpceGkTxLo/vkqKQzmVpxBzIoXuapo5XTA6PgYev3OQWJbHcYAWmskoqD7pRnOQ6OoT0zg441X0xv0hATNBhkunfw5xqUm98UWWmMaZsGOCYkhC8Z7R+c2+h23OUQoDGliGhaGNDFkwfZ4yscQJotqL2R8urEPL0IQaB9X5Ql0gCEkXuDyVvuf8LV3YtLv5Xwb5qiE5M3WNTyw84fMTy5h2czPh2isjTfg6zy2iIbG29ceH6o/K1SA5Z0KqmKjyGmf6AC10+cUKBQ/e/0eTGkwMTWD0xoWE7XiFJpKKk6qns3UvXPZk90OaCbGZjKjdh5K9Rn+jNvJy+8+y/bMRoSAsfEpTK6Yzkv7niIi7TIXpo8hAuXz3Pbfh/23SnZ5c/vr5FUvJ1XNItCK0lG2vV0t3Lf+dqTUxGSak9KnUBurp9vvImbEOZ4uBiZDUaQoLYYwqTXH0JLdgq88LMMKbUNoXIpNunJ+nprYqNB97cwdJO1UodHErQQzU/PZm90xQLLC92rI+AcBTdv+vbR0vcMVs/+xuIu8cNZ7YcMSfrPthwgkTXULw03NJYL+fP130cpHiYKXs6HjVda1PYMjI4M7BbpgY1a3riRmJAeUYxU+hjDCI5wCQXvuAAiIyCQa2Nz5Gm+254gbiePu2SX7XNa+o1r9tTwIYXPe+MuxDLvgbwiDHR3bsGQUjQqpV2VX45iFSF4Aq3c+jkKFfa0WNCwpup9iIP11n6vpKw9fe7RkN/Byyypk8XmlFaOT48ipgE4/w8SKaQSqLwH45t5X6PJacXWuOI6L0j6WiByxdDA10cT42HQmxKczIT4DS0QKKUJhEmi/H6Jn1M5lWeMXiRtpPJUL7zsRDdTM/huRdT8JUSjm1i9gbv3pSGEWvRJN1svw+PZfFVVJMUDE50PVi5DCKLS7UC5vtb3GmfmLSEcqUVrRkJyApxWOMI6QMy3WJmSULR1vsWjcErQuEN4ybGLSwRKaiNXX40QKg51dbxMz0qEEuipLZ9CDKRS+FiRlnIRphypJF7u62YbDJ2d+MVyPIU2eaX6UtftXY2CwvWMbU6tn4Ss/dIGn1cxlavVsdnVtZ9XOlbT0vk1EOsdNlGEd2NGa0E4IIfACl2pnNG3unqKbKkArZo/6EBQloq3nAL7IcqB3DxWRKhCaiBllSmIm23s2YhTT0/oI9YUutxOlA0TRTZZCkjArikGlSXkLi063HVH0UwxhsqD2AhaOO7fozQVsPLCOVbsewiZOeQjSdxKqr1tchVNNoAM0Pn/a/zgNyfHMqG0iKLNXAsH4dCNXzvoXNh94g9++83+IyMSJ9bJCzaX7vCpZ7FxQ+i4VqeTKmV8iIpPF7w2q7XFURmrQRW7dlWkmZVRyoLe1aGcKi5g36sPFhR6issRAG1Zq3NKvFVLR91dh3UEPbgARRK0ECTtF1IwRt5LEzSRK6yHq7wWvrKReM15nIVYCbBHj/rd/wKu7nivGUaLPGSnay5l18zl/7JUI5HE1HRzUqJckQSB5o/XPvLZvNVXOKM6acBEpp7LwoGHx8SlX8bONdyEQnNFwcb8t+G3Z/YBgW8dbfGjs2aAL3zUkJyDQGBgE5VW1Qc7ba62otCuRyH7c2+V1klcZfO1jYoV0qI7Wsi+/fWAcX5TyPmHqv+vSUy6/3XQflrDCY2d7szvDdItGEZEJVu16kFW7HmRKajYLG5YwOjkuJGigfGbVncpjLSuoNFInVmWVM5EXeOzN7uBAbjfOu1EumLIsbHVaE6/Hlg7ZoJfJlTP6kow64NzJSzl70kUhl5XEPGYnSJmjcXUP6GAoB68YZOaYWX1KP72cD/Jkgyx57dPrdocMorRiauVMXjnwNHEjPlBe+n0YeHZ8S+Y14kZqUJe1xPWqmNfb1vU6GzvX8OG6j3HWxI+F87OkiVUMDIPjLeH21wllJUkhsKSNIezQsPapM4klLCqtGlJORb+OOLrIkqqsC5tGI5HMqj4FV2UHOSncF0hm/AxzqxYyZ/SC8BspJHu6dxKRFpVmirfbNhU68xSfnlI9kzkVC8kEXSjth96ePpypLc4hG+TIBB1kgvbwx9cuAkGFXUvSqqTTP4in88U5wsFca9hHsaRawzPswQmTkP6H3k1hUmE2UBMdxcKxHy1kf4svzgc5PO0yPX0ajhkJXVAvKMQrJVWT93NEzGjouk6rnsvTe35HsmicSxIktGB+7dk4Msro5FgmVpxU9HxE6OE92/IYlix4Sq/ue4ZTGhaFzSgFmo9P/zTzOxazN9NCbbwBVVSjekh6CEzD4nPTbw7b9JUijnc6NrD2wHMsHnMh02rmsKtrB7u6mun1e6iMVDO9pgmtdBiLuUG+QEQd79eG44R5WYEKmDP6Q8ypP73Q7FGr4lnsgqV4a9+rZPx2ptfMDYkhheThTb+kzduLKU3yQY6Dbis3nba8kOcRUBdvYGx0Chmvvd+Reikk505aig7Ltv3VxvoDa9md3YIjCyppf34n6/a8xLz6ReW5ASakG5lYcVKRiKo8d9qPECW5MYTBlKqT+32HEFiGzbOtvyMdKQS3DcnxjE1NKtqkQs6rz+2WrN/3GgkjXkj9H2OTDDmUVdVhGk6hVFDwjHQhOyqR7OjYynN7HsExYjSkJoS5qB6vm209a8l4bbTl99Ljd5BTPbR27yorEhnMqV7Qp8pKuSx0kegqlIiSNX5193M83PzTkBiFOCXGUy2/YfWOx4vxjw4TCKWkYd9hfn2Is9Y/h1auHEr3S2GQ10Gx71WYliRQfoEYpW1CQrJx3zqe2rXiSAryaCSkwDM5P0vW6ykUXqSBIQw0Cl8HuH6OjNtJc/sm/rjrN8SMNJOTswoEE4XM5zttG/G0hymscIVJI8X2ji3UxEZjCIO8zlIdraMnyNPtdhIzExiGiYGJFAJf+fjKp8ftoiN3kJd3r2J7z3qsYjGrX1JQGLzc+iQHs63MH72Y6tgoomYMQ5porfC1T84tJEibOzZjCgNFQHe+lDAVg6ffEezv2UOlWcm2tg3UJ8aRciqwTQdDFmpEXuDSkTvItrYNPLvndzgy3ieRx19TL+w6cVUOT+dImjXEzSRRmcbXeTJ+G53efvI6IGHEsEWk0NNZB3SrdlKyFl/nCfCIyuQAxHk6h69dIiJNXmcItE/CqKDd30/cSJMw08SNNKaM0O23kfHa6QraMImQMtN9KZohA1hJp9cOQlFljiJmplDaI+N30OXvQ2OTNBKFih/Q5u3t87i0KGsm0yclMZkiIhNkVS+5IEvMiFJljyZupMmpbtrdfWSCDAkjiSWKOT6tlWHIu5LpqptffOG54991YssIDjEEkA16yPm9IAq6OG5UECsipsRdhjCpMOoQwsDAKJZ9B87DEhEcWcjcGqSKrjNUmLXFKqFPRrUVM6oKWzpUitqiAjgy12mtSJqp0JHoDboAjSksKszRocsaViqt+mGgp6C6ojJKVEYLKizoxQ1yaKGxpUNamKEnB6CliSulkyk2AAABZUlEQVQriATrTmAcgiqkmwdvjjZETePIp6CUDg5zfXDP/Wii3pKhDgoF8yOMc/R6XukAVZqlHjx2EjrAVm3kjCbg+RMRh4zA8UKhzHZstmSEIO8RSY61SDVgs/UIvL9Qqofo93Kb5PvV+fT9eG+x2Zs6mpPF/QiyZcuW3OzZs9/VWk9/ryf6viiP4+gIdKwljSAI3lFKiWPxHOTZZ58thBA3CyECTuhfqfnrgv8iYmghRCfwiGEYx4RLs7jP9QnXdR8RQlym+/YBjRiVo6K3QAjhKqX+Pp1Ot7344ovHhD8B8IlPfEI0Nzebnud9Vmv9OcMwRjPyh4uH5U1pIyII3ECpYI2AH3R1dT27Y8eOY2bmEOkLFiwQWmuZzWaFUioihBAjnteRXdtgfJMwDr4bdHVlshNr4zz33HPHlcwa+ePExwtqG7ZoZN2GDWoEGSMwAiMwAiMwAiMwAiMwAiMwAiNw3PD/Ad0JVZHNnanPAAAAAElFTkSuQmCC", + "contentEncoding": { + "id": "http://data.europa.eu/snb/encoding/6146cde7dd", + "inScheme": { + "id": "http://data.europa.eu/snb/encoding/25831c2", + "type": "ConceptScheme" + }, + "prefLabel": { + "en": [ + "base64" + ] + }, + "type": "Concept" + }, + "contentType": { + "id": "http://publications.europa.eu/resource/authority/file-type/PNG", + "inScheme": { + "id": "http://publications.europa.eu/resource/authority/file-type", + "type": "ConceptScheme" + }, + "notation": "file-type", + "prefLabel": { + "en": [ + "PNG" + ] + }, + "type": "Concept" + }, + "id": "urn:epass:mediaObject:https://avatars.githubusercontent.com/u/22613412?v=4", + "page": 1, + "type": "MediaObject" + }, + "type": "DisplayDetail" + } + ], + "id": "urn:epass:individualDisplay:c05743e7-9f9d-4e0b-899b-7ae6514c7a02", + "language": { + "id": "http://publications.europa.eu/resource/authority/language/ENG", + "inScheme": { + "id": "http://publications.europa.eu/resource/authority/language", + "type": "ConceptScheme" + }, + "notation": "language", + "prefLabel": { + "en": [ + "English" + ] + }, + "type": "Concept" + }, + "type": "IndividualDisplay" + } + ], + "language": [ + { + "id": "http://publications.europa.eu/resource/authority/language/ENG", + "inScheme": { + "id": "http://publications.europa.eu/resource/authority/language", + "type": "ConceptScheme" + }, + "notation": "language", + "prefLabel": { + "en": [ + "English" + ] + }, + "type": "Concept" + } + ], + "primaryLanguage": { + "id": "http://publications.europa.eu/resource/authority/language/ENG", + "inScheme": { + "id": "http://publications.europa.eu/resource/authority/language", + "type": "ConceptScheme" + }, + "notation": "language", + "prefLabel": { + "en": [ + "English" + ] + }, + "type": "Concept" + }, + "title": { + "en": [ + "DigiComp Generic" + ] + }, + "type": "DisplayParameter" + }, + "id": "http://1edtech.edu/credentials/3732", + "issuanceDate": "2010-01-01T00:00:00Z", + "issued": "2010-01-01T00:00:00Z", + "issuer": { + "id": "https://1edtech.edu/issuers/565049", + "legalName": { + "en": "1EdTech University" + }, + "location": { + "address": { + "countryCode": { + "id": "http://publications.europa.eu/resource/authority/language/USA", + "inScheme": { + "id": "http://publications.europa.eu/resource/authority/country", + "type": "ConceptScheme" + }, + "notation": "country", + "prefLabel": { + "en": "the United States of America" + }, + "type": "Concept" + }, + "id": "urn:epass:certificateAddress:1", + "type": "Address" + }, + "id": "urn:epass:certificateLocation:1", + "type": "Location" + }, + "type": "Organisation" + }, + "type": [ + "VerifiableCredential", + "VerifiableAttestation", + "EuropeanDigitalCredential" + ], + "validFrom": "2010-01-01T00:00:00Z" +} \ No newline at end of file diff --git a/test/OBv3_example.json b/test/OBv3_example.json new file mode 100644 index 0000000..59e955c --- /dev/null +++ b/test/OBv3_example.json @@ -0,0 +1,723 @@ +{ + "@context": [ + "https://www.w3.org/ns/credentials/v2", + "https://purl.imsglobal.org/spec/ob/v3p0/context-3.0.3.json", + "https://purl.imsglobal.org/spec/ob/v3p0/extensions.json" + ], + "id": "http://1edtech.edu/credentials/3732", + "type": [ + "VerifiableCredential", + "OpenBadgeCredential" + ], + "name": "1EdTech University Degree for Example Student", + "description": "1EdTech University Degree Description", + "image": { + "id": "https://raw.githubusercontent.com/hamrt/credential-converter/refs/heads/image/test/edubadges_100x100.png", + "type": "Image", + "caption": "1EdTech University Degree for Example Student" + }, + "credentialSubject": { + "id": "did:example:ebfeb1f712ebc6f1c276e12ec21", + "type": [ + "AchievementSubject" + ], + "activityEndDate": "2010-01-02T00:00:00Z", + "activityStartDate": "2010-01-01T00:00:00Z", + "creditsEarned": 42, + "licenseNumber": "A-9320041", + "role": "Major Domo", + "source": { + "id": "https://school.edu/issuers/201234", + "type": [ + "Profile" + ], + "name": "1EdTech College of Arts" + }, + "term": "Fall", + "identifier": [ + { + "type": "IdentityObject", + "identityHash": "student@1edtech.edu", + "identityType": "emailAddress", + "hashed": false, + "salt": "not-used" + }, + { + "type": "IdentityObject", + "identityHash": "somebody@gmail.com", + "identityType": "emailAddress", + "hashed": false, + "salt": "not-used" + } + ], + "achievement": { + "id": "https://1edtech.edu/achievements/degree", + "type": [ + "Achievement" + ], + "alignment": [ + { + "type": [ + "Alignment" + ], + "targetCode": "degree", + "targetDescription": "1EdTech University Degree programs.", + "targetName": "1EdTech University Degree", + "targetFramework": "1EdTech University Program and Course Catalog", + "targetType": "CFItem", + "targetUrl": "https://1edtech.edu/catalog/degree" + }, + { + "type": [ + "Alignment" + ], + "targetCode": "degree", + "targetDescription": "1EdTech University Degree programs.", + "targetName": "1EdTech University Degree", + "targetFramework": "1EdTech University Program and Course Catalog", + "targetType": "CTDL", + "targetUrl": "https://credentialengineregistry.org/resources/ce-98cb027b-95ef-4494-908d-6f7790ec6b6b" + } + ], + "achievementType": "Degree", + "creator": { + "id": "https://1edtech.edu/issuers/565049", + "type": [ + "Profile" + ], + "name": "1EdTech University", + "url": "https://1edtech.edu", + "phone": "1-222-333-4444", + "description": "1EdTech University provides online degree programs.", + "endorsement": [ + { + "@context": [ + "https://www.w3.org/ns/credentials/v2", + "https://purl.imsglobal.org/spec/ob/v3p0/context-3.0.3.json" + ], + "id": "http://1edtech.edu/endorsementcredential/3732", + "type": [ + "VerifiableCredential", + "EndorsementCredential" + ], + "name": "SDE endorsement", + "issuer": { + "id": "https://accrediter.edu/issuers/565049", + "type": [ + "Profile" + ], + "name": "Example Accrediting Agency" + }, + "validFrom": "2010-01-01T00:00:00Z", + "validUntil": "2020-01-01T00:00:00Z", + "credentialSubject": { + "id": "https://1edtech.edu/issuers/565049", + "type": [ + "EndorsementSubject" + ], + "endorsementComment": "1EdTech University is in good standing" + }, + "credentialSchema": [ + { + "id": "https://purl.imsglobal.org/spec/ob/v3p0/schema/json/ob_v3p0_endorsementcredential_schema.json", + "type": "1EdTechJsonSchemaValidator2019" + }, + { + "id": "https://accrediter.edu/schema/endorsementcredential.json", + "type": "1EdTechJsonSchemaValidator2019" + } + ], + "credentialStatus": { + "id": "https://1edtech.edu/credentials/3732/revocations", + "type": "1EdTechRevocationList" + }, + "refreshService": { + "id": "http://1edtech.edu/credentials/3732", + "type": "1EdTechCredentialRefresh" + }, + "proof": [ + { + "type": "DataIntegrityProof", + "cryptosuite": "eddsa-rdf-2022", + "created": "2022-05-26T18:17:08Z", + "verificationMethod": "https://accrediter.edu/issuers/565049#zvPkQiUFfJrgnCRhyPkTSkgrGXbnLR15pHH5HZVYNdM4TCAwQHqG7fMeMPLtYNRnEgoV1aJdR5E61eWu5sWRYgtA", + "proofPurpose": "assertionMethod", + "proofValue": "zvPkQiUFfJrgnCRhyPkTSkgrGXbnLR15pHH5HZVYNdM4TCAwQHqG7fMeMPLtYNRnEgoV1aJdR5E61eWu5sWRYgtA" + } + ] + }, + { + "@context": [ + "https://www.w3.org/ns/credentials/v2", + "https://purl.imsglobal.org/spec/ob/v3p0/context-3.0.3.json" + ], + "id": "http://1edtech.edu/endorsementcredential/3733", + "type": [ + "VerifiableCredential", + "EndorsementCredential" + ], + "name": "SDE endorsement", + "issuer": { + "id": "https://state.gov/issuers/565049", + "type": [ + "Profile" + ], + "name": "State Department of Education" + }, + "validFrom": "2010-01-01T00:00:00Z", + "validUntil": "2020-01-01T00:00:00Z", + "credentialSubject": { + "id": "https://1edtech.edu/issuers/565049", + "type": [ + "EndorsementSubject" + ], + "endorsementComment": "1EdTech University is in good standing" + }, + "credentialSchema": [ + { + "id": "https://purl.imsglobal.org/spec/ob/v3p0/schema/json/ob_v3p0_endorsementcredential_schema.json", + "type": "1EdTechJsonSchemaValidator2019" + }, + { + "id": "https://state.gov/schema/endorsementcredential.json", + "type": "1EdTechJsonSchemaValidator2019" + } + ], + "credentialStatus": { + "id": "https://state.gov/credentials/3732/revocations", + "type": "1EdTechRevocationList" + }, + "refreshService": { + "id": "http://state.gov/credentials/3732", + "type": "1EdTechCredentialRefresh" + }, + "proof": [ + { + "type": "DataIntegrityProof", + "cryptosuite": "eddsa-rdf-2022", + "created": "2022-05-26T18:25:59Z", + "verificationMethod": "https://accrediter.edu/issuers/565049#z5bDnmSgDczXwZGya6ZjxKaxkdKxzsCMiVSsgEVWxnaWK7ZqbKnzcCd7mUKE9DQaAL2QMXP5AquPeW6W2CWrZ7jNC", + "proofPurpose": "assertionMethod", + "proofValue": "z5bDnmSgDczXwZGya6ZjxKaxkdKxzsCMiVSsgEVWxnaWK7ZqbKnzcCd7mUKE9DQaAL2QMXP5AquPeW6W2CWrZ7jNC" + } + ] + } + ], + "image": { + "id": "https://1edtech.edu/logo.png", + "type": "Image", + "caption": "1EdTech University logo" + }, + "email": "registrar@1edtech.edu", + "address": { + "type": [ + "Address" + ], + "addressCountry": "USA", + "addressCountryCode": "US", + "addressRegion": "TX", + "addressLocality": "Austin", + "streetAddress": "123 First St", + "postOfficeBoxNumber": "1", + "postalCode": "12345", + "geo": { + "type": "GeoCoordinates", + "latitude": 1, + "longitude": 1 + } + }, + "otherIdentifier": [ + { + "type": "IdentifierEntry", + "identifier": "12345", + "identifierType": "sourcedId" + }, + { + "type": "IdentifierEntry", + "identifier": "67890", + "identifierType": "nationalIdentityNumber" + } + ], + "official": "Horace Mann", + "parentOrg": { + "id": "did:example:123456789", + "type": [ + "Profile" + ], + "name": "Universal Universities" + } + }, + "creditsAvailable": 36, + "criteria": { + "id": "https://1edtech.edu/achievements/degree", + "narrative": "# Degree Requirements\nStudents must complete..." + }, + "description": "1EdTech University Degree Description", + "endorsement": [ + { + "@context": [ + "https://www.w3.org/ns/credentials/v2", + "https://purl.imsglobal.org/spec/ob/v3p0/context-3.0.3.json" + ], + "id": "http://1edtech.edu/endorsementcredential/3734", + "type": [ + "VerifiableCredential", + "EndorsementCredential" + ], + "name": "EAA endorsement", + "issuer": { + "id": "https://accrediter.edu/issuers/565049", + "type": [ + "Profile" + ], + "name": "Example Accrediting Agency" + }, + "validFrom": "2010-01-01T00:00:00Z", + "validUntil": "2020-01-01T00:00:00Z", + "credentialSubject": { + "id": "https://1edtech.edu/issuers/565049", + "type": [ + "EndorsementSubject" + ], + "endorsementComment": "1EdTech University is in good standing" + }, + "credentialSchema": [ + { + "id": "https://purl.imsglobal.org/spec/ob/v3p0/schema/json/ob_v3p0_endorsementcredential_schema.json", + "type": "1EdTechJsonSchemaValidator2019" + }, + { + "id": "https://accrediter.edu/schema/endorsementcredential.json", + "type": "1EdTechJsonSchemaValidator2019" + } + ], + "credentialStatus": { + "id": "https://1edtech.edu/credentials/3732/revocations", + "type": "1EdTechRevocationList" + }, + "refreshService": { + "id": "http://1edtech.edu/credentials/3732", + "type": "1EdTechCredentialRefresh" + }, + "proof": [ + { + "type": "DataIntegrityProof", + "cryptosuite": "eddsa-rdf-2022", + "created": "2022-05-26T18:17:08Z", + "verificationMethod": "https://accrediter.edu/issuers/565049#zvPkQiUFfJrgnCRhyPkTSkgrGXbnLR15pHH5HZVYNdM4TCAwQHqG7fMeMPLtYNRnEgoV1aJdR5E61eWu5sWRYgtA", + "proofPurpose": "assertionMethod", + "proofValue": "zvPkQiUFfJrgnCRhyPkTSkgrGXbnLR15pHH5HZVYNdM4TCAwQHqG7fMeMPLtYNRnEgoV1aJdR5E61eWu5sWRYgtA" + } + ] + } + ], + "fieldOfStudy": "Research", + "humanCode": "R1", + "image": { + "id": "https://raw.githubusercontent.com/hamrt/credential-converter/refs/heads/image/test/edubadges_100x100.png", + "type": "Image", + "caption": "1EdTech University Degree" + }, + "name": "1EdTech University Degree", + "otherIdentifier": [ + { + "type": "IdentifierEntry", + "identifier": "abde", + "identifierType": "identifier" + } + ], + "resultDescription": [ + { + "id": "urn:uuid:f6ab24cd-86e8-4eaf-b8c6-ded74e8fd41c", + "type": [ + "ResultDescription" + ], + "alignment": [ + { + "type": [ + "Alignment" + ], + "targetCode": "project", + "targetDescription": "Project description", + "targetName": "Final Project", + "targetFramework": "1EdTech University Program and Course Catalog", + "targetType": "CFItem", + "targetUrl": "https://1edtech.edu/catalog/degree/project" + } + ], + "allowedValue": [ + "D", + "C", + "B", + "A" + ], + "name": "Final Project Grade", + "requiredValue": "C", + "resultType": "LetterGrade" + }, + { + "id": "urn:uuid:a70ddc6a-4c4a-4bd8-8277-cb97c79f40c5", + "type": [ + "ResultDescription" + ], + "alignment": [ + { + "type": [ + "Alignment" + ], + "targetCode": "project", + "targetDescription": "Project description", + "targetName": "Final Project", + "targetFramework": "1EdTech University Program and Course Catalog", + "targetType": "CFItem", + "targetUrl": "https://1edtech.edu/catalog/degree/project" + } + ], + "allowedValue": [ + "D", + "C", + "B", + "A" + ], + "name": "Final Project Grade", + "requiredLevel": "urn:uuid:d05a0867-d0ad-4b03-bdb5-28fb5d2aab7a", + "resultType": "RubricCriterionLevel", + "rubricCriterionLevel": [ + { + "id": "urn:uuid:d05a0867-d0ad-4b03-bdb5-28fb5d2aab7a", + "type": [ + "RubricCriterionLevel" + ], + "alignment": [ + { + "type": [ + "Alignment" + ], + "targetCode": "project", + "targetDescription": "Project description", + "targetName": "Final Project", + "targetFramework": "1EdTech University Program and Course Catalog", + "targetType": "CFRubricCriterionLevel", + "targetUrl": "https://1edtech.edu/catalog/degree/project/rubric/levels/mastered" + } + ], + "description": "The author demonstrated...", + "level": "Mastered", + "name": "Mastery", + "points": "4" + }, + { + "id": "urn:uuid:6b84b429-31ee-4dac-9d20-e5c55881f80e", + "type": [ + "RubricCriterionLevel" + ], + "alignment": [ + { + "type": [ + "Alignment" + ], + "targetCode": "project", + "targetDescription": "Project description", + "targetName": "Final Project", + "targetFramework": "1EdTech University Program and Course Catalog", + "targetType": "CFRubricCriterionLevel", + "targetUrl": "https://1edtech.edu/catalog/degree/project/rubric/levels/basic" + } + ], + "description": "The author demonstrated...", + "level": "Basic", + "name": "Basic", + "points": "4" + } + ] + }, + { + "id": "urn:uuid:b07c0387-f2d6-4b65-a3f4-f4e4302ea8f7", + "type": [ + "ResultDescription" + ], + "name": "Project Status", + "resultType": "Status" + } + ], + "specialization": "Computer Science Research", + "tag": [ + "research", + "computer science" + ] + }, + "image": { + "id": "https://1edtech.edu/credentials/3732/image", + "type": "Image", + "caption": "1EdTech University Degree for Example Student" + }, + "narrative": "There is a final project report and source code evidence.", + "result": [ + { + "type": [ + "Result" + ], + "alignment": [ + { + "type": [ + "Alignment" + ], + "targetCode": "project", + "targetDescription": "Project description", + "targetName": "Final Project", + "targetFramework": "1EdTech University Program and Course Catalog", + "targetType": "CFItem", + "targetUrl": "https://1edtech.edu/catalog/degree/project/result/1" + } + ], + "resultDescription": "urn:uuid:f6ab24cd-86e8-4eaf-b8c6-ded74e8fd41c", + "value": "A" + }, + { + "type": [ + "Result" + ], + "achievedLevel": "urn:uuid:d05a0867-d0ad-4b03-bdb5-28fb5d2aab7a", + "alignment": [ + { + "type": [ + "Alignment" + ], + "targetCode": "project", + "targetDescription": "Project description", + "targetName": "Final Project", + "targetFramework": "1EdTech University Program and Course Catalog", + "targetType": "CFItem", + "targetUrl": "https://1edtech.edu/catalog/degree/project/result/1" + } + ], + "resultDescription": "urn:uuid:f6ab24cd-86e8-4eaf-b8c6-ded74e8fd41c" + }, + { + "type": [ + "Result" + ], + "resultDescription": "urn:uuid:f6ab24cd-86e8-4eaf-b8c6-ded74e8fd41c", + "status": "Completed" + } + ] + }, + "endorsement": [ + { + "@context": [ + "https://www.w3.org/ns/credentials/v2", + "https://purl.imsglobal.org/spec/ob/v3p0/context-3.0.3.json" + ], + "id": "http://1edtech.edu/endorsementcredential/3735", + "type": [ + "VerifiableCredential", + "EndorsementCredential" + ], + "name": "EAA endorsement", + "issuer": { + "id": "https://accrediter.edu/issuers/565049", + "type": [ + "Profile" + ], + "name": "Example Accrediting Agency" + }, + "validFrom": "2010-01-01T00:00:00Z", + "validUntil": "2020-01-01T00:00:00Z", + "credentialSubject": { + "id": "https://1edtech.edu/issuers/565049", + "type": [ + "EndorsementSubject" + ], + "endorsementComment": "1EdTech University is in good standing" + }, + "credentialSchema": [ + { + "id": "https://purl.imsglobal.org/spec/ob/v3p0/schema/json/ob_v3p0_endorsementcredential_schema.json", + "type": "1EdTechJsonSchemaValidator2019" + }, + { + "id": "https://accrediter.edu/schema/endorsementcredential.json", + "type": "1EdTechJsonSchemaValidator2019" + } + ], + "credentialStatus": { + "id": "https://1edtech.edu/credentials/3732/revocations", + "type": "1EdTechRevocationList" + }, + "refreshService": { + "id": "http://1edtech.edu/credentials/3732", + "type": "1EdTechCredentialRefresh" + }, + "proof": [ + { + "type": "DataIntegrityProof", + "cryptosuite": "eddsa-rdf-2022", + "created": "2022-05-26T18:17:08Z", + "verificationMethod": "https://accrediter.edu/issuers/565049#zvPkQiUFfJrgnCRhyPkTSkgrGXbnLR15pHH5HZVYNdM4TCAwQHqG7fMeMPLtYNRnEgoV1aJdR5E61eWu5sWRYgtA", + "proofPurpose": "assertionMethod", + "proofValue": "zvPkQiUFfJrgnCRhyPkTSkgrGXbnLR15pHH5HZVYNdM4TCAwQHqG7fMeMPLtYNRnEgoV1aJdR5E61eWu5sWRYgtA" + } + ] + } + ], + "evidence": [ + { + "id": "https://1edtech.edu/credentials/3732/evidence/1", + "type": [ + "Evidence" + ], + "narrative": "# Final Project Report \n This project was ...", + "name": "Final Project Report", + "description": "This is the final project report.", + "genre": "Research", + "audience": "Department" + }, + { + "id": "https://github.com/somebody/project", + "type": [ + "Evidence" + ], + "name": "Final Project Code", + "description": "This is the source code for the final project app.", + "genre": "Research", + "audience": "Department" + } + ], + "issuer": { + "id": "https://1edtech.edu/issuers/565049", + "type": [ + "Profile" + ], + "name": "1EdTech University", + "url": "https://1edtech.edu", + "phone": "1-222-333-4444", + "description": "1EdTech University provides online degree programs.", + "endorsement": [ + { + "@context": [ + "https://www.w3.org/ns/credentials/v2", + "https://purl.imsglobal.org/spec/ob/v3p0/context-3.0.3.json" + ], + "id": "http://1edtech.edu/endorsementcredential/3736", + "type": [ + "VerifiableCredential", + "EndorsementCredential" + ], + "name": "EAA endorsement", + "issuer": { + "id": "https://accrediter.edu/issuers/565049", + "type": [ + "Profile" + ], + "name": "Example Accrediting Agency" + }, + "validFrom": "2010-01-01T00:00:00Z", + "validUntil": "2020-01-01T00:00:00Z", + "credentialSubject": { + "id": "https://1edtech.edu/issuers/565049", + "type": [ + "EndorsementSubject" + ], + "endorsementComment": "1EdTech University is in good standing" + }, + "credentialSchema": [ + { + "id": "https://purl.imsglobal.org/spec/ob/v3p0/schema/json/ob_v3p0_endorsementcredential_schema.json", + "type": "1EdTechJsonSchemaValidator2019" + }, + { + "id": "https://accrediter.edu/schema/endorsementcredential.json", + "type": "1EdTechJsonSchemaValidator2019" + } + ], + "credentialStatus": { + "id": "https://1edtech.edu/credentials/3732/revocations", + "type": "1EdTechRevocationList" + }, + "refreshService": { + "id": "http://1edtech.edu/credentials/3732", + "type": "1EdTechCredentialRefresh" + }, + "proof": [ + { + "type": "DataIntegrityProof", + "cryptosuite": "eddsa-rdf-2022", + "created": "2022-05-26T18:17:08Z", + "verificationMethod": "https://accrediter.edu/issuers/565049#zvPkQiUFfJrgnCRhyPkTSkgrGXbnLR15pHH5HZVYNdM4TCAwQHqG7fMeMPLtYNRnEgoV1aJdR5E61eWu5sWRYgtA", + "proofPurpose": "assertionMethod", + "proofValue": "zvPkQiUFfJrgnCRhyPkTSkgrGXbnLR15pHH5HZVYNdM4TCAwQHqG7fMeMPLtYNRnEgoV1aJdR5E61eWu5sWRYgtA" + } + ] + } + ], + "image": { + "id": "https://1edtech.edu/logo.png", + "type": "Image", + "caption": "1EdTech University logo" + }, + "email": "registrar@1edtech.edu", + "address": { + "type": [ + "Address" + ], + "addressCountry": "USA", + "addressCountryCode": "US", + "addressRegion": "TX", + "addressLocality": "Austin", + "streetAddress": "123 First St", + "postOfficeBoxNumber": "1", + "postalCode": "12345", + "geo": { + "type": "GeoCoordinates", + "latitude": 1, + "longitude": 1 + } + }, + "otherIdentifier": [ + { + "type": "IdentifierEntry", + "identifier": "12345", + "identifierType": "sourcedId" + }, + { + "type": "IdentifierEntry", + "identifier": "67890", + "identifierType": "nationalIdentityNumber" + } + ], + "official": "Horace Mann", + "parentOrg": { + "id": "did:example:123456789", + "type": [ + "Profile" + ], + "name": "Universal Universities" + } + }, + "validFrom": "2010-01-01T00:00:00Z", + "validUntil": "2030-01-01T00:00:00Z", + "credentialSchema": [ + { + "id": "https://purl.imsglobal.org/spec/ob/v3p0/schema/json/ob_v3p0_achievementcredential_schema.json", + "type": "1EdTechJsonSchemaValidator2019" + } + ], + "credentialStatus": { + "id": "https://1edtech.edu/credentials/3732/revocations", + "type": "1EdTechRevocationList" + }, + "refreshService": { + "id": "http://1edtech.edu/credentials/3732", + "type": "1EdTechCredentialRefresh" + }, + "proof": [ + { + "type": "DataIntegrityProof", + "created": "2024-05-31T14:05:25Z", + "verificationMethod": "https://1edtech.edu/issuers/565049#z6MkphU6QmojC6GdUBNYypgnGaiL2TLisLMxpE1oZcmKg7Ad", + "cryptosuite": "eddsa-rdfc-2022", + "proofPurpose": "assertionMethod", + "proofValue": "z5A4ZXLJa4dUArTmpdP9vnrYijMLCT1tR9KWaFmLT2PeQp3gSnGA9wrRJqrJ5Z8YnpVDxZQWRGjjWNbj2PKDJe7dt" + } + ] +} diff --git a/test/Quick_test.md b/test/Quick_test.md new file mode 100644 index 0000000..f8f2282 --- /dev/null +++ b/test/Quick_test.md @@ -0,0 +1,4 @@ +example: +```sh +cargo run -- -i ./test/OBv3_example.json -o ./test/ELM_export_example.json -m ./json/mapping/custom_mapping_OBv3_ELM_latest.json -c OBv3toELM +``` \ No newline at end of file diff --git a/test/edubadges.png b/test/edubadges.png new file mode 100644 index 0000000..b963ca3 Binary files /dev/null and b/test/edubadges.png differ diff --git a/test/edubadges_100x100.png b/test/edubadges_100x100.png new file mode 100644 index 0000000..f4ca569 Binary files /dev/null and b/test/edubadges_100x100.png differ diff --git a/test/encoded_test copy.json b/test/encoded_test copy.json new file mode 100644 index 0000000..2c5e44d --- /dev/null +++ b/test/encoded_test copy.json @@ -0,0 +1,6 @@ +{ + "From": {"Name": "OB", "Version": "3.0"}, + "To": {"Name": "elm", "Version": "3.2"}, + "Parameters": { "PreferredLanguages": ["en", "sv"]}, + "Content" : "ewogICJAY29udGV4dCI6IFsKICAgICJodHRwczovL3d3dy53My5vcmcvbnMvY3JlZGVudGlhbHMvdjIiLAogICAgImh0dHBzOi8vcHVybC5pbXNnbG9iYWwub3JnL3NwZWMvb2IvdjNwMC9jb250ZXh0LTMuMC4zLmpzb24iLAogICAgImh0dHBzOi8vcmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbS9lZHVjcmVkZW50aWFscy9vYnYzLWV4YW1wbGVzL3JlZnMvaGVhZHMvbWFpbi9jb250ZXh0cy9lZHVjcmVkZW50aWFsLmpzb24iCiAgXSwKICAiaWQiOiAiaHR0cDovL2V4YW1wbGUuY29tL2NyZWRlbnRpYWxzL2NyZC1BMUIyQzMiLAogICJ0eXBlIjogWwogICAgIlZlcmlmaWFibGVDcmVkZW50aWFsIiwKICAgICJPcGVuQmFkZ2VDcmVkZW50aWFsIgogIF0sCiAgImlzc3VlciI6IHsKICAgICJpZCI6ICJodHRwczovL2V4YW1wbGUuY29tL2lzc3VlcnMvaXNzLTlaOFk3WCIsCiAgICAidHlwZSI6IFsKICAgICAgIlByb2ZpbGUiCiAgICBdLAogICAgIm5hbWUiOiAiVW5pdmVyc2l0ZWl0IHZhbiBIYXJkZXJ3aWprIiwKICAgICJvdGhlcklkZW50aWZpZXIiOiBbCiAgICAgIHsKICAgICAgICAidHlwZSI6ICJJZGVudGlmaWVyRW50cnkiLAogICAgICAgICJpZGVudGlmaWVyIjogIlVOMVZIIiwKICAgICAgICAiaWRlbnRpZmllclR5cGUiOiAiZXh0OkJSSU4iCiAgICAgIH0sCiAgICAgIHsKICAgICAgICAidHlwZSI6ICJJZGVudGlmaWVyRW50cnkiLAogICAgICAgICJpZGVudGlmaWVyIjogInV2aC5leGFtcGxlLmNvbSIsCiAgICAgICAgImlkZW50aWZpZXJUeXBlIjogIm5hbWUiCiAgICAgIH0KICAgIF0sCiAgICAiaW1hZ2UiOiB7CiAgICAgICJpZCI6ICJodHRwczovL3Jhdy5naXRodWJ1c2VyY29udGVudC5jb20vaGFtcnQvY3JlZGVudGlhbC1jb252ZXJ0ZXIvcmVmcy9oZWFkcy9pbWFnZS90ZXN0L3VuaXZlcnNpdHlfb2ZfaGFyZGVyd2lqa183NXgxMDAuanBnIiwKICAgICAgInR5cGUiOiAiSW1hZ2UiLAogICAgICAiY2FwdGlvbiI6ICJVbml2ZXJzaXR5IG9mIEhhcmRlcndpamsgbG9nbyIKICAgIH0sCiAgICAiYWRkcmVzcyI6IHsKICAgICAgInR5cGUiOiBbCiAgICAgICAgIkFkZHJlc3MiCiAgICAgIF0sCiAgICAgICJhZGRyZXNzQ291bnRyeSI6ICJOREwiLAogICAgICAiYWRkcmVzc0NvdW50cnlDb2RlIjogIk5MIiwKICAgICAgImFkZHJlc3NSZWdpb24iOiAiVVQiLAogICAgICAiYWRkcmVzc0xvY2FsaXR5IjogIkhhcmRlcndpamsiLAogICAgICAic3RyZWV0QWRkcmVzcyI6ICIxMjMgRmlyc3QgU3QiLAogICAgICAicG9zdE9mZmljZUJveE51bWJlciI6ICIxIiwKICAgICAgInBvc3RhbENvZGUiOiAiMTIzNDUiLAogICAgICAiZ2VvIjogewogICAgICAgICJ0eXBlIjogIkdlb0Nvb3JkaW5hdGVzIiwKICAgICAgICAibGF0aXR1ZGUiOiAxLAogICAgICAgICJsb25naXR1ZGUiOiAxCiAgICAgIH0KICAgIH0KICB9LAogICJ2YWxpZEZyb20iOiAiMjAyNC0wOC0zMFQwMDowMDowMFoiLAogICJ2YWxpZFVudGlsIjogIjIwMjktMDgtMzBUMDA6MDA6MDBaIiwKICAiY3JlZGVudGlhbFN1YmplY3QiOiB7CiAgICAiaWQiOiAiaHR0cHM6Ly9leGFtcGxlLmNvbS9zdHVkZW50cy9zdHUtN1o2WDVXIiwKICAgICJ0eXBlIjogWwogICAgICAiQWNoaWV2ZW1lbnRTdWJqZWN0IgogICAgXSwKICAgICJpZGVudGlmaWVyIjogWwogICAgICB7CiAgICAgICAgInR5cGUiOiAiSWRlbnRpdHlPYmplY3QiLAogICAgICAgICJpZGVudGl0eUhhc2giOiAic3R1ZGVudEAxZWR0ZWNoLmVkdSIsCiAgICAgICAgImlkZW50aXR5VHlwZSI6ICJlbWFpbEFkZHJlc3MiLAogICAgICAgICJoYXNoZWQiOiBmYWxzZSwKICAgICAgICAic2FsdCI6ICJub3QtdXNlZCIKICAgICAgfQogICAgXSwKICAgICJhY2hpZXZlbWVudCI6IHsKICAgICAgImlkIjogImh0dHBzOi8vZXhhbXBsZS5jb20vYWNoaWV2ZW1lbnRzL2FjaC04NzY1NDMiLAogICAgICAidHlwZSI6IFsKICAgICAgICAiQWNoaWV2ZW1lbnQiLAogICAgICAgICJFZHVjcmVkZW50aWFsQWNoaWV2ZW1lbnQiCiAgICAgIF0sCiAgICAgICJjcml0ZXJpYSI6IHsKICAgICAgICAibmFycmF0aXZlIjogIkRlIHN0dWRlbnQgaGVlZnQgZGUgZWVyc3RlIHN0YXAgdmFuIHRyYW5zbXV0YXRpZSBhZmdlcm9uZCwgd2FhcmJpaiBrYXR0ZW4gem9uZGVyIGJsaWp2ZW5kZSBzY2hhZGUgd29yZGVuIG9tZ2V6ZXQgaW4ga2V1a2VuYXBwYXJhdHV1ci4iCiAgICAgIH0sCiAgICAgICJkZXNjcmlwdGlvbiI6ICJEZSBzdHVkZW50IGhlZWZ0IG1ldCBzdWNjZXMgZGUgZWVyc3RlIHN0YXAgaW4gdHJhbnNtdXRhdGllIGFmZ2Vyb25kLCB3YWFyYmlqIGthdHRlbiB6b25kZXIgYmxpanZlbmRlIHNjaGFkZSB3b3JkZW4gb21nZXpldCBpbiBrZXVrZW5hcHBhcmF0dXVyLiIsCiAgICAgICJuYW1lIjogIk1pY3JvY3JlZGVudGlhbCBCYXNpc29temV0dGluZyBLYXQgbmFhciBLb2ZmaWV6ZXRhcHBhcmFhdCIsCiAgICAgICJpbWFnZSI6IHsKICAgICAgICAiaWQiOiAiaHR0cHM6Ly9yYXcuZ2l0aHVidXNlcmNvbnRlbnQuY29tL2hhbXJ0L2NyZWRlbnRpYWwtY29udmVydGVyL3JlZnMvaGVhZHMvaW1hZ2UvdGVzdC9lZHViYWRnZXNfMTAweDEwMC5qcGciLAogICAgICAgICJ0eXBlIjogIkltYWdlIgogICAgICB9LAogICAgICAiaW5MYW5ndWFnZSI6ICJubC1OTCIsCiAgICAgICJlZHVjYXRpb25Qcm9ncmFtSWRlbnRpZmllciI6IDIwMTIxMzUwLAogICAgICAiRUNUUyI6IDMuMCwKICAgICAgImNyZWRpdHNBdmFpbGFibGUiOiAzLAoKICAgICAgImFsaWdubWVudCI6IFsKICAgICAgICB7CiAgICAgICAgICAidHlwZSI6IFsKICAgICAgICAgICAgIkFsaWdubWVudCIKICAgICAgICAgIF0sCiAgICAgICAgICAidGFyZ2V0VHlwZSI6ICJleHQ6UXVhbGl0eUFzc3VyYW5jZSIsCiAgICAgICAgICAidGFyZ2V0TmFtZSI6ICJXIFByYWN0aXNjaGUgdG9lcGFzc2luZyB2YW4gYW5pbWFsZSB0cmFuc211dGF0aWUiLAogICAgICAgICAgInRhcmdldERlc2NyaXB0aW9uIjogIkFjY3JlZGl0YXRpZSB2YW4gZGUgb3BsZWlkaW5nIGRvb3IgZGUgV2lqemUgUmFhZCB2YW4gZGUgTWFnacOrcnMiLAogICAgICAgICAgInRhcmdldENvZGUiOiAiQVYtNzM4MSIsCiAgICAgICAgICAidGFyZ2V0VXJsIjogImh0dHBzOi8vZGF0YS5leGFtcGxlLmNvbS9kZWNpc2lvbnMvQVYtNzM4MSIKICAgICAgICB9LAogICAgICAgIHsKICAgICAgICAgICJ0eXBlIjogWwogICAgICAgICAgICAiQWxpZ25tZW50IgogICAgICAgICAgXSwKICAgICAgICAgICJ0YXJnZXRUeXBlIjogImV4dDpFUUYiLAogICAgICAgICAgInRhcmdldE5hbWUiOiAiRVFGIGxldmVsIDQiLAogICAgICAgICAgInRhcmdldENvZGUiOiAiNCIsCiAgICAgICAgICAidGFyZ2V0VXJsIjogImh0dHBzOi8vY29udGVudC5leGFtcGxlLmNvbS9kZXNjcmlwdGlvbi1lcWYtbGV2ZWxzIgogICAgICAgIH0KICAgICAgXSwKICAgICAgInBhcnRpY2lwYXRpb25UeXBlIjogIm9uc2l0ZSBvciBibGVuZGVkIiwKICAgICAgImFzc2Vzc21lbnRUeXBlIjogInRlc3RpbmciLAogICAgICAiaWRlbnRpdHlDaGVja2VkIjogdHJ1ZSwKICAgICAgInN1cGVydmlzaW9uVHlwZSI6ICJvbnNpdGUgd2l0aCBpZGVudGl0eSB2ZXJpZmljYXRpb24iLAogICAgICAicmVzdWx0RGVzY3JpcHRpb24iOiBbCiAgICAgICAgewogICAgICAgICAgImlkIjogImh0dHBzOi8vZXhhbXBsZS5jb20vcmVzdWx0cy9lY3RzLW5sLU5MLUExQjJDMyIsCiAgICAgICAgICAidHlwZSI6IFsKICAgICAgICAgICAgIlJlc3VsdERlc2NyaXB0aW9uIgogICAgICAgICAgXSwKICAgICAgICAgICJ2YWx1ZU1heCI6ICIxMCIsCiAgICAgICAgICAidmFsdWVNaW4iOiAiMSIsCiAgICAgICAgICAibmFtZSI6ICJGaW5hbCBQcm9qZWN0IEdyYWRlIiwKICAgICAgICAgICJyZXF1aXJlZFZhbHVlIjogIjYiLAogICAgICAgICAgInJlc3VsdFR5cGUiOiAiZXh0OkVDVFNHcmFkZVNjb3JlIgogICAgICAgIH0KICAgICAgXQogICAgfSwKICAgICJyZXN1bHQiOiBbCiAgICAgIHsKICAgICAgICAidHlwZSI6IFsKICAgICAgICAgICJSZXN1bHQiCiAgICAgICAgXSwKICAgICAgICAicmVzdWx0RGVzY3JpcHRpb24iOiAiaHR0cHM6Ly9leGFtcGxlLmNvbS9yZXN1bHRzL2VjdHMtbmwtTkwtQTFCMkMzIiwKICAgICAgICAidmFsdWUiOiAiOC41IgogICAgICB9CiAgICBdCiAgfSwKICAiY3JlZGVudGlhbFNjaGVtYSI6IFsKICAgIHsKICAgICAgImlkIjogImh0dHBzOi8vcHVybC5pbXNnbG9iYWwub3JnL3NwZWMvb2IvdjNwMC9zY2hlbWEvanNvbi9vYl92M3AwX2FjaGlldmVtZW50Y3JlZGVudGlhbF9zY2hlbWEuanNvbiIsCiAgICAgICJ0eXBlIjogIjFFZFRlY2hKc29uU2NoZW1hVmFsaWRhdG9yMjAxOSIKICAgIH0sCiAgICB7CiAgICAgICJpZCI6ICJodHRwczovL3Jhdy5naXRodWJ1c2VyY29udGVudC5jb20vZWR1Y3JlZGVudGlhbHMvb2J2My1leGFtcGxlcy9yZWZzL2hlYWRzL21haW4vc2NoZW1hcy9taWNyb2NyZWRlbnRpYWwuanNvbiIsCiAgICAgICJ0eXBlIjogIjFFZFRlY2hKc29uU2NoZW1hVmFsaWRhdG9yMjAxOSIKICAgIH0sCiAgICB7CiAgICAgICJpZCI6ICJodHRwczovL3Jhdy5naXRodWJ1c2VyY29udGVudC5jb20vZWR1Y3JlZGVudGlhbHMvb2J2My1leGFtcGxlcy9yZWZzL2hlYWRzL21haW4vc2NoZW1hcy9taWNyb2NyZWRlbnRpYWxfZWN0cy5qc29uIiwKICAgICAgInR5cGUiOiAiMUVkVGVjaEpzb25TY2hlbWFWYWxpZGF0b3IyMDE5IgogICAgfQogIF0KfQo=" +} \ No newline at end of file diff --git a/test/encoded_test.json b/test/encoded_test.json new file mode 100644 index 0000000..23d51e8 --- /dev/null +++ b/test/encoded_test.json @@ -0,0 +1,6 @@ +{ + "From": {"Name": "OB", "Version": "3.0"}, + "To": {"Name": "elm", "Version": "3.2"}, + "Parameters": { "PreferredLanguages": ["en", "sv"]}, + "Content" : "ewogICAgIkBjb250ZXh0IjogWwogICAgICAiaHR0cHM6Ly93d3cudzMub3JnL25zL2NyZWRlbnRpYWxzL3YyIiwKICAgICAgImh0dHBzOi8vcHVybC5pbXNnbG9iYWwub3JnL3NwZWMvb2IvdjNwMC9jb250ZXh0LTMuMC4zLmpzb24iLAogICAgICAiaHR0cHM6Ly9wdXJsLmltc2dsb2JhbC5vcmcvc3BlYy9vYi92M3AwL2V4dGVuc2lvbnMuanNvbiIKICAgIF0sCiAgICAiaWQiOiAiaHR0cDovLzFlZHRlY2guZWR1L2NyZWRlbnRpYWxzLzM3MzIiLAogICAgInR5cGUiOiBbCiAgICAgICJWZXJpZmlhYmxlQ3JlZGVudGlhbCIsCiAgICAgICJPcGVuQmFkZ2VDcmVkZW50aWFsIgogICAgXSwKICAgICJuYW1lIjogIjFFZFRlY2ggVW5pdmVyc2l0eSBEZWdyZWUgZm9yIEV4YW1wbGUgU3R1ZGVudCIsCiAgICAiZGVzY3JpcHRpb24iOiAiMUVkVGVjaCBVbml2ZXJzaXR5IERlZ3JlZSBEZXNjcmlwdGlvbiIsCiAgICAiaW1hZ2UiOiB7CiAgICAgICJpZCI6ICJodHRwczovL3Jhdy5naXRodWJ1c2VyY29udGVudC5jb20vaGFtcnQvY3JlZGVudGlhbC1jb252ZXJ0ZXIvcmVmcy9oZWFkcy9pbWFnZS90ZXN0L2VkdWJhZGdlc18xMDB4MTAwLnBuZyIsCiAgICAgICJ0eXBlIjogIkltYWdlIiwKICAgICAgImNhcHRpb24iOiAiMUVkVGVjaCBVbml2ZXJzaXR5IERlZ3JlZSBmb3IgRXhhbXBsZSBTdHVkZW50IgogICAgfSwKICAgICJjcmVkZW50aWFsU3ViamVjdCI6IHsKICAgICAgImlkIjogImRpZDpleGFtcGxlOmViZmViMWY3MTJlYmM2ZjFjMjc2ZTEyZWMyMSIsCiAgICAgICJ0eXBlIjogWwogICAgICAgICJBY2hpZXZlbWVudFN1YmplY3QiCiAgICAgIF0sCiAgICAgICJhY3Rpdml0eUVuZERhdGUiOiAiMjAxMC0wMS0wMlQwMDowMDowMFoiLAogICAgICAiYWN0aXZpdHlTdGFydERhdGUiOiAiMjAxMC0wMS0wMVQwMDowMDowMFoiLAogICAgICAiY3JlZGl0c0Vhcm5lZCI6IDQyLAogICAgICAibGljZW5zZU51bWJlciI6ICJBLTkzMjAwNDEiLAogICAgICAicm9sZSI6ICJNYWpvciBEb21vIiwKICAgICAgInNvdXJjZSI6IHsKICAgICAgICAiaWQiOiAiaHR0cHM6Ly9zY2hvb2wuZWR1L2lzc3VlcnMvMjAxMjM0IiwKICAgICAgICAidHlwZSI6IFsKICAgICAgICAgICJQcm9maWxlIgogICAgICAgIF0sCiAgICAgICAgIm5hbWUiOiAiMUVkVGVjaCBDb2xsZWdlIG9mIEFydHMiCiAgICAgIH0sCiAgICAgICJ0ZXJtIjogIkZhbGwiLAogICAgICAiaWRlbnRpZmllciI6IFsKICAgICAgICB7CiAgICAgICAgICAidHlwZSI6ICJJZGVudGl0eU9iamVjdCIsCiAgICAgICAgICAiaWRlbnRpdHlIYXNoIjogInN0dWRlbnRAMWVkdGVjaC5lZHUiLAogICAgICAgICAgImlkZW50aXR5VHlwZSI6ICJlbWFpbEFkZHJlc3MiLAogICAgICAgICAgImhhc2hlZCI6IGZhbHNlLAogICAgICAgICAgInNhbHQiOiAibm90LXVzZWQiCiAgICAgICAgfSwKICAgICAgICB7CiAgICAgICAgICAidHlwZSI6ICJJZGVudGl0eU9iamVjdCIsCiAgICAgICAgICAiaWRlbnRpdHlIYXNoIjogInNvbWVib2R5QGdtYWlsLmNvbSIsCiAgICAgICAgICAiaWRlbnRpdHlUeXBlIjogImVtYWlsQWRkcmVzcyIsCiAgICAgICAgICAiaGFzaGVkIjogZmFsc2UsCiAgICAgICAgICAic2FsdCI6ICJub3QtdXNlZCIKICAgICAgICB9CiAgICAgIF0sCiAgICAgICJhY2hpZXZlbWVudCI6IHsKICAgICAgICAiaWQiOiAiaHR0cHM6Ly8xZWR0ZWNoLmVkdS9hY2hpZXZlbWVudHMvZGVncmVlIiwKICAgICAgICAidHlwZSI6IFsKICAgICAgICAgICJBY2hpZXZlbWVudCIKICAgICAgICBdLAogICAgICAgICJhbGlnbm1lbnQiOiBbCiAgICAgICAgICB7CiAgICAgICAgICAgICJ0eXBlIjogWwogICAgICAgICAgICAgICJBbGlnbm1lbnQiCiAgICAgICAgICAgIF0sCiAgICAgICAgICAgICJ0YXJnZXRDb2RlIjogImRlZ3JlZSIsCiAgICAgICAgICAgICJ0YXJnZXREZXNjcmlwdGlvbiI6ICIxRWRUZWNoIFVuaXZlcnNpdHkgRGVncmVlIHByb2dyYW1zLiIsCiAgICAgICAgICAgICJ0YXJnZXROYW1lIjogIjFFZFRlY2ggVW5pdmVyc2l0eSBEZWdyZWUiLAogICAgICAgICAgICAidGFyZ2V0RnJhbWV3b3JrIjogIjFFZFRlY2ggVW5pdmVyc2l0eSBQcm9ncmFtIGFuZCBDb3Vyc2UgQ2F0YWxvZyIsCiAgICAgICAgICAgICJ0YXJnZXRUeXBlIjogIkNGSXRlbSIsCiAgICAgICAgICAgICJ0YXJnZXRVcmwiOiAiaHR0cHM6Ly8xZWR0ZWNoLmVkdS9jYXRhbG9nL2RlZ3JlZSIKICAgICAgICAgIH0sCiAgICAgICAgICB7CiAgICAgICAgICAgICJ0eXBlIjogWwogICAgICAgICAgICAgICJBbGlnbm1lbnQiCiAgICAgICAgICAgIF0sCiAgICAgICAgICAgICJ0YXJnZXRDb2RlIjogImRlZ3JlZSIsCiAgICAgICAgICAgICJ0YXJnZXREZXNjcmlwdGlvbiI6ICIxRWRUZWNoIFVuaXZlcnNpdHkgRGVncmVlIHByb2dyYW1zLiIsCiAgICAgICAgICAgICJ0YXJnZXROYW1lIjogIjFFZFRlY2ggVW5pdmVyc2l0eSBEZWdyZWUiLAogICAgICAgICAgICAidGFyZ2V0RnJhbWV3b3JrIjogIjFFZFRlY2ggVW5pdmVyc2l0eSBQcm9ncmFtIGFuZCBDb3Vyc2UgQ2F0YWxvZyIsCiAgICAgICAgICAgICJ0YXJnZXRUeXBlIjogIkNUREwiLAogICAgICAgICAgICAidGFyZ2V0VXJsIjogImh0dHBzOi8vY3JlZGVudGlhbGVuZ2luZXJlZ2lzdHJ5Lm9yZy9yZXNvdXJjZXMvY2UtOThjYjAyN2ItOTVlZi00NDk0LTkwOGQtNmY3NzkwZWM2YjZiIgogICAgICAgICAgfQogICAgICAgIF0sCiAgICAgICAgImFjaGlldmVtZW50VHlwZSI6ICJEZWdyZWUiLAogICAgICAgICJjcmVhdG9yIjogewogICAgICAgICAgImlkIjogImh0dHBzOi8vMWVkdGVjaC5lZHUvaXNzdWVycy81NjUwNDkiLAogICAgICAgICAgInR5cGUiOiBbCiAgICAgICAgICAgICJQcm9maWxlIgogICAgICAgICAgXSwKICAgICAgICAgICJuYW1lIjogIjFFZFRlY2ggVW5pdmVyc2l0eSIsCiAgICAgICAgICAidXJsIjogImh0dHBzOi8vMWVkdGVjaC5lZHUiLAogICAgICAgICAgInBob25lIjogIjEtMjIyLTMzMy00NDQ0IiwKICAgICAgICAgICJkZXNjcmlwdGlvbiI6ICIxRWRUZWNoIFVuaXZlcnNpdHkgcHJvdmlkZXMgb25saW5lIGRlZ3JlZSBwcm9ncmFtcy4iLAogICAgICAgICAgImVuZG9yc2VtZW50IjogWwogICAgICAgICAgICB7CiAgICAgICAgICAgICAgIkBjb250ZXh0IjogWwogICAgICAgICAgICAgICAgImh0dHBzOi8vd3d3LnczLm9yZy9ucy9jcmVkZW50aWFscy92MiIsCiAgICAgICAgICAgICAgICAiaHR0cHM6Ly9wdXJsLmltc2dsb2JhbC5vcmcvc3BlYy9vYi92M3AwL2NvbnRleHQtMy4wLjMuanNvbiIKICAgICAgICAgICAgICBdLAogICAgICAgICAgICAgICJpZCI6ICJodHRwOi8vMWVkdGVjaC5lZHUvZW5kb3JzZW1lbnRjcmVkZW50aWFsLzM3MzIiLAogICAgICAgICAgICAgICJ0eXBlIjogWwogICAgICAgICAgICAgICAgIlZlcmlmaWFibGVDcmVkZW50aWFsIiwKICAgICAgICAgICAgICAgICJFbmRvcnNlbWVudENyZWRlbnRpYWwiCiAgICAgICAgICAgICAgXSwKICAgICAgICAgICAgICAibmFtZSI6ICJTREUgZW5kb3JzZW1lbnQiLAogICAgICAgICAgICAgICJpc3N1ZXIiOiB7CiAgICAgICAgICAgICAgICAiaWQiOiAiaHR0cHM6Ly9hY2NyZWRpdGVyLmVkdS9pc3N1ZXJzLzU2NTA0OSIsCiAgICAgICAgICAgICAgICAidHlwZSI6IFsKICAgICAgICAgICAgICAgICAgIlByb2ZpbGUiCiAgICAgICAgICAgICAgICBdLAogICAgICAgICAgICAgICAgIm5hbWUiOiAiRXhhbXBsZSBBY2NyZWRpdGluZyBBZ2VuY3kiCiAgICAgICAgICAgICAgfSwKICAgICAgICAgICAgICAidmFsaWRGcm9tIjogIjIwMTAtMDEtMDFUMDA6MDA6MDBaIiwKICAgICAgICAgICAgICAidmFsaWRVbnRpbCI6ICIyMDIwLTAxLTAxVDAwOjAwOjAwWiIsCiAgICAgICAgICAgICAgImNyZWRlbnRpYWxTdWJqZWN0IjogewogICAgICAgICAgICAgICAgImlkIjogImh0dHBzOi8vMWVkdGVjaC5lZHUvaXNzdWVycy81NjUwNDkiLAogICAgICAgICAgICAgICAgInR5cGUiOiBbCiAgICAgICAgICAgICAgICAgICJFbmRvcnNlbWVudFN1YmplY3QiCiAgICAgICAgICAgICAgICBdLAogICAgICAgICAgICAgICAgImVuZG9yc2VtZW50Q29tbWVudCI6ICIxRWRUZWNoIFVuaXZlcnNpdHkgaXMgaW4gZ29vZCBzdGFuZGluZyIKICAgICAgICAgICAgICB9LAogICAgICAgICAgICAgICJjcmVkZW50aWFsU2NoZW1hIjogWwogICAgICAgICAgICAgICAgewogICAgICAgICAgICAgICAgICAiaWQiOiAiaHR0cHM6Ly9wdXJsLmltc2dsb2JhbC5vcmcvc3BlYy9vYi92M3AwL3NjaGVtYS9qc29uL29iX3YzcDBfZW5kb3JzZW1lbnRjcmVkZW50aWFsX3NjaGVtYS5qc29uIiwKICAgICAgICAgICAgICAgICAgInR5cGUiOiAiMUVkVGVjaEpzb25TY2hlbWFWYWxpZGF0b3IyMDE5IgogICAgICAgICAgICAgICAgfSwKICAgICAgICAgICAgICAgIHsKICAgICAgICAgICAgICAgICAgImlkIjogImh0dHBzOi8vYWNjcmVkaXRlci5lZHUvc2NoZW1hL2VuZG9yc2VtZW50Y3JlZGVudGlhbC5qc29uIiwKICAgICAgICAgICAgICAgICAgInR5cGUiOiAiMUVkVGVjaEpzb25TY2hlbWFWYWxpZGF0b3IyMDE5IgogICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgIF0sCiAgICAgICAgICAgICAgImNyZWRlbnRpYWxTdGF0dXMiOiB7CiAgICAgICAgICAgICAgICAiaWQiOiAiaHR0cHM6Ly8xZWR0ZWNoLmVkdS9jcmVkZW50aWFscy8zNzMyL3Jldm9jYXRpb25zIiwKICAgICAgICAgICAgICAgICJ0eXBlIjogIjFFZFRlY2hSZXZvY2F0aW9uTGlzdCIKICAgICAgICAgICAgICB9LAogICAgICAgICAgICAgICJyZWZyZXNoU2VydmljZSI6IHsKICAgICAgICAgICAgICAgICJpZCI6ICJodHRwOi8vMWVkdGVjaC5lZHUvY3JlZGVudGlhbHMvMzczMiIsCiAgICAgICAgICAgICAgICAidHlwZSI6ICIxRWRUZWNoQ3JlZGVudGlhbFJlZnJlc2giCiAgICAgICAgICAgICAgfSwKICAgICAgICAgICAgICAicHJvb2YiOiBbCiAgICAgICAgICAgICAgICB7CiAgICAgICAgICAgICAgICAgICJ0eXBlIjogIkRhdGFJbnRlZ3JpdHlQcm9vZiIsCiAgICAgICAgICAgICAgICAgICJjcnlwdG9zdWl0ZSI6ICJlZGRzYS1yZGYtMjAyMiIsCiAgICAgICAgICAgICAgICAgICJjcmVhdGVkIjogIjIwMjItMDUtMjZUMTg6MTc6MDhaIiwKICAgICAgICAgICAgICAgICAgInZlcmlmaWNhdGlvbk1ldGhvZCI6ICJodHRwczovL2FjY3JlZGl0ZXIuZWR1L2lzc3VlcnMvNTY1MDQ5I3p2UGtRaVVGZkpyZ25DUmh5UGtUU2tnckdYYm5MUjE1cEhINUhaVllOZE00VENBd1FIcUc3Zk1lTVBMdFlOUm5FZ29WMWFKZFI1RTYxZVd1NXNXUllndEEiLAogICAgICAgICAgICAgICAgICAicHJvb2ZQdXJwb3NlIjogImFzc2VydGlvbk1ldGhvZCIsCiAgICAgICAgICAgICAgICAgICJwcm9vZlZhbHVlIjogInp2UGtRaVVGZkpyZ25DUmh5UGtUU2tnckdYYm5MUjE1cEhINUhaVllOZE00VENBd1FIcUc3Zk1lTVBMdFlOUm5FZ29WMWFKZFI1RTYxZVd1NXNXUllndEEiCiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgXQogICAgICAgICAgICB9LAogICAgICAgICAgICB7CiAgICAgICAgICAgICAgIkBjb250ZXh0IjogWwogICAgICAgICAgICAgICAgImh0dHBzOi8vd3d3LnczLm9yZy9ucy9jcmVkZW50aWFscy92MiIsCiAgICAgICAgICAgICAgICAiaHR0cHM6Ly9wdXJsLmltc2dsb2JhbC5vcmcvc3BlYy9vYi92M3AwL2NvbnRleHQtMy4wLjMuanNvbiIKICAgICAgICAgICAgICBdLAogICAgICAgICAgICAgICJpZCI6ICJodHRwOi8vMWVkdGVjaC5lZHUvZW5kb3JzZW1lbnRjcmVkZW50aWFsLzM3MzMiLAogICAgICAgICAgICAgICJ0eXBlIjogWwogICAgICAgICAgICAgICAgIlZlcmlmaWFibGVDcmVkZW50aWFsIiwKICAgICAgICAgICAgICAgICJFbmRvcnNlbWVudENyZWRlbnRpYWwiCiAgICAgICAgICAgICAgXSwKICAgICAgICAgICAgICAibmFtZSI6ICJTREUgZW5kb3JzZW1lbnQiLAogICAgICAgICAgICAgICJpc3N1ZXIiOiB7CiAgICAgICAgICAgICAgICAiaWQiOiAiaHR0cHM6Ly9zdGF0ZS5nb3YvaXNzdWVycy81NjUwNDkiLAogICAgICAgICAgICAgICAgInR5cGUiOiBbCiAgICAgICAgICAgICAgICAgICJQcm9maWxlIgogICAgICAgICAgICAgICAgXSwKICAgICAgICAgICAgICAgICJuYW1lIjogIlN0YXRlIERlcGFydG1lbnQgb2YgRWR1Y2F0aW9uIgogICAgICAgICAgICAgIH0sCiAgICAgICAgICAgICAgInZhbGlkRnJvbSI6ICIyMDEwLTAxLTAxVDAwOjAwOjAwWiIsCiAgICAgICAgICAgICAgInZhbGlkVW50aWwiOiAiMjAyMC0wMS0wMVQwMDowMDowMFoiLAogICAgICAgICAgICAgICJjcmVkZW50aWFsU3ViamVjdCI6IHsKICAgICAgICAgICAgICAgICJpZCI6ICJodHRwczovLzFlZHRlY2guZWR1L2lzc3VlcnMvNTY1MDQ5IiwKICAgICAgICAgICAgICAgICJ0eXBlIjogWwogICAgICAgICAgICAgICAgICAiRW5kb3JzZW1lbnRTdWJqZWN0IgogICAgICAgICAgICAgICAgXSwKICAgICAgICAgICAgICAgICJlbmRvcnNlbWVudENvbW1lbnQiOiAiMUVkVGVjaCBVbml2ZXJzaXR5IGlzIGluIGdvb2Qgc3RhbmRpbmciCiAgICAgICAgICAgICAgfSwKICAgICAgICAgICAgICAiY3JlZGVudGlhbFNjaGVtYSI6IFsKICAgICAgICAgICAgICAgIHsKICAgICAgICAgICAgICAgICAgImlkIjogImh0dHBzOi8vcHVybC5pbXNnbG9iYWwub3JnL3NwZWMvb2IvdjNwMC9zY2hlbWEvanNvbi9vYl92M3AwX2VuZG9yc2VtZW50Y3JlZGVudGlhbF9zY2hlbWEuanNvbiIsCiAgICAgICAgICAgICAgICAgICJ0eXBlIjogIjFFZFRlY2hKc29uU2NoZW1hVmFsaWRhdG9yMjAxOSIKICAgICAgICAgICAgICAgIH0sCiAgICAgICAgICAgICAgICB7CiAgICAgICAgICAgICAgICAgICJpZCI6ICJodHRwczovL3N0YXRlLmdvdi9zY2hlbWEvZW5kb3JzZW1lbnRjcmVkZW50aWFsLmpzb24iLAogICAgICAgICAgICAgICAgICAidHlwZSI6ICIxRWRUZWNoSnNvblNjaGVtYVZhbGlkYXRvcjIwMTkiCiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgXSwKICAgICAgICAgICAgICAiY3JlZGVudGlhbFN0YXR1cyI6IHsKICAgICAgICAgICAgICAgICJpZCI6ICJodHRwczovL3N0YXRlLmdvdi9jcmVkZW50aWFscy8zNzMyL3Jldm9jYXRpb25zIiwKICAgICAgICAgICAgICAgICJ0eXBlIjogIjFFZFRlY2hSZXZvY2F0aW9uTGlzdCIKICAgICAgICAgICAgICB9LAogICAgICAgICAgICAgICJyZWZyZXNoU2VydmljZSI6IHsKICAgICAgICAgICAgICAgICJpZCI6ICJodHRwOi8vc3RhdGUuZ292L2NyZWRlbnRpYWxzLzM3MzIiLAogICAgICAgICAgICAgICAgInR5cGUiOiAiMUVkVGVjaENyZWRlbnRpYWxSZWZyZXNoIgogICAgICAgICAgICAgIH0sCiAgICAgICAgICAgICAgInByb29mIjogWwogICAgICAgICAgICAgICAgewogICAgICAgICAgICAgICAgICAidHlwZSI6ICJEYXRhSW50ZWdyaXR5UHJvb2YiLAogICAgICAgICAgICAgICAgICAiY3J5cHRvc3VpdGUiOiAiZWRkc2EtcmRmLTIwMjIiLAogICAgICAgICAgICAgICAgICAiY3JlYXRlZCI6ICIyMDIyLTA1LTI2VDE4OjI1OjU5WiIsCiAgICAgICAgICAgICAgICAgICJ2ZXJpZmljYXRpb25NZXRob2QiOiAiaHR0cHM6Ly9hY2NyZWRpdGVyLmVkdS9pc3N1ZXJzLzU2NTA0OSN6NWJEbm1TZ0Rjelh3Wkd5YTZaanhLYXhrZEt4enNDTWlWU3NnRVZXeG5hV0s3WnFiS256Y0NkN21VS0U5RFFhQUwyUU1YUDVBcXVQZVc2VzJDV3JaN2pOQyIsCiAgICAgICAgICAgICAgICAgICJwcm9vZlB1cnBvc2UiOiAiYXNzZXJ0aW9uTWV0aG9kIiwKICAgICAgICAgICAgICAgICAgInByb29mVmFsdWUiOiAiejViRG5tU2dEY3pYd1pHeWE2Wmp4S2F4a2RLeHpzQ01pVlNzZ0VWV3huYVdLN1pxYktuemNDZDdtVUtFOURRYUFMMlFNWFA1QXF1UGVXNlcyQ1dyWjdqTkMiCiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgXQogICAgICAgICAgICB9CiAgICAgICAgICBdLAogICAgICAgICAgImltYWdlIjogewogICAgICAgICAgICAiaWQiOiAiaHR0cHM6Ly8xZWR0ZWNoLmVkdS9sb2dvLnBuZyIsCiAgICAgICAgICAgICJ0eXBlIjogIkltYWdlIiwKICAgICAgICAgICAgImNhcHRpb24iOiAiMUVkVGVjaCBVbml2ZXJzaXR5IGxvZ28iCiAgICAgICAgICB9LAogICAgICAgICAgImVtYWlsIjogInJlZ2lzdHJhckAxZWR0ZWNoLmVkdSIsCiAgICAgICAgICAiYWRkcmVzcyI6IHsKICAgICAgICAgICAgInR5cGUiOiBbCiAgICAgICAgICAgICAgIkFkZHJlc3MiCiAgICAgICAgICAgIF0sCiAgICAgICAgICAgICJhZGRyZXNzQ291bnRyeSI6ICJVU0EiLAogICAgICAgICAgICAiYWRkcmVzc0NvdW50cnlDb2RlIjogIlVTIiwKICAgICAgICAgICAgImFkZHJlc3NSZWdpb24iOiAiVFgiLAogICAgICAgICAgICAiYWRkcmVzc0xvY2FsaXR5IjogIkF1c3RpbiIsCiAgICAgICAgICAgICJzdHJlZXRBZGRyZXNzIjogIjEyMyBGaXJzdCBTdCIsCiAgICAgICAgICAgICJwb3N0T2ZmaWNlQm94TnVtYmVyIjogIjEiLAogICAgICAgICAgICAicG9zdGFsQ29kZSI6ICIxMjM0NSIsCiAgICAgICAgICAgICJnZW8iOiB7CiAgICAgICAgICAgICAgInR5cGUiOiAiR2VvQ29vcmRpbmF0ZXMiLAogICAgICAgICAgICAgICJsYXRpdHVkZSI6IDEsCiAgICAgICAgICAgICAgImxvbmdpdHVkZSI6IDEKICAgICAgICAgICAgfQogICAgICAgICAgfSwKICAgICAgICAgICJvdGhlcklkZW50aWZpZXIiOiBbCiAgICAgICAgICAgIHsKICAgICAgICAgICAgICAidHlwZSI6ICJJZGVudGlmaWVyRW50cnkiLAogICAgICAgICAgICAgICJpZGVudGlmaWVyIjogIjEyMzQ1IiwKICAgICAgICAgICAgICAiaWRlbnRpZmllclR5cGUiOiAic291cmNlZElkIgogICAgICAgICAgICB9LAogICAgICAgICAgICB7CiAgICAgICAgICAgICAgInR5cGUiOiAiSWRlbnRpZmllckVudHJ5IiwKICAgICAgICAgICAgICAiaWRlbnRpZmllciI6ICI2Nzg5MCIsCiAgICAgICAgICAgICAgImlkZW50aWZpZXJUeXBlIjogIm5hdGlvbmFsSWRlbnRpdHlOdW1iZXIiCiAgICAgICAgICAgIH0KICAgICAgICAgIF0sCiAgICAgICAgICAib2ZmaWNpYWwiOiAiSG9yYWNlIE1hbm4iLAogICAgICAgICAgInBhcmVudE9yZyI6IHsKICAgICAgICAgICAgImlkIjogImRpZDpleGFtcGxlOjEyMzQ1Njc4OSIsCiAgICAgICAgICAgICJ0eXBlIjogWwogICAgICAgICAgICAgICJQcm9maWxlIgogICAgICAgICAgICBdLAogICAgICAgICAgICAibmFtZSI6ICJVbml2ZXJzYWwgVW5pdmVyc2l0aWVzIgogICAgICAgICAgfQogICAgICAgIH0sCiAgICAgICAgImNyZWRpdHNBdmFpbGFibGUiOiAzNiwKICAgICAgICAiY3JpdGVyaWEiOiB7CiAgICAgICAgICAiaWQiOiAiaHR0cHM6Ly8xZWR0ZWNoLmVkdS9hY2hpZXZlbWVudHMvZGVncmVlIiwKICAgICAgICAgICJuYXJyYXRpdmUiOiAiIyBEZWdyZWUgUmVxdWlyZW1lbnRzXG5TdHVkZW50cyBtdXN0IGNvbXBsZXRlLi4uIgogICAgICAgIH0sCiAgICAgICAgImRlc2NyaXB0aW9uIjogIjFFZFRlY2ggVW5pdmVyc2l0eSBEZWdyZWUgRGVzY3JpcHRpb24iLAogICAgICAgICJlbmRvcnNlbWVudCI6IFsKICAgICAgICAgIHsKICAgICAgICAgICAgIkBjb250ZXh0IjogWwogICAgICAgICAgICAgICJodHRwczovL3d3dy53My5vcmcvbnMvY3JlZGVudGlhbHMvdjIiLAogICAgICAgICAgICAgICJodHRwczovL3B1cmwuaW1zZ2xvYmFsLm9yZy9zcGVjL29iL3YzcDAvY29udGV4dC0zLjAuMy5qc29uIgogICAgICAgICAgICBdLAogICAgICAgICAgICAiaWQiOiAiaHR0cDovLzFlZHRlY2guZWR1L2VuZG9yc2VtZW50Y3JlZGVudGlhbC8zNzM0IiwKICAgICAgICAgICAgInR5cGUiOiBbCiAgICAgICAgICAgICAgIlZlcmlmaWFibGVDcmVkZW50aWFsIiwKICAgICAgICAgICAgICAiRW5kb3JzZW1lbnRDcmVkZW50aWFsIgogICAgICAgICAgICBdLAogICAgICAgICAgICAibmFtZSI6ICJFQUEgZW5kb3JzZW1lbnQiLAogICAgICAgICAgICAiaXNzdWVyIjogewogICAgICAgICAgICAgICJpZCI6ICJodHRwczovL2FjY3JlZGl0ZXIuZWR1L2lzc3VlcnMvNTY1MDQ5IiwKICAgICAgICAgICAgICAidHlwZSI6IFsKICAgICAgICAgICAgICAgICJQcm9maWxlIgogICAgICAgICAgICAgIF0sCiAgICAgICAgICAgICAgIm5hbWUiOiAiRXhhbXBsZSBBY2NyZWRpdGluZyBBZ2VuY3kiCiAgICAgICAgICAgIH0sCiAgICAgICAgICAgICJ2YWxpZEZyb20iOiAiMjAxMC0wMS0wMVQwMDowMDowMFoiLAogICAgICAgICAgICAidmFsaWRVbnRpbCI6ICIyMDIwLTAxLTAxVDAwOjAwOjAwWiIsCiAgICAgICAgICAgICJjcmVkZW50aWFsU3ViamVjdCI6IHsKICAgICAgICAgICAgICAiaWQiOiAiaHR0cHM6Ly8xZWR0ZWNoLmVkdS9pc3N1ZXJzLzU2NTA0OSIsCiAgICAgICAgICAgICAgInR5cGUiOiBbCiAgICAgICAgICAgICAgICAiRW5kb3JzZW1lbnRTdWJqZWN0IgogICAgICAgICAgICAgIF0sCiAgICAgICAgICAgICAgImVuZG9yc2VtZW50Q29tbWVudCI6ICIxRWRUZWNoIFVuaXZlcnNpdHkgaXMgaW4gZ29vZCBzdGFuZGluZyIKICAgICAgICAgICAgfSwKICAgICAgICAgICAgImNyZWRlbnRpYWxTY2hlbWEiOiBbCiAgICAgICAgICAgICAgewogICAgICAgICAgICAgICAgImlkIjogImh0dHBzOi8vcHVybC5pbXNnbG9iYWwub3JnL3NwZWMvb2IvdjNwMC9zY2hlbWEvanNvbi9vYl92M3AwX2VuZG9yc2VtZW50Y3JlZGVudGlhbF9zY2hlbWEuanNvbiIsCiAgICAgICAgICAgICAgICAidHlwZSI6ICIxRWRUZWNoSnNvblNjaGVtYVZhbGlkYXRvcjIwMTkiCiAgICAgICAgICAgICAgfSwKICAgICAgICAgICAgICB7CiAgICAgICAgICAgICAgICAiaWQiOiAiaHR0cHM6Ly9hY2NyZWRpdGVyLmVkdS9zY2hlbWEvZW5kb3JzZW1lbnRjcmVkZW50aWFsLmpzb24iLAogICAgICAgICAgICAgICAgInR5cGUiOiAiMUVkVGVjaEpzb25TY2hlbWFWYWxpZGF0b3IyMDE5IgogICAgICAgICAgICAgIH0KICAgICAgICAgICAgXSwKICAgICAgICAgICAgImNyZWRlbnRpYWxTdGF0dXMiOiB7CiAgICAgICAgICAgICAgImlkIjogImh0dHBzOi8vMWVkdGVjaC5lZHUvY3JlZGVudGlhbHMvMzczMi9yZXZvY2F0aW9ucyIsCiAgICAgICAgICAgICAgInR5cGUiOiAiMUVkVGVjaFJldm9jYXRpb25MaXN0IgogICAgICAgICAgICB9LAogICAgICAgICAgICAicmVmcmVzaFNlcnZpY2UiOiB7CiAgICAgICAgICAgICAgImlkIjogImh0dHA6Ly8xZWR0ZWNoLmVkdS9jcmVkZW50aWFscy8zNzMyIiwKICAgICAgICAgICAgICAidHlwZSI6ICIxRWRUZWNoQ3JlZGVudGlhbFJlZnJlc2giCiAgICAgICAgICAgIH0sCiAgICAgICAgICAgICJwcm9vZiI6IFsKICAgICAgICAgICAgICB7CiAgICAgICAgICAgICAgICAidHlwZSI6ICJEYXRhSW50ZWdyaXR5UHJvb2YiLAogICAgICAgICAgICAgICAgImNyeXB0b3N1aXRlIjogImVkZHNhLXJkZi0yMDIyIiwKICAgICAgICAgICAgICAgICJjcmVhdGVkIjogIjIwMjItMDUtMjZUMTg6MTc6MDhaIiwKICAgICAgICAgICAgICAgICJ2ZXJpZmljYXRpb25NZXRob2QiOiAiaHR0cHM6Ly9hY2NyZWRpdGVyLmVkdS9pc3N1ZXJzLzU2NTA0OSN6dlBrUWlVRmZKcmduQ1JoeVBrVFNrZ3JHWGJuTFIxNXBISDVIWlZZTmRNNFRDQXdRSHFHN2ZNZU1QTHRZTlJuRWdvVjFhSmRSNUU2MWVXdTVzV1JZZ3RBIiwKICAgICAgICAgICAgICAgICJwcm9vZlB1cnBvc2UiOiAiYXNzZXJ0aW9uTWV0aG9kIiwKICAgICAgICAgICAgICAgICJwcm9vZlZhbHVlIjogInp2UGtRaVVGZkpyZ25DUmh5UGtUU2tnckdYYm5MUjE1cEhINUhaVllOZE00VENBd1FIcUc3Zk1lTVBMdFlOUm5FZ29WMWFKZFI1RTYxZVd1NXNXUllndEEiCiAgICAgICAgICAgICAgfQogICAgICAgICAgICBdCiAgICAgICAgICB9CiAgICAgICAgXSwKICAgICAgICAiZmllbGRPZlN0dWR5IjogIlJlc2VhcmNoIiwKICAgICAgICAiaHVtYW5Db2RlIjogIlIxIiwKICAgICAgICAiaW1hZ2UiOiB7CiAgICAgICAgICAiaWQiOiAiaHR0cHM6Ly9yYXcuZ2l0aHVidXNlcmNvbnRlbnQuY29tL2hhbXJ0L2NyZWRlbnRpYWwtY29udmVydGVyL3JlZnMvaGVhZHMvaW1hZ2UvdGVzdC9lZHViYWRnZXNfMTAweDEwMC5wbmciLAogICAgICAgICAgInR5cGUiOiAiSW1hZ2UiLAogICAgICAgICAgImNhcHRpb24iOiAiMUVkVGVjaCBVbml2ZXJzaXR5IERlZ3JlZSIKICAgICAgICB9LAogICAgICAgICJuYW1lIjogIjFFZFRlY2ggVW5pdmVyc2l0eSBEZWdyZWUiLAogICAgICAgICJvdGhlcklkZW50aWZpZXIiOiBbCiAgICAgICAgICB7CiAgICAgICAgICAgICJ0eXBlIjogIklkZW50aWZpZXJFbnRyeSIsCiAgICAgICAgICAgICJpZGVudGlmaWVyIjogImFiZGUiLAogICAgICAgICAgICAiaWRlbnRpZmllclR5cGUiOiAiaWRlbnRpZmllciIKICAgICAgICAgIH0KICAgICAgICBdLAogICAgICAgICJyZXN1bHREZXNjcmlwdGlvbiI6IFsKICAgICAgICAgIHsKICAgICAgICAgICAgImlkIjogInVybjp1dWlkOmY2YWIyNGNkLTg2ZTgtNGVhZi1iOGM2LWRlZDc0ZThmZDQxYyIsCiAgICAgICAgICAgICJ0eXBlIjogWwogICAgICAgICAgICAgICJSZXN1bHREZXNjcmlwdGlvbiIKICAgICAgICAgICAgXSwKICAgICAgICAgICAgImFsaWdubWVudCI6IFsKICAgICAgICAgICAgICB7CiAgICAgICAgICAgICAgICAidHlwZSI6IFsKICAgICAgICAgICAgICAgICAgIkFsaWdubWVudCIKICAgICAgICAgICAgICAgIF0sCiAgICAgICAgICAgICAgICAidGFyZ2V0Q29kZSI6ICJwcm9qZWN0IiwKICAgICAgICAgICAgICAgICJ0YXJnZXREZXNjcmlwdGlvbiI6ICJQcm9qZWN0IGRlc2NyaXB0aW9uIiwKICAgICAgICAgICAgICAgICJ0YXJnZXROYW1lIjogIkZpbmFsIFByb2plY3QiLAogICAgICAgICAgICAgICAgInRhcmdldEZyYW1ld29yayI6ICIxRWRUZWNoIFVuaXZlcnNpdHkgUHJvZ3JhbSBhbmQgQ291cnNlIENhdGFsb2ciLAogICAgICAgICAgICAgICAgInRhcmdldFR5cGUiOiAiQ0ZJdGVtIiwKICAgICAgICAgICAgICAgICJ0YXJnZXRVcmwiOiAiaHR0cHM6Ly8xZWR0ZWNoLmVkdS9jYXRhbG9nL2RlZ3JlZS9wcm9qZWN0IgogICAgICAgICAgICAgIH0KICAgICAgICAgICAgXSwKICAgICAgICAgICAgImFsbG93ZWRWYWx1ZSI6IFsKICAgICAgICAgICAgICAiRCIsCiAgICAgICAgICAgICAgIkMiLAogICAgICAgICAgICAgICJCIiwKICAgICAgICAgICAgICAiQSIKICAgICAgICAgICAgXSwKICAgICAgICAgICAgIm5hbWUiOiAiRmluYWwgUHJvamVjdCBHcmFkZSIsCiAgICAgICAgICAgICJyZXF1aXJlZFZhbHVlIjogIkMiLAogICAgICAgICAgICAicmVzdWx0VHlwZSI6ICJMZXR0ZXJHcmFkZSIKICAgICAgICAgIH0sCiAgICAgICAgICB7CiAgICAgICAgICAgICJpZCI6ICJ1cm46dXVpZDphNzBkZGM2YS00YzRhLTRiZDgtODI3Ny1jYjk3Yzc5ZjQwYzUiLAogICAgICAgICAgICAidHlwZSI6IFsKICAgICAgICAgICAgICAiUmVzdWx0RGVzY3JpcHRpb24iCiAgICAgICAgICAgIF0sCiAgICAgICAgICAgICJhbGlnbm1lbnQiOiBbCiAgICAgICAgICAgICAgewogICAgICAgICAgICAgICAgInR5cGUiOiBbCiAgICAgICAgICAgICAgICAgICJBbGlnbm1lbnQiCiAgICAgICAgICAgICAgICBdLAogICAgICAgICAgICAgICAgInRhcmdldENvZGUiOiAicHJvamVjdCIsCiAgICAgICAgICAgICAgICAidGFyZ2V0RGVzY3JpcHRpb24iOiAiUHJvamVjdCBkZXNjcmlwdGlvbiIsCiAgICAgICAgICAgICAgICAidGFyZ2V0TmFtZSI6ICJGaW5hbCBQcm9qZWN0IiwKICAgICAgICAgICAgICAgICJ0YXJnZXRGcmFtZXdvcmsiOiAiMUVkVGVjaCBVbml2ZXJzaXR5IFByb2dyYW0gYW5kIENvdXJzZSBDYXRhbG9nIiwKICAgICAgICAgICAgICAgICJ0YXJnZXRUeXBlIjogIkNGSXRlbSIsCiAgICAgICAgICAgICAgICAidGFyZ2V0VXJsIjogImh0dHBzOi8vMWVkdGVjaC5lZHUvY2F0YWxvZy9kZWdyZWUvcHJvamVjdCIKICAgICAgICAgICAgICB9CiAgICAgICAgICAgIF0sCiAgICAgICAgICAgICJhbGxvd2VkVmFsdWUiOiBbCiAgICAgICAgICAgICAgIkQiLAogICAgICAgICAgICAgICJDIiwKICAgICAgICAgICAgICAiQiIsCiAgICAgICAgICAgICAgIkEiCiAgICAgICAgICAgIF0sCiAgICAgICAgICAgICJuYW1lIjogIkZpbmFsIFByb2plY3QgR3JhZGUiLAogICAgICAgICAgICAicmVxdWlyZWRMZXZlbCI6ICJ1cm46dXVpZDpkMDVhMDg2Ny1kMGFkLTRiMDMtYmRiNS0yOGZiNWQyYWFiN2EiLAogICAgICAgICAgICAicmVzdWx0VHlwZSI6ICJSdWJyaWNDcml0ZXJpb25MZXZlbCIsCiAgICAgICAgICAgICJydWJyaWNDcml0ZXJpb25MZXZlbCI6IFsKICAgICAgICAgICAgICB7CiAgICAgICAgICAgICAgICAiaWQiOiAidXJuOnV1aWQ6ZDA1YTA4NjctZDBhZC00YjAzLWJkYjUtMjhmYjVkMmFhYjdhIiwKICAgICAgICAgICAgICAgICJ0eXBlIjogWwogICAgICAgICAgICAgICAgICAiUnVicmljQ3JpdGVyaW9uTGV2ZWwiCiAgICAgICAgICAgICAgICBdLAogICAgICAgICAgICAgICAgImFsaWdubWVudCI6IFsKICAgICAgICAgICAgICAgICAgewogICAgICAgICAgICAgICAgICAgICJ0eXBlIjogWwogICAgICAgICAgICAgICAgICAgICAgIkFsaWdubWVudCIKICAgICAgICAgICAgICAgICAgICBdLAogICAgICAgICAgICAgICAgICAgICJ0YXJnZXRDb2RlIjogInByb2plY3QiLAogICAgICAgICAgICAgICAgICAgICJ0YXJnZXREZXNjcmlwdGlvbiI6ICJQcm9qZWN0IGRlc2NyaXB0aW9uIiwKICAgICAgICAgICAgICAgICAgICAidGFyZ2V0TmFtZSI6ICJGaW5hbCBQcm9qZWN0IiwKICAgICAgICAgICAgICAgICAgICAidGFyZ2V0RnJhbWV3b3JrIjogIjFFZFRlY2ggVW5pdmVyc2l0eSBQcm9ncmFtIGFuZCBDb3Vyc2UgQ2F0YWxvZyIsCiAgICAgICAgICAgICAgICAgICAgInRhcmdldFR5cGUiOiAiQ0ZSdWJyaWNDcml0ZXJpb25MZXZlbCIsCiAgICAgICAgICAgICAgICAgICAgInRhcmdldFVybCI6ICJodHRwczovLzFlZHRlY2guZWR1L2NhdGFsb2cvZGVncmVlL3Byb2plY3QvcnVicmljL2xldmVscy9tYXN0ZXJlZCIKICAgICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgXSwKICAgICAgICAgICAgICAgICJkZXNjcmlwdGlvbiI6ICJUaGUgYXV0aG9yIGRlbW9uc3RyYXRlZC4uLiIsCiAgICAgICAgICAgICAgICAibGV2ZWwiOiAiTWFzdGVyZWQiLAogICAgICAgICAgICAgICAgIm5hbWUiOiAiTWFzdGVyeSIsCiAgICAgICAgICAgICAgICAicG9pbnRzIjogIjQiCiAgICAgICAgICAgICAgfSwKICAgICAgICAgICAgICB7CiAgICAgICAgICAgICAgICAiaWQiOiAidXJuOnV1aWQ6NmI4NGI0MjktMzFlZS00ZGFjLTlkMjAtZTVjNTU4ODFmODBlIiwKICAgICAgICAgICAgICAgICJ0eXBlIjogWwogICAgICAgICAgICAgICAgICAiUnVicmljQ3JpdGVyaW9uTGV2ZWwiCiAgICAgICAgICAgICAgICBdLAogICAgICAgICAgICAgICAgImFsaWdubWVudCI6IFsKICAgICAgICAgICAgICAgICAgewogICAgICAgICAgICAgICAgICAgICJ0eXBlIjogWwogICAgICAgICAgICAgICAgICAgICAgIkFsaWdubWVudCIKICAgICAgICAgICAgICAgICAgICBdLAogICAgICAgICAgICAgICAgICAgICJ0YXJnZXRDb2RlIjogInByb2plY3QiLAogICAgICAgICAgICAgICAgICAgICJ0YXJnZXREZXNjcmlwdGlvbiI6ICJQcm9qZWN0IGRlc2NyaXB0aW9uIiwKICAgICAgICAgICAgICAgICAgICAidGFyZ2V0TmFtZSI6ICJGaW5hbCBQcm9qZWN0IiwKICAgICAgICAgICAgICAgICAgICAidGFyZ2V0RnJhbWV3b3JrIjogIjFFZFRlY2ggVW5pdmVyc2l0eSBQcm9ncmFtIGFuZCBDb3Vyc2UgQ2F0YWxvZyIsCiAgICAgICAgICAgICAgICAgICAgInRhcmdldFR5cGUiOiAiQ0ZSdWJyaWNDcml0ZXJpb25MZXZlbCIsCiAgICAgICAgICAgICAgICAgICAgInRhcmdldFVybCI6ICJodHRwczovLzFlZHRlY2guZWR1L2NhdGFsb2cvZGVncmVlL3Byb2plY3QvcnVicmljL2xldmVscy9iYXNpYyIKICAgICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgXSwKICAgICAgICAgICAgICAgICJkZXNjcmlwdGlvbiI6ICJUaGUgYXV0aG9yIGRlbW9uc3RyYXRlZC4uLiIsCiAgICAgICAgICAgICAgICAibGV2ZWwiOiAiQmFzaWMiLAogICAgICAgICAgICAgICAgIm5hbWUiOiAiQmFzaWMiLAogICAgICAgICAgICAgICAgInBvaW50cyI6ICI0IgogICAgICAgICAgICAgIH0KICAgICAgICAgICAgXQogICAgICAgICAgfSwKICAgICAgICAgIHsKICAgICAgICAgICAgImlkIjogInVybjp1dWlkOmIwN2MwMzg3LWYyZDYtNGI2NS1hM2Y0LWY0ZTQzMDJlYThmNyIsCiAgICAgICAgICAgICJ0eXBlIjogWwogICAgICAgICAgICAgICJSZXN1bHREZXNjcmlwdGlvbiIKICAgICAgICAgICAgXSwKICAgICAgICAgICAgIm5hbWUiOiAiUHJvamVjdCBTdGF0dXMiLAogICAgICAgICAgICAicmVzdWx0VHlwZSI6ICJTdGF0dXMiCiAgICAgICAgICB9CiAgICAgICAgXSwKICAgICAgICAic3BlY2lhbGl6YXRpb24iOiAiQ29tcHV0ZXIgU2NpZW5jZSBSZXNlYXJjaCIsCiAgICAgICAgInRhZyI6IFsKICAgICAgICAgICJyZXNlYXJjaCIsCiAgICAgICAgICAiY29tcHV0ZXIgc2NpZW5jZSIKICAgICAgICBdCiAgICAgIH0sCiAgICAgICJpbWFnZSI6IHsKICAgICAgICAiaWQiOiAiaHR0cHM6Ly8xZWR0ZWNoLmVkdS9jcmVkZW50aWFscy8zNzMyL2ltYWdlIiwKICAgICAgICAidHlwZSI6ICJJbWFnZSIsCiAgICAgICAgImNhcHRpb24iOiAiMUVkVGVjaCBVbml2ZXJzaXR5IERlZ3JlZSBmb3IgRXhhbXBsZSBTdHVkZW50IgogICAgICB9LAogICAgICAibmFycmF0aXZlIjogIlRoZXJlIGlzIGEgZmluYWwgcHJvamVjdCByZXBvcnQgYW5kIHNvdXJjZSBjb2RlIGV2aWRlbmNlLiIsCiAgICAgICJyZXN1bHQiOiBbCiAgICAgICAgewogICAgICAgICAgInR5cGUiOiBbCiAgICAgICAgICAgICJSZXN1bHQiCiAgICAgICAgICBdLAogICAgICAgICAgImFsaWdubWVudCI6IFsKICAgICAgICAgICAgewogICAgICAgICAgICAgICJ0eXBlIjogWwogICAgICAgICAgICAgICAgIkFsaWdubWVudCIKICAgICAgICAgICAgICBdLAogICAgICAgICAgICAgICJ0YXJnZXRDb2RlIjogInByb2plY3QiLAogICAgICAgICAgICAgICJ0YXJnZXREZXNjcmlwdGlvbiI6ICJQcm9qZWN0IGRlc2NyaXB0aW9uIiwKICAgICAgICAgICAgICAidGFyZ2V0TmFtZSI6ICJGaW5hbCBQcm9qZWN0IiwKICAgICAgICAgICAgICAidGFyZ2V0RnJhbWV3b3JrIjogIjFFZFRlY2ggVW5pdmVyc2l0eSBQcm9ncmFtIGFuZCBDb3Vyc2UgQ2F0YWxvZyIsCiAgICAgICAgICAgICAgInRhcmdldFR5cGUiOiAiQ0ZJdGVtIiwKICAgICAgICAgICAgICAidGFyZ2V0VXJsIjogImh0dHBzOi8vMWVkdGVjaC5lZHUvY2F0YWxvZy9kZWdyZWUvcHJvamVjdC9yZXN1bHQvMSIKICAgICAgICAgICAgfQogICAgICAgICAgXSwKICAgICAgICAgICJyZXN1bHREZXNjcmlwdGlvbiI6ICJ1cm46dXVpZDpmNmFiMjRjZC04NmU4LTRlYWYtYjhjNi1kZWQ3NGU4ZmQ0MWMiLAogICAgICAgICAgInZhbHVlIjogIkEiCiAgICAgICAgfSwKICAgICAgICB7CiAgICAgICAgICAidHlwZSI6IFsKICAgICAgICAgICAgIlJlc3VsdCIKICAgICAgICAgIF0sCiAgICAgICAgICAiYWNoaWV2ZWRMZXZlbCI6ICJ1cm46dXVpZDpkMDVhMDg2Ny1kMGFkLTRiMDMtYmRiNS0yOGZiNWQyYWFiN2EiLAogICAgICAgICAgImFsaWdubWVudCI6IFsKICAgICAgICAgICAgewogICAgICAgICAgICAgICJ0eXBlIjogWwogICAgICAgICAgICAgICAgIkFsaWdubWVudCIKICAgICAgICAgICAgICBdLAogICAgICAgICAgICAgICJ0YXJnZXRDb2RlIjogInByb2plY3QiLAogICAgICAgICAgICAgICJ0YXJnZXREZXNjcmlwdGlvbiI6ICJQcm9qZWN0IGRlc2NyaXB0aW9uIiwKICAgICAgICAgICAgICAidGFyZ2V0TmFtZSI6ICJGaW5hbCBQcm9qZWN0IiwKICAgICAgICAgICAgICAidGFyZ2V0RnJhbWV3b3JrIjogIjFFZFRlY2ggVW5pdmVyc2l0eSBQcm9ncmFtIGFuZCBDb3Vyc2UgQ2F0YWxvZyIsCiAgICAgICAgICAgICAgInRhcmdldFR5cGUiOiAiQ0ZJdGVtIiwKICAgICAgICAgICAgICAidGFyZ2V0VXJsIjogImh0dHBzOi8vMWVkdGVjaC5lZHUvY2F0YWxvZy9kZWdyZWUvcHJvamVjdC9yZXN1bHQvMSIKICAgICAgICAgICAgfQogICAgICAgICAgXSwKICAgICAgICAgICJyZXN1bHREZXNjcmlwdGlvbiI6ICJ1cm46dXVpZDpmNmFiMjRjZC04NmU4LTRlYWYtYjhjNi1kZWQ3NGU4ZmQ0MWMiCiAgICAgICAgfSwKICAgICAgICB7CiAgICAgICAgICAidHlwZSI6IFsKICAgICAgICAgICAgIlJlc3VsdCIKICAgICAgICAgIF0sCiAgICAgICAgICAicmVzdWx0RGVzY3JpcHRpb24iOiAidXJuOnV1aWQ6ZjZhYjI0Y2QtODZlOC00ZWFmLWI4YzYtZGVkNzRlOGZkNDFjIiwKICAgICAgICAgICJzdGF0dXMiOiAiQ29tcGxldGVkIgogICAgICAgIH0KICAgICAgXQogICAgfSwKICAgICJlbmRvcnNlbWVudCI6IFsKICAgICAgewogICAgICAgICJAY29udGV4dCI6IFsKICAgICAgICAgICJodHRwczovL3d3dy53My5vcmcvbnMvY3JlZGVudGlhbHMvdjIiLAogICAgICAgICAgImh0dHBzOi8vcHVybC5pbXNnbG9iYWwub3JnL3NwZWMvb2IvdjNwMC9jb250ZXh0LTMuMC4zLmpzb24iCiAgICAgICAgXSwKICAgICAgICAiaWQiOiAiaHR0cDovLzFlZHRlY2guZWR1L2VuZG9yc2VtZW50Y3JlZGVudGlhbC8zNzM1IiwKICAgICAgICAidHlwZSI6IFsKICAgICAgICAgICJWZXJpZmlhYmxlQ3JlZGVudGlhbCIsCiAgICAgICAgICAiRW5kb3JzZW1lbnRDcmVkZW50aWFsIgogICAgICAgIF0sCiAgICAgICAgIm5hbWUiOiAiRUFBIGVuZG9yc2VtZW50IiwKICAgICAgICAiaXNzdWVyIjogewogICAgICAgICAgImlkIjogImh0dHBzOi8vYWNjcmVkaXRlci5lZHUvaXNzdWVycy81NjUwNDkiLAogICAgICAgICAgInR5cGUiOiBbCiAgICAgICAgICAgICJQcm9maWxlIgogICAgICAgICAgXSwKICAgICAgICAgICJuYW1lIjogIkV4YW1wbGUgQWNjcmVkaXRpbmcgQWdlbmN5IgogICAgICAgIH0sCiAgICAgICAgInZhbGlkRnJvbSI6ICIyMDEwLTAxLTAxVDAwOjAwOjAwWiIsCiAgICAgICAgInZhbGlkVW50aWwiOiAiMjAyMC0wMS0wMVQwMDowMDowMFoiLAogICAgICAgICJjcmVkZW50aWFsU3ViamVjdCI6IHsKICAgICAgICAgICJpZCI6ICJodHRwczovLzFlZHRlY2guZWR1L2lzc3VlcnMvNTY1MDQ5IiwKICAgICAgICAgICJ0eXBlIjogWwogICAgICAgICAgICAiRW5kb3JzZW1lbnRTdWJqZWN0IgogICAgICAgICAgXSwKICAgICAgICAgICJlbmRvcnNlbWVudENvbW1lbnQiOiAiMUVkVGVjaCBVbml2ZXJzaXR5IGlzIGluIGdvb2Qgc3RhbmRpbmciCiAgICAgICAgfSwKICAgICAgICAiY3JlZGVudGlhbFNjaGVtYSI6IFsKICAgICAgICAgIHsKICAgICAgICAgICAgImlkIjogImh0dHBzOi8vcHVybC5pbXNnbG9iYWwub3JnL3NwZWMvb2IvdjNwMC9zY2hlbWEvanNvbi9vYl92M3AwX2VuZG9yc2VtZW50Y3JlZGVudGlhbF9zY2hlbWEuanNvbiIsCiAgICAgICAgICAgICJ0eXBlIjogIjFFZFRlY2hKc29uU2NoZW1hVmFsaWRhdG9yMjAxOSIKICAgICAgICAgIH0sCiAgICAgICAgICB7CiAgICAgICAgICAgICJpZCI6ICJodHRwczovL2FjY3JlZGl0ZXIuZWR1L3NjaGVtYS9lbmRvcnNlbWVudGNyZWRlbnRpYWwuanNvbiIsCiAgICAgICAgICAgICJ0eXBlIjogIjFFZFRlY2hKc29uU2NoZW1hVmFsaWRhdG9yMjAxOSIKICAgICAgICAgIH0KICAgICAgICBdLAogICAgICAgICJjcmVkZW50aWFsU3RhdHVzIjogewogICAgICAgICAgImlkIjogImh0dHBzOi8vMWVkdGVjaC5lZHUvY3JlZGVudGlhbHMvMzczMi9yZXZvY2F0aW9ucyIsCiAgICAgICAgICAidHlwZSI6ICIxRWRUZWNoUmV2b2NhdGlvbkxpc3QiCiAgICAgICAgfSwKICAgICAgICAicmVmcmVzaFNlcnZpY2UiOiB7CiAgICAgICAgICAiaWQiOiAiaHR0cDovLzFlZHRlY2guZWR1L2NyZWRlbnRpYWxzLzM3MzIiLAogICAgICAgICAgInR5cGUiOiAiMUVkVGVjaENyZWRlbnRpYWxSZWZyZXNoIgogICAgICAgIH0sCiAgICAgICAgInByb29mIjogWwogICAgICAgICAgewogICAgICAgICAgICAidHlwZSI6ICJEYXRhSW50ZWdyaXR5UHJvb2YiLAogICAgICAgICAgICAiY3J5cHRvc3VpdGUiOiAiZWRkc2EtcmRmLTIwMjIiLAogICAgICAgICAgICAiY3JlYXRlZCI6ICIyMDIyLTA1LTI2VDE4OjE3OjA4WiIsCiAgICAgICAgICAgICJ2ZXJpZmljYXRpb25NZXRob2QiOiAiaHR0cHM6Ly9hY2NyZWRpdGVyLmVkdS9pc3N1ZXJzLzU2NTA0OSN6dlBrUWlVRmZKcmduQ1JoeVBrVFNrZ3JHWGJuTFIxNXBISDVIWlZZTmRNNFRDQXdRSHFHN2ZNZU1QTHRZTlJuRWdvVjFhSmRSNUU2MWVXdTVzV1JZZ3RBIiwKICAgICAgICAgICAgInByb29mUHVycG9zZSI6ICJhc3NlcnRpb25NZXRob2QiLAogICAgICAgICAgICAicHJvb2ZWYWx1ZSI6ICJ6dlBrUWlVRmZKcmduQ1JoeVBrVFNrZ3JHWGJuTFIxNXBISDVIWlZZTmRNNFRDQXdRSHFHN2ZNZU1QTHRZTlJuRWdvVjFhSmRSNUU2MWVXdTVzV1JZZ3RBIgogICAgICAgICAgfQogICAgICAgIF0KICAgICAgfQogICAgXSwKICAgICJldmlkZW5jZSI6IFsKICAgICAgewogICAgICAgICJpZCI6ICJodHRwczovLzFlZHRlY2guZWR1L2NyZWRlbnRpYWxzLzM3MzIvZXZpZGVuY2UvMSIsCiAgICAgICAgInR5cGUiOiBbCiAgICAgICAgICAiRXZpZGVuY2UiCiAgICAgICAgXSwKICAgICAgICAibmFycmF0aXZlIjogIiMgRmluYWwgUHJvamVjdCBSZXBvcnQgXG4gVGhpcyBwcm9qZWN0IHdhcyAuLi4iLAogICAgICAgICJuYW1lIjogIkZpbmFsIFByb2plY3QgUmVwb3J0IiwKICAgICAgICAiZGVzY3JpcHRpb24iOiAiVGhpcyBpcyB0aGUgZmluYWwgcHJvamVjdCByZXBvcnQuIiwKICAgICAgICAiZ2VucmUiOiAiUmVzZWFyY2giLAogICAgICAgICJhdWRpZW5jZSI6ICJEZXBhcnRtZW50IgogICAgICB9LAogICAgICB7CiAgICAgICAgImlkIjogImh0dHBzOi8vZ2l0aHViLmNvbS9zb21lYm9keS9wcm9qZWN0IiwKICAgICAgICAidHlwZSI6IFsKICAgICAgICAgICJFdmlkZW5jZSIKICAgICAgICBdLAogICAgICAgICJuYW1lIjogIkZpbmFsIFByb2plY3QgQ29kZSIsCiAgICAgICAgImRlc2NyaXB0aW9uIjogIlRoaXMgaXMgdGhlIHNvdXJjZSBjb2RlIGZvciB0aGUgZmluYWwgcHJvamVjdCBhcHAuIiwKICAgICAgICAiZ2VucmUiOiAiUmVzZWFyY2giLAogICAgICAgICJhdWRpZW5jZSI6ICJEZXBhcnRtZW50IgogICAgICB9CiAgICBdLAogICAgImlzc3VlciI6IHsKICAgICAgImlkIjogImh0dHBzOi8vMWVkdGVjaC5lZHUvaXNzdWVycy81NjUwNDkiLAogICAgICAidHlwZSI6IFsKICAgICAgICAiUHJvZmlsZSIKICAgICAgXSwKICAgICAgIm5hbWUiOiAiMUVkVGVjaCBVbml2ZXJzaXR5IiwKICAgICAgInVybCI6ICJodHRwczovLzFlZHRlY2guZWR1IiwKICAgICAgInBob25lIjogIjEtMjIyLTMzMy00NDQ0IiwKICAgICAgImRlc2NyaXB0aW9uIjogIjFFZFRlY2ggVW5pdmVyc2l0eSBwcm92aWRlcyBvbmxpbmUgZGVncmVlIHByb2dyYW1zLiIsCiAgICAgICJlbmRvcnNlbWVudCI6IFsKICAgICAgICB7CiAgICAgICAgICAiQGNvbnRleHQiOiBbCiAgICAgICAgICAgICJodHRwczovL3d3dy53My5vcmcvbnMvY3JlZGVudGlhbHMvdjIiLAogICAgICAgICAgICAiaHR0cHM6Ly9wdXJsLmltc2dsb2JhbC5vcmcvc3BlYy9vYi92M3AwL2NvbnRleHQtMy4wLjMuanNvbiIKICAgICAgICAgIF0sCiAgICAgICAgICAiaWQiOiAiaHR0cDovLzFlZHRlY2guZWR1L2VuZG9yc2VtZW50Y3JlZGVudGlhbC8zNzM2IiwKICAgICAgICAgICJ0eXBlIjogWwogICAgICAgICAgICAiVmVyaWZpYWJsZUNyZWRlbnRpYWwiLAogICAgICAgICAgICAiRW5kb3JzZW1lbnRDcmVkZW50aWFsIgogICAgICAgICAgXSwKICAgICAgICAgICJuYW1lIjogIkVBQSBlbmRvcnNlbWVudCIsCiAgICAgICAgICAiaXNzdWVyIjogewogICAgICAgICAgICAiaWQiOiAiaHR0cHM6Ly9hY2NyZWRpdGVyLmVkdS9pc3N1ZXJzLzU2NTA0OSIsCiAgICAgICAgICAgICJ0eXBlIjogWwogICAgICAgICAgICAgICJQcm9maWxlIgogICAgICAgICAgICBdLAogICAgICAgICAgICAibmFtZSI6ICJFeGFtcGxlIEFjY3JlZGl0aW5nIEFnZW5jeSIKICAgICAgICAgIH0sCiAgICAgICAgICAidmFsaWRGcm9tIjogIjIwMTAtMDEtMDFUMDA6MDA6MDBaIiwKICAgICAgICAgICJ2YWxpZFVudGlsIjogIjIwMjAtMDEtMDFUMDA6MDA6MDBaIiwKICAgICAgICAgICJjcmVkZW50aWFsU3ViamVjdCI6IHsKICAgICAgICAgICAgImlkIjogImh0dHBzOi8vMWVkdGVjaC5lZHUvaXNzdWVycy81NjUwNDkiLAogICAgICAgICAgICAidHlwZSI6IFsKICAgICAgICAgICAgICAiRW5kb3JzZW1lbnRTdWJqZWN0IgogICAgICAgICAgICBdLAogICAgICAgICAgICAiZW5kb3JzZW1lbnRDb21tZW50IjogIjFFZFRlY2ggVW5pdmVyc2l0eSBpcyBpbiBnb29kIHN0YW5kaW5nIgogICAgICAgICAgfSwKICAgICAgICAgICJjcmVkZW50aWFsU2NoZW1hIjogWwogICAgICAgICAgICB7CiAgICAgICAgICAgICAgImlkIjogImh0dHBzOi8vcHVybC5pbXNnbG9iYWwub3JnL3NwZWMvb2IvdjNwMC9zY2hlbWEvanNvbi9vYl92M3AwX2VuZG9yc2VtZW50Y3JlZGVudGlhbF9zY2hlbWEuanNvbiIsCiAgICAgICAgICAgICAgInR5cGUiOiAiMUVkVGVjaEpzb25TY2hlbWFWYWxpZGF0b3IyMDE5IgogICAgICAgICAgICB9LAogICAgICAgICAgICB7CiAgICAgICAgICAgICAgImlkIjogImh0dHBzOi8vYWNjcmVkaXRlci5lZHUvc2NoZW1hL2VuZG9yc2VtZW50Y3JlZGVudGlhbC5qc29uIiwKICAgICAgICAgICAgICAidHlwZSI6ICIxRWRUZWNoSnNvblNjaGVtYVZhbGlkYXRvcjIwMTkiCiAgICAgICAgICAgIH0KICAgICAgICAgIF0sCiAgICAgICAgICAiY3JlZGVudGlhbFN0YXR1cyI6IHsKICAgICAgICAgICAgImlkIjogImh0dHBzOi8vMWVkdGVjaC5lZHUvY3JlZGVudGlhbHMvMzczMi9yZXZvY2F0aW9ucyIsCiAgICAgICAgICAgICJ0eXBlIjogIjFFZFRlY2hSZXZvY2F0aW9uTGlzdCIKICAgICAgICAgIH0sCiAgICAgICAgICAicmVmcmVzaFNlcnZpY2UiOiB7CiAgICAgICAgICAgICJpZCI6ICJodHRwOi8vMWVkdGVjaC5lZHUvY3JlZGVudGlhbHMvMzczMiIsCiAgICAgICAgICAgICJ0eXBlIjogIjFFZFRlY2hDcmVkZW50aWFsUmVmcmVzaCIKICAgICAgICAgIH0sCiAgICAgICAgICAicHJvb2YiOiBbCiAgICAgICAgICAgIHsKICAgICAgICAgICAgICAidHlwZSI6ICJEYXRhSW50ZWdyaXR5UHJvb2YiLAogICAgICAgICAgICAgICJjcnlwdG9zdWl0ZSI6ICJlZGRzYS1yZGYtMjAyMiIsCiAgICAgICAgICAgICAgImNyZWF0ZWQiOiAiMjAyMi0wNS0yNlQxODoxNzowOFoiLAogICAgICAgICAgICAgICJ2ZXJpZmljYXRpb25NZXRob2QiOiAiaHR0cHM6Ly9hY2NyZWRpdGVyLmVkdS9pc3N1ZXJzLzU2NTA0OSN6dlBrUWlVRmZKcmduQ1JoeVBrVFNrZ3JHWGJuTFIxNXBISDVIWlZZTmRNNFRDQXdRSHFHN2ZNZU1QTHRZTlJuRWdvVjFhSmRSNUU2MWVXdTVzV1JZZ3RBIiwKICAgICAgICAgICAgICAicHJvb2ZQdXJwb3NlIjogImFzc2VydGlvbk1ldGhvZCIsCiAgICAgICAgICAgICAgInByb29mVmFsdWUiOiAienZQa1FpVUZmSnJnbkNSaHlQa1RTa2dyR1hibkxSMTVwSEg1SFpWWU5kTTRUQ0F3UUhxRzdmTWVNUEx0WU5SbkVnb1YxYUpkUjVFNjFlV3U1c1dSWWd0QSIKICAgICAgICAgICAgfQogICAgICAgICAgXQogICAgICAgIH0KICAgICAgXSwKICAgICAgImltYWdlIjogewogICAgICAgICJpZCI6ICJodHRwczovL3Jhdy5naXRodWJ1c2VyY29udGVudC5jb20vaGFtcnQvY3JlZGVudGlhbC1jb252ZXJ0ZXIvcmVmcy9oZWFkcy9pbWFnZS90ZXN0L2VkdWJhZGdlc18xMDB4MTAwLnBuZyIsCiAgICAgICAgInR5cGUiOiAiSW1hZ2UiLAogICAgICAgICJjYXB0aW9uIjogIjFFZFRlY2ggVW5pdmVyc2l0eSBsb2dvIgogICAgICB9LAogICAgICAiZW1haWwiOiAicmVnaXN0cmFyQDFlZHRlY2guZWR1IiwKICAgICAgImFkZHJlc3MiOiB7CiAgICAgICAgInR5cGUiOiBbCiAgICAgICAgICAiQWRkcmVzcyIKICAgICAgICBdLAogICAgICAgICJhZGRyZXNzQ291bnRyeSI6ICJVU0EiLAogICAgICAgICJhZGRyZXNzQ291bnRyeUNvZGUiOiAiVVMiLAogICAgICAgICJhZGRyZXNzUmVnaW9uIjogIlRYIiwKICAgICAgICAiYWRkcmVzc0xvY2FsaXR5IjogIkF1c3RpbiIsCiAgICAgICAgInN0cmVldEFkZHJlc3MiOiAiMTIzIEZpcnN0IFN0IiwKICAgICAgICAicG9zdE9mZmljZUJveE51bWJlciI6ICIxIiwKICAgICAgICAicG9zdGFsQ29kZSI6ICIxMjM0NSIsCiAgICAgICAgImdlbyI6IHsKICAgICAgICAgICJ0eXBlIjogIkdlb0Nvb3JkaW5hdGVzIiwKICAgICAgICAgICJsYXRpdHVkZSI6IDEsCiAgICAgICAgICAibG9uZ2l0dWRlIjogMQogICAgICAgIH0KICAgICAgfSwKICAgICAgIm90aGVySWRlbnRpZmllciI6IFsKICAgICAgICB7CiAgICAgICAgICAidHlwZSI6ICJJZGVudGlmaWVyRW50cnkiLAogICAgICAgICAgImlkZW50aWZpZXIiOiAiMTIzNDUiLAogICAgICAgICAgImlkZW50aWZpZXJUeXBlIjogInNvdXJjZWRJZCIKICAgICAgICB9LAogICAgICAgIHsKICAgICAgICAgICJ0eXBlIjogIklkZW50aWZpZXJFbnRyeSIsCiAgICAgICAgICAiaWRlbnRpZmllciI6ICI2Nzg5MCIsCiAgICAgICAgICAiaWRlbnRpZmllclR5cGUiOiAibmF0aW9uYWxJZGVudGl0eU51bWJlciIKICAgICAgICB9CiAgICAgIF0sCiAgICAgICJvZmZpY2lhbCI6ICJIb3JhY2UgTWFubiIsCiAgICAgICJwYXJlbnRPcmciOiB7CiAgICAgICAgImlkIjogImRpZDpleGFtcGxlOjEyMzQ1Njc4OSIsCiAgICAgICAgInR5cGUiOiBbCiAgICAgICAgICAiUHJvZmlsZSIKICAgICAgICBdLAogICAgICAgICJuYW1lIjogIlVuaXZlcnNhbCBVbml2ZXJzaXRpZXMiCiAgICAgIH0KICAgIH0sCiAgICAidmFsaWRGcm9tIjogIjIwMTAtMDEtMDFUMDA6MDA6MDBaIiwKICAgICJ2YWxpZFVudGlsIjogIjIwMzAtMDEtMDFUMDA6MDA6MDBaIiwKICAgICJjcmVkZW50aWFsU2NoZW1hIjogWwogICAgICB7CiAgICAgICAgImlkIjogImh0dHBzOi8vcHVybC5pbXNnbG9iYWwub3JnL3NwZWMvb2IvdjNwMC9zY2hlbWEvanNvbi9vYl92M3AwX2FjaGlldmVtZW50Y3JlZGVudGlhbF9zY2hlbWEuanNvbiIsCiAgICAgICAgInR5cGUiOiAiMUVkVGVjaEpzb25TY2hlbWFWYWxpZGF0b3IyMDE5IgogICAgICB9CiAgICBdLAogICAgImNyZWRlbnRpYWxTdGF0dXMiOiB7CiAgICAgICJpZCI6ICJodHRwczovLzFlZHRlY2guZWR1L2NyZWRlbnRpYWxzLzM3MzIvcmV2b2NhdGlvbnMiLAogICAgICAidHlwZSI6ICIxRWRUZWNoUmV2b2NhdGlvbkxpc3QiCiAgICB9LAogICAgInJlZnJlc2hTZXJ2aWNlIjogewogICAgICAiaWQiOiAiaHR0cDovLzFlZHRlY2guZWR1L2NyZWRlbnRpYWxzLzM3MzIiLAogICAgICAidHlwZSI6ICIxRWRUZWNoQ3JlZGVudGlhbFJlZnJlc2giCiAgICB9LAogICAgInByb29mIjogWwogICAgICB7CiAgICAgICAgInR5cGUiOiAiRGF0YUludGVncml0eVByb29mIiwKICAgICAgICAiY3JlYXRlZCI6ICIyMDI0LTA1LTMxVDE0OjA1OjI1WiIsCiAgICAgICAgInZlcmlmaWNhdGlvbk1ldGhvZCI6ICJodHRwczovLzFlZHRlY2guZWR1L2lzc3VlcnMvNTY1MDQ5I3o2TWtwaFU2UW1vakM2R2RVQk5ZeXBnbkdhaUwyVExpc0xNeHBFMW9aY21LZzdBZCIsCiAgICAgICAgImNyeXB0b3N1aXRlIjogImVkZHNhLXJkZmMtMjAyMiIsCiAgICAgICAgInByb29mUHVycG9zZSI6ICJhc3NlcnRpb25NZXRob2QiLAogICAgICAgICJwcm9vZlZhbHVlIjogIno1QTRaWExKYTRkVUFyVG1wZFA5dm5yWWlqTUxDVDF0UjlLV2FGbUxUMlBlUXAzZ1NuR0E5d3JSSnFySjVaOFlucFZEeFpRV1JHampXTmJqMlBLREplN2R0IgogICAgICB9CiAgICBdCn0K" +} \ No newline at end of file diff --git a/test/university_of_harderwijk_75x100.jpg b/test/university_of_harderwijk_75x100.jpg new file mode 100644 index 0000000..826e998 Binary files /dev/null and b/test/university_of_harderwijk_75x100.jpg differ diff --git a/test/uvh_at_microcredential_full_1.json b/test/uvh_at_microcredential_full_1.json new file mode 100644 index 0000000..d7639b4 --- /dev/null +++ b/test/uvh_at_microcredential_full_1.json @@ -0,0 +1,172 @@ +{ + "@context": [ + "https://www.w3.org/ns/credentials/v2", + "https://purl.imsglobal.org/spec/ob/v3p0/context-3.0.3.json", + "https://raw.githubusercontent.com/educredentials/obv3-examples/refs/heads/main/contexts/educredential.json" + ], + "id": "http://example.com/credentials/crd-A1B2C3", + "type": [ + "VerifiableCredential", + "OpenBadgeCredential" + ], + "issuer": { + "id": "https://example.com/issuers/iss-9Z8Y7X", + "type": [ + "Profile" + ], + "name": "Universiteit van Harderwijk", + "otherIdentifier": [ + { + "type": "IdentifierEntry", + "identifier": "UN1VH", + "identifierType": "ext:BRIN" + }, + { + "type": "IdentifierEntry", + "identifier": "uvh.example.com", + "identifierType": "name" + } + ], + "image": { + "id": "https://raw.githubusercontent.com/hamrt/credential-converter/refs/heads/image/test/university_of_harderwijk_75x100.jpg", + "type": "Image", + "caption": "University of Harderwijk logo" + }, + "address": { + "type": [ + "Address" + ], + "addressCountry": "NDL", + "addressCountryCode": "NL", + "addressRegion": "UT", + "addressLocality": "Harderwijk", + "streetAddress": "123 First St", + "postOfficeBoxNumber": "1", + "postalCode": "12345", + "geo": { + "type": "GeoCoordinates", + "latitude": 1, + "longitude": 1 + } + } + }, + "validFrom": "2024-08-30T00:00:00Z", + "validUntil": "2029-08-30T00:00:00Z", + "credentialSubject": { + "id": "https://example.com/students/stu-7Z6X5W", + "type": [ + "AchievementSubject" + ], + "identifier": [ + { + "type": "IdentityObject", + "identityHash": "student@1edtech.edu", + "identityType": "emailAddress", + "hashed": false, + "salt": "not-used" + } + ], + "achievement": { + "id": "https://example.com/achievements/ach-876543", + "type": [ + "Achievement", + "EducredentialAchievement" + ], + "criteria": { + "narrative": "De student heeft de eerste stap van transmutatie afgerond, waarbij katten zonder blijvende schade worden omgezet in keukenapparatuur." + }, + "description": "De student heeft met succes de eerste stap in transmutatie afgerond, waarbij katten zonder blijvende schade worden omgezet in keukenapparatuur.", + "name": "Microcredential Basisomzetting Kat naar Koffiezetapparaat", + "image": { + "id": "https://raw.githubusercontent.com/hamrt/credential-converter/refs/heads/image/test/edubadges_100x100.png", + "type": "Image" + }, + "inLanguage": "nl-NL", + "educationProgramIdentifier": 20121350, + "ECTS": 3.0, + "creditsAvailable": 3, + + "alignment": [ + { + "type": [ + "Alignment" + ], + "targetType": "ext:QualityAssurance", + "targetName": "W Practische toepassing van animale transmutatie", + "targetDescription": "Accreditatie van de opleiding door de Wijze Raad van de Magiërs", + "targetCode": "AV-7381", + "targetUrl": "https://data.example.com/decisions/AV-7381" + }, + { + "type": [ + "Alignment" + ], + "targetType": "ext:EQF", + "targetName": "EQF level 4", + "targetCode": "4", + "targetUrl": "https://content.example.com/description-eqf-levels" + } + ], + "learningOutcome": [ + { + "id": "urn:epass:learningOutcome:1", + "type": "LearningOutcome", + "relatedSkill": { + "id": "https://publications.europa.eu/resource/authority/snb/dcf/860966ekgo", + "title": "5.4 Identifying digital competence gaps" + }, + "title": "Name of DigiComp Competence" + }, + { + "id": "urn:epass:learningOutcome:3", + "type": "LearningOutcome", + "relatedSkill": { + "id": "http://data.europa.eu/snb/dcf/34v10n662m", + "title": "3.1 Proficiency Level Foundation 2" + }, + "title": "Name of DigiComp Competence 2" + } + ], + "participationType": "onsite or blended", + "assessmentType": "testing", + "identityChecked": true, + "supervisionType": "onsite with identity verification", + "resultDescription": [ + { + "id": "https://example.com/results/ects-nl-NL-A1B2C3", + "type": [ + "ResultDescription" + ], + "valueMax": "10", + "valueMin": "1", + "name": "Final Project Grade", + "requiredValue": "6", + "resultType": "ext:ECTSGradeScore" + } + ] + }, + "result": [ + { + "type": [ + "Result" + ], + "resultDescription": "https://example.com/results/ects-nl-NL-A1B2C3", + "value": "8.5" + } + ] + }, + "credentialSchema": [ + { + "id": "https://purl.imsglobal.org/spec/ob/v3p0/schema/json/ob_v3p0_achievementcredential_schema.json", + "type": "1EdTechJsonSchemaValidator2019" + }, + { + "id": "https://raw.githubusercontent.com/educredentials/obv3-examples/refs/heads/main/schemas/microcredential.json", + "type": "1EdTechJsonSchemaValidator2019" + }, + { + "id": "https://raw.githubusercontent.com/educredentials/obv3-examples/refs/heads/main/schemas/microcredential_ects.json", + "type": "1EdTechJsonSchemaValidator2019" + } + ] +} diff --git a/test/uvh_at_microcredential_full_edtech_proposal_LO.json b/test/uvh_at_microcredential_full_edtech_proposal_LO.json new file mode 100644 index 0000000..a0e0463 --- /dev/null +++ b/test/uvh_at_microcredential_full_edtech_proposal_LO.json @@ -0,0 +1,216 @@ +{ + "@context": [ + "https://www.w3.org/ns/credentials/v2", + "https://purl.imsglobal.org/spec/ob/v3p0/context-3.0.3.json", + "https://raw.githubusercontent.com/educredentials/obv3-examples/refs/heads/main/contexts/educredential.json" + ], + "id": "http://example.com/credentials/crd-A1B2C3", + "type": [ + "VerifiableCredential", + "OpenBadgeCredential" + ], + "issuer": { + "id": "https://example.com/issuers/iss-9Z8Y7X", + "type": [ + "Profile" + ], + "name": "Universiteit van Harderwijk", + "otherIdentifier": [ + { + "type": "IdentifierEntry", + "identifier": "UN1VH", + "identifierType": "ext:BRIN" + }, + { + "type": "IdentifierEntry", + "identifier": "uvh.example.com", + "identifierType": "name" + } + ], + "image": { + "id": "https://raw.githubusercontent.com/hamrt/credential-converter/refs/heads/image/test/university_of_harderwijk_75x100.jpg", + "type": "Image", + "caption": "University of Harderwijk logo" + }, + "address": { + "type": [ + "Address" + ], + "addressCountry": "NDL", + "addressCountryCode": "NL", + "addressRegion": "UT", + "addressLocality": "Harderwijk", + "streetAddress": "123 First St", + "postOfficeBoxNumber": "1", + "postalCode": "12345", + "geo": { + "type": "GeoCoordinates", + "latitude": 1, + "longitude": 1 + } + } + }, + "validFrom": "2024-08-30T00:00:00Z", + "validUntil": "2029-08-30T00:00:00Z", + "credentialSubject": { + "id": "https://example.com/students/stu-7Z6X5W", + "type": [ + "AchievementSubject" + ], + "identifier": [ + { + "type": "IdentityObject", + "identityHash": "student@1edtech.edu", + "identityType": "emailAddress", + "hashed": false, + "salt": "not-used" + } + ], + "achievement": { + "id": "https://example.com/achievements/ach-876543", + "type": [ + "Achievement", + "EducredentialAchievement" + ], + "criteria": { + "narrative": "De student heeft de eerste stap van transmutatie afgerond, waarbij katten zonder blijvende schade worden omgezet in keukenapparatuur." + }, + "description": "De student heeft met succes de eerste stap in transmutatie afgerond, waarbij katten zonder blijvende schade worden omgezet in keukenapparatuur.", + "name": "Microcredential Basisomzetting Kat naar Koffiezetapparaat", + "image": { + "id": "https://raw.githubusercontent.com/hamrt/credential-converter/refs/heads/image/test/edubadges_100x100.png", + "type": "Image" + }, + "inLanguage": "nl-NL", + "educationProgramIdentifier": 20121350, + "ECTS": 3.0, + "creditsAvailable": 3, + + "alignment": [ + { + "type": [ + "Alignment" + ], + "targetType": "ext:QualityAssurance", + "targetName": "W Practische toepassing van animale transmutatie", + "targetDescription": "Accreditatie van de opleiding door de Wijze Raad van de Magiërs", + "targetCode": "AV-7381", + "targetUrl": "https://data.example.com/decisions/AV-7381" + }, + { + "type": [ + "Alignment" + ], + "targetType": "ext:EQF", + "targetName": "EQF level 4", + "targetCode": "4", + "targetUrl": "https://content.example.com/description-eqf-levels" + }, + { + "type": [ + "Alignment", + "LearningOutcome" + ], + "targetName": "Monetizing with data and software", + "targetUrl": "http://myinstitute.eu/LearningOutcome-1", + "targetCode": "LO1", + "targetDescription": "- Student understands the basic principles of data and software business, and the special characteristics of software industry\n- He/she can critically analyse how it is possible to monetize with data and software\n- He/she can analyze the feasibility of software business models. Student can apply theoretical knowledge and understanding of the data and software business characteristics to collaboratively create a solid lean canvas model for a software start-up.\n", + "relations": [ + { + "type": [ + "Alignment", + "FrameworkAlignment" + ], + "targetName": "think creatively", + "targetUrl": "http://data.europa.eu/esco/skill/d207a30b-2f80-4138-9b77-f88d549b8768", + "targetFramework": "ESCO", + "targetType": "ext:ESCO", + "frameworkUrl": "http://data.europa.eu/esco/concept-scheme/skills" + }, + { + "type": [ + "Alignment", + "FrameworkAlignment" + ], + "targetName": "5.4 Identifying digital competence gaps", + "targetUrl": "https://publications.europa.eu/resource/authority/snb/dcf/860966ekgo", + "targetFramework": "DigiComp", + "targetType": "ext:DigiComp", + "frameworkUrl": "https://publications.europa.eu/resource/authority/snb/dcf/25831c2" + } + ] + }, + + { + "targetUrl": "http://myinstitute.eu/LearningOutcome-3", + "targetName": "Name of DigiComp Competence 2", + "targetCode": "LO2", + "type": [ + "Alignment", + "LearningOutcome" + ], + "targetDescription": "- something else\n", + "relations": [ + { + "type": [ + "Alignment", + "FrameworkAlignment" + ], + "targetName": "3.1 Proficiency Level Foundation 2", + "targetUrl": "http://data.europa.eu/snb/dcf/34v10n662m", + "targetFramework": "DigiComp", + "targetType": "ext:DigiComp", + "frameworkUrl": "https://publications.europa.eu/resource/authority/snb/dcf/25831c2" + } + ] + } + + + + ], + + + "participationType": "onsite or blended", + "assessmentType": "testing", + "learningSetting": "formal", + "identityChecked": true, + "supervisionType": "onsite with identity verification", + "resultDescription": [ + { + "id": "https://example.com/results/ects-nl-NL-A1B2C3", + "type": [ + "ResultDescription" + ], + "valueMax": "10", + "valueMin": "1", + "name": "Final Project Grade", + "requiredValue": "6", + "resultType": "ext:ECTSGradeScore" + } + ] + }, + "result": [ + { + "type": [ + "Result" + ], + "resultDescription": "https://example.com/results/ects-nl-NL-A1B2C3", + "value": "8.5" + } + ] + }, + "credentialSchema": [ + { + "id": "https://purl.imsglobal.org/spec/ob/v3p0/schema/json/ob_v3p0_achievementcredential_schema.json", + "type": "1EdTechJsonSchemaValidator2019" + }, + { + "id": "https://raw.githubusercontent.com/educredentials/obv3-examples/refs/heads/main/schemas/microcredential.json", + "type": "1EdTechJsonSchemaValidator2019" + }, + { + "id": "https://raw.githubusercontent.com/educredentials/obv3-examples/refs/heads/main/schemas/microcredential_ects.json", + "type": "1EdTechJsonSchemaValidator2019" + } + ] +}