From b51a3f8fd8b7b419dd07a7ba6f9ec168cac73928 Mon Sep 17 00:00:00 2001 From: boneyard93501 <4523011+boneyard93501@users.noreply.github.com> Date: Wed, 1 Mar 2023 05:49:23 -0700 Subject: [PATCH] archive old cerramic example --- archived/aqua-ceramic-integration/.gitignore | 5 + archived/aqua-ceramic-integration/README.md | 380 ++++++++++++++++++ .../aqua/ceramic_demo.aqua | 44 ++ .../assets/figure_1.jpg | Bin 0 -> 126629 bytes .../assets/figure_1_code.md | 18 + .../ceramic/schema_id.txt | 85 ++++ .../ceramic/snapshot_schema.json | 15 + .../configs/Config.toml | 17 + .../configs/ceramic_adapter_cfg.json | 8 + .../configs/ceramic_adapter_deploy_cfg.json | 23 ++ .../configs/curl_adapter_cfg.json | 8 + .../aqua-ceramic-integration/scripts/build.sh | 18 + .../services/ceramic-adapter-basic/.gitignore | 5 + .../services/ceramic-adapter-basic/Cargo.toml | 22 + .../ceramic-adapter-basic/src/ceramic_cli.rs | 59 +++ .../ceramic-adapter-basic/src/main.rs | 25 ++ .../ceramic-adapter-custom/.gitignore | 5 + .../ceramic-adapter-custom/Cargo.toml | 22 + .../ceramic-adapter-custom/src/ceramic_cli.rs | 109 +++++ .../src/ceramic_http.rs | 81 ++++ .../ceramic-adapter-custom/src/main.rs | 26 ++ .../services/curl-adapter/Cargo.toml | 21 + .../services/curl-adapter/src/main.rs | 39 ++ 23 files changed, 1035 insertions(+) create mode 100644 archived/aqua-ceramic-integration/.gitignore create mode 100644 archived/aqua-ceramic-integration/README.md create mode 100644 archived/aqua-ceramic-integration/aqua/ceramic_demo.aqua create mode 100644 archived/aqua-ceramic-integration/assets/figure_1.jpg create mode 100644 archived/aqua-ceramic-integration/assets/figure_1_code.md create mode 100644 archived/aqua-ceramic-integration/ceramic/schema_id.txt create mode 100644 archived/aqua-ceramic-integration/ceramic/snapshot_schema.json create mode 100644 archived/aqua-ceramic-integration/configs/Config.toml create mode 100644 archived/aqua-ceramic-integration/configs/ceramic_adapter_cfg.json create mode 100644 archived/aqua-ceramic-integration/configs/ceramic_adapter_deploy_cfg.json create mode 100644 archived/aqua-ceramic-integration/configs/curl_adapter_cfg.json create mode 100755 archived/aqua-ceramic-integration/scripts/build.sh create mode 100644 archived/aqua-ceramic-integration/services/ceramic-adapter-basic/.gitignore create mode 100644 archived/aqua-ceramic-integration/services/ceramic-adapter-basic/Cargo.toml create mode 100644 archived/aqua-ceramic-integration/services/ceramic-adapter-basic/src/ceramic_cli.rs create mode 100644 archived/aqua-ceramic-integration/services/ceramic-adapter-basic/src/main.rs create mode 100644 archived/aqua-ceramic-integration/services/ceramic-adapter-custom/.gitignore create mode 100644 archived/aqua-ceramic-integration/services/ceramic-adapter-custom/Cargo.toml create mode 100644 archived/aqua-ceramic-integration/services/ceramic-adapter-custom/src/ceramic_cli.rs create mode 100644 archived/aqua-ceramic-integration/services/ceramic-adapter-custom/src/ceramic_http.rs create mode 100644 archived/aqua-ceramic-integration/services/ceramic-adapter-custom/src/main.rs create mode 100644 archived/aqua-ceramic-integration/services/curl-adapter/Cargo.toml create mode 100644 archived/aqua-ceramic-integration/services/curl-adapter/src/main.rs diff --git a/archived/aqua-ceramic-integration/.gitignore b/archived/aqua-ceramic-integration/.gitignore new file mode 100644 index 0000000..bbccc88 --- /dev/null +++ b/archived/aqua-ceramic-integration/.gitignore @@ -0,0 +1,5 @@ +debug/ +target/ +Cargo.lock +**/*.bk +**/*.bak diff --git a/archived/aqua-ceramic-integration/README.md b/archived/aqua-ceramic-integration/README.md new file mode 100644 index 0000000..9dafb4d --- /dev/null +++ b/archived/aqua-ceramic-integration/README.md @@ -0,0 +1,380 @@ +# Ceramic Adapter For Fluence And Aqua + +**WIP -- Tread with care.** + +## Overview + +In order to use services available outside the Fluence network, such as [IPFS](https://ipfs.io/) or [Ceramic](https://ceramic.network/), we need to create adapters, which are generally implemented with Wasm modules, that allow us to bridge the Fluence network with many other networks and protocols. Once our adapter services are in place, we can use Aqua to seamlessly integrate such resources into our distributed, peer-to-peer application composition. + +![image](assets/figure_1.jpg) + +In this example, we develop an adapter for the Ceramic [CLI API](https://developers.ceramic.network/build/cli/api/) with the goal of seamlessly integrating Ceramic services into Fluence peer-to-peer applications composed with Aqua. See Figure 1. + +Our adapter service mounts the Ceramic CLI with the [MountedBinaryResult](https://fluence.dev/docs/marine-book/marine-rust-sdk/developing/mounted-binaries) interface requiring the availability of [Ceramic tools](https://developers.ceramic.network/build/cli/installation/) as a sidecar. In addition, a limited Ceramic HTTP API implementation is also available using the Marine [curl adapter](https://fluence.dev/docs/build/tutorials/curl-as-a-service). Since the HTTP API is limited and won't let users create streams, it is offered primarily for educational purposes, although it may be useful in scenarios where a ceramic daemon deployment is not feasible. + +**Please note that Ceramic binary access is currently only available at Fluence's `stage` network environment (`aqua config default_peers stage`) with path `/usr/bin/ceramic`.** + +ToDos: + +- [ ] Refactor CLI adapter for optional built-in deployment +- [ ] Separate HTTP from CLI code +- [ ] Add multimodule tests +- [X] Add use of Aqua demo +- [X] Change fldist to aqua cli + +For another, comprehensive, end-to-end implementation of an adapter, see [Aqua IPFS Library](https://fluence.dev/docs/aqua-book/libraries/aqua-ipfs) and [Aqua IPFS demo](https://github.com/fluencelabs/examples/tree/main/aqua-examples/aqua-ipfs-integration). + +## Ceramic CLI Adapter Module + +You can find the code in the `services/ceramic-adapter-custom/src` directory. Let's have a look at the `ceramic_cli.rs` file. In order for the adapter to work, we need to have the binary, i.e. `ceramic daemon`, available at the host node level, which, in the case of the `stage` network, is at `/usr/bin/ceramic`. + +We start with the general Marine setup of our project and at the end of the file we have our linked binary code using Rust's (FFI) [`extern`](https://doc.rust-lang.org/std/keyword.extern.html): + +```rust +use marine_rs_sdk::{marine, MountedBinaryResult}; + +// + +// mount binary with `extern` +#[marine] +#[link(wasm_import_module = "host")] +extern "C" { + pub fn ceramic(cmd: Vec) -> MountedBinaryResult; +} +``` + +We now can call the ceramic cli binary at the node level with a simple `ceramic(args)` call. The return of the extern `ceramic` call is [MountedBinaryResult](https://github.com/fluencelabs/marine-rs-sdk/blob/2bd0c63a932756f32423a4815fb2dce485abe67a/src/mounted_binary.rs#L27), which we can use as is or map into a more suitable return type. See the `services/ceramic-adapter` directory for an implementation utilizing the `MountedBinaryResult` struct making it suitable for a lower level library or (optional) built-in use. + +For the purpose of ur example, we map the `MountedBinaryResult` into a custom `CeramicResult` with both a `new` and `crate` implementation where the former takes a `MountedBinaryResult` and maps it into `CeramicResult` and the latter creates `CeramicResult` from individual args. + +Let's have a look at `create_stream`: + +```rust +use marine_rs_sdk::{marine, MountedBinaryResult}; + +#[marine] +pub struct CeramicResult { + pub ret_code: i32, + pub stderr: String, + pub stdout: String, +} + +impl CeramicResult { + fn new(mb: MountedBinaryResult) -> Self { + CeramicResult { + ret_code: mb.ret_code, + stderr: String::from_utf8(mb.stderr).unwrap(), + stdout: String::from_utf8(mb.stdout).unwrap(), + } + } + + fn create(ret_code: i32, stdout: String, stderr: String) -> Self { + CeramicResult { + ret_code, + stderr, + stdout, + } + } +} + +// + +#[marine] +pub fn create_stream(payload: String) -> CeramicResult { + let args = vec![ + "create".to_string(), + "tile".to_string(), + "--content".to_string(), + payload, + ]; + let response: MountedBinaryResult = ceramic(args); + if response.stderr.len() > 0 { + return CeramicResult::new(response); + } + let stdout_str: String = String::from_utf8(response.stdout).unwrap(); + + // extract StreamId from formatted response code + if stdout_str.contains("StreamID") { + let res: Vec<&str> = stdout_str.split("\n").collect(); + let stream_id = res[0].replace("StreamID(", "").replace(")", ""); + return CeramicResult::create(response.ret_code, stream_id.to_string(), "".to_string()); + } else { + return CeramicResult::create( + response.ret_code, + "Missing StreamId".to_string(), + "".to_string(), + ); + } +} + +// +``` + +[Creating a stream](https://developers.ceramic.network/build/cli/quick-start/#2-create-a-stream) with the cli, requires the args `ceramic create tile --content` plus some content, e.g., `'{ "Foo": "Bar" }'`, which returns the StreamId and echoes back the formatted content: + +```bash +StreamID(kjzl6cwe1jw147ww5d8pswh1hjh686mut8v1br10dar8l9a3n1wf8z38l0bg8qa) +{ + "Foo": "Bar" +} +``` + +If we just want to return the StreamId as our `CeramicResult.stdout` value so we can easily access and use it in Aqua, we can clean up the raw response string and extract just the StreamId, which we are doing in the code example above. A more generalized solution would use another service to do that extraction as part of the Aqua workflow. Regardless, in this example, the `create_stream` function returns a `CeramicResult` where `stdout` is the StreamId string, if available. See `ceramic_cli.rs` for the remaining [cli wrappers](https://developers.ceramic.network/build/cli/quick-start/) *show*, *state*, *update*, and *create_schema*. + +To build the adapter, run: + +```bash +./scripts/build.sh +``` + +Once the Wasm modules are compiled, we can inspect them with `mrepl`. Make sure you have a local version of [Ceramic CLI](https://developers.ceramic.network/build/cli/installation/#1-install-the-cli) installed and running. + +## Interacting With Adapter Locally + +With the ceramic daemon running, let's start the REPL: + +```bash +mrepl configs/Config.toml +``` + +Before we checkout our handiwork, let's have a look at the `Config.toml` file: + +```toml +modules_dir = "artifacts" # <-- that's where our Wasm modules are + + +[[module]] +name = "curl_adapter" # <-- for the curl adapter which we need for the http adapter +max_heap_size = "100 KiB" +logger_enabled = true + +[module.mounted_binaries] +curl = "/usr/bin/curl" # <-- path to curl on LOCAL machine + + +[[module]] +name = "ceramic_adapter_custom" <-- for the ceramic adapter we are creating +max_heap_size = "50 KiB" +logger_enabled = true + +[module.mounted_binaries] +ceramic = "/xxx/yyy/.nvm/versions/node/v14.16.0/bin/ceramic" # <--replace with your path to ceramic on LOCAL machine +``` + +In our case, we are using two local binaries, `curl` and `ceramic` and we need the local path for each binary, which you get with `which curl` and `which ceramic`, respectively. **Make sure you update the binary paths with your paths**. + +In the REPL, we can now interact with our adapter functions: + +```rust +Welcome to the Marine REPL (version 0.9.1) +Minimal supported versions + sdk: 0.6.0 + interface-types: 0.20.0 + +app service was created with service id = 06431523-4a89-4ea3-bf4b-2e5a5e6b9a78 +elapsed time 100.0461ms + +1> i +Loaded modules interface: +data CeramicResult: + ret_code: i32 + stderr: string + stdout: string +data MountedBinaryResult: + ret_code: i32 + error: string + stdout: []u8 + stderr: []u8 + +ceramic_adapter_custom: + fn update(stream_id: string, payload: string) -> CeramicResult + fn state(stream_id: string) -> CeramicResult + fn create_stream(payload: string) -> CeramicResult + fn http_pins(url: string, port: u32) -> string + fn http_streams(url: string, port: u32, stream_id: string) -> string + fn http_chain_id(url: string, port: u32) -> string + fn http_rm_pin(url: string, port: u32, stream_id: string) -> string + fn http_health(url: string, port: u32) -> string + fn create_schema(schema: string) -> CeramicResult + fn show(stream_id: string) -> CeramicResult + fn http_pin(url: string, port: u32, stream_id: string) -> string + fn ceramic_request(args: []string) -> CeramicResult +curl_adapter: + fn curl_request(cmd: []string) -> MountedBinaryResult +``` + +The `interface` command lists all exposed interfaces and functions corresponding to what we marked public in our Rust code and includes the `http` functions we briefly discussed above. Let's test some functions! + +```rust +2> call ceramic_adapter_custom create_stream ["{\"foo\":\"bar\"}"] +result: Object({"ret_code": Number(0), "stderr": String(""), "stdout": String("kjzl6cwe1jw147gy6h9ygbtzzs0pjg4qyhp4bhx69k88h25e95ads7ybc0aa8sx")}) + elapsed time: 1.510019477s + +3> call ceramic_adapter_custom update ["kjzl6cwe1jw147gy6h9ygbtzzs0pjg4qyhp4bhx69k88h25e95ads7ybc0aa8sx","{\"foo\":\"bar closed\"}"] +result: Object({"ret_code": Number(0), "stderr": String(""), "stdout": String("{\n \"foo\": \"bar closed\"\n}\n")}) + elapsed time: 1.503898936s + +4> call ceramic_adapter_custom show ["kjzl6cwe1jw147gy6h9ygbtzzs0pjg4qyhp4bhx69k88h25e95ads7ybc0aa8sx"] +result: Object({"ret_code": Number(0), "stderr": String(""), "stdout": String("{\n \"foo\": \"bar closed\"\n}\n")}) + elapsed time: 1.37588522s + +5> call ceramic_adapter_custom http_streams ["127.0.0.1", 7007, "kjzl6cwe1jw147gy6h9ygbtzzs0pjg4qyhp4bhx69k88h25e95ads7ybc0aa8sx"] +result: String("{\"streamId\":\"kjzl6cwe1jw147gy6h9ygbtzzs0pjg4qyhp4bhx69k88h25e95ads7ybc0aa8sx\",\"state\":{\"type\":0,\"content\":{\"foo\":\"bar\"},\"metadata\":{\"unique\":\"53BLyT4m2wXSim4y\",\"controllers\":[\"did:key:z6Mkupzc4V3f7RiQCzjxVqqqRXbkmuAdN38oPqATcyWq2HaN\"]},\"signature\":2,\"anchorStatus\":\"PENDING\",\"log\":[{\"cid\":\"bagcqceralapnmkp2h5ok5mdzg6sbusonrpkuo6r2jg67ga5vd3jbzyjhcuiq\",\"type\":0},{\"cid\":\"bagcqceratnh7647bpprjja6pmn6eaeapi2agqxyzdp2lvu2stradj5u7sima\",\"type\":1},{\"cid\":\"bagcqceratxvtlnupnt3cjsr7eob6osksdoatkmlzoyvs3plpitvza2vp244a\",\"type\":1}],\"anchorScheduledFor\":\"2021-10-20T18:00:00.000Z\",\"next\":{\"content\":{\"foo\":\"bar closed\"},\"metadata\":{\"unique\":\"53BLyT4m2wXSim4y\",\"controllers\":[\"did:key:z6Mkupzc4V3f7RiQCzjxVqqqRXbkmuAdN38oPqATcyWq2HaN\"]}},\"doctype\":\"tile\"}}") + elapsed time: 280.67577ms + +6> +``` + +In (2) we call the create stream function and get back the StreamId in the `stdout` key. Copy the SteamId and past it into the `update` command along with new content (3) and then in the `show` command in (4) to verify that our update was successful. In (5) we use one fo the http calls to `show`, also with the above StreamId and the *localhost* and *7007* host and port params, respectively. Notice the much more verbose output. Since we are using the (default) Ceramic testnet, you can see that the anchoring of our stream `"anchorStatus\":\"PENDING\"` is still pending. Give it a few shakes, re-run the command and you should see a block confirmation instead: + +```rust +6> call ceramic_adapter_custom http_streams ["127.0.0.1", 7007, "kjzl6cwe1jw147gy6h9ygbtzzs0pjg4qyhp4bhx69k88h25e95ads7ybc0aa8sx"] +result: String("{\"streamId\":\"kjzl6cwe1jw147gy6h9ygbtzzs0pjg4qyhp4bhx69k88h25e95ads7ybc0aa8sx\",\"state\":{\"type\":0,\"content\":{\"foo\":\"bar closed\"},\"metadata\":{\"unique\":\"53BLyT4m2wXSim4y\",\"controllers\":[\"did:key:z6Mkupzc4V3f7RiQCzjxVqqqRXbkmuAdN38oPqATcyWq2HaN\"]},\"signature\":2,\"anchorStatus\":\"ANCHORED\",\"log\":[{\"cid\":\"bagcqceralapnmkp2h5ok5mdzg6sbusonrpkuo6r2jg67ga5vd3jbzyjhcuiq\",\"type\":0},{\"cid\":\"bagcqceratnh7647bpprjja6pmn6eaeapi2agqxyzdp2lvu2stradj5u7sima\",\"type\":1},{\"cid\":\"bagcqceratxvtlnupnt3cjsr7eob6osksdoatkmlzoyvs3plpitvza2vp244a\",\"type\":1},{\"cid\":\"bafyreifqb3qxuc7pgb7yi67z2b7v5tq62a3nwtr2em5bwl4dmw6yprdnbu\",\"type\":2,\"timestamp\":1634752889}],\"anchorProof\":{\"root\":\"bafyreie3a5rnztmxxjpwpxhatvlfgkv3mp3hdyrfpdwhwzfgwff6snwofi\",\"txHash\":\"bagjqcgzam3yccif57fc6otuo7qtda6d5hkm3wig5ghdjbwjosvogyher5q3q\",\"chainId\":\"eip155:3\",\"blockNumber\":11266361,\"blockTimestamp\":1634752889},\"doctype\":\"tile\"}}") + elapsed time: 20.946101ms +``` + +That is, `...\"chainId\":\"eip155:3\",\"blockNumber\":11266361,\"blockTimestamp\":1634752889}, ...` contains the chain confirmation reference and is readily viewable on [etherscan](https://ropsten.etherscan.io/block/11266361). + +Looks like our services are working and ready for deployment to the `stage` network. We use the `aqua` command line tool to do so: + +```bash +aqua remote deploy_service \ + --addr /dns4/stage.fluence.dev/tcp/19004/wss/p2p/12D3KooWJ4bTHirdTFNZpCS72TAzwtdmavTBkkEXtzo6wHL25CtE \ + --config-path configs/ceramic_adapter_deploy_cfg.json \ + --service ceramic-service \ + --sk +``` + +Which gives us our service id: + +```bash +Going to upload a module... +2022.04.29 12:03:55 [ERROR] created ipfs client to /ip4/134.209.186.43/tcp/5004 +2022.04.29 12:03:55 [ERROR] connected to ipfs +2022.04.29 12:03:55 [ERROR] file uploaded +Going to upload a module... +2022.04.29 12:03:57 [ERROR] created ipfs client to /ip4/134.209.186.43/tcp/5004 +2022.04.29 12:03:57 [ERROR] connected to ipfs +2022.04.29 12:03:57 [ERROR] file uploaded +Now time to make a blueprint... +Blueprint id: +9eda8608af7fdb304b1cbbdd875df3a5a08616bbe9847e74454e1b217c7b4fd4 +And your service id is: +"e9fbfb09-c8b8-447a-b405-5de579b8db6c" # <-- this is different for you +``` + +With our modules deployed and linked into service `e9fbfb09-c8b8-447a-b405-5de579b8db6c`, we are now ready to utilize Ceramic streams from the Fluence network with Aqua. + +## Using the Ceramic Adapter With Aqua + +Now that we have our Ceramic adapter serivce deployed to the Fluence `stage` network, we can use Aqua to make the Ceramic streams functionality available by composition. Let's create a demo Aqua script to illustrate the use. See the `ceramic_demo.aqua` file in the `aqua` directory: + +```aqua +data CeramicResult: + ret_code: i32 + stderr: string + stdout: string + +service CeramicAdapter("service-id"): + ceramic_request(args: []string) -> CeramicResult + create_schema(schema: string) -> CeramicResult + create_stream(payload: string) -> CeramicResult + show(stream_id: string) -> CeramicResult + state(stream_id: string) -> CeramicResult + update(stream_id: string, payload: string) -> CeramicResult + +-- aqua function to create stream and return stream id +func create(payload:string, node:string, service_id:string) -> string: + on node: + CeramicAdapter service_id + create_res <- CeramicAdapter.create_stream(payload) + <- create_res.stdout + +-- aqua function to create stream and return CeramicResult +func create_obj(payload:string, node:string, service_id:string) -> CeramicResult: + on node: + CeramicAdapter service_id + create_res <- CeramicAdapter.create_stream(payload) + <- create_res + +-- aqua function to create stream, show, update and return stream id, show and update as stdout strings +func roundtrip(payload:string, payload_two: string, node:string, service_id:string) -> string, string, string: + on node: + CeramicAdapter service_id + create_res <- CeramicAdapter.create_stream(payload) --< return the stream_id in stdout + show_res <- CeramicAdapter.show(create_res.stdout) --< + update_res <- CeramicAdapter.update(create_res.stdout, payload_two) + <- create_res.stdout, show_res.stdout, update_res.stdout +``` + +We created three Aqua demo functions and used marine to export all interfaces to our aqua file before we added our code with `marine aqua artifacts/ceramic_adapter_custom.wasm >> aqua/ceramic_demo.aqua`.: + +- `func create(payload:string, node:string, service_id:string) -> string:` shows how to create a stream and return only the StreamId as a string +- `func create_obj(payload:string, node:string, service_id:string) -> CeramicResult:` shows how to create a stream and return the `CeramicResult` struct +- `func roundtrip(payload:string, payload_two: string, node:string, service_id:string) -> string, string, string: + on node:` show how to create and update a stream, save intermittent results and return the triple (stream_id, show result before update, show result after update) + + + +We continue to use `aqua` cli to run our Aqua scripts. First, let's run our simple `create` which returns the StreamId as a string: + +```bash +aqua run -i aqua \ + --addr /dns4/stage.fluence.dev/tcp/19004/wss/p2p/12D3KooWJ4bTHirdTFNZpCS72TAzwtdmavTBkkEXtzo6wHL25CtE \ + -f'create(arg, "12D3KooWJ4bTHirdTFNZpCS72TAzwtdmavTBkkEXtzo6wHL25CtE", "e9fbfb09-c8b8-447a-b405-5de579b8db6c")' \ + -d '{"arg": "{\"foo\":\"bar\"}" + }' +``` + +Returns: + +```bash +Your peerId: 12D3KooWKgpdZo2xVDYQ9MPqT3tMQwgo2zWQFWNtVPYWyhLN5kK5 +"kjzl6cwe1jw145d1ks7ubujk6hxc8em4n3z65may2mc9b321wep8hci0eprrpo3" +``` + +Now, we run the same functionality but with the `CeramicResult` as the return value: + +```bash +aqua run -i aqua \ + --addr /dns4/stage.fluence.dev/tcp/19004/wss/p2p/12D3KooWJ4bTHirdTFNZpCS72TAzwtdmavTBkkEXtzo6wHL25CtE \ + -f'create_obj(arg, "12D3KooWJ4bTHirdTFNZpCS72TAzwtdmavTBkkEXtzo6wHL25CtE", "e9fbfb09-c8b8-447a-b405-5de579b8db6c")' \ + -d '{"arg": "{\"foo\":\"bar\"}" + }' +``` + +Which returns the `CeramicResult` object: + +```bash +Your peerId: 12D3KooWLsy44ycUSiQzEDX9PNZW3XEpLmAcLMaKxCZHqJKhu2Uc +{ + "ret_code": 0, + "stderr": "", + "stdout": "kjzl6cwe1jw1485qhhhjzpua7cc7xq03qqi2z0w93e12qc1w8sob78o2pebdvef" +} +``` + +This allows us to access members with the dot notation, e.g, CeramicResultObj.stderr. Finally, we run our roundtrip function where we create, update and show: + +```bash +aqua run -i aqua \ + --addr /dns4/stage.fluence.dev/tcp/19004/wss/p2p/12D3KooWJ4bTHirdTFNZpCS72TAzwtdmavTBkkEXtzo6wHL25CtE \ + -f'roundtrip(arg, arg_2, "12D3KooWJ4bTHirdTFNZpCS72TAzwtdmavTBkkEXtzo6wHL25CtE", "e9fbfb09-c8b8-447a-b405-5de579b8db6c")' \ + -d '{"arg": "{\"foo\":\"bar open\"}", "arg_2":"{\"foo\":\"bar closed\"}"}' +``` + +Which returns the triple: + +```bash +Your peerId: 12D3KooWDvsgbe7MByxPkCwLU96kLcaq3Fyyc15w8SpZf6ELwtAW +[ +"kjzl6cwe1jw149tb39f0fe8bmig9kfi49ih2wuf09eslamxb4hckwgrfk2ivox9", +"{\n \"foo\": \"bar open\"\n}\n", +"{\n \"foo\": \"bar closed\"\n}\n" +] +``` + +## Summary + +We created a distributed adapter service allowing us not only to bring decentralized store to Fluence's decentralized compute but also to seamlessly integrate that functionality into any composition with Aqua. We further demonstrated the use of Ceramic with Aqua. While the project is still work in progress, feel free to use and share any issues or improvement requests in *Issues*. + diff --git a/archived/aqua-ceramic-integration/aqua/ceramic_demo.aqua b/archived/aqua-ceramic-integration/aqua/ceramic_demo.aqua new file mode 100644 index 0000000..d2c4d88 --- /dev/null +++ b/archived/aqua-ceramic-integration/aqua/ceramic_demo.aqua @@ -0,0 +1,44 @@ +data CeramicResult: + ret_code: i32 + stderr: string + stdout: string + +service CeramicAdapter("service-id"): + ceramic_request(args: []string) -> CeramicResult + create_schema(schema: string) -> CeramicResult + create_stream(payload: string) -> CeramicResult + show(stream_id: string) -> CeramicResult + state(stream_id: string) -> CeramicResult + update(stream_id: string, payload: string) -> CeramicResult + + http_streams(url:string, port: u32, stream_id:string) -> string + +-- aqua function to create stream and return stream id +func create(payload:string, node:string, service_id:string) -> string: + on node: + CeramicAdapter service_id + create_res <- CeramicAdapter.create_stream(payload) + <- create_res.stdout + +-- aqua function to create stream and return CeramicResult +func create_obj(payload:string, node:string, service_id:string) -> CeramicResult: + on node: + CeramicAdapter service_id + create_res <- CeramicAdapter.create_stream(payload) + <- create_res + +-- aqua function to create stream, show, update and return stream id, show and update as stdout strings +func roundtrip(payload:string, payload_two: string, node:string, service_id:string) -> string, string, string: + on node: + CeramicAdapter service_id + create_res <- CeramicAdapter.create_stream(payload) --< return the stream_id in stdout + show_res <- CeramicAdapter.show(create_res.stdout) --< use the stream_id + update_res <- CeramicAdapter.update(create_res.stdout, payload_two) --< update the stream + <- create_res.stdout, show_res.stdout, update_res.stdout --< return the stream id, the show result, show result afer update + + +func http_show_stream(stream_id: string, node: string, service_id:string) -> string: + on node: + CeramicAdapter service_id + res <- CeramicAdapter.http_streams("127.0.0.1", 7007, stream_id) + <- res \ No newline at end of file diff --git a/archived/aqua-ceramic-integration/assets/figure_1.jpg b/archived/aqua-ceramic-integration/assets/figure_1.jpg new file mode 100644 index 0000000000000000000000000000000000000000..da6b3f5c485e9675162ba59f2a947348fd949a4e GIT binary patch literal 126629 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 z zyrpz2>0B&)EXK|7dME5~rJL8jk-|T1R3aRqkm+5cRSQg|NSPI9lWPr@2@_UVDlVVh z*^djLqKfrqClbp5(Kc^AuT{3)tr!EF5`KU6@(0m}!5&A;YdtQO zBUhZm__t?AI`OcOMlN7_uU1JwoJP&)pYc#uRr!`&vaJcYcc}OzPwR}jk~RmQP~_oQ z(@c5I>JDzEjjG*>9;cdWQ$zzeD?wA;a7y$!&ASo&Cm(3HsZ$9yTH`xc(FF*-qe_Rkdw(@X5a|IFTij=yLpAAGwTO^u6s#c&NxboPpEF4?@w&va7 zwaDZRKkgpahe8Q^QwnsXI~3X~?oCHeaL`sLKnA6ku?NQPNhK{kSU<6*n;*ENOSC(x1Tu-jGaPXqSEluj+^m;X5iM~fj#e_vy zy?326X{LqpOdxm%vTzKkUJo&~fvxW6(#I`2xd-Fft_aE+M98Q=m&0fq-a^{O-GR>K zDa&Sghw8Jw?+A0dzr*%r7mz>uQe+W)&)#jdslqNol)>LRV-&?q>W7dwI0G$DiO2@- zJSVvnavJBnoVRJC1Dc@Qal>JoO~=3TmsMHd%9@Zt=@fWsyh$MOOs>P@%t~J-)eIN0 z8uKor7u5^RebF8r{%8CNy`V=h5b-#;6&yrj z!^u{^ktN8~vuIZd=!=Q-J$=D4=%qT`N}uiiFc!Xv#-L+W`4N^!6{Q}4T2>>iE1qO6xZvYv6+9`x8 zZnq|HoDeI*#ibi_Do1-G{XpsYG)5gfiVyMX9(JCb6sanX zl<)d%#1%S~5FKX(!B)SpKGZ_^6F%U2CJFHqlPz}lZG}IX^(^mt_Mf?NES`PRou{v; zxw+Rr39z$yj1!9Xrvp%oNKR!wn?ffm?m^KKGo>n%q)`WqMk1p_>cuJa1(S)-8>;xuqrwX=kTbMeF4tzIy(mq}5i@kDIoo-^&` zPYu#pp9#K~YRvVN^lD;9M=3g}6^UZ_b=08&Aqx23w@~o8 zjp&rv)S~MJwPfUp3u*P%cb{JEQF@XsdvmU{1s2W*twaN>5YVe&>f1{{Mer!I@{T|G zP1{$FM&>>-@!XlupiX+xH22PR=Zye_KmnokI(}z8m3f-?lbDNWaoO{l7j$eI*9s^- z)7q){87b9xnc^kL2v@TVJ6v_laiMSiuEgF4hT>Chw=YaETqFn?SIf^( zD%)Z7RL9pEWJ`$Zp_b=aEu+3-+&9bA$fVA7dUQIGLX?q*st6WBZlOjA0XX{}SXC6X z6h?W;nA;1#IA8kBC{6P^OT_8zQdd)gB(A6}C8XwwY#Hs+7|-b;=j@cBYbV3kUd5}j z#PLlW<3cUKv%y?jK7ulc55SH{^R|2lZ7X7~M9o(dNZZRPoE>wiP%{Xynrz|@K`b4L zn=S(g8~e^Q31AaoV;$X{!8D@o9oR=a*pxAGIZkV%oO!|6lNwv^qt~SDUr!jC>kJ^B z_4YsrVEuSzZV!%NpPEjEO0I{k^H3{TO^v!n`=3Ne69TfA>ZqcLD)vR69ad4+EG-GU z_cT7|$&p_;Fgk(bJ0MQU&AG>{ovH%8;uNm1Ft@-_L`lOyH4({BXZ#``@0POVDG5Gvh zyL=*3>B`)E$7`S&)^cr>O^)h{DB4x=Wis6dXuQ8$W@185#{i{tT;vuq(w~VCg}XdQ z)r3Z+oQ&^oldF@Npr2G+_r^Bpr1zToU6HCoU1EzB**yUp_uYM*(Js^xPdI+X+2W%M z-NNVl(yY_A7ZyK?o2Ru)r@LFdz=FxVwK@;3n1Q2Zx;#`=X^Y^W*XE}RDkiiALK-jS z&wEgDOlXmx)XoGi7GbEGXQE*h)u>DYRJ%6mHc9SVlCfejg^t}YeT(+!Z0O-KztNO? zt(7`T{~Oz!S3t2UCs7HIR^1*Uqi50&9OAX{?FjOH>E+c8aW~@;#0do>Y#wG?dZ%6s zGe~Y7TY9||BfdIm*->0{evOZxQu%Z&p^JUR;rM1J##U+q*{r9^ZMh7=Z@9l=sr)kZ zxb<L9}^R;)V_xmpgUB`{BMd9K%SFpl_w|?#q(9R=tYcj0# z(3H4|PHBtlA-8Lfu_QYx7p{|`JsK=$XHF0f)!*UJF)~G#_E+mW(;R)+lLXJZM6Xl7;U>Tj@Aq969I?S3DkeK(DHD8c$&f`J4KK#TKw2nEc@}mul7|SMB*Xc zZBre5{cbQio_b=|J28_nks?^{q36}bfu}UwD=!BTKC?5S5S*bz_(55l%H5&XYIzbQ zK&-TiL!*IFKG~s(3L&no+0@T}QUQb3Ci3Arn^eh$tI_}&M}g`@Ukn$j$|*sOU1e(W zMNOBEf^%OdUbc^TnLvYc$Fv`n7U7v%%sgv-?=@P;%b$w75Y2dr?NV_U4ZjFu=1a^I zRdPZNun*Ee))r@V`)Q|g09h}8^7;h*chU2Z{^~|a#q`;)rz|#Bsqj&={VlLi9$_4^ z?ThPmTv_CO+4@>p?J5)2ttnn3BbtWe=Pt$O$xZo^pc9M70{}~K&azq28y}Z+rqc-* zxYU!og#|8x5Qp!M0~2_0u^kNL{tTUK$v9oiNMn&Rd^YWJ>nB>h8)|o|j2?P$hEB14 zoaifTe)9P`7yHHidX2%IG^O2_gxC4N+Q$xL`Fc)!iqG~8VV0NZ%o1}xRTfaR>YvD@ z?)pfJn8oisgjHGb6R2=D?TuVR#4}~yN;(-@pKg_e6nkPQD#-({2y(};^OJeT#Y_3* z;P;xKK`>^kQCA2-S8p`GJmzem5B97_jKZxggW?dXJ>63uunB4qK2jU<1W{~u1su+! z3NRuHRQXylv`ICM^?~ihi4tOTWzur{w&J#1UX&n_b96a@^bY~rl5V|j4i4Hzi;v5n zBD@HBLt?xkFr_tn%b#Ue2nB!*XOV#^dqGHh6occ0OHsk4`>W1tiDJC5<}GL97c>n& zM6h?=o{yb!|5OFFM+I@(H^D*_p{?~a8pFE<_t5pUHEZ$-+@C(gzH)B~)HwkHc&8qJ zmNn)N?C76igZWG4;b-_B!KqIicbwwY7yWT&ZW#yp)H62E|dlXwr3JtH? zmDPR&M6+0gh)n&v+P9;fXJ1>Q8$JB=9}r6eNr^9kHU0W`(0Dbgl!IK#Ldco#prjPf z3b$x*shy+9x)Y$;r+&x*95n5F2r&E@hBCOzomnvrv%>1&x0bs4?V}3#;Dvqg`SVYI zOIAHSS`~ATOZHYo7OB4?!IRqV-E-DQ{CAWMwR3{{S%yO6Q7VU$+1pnmN#2e8$mVNk z2MKl#X9SPT45g`p5`8q;`j$1sW3iUu1yJI-n63J}YyuJtVkT># zL3tX*lB4(6bDY)1ve^XYBkgtAd$`1ljZnN#-7Q*FHX|2j@%AC5CVtfw`5zl!doY1} zWN!^Cd(HZtg~}V@Srcua_pL;IK5OA;*_6pp8o58zhOR=dj?Edg8WO^?EV}Yt6Y?yO zPS-46Qk)v6d0Fk0Z9(LC`vqW&Wu5Vb4T zTngAo&;c!AQtC>BV8;pOVrST=ish;eYvL$p1siI4pO<9b?A8^b11ZwIZ3)y$^zWQL zj)y!UQ7$=Rh3WIq7~1-olgn~BEOJ{;2{PTMZhkCpGf+%7+5}(iz(H3(ApNi+`hYUJ zQ21mgN#d=m^tGx}ei`b6kTU`0m85gb0TDU-u`H2c1|vJYe<*?YTS>(q{ol`(N&iKc z_#ZIex02h-f*@eki_6KXCkbJBVmn2qu7QtKEk|-1?%oz?7RC-GTDOXbs~^byh%ER| zeX&_|8;T$VYe!NLZww$LvuI0vn@ML!*6y3Mv9juW2)=N2m+IJ@nLI;5PTfAfS1ii5 z@k+pC_r}WZm7^D~QuheXnc~RB!~&rBsFB$2$ED#Gk0=DRhuKyOH)+i07GAP@GFhJg z4w^Z8-#-zZ_gi&T?pbq*KbN;(*LP4xszx2;8R<@0*0)RsXln*o`Pl4Hc8e9q;I>{6 z?NORFMIO~P@HsY?&wr)=|3@dlKl{9&J7IqD8~z7OnBQ%XKTe6iDW3DwPFX*m!hZUR z>lZrr&kQ^(6MPY-1BKI?>wAqCftA+{i&mEL>$uui^dS{B!kxD`*aDkgrl(0c93K%b z>-`R*`>jGu?^L%F8iR2Kd!t%UE?*1eI{bD9ZfDBCsw1bnK>Y#hmK`t?9e1F_9M{XK z$3&%N@UiLZNgr}Qhhy6&l2{22g3a7ss4LM1D?-@rgmYFqDZ}PIq+oSN#j+bJUc_Zfsb83iHf$;XdV1~&-#g}G1A`jOAj9AN zJVc&quwiTMKjt0Od2^y_^)Y3ddx1*%#h6^yZx)$%sc(Gl(3UwiVF*(u@a;au>4!Ix zo00~2L;%2miQ2nJ9eXx$mutra9Y8%gwcT&HF6HU)+Q_c?a{}2MW&`ZlC_IoWy);o( zY?2gTE@KB2BePlVaJc21K1scy#`WlLEbo7)aAI=i%#Rc4XaD`vC+aUW^Pe|SS@6k3 zW-5~2%?_wJfv;4LxXPLM%r8QAD+}FJKGCR&khl|oNW_o;QgVD6Ng?s zJhVdq-Fm=?VP59?tw5=Vv?_%rgQQasoo~GW`q@>;ahL$^XY~U0E ziqCHWfA+dfNXsQ^;>G4W&~rx&a1pJB6yfbVLmlm+<931Ex^SU5)>1E@+3Ju?LNsP7Hoo zVp7-^Gv}k#B$F`^zpgXW)xow3&BpuXQi1za@j86GBY^h6*r69;Z09uy@o?kn zn^_7XzX^*RicRWw2M#`WoS8aemd2mM$#$ zY!BPX-fVU%xpVASs6hY_z}!ZME_eb4;H4@wqwuJ93v-iJW#OqUEC+R zT2+f^78_$mI|GVtarM2jalmSZv4IP~TVY_UOIRf9GLOs~-1fYYdm#TDh<2 z;)Z6Cs0PVHD})B&Ly`LZbWXf@21`|N#Dg*=9rhY3gqoe!`XoBP48)Gc8R|0=Qd=Mu z-A*K?k&R08jkQ#E(n!9=2e@j-Of918g*nyf=-IIz9>q#R|Dhm)2g+H6ia6MaLfpg@ zaaoG@bsMBR0?g)3g3sm@|BZhB8J^^n4T(4E1XbwREg=f!-gJ=UdZ;JzA9&W zI~wOE9SI^{L+vKv^`9W$D0|G7MNdoOwIV*v@sCzox^cwDorU(E6-xDzDi7LpXRK!U zD*2Sc7uJRfpJ7C39IC+&VC|^LMqz@6^P{JFbLYeu=O5Y7y>md|$??v{H{^AzI@YFb zg!S@Qp+kELUA!$ffRmYb!ou|MbaZ%a)ZLo~yl47|@M=7AH3PpghmKa|CSE7dAami5 zH-d?>u5;aoewICkeP=XLJsfuQT%uuokEPabNDo}bweFf6z4CxYAej)B_?AT-DZp^C zcj4(+-Th{4EIfd-qX=~CPF$Ary1!NNb<8o0l^Cvfv%Df@QteS5HAiP^a}vrLc9!*(BPx`=Q2mvP2y*C zVZ!KSCr-^1&mX)yrpf%!N@!MMJPg~rxcUJL8PCSZ9O#u)(w@RqXTyb_$D?14iC4rO zHnTqyCT}ZdK}~m1Rr-INfUKF!35zwb;mf<#f?5t35_mFld-Fc>HzetL-ipaR^PFWf zfa641o(Z7*TKTsCvm&7=lGZ+Sr3)!(+52GdI|w+m3LW`?7evZv0Tq^(kCxXLB85vY zUHaLU^*_G<&$h4sWnS{HB_T#)S~rF&eK~gY%$B)CL~cp-KXgCaPN)6e^h=kK;Z#E8 zy@bN0y4^(kQim}~tEGdO1{2TZ3m3fe13kc}!&^g5Zm^$frmUrr`D;Azzxw!pW%T}P zdjE~+-9qh_AC<5DhKl6U%5@;IH;%}*+Jpssf%QyS)Ncn7*8rr@KKSmUz{b(ca#F1w zBRy``P8TY7C+C%|l8%A)s-npSR4M>-dDlSo9drrOh9nB+0y2-!kgX5B!K7d)z@H}Q z>3#=wiu~phhM6I_NF4hP8VJKf01VJ;Bw-$co3a9!F|WWFD2eIDcM$&L;nheGp@zg2 z)r8zWL(~Gc2PYUwL5nEQ_5_fXxJ&@rhQY&VqFdvqtS72s0BHq-gB(#KPXYbTlw?37 z(-44>x6eWkPLlY53zL=j4mw>{S&#{iLjJnSUt{@a$E9U|3pn~fs6&Etx#qEW1csjF z(WJJq#@P14(DY@=`#x8D+FMqYQ1?-02lsv~lm18Nz(&hmgV{tl@W-^|XaD`P)1F_j zl)tfY{7FotKiY@+Us?3~e+4(OiR2`D5EO7&V@s+|f62jZF^w$K_L8+v8uHJ+hWG_9 zI-Xa%*xX!N)I1FZ0GTQZJ4iD4for%Z7AdY%Ia#oNL%zeaHYOE*XOW5$eHIDl+6XrD zS{r<2Npz18#JLgfok7HFD1S5!>5BSVO?mUM$8S0fo_O?9*>x5Yf@D<{Lp&hB@|Qi4 zl$9!{&D&3Rz_yD%4bXa@?CYDKzBI4gVtQ)x&^;1#)R(6m*KtdGxxR1YLx;|)ik`n> z@1c+XC$oED&Um;Ht}`&TnT_p4r*6>Ao26no#Vj*=<;}5Gl-8o;AyTLg8&mdgz zWouqIY&(puu#Cfw1o^}=qvB+@qn9(^wLJ$xg9-OQy$8`$BWb)%XPLaeOg8ZS5|EQ|mfIWUAf+#zu zfZ$RMcJz66dC*A4#Aj(Htqyoe#f9sBP5}n-GE27d-E{T^=wkrkjpB==m zPU`A2E{&#CwOwc>FS={ip{3obdC!shjOMDg^d$4Kov;Z1b3`Z(8Tm+poRDl9+G&oL zE_al36Af8^K~2Y8C>6~L@s6#Uu6&z)Ua7F+r7%BPn|r`YyT6oo6h^Kd56AScrUFdG z!O6?7SM+>UT1>OGK-O*%n@IRG$cYRYY~>rCjrR_nqiwNg#htLu&fRLTVaTj zkFr{cr5y{=b5@Ayxqj@CW^!5S&3jy_t7@Yf%Zo1xd&55;C7Wai2DP z{l(>E&2Yu)PqhkE>Cwz#VC=5 z{Vi1PL%@x7`9$6~%3~{l8ysN~?}gC{&mpwqvUj`Q;N-*YaJlaj7c%_vQ*Rz+!{S`A2Hu+B3)C7QN&G=lSH~gsoGgfzKM?_~${L|!ZFgaf4#%sq#KH;VdUA(ah zEL*VE`MIOVog|tayok>GAqlaKJWKcPs-)>FX?v5ImTwaoCQ-+aCwxL%0jI`i$h%y$ zYtp-Sa2m0>uClp3#$#mK_Ayy;;0e2nc6X?;=^EbtaoJ8Q03l9zRJP`AEvLJ;@|Bu< zY^)1z@^eueY(%fxu-yl^>6AhU5S^C1weqO z^aUyh!$&XOmMTVZL~D2GO@^PSB?HqTEbyJJ8RPct8RZ@Mxc;^+LJrblQl-t)#raI- z`=`k-x{TcnDx4>BPv6-%E_;a80Qoa7PsqnK9LH_#-Xj3CKXT}q^DTF|AaaQB_vG$b3R`5i96T0#%iFvdtgWAc8Ep`}CVwv0@Y8PD+ z=X;nI#k*y&cJElIXF?FHjmW8f&oo8HHtsu=XX`{ z+TX#%=lo{~rn;}E1~pi^w0{pb_-pvVpZoYPKCSwHY1tcop+B7uRARnbMv>}th%4p4 zw;D7i^ke%+{y(w1w!b$zknjH@j?2mi@7~tP15mp+Wc!(&jO&boC3p^_YK_^OzdV(f z&QYCNmlB zJ&(_sOdmchGy=5R5Hv286z0kRaK|TxfD+W$IiV~=D=#4NL(a(`F-&s<%-bq}{mGq8 zVg>41t_R!=O5Z_2aD9@J8c&3V&kPZ$V+GG_D|rL2p&ZR1dZGw`k}3`Qnr4AO{31w({7wXC`UDN6ZlP0Bh}< zFeJ{|5vaa7{MTz7p!#)*zee#_EdH7Ht7b^Wz^CJ^_2obf3 z9D7Q-3#5P9-$8LC{ew+NkBJo<(Ekg0R`)08e}5#0{K-7$e*kapXjDWf00l`jS#Os2 zie}ZQ80!^>kQV<%ZD#b=IuMs1c8ML_#B z@~f@A^ZT)Grp*UM!YGhCALmgxeufy8@EwGPkb*_>0n1I)Md(UA@{FZa9Q}c1 zfEalc47C#@TWM(o%pEfQxdMvKobb7sW5qlQs=f1fDh1VEVWdQ?2g>6a=>4z&OgQXN z>N{vqegKMNM#cbK3U@}t{9peYg6l$7NE|Ww0lmj#T748JDM|6OH%1;ejk`0ob82%3TjA=u#RF(;8>>0EDc`|saQKHOy|z7oDM z?*)4BaB?Wa?BK*Zc*Z_t4S-XA2g#QE9ZD{N}|_ACts zXkh_{zFXTujs{W+olekd;^pt4>#)7H45Fpy(WSDd++SE)kj{iK(o6J41e8$syJtWP zj5g_&(*E94AO=NWIlYwXM1o0^c<_+|a)uF!fAr%!s=hMml3Dk9WI}UPgMl2leFru2 z1E}_IKR(|NxDv;y^>3w2hpuhVZ6NDG=zIsY5B~lY2O%)tp<35Y1D?=vz0l|rUi9?J&N&F4)iD&-kb$uDM5ZavyM=o`f2tZ~S zmHqp#vU8$QJ>R`P>z)1@`s8=eQ1TI82vC>P`rS*GSr9?j7rlTx_~T`ue*cQ$^ZS%( zed~X9;pT6~Hb~?2rTM3o#JTS3Fw9lqwCUK>85Dy?^KNs#)e8VPv@9L}7Cz%Yq+!{@ z74vs3>y#hvS6stfeEO2CjVaz2bWE@o4SdrB)BlJek0D)}8#z8nO@B9XJj(v|X#DOr zqW;Zcyz(Pz#`VV=TpZ?iSMRQhLsd=MX)A35RE1+dELCA~w5D}Vh)SfY(7~~E@wMUK zi=)xsCY;#+v^n_)WB;v;rRffTl2Uk^7wamkTK@UVbVU*f$mJoH8jD2UIUx=gAU<#X z6*KX{rZ?(lZCuV!c8%_XcEdcnp1JGt*4iMRFK{OrA)~`gFXq3qw0I2u?1}gPbEy4a zf`Z-;3#!Lch$&|)T)m`WA?kz3+g)euQSl z^&f1r#r{A_V)k!MTK?EL{VT~q^|s|*_+HYdP1#t?$+G7kguji0qBk#SQY#cM-&ww- z+GW?*Of*um-@XV;_D8Spb${>atFSGeC;JuDYEeKpPp9#Oy>OupQ|9jd~_sFY6P(T8Y;HN=tzGOzzu+bzk{;U z%SEPIkd)9dL)}auff`WzC;HgOa_3O{)XT7S;N&4x`tjWi9kNRcpbB`-?5lVhVQtXS zBv`!cZ+D0MM}REL{9_ZMw+7Ijm9~0qWs-~R42Ge$WS8w`=o(=Kxo=+q(Cf^9<~n}2 zp#m%=l8XKz9-t(^O`MXlfqR^P1bo)EY+>xTf_0SPZ+GSDKYLdc%2<$HiV_D0K|uGG zCBU2nXudps1l!r6B87^Oy)S0NnG`Wss{>bV2yF2N|MZW^Bk(?b|96npYoKdfb)%?` ziWs^GfE;cCoQ#QbKsMAWM9aMfxb!CB?*IenCk1+8#sn+mKB@2U8q|pv-L=KmJGoM! z^mZe%=5J#ut{|~{`oLAb`wlA6HG~k3fFAqGI&|go_<_``+9er74a7JwCjb0!{K>DO z62N4j^8nrHRv;?!izCPI`ZGhw6@WgoeREX9_qqOT=fU#1M?g^2QUBe@ICqTdRj=6Z zbgdk{ZAh0ClMkx_L)G6f7p;)ZQ^V*lH6(q@MDNcVSZMOs7=S)ms{T7PijP$y5SXX@ zp*>@TCW%Wh{2UvW*!%c}SF1$w^11sCz*PKp@-LIduv7HL`equ;hS@oXyI3(OHu$jt z`LkPYy3A*;l@@RWieo5EV?iA2`s&j;nPidI0=22)Mw9+4=;j;^$QF0b;fGR0tis)7 zuV>4L?Agw|Yu3Z3AMt&9!k?8LfBV%5I}f#_Vzo*faC`HD>vJb zpE@uXBAd$K6hxNgcCn|xm<<0*%YxCD(!0j(YesjK6xE}Bwbfy-F)Dh^mT=82- zOY$qjDFCAsi8}%P4zMKt+mp+F9#Cd*lL%!ZEY9*nImN!#<8eaSnj7O2;aDhMfjXN>Aa1Qk9k^wCVUBM;q}2fWt}+aD-VuI_GoHlkYR ztd8I!_LNB6@DqiyyapY|hse1v#w~-&AJ*@eo{5m6T#T19;^03P|2QFXe%C8C0T%WY zk_Ihj>oCutAzlO=(de~u1$tCf00RsU!OWp&zL&F53PyK7UrBd;5vVIZeHE95H zLRsKY+IvG2r-K))$CX_htIS{|+~vOhk@hWX&B+*nns+{WMbAy8nr-ingOE(;bq-~S z2*RYqnuI%EU%e7%fo6S#qSu=13e9DBMc**N{;ZXvbuxb02ov1bEO$>+asw0@{?U;? z35|pHfE_-42f@KnR**UzG~8bXAytJ#2l}6Nl2f!wE%>~0iFBx2J3@Is`DV2op4=22 zGuRc3!+KHC1Fu4&{Dp>9gh%CcN1w!MjsamE8N2|B*YX!Cm6$xM5X z`&#UhF+H&3tqsQy<=~w8;RuSXR^Uq_o8;@bk7C9miKefo&1NQbxMMlhbDQCAc8=>g zmV;d@)eO-kqm8u$7F>4cG(B#wvm3(bh_uP*K%Z4iEFd6 z;iHd#=FwrQcJ`&ERyJ~Mij%#rb1mq#ci3fusWr}|MHd6*Am082Gk-heK|5$~mwVg1 zgL45snHYQNiW?JWp}6HUER|E0DfB*!k-#)J79)#_fiY}6l3@3~Z2V?WtkO^QUTp=Q zV!Bk?`Y6pCpH<%F<d)b zE^SwelHrnvr$>{)XDZ_`&*q19lGu%e_)GWNXM!M=Gi#S|Hf>`NMj2;mt>HD|&0IoI zb0bAvZB6>c)$JVbh3dw}8ZI77b-|}|FXE+G+@4eqrQ|jM*)wHWowx386d^mCcneq4 zf}S|ul*!&Q5gMbK)HkZ z9Te=!kc!b~Ug5L{4F1&J>-zMJt+{$~+)Ce4eIDn!9eVnS$l^@k%(2`ItbGX4Jd4zK zAm4mM)hapl#mOu**WI-0!aWOLm%V`kkgmWn2t<`0 z4h3(&S94SxQfbW2nyHzp8Q$JE_PvJ?ImM-T-;Mc=F+Z6ai*8zTz*gT|VDe8MW!U0q z9aTB1-+v-{xYG99U^8l_xvgbmYR#9@?A6am5!WEJfu7D6t@~Ewc+TP$*EDd4*9aj< zNQ6g>{46@$dc^haO{co(H~M7V;)4mNQeDhlzwl$L9N{oVq{|Ekfpulhqo%n_SrSWs zb!5A~jH4#JxG&09;3m_u@!%D!Z`D%xE60`Z-+JSmd%Xu%(b)#2CmQ2aMp7*a3EH@s zmKgh%vAUz3ug<^8-0Co$iM#i_@7lcSo^>46M~geRCZN`y#}f$;4|Pll`m@Q+;A02| z9GQi828K2Hp?J{T>m5gm(8T=DYyc9uSJUC^vyPzkdD^aVqpu*}pu;=2aVv92E?X12C26GGZ#tJv;FZ{`ScV{Ow1)fSI^US?D{{9_B?$x}R z(P`iaHy8G5l~aGs9q-?N3oy3?htJSD6Xju(fhOYQ4-M|-`xhQM0V=Yb|$?+S}#4WilhdPjQNdv=kHZSH@n)AKP{xT zkA9J7C%KjoQ#(f7jj*dIkDSoe5%W6A zwH13;v^pN5yeaLOEQQ|5M1g?#jW8#Q))9hmWHVT}S|gPo(u_1NFQvz(vODec)(i-J@1K93ZX>^|F2pTpkf z^woox0lvcJt81=t4o>&rwZd816Er(bWT`pxz^Sb?z>7-jalgNqVYJ3sqQhbP3+IpJqB_is6q#v*(~}It3GxX6^6-ZoK;Ib{TwMUhju{!qm^W3pM3=uo(GO*Fu7CJCt6P zcbX_U*m&MiQ6jK2L|JD}?7a3iVRbzTqdVL<#JFi>qLJcrR`^rVYBOlvxpr%$W`_h@ zPyxG*{HA#WZ-vsRih75&r_<<30FEF_m7lB17?6%MtBWY(B-zT^n)lk}1N}@dK$4U< zN|atDCAz&GCCiUT5> z`n%Y$S(VN;Q(Pcq;>slWcm{)a&>9Tx`+V+DO>&1&K3^x$m}_tZ zQYGMbqwwveyNfN;+_=4PQ4gij6cBIid!v&=@tZUmK2*;%X^B^ijk3Kb2OJ1|bE`8I zVl`_warK%y49=T=tM25F;fHU&H#=YxAW?FD7T34J39yhK=m z|A&d1)-pDP=1>)Qd_$kmH7$gvAl1+5GgfCi!nundznB*FU|&o*XDG(s&B1)(sbn)Z z8|`&@UEKD5^d5XBl82ixc&J7C0Ap?tS}0A%s4#WbJm|b=C@Qu~Ya4%#EXfkDT^tjr zIe(Gg7==RKN5-fg!&R5y!z>8uJju94ong)%!HN=Y>9#%3Zcj0duV(j0pPYZI6wmfl zsgzyr6KAov@2&?SZchI+sdr4#1(h>CPJ|9B+p&e;8*Hfelhzydn7ln95IEt8*uM); z;Qc6KPmyuwjtGVp5NPMahDE5-dnY&5bv7M3!!T>x$>qy{Xq9@|_?MF1$)t4Ye37or z;-RJ@a`kxfXzovnFC+PvMJAC1Y8j|8k^4}M-W^*L<4@-ub}dZXlIqfsvVN8m<=2|s zQj~YDi#Vs;l}-O%)w8ZI0{CA>yB8hG67LQBLlKfFOk!WSjEa)ca256T?Vb|RWJSB; zHF9~WuvlrXp034v)U<)@3yow))eZ7^K_mm>G=4E)wLesq*Sl^48B%kg(et+ZfwQvy zy)MJAHTQ1rp5t@85?6bBeD7rd>@^ZhWXmRA#L0&dkIik5=MlX0s)ob@*aektk6!3q z?yYg>`I=yU>4ux*_R$r8S?_!pezAFD(jJRk6PZhp1#}%6I10T@bn(@w6G=Xm^fuSR zb$mEc?**dY@ISG+C?xtC4K?n?!e}o8%o{Rfc*ewq4|70A+}?N;S$S5~RxH1?(M5Sj zB(3Z2eyC#P4k`pnjnKR|m?`R4S)6TID2B=eGJFvHFzGM!ZoS|QwDH5evO ze2i#-JUi8kh{DzE@)KUqNyNfV5rs;-1v*>&bmu(lXC-LhZkFmYyGe?@+g=aHb-<~+ zdA>JQx)`O%?KF;s8fl)FitYB49@SsVz{j@E&1bA}l@iZaR}vI_M5VZbN0nzzO*)z| zg`XW3D8H?oq$yf#tz+6!?Par2b{!91lfX-~A(;UCx|Ll|0uqi5Z(xDjL&Ie)b#HU3 zysAZqt)09*{x%RP=NTMoe^I;tBVjfp#g)i*Xi8|^y*~uC5dns;RpVV`zdo+-6*i%0 zTrVpxD*prf;jNQJw6(S=(=4bDk|KfgsjjYig9t8s=k6UsGoEa3uB>&OB;YNNIXUFI zJ!oHOx-_(8mKIYsZX3F>cK=1_gTj_uU22)mq7QH7LX{pPn@-JVRMf1o`?HdIH!!rW zbe7AFV)(uP)82PSHPOHMf}ns1k>0@q0xBRyP{70nh=>tTLJ^_@F9ZZcTEvh@Z$bp6 z`U*C>5IRWjML;@8C?N@;R5PG4n&KVz+`Y$l&+hNuJ$v_-J?|fLGT(D%zBBXWTb}ZH zK2H~HFUnbo)^M?A%)D^bfS{V{Z*=6S$jrmfc(XTNW_&zTFXk zlqHx9!cw43KF+oD^3-&T-bS{JYhDITTF1DXwbd7D)ouG5ZX^j13+v-@SJ=2q3iy#C z&|%a0&t8)M97hbI9Z9p%!a!w*g8{6-EoZ(NST5_fU zNdh~SZUlo0`WmbgpXGM8G}Wc3rQfzP!o1ggxF>~sy@(*7@*xuIfN`l}KltLy-Q&+Z z=zRSgkegcp-wolP^U@{tVcZi!bQ&7vcKgh=@P=*qx3Sd#sSPo}0T){VmR&Ykm^13a zYSFr5@>j9iO%uoA>rJ|s>zWgtkDS-;(Czm#+)Tbx6dx&{lcDuN);ZlRf9CAI>SzI5 zWmD~!g$sKg7JMc2lM-Q-@;`7J>Qu->!=AQYtUkk~CruXR=t0mZA$&PyV;SasK_Kwx zVfr_#qDsT^!yP+MTQx`toU`L7jmfO5(wD}T8Q0t>a$39Q%>hwn*B0g!lDB%%kpdX= z3cN`9qW;jK^R?0S+ufr&ul@|=>|wvg;81|@H!@%M=Uw(__s-AcHG-%|y5Z$Qc5d!! z&7_%FyTXfTJD&r+Di@Er%}!fY8T2|UvlEQ{i&-ECS^-p!VLjtKjPWx_(Bvqf#$s># ze7XO`B6v*k>!OEi^WO70E4**c)A-&Qgv7ML9;6ooa<)Ko6b&p4d+voDBZvtvOIr5O ztY({CZ9FHZ(^TF0$kE}A>kCL)P#Yi0$mDQ3g44n^JVL{76a%m>kjStn0p>Axjy$d? zP0LOt-=7&&+@jhz7FKKc@JX)7&J-On`$N+}HRGfIdhZo}@ikc7kC^pJn)?E&V*>)O zoWky7T}yH7PZ-+k$#<#jv2A0lr(y2W#>e#inp09cPP}S$e^$CV7MpR2B@@66s z+-5*DMkpSpEw$EKUei<@Juw=pe?L9x#K)>SG38zvrheVwFLE>BmfmRF`OjQVz&#vCWuan3y3C??{6k`a0 zb!Mr2>mWq;p@hLm0iWlOT6!bV0acSyJv)h5SyD~Uuu5m!Om+REdE5ialp=eQ&eZT z(RyrYkO-wKj2OV0X*H%dBshoEXq5E-lw#=Ve|`R*cdSOZuQYxj+5S#Zu=iJd1Wt(M zPKFbus69#5Y@_vh)kH1Uas9Z!kLOg0)UhvZzIQNnbFcBPEt)D!8NQAO?88hd;+6O$>CvK#K{+ZN>42O;Q2$MW+~0f9sM%pq^O&A z#^UwIX?z~af3Oa+^PonU(@1{CQ)>n)cNPundDO7-10Vf0eO1h~*^k1yUH%Sc9iNGU6kHcx4m%Q(6Rm*}DC}5J$H*)^<3ZL%SZ^<<&^nyg~ES1`52r^mk5Nzi6&;|V*j zdkS7v7m%v?Az6;!rr#!d=!*a4wI9D`9raDKI-35Ii;iUHRU?T~?Es^r!%(YJ;o_vF zK3sI(*D-bCs7O`Ay|n$x`jVGcX@(M{XrwxKAJefbrz*YcBV&o8^#I8am7hk(SPcgx z>e?FSy()eNgNK6-h75SD@?9ofSzVFxJ?Pd8VXQZRZ&kvBvyK;rY6%Ys4tHL~$)T6G zyXK|G$85?hLN5!!Z7S-H@umfMD2K}hx$EAx#$M~|#&$FA(`LG}ls0St80B(d{ynGy z0EuDgy5u>3r?uqx<-evZ8Rz;RzOC6WBy=max&Fx?y2>h2&U&rp7`FAT5!%3L z6?qahHft4&^VeWRTirIV@~dZ|gJOKbPHtxV@+89C{P1bjpbae6tmGj%ubrhK1qZO{ zz_ugc8?C3|Wmj1V7yGcf_&O-4c9)BMaIKZwbF=T`g|iX4!HTkgdlx|gOL7)yV&KXA zjUtLU3#aZ{Xh>8Wh1y(65>Sm&++5iZJR=KNx1*dMzy)=cT@Y7)zsflsItaX?sK#Ms z(Z{^9g=j&!)RMbfoH5I?kuMv)ie9xumA7>w?`mqw_f%EZKe?>?a1p~?AP@;%hPY0) zJK3OTXwQnG)ObLSfD?Ln)j_eEO>os?s_S1jGt}GL&pQH^%Y3&Ws@?62odruksDkSj z>N!dYqPLc_7e&V&8Y5tA$o(2;0vbyE&m`c8x2bRcFyZdA?zOkzeiW?6w+Ml7`sWQ> z7}Xk_M4I&w8Q1Yy1`R>d6gp+GuWtGmqCOWshY>?kdNh^ip%N)SQSa+boBC!J$ghl}{_&VvLsM;sN7L5yi9wmdxrONT&X9*$n(=wIH)_(x1X0Z+ z(24%k{kPt2$^*2iq(%v*8>4}K4pwohr9Hq2VKNrLmh=^Q77Um5d6EBV`@HvHN@JYX zGvhm^uP>EHI(21UFPaJkiWl-bo$k{!0I7$K-n1lmVzYSDXh1)1r$c|qjNM9zIIXMZ ztL8?j+qHphp8XkS>eEqII#aKY=QlUOkXpm;U^S`vbUzFa4bg2WNM;e!iYYnr`C;y~ zMTb9c1IV0e9=ca`Y?oit#)ONCmE*vB)01oKFqBe~A+mEnEtrDnNK`!s_{LQ^vJq`? zuhQ!I^g?)kDKkMX0blXvk>ws&qZ5fwk{-CaFTllFFb0X{vf$gH#qFgiTvi5Le#|_- zBAXT_F7*g^Yqi2zgWXl{s3S_Jx3%{$KTut*g@@1ZY$oz_z+|B(IipxU##=zC)f%*6 zKDQ6*I^r+aHjjI2eXiDUbc)h&-)G+#TQl6AX?sghpPyH(yxTt{aE!yRht64_VOq1! zFhZFUXsvFNNI*Y92A$AZ-;WM%D~G=M=8zNnRj_~Ub)v88TT`Z5;w#tLK{b&B*#i8~ z*WiQ{0YpiZ!Sps{(!5|ft)_t@boeuZwn4{(^*}sP#P|=GDcd*B(kk&3{$BsBiu%Ry zI=N=$8usJn<6fi+vv8<5<8f=+7&>NQD>Xhzrf*CC(k)hAvJ{mc}9$@((pIpEh@> z=b(084*GZmOl9JR@|r`s6JW8j2CYs?3*Ta@gfzEKEH`Bf4u<^XvT1zS7AsWJnd~@Y zCRq0erYf^lS{21-WgmiTxWyBicOX?bB#aP8iui z>aQPk*$!CQv_BBP`fl-J>04pe%jCWnCyAdyRVH@hs{m95gJakLN67A7Lpxy+ER)v` z9nj=r6hg-tg{Z|^HI99*>hF%1)FIBDjT)0n4qs$_P%L2{#W=iWEHO_plqiXuG2EM# zu)rM&<+7ajX4MUDNV09V)M29?Cr^1TBBy8C6%VnWy@6`8>?bfMakLI{fb1m%5fXVk z6v?!8w12ZN&9V4-@$vQzMNveXIPv{l&j=qf_{ zf_|TzXRR)he-6H%YTtg$I9&K%i8`ptOmjkbpjAZqIGbhB}oj}qR6UNq|S^=h245<60(O9YAb) zW4$f&uwzJmm?t4oNtDG$y9 zcW!vD70*mn|IoQYiqrxNU>h({03QXheq`ZfV5qNU`1oqbwKcC0e^S@3@8|D4yL{3< z*KXiVxY~PqyQqM~C!{dUJ4cx10i-47Vbn*{t!Q0@XnY*Ti{Lb?r_JzlHPyCza$(jI z?O-tfH2Io%eL7cIVJP5BZ=P)Aru2+qdCbWKi7u45vw|aD{L_yoVso?FrfE(oorMZT zoG*pS@9xB(R7S(vm8NwmQ>{vSkr?Qhk2{bK0tXVHa&K#Z?w9U0(H~8KqmPX5lG@}e z&M8mULcO%orSI+H(U!Yv>};N^(4@h>7dD^UMpG|n4(u_4oAnU z%+SlZZlYcFJNmaUCCsF4HgU5mXAkQ%8;oOk;ALi6VzkX?fazE#N19fWSNzfu9o=Cu z`NaYcnSLs$Ub?TrFTtYV*tr6Yh7;G-=GEbroCQNm2%W}+x8;aqE&{3#O24#-tSCYs zle<&N%FRjl2hE&CW}eidSXD`fwpAWoIDMy3OlMPBBg7ya=7Ep1g-Pi_B9KbPA~(sF z@a`Z)ZMN*Vp7(Xn8iTv2zU4Xl!DeaYc=XNv-?)0eQx$%488?d2v?vA}B1}Wpg}R)} zqt!Sm4^ovRfyy_M_+Bs3)8c~nLQ`4%QY*5uzuAtG{J^Gc$2Ge$(EAN<&E)G*5bSZ# zS_f%bF^aU$(IuLTbq(X18lS6+*%v7XcbK`;E#gG^43L~_MVmH(OR)i%zG{qYhn0c z?K@*BnjqzUGN_L(O*Hd(%1WhDi%X7l292PQx2wEINvpxZl56y+j2R)|V&Y>>sS~&O z_vxOaY4vDL4^ej!0Hby+cO4__CF?AW5PdZ8se*x3WzD!=iC4#@m+OOsLeZ1ni};i1 z#S^zvxUOlA6{IwT@&@h262IwSPF4dFpCe{21J`0YEn(!LxB!scwLc#@cj;h?hmWXE zt;o(Bz@s9icTy zjntIGT}SV$a_39-hOWuXrL<_X#Ry$W5}Y9==|-eqp2Wks2F%DB!O)C4d3F-lKQLME)T9U~UeR-YbINmZrMs_Q1FtXjCdG<>5Q>~;=K z)6!vvFCOM`@rq31W3YR%!_I1D>{J3)8I9EY#gRGfk9 z{XS2dmwa&IpvZ05ns&~-^!69TI-8oPOU~`t@C6_auusl%z;b2bfNuC2>W_-sN*mC* zBEyu^53e{Dwz=XlS}4kb>ihu zB!`=gN(Xz%cboH5sdxPDh#9zGaj4b*val>+?KISm5w)NdVS0(5XiZ6}i4aG{>z0a;!uUw1e$E2dqWh_#=zMnC1`Gv>tT$MfDuVl# z3=#C2HLJ%;zrxltStlN))ickMS{^IEKzuuU^wDft@1;;S;6g?w8e1_DEI~%{Ym`MG z==^X%S7>)KBEqrj3rSY6zpJHG5Mic9>4Gu4wrmRKY2+^{fVqq7}mFw?vj6`?(KiA3B&q zZ_rFoc#Js)xW_gg7x%j3D%Jm@L%!HZO!m8}&7s{7X8gvdVvty(^NBi8kJgHS%IC*| zF8xFY{Z|DJEB!@+9_#Mq@dAFzTW8ONStIVb5~Yvg4r}j2h=2rAu#Gdcceo@Frm4g- zis{sciL=Z~82IzR)vSr!+|;ALO~%PWQ%3&CdN7Bz%jD1;4d zpv8`H9H6!mW1_q<`vEEP`&3`Q`+j+ADH*#`i-?0dp0c5%XCL3A#WEg7evkb=zNm#< z7?Pe_MT)ezEiy{TYKMU4YBE8zKY#7m8o~f}BU}MGoo#kb9u=s;QrXk&F`)JAP0zAE z=MaXAkpqGOb}EAh^JRIQu$TLR4ly_nZ`_C}G=Gl)D4; zSg%o4W3dOY0~|v@D?E=j3xlvuQJfBTK7toaU$1^LW;ZiUJa%m0QvcoIG^B>z^MeC3 z7sr}gCR-MD2Q+XCAnHxZabX=0(~&jmfmW*b#zol{@8#A(=V-c zIhJWD7uvFraIP1!K>*HOrI{83Ai)wC^*k_v6-G%J9Auh&O|6|G1k9*6K7DqP*!EmI z_SKR7BIY^`k?#?;pR{7W&S`bYf&d+F(VPDHp7cA&>47HY+P8_Wi9MAEd602fIX0ek za{j5$pwV+)t3-_CE|6y!kiq{9gdi zxfj!Oc5ozDl_WKw2CK4K#76i0899qnXYW6a6D8`Olauz&vhkLG7+IKnOBj(j=f4(U zWv*NULR-}z{EM!B;luxrVAT=o3qQGd7>HKG(D_ud;Lfqzgh0V2Ye)3FX{;0S0?0Ey zG9785{P4Z?u>$E7ao3NJQ9{pXn1uitxMv8|}lRo8+$0Lg#rWPsDbQ z)NEp@uS%AcEZyWrCKq*|EWJqmZt*4eGsb73U-f@VTd2m}_KyLAIfOk&jk^kv^CElT7tsDuOa87V8`fOXk%#pdX zpRcCP8zjG!LX66k%IXE(6zw~x`{d!_UCL21Cs#kcY`u%srx`>+4|+hzzOo-Q3t#v9 zdHZYpnQ|f7LgmjszrBx4`ogw8GuHgR>_)oBHi3OxM><^`Iq;%sMUkXW{5xP9(T@sbD8WPH0PDj%-mD`jj zbz8U22P>uab7yNiGfh;*Co<&mVa7WbK1Vx?kFg*N3WrGNhpXxaf@*Aw&U*+P?M$&S zY7l+DZlNnWV6HsnWFkKL8cjTu-yVej?Hqh4?C;)w6XJhZZinZh z6ALZx@9bise1#gmhh6(tS;s5$6aNEz>J`}2fwzy|Jz6BR6t+# z5%gf?;UQnur;0zh>SrYm`wj06p&uUrJ?U$|hG))yAD*kZ3C~V!Js z5Bj?|aO(hfi~qWEGnb4jcJ7xCPFAU|3%m!(P{>f{^WeJSnq~1i&8@niw+?F0 zcm6fo?U()bZyns}Z%`YBAF3-(B%SV8zHNFsV1KmPi*88uUF7r+#=^8|XRv)YWb8=R z7uh3uNrwZd?`j}6L(Of3pIk%nKee{$`H{-p(8=)1A|Svr+-GvDQZa-|xm1WaRL z%d$bn%ylrD$zl-Lpiw}3^?QSG<|Y2`4*yMQ|Nkq)k~zr5`l>9iwT)uEqVhK$!MrBQ zTX%HKjp?N+@$d6={1cMG@=t?F+m9eW|1pQ>UsmdWr)m24z5koI)&3Xc&hvBnzX9Xe Bdc6Pu literal 0 HcmV?d00001 diff --git a/archived/aqua-ceramic-integration/assets/figure_1_code.md b/archived/aqua-ceramic-integration/assets/figure_1_code.md new file mode 100644 index 0000000..bd2a6f6 --- /dev/null +++ b/archived/aqua-ceramic-integration/assets/figure_1_code.md @@ -0,0 +1,18 @@ +```mermaid + sequenceDiagram + title: Figure 1: Stylized Use of Adapters + + participant C as Fluence Client Peer + participant F as Relay Node + participant S as Peer(s) hosting adapter(s) + participant O as Exogenous API/Runtime + + C ->> F: Launch Aqua script to compose adapter services + other services + F ->> S: Call adapter service(s) + S ->> S: Call host binary + S ->> O: Request to exogenous resource + O ->> S: Response from exogenous service(s) + S ->> S: Update Aqua workflow (Particle) + S ->> F: Return result + F ->> C: Return result +``` \ No newline at end of file diff --git a/archived/aqua-ceramic-integration/ceramic/schema_id.txt b/archived/aqua-ceramic-integration/ceramic/schema_id.txt new file mode 100644 index 0000000..37fad17 --- /dev/null +++ b/archived/aqua-ceramic-integration/ceramic/schema_id.txt @@ -0,0 +1,85 @@ +kjzl6cwe1jw14b4395tqak897qks1f87ljtkkoaop4133wdsire65g0tzol8zaa +eraStreamID(kjzl6cwe1jw14b4395tqak897qks1f87ljtkkoaop4133wdsire65g0tzol8zaa) + + +commit: + +ceramic commits% mbp16~/localdev(:|✔) % ceramic commits kjzl6cwe1jw14b4395tqak897qks1f87ljtkkoaop4133wdsire65g0tzol8zaa +[ + "k3y52l7qbv1fryn1355fez3upj0zre4ae18yab0rzmknq3qa2tesrqpxx9qv3ux34", + "k6zn3rc3v8qin273e8dy6fftce0s2pe6w9yo2o2ebaz3i0r1onkflgr2wvycxpja9ov4dsqgx4zpw0shihnafw3dlq5lv2qs0q1mpoqfrj996ooh3q0utj7" +] + + + + +StreamID(kjzl6cwe1jw14b9zk6i99zoupa7odnn3r9ftwfh7iocgrgvep6jfbhe3ko8a7jf) +{ + "proposal": "https://ipfs.fleek.co/ipfs/Qmd6o2bFhuN2pkXa3qTW32zAcKHwhvz5pcj5rs1NzPcJcx" +} + + + +ceramic create tile --content '{"proposal":"https://ipfs.fleek.co/ipfs/Qmd6o2bFhuN2pkXa3qTW32zAcKHwhvz5pcj5rs1NzPcJcx"}' --schema k3y52l7qbv1fryn1355fez3upj0zre4ae18yab0rzmknq3qa2tesrqpxx9qv3ux34 +StreamID(kjzl6cwe1jw14b9zk6i99zoupa7odnn3r9ftwfh7iocgrgvep6jfbhe3ko8a7jf) +{ + "proposal": "https://ipfs.fleek.co/ipfs/Qmd6o2bFhuN2pkXa3qTW32zAcKHwhvz5pcj5rs1NzPcJcx" +} + + + +ceramic create tile --content '{"proposal":"https://ipfs.fleek.co/ipfs/Qmd6o2bFhuN2pkXa3qTW32zAcKHwhvz5pcj5rs1NzPcJcx"}' --schema k3y52l7qbv1fryn1355fez3upj0zre4ae18yab0rzmknq3qa2tesrqpxx9qv3ux34 +StreamID(kjzl6cwe1jw14b9zk6i99zoupa7odnn3r9ftwfh7iocgrgvep6jfbhe3ko8a7jf) +{ + "proposal": "https://ipfs.fleek.co/ipfs/Qmd6o2bFhuN2pkXa3qTW32zAcKHwhvz5pcj5rs1NzPcJcx" + + + + + + + +ceramic create tile --content '{"proposal":"https://ipfs.fleek.co/ipfs/Qmd6o2bFhuN2pkXa3qTW32zAcKHwhvz5pcj5rs1NzPcJcx"}' --schema k3y52l7qbv1fryn1355fez3upj0zre4ae18yab0rzmknq3qa2tesrqpxx9qv3ux34 +StreamID(kjzl6cwe1jw14946s42j0ew60kmmw5g0tzc28ceat2algr49l7bb8shv30zd2h3) +{ + "proposal": "https://ipfs.fleek.co/ipfs/Qmd6o2bFhuN2pkXa3qTW32zAcKHwhvz5pcj5rs1NzPcJcx" +} + + + +ceramic state kjzl6cwe1jw14946s42j0ew60kmmw5g0tzc28ceat2algr49l7bb8shv30zd2h3 +{ + "type": 0, + "content": { + "proposal": "https://ipfs.fleek.co/ipfs/Qmd6o2bFhuN2pkXa3qTW32zAcKHwhvz5pcj5rs1NzPcJcx" + }, + "metadata": { + "schema": "k3y52l7qbv1fryn1355fez3upj0zre4ae18yab0rzmknq3qa2tesrqpxx9qv3ux34", + "unique": "USgiCW4TyR3dax1w", + "controllers": [ + "did:key:z6Mkupzc4V3f7RiQCzjxVqqqRXbkmuAdN38oPqATcyWq2HaN" + ] + }, + "signature": 2, + "anchorStatus": "ANCHORED", + "log": [ + { + "cid": "bagcqceratishgp6t3ffgdxhwxqj6cnglwrc7ukg64jqdtybpawpgzrjsiddq", + "type": 0 + }, + { + "cid": "bafyreidncrcks36g6yctlr743ouygvtdg7657xe4gf2brmmx4etjysrhxi", + "type": 2, + "timestamp": 1629951384 + } + ], + "anchorProof": { + "root": "bafyreidpqmfi2enod635viwxmixzfe2qdoon5hdlkowdot6r5bhwovaamy", + "txHash": "bagjqcgzaplsuv3z3nuqw3n6mai4cjvujczgqjjfetqnh3nczjav2gsaurjmq", + "chainId": "eip155:3", + "blockNumber": 10910933, + "blockTimestamp": 1629951384 + }, + "doctype": "tile" +} +mbp16~/localdev(:|✔) % \ No newline at end of file diff --git a/archived/aqua-ceramic-integration/ceramic/snapshot_schema.json b/archived/aqua-ceramic-integration/ceramic/snapshot_schema.json new file mode 100644 index 0000000..6250e2e --- /dev/null +++ b/archived/aqua-ceramic-integration/ceramic/snapshot_schema.json @@ -0,0 +1,15 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "Snapshot", + "type": "object", + "properties": { + "proposal": { "type": "string" }, + "proposal_verifications": { + "type": "array", + "items": { "type": "string" } + }, + "vote": { "type": "string" }, + "vote_verifications": { "type": "array", "items": { "type": "string" } } + }, + "required": ["proposal"] +} diff --git a/archived/aqua-ceramic-integration/configs/Config.toml b/archived/aqua-ceramic-integration/configs/Config.toml new file mode 100644 index 0000000..c3293b1 --- /dev/null +++ b/archived/aqua-ceramic-integration/configs/Config.toml @@ -0,0 +1,17 @@ +modules_dir = "artifacts" + +[[module]] +name = "curl_adapter" +max_heap_size = "100 KiB" +logger_enabled = true + +[module.mounted_binaries] +curl = "/usr/bin/curl" + +[[module]] +name = "ceramic_adapter_custom" +max_heap_size = "50 Kib" +logger_enabled = true + +[module.mounted_binaries] +ceramic = "/Users/bebo/.nvm/versions/node/v14.16.0/bin/ceramic" diff --git a/archived/aqua-ceramic-integration/configs/ceramic_adapter_cfg.json b/archived/aqua-ceramic-integration/configs/ceramic_adapter_cfg.json new file mode 100644 index 0000000..e8f44fb --- /dev/null +++ b/archived/aqua-ceramic-integration/configs/ceramic_adapter_cfg.json @@ -0,0 +1,8 @@ +{ + "name": "ceramic_adapter_custom", + "mountedBinaries": { + "ceramic": "/usr/bin/ceramic" + }, + "max_heap_size": "100 KiB", + "logger_enabled": true +} diff --git a/archived/aqua-ceramic-integration/configs/ceramic_adapter_deploy_cfg.json b/archived/aqua-ceramic-integration/configs/ceramic_adapter_deploy_cfg.json new file mode 100644 index 0000000..92c85e8 --- /dev/null +++ b/archived/aqua-ceramic-integration/configs/ceramic_adapter_deploy_cfg.json @@ -0,0 +1,23 @@ +{ + "ceramic-service": { + "name": "ceramic-service", + "modules": [ + { + "name": "curl_adapter", + "path": "./artifacts/curl_adapter.wasm", + "mounted_binaries": [["curl", "/usr/bin/curl"]], + "preopened_files": null, + "mapped_dirs": null, + "logger_enabled": true + }, + { + "name": "ceramic_adapter_custom", + "path": "./artifacts/ceramic_adapter_custom.wasm", + "mounted_binaries": [["ceramic", "/usr/bin/ceramic"]], + "preopened_files": null, + "mapped_dirs": null, + "logger_enabled": true + } + ] + } +} diff --git a/archived/aqua-ceramic-integration/configs/curl_adapter_cfg.json b/archived/aqua-ceramic-integration/configs/curl_adapter_cfg.json new file mode 100644 index 0000000..3b0be51 --- /dev/null +++ b/archived/aqua-ceramic-integration/configs/curl_adapter_cfg.json @@ -0,0 +1,8 @@ +{ + "name": "curl_adapter", + "mountedBinaries": { + "curl": "/usr/bin/curl" + }, + "mem_page_count": 100, + "logger_enabled": true +} diff --git a/archived/aqua-ceramic-integration/scripts/build.sh b/archived/aqua-ceramic-integration/scripts/build.sh new file mode 100755 index 0000000..3966014 --- /dev/null +++ b/archived/aqua-ceramic-integration/scripts/build.sh @@ -0,0 +1,18 @@ +#!/usr/bin/env bash + +set -o errexit -o nounset -o pipefail + + +mkdir -p artifacts +rm -f artifacts/*.wasm + +cd services/curl-adapter +cargo update --aggressive +marine build --release +cp target/wasm32-wasi/release/curl_adapter.wasm ../../artifacts/ + +cd ../ceramic-adapter-custom +cargo update --aggressive +marine build --release +cp target/wasm32-wasi/release/ceramic_adapter_custom.wasm ../../artifacts/ + diff --git a/archived/aqua-ceramic-integration/services/ceramic-adapter-basic/.gitignore b/archived/aqua-ceramic-integration/services/ceramic-adapter-basic/.gitignore new file mode 100644 index 0000000..bbccc88 --- /dev/null +++ b/archived/aqua-ceramic-integration/services/ceramic-adapter-basic/.gitignore @@ -0,0 +1,5 @@ +debug/ +target/ +Cargo.lock +**/*.bk +**/*.bak diff --git a/archived/aqua-ceramic-integration/services/ceramic-adapter-basic/Cargo.toml b/archived/aqua-ceramic-integration/services/ceramic-adapter-basic/Cargo.toml new file mode 100644 index 0000000..7928802 --- /dev/null +++ b/archived/aqua-ceramic-integration/services/ceramic-adapter-basic/Cargo.toml @@ -0,0 +1,22 @@ +[package] +name = "ceramic-adapter_raw" +version = "0.1.0" +authors = ["boneyard93501 <4523011+boneyard93501@users.noreply.github.com>"] +edition = "2018" +description = "ceramic-adapter-raw" +license = "Apache-2.0" + +[[bin]] +name = "ceramic_adapter_raw" +path = "src/main.rs" + +[dependencies] +marine-rs-sdk = { version = "0.7.1", features = ["logger"] } +log = "0.4.14" + +[dev-dependencies] +marine-rs-sdk-test = "0.8.1" + +[dev] +[profile.release] +opt-level = "s" diff --git a/archived/aqua-ceramic-integration/services/ceramic-adapter-basic/src/ceramic_cli.rs b/archived/aqua-ceramic-integration/services/ceramic-adapter-basic/src/ceramic_cli.rs new file mode 100644 index 0000000..73b5bf2 --- /dev/null +++ b/archived/aqua-ceramic-integration/services/ceramic-adapter-basic/src/ceramic_cli.rs @@ -0,0 +1,59 @@ +use marine_rs_sdk::{marine, MountedBinaryResult}; + +#[marine] +// general purpose request call where users provides the vector of +// properly formatted args +// e.g., +pub fn ceramic_request(args: Vec) -> MountedBinaryResult { + ceramic(args) +} + +#[marine] +pub fn create_stream(payload: String) -> MountedBinaryResult { + let args = vec![ + "create".to_string(), + "tile".to_string(), + "--content".to_string(), + payload, + ]; + ceramic(args) +} + +#[marine] +pub fn show(stream_id: String) -> MountedBinaryResult { + ceramic(vec!["show".to_string(), stream_id]) +} + +#[marine] +pub fn state(stream_id: String) -> MountedBinaryResult { + ceramic(vec!["state".to_string(), stream_id]) +} + +#[marine] +pub fn update(stream_id: String, payload: String) -> MountedBinaryResult { + ceramic(vec![ + "update".to_string(), + stream_id, + "--content".to_string(), + payload, + ]) +} + +#[marine] +pub fn create_schema(schema: String) -> MountedBinaryResult { + let args = vec![ + "create".to_string(), + "tile".to_string(), + "--content".to_string(), + schema, + ]; + ceramic(args) +} + +// link to binary on host node with `extern` where the path comes from the +// config file. E.g., `/usr/bin/ceramic` +#[marine] +#[link(wasm_import_module = "host")] +extern "C" { + pub fn ceramic(cmd: Vec) -> MountedBinaryResult; +} diff --git a/archived/aqua-ceramic-integration/services/ceramic-adapter-basic/src/main.rs b/archived/aqua-ceramic-integration/services/ceramic-adapter-basic/src/main.rs new file mode 100644 index 0000000..5da1ed5 --- /dev/null +++ b/archived/aqua-ceramic-integration/services/ceramic-adapter-basic/src/main.rs @@ -0,0 +1,25 @@ +/* + * Copyright 2021 Fluence Labs Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +use marine_rs_sdk::{module_manifest, WasmLoggerBuilder}; + +module_manifest!(); + +pub mod ceramic_cli; + +pub fn main() { + WasmLoggerBuilder::new().build().ok(); +} diff --git a/archived/aqua-ceramic-integration/services/ceramic-adapter-custom/.gitignore b/archived/aqua-ceramic-integration/services/ceramic-adapter-custom/.gitignore new file mode 100644 index 0000000..bbccc88 --- /dev/null +++ b/archived/aqua-ceramic-integration/services/ceramic-adapter-custom/.gitignore @@ -0,0 +1,5 @@ +debug/ +target/ +Cargo.lock +**/*.bk +**/*.bak diff --git a/archived/aqua-ceramic-integration/services/ceramic-adapter-custom/Cargo.toml b/archived/aqua-ceramic-integration/services/ceramic-adapter-custom/Cargo.toml new file mode 100644 index 0000000..a38a54e --- /dev/null +++ b/archived/aqua-ceramic-integration/services/ceramic-adapter-custom/Cargo.toml @@ -0,0 +1,22 @@ +[package] +name = "ceramic-adapter-custom" +version = "0.1.0" +authors = ["boneyard93501 <4523011+boneyard93501@users.noreply.github.com>"] +edition = "2018" +description = "ceramic-adapter-custom" +license = "Apache-2.0" + +[[bin]] +name = "ceramic_adapter_custom" +path = "src/main.rs" + +[dependencies] +marine-rs-sdk = { version = "0.7.1", features = ["logger"] } +log = "0.4.14" + +[dev-dependencies] +marine-rs-sdk-test = "0.8.1" + +[dev] +[profile.release] +opt-level = "s" diff --git a/archived/aqua-ceramic-integration/services/ceramic-adapter-custom/src/ceramic_cli.rs b/archived/aqua-ceramic-integration/services/ceramic-adapter-custom/src/ceramic_cli.rs new file mode 100644 index 0000000..5149156 --- /dev/null +++ b/archived/aqua-ceramic-integration/services/ceramic-adapter-custom/src/ceramic_cli.rs @@ -0,0 +1,109 @@ +use marine_rs_sdk::{marine, MountedBinaryResult}; + +#[marine] +pub struct CeramicResult { + pub ret_code: i32, + pub stderr: String, + pub stdout: String, +} + +impl CeramicResult { + fn new(mb: MountedBinaryResult) -> Self { + CeramicResult { + ret_code: mb.ret_code, + stderr: String::from_utf8(mb.stderr).unwrap(), + stdout: String::from_utf8(mb.stdout).unwrap(), + } + } + + fn create(ret_code: i32, stdout: String, stderr: String) -> Self { + CeramicResult { + ret_code, + stderr, + stdout, + } + } +} + +#[marine] +// general purpose function where all args need to be provided +// e.g., ["ceramic", "state", "stream_id"] +pub fn ceramic_request(args: Vec) -> CeramicResult { + let response: MountedBinaryResult = ceramic(args); + CeramicResult::new(response) +} + +#[marine] +// https://developers.ceramic.network/build/cli/quick-start/#2-create-a-stream +pub fn create_stream(payload: String) -> CeramicResult { + let args = vec![ + "create".to_string(), + "tile".to_string(), + "--content".to_string(), + payload, + ]; + + let response: MountedBinaryResult = ceramic(args); + if response.stderr.len() > 0 { + return CeramicResult::new(response); + } + let stdout_str: String = String::from_utf8(response.stdout).unwrap(); + + if stdout_str.contains("StreamID") { + let res: Vec<&str> = stdout_str.split("\n").collect(); + let stream_id = res[0].replace("StreamID(", "").replace(")", ""); + return CeramicResult::create(response.ret_code, stream_id.to_string(), "".to_string()); + } else { + return CeramicResult::create( + response.ret_code, + "".to_string(), + "Missing StreamId".to_string(), + ); + } +} + +#[marine] +// https://developers.ceramic.network/build/cli/quick-start/#3-query-a-stream +pub fn show(stream_id: String) -> CeramicResult { + let response: MountedBinaryResult = ceramic(vec!["show".to_string(), stream_id]); + CeramicResult::new(response) +} + +#[marine] +// https://developers.ceramic.network/build/cli/quick-start/#7-query-the-stream-you-created +pub fn state(stream_id: String) -> CeramicResult { + let response: MountedBinaryResult = ceramic(vec!["state".to_string(), stream_id]); + CeramicResult::new(response) +} + +#[marine] +// https://developers.ceramic.network/build/cli/quick-start/#4-update-a-stream +pub fn update(stream_id: String, payload: String) -> CeramicResult { + let response: MountedBinaryResult = ceramic(vec![ + "update".to_string(), + stream_id, + "--content".to_string(), + payload, + ]); + CeramicResult::new(response) +} + +#[marine] +// https://developers.ceramic.network/build/cli/quick-start/#5-create-a-schema +pub fn create_schema(schema: String) -> CeramicResult { + let args = vec![ + "create".to_string(), + "tile".to_string(), + "--content".to_string(), + schema, + ]; + let response: MountedBinaryResult = ceramic(args); + CeramicResult::new(response) +} + +// mounted_binaries are available to import like this: +#[marine] +#[link(wasm_import_module = "host")] +extern "C" { + pub fn ceramic(cmd: Vec) -> MountedBinaryResult; +} diff --git a/archived/aqua-ceramic-integration/services/ceramic-adapter-custom/src/ceramic_http.rs b/archived/aqua-ceramic-integration/services/ceramic-adapter-custom/src/ceramic_http.rs new file mode 100644 index 0000000..c77996b --- /dev/null +++ b/archived/aqua-ceramic-integration/services/ceramic-adapter-custom/src/ceramic_http.rs @@ -0,0 +1,81 @@ +use marine_rs_sdk::{marine, MountedBinaryResult}; + +// source: https://developers.ceramic.network/build/http/api/ +static API: &str = "api"; +static VERSION: &str = "v0"; +static STREAM: &str = "streams"; + +fn url_maker(host: String, port: u32, arg: String, stream_id: Option) -> String { + let curl_args = format!( + "http://{}:{}/{}/{}/{}", + host, + port, + API, + VERSION, + arg.to_uppercase(), + ); + match stream_id { + Some(sid) => format!("{}/{}", curl_args, sid), + None => curl_args, + } +} + +#[marine] +pub fn http_streams(url: String, port: u32, stream_id: String) -> String { + // curl http://localhost:7007/api/v0/streams/kjzl6cwe1jw147r7878h32yazawcll6bxe5v92348cxitif6cota91qp68grbhm + let url = url_maker(url, port, STREAM.to_string(), Some(stream_id)); + let cmd = vec![url, "GET".to_string()]; + let response: MountedBinaryResult = curl_request(cmd); + String::from_utf8(response.stdout).unwrap() +} + +#[marine] +pub fn http_chain_id(url: String, port: u32) -> String { + let url = url_maker(url, port, "NODE/CHAINS".to_string(), None); + let cmd = vec![url, "GET".to_string()]; + println!("cmd: {:?}", cmd); + let response: MountedBinaryResult = curl_request(cmd); + String::from_utf8(response.stdout).unwrap() +} + +#[marine] +pub fn http_health(url: String, port: u32) -> String { + let url = url_maker(url, port, "NODE/HEALTHCHECK".to_string(), None); + let cmd = vec![url, "GET".to_string()]; + println!("cmd: {:?}", cmd); + let response: MountedBinaryResult = curl_request(cmd); + String::from_utf8(response.stdout).unwrap() +} + +#[marine] +pub fn http_pins(url: String, port: u32) -> String { + let url = url_maker(url, port, "PINS".to_string(), None); + let cmd = vec![url, "GET".to_string()]; + let response: MountedBinaryResult = curl_request(cmd); + String::from_utf8(response.stdout).unwrap() +} + +#[marine] +pub fn http_pin(url: String, port: u32, stream_id: String) -> String { + let url = url_maker(url, port, "PINS".to_string(), Some(stream_id)); + let cmd = vec![url, "GET".to_string()]; + println!("cmd: {:?}", cmd); + let response: MountedBinaryResult = curl_request(cmd); + String::from_utf8(response.stdout).unwrap() +} + +#[marine] +pub fn http_rm_pin(url: String, port: u32, stream_id: String) -> String { + // not available in gateway mode: https://developers.ceramic.network/build/http/api/#remove-from-pinset + let url = url_maker(url, port, "PINS".to_string(), Some(stream_id)); + let cmd = vec![url, "-X DELETE".to_string()]; + println!("cmd: {:?}", cmd); + let response: MountedBinaryResult = curl_request(cmd); + String::from_utf8(response.stdout).unwrap() +} + +#[marine] +#[link(wasm_import_module = "curl_adapter")] +extern "C" { + pub fn curl_request(cmd: Vec) -> MountedBinaryResult; +} diff --git a/archived/aqua-ceramic-integration/services/ceramic-adapter-custom/src/main.rs b/archived/aqua-ceramic-integration/services/ceramic-adapter-custom/src/main.rs new file mode 100644 index 0000000..c9d4255 --- /dev/null +++ b/archived/aqua-ceramic-integration/services/ceramic-adapter-custom/src/main.rs @@ -0,0 +1,26 @@ +/* + * Copyright 2021 Fluence Labs Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +use marine_rs_sdk::{module_manifest, WasmLoggerBuilder}; + +module_manifest!(); + +pub mod ceramic_cli; +pub mod ceramic_http; + +pub fn main() { + WasmLoggerBuilder::new().build().ok(); +} diff --git a/archived/aqua-ceramic-integration/services/curl-adapter/Cargo.toml b/archived/aqua-ceramic-integration/services/curl-adapter/Cargo.toml new file mode 100644 index 0000000..a2ee3c5 --- /dev/null +++ b/archived/aqua-ceramic-integration/services/curl-adapter/Cargo.toml @@ -0,0 +1,21 @@ +[package] +name = "curl-adapter" +version = "0.1.0" +authors = ["Fluence Labs"] +edition = "2018" +publish = false + +[[bin]] +path = "src/main.rs" +name = "curl_adapter" + +[dependencies] +marine-rs-sdk = { version = "0.7.1", features = ["logger"] } +log = "0.4.14" + +[dev-dependencies] +marine-rs-sdk-test = "0.8.1" + +[dev] +[profile.release] +opt-level = "s" diff --git a/archived/aqua-ceramic-integration/services/curl-adapter/src/main.rs b/archived/aqua-ceramic-integration/services/curl-adapter/src/main.rs new file mode 100644 index 0000000..e60fc7f --- /dev/null +++ b/archived/aqua-ceramic-integration/services/curl-adapter/src/main.rs @@ -0,0 +1,39 @@ +/* + * Copyright 2021 Fluence Labs Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#![allow(improper_ctypes)] + +use marine_rs_sdk::marine; +use marine_rs_sdk::module_manifest; +use marine_rs_sdk::MountedBinaryResult; +use marine_rs_sdk::WasmLoggerBuilder; + +module_manifest!(); + +pub fn main() { + WasmLoggerBuilder::new().build().ok(); +} + +#[marine] +pub fn curl_request(cmd: Vec) -> MountedBinaryResult { + curl(cmd) +} + +#[marine] +#[link(wasm_import_module = "host")] +extern "C" { + fn curl(cmd: Vec) -> MountedBinaryResult; +}