Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How should a byte steam be encoded into JSON for a dereferenced Did URL that points to an external resource outside the DID Document? #129

Open
kdenhartog opened this issue May 25, 2021 · 14 comments

Comments

@kdenhartog
Copy link
Member

Currently the only examples in the test suite for the executions.output.contentStream property in the dereferencer data model input is stringified JSON. How should we encode a different media type such as image/jpeg into the result?

@msporny
Copy link
Member

msporny commented May 31, 2021

Currently the only examples in the test suite for the executions.output.contentStream property in the dereferencer data model input is stringified JSON. How should we encode a different media type such as image/jpeg into the result?

At present, the test suite isn't designed to do this and probably won't get that functionality by the time CR ends.

If someone needs this functionality, they will have to come up with a PR to support it. @peacekeeper might have done more thinking on this since that's his part of the test suite.

@kdenhartog
Copy link
Member Author

kdenhartog commented Jun 6, 2021

The proposed method I've been working towards is converting the data to a data URI. So for a image/jpeg it will be data:image/jpeg;base64,<base64encodedImage>. This seems like a robust way to represent any byte stream of a resource in JSON. Does anyone see any problems with this approach?

@jandrieu
Copy link

jandrieu commented Jun 6, 2021

@kdenhartog I am not sure I understand the question.

But, I may have been working on similar solutions.

Are you wondering how to embed arbitrary data in a JSON object?

Or do you want to put arbitrary data in your DID Document, such that said data gets returned when the right DID-URL is dereferenced?

You could put the data in a data: URL and put that data:URL as a service endpoint, but I wouldn't recommend it.

I am confused, in part, because embedding != external resource, so I think I lost what you were trying to get at.

What's the use case you're trying to solve for?

@kdenhartog
Copy link
Member Author

kdenhartog commented Jun 6, 2021

Currently the way that we have to provide the input and outputs for our test results have to be encoded into A JSON object for dereferencing. As an example did:web:kyledenhartog.com?service=dogPicService&relativeRef=JwIZJYD.gif should map to https://i.imgur.com/JwIZJYD.gif which results in a stream of bytes. In order to put this data into executions.output.contentStream we need some way to encode the resulting resource that has been dereferenced. So the original question was how should we do that? My proposal is to encode it using a data URI so that we can support any arbitrarily referenced resource.

@msporny
Copy link
Member

msporny commented Jun 6, 2021

My proposal is to encode it using a data URI so that we can support any arbitrarily referenced resource.

Yes, this works @kdenhartog -- and given that no one else has proposed something, and that what you're suggesting should work for the purposes of the test suite, we're good.

I'm not sure we need to test this as a part of the test suite, though? Is there a dereferencing test that would exercise this capability?

@jandrieu
Copy link

jandrieu commented Jun 6, 2021

So, this is something I've been doing a lot of work with recently. My opinion is that data: urls are insufficient for a number of reasons, BUT they can work in many instances. The problem is that data:urls only provide a media-type for content description. It doesn't provide for alternative encodings, compression, or encryption. See the Learning and Employment Record for an approach that embeds arbritary content in JSON-LD. https://drive.google.com/file/d/1RfdXAUNhp0kluD9htpb8c_Tg2dLm2QcJ/view)

FWIW, there is also a new property for DID Documents I've been working on called "LinkedResources" which may be a better way to do what you're trying to do. It's supported by DID-core and will be submitted to the DID Spec Registries, but is not ready for submission as we are proving out the concept with multiple implementations before socializing. Ping me separately if you'd like to learn more.

I'm still confused by your use case however.

Taking your example,

did:web:kyledenhartog.com?service=dogPicService&relativeRef=JwIZJYD.gif

should map to

https://i.imgur.com/JwIZJYD.gif

which results in a stream of bytes. In order to put this data into

executions.output.contentStream

I'm not following this last bit at all. It seems like you are testing a method-specific dereferencing semantic with a parameter that is not well defined (highlighting the tribal wisdom issues already raised).

My interpretation of how one would process your proposed did is this:

  1. Parse DID-URL
    a. DID : did:web:kyledenhartog.com
    b. service : dogPicService
    c. relativeRef=JwIZJYD.gif
  2. Resolve DID Document for did:web:kyledenhartog.com
  3. Find service listing in DID Document with an id of did:web:kyledenhartog.com#dogPicService
  4. That would be something like
service:[{
  "id":"#docPicService",
  "type":"webWithRelativeRef",
  "serviceEndpoint":"https://i.imgur.com"
}...]

Note, currently there are only two service types listed in the did spec registries, so the value of the "type" property is ambiguous, but that type property should definitively explain how you work with that service endpoint. I just made up a type that I am interpreting as saying this is a normal web link which is intended to work correctly when you append the RelativeRef property.

Continuing the flow:
5. That service endpoint gets interpreted with the append RelativeRef semantic to return the URL https://i.imgur.com/JwIZJYD.gif
6. Dereference that URL using your preferred https compatible network library
a. the result is the stream of bytes representing that gif, in whatever packaging your library provides

In this flow, I don't understand why there is any confusion about what gets put into executions.output.contentStream, in part because it seems that it MUST be whatever is returned in the payload for that gif, and presumably the header data from that retrieval gets mapped to contentMetadata. And this is entirely the responsibility of the resolver--not a function of DID Core. How and what you put into that dereferencing response is currently method-specific and otherwise pre-standards track with the DID Resolution spec.

Personally, I would not build out an implementation this way. I would simply take the DID Document, transform the DID-URL into a URL with the service property semantics, and then dereference that URL.

In particular,

<img src="did:web:kyledenhartog.com?service=dogPicService&relativeRef=JwIZJYD.gif">

IMO, should work in any DID enabled browser to actually render that image.

We have so much implemented in web libraries that the current dereferencing semantics don't make much sense to me. What I think we need is for dids to be usable as URLs, full stop. We probably don't want to do that by reinventing dereferencing, we want to do that by defining outputs that standard browser agents can use.

Sure, you can also create bespoke dereferencing (such as pulling something from the chain) that, would by its nature, be method-specific, but this pattern of transforming a DID-URL into a URL is going to be vital for a reasonable transition of current web-centric applications to DID-aware applications. The actual dereferencing in that vast array of use cases should just use standard web dereferencing.

So, let me try the use case question again.

What is the real-world value-creating interaction that you are trying to enable? The IMG tag example above doesn't need the dereferencing API and will likely never use a DID resolver to do the dereferencing.

Further, the dereferencing contract is stated in an abstract form. You're basically asking for a non-abstract solution, which is out of scope for DID-Core, IMO.

On the other hand, I would love to see a test using a data URL for a service, which returns the image via http (although I still feel that is testing the resolver and not did-core):

service:[{
  "id":"#docPicService",
  "type":"dataUrl",  
"serviceEndpoint":"data:image/jpeg;base64,/9j//gAQTGF2YzU4LjE4LjEwMAD/2wBDAAgKCgsKCw0NDQ0NDRAPEBAQEBAQEBAQEBASEhIVFRUSEhIQEBISFBQVFRcXFxUVFRUXFxkZGR4eHBwjIyQrKzP/xACUAAACAwEBAQEAAAAAAAAAAAACAwAEAQUGBwgBAQEBAQEBAAAAAAAAAAAAAAABAgMEBRAAAgEDAQYCCAQFBAIABwEBAAECEQQDElFBMSETBRRhcfAGMhVSIpHhoUKBYvFTFiPBsdFDJDM1RNKCc3SyclQRAQEAAgIBBAMBAQAAAAAAAAABAhETElFSMSEDImFBkSP/wAARCAF4A1YDASIAAhEAAxEA/9oADAMBAAIRAxEAPwD4CQhtArCB6WGoE2F0C0MeoDVEnYVemEsLZcURqic+9VQ8OGrY6CiGok7Uc7woxWq8zoUGJGO1HN8ItrDVjF72dNIckOSjj+Bj5meBXmdrSEojvRxfALe2KlZrzPQtFaaM9qy4fhF5k8KvM62kmkcmTTl+EXmb4ReZ1tIekzyZeWXH8GtrC8GtrOxpDURyZeRxvBLawvAraztaQtJjly8jh+BW1+v7m+BW1nc0B6By5eRwvh8fML4fDzO5pD0jly8jg/D4eYXw+Pmd3SbpM8mXkcD4dHzJ8Oj5nodJugcmXkef+GR2v1/crT7fR8j1mk1YdQ5MvI8lGwrxLC7bE9UrZbBqwLYOTLyPJ/DIk+GRPbRtU9w3wi2Gu+Xqo8J8LiT4XE934JE8EicmXqrLw3wuPr/MnwuPr/M9v4PyFuzlsHJl6qPGfC4+v8yfC4+v8z2PhJC/Cy2Dky9VHk/hUfX+ZPhUfX+Z6zw8thnh5bB2y9VHlPhUfX+ZPhUfX+Z6joy2fmZ0ZbB2y9VHmPhUfX+ZPhUfX+Z6XpS2E6b2Dtl6qPM/Co7fX7k+FR2+v3PR6TNLHbL1Ued+Fx9f5k+Fx9f5noKMlEO2Xqo898Lj6/zJ8Lj6/wAz0HInIdsvVR534ZEnwyJ3yDtl6q08/wDDo7DPh0dh3qEoOTL1UcD4dHYZ8OjsO6QcmXqo4Hw+OwngI7Dt0JQcmXmjh+AjsB8Ath3AaDky80cTwMdhngVs/M7VAaGuTLzRxfArZ+YPgls/M7VDKF5MvNHF8H5E8H5HXoZQvJl5o5Pg/Izwh1aEoOTLzRx3asHwrOs0DQ1yZeWnJ8KzPDM61AaDkyZcnok6LPcd+9nbrsrwzn/lwZoKUMyXKrVXGXGjRSwdplm7Rd9yWVJW+aGJ49Pva172rVypsob5Mh5PomdJl6hlDXfLyqhoYOhl6iMoi96KWlg0Z6O7sMVtZWtyrnDllcam8MPfxU+fnvOLyNdxVoyUZ6DuPb8dirZwusFz18SyvpOvSb/RL+I43IuxX5mUHOhdu7C5sei8+N4+tjWXHzT1QfB8jW2XNIEShdqEhpAMIQgEIQgEIQgEIQgGEIQKhCEKG0GJGJDUjlaNSGJGpDEjFqokOSBSHJGNjEhiiRDEQRRGKBEORkAsYxQDQxAAsYzQMNMhWkNRHJB0IipPgVGXMhVoAugVA6BpGbQvSGojNISRAvSHpGUDoQK0hJDaB0MIVpDURukNRATpC0jtIWkyK+kJRH6QtJQrSTSWNJukmxX0ljHEmktRjyGwug7HHeTSWYQ4FDooajVEKgGUDobQ0gyhAiACShpAMojNEdhpC7A6IbDOnDYbUyo2A6MNhnRhsHGVGxX8NAHwuNlqoNRsVfBYxXgsfr/M6Goypdo5rsIAOwju9fzOtUzUGnEdl5C/As7tTKllHA8FIDwcj0QJEebdpLYA7aWw9M6GUjsA8s7aWwW8Eth6pxiA4R2Gx5R4p7AHinsPWdKL3APBB7gPJvHPYDolsPUu3hsA8PDYB5dwYGlnqHbQ2C3aQA8zpZlGeidnAW7OG38vxKPPUBod7wcRbs1sKOG0ZQ7Ls2Jdo9gHJYO9elHVdo9gmVrID653jveK0vsNhfR6tjcWeDXHfjloX+SPmjm3vZvhfs13PHDLHNgz3Vvkt8seEsbVOar7y3niO63lx3XNjy5YRi4YoYlp5KkFSoEL+8h2zN21/VgySjOKfHHJOtY+nYa2PYXOPsfZryz7Tk7ZG66kcLzXEpyWRyzUdYJcEvzLWTtnaLG59osuSxhmx2PRlhxOUoxVUuVVzpvOFi9qLvHjwdWysrjPbpRxXOXHXIorhv5tbTm3PfLy5Xc9WLGn3Lp9VxqtOilNNa/mblV3bjs3b+8S7Dnt7dWC7hknjzQxc4rppuqTdU3wYVrHsfde45+yQ7XC3S6scVxGc3nU8a97JWlU3uPIy7tfeF7fb41HF4CcsmGcff1N1q93kdnL7WXkllyYrKzt7rNBwyXeOFMstXJtV5Jvea2OxZ9g7f1vZ3Hlwwn4jJcRzvdk0qVK/YqXODs/cu399WDt2Ozn2zniy45Nyn9Wlqda1TOBb+0V9bfDP8WKb7c5vG3X69da6+fnuObb93z2uPueNY4OPcU1lrVaVqr9NPMbH0C19mu23Pc+245Y4Qw/DVdZoVcVmkq8pOtUnvaF907N2juFrHovtlrcxz48cI2ed5YThOWn/JqpSS4+ZR733O57Td9kubdRcl23GnGXOE4ttOMlvTR57uHtLlurZ22CytO3wlkWWfh4aZTnF1TcuPHYbg6/ec3YuzZ8/al2mGfoR0yuJzks0slKuSeyr5I9ff23b+95+x2eS1jjTsPFSnFtS6eOP/oWxS28T5/m9q81zgcc9jZZbh43i8XLH/m00p6K03lCftHfPP2+4x6cWSxwrBBx4Tgt0lse9FHpbSHZvaSN9aYu2Y7HJbYcmbDlxTk21iXDJVOtfuBfPtXaOx9sn8Mw3Ge9tJOWWcnWEk9OtKnHmcq79rs+bBnx21lZ2E7iquMtvBqeRPdzrSu+h53uHdc1/a2NtOMYxssTxQ08ZJyrV/gUedIFQyh0GEIQ0jCEIBCEIFQhCAYQ0gGEIQDoKI2MSIYjzbaFpGKJENiZGKI5QIhqMoxQDUBioNVCBaxhrGxyGIBCxscsbGIsRArdNgaWXnwFUMgYoJjFGgMuBEUMgmg+XNgqJAKQxINRGJGaFUCSG6QtJlC6BUGaQ1EgVQNIZpC0kQCQaQVA1EgGgVBlDaEC6BJDKG0IBobQOhKEGRjVlmgEEOCtjEtwiKgi3FHVW0NobQlCIhCEAhCEAEhCAYYaYBhCENATDTAMIaQgwhCAQw0wASEIVWGEIEYYQgGEIQB+G3zXMtGHHLJJJtqOxGZ7fPayUc2KeJvmlJUqen9l6+NyUaX+DJze7hzOl3a3zvtdtHJkjdSWWk88GnpUnyVeL/I0Pn8YyySUYJyk3RJcWZkxzxTcMkXCS4xfFHsp9lhZZ8MY38Y3DlB44LH9XPf7zQnJ2jJcXN5kubpQhgnpncTXKT8o/iB5TBhlcZYYo01TkoqvDmS7t8lncZMGSmrG6OnNfsevj2eNnlsbnHcxzwyXEYrTGnLbx/Iud27JC6urzLiuoSywrlng0uqX/wDqvGnkB84BPW4exY/D4ct1eQtZZ/8A1QlHU5bKvUqfYs/2y/F5LZ3CXTwrM56eVH5V/Mo8QCe5fs1b6MeX4lj6OWkYZND5zf6aV/Op5XuFlPt91kt5yUnB+8uDW0Cvmts9vp62OWPWtUG/1LagclrnxQhknjlGE1WLa4o972lYO92UbS6nSdrJTjL9TxrjEpXGOff7vNk6kbaztFojOXuxitkeVW+PEo8G0Loj1lz2JRxYc9tcxusOTJHFLJGNOnJunONf9QY9glLuWew6yrixvJr0ujoq0pXl9wPJaUBRbD2+D2dwZLa3uM9/C2Vw3GCcHL6q0p7yEQ9m8nirvFmzQw4rSjyZ3VxpL3aR5cfSUeKcUHgtMlzk6eGDyTfNRXHketv+w4rftzv8F7jucamofTBri6c6t0psF+yX/wAZxf8A4s3/APJR5CFvPNljhxwc5ydFFcXLYhOW3eOUoTi4yi6ST4pnp+xqvfrb/wDZl/vI7Ofske5Xfdbqd3C1xW9zJTlKNePPlz/ID55jsstxPRixzyS46Yqr+xVlgXNNNNcfI+lW/ZLqy7jbKzv1S5wZJ4rmEP0xXNaW9/pODm7FmeG1uMOXxKuszwukaOGVOjUgPIzxOSVW5UVFV8FsE9BH0ePsrXPdxndqGG0UVmz9OUl1GqvHGCdZNcHzFf2nklfWtvC5TxXUJzxXGiSTUFzUsbalF/uaHzd4EFCzyZVN48c5rGtU3FN6Y7XTgj6Lh9mLe5vfC2/ccebp45zuJxxumLQ6USrWbdHwoIte3Z8Uu74rPuKWLDgi8s4Y+WaDfutSdY03jY+bvCKeE+5d19nLK+XbMWC9wYM8rNOGLppO4a56qpqjfDgfPLfsk52l/dXGRW0bKfTanF1yZf6a4UfmXavFvCA8LOkLOkyvkc14mB02dNi2b7Uc5wYOll9oBovYUqMwtNCmjcoSQOgJoYQhAMIQgHcUBygahyPI0WoMcoBIcgFqAxQGqg1UMISoDlAaqDlQBCiMUSwojFEiKyixqiywojFEgqUCSLOlGqJAmhWyF2XIoz4kRWoEkHQNIztApDUgkhqRm1S9JukZQKhjYCgVA6B0GwqgdBlAqGdhVAqB6TaDaJQKhoRnYGhKBkGxlAQ6EiuZQ6Kogt4T4BQjUuLR0IllIGKGmwNCUCIEDQlAjABIQgEIQgAgjAQAIEQoEhpCgCGmEAkNIAJDSACQ0hVACMBoEAQKhABIQgHoOxXeCzuck88nCMsUoVpXnIvZLzt9lZ5La1yTzvPljKc5R0qKi0+VfyoeRBZoeovO42+bvOG5hKuOPSq6P9K58mdV3drfx7jiyPJjt8mZZI54wbjFpLlNLhU+f0OtY9yz9vcumoSjPlOE1WMvSgPYZ5Wlr27tssWSWTFjuqucouLlTjKnE5mHulrHufcc8pNQz45xxuj5trkjg3/c8/cOmpqEIY1SMILTBfscoD2WS57Z3G2tHc5p4MlrFRcVBy1pfLw4l7L3iwldXGSM5aJ2aww+l+8tx8+IUellfW/wywt9T6mHPrmqPlGvGu/9jnd9uMV5f5M2GWqDUaOjXBeZywWgO12K9w2GfNPM2ozwTgnSv1PgH2q8tY4Luzu3KGK5+rqJN6JLe0jz9DKFHqs19YdvsY2dnklct5oZp5GtMfpfupM60u5dqhc5+5wzZHmy4Xj8PoapJqlXPYfPKA0A9FdX9vks+1YoyrO2yasqo+Srt3nenf2fccvdISeXwtxHE+vCDfScI0rKNK0PnVDp9v7jn7dklPFpamtM4TWqE47JIo9ReYrPB7LyxWuadxDxEf8AJKOhSlXnpWw8X2e9+GX2K506lHVGS2xkqM6Hcu7XHcYwxyjixYoOscWKOmC86Hn2gPc4Z+z1jd/EsdzlyyjKWSFroacZvhFyapRM43xXFl7X3XFkenPdZ1ljGnKnpXI820C0B7y17zY4n2hzyNK1t82PL9LdJTjy9NSh2Lv0O2RvYZVri9WW3TVVHLzpT01PHUAYHs+x97hgtry1uLrJaTuMnWjdxjranvUo0fHadJd/ssHcbSUry4u4YMWZZLicGk8kly0Y4qqW0+bNC2Udbs2a2w3uXLmvM1jqlN4s2KLmk3Juk4pc4tHrrv2g7Xkn3R4m/wDyLKOCORY9Cz5U+c9K92p82aAaKPVdxv8Axtx2X4fNvPb4MWJcqNZVLgq8Vt8jp+3Hc1my4+3w0xeGmS60JJSuGlXhxoeO7dez7ZdRucUMc8kE9HUWpRb/AFLnxRz80558s8uR6p5JOcntbNCjQGg9oChFIaFtFhoW0blFdoGg5oGhRXaFNFloU0dNhDQDRYaFtG4EEDYBsYYaYB6ZRGqIaQ9I8SlKA1RHKI1RAQojVEeojVEjKukxqTLCgOUERVYdGo1QQ1QRAo2pbUEKlDYQAhgMUNfAgqTZSkWsjEJGWApDUglEYkc1CkMSNSGJGQugaQVBiRkBQJIPSGkAuhKDqEoYZJobQZQyhVCQIgUIZDSARkFvBHxVEURlnGhEVVl+CR0jYlyDIQ0ywhpCDCGkAXQlAyFCyBkAGhKEIAJhlUZUDTDSFA0MoFUypQJAiAAQ0gAkNIABAiACANBAWYMoDQATAjABIEQ0gARgIEBCBAww0wKwhCFC6A0HA0KE0AoWKA0ArNCmi00LaIKzQtotOItoorNC2i00LaKKrQDRZaFtFFZoW0WmhbQFVoW0WWhTQVWaAoWGhbRQhoW0WGhbRqCs0AWGhbRdqS0KaLDQto1KK7QDQ9oW0dIENC2iw0KaOkoSYGwSo9ckPQ3ShkYo8alJDkhygNUCBSDVR6ghvTREKUhqYSxoYsZACY2MgliGrEQZ1EDWo3ponTRBkYgz5IfShXyMiKEuJEjd4aRioiQaRqQxI5jEhiREhqRkDQJIKgVDKMNNCoAJAiEAGBGFGENMIIaDU2pQUVVlhicfEc+JWjccd5bSAxxH0ojo0wwFyA1pFQ4gnqInUQDiC9SCA0hCAYQhAAqV88tMSxQoXMlwKqj1294azS2ly3wQfNoveGxP9JRx+s9pOs9p2PC4thnhcWwDm9XzNWQuuyx7WYrSK/UzW4K2sNSMyYlj51E46tlFshCGGUIQgGENMAwhCEGEIQoBgjAQAIaQsAmBGFGGGmBWAhgBGGBGAQEIEo0w0hQpgjWAQJaFtD2hbRQhoBoe0LaArtANFhoBoCs0LaLLQtoorNCmiy0LaKqs0LaLDQDRRWaFtFloW0UVmgGiw0LaKqs0LaLDQtosCGhbQ9oUzpAhiWOYlm4yWwSME6K91UamGoIbGCPErE2NUmEoDVAgxSGqZixjFjZASkhqmgOmGsTIh8ZJjFJC44xmmhAdUaJLCXIzTYJcDm5GX8vJHOfNmdoBIakRIakYoxINIJINIwjEhqRiQxIwBoSgRAgaGmkAwhCAQEIkVzAPpulSpplKXJHUfKI+0xVepmtK43Qy/KErfLsPYaFsJoRvTTyLUoLhQdhrJjrxxc6IZgx0CrkFRBS4BAydFU0OXPLSVKcAat7mNxx1TcjrR4AcRKTdKGSUk+DO7RHPuJQXAgoJup0o8Ec6HNnRiUGaQ0iBIaYAt8jkTevIdDPPSilihqdSq6GJURYqKiMKg6slWAQg3UwXIFicktKAqZp6nQZjXIrwVZcy5FHRR0NoEkNoqGGSARjyQi6Ga8b3BSiDK4yf4wFmDFBMFpIACEIEQhCAYYaYUCCHQwuwBgZg2AIaYUCQhABIaQDDDTCogIZgUugNBlDKAIaAoPaAaKK7QtostC2gKzQpotNCmiis0KaLLQpoqq7QtostC2gK7QpostCmgEMUx7Es1FJYpjJMryZqAJMrykbKRWlI6yCSkKbICdZEYQhDY+iJjkxcYDemz54bqQyM0KWNjFjYFlSQ1SRVUGNUWQW00MVCmlIakzI6CpQyVGitHUHzIIlzHcEDFBy5IwihlkVR2TmwUjKIkNSMSGpHOqxIYkakGkYZDQI00yMIaQDCGmACQ0gGBxBHRRqe4RlypOh0rXPCMeJxMmN5JUR1sdjLTsPRpt1ldQ2ist1BRdHzKnw+W0z4bN72Ucnqap1Z0seSKJ8KyBrtmVbTO4G9aInNlXuhqynFlCcJPJTYFXsCVC3UVCOlGsA5SpE4OXKmyxeZXBJLeceUZZFVCDrW9GdBM83ilOPKpa1ZNrOjLvVJU4nUyk6mXzA7VQanI609oXWntMWK24k9Q/BGiKarOXM60FREUSNCIEYQhCAWjn5pc6HRqcqfOZQzHEtJC40QzUgGI2ToiRYjO6IBEXqnVnQUo7Dn440LJRY1Q2L7ErDYvsINQD5yjGPBHHlPXIt3EqKhRxrmFWkGQ0MsIQgEMNIAJDSAKIEYAJgZhQBAjC7AghmFAGBGFGGGmEEIQhQNABhlAhLQtoc0C0VVdimWGhTRQhoUyw0JaKpDFsc0LaAQxLHsrsBbK0pBzmUMmQ3FSUypOYmWQruR3mLI5SFGkOutKEw0wohhpgH06Mkh8ZI87HLKvEsRzSPAPQJodGhw1mlQsQzOgHZVByOXGUh6nIyrpJDVFHPhOVR3UZEXtKN0oqLKyxGVSAqUK+WVCy+Bz8pzRXCSMGpGKjUg0jUhiRijAyEMIwhCEEIQgEIQgGENIAAUsqhHmDQTkxSyKh0x9xmO5hrqeixXuLSeTdhI3wmRbj0yzy1HtleYto1XmLavueBlgzRVaExwzvcyfFbfRvF4tq+5jusT3o8H/wCT5krcraXTL1N1dRS+k5eH6m2chu4lRNM72DG4x5maiyuBjQygSRhXGurbLm91HN8BdLg6Hrwqll0rxPgLpbyeGu0e31E1Gu9HhXhu1uYOm7jufr+x72q3kpAclHg/83yy+w2EpLin9j2bjj2APHi+VFue4OHgjXmdFIdpiuCoDQyjKENoLk9JlGmVMWuXBGrFKXEiquTJFTim6IY44K1Uhs+3LI66gPhH8RuXH9/4GKWHyCfQe+gl9pkuEhUu2ZV+o1+P7D2saXKRzZZNcg8nbLhrlI3D2/Pi4/UTeP7/AMDYrkGO8Pl+UzpZPlZO0CjQtE/lZVyynDlokNjM0Jy5pci5a440+pAYc05Qo40Gp0KrodHDJbBTtcb4Sa9fSVqsLUyBngn869f3AdlPajOrKJQu+4TwYpSruMoKS0trYCcbt88k4OU2/qdUdkohCEKBIaQIWYGCUYYEYBhCELAIIRhQBgRgAkCMKMMNMCBBGA0KpLQpj2KYCGJZYkIkAliJSNnOhz8mWhpRzmc7JlFZMxzcmU6zEWMmYoTyVFOVQDvMdDTCGGxpDCFEIYQo0hhAPbq3lsHxwS2HTjhkPWFnhaczoy2DYQo+Z0OlInSZhDccUWdKK8aocmwHqKNcVQFNhOpkV1xOhj4HPXE6EOBlBZHRHOk6stZZFI5IJDkLSGpGMkMQxC0MRzRpCEIIQhAIQhABIQgGENIQYEgSAWVIPUisg4c2FdBUpzG44xXBFSvMuYzri2tJR3oOkNiE1Nqa2JKGP5UJdNyGA0G0CSpKEoUYYQhRtSVMIQbUlTCBUMNMCIYaCUQxpSdAHOgKxZpPXFcmVV7XGEX5HnpXHUyOki5d9eGF1i+Z5TDb5nPg0aHroxk1/wCxr9w9GX+qznxw5Eucg1iyfMa7C44Z1wmyUuV+oraMvzs3Tl+ZjtFWNVyt5qyXK8xH+b5zNWZfqHafoWetdbPz/A3xVxHjAr9TN8xOtm2ovbHxBaV9lXGD+wavpP8A6vyKqzTpX6EUcd7mnJqkGkTePiMulkuHP/ra9CK/UfysLrZfkX3C689+M12xaL66+Vm9ZbGE7in/AEg+K24fyHbFlnUU91CSt8OaOnIqoGdzqVFDT+wyPAzfkWceC0ilHSkXXZW84/45pM5QSqnUxoW5duzJcmmUJ4c2N/VBpbS3C5ywdalv4jPhOCktnqjI4lCHoetaZlRxUSlcws8MU+qk26Io5LAGP7gmkCYEZQATAjCwCQ0wowWMAAhhpgGGGmAQEIEoWxTGN0Kc8iKJJnPyZkgM1xSqTOFmueJ00LeXP5nIzZ/Mp5Mz2lVyqdscFMlkb3iXzIYdpBhCENCEIQohDCBEIQgEIQgH2yMEh6jErxkOUj57qZoiKlGJHPkApVMqnTNWIsR4D0gyqLEzXBl4KiMo5Sg6j29KLelVK+VKhz2zXPlKoKRKDEjNrLUNQKQ1HKiJB0NSCOaF0BboOBcagDUIyhCjSEIQYQhABIaQASBUIBB8FRCd5ZK1DsfNlxIr440LSOsaEQhAiEIQowr5MihxLDOXJPLkcdhRaWRMNSTKcsUoIfiVEaDyEIZEIQgEIQW5UAJsQ25PkNjGUzo48ChzYb0qYsD4yR04/SqI2hhDQMmPrrSxCsIrgW06B62DSurTzRPCP+EdrkTXIz8+Wlbwkv4QfCz2L7lrXIqZ7t4oN7C/PkR2k3uX3FeEl8pxcXfMuZNxXJOlWqEffZRdG4p7KGut8o67tH8jEO0a/Qyou+PYvsM+NN7l9jXTJSbmzlkhpo16BNvYvBySdDpru8Xx0hLuuN/L9h0yYJ6b2G6HsZYXc8T+QYr/ABv5B1yFDQ9jMcWi+7vE/wBMX+wEs2HJFx08dnIvXIcTHXJOu4vkhhjBchuk2yXQgygFCVQ0BoMBIKszx/dJSuLu2wQrylqk0z1eaaim3uPLdsi7i5y55LlWkSxl6mHKKQZpCKwhphECCGYABAiFCwQwS7GAhg0KBMNFtgaxEsiQrJlocbPc0qbFvLcU3nHz3Rz890cfLnbOswot5rmvJHNlNsXqbBPTMBCGEOjSEIQiMIQhRpCECMIQgEIaQgwhpCj7JFjaiEM3Hzm0ciR4iajoGUXIssRZWQ9AOqFUUgjkbHUpZp7h8pURz5OrIwwNC0MRzoNDEChiOdBI0iCMowhCEGGGmAQhpgGEIQCEIQohCEAKPEtRVWJii5jibjUWEhiIadGkIQhEYQ0ByUUUDN0QnHBatRXnm1ukRkJTS58iB2R1IkLXNj0jQKhlAiALIRyoLSlN8grHMsY8DlzZaxW0YrmuZcpQilKCiqIIIyoa20FhAsDCEIAJgZgZA2eV73nePDpT990PTs8XdW1xd9wX01hE1AUcatLBNqkpHjueS8VOfPmey9oLmOKEMfyqj9J4ntlxhWaWTI6M9GMR9ChhhSP0rgP6MPlRyI91tfnX3G/FrX519y9au1/w+J8YonhcPy/Y53xa1+dff8CfF7TfkSHXIWnZ4vM492oYskIY3LU3TiXH3iyS/wDailayV3cSyrmlyRjrRJxywcUpydS6rPN/VkduXas2OKuHSS2Lcge63Eo2KyYoqDUkmc+447t7lcM0jrdvw53HI8mTVSlK/vwKVvlnkxqUuLOjbypkSb5Pky72iy0LZdyQoVqGQkB8hzRUyyoUeZ7vcaIaIvnJ0Lvb7foYIrfQ40143uEY/px836T1kVRUN1BECIZAEIQyjDAjCjDAjChRgYIGC2ySlpKGXOo7zcgdPKkcvNcpFC4vUq8Tzue8rwZ1mI6me8VGcDNdOW8pzyuTK7PRjgDcmwTDTsIQhCqwhCAQhCEEIQhRCBUC0Mmwsg9YpMesDM9oKiiHoL6xBdMx3HMcaAlzPGiRULsfXo8DZPkYhcnzPHWmotQQiCLUTKHIehCHoDQgQtxyqKuaRTQzJKrFoyyahiFoYjlWTEMQCDRhTEaRGkAmGmEEIQgGGmGgYCwzGAAQC2BgQ3iYHBVZVOijoQRVjHmXUjtGhENIVphCEIiCZKqY4iA40ZdPJwLUs3UaSTOlye4CsdiCK8YjQXIxKcvQbkBakRKUuCAbw4ueSQeO9xTqoF1VCsTlKj5HRfSwRqwcaVKnE7pn1acXmZHY8bg2jVdYX+r8jgY7S3UFrlKpyI41kyuMZyUa8mb+P6r3HWxP9SJrg+EkeUVjL+pIYrPKuGWRrWDL09VtRKrajzXQuVwyP7k6d2v1/mOuPlp6WpDzFbyP6m/sGst560M9cR6ahhwY3N5H9Pr9jZXmaKq4+v2HXEXrrPDBjlOT5RR5uPflFSlihKTpy5HM7rd57lQwwxypKX1S2I7lpgjixRVOY1ofN7yHcLzVnnGVG60PKS1RdJJo/QFEUp9vtJussMH+x6MfskHwrUiakfbJdm7fPjbx/Y58/Zvt83VQcfQztzYj5HVG8eB9Nl7J2jfLLkX7fidDtnsrb48+tylkS3P+ZnnwHle2eyl53LGsiaxp7X+J9I7b7OXNlhUKxnx51/0PaW9usSSgqJcjoLHJ8Dx5fZb7NuRjnmwxjhyQbT5J+ny8jzPelGNvKPDmvyTPdZMUoqrR8N9rb7LHJoTot/mZwm8omi8ffbfHkWFp7lXd/seui3yZ8RwPVmxv+JH25e7H0Hp+zGY6TTuwl1MfoK8uQFrOja2ljIt552VZnC7hm6eOT8mdO5z9DG5tN02HgbzuPjJ6IRklvKOx2fDWHUkvqlzPULCzyTufDY1CKdUJj3TN6v8AA6D2vSkD0pHkPiub1f4BLu2fUv8An8Aj07jQEHFmlmgpNcRhyAENMKjDDRcpJFGsrzyKKK+a5jFbTzl3fcnzOsg6Oe7pXmeauL3jzOZnvHLgcqeSUj0Y4B+XPKb4lNtkNO8kgwhhDYhCECoQgVGTaBIPWKTLULOT5mbnGnPCUG+B2Y2fkW42qW5GOQcJYXsHq38jtq38h6weRy5BxI2/kPjh8jr9HyC6aM9hzFhQfTL7ihbRjYqaaAtFloU0alHJu+EfSznVOnd+7H0nMod57I+ubhe8xyJE8tVZiWYleJYRlDkNQpDUAQvJKkQyllmcqivWoaFoajKDQ1CkNRyqGoNAINGAxGmI0yBYBrBAM0FBogwgRCgTAqEoQJkt4UeaGUEr6XTaUGWIKiEriW4rmaaWccSwgYoYdY0hDSGRlCUNJz3GgItySF5JuJz8t5jx8XV7EbkHR114C20ucpJHE8XnyvTihTzGRscuV1zT/Y0G5O5W+N0j9b8ii7q+ueUIuMTt47LBj4Rq9rLiVOCGx53H2yc3qyzfo4nYt7PHiokuBabogsOSNeZdi+1pi3sR4uEvE3TlxSfI9hPJGUHFbzlYrS3tcM8kp0aew5jiXdwoVdfJCe3RlOuR7S/cW+C4Vaqj2cwsLxYIKKfDyNI6KYdSn4jHtYXiMe1/YaRbqQreIx7X9ieIxbX9hr9ps8FugpXGJ/qf2K1zdW8IUc6OXJVQ01KuY8zk6A3M1HJDGouU5KtED2zF1J44t058T0mawnC6jnxKu70eZhvF5aORaum4pSXFNcx1D02Ts+K5z+IlPTPfRDPg+P8Aqv7GOzXV5dG1PSvs8P6jEvtKXDIOx1eeqEuZ3H2mfzRERsZwnSVOW8d4nVUxYHOSPTW9ssarQPBbqCTaLGWeiDew57b18PH97v54E4Yp6XyR81ufafuFrNw6mpr0L/Rns80JXGXJlmqxgmfF72azXWSnzNI9/wBWM18o9X/efcqNVqn6P/pPJ9wv8t/k15BWO2yZMmhcSxl7dmxKsqHt/wCbIO24JXFzjhHbU+zpcktiPG+znbnics81zfuntqHm+yz+MJHkzqqWLQtWSJxskW06HAz2c3VpyOEHqc2S3UJVnFrYecxY7SUpzxQVU+NDwvcJTwZKKUgbXu+e2jJJKVd75HWY/A9ZdUm3yONJUF4rqdynJ1CZRqLtpgefNGCKsY8qnSsNUJ60Qe8x2EoxSbSGOzltRy13CdOJPiTW85WC/K2nFbSnKNGU5d4aOVn7zx5l61HYyTUUcG5vYwTODc93rwPN57yeRvm+Z3xwHUuu4N1SOBkyym6tiqthRxtnomMgDmNWKTHwxOvA6GPGauUacroZNhnQnsPTQx13F2FvF7jjyHV4zoT2DFaZXuPoELaGwvQs8Y5aPmysMrC+H5fX+Z9SVri2Gu2x7kZ5KPnMO2veXoWHkexdvHYZ0FuRjvfLLzULPTuRZVuluOy8YOhIb2rmrBHYTpR2F9oS0TYq9NbDNK2D2LZEJaFscxTAUxTGsWzQVIRIsSESA5N77sfSzlnVvfdj6Wco9M9h9RqPgV1zLEUeWi1Fj0ytFDEyC0mNRUTGJkD5OiZzJvmWckqIo1OVQxDkJQ5HNBoahSGoxQwYhYxGEMQYCDIBaMoMMMhYRDQICwgWURBC0MAwygRAqRXMv4o1KEecjr440Rto1I0hprasIEQDC5CPLlxKhYhOjAfK3jlg45EufBnDn2aGOWpLX6T0amnxGpl7N9XmoYGtiLCxNb0dnJgU1WPJnMnGWN8x2Opfu8VUDrxj/wBM36+gLXImuRYmm+Lh/wD80vX9hiuML42kn+xat4ttNnSyTWOLk+CI3pyllwP/AOVlH9hGSVhlrCWNp71xSF/FFl1yxxUlHfwqcm2uck5Zs04RUXLkDTuaO1/Kl6YsnS7XLYv2OJO6xtgeJgb6m3edh26XA34VZS9109Bw1dwQ5Xy8/uOrO3RfZrT+pL1/cS+zW+7JL1/cqeO82Tx3mx1Nn/BIfpyP7fiU7n2Yhc6NWWmh1XrqLPjPNnk7u5uJXfT6zpJ05Ov+g6m3q8Pa7rtkHLHPrrzpVI9hbLP04uaqmq0KVtnhgwrFKevkuPM6cZRxKmtQrtM9b/GhuE/lkZon8sidWP8AXgEpJ/8AfAz1y8OwNL3wn9zKeUhyruzQD+v+pF/uZ1fTRW0r+I2MYp1dWWGstOUk/QIrl2Gfx/uNFj6NhWzQxzVG+TI5SiuaKM+44MfKTVUaxmNvxLDL2eK9ou4Q7daZMUPp1L8j4ZicZ5Z5HwbbR7j2u7jC6zaMfDfzrWh871OPA+p9OP4vM7Vn3PwudzcFOr51Ordd9x3MVHpJUe6nM8YCenpEfWbb2g7fDHGPONPR+B0sfe7DI+WSnpp/yfFTU2uBnixZfeVf2b/7YlW4u7fQ9OWNaOh8U6uT5mTqz+ZnPgnlXoJRleXbXvczs33btGCKUeHPluKfYVXI5b6L/U9Tc/VKjOWU1dDzWDH08aX3HRjVnS6cXyHRt0iMkxUYrmOjlxx4CssXE5eXNHHxIrv9VFLNmocN9yguRy81851pU31Vcub3ikcTJnlPeV5TbYHM9OOKI2YEotsuYsNXWhbZF0HHjbZ1sWBjcOKPLkdeEEkcbV2pxt/IuwtKlqNC3GSSOVu02rq2SHxw0GqaD1owbYkMWpA60FqQNi6kgoTbkJkwISoypt10qmuBTVxQkrrkQ2ZKKKkhbuhXVTINYthNglCWKY1imFLYtjGLYQpimOYtooTIRIsSK8ijlXvux9LOUdW992PpZyjvPYfVYRLcUV4tVLcWjzhlABhlCAEMJQCToiBGWXMWhTdWHE5Vk9DEJQxHMOQxCkMRioahiFIYjAahiEoajIIhCEGEIQCEIQCEIQohCECrGGFXU6sUVsUaJFxcDo0whCBUIQhRCVoKyT0Kpz1mlN7AOwshbx5TkzkscU61qMhPeRuV6CM9g96Mq0zXI4kMtC9DKpFaJz2WhaoOq/2OZSjPSxy04lLPonNUX4iGm4ItROJ366eC20LjN0PTRVEfPe4Tnfd1WCknDGk60+nmaRatsfg+3tS45GkvSznd06uHJZW0FTWtcn5bD2maxc5W64YsbUmeTc3edwucj5xxy6eP0IBiscbXGQmXacU1TXNfuddGm5R5ufs/ikuVxmXof4nMyezeVv6LzMls9We3ITvU0+eS9nb/APTdy/en/JTydi7rjVfEOX/3I+nipI3y1NPluHtXdXkpKUqLzTqdrs/a7l9x15tWjGq8974I+hWcMSm5SaVKUT38S3kzW71QxuOvfQclbcfF3HHYwzZckdf1cj5d3vv13dZ3RzhGr5Hp+6tzyYreD5ybb/0KPcPZ6dwlomk0t/P/AFN/XlMbujxEe6Xa/wC6f3LK7v3FcMuY97272exWlJTSnLazuSsLeSo8cfsd+XE7Pk79oO5Q4Z5fuF/c3dP6zPpb7LZv/qj9ipL2es5foS9CHLidnW9k+85rukc2SU/S9p9VPl3abHFYZP8AGqKqf5n0+ElOCaPH9v5XbUULvJoxs+ZXOWKlkyyfBP8Ac973PXKFI7D5f3PFlljlGNasmGKV8yvszz3GSe5t0CsrHJeZKJfTvOk+1ZY1cv8AY9f2qx8PhT3s90zkx1HKx47uXalZYozVXV0frU81Q+m9xt3fZo4I7ube4SvZhNVq/X9zWH2+R85oSh9G/thbX6/uT+2Vtfr+5vlxZfNzUqs9nd9jjbx1J1OXZ2PVy1pyiOXFp6vtfStbaMnxZelmhldYpHHyv9K4I7Fpb0jV7zhll2u2RQxutS1pZdjBJHTt4Y58qHPY4CtHnfM4972nR9SbZ9KWCC4IpXFsp8jPZp8MuMDUmKhg1cT6xc9nx5E+FThZe0dP3PzO2OdR5y37bHLSu/12nWXYIy9fxBWPNhlwfIu477JjdHzHbLyG4ewwhv8AX7lv4LjMj3iC4r8/wLePu2GW8zuiuuzQW0P4UlwZ049wwS3jld4nvJ8jivtktoPw7It56DxGPaF1sXzev3Ijzj7fl2geByreen6uP5vy/EPVj9f5kHk/C5V/Mzw+XZ+Z6/8Ax+v8zNOP1/mUeMccqdOYD6y3M9lJQKssMG6lR5FzmBrmely4MfGhxcsEmIKiq+JZigIosIo0FhAsKUxTGsUwpTFthyK7YBgMrPIxTyMIfIRIzWY5Glcu992PpZyjqXvux9LOWdp7I+qxTHqoiM1Qsxmjgp8ahi1NG6kZqCKmWQ2UijKdWQQYhIxHGsnIYhSGIwGoahKGIxUNTGIShiMhyGIShqJoMCBCJoQgRDIEgVCUAwhpCgWFhWqaBaL1tj3m46SL0VQNGpBFA0JQIgAENMARljqicfpZG+TVDpXM5QUafqdGPrb44VnJr9isuYoS1JN1OjFURXxfW3LduLlA01BqTiwCGl26WLNXky1GK6lXv4HDOlgyalR7jNbjrNCVgxp6tCrt3liHNIIy7aVpQUlRi422CK5Y4r9i3QlAzpW6OH5I/YHoYP6cS1pM0g0q9DB/Tj9idDB/TiWtJNITSl4fD8nr9hbtcXynR0k0oGnGlaYqcDy132vFbPJcY8s4Sa28j38oROJe2UbmDhJ0i9hqVl4ays28/iJTeRc9Ndx6WhJq0sMcMWpKnCr2HDn7Qduxujcn9jtJbGHfIea/uTt38X5E/uXt38X5F6ZMPTUF0PN/3P27+L7oW/aft+6v5f8AJvor1MeND3NmteJHxd+1FovdXP8Ab/k9L232kzZnFQpR/dHPLG/10xr6LktZSfCpyctjWXuD8F9nze80vuWp3GmNZUOWm3kby0xP6HE4uZQwQpw2FXvHeo45uj5xfPnxPBPvmXNlpStfP8D0zGuVe0ssNZzyPedxKhUsv/TFl+hzqGwjGXEdLDChZt8FVViL1rBByVX5HPY8L3mLcKR4nkrfM8Scac6nqrjK7nJyTp5gwtI8dCrtPRiOXbY+tkq+C5nqIKiE48Gl8B/AqMyZdCFYLzROtSjd5OWkoxjkoB7qHcYtEd7jZ4KUs0dot5c2yRnSveSusb3laU8ct54vr5lukb4rJskaZeoljhI5ee1i9xzldTW6RkrqT41Krn57Zps4uXFkhzT5HopZdRUyUaNyq4His0N5ax90yxpXkKyY03yKUsLO28WXoI94e+Raj3lfMeMlEChrpiPd/GF83+5Yxd0TlxPnYyOSUd44oPq0O4cuI3x3mfLld5EqF/BfyXFmOIfRFe13m+L8zx8LrXwaLiyNnO4aHbyXVd5Rc9T4lJtsbji6k1oXIoaCggiMWwmAzClsUxjFMqlMSxzEsorSiVHF1OgytLiEV6MwawGaVzLz3Y+k5h07z3Y+k5h2nsr6VHUPWoGLQdTihsGx+oqxGVMVEnIp1JOTFpkQ9MahCGo41DkMQlDEZD0MTEoYjNDkGmKQaMByGoQhiIG1GoQMRENNBNMgiEIQQhtCFBwjVnVxqiKWKJ0orkdY6wRDSEAkCMAEANg7QK2qfV4rTT7m5+caNRdRDtZ8nrrR19eYUcWTXqk6kDoRUUNJQ0qIQhDWxhsZOLqiAmWo9FhyaootnnrbLolpfB/kegjzRrTvEIaQ5oEgzkTkAshCAQhCAVc+VY1U8Jn77PJdTwY02o+uw7vdrh4sU35cjyFli0ReSXvTdf2Okc68h3nPc57jm3SPKiPJzt8zddLPqHhOrmdVxO5DtuFRS0o9WP2df4j4S4STpQBpo+7S7Tby/Sihl7Jha5RR2556R8XIfVMns5jlzpT19Jz8vs3BLlX1/c3z4+B87PovYL3GnppWX+xw8/Z+lx/3Oz2bt8o5XKO7cZ+zPG4j6xbZ+S5lTuvco4sUlWroBBSjFVW5HzTv1zkTlFPlU8mPukry/crt580qPlUb2e2dxcLlX8Dk48U889MebZ9c7L2rw8U6c2j1ZXUHoMWOkVFLgde3tW/qkXLa10fU950qI+fcmuqrp0x5HCvskVF1PQZnSLPF3+TU9Nd5MWclOEcVapKpaWhbCkscqHIz21zKbcZ0PTiw9HKUKFKVGzzrtL18Mj+4vwt98/5/gaV0449eauw7awRpzRUssEoRTnxOujNrKp4eGwzw2PYXqA0M7acx2kNgDsobDq0JQbZcXwEBT7fDYd2hmkbHnn26Al9tjsPSuJNJrbTyku2LYIl2pbPX7nr9JNKHYfOLjtTVeR5/NZTg+B9hnijLcc7LZQmuBvH7MoPj8sU48UJPo9x2xc6I4GbtclV0PTj9u/ceXNL2W0nDcUnFo79og45ZR4Muwv8AJDdX9znGD4o9Jj7pB01KjOthvsMt54UhnpB9Ljng+SYzqR2nziGbJF11FqN9lj5nLoPe6094DZ5GPdJb16/YtR7lF7zHGj0DYps56vcb/UMWeEt5LipzFGuUXvAqZ0AbFMNsUxoAxbNYtlVQvPdj6TmHRvPdj6TmHonsj6LFsdGoMaDEedTkZKVEDUTkmZqAcjUyvUNMxUWUxyZVTHJnKoemMTEJjEyCwmMTK6YxMzYLCYaYhMNMzoWUwkxKYSZNMnpjExCYaZmxVlMNMQmGmTQeQNY2F0pDrVAFFcwunIOMGmTVF3HEtIrxrsYzU9jNukNILqGGmkIQjLDAwQBIaQIGhKGkAAgRDShIQghAvkd+1zaoqpwRmLJ0pV3GnXb1bQsmPNCUU6lS5zQUeTMWNLyVSUPK4c05NuGaq2cS71c3zo3pdu5pBocfxGf5l9wvE3K3r7jRt16AtHN8XdbYheMuN7iLEKuLXHn99VRUjbYIPTp5F3xWTZAnXfyoaZ0GNvbcUgnhweQfiP4F6/sBLPF8UZ0mingxLgL6MB3Wh8pOtD5WDRDwQEys4y/kdDqY9jC14/MGnmMvaMc3zXIO3ssdo/p+56CU8bKs4Kfug0r5J6oNLjQ8lm7V1m3JVr67T2Xh5D4W9eI2aeEsewQx5dVF9vxPf29pHF5luGKMaeQ8dl0gLGUEz4Eac27y0g6HkGupkqdm+zfpRzcMd50jhkeoKhulDDDSFaUTShhAF0RtAjSowAMEisIQgQJAjABIQgAgjAGAADDAZQlxTKOTDFnQEM1EcPLZxe44dx25S4I9mytKCZ02Pm+bt841OZLDKPFH0/JhizlZrKLryOs+zKK+ftUMPTZrCleRyslq4o9GP2yjnEDlBxAOm5RCEIUam1wGxzTjvEkGhcV1kQ+N7KvM5hDHWDt+MQfiYs4FTameMd/qxe8FyTOLrkidSW0zxi3dOqj6WUA5ScuIBvQ9/GTLCZSTHpnlU5yKspGzkVXIzUPTGoqxY2piotJjUyomOTOdgsJjEyumGmQWUxqZWTGJkFhMYmVkxiZnTKymMTK6YaZjQsJjEyumGmQWKhY5VnQrOXIO3rrqd8Ysepw46otdIp4syRY8QjWmzeiH0hSuYjVcQOemtC00M1JGvLE52bMopszoVct2559EOG86a4HDsseqTmzuksZaQhORhWkN+kn0lAUIM5E014AJIWOmydNgVyDXBoAAKGBgg2EkFqkkRlq2uceKVZQ/c23HUVvSPoOJf48soOME36D1UbjBmXJpCZwXGPMlbfN/C3eGP0Qmhf8A563TPf5Mc5iPDyRdsvFdS92TC694t0z2PSlsYLwN7mOzLyCu7mPFSZvxDMuMZHrPDvYwei/lLtNvLfFMmyX2GLukv4vsz0PhYvjBfYW7XG/0Iu25XD+Ky/i+zKM+7zc6JP8AfkemlZw+RAYu24VPU4l2ztSx3F5KKah+Q7r3n9M9BHFBKgfTh6s59jbzXi7jfA1XmVcYHo+nD1Yt4ceyo7NbcLxjlycWdq0jX6ivLDGUuUUdnFjUIpGlMobQOjCUTk2VQlBlCUCAKeeemLLx5/uGVLkjfVnKvPZpa5j4RohGJJurLp0cQsw1mEVhCECIQhAMMCMKgSEIBAQgQMMNMAEWGxZoC2KbDbEtgY2KbNbFNm4MbFMNi2VAMVJBti2yqrSgnuOfkwJ7jpsWwPOZbRbDk5bRrgj2M4lOUEzpjlYPFywyjuEtUPWZMCZzMtt5HfkHFIXZW73FaUJROsylCSEIaEIQhRhCECIQhAPZQdSzqKcXQJyPC0ZOQpMS5GpmaLKY1MrJjUznWT0xqZWQ5MzRYTGJldMYmZFhMYmV0xqZA+oxMrJjEyIsJjEysmMTM6FhMYmV0w6l0HxWqSO/iwKnA41qk5HpIOiO0nwsZ0lsKNxLRE6TlRHnrvLqdC6aV4rLlfJllW+fdJly3glFHRiZHJ6Nz8zEzx5q6ZNs9HQpP6shjarNvj0QSLYlPkbU50bOSSOe7vGpUY6daM5fQWWZqSDp+Ix/MEs2N/qK3gsfmD8Ph5m94i91I/MgeqvmX3KD7cvmYv4e90pGd4jq9SW6f5g9aXz/AJnI8Dk+eX3A8BP55DeI6GW7nFLTOrZ1IVcVXjTmcPBYqORSbbptO8jFGECIYQpoW41Hg0Eqyq2mcX9LodjDjztVcmc+jryGfEp270yOje3UlHJHjUVqybqiF3/Glzh/v/wb/cGHfH8mTq0dqzeZUuLnPgi5JVCl33Hk5Qjz9H4HNz3WXNKjg0n5Bm1XfeblfoF/Hc6442Wo4o7Anhg9x02yqrvz34n6/sGu+wbpof2GeHhsB6OLehtHVw3vVVYx+5bjk1ypShQwTx+6qHbw4ovmZronRqTw/mX0jTlW5I5vhvNmdFo6dCvlelNhNOeoxhKsnQsq5wr9aPN3uWUuSfM85K3uG66mdGH0aV9bx4zRSyd5tYV+pfdHgHY558ZP1/ci7VJ+9J+v7nQ7PWZPaK2jWkl+TOZP2ohXl/scldpgnV8y1Ht+FfpT9fSDsVk9o5z5QUvt+By/GXVzPg16eR6KNnhj+lD44YR4RSG2eyrb6kvq4l43SjTNZLIGQygCEIUYQhAMIQhRhhpgGAMjAbAjYFTGwKgRsBsxsBsojYlsJsS2dBGxbZGxTZRrYtsjYtsIjYps1sU2VUbFNmtimwyxiWG2KbNRotiJRqPYtlFOUEVJ4ToS4ipFVxJ25UliaO9JFWUDrjnRxaUIdCeNFRxodZQowIw6owhCAepqDKQnULcjxg0xqZWTGpnOi0mNTKiYxMzYLSY1MqJjUzOhbTDTKyYaZhFpMamVExqkQWahplaoaZBbTDTKyYxMgfU1vkJqFUiHYbh4mXfiMtjOZyN5HSZK6Eu4ye5g4G80qvcVFFM69vFJKhrttXWxco0LMWVIsfGaRiqtTlSIjFHeF1o7AevBEdFohW68CPPAmkZllREt1vKblqZexLSkRldQYjUFUzoNNF1NqZ001oBrkMAkBkENMSoaRlCGkIBMoEbFVZRYxR3sp5ccZybaqdBvTGhTkF0pu3xNe6hHhMXyo6BFFtmth1la4k9WlUQWVRcnyReS0Y6LiVHBs57a0pNUMLEoMXoZrbNhTJHHrG6GPjHSi7TTjZpdGdVuHw7zLGqaPX7DJ41Nuoh2+PYjpK2J+0P8Pr9hL9oXs9fsa7bG9yM8Lj2IrO6U/aHJuhL7FbL3u4yRa0S9NC+rbGtyC8Pj2IbN3y5dpmy5m3NUSOsg1jjHggqE2hZBgNCIAgRAMMNMAhCEAwhCFRgNAgakEYATYFSjTDKi6lBti6mVAbA1sW2Y2LbNAmxbZjYtsAmxbYLYts2CbFtmNi2wI2LbMbFtlEbFtkbFtmkRsW2RsU2BrYpsjYtsCNimzWxLZYrWxbZGxTZRGxLZrYlsqtbEsJsS2ALESQxsWzrBWlFCqFmQhnWBLMCYJ0R2NQGoruRlThoW0xqZUTGpmLBbTDTKyYaZixFlMamVkxqZjSrKYxMrJhpmRZTGplRMamZsFpMNMrKQaZnQtJhplVMYmZRaTDTK2oNMoshJiFINMiLcObOxh4HIwnWhyRqNLtTaiKh1NKOhukFMOpnQ3SjdCJU2pNDYwSdSwmITDTIHphpleoaZFWKm1EVGRZNIemZxYxRYaxnOtgNGaGboZNJosg3QyaGNGihsOJmhhJUDTZOolhNgMiBLGFx1KpXYplHo649qF1htR57mT6to01MndpDyMpDyOHWW0H69pdM35dtwhtK2VpckcysyJzrzLoWQAgTLDCEIUQhCAYQwgGGGmAQhCGgBhphRoJKg1AIGoDYNSoKplQKg1NAmwKgti2yBtQKi6gVAY2A2LbAcjQJsW5ANgOQDGwGxbYDkbBti2wGxbZoG2LbBbFthlrYtsFsW2VRNi2wWxbZQTYpsxsW2BrYtsFsW2aaa2LbMbFNkGti2zGxbZvQ1sU2Y2LbGhrYpsjYps0I2LbI2KbNwRsU2a2KbOsRjMNMNB1SVBIQOTHJiEORyocmMTFINGaHJlrG0U0PhuOVFuTQFTGYcwyoxMSGiByYxMShiJQ5MYmJQ1EQ1MNMUhhgMTGxYlDY8QOnhOhFlHFuLqOkU5SD1FcYgpyYxMSMQDakqCaA2ptQEEQFU2oBpmqZqGQyaWVzTI6yuoJcBiuoM4ocSNO4rmDDWeBxojkFdZZ8YXWxnLQRkdHrYyvLKtxWMAZqM1AEGozRVJUwg0bQhCGEQhCAQw0wMtIQgVKmVMIaG1BqQwlEqSoJCDamVMMA0hhCwY2BU1gGhKg1ICURsCpoIGNi2wmAaRjYtsIWwMbAqaLKI2A2aAzahbAbCYtlGNgNmgMDGxbYTFsrIWwGzQSgGLYximAtsW2GxbNBbYtsNiwBYpsYKZWi2xbYbFMoFsW2GxbNAGxbYbFMoBsU2GxbNQA2KbDYtnWAQTTDYwhCAf//Z"
}...]

(fwiw, that is the data:url for the gif at https://i.imgur.com/JwIZJYD.gif

@kdenhartog
Copy link
Member Author

I'm not sure we need to test this as a part of the test suite, though? Is there a dereferencing test that would exercise this capability

My intent was to add one to show the usage of service=dogPicService&relativeRef=JwIZJYD.gif parameters since they were at risk. That's the main use case for why those parameters would be used in my mind. I'm sure there's plenty of other ones though.

@kdenhartog
Copy link
Member Author

kdenhartog commented Jun 7, 2021

What is the real-world value-creating interaction that you are trying to enable?

A DID URL that behaves like a PURL.

The IMG tag example above doesn't need the dereferencing API and will likely never use a DID resolver to do the dereferencing.

Certainly, but it requires a DID enabled browser which we don't currently have.

You're basically asking for a non-abstract solution, which is out of scope for DID-Core, IMO.

Agreed. Only reason I'm having to produce a non-abstract solution is because something needs to go in the executions.output.contentStream and to date we've only had JSON objects. Surely a DID URL can point to something other than a JSON object right?

On the other hand, I would love to see a test using a data URL for a service, which returns the image via http (although I still feel that is testing the resolver and not did-core)

Yeah I do think we're quite close to heading into resolver land so saying this must be done in some normative way is incorrect in my eyes. I'm more just heading in the direction of "What do I put in there when the DID URL references an external resource... oh I'll just put an encoded string in there since it at least fits in a JSON object". I suspect others may head in a different direction which is fine until DID Resolution defines how this should work.

@jandrieu
Copy link

jandrieu commented Jun 7, 2021

@kdenhartog wrote

Certainly, but it requires a DID enabled browser which we don't currently have.

To be clear, it only needs an http request library, which are available in just about every language on every platform. You don't need a full browser.

@kdenhartog
Copy link
Member Author

@kdenhartog wrote

Certainly, but it requires a DID enabled browser which we don't currently have.

To be clear, it only needs an http request library, which are available in just about every language on every platform. You don't need a full browser.

While that's true http libraries are really all that is needed, we also don't support DID URLs at the moment either. Hence the need to find a way to transform a DID URL to a HTTP URL when fetching an external resource not contained within the DID Document so that we can glue the two concepts together.

@peacekeeper
Copy link
Contributor

peacekeeper commented Jun 8, 2021

@kdenhartog few comments..

  1. If all we want to do is remove the at-risk markers for service and relativeRef, then I think we don't need to actually test dereferencing DID URLs that have these parameters. It should be sufficient to submit a test report for the did-identifier test suite, which simply tests the syntax (also see my comment verification method IDs MUST contain a fragment did-core#708 about "Separating Identification from Interaction").

  2. Having said that, I fully agree with the DIDs-as-PURLs use case, and I'm excited to see it get implemented! This was the reason for introducing these parameters in the first place.

  3. (Side note: Of course with matrix parameters this would have worked even better, since this would have allowed us to do "partial redirection" with DID PURLs - see slides here for an explanation.)

  4. If in the test suite you want to express that the contentStream contains binary data, I suggest we use hex encoding, to be consistent with the example of resolveRepresentation() that also contains e.g. binary CBOR data: https://github.com/w3c/did-test-suite/blob/main/packages/did-core-test-server/suites/implementations/resolver-example-didwg.json#L131. What do you think about that?

  5. In your example DID URL did:web:kyledenhartog.com?service=dogPicService&relativeRef=JwIZJYD.gif, I would consider the option that the dereference() process may actually NOT return the binary GIF directly - instead it could return something like the following:

{
    "dereferencingMetadata": {
      "resourceUrl": "https://i.imgur.com/JwIZJYD.gif"
    },
    "contentStream": null,
    "contentMetadata": {}
}

Retrieving the binary GIF data would then be a second (purely HTTP based) dereferencing process. This may be more consistent with how today's HTTP-based PURLs work, which redirect you to a resource and trigger a second dereferencing process, rather than returning the resource itself in the first step. But these details are really out of scope for DID Core and we should collaborate on DID Resolution to specify this.

@kdenhartog
Copy link
Member Author

If in the test suite you want to express that the contentStream contains binary data, I suggest we use hex encoding, to be consistent with the example of resolveRepresentation() that also contains e.g. binary CBOR data: https://github.com/w3c/did-test-suite/blob/main/packages/did-core-test-server/suites/implementations/resolver-example-didwg.json#L131. What do you think about that?

Was happy to convert to to hex, but prefer your proposal in number 5 instead. Will go with that.

In your example DID URL did:web:kyledenhartog.com?service=dogPicService&relativeRef=JwIZJYD.gif, I would consider the option that the dereference() process may actually NOT return the binary GIF directly - instead it could return something like the following

I actually way prefer this methodology. Will go in this direction instead and implement the test to behave in that way as well.

Retrieving the binary GIF data would then be a second (purely HTTP based) dereferencing process. This may be more consistent with how today's HTTP-based PURLs work, which redirect you to a resource and trigger a second dereferencing process, rather than returning the resource itself in the first step. But these details are really out of scope for DID Core and we should collaborate on DID Resolution to specify this.

+1 agreed

@kdenhartog
Copy link
Member Author

kdenhartog commented Jun 9, 2021

@peacekeeper in order to comply with a few of the already written tests I had to modify the output to be:

{
            "contentStream": "https://i.imgur.com/KW6NCtG.jpg",
            "dereferencingMetadata": {
                "contentType": "text/url"
            },
            "contentMetadata": {}
}

Does that work for you? My implementation is passing all the tests now with this change.

@peacekeeper
Copy link
Contributor

peacekeeper commented Jun 15, 2021

@kdenhartog yes I like this! You're right, my earlier example was incorrect, since the dereferencing part of the spec says that contentStream MUST contain a resource.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants