# Other Languages
For details on what each of these examples are doing, please refer to our Getting Started with cURL/REST page.
If you don't see your language on the list, please reach out to our Support Engineers.
# C#
/*
* Simple C# example on how to use the Moku REST API for Liquid Instrument
* Moku Devices.
* IMPORTANT: Deploy the Oscilloscope through the Desktop or iPad apps before
* running this script in order to transfer the instrument data. See
* https://apis.liquidinstruments.com/starting-curl.html#first-steps
* NOTE: This example demonstrates how to deploy and interact with an
* Oscilloscope. Details on list of methods and associated request
* schemas can be found at
* https://apis.liquidinstruments.com/reference/oscilloscope/
*/
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Text.Json;
using System.Threading.Tasks;
class MokuDemo
{
const string IP_ADDRESS = "192.168.73.1";
static Uri baseUri = new Uri(String.Format("http://{0}/api/", IP_ADDRESS));
static async Task Main(string[] args)
{
/* Create a HttpClient object, we will be using the
* same object to send every request */
HttpClient client = new HttpClient();
client.BaseAddress = baseUri;
client.DefaultRequestHeaders.Accept.Add(
new MediaTypeWithQualityHeaderValue("application/json"));
/*
* The first thing we need to do is to take ownership of the Moku.
* We do that by sending a `POST` to the `claim_ownership` resource
* and it gives us back a key that we can include in all future
* requests to prove we are the owner.
*/
HttpResponseMessage clientKeyResponse = await client.PostAsync(
"moku/claim_ownership", null);
if (clientKeyResponse.IsSuccessStatusCode)
{
IEnumerable<string> headerValues = new string[] { };
clientKeyResponse.Headers.TryGetValues("Moku-Client-Key", out headerValues);
/*
* Now that we obtained the clientKey, we include it as
* part of header for every subsequent request proving
* the ownership.
* Let's do that by adding it to the DefaultRequestHeaders of
* the HttpClient object
*/
client.DefaultRequestHeaders.Add("Moku-Client-Key", headerValues.First());
}
else
{
Console.WriteLine("Unexpected error: HTTP Response Code {0}", clientKeyResponse.StatusCode);
}
// Get the Moku's name
HttpResponseMessage nameResponse = await client.GetAsync("moku/name");
if (nameResponse.IsSuccessStatusCode)
{
string responseContent = nameResponse.Content.ReadAsStringAsync().Result;
var nameObject = JsonDocument.Parse(responseContent);
Console.WriteLine("Moku name is '{0}'", nameObject.RootElement.GetProperty("data"));
}
else
{
Console.WriteLine("Unexpected error: HTTP Response Code {0}", nameResponse.StatusCode);
}
/*
* As you can see, all responses from the Moku are formatted as a JSON
* dictionary
* with four properties. `success` can be true or false depending whether what
* you asked for was valid. It it's true, `data` contains the value(s) you asked
* for.
* If it's false then `code` and `messages` tell you why.
*
* The first time you access an instrument's resource, that instrument is
* deployed.
* Here we set the Oscilloscope frontend, implicitly deploying it first.
*/
var frontendRequest = new
{
channel = 1,
range = "10Vpp",
coupling = "AC",
impedance = "1MOhm"
};
StringContent frontendRequestContent = new StringContent(JsonSerializer.Serialize(frontendRequest));
HttpResponseMessage frontendResponse = await client.PostAsync("oscilloscope/set_frontend", frontendRequestContent);
if (frontendResponse.IsSuccessStatusCode)
{
string responseContent = frontendResponse.Content.ReadAsStringAsync().Result;
var frontendObject = JsonDocument.Parse(responseContent).RootElement.GetProperty("data");
var frontendParams = JsonSerializer.Deserialize<JsonDocument>(frontendObject.ToString());
Console.WriteLine("Input range configured to : {0}", frontendParams.RootElement.GetProperty("range"));
}
else
{
Console.WriteLine("Unexpected error: HTTP Response Code {0}", frontendResponse.StatusCode);
}
//Get Data
StringContent getDataContent = new StringContent(JsonSerializer.Serialize(new { wait_reacquire = false }));
HttpResponseMessage getDataResponse = await client.PostAsync("oscilloscope/get_data", getDataContent);
if (getDataResponse.IsSuccessStatusCode)
{
string responseContent = getDataResponse.Content.ReadAsStringAsync().Result;
var getDataObject = JsonDocument.Parse(responseContent).RootElement.GetProperty("data");
Console.WriteLine("Channel1 data: {0}", getDataObject.GetProperty("ch1"));
}
else
{
Console.WriteLine("Unexpected error: HTTP Response Code {0}", getDataResponse.StatusCode);
}
}
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
# Go
// Simple example of interacting with a Moku REST API from Go.
// This prioritises simplicity over, e.g. type safety so request bodies are formed
// as string and returns are unmarshalled to maps rather than structs.
package main
import (
"bytes"
"encoding/json"
"errors"
"fmt"
"io/ioutil"
"log"
"net/http"
)
// These fields are case-insensitively matched against the JSON field names and therefore
// capitalized according to Go convention rather than exactly matching the JSON.
type moku_response struct {
Success bool
Data interface{}
Messages []string
Code string
}
func do_rest_request(base_url, client_key, endpoint string, body []byte) (interface{}, error) {
client := &http.Client{}
req, err := http.NewRequest("POST", base_url+endpoint, bytes.NewReader(body))
if err != nil {
return nil, err
}
req.Header.Add("content-type", "application/json")
if client_key != "" {
req.Header.Add("Moku-Client-Key", client_key)
}
resp, err := client.Do(req)
if err != nil {
return nil, err
}
defer resp.Body.Close()
respBody, readErr := ioutil.ReadAll(resp.Body)
if readErr != nil {
return nil, readErr
}
response := moku_response{}
jsonErr := json.Unmarshal(respBody, &response)
if jsonErr != nil {
return nil, jsonErr
}
if response.Success == false {
return nil, errors.New(response.Messages[0])
}
return response.Data, nil
}
func take_ownership(base_url string) (string, error) {
data, err := do_rest_request(base_url, "", "moku/claim_ownership", nil)
if err != nil {
return "", err
}
return data.(string), nil
}
func relinquish_ownership(base_url, client_key string) error {
_, err := do_rest_request(base_url, client_key, "moku/relinquish_ownership", nil)
return err
}
func main() {
// Change your IP address here
base_url := "http://192.168.73.1/api/"
// The data returned from the take ownership request is exactly the client key (as well as the key
// being present in a header)
client_key, err := take_ownership(base_url)
if err != nil {
log.Fatal(err)
}
defer relinquish_ownership(base_url, client_key)
// Now that we have ownership, and a client key to prove it, we can issue requests to any other endpoint we like.
// Here the JSON body is formed directly as a byte array, you can also use the JSON library to marshall a struct
// with the parameters if you prefer to keep strong typing on the requests.
_, err = do_rest_request(base_url, client_key, "oscilloscope/set_frontend",
[]byte(`{"channel": 1, "impedance": "1MOhm", "coupling": "AC", "range": "10Vpp"}`))
data, err := do_rest_request(base_url, client_key, "oscilloscope/get_data", []byte(`{"wait_reacquire": false}`))
// At this point, the actual request-specific response data (right now, frame data) is just in a map.
// If you want to maintain type safety, you can:
// 1. Open-code more of the do_rest_request so you can pass a response-specific struct to the unmarshalling
// 2. Re-structure it with e.g https://github.com/mitchellh/mapstructure
// 3. Make do_rest_response generic on the return structure (requires Go 1.18+, still in beta at the time of writing)
fmt.Println(data.(map[string]interface{})["ch1"])
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
# Java
/*
* Simple Java example on how to use the Moku REST API for Liquid Instrument Moku Devices.
* IMPORTANT: Deploy the Oscilloscope through the Desktop or iPad apps before
* running this script in order to transfer the instrument data. See
* https://apis.liquidinstruments.com/starting-curl.html#first-steps
* NOTE: This example uses cliftonlabs json-simple library to serialize/de-serialize request
* and response. For more information, please visit https://cliftonlabs.github.io/json-simple/
* NOTE: This example demonstrates how to deploy and interact with an Oscilloscope.
* Details on list of methods and associated request schemas can be found at
* https://apis.liquidinstruments.com/reference/oscilloscope/
*/
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.net.http.HttpResponse.BodyHandlers;
import java.util.Map;
import static java.util.Map.entry;
import java.net.http.HttpRequest.BodyPublishers;
import com.github.cliftonlabs.json_simple.JsonObject;
import com.github.cliftonlabs.json_simple.Jsoner;
public class MokuDemo {
static String ipAddress = "192.168.73.1";
private static JsonObject executeAPICall(HttpRequest request, HttpClient client) throws Exception {
HttpResponse<String> getDataResponse = client.send(request, BodyHandlers.ofString());
if (getDataResponse.statusCode() != 200) {
String errorText = String.format("Error occurred. Response code: %d", getDataResponse.statusCode());
throw new Exception(errorText);
}
JsonObject data = (JsonObject) Jsoner.deserialize(getDataResponse.body());
if (!(Boolean) data.get("success")) {
System.out.println(data.get("messages"));
}
Object returnData = data.get("data");
if (returnData.getClass().getName() == "java.lang.String") {
return (JsonObject) Jsoner.deserialize((String) returnData);
}
return (JsonObject) returnData;
}
public static void main(String[] args) throws Exception {
HttpClient client = HttpClient.newHttpClient();
/*
* The first thing we need to do is to take ownership of the Moku.
* We do that by sending a `POST` to the `claim_ownership` resource and it
* gives us back a key that we can include in all future requests to prove we
* are the owner.
*/
String clientKeyURI = String.format("http://%s/api/moku/claim_ownership", ipAddress);
HttpRequest clientKeyRequest = HttpRequest.newBuilder()
.uri(URI.create(clientKeyURI))
.headers("Content-Type", "application/json")
.POST(BodyPublishers.noBody())
.build();
HttpResponse<String> clientKeyResponse = client.send(clientKeyRequest, BodyHandlers.ofString());
String clientKey = clientKeyResponse.headers().firstValue("Moku-Client-Key").orElseThrow();
// Get the Moku's name
String mokuNameURI = String.format("http://%s/api/moku/name", ipAddress);
HttpRequest nameRequest = HttpRequest.newBuilder()
.uri(URI.create(mokuNameURI))
.headers("Content-Type", "application/json")
.headers("Moku-Client-Key", clientKey)
.GET()
.build();
HttpResponse<String> nameResponse = client.send(nameRequest, BodyHandlers.ofString());
System.out.println(nameResponse.body());
/*
* As you can see, all responses from the Moku are formatted as a JSON
* dictionary
* with four properties. `success` can be true or false depending whether what
* you asked for was valid. It it's true, `data` contains the value(s) you asked
* for.
* If it's false then `code` and `messages` tell you why.
*
* The first time you access an instrument's resource, that instrument is
* deployed.
* Here we set the Oscilloscope frontend, implicitly deploying it first.
*/
JsonObject obj = new JsonObject().putAllChain(Map.ofEntries(
entry("channel", 1),
entry("range", "10Vpp"),
entry("coupling", "AC"),
entry("impedance", "1MOhm")));
String frontendURI = String.format("http://%s/api/oscilloscope/set_frontend", ipAddress);
HttpRequest frontendRequest = HttpRequest.newBuilder()
.uri(URI.create(frontendURI))
.headers("Content-Type", "application/json")
.headers("Moku-Client-Key", clientKey)
.POST(BodyPublishers.ofString(obj.toJson()))
.build();
JsonObject frontendResponse = executeAPICall(frontendRequest, client);
// Print the impedance deserialized from response object
System.out.println(frontendResponse.get("impedance"));
/*
* Now that instrument is deployed, we can read out a frame of data using the
* get_data method which returns time series data for channels 1 & 2.
*/
JsonObject getDataRequestBody = new JsonObject().putAllChain(
Map.ofEntries(entry("wait_reacquire", true)));
String getDataURI = String.format("http://%s/api/oscilloscope/get_data", ipAddress);
HttpRequest getDataRequest = HttpRequest.newBuilder()
.uri(URI.create(getDataURI))
.headers("Content-Type", "application/json")
.headers("Moku-Client-Key", clientKey)
.POST(BodyPublishers.ofString(getDataRequestBody.toJson()))
.build();
JsonObject getDataResponse = executeAPICall(getDataRequest, client);
System.out.println(getDataResponse.get("ch1"));
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
# Javascript (Node.js)
/**
* Let's Moku!
*
* We're going to poke and prod a little bit at the Moku's API server directly
* using just node.js's `request` library. The below code assumes you are connected
* to your Moku's WiFi access point. If this isn't true, replace the IP address
* below with your Moku's address as read out of the Moku desktop app.
*
* This can be run using `node moku-node.js` with node v14+
* First, run `npm install --save request`
**/
const request = require('request')
// Helper function for making HTTP requests asynchronously
// options is a dict containing url, method, headers dict (optional), body (optional)
async function makeRequest(options) {
return new Promise((resolve, reject) => {
request(options, (err, response, body) => {
if (err) reject(err)
else resolve({ body, response })
})
})
}
async function main() {
/*
* The first thing we need to do is to take ownership of the Moku.
* We do that by sending a `POST` to the `claim_ownership` resource and it
* gives us back a key that we can include in all future requests to prove we
* are the owner.
*/
const IP_ADDRESS = '192.168.73.1'
let response = await makeRequest({
url: `http://${IP_ADDRESS}/api/moku/claim_ownership`,
method: 'POST',
})
console.log(JSON.parse(response.body))
const clientKey = response.response.headers['moku-client-key']
// Get the Moku's name
response = await makeRequest({
url: `http://${IP_ADDRESS}/api/moku/name`, method: 'GET',
headers: { 'Moku-Client-Key': clientKey }
})
console.log(JSON.parse(response.body))
/*
* As you can see, all responses from the Moku are formatted as a JSON dictionary
* with four properties. `success` can be true or false depending whether what
* you asked for was valid. It it's true, `data` contains the value(s) you asked for.
* If it's false then `code` and `messages` tell you why.
*
* The first time you access an instrument's resource, that instrument is deployed.
* Here we set the Oscilloscope frontend, implicitly deploying it first.
*/
response = await makeRequest({
url: `http://${IP_ADDRESS}/api/oscilloscope/set_frontend`,
method: 'POST',
body: JSON.stringify({ channel: 1, range: '10Vpp', coupling: 'AC', impedance: '1MOhm' }),
headers: { 'Moku-Client-Key': clientKey }
})
console.log(JSON.parse(response.body))
response = await makeRequest({
url: `http://${IP_ADDRESS}/api/oscilloscope/get_data`,
method: 'POST',
body: JSON.stringify({ wait_reacquire: false }),
headers: { 'Moku-Client-Key': clientKey }
})
// This prints out a frame dictionary like so:
// { time: [-0.005, -0.004, -0.003, ...], ch1: [0.0, 0.0, 0.0, ...], ... }
console.log(JSON.parse(response.body).data)
}
main()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
# Perl
# Simple example of using the Moku REST API for Liquid Instruments Moku devices.
# IMPORTANT: Deploy the Oscilloscope through the Desktop or iPad apps before
# running this script in order to transfer the instrument data. See
# https://apis.liquidinstruments.com/starting-curl.html#first-steps
use warnings;
use strict;
use Data::Dumper;
use JSON;
use REST::Client;
# Create a REST Client pointed at our Moku's IP address.
# All Moku REST endpoints expect (and return) JSON bodies, so we attach that header
# permanently to the client (rather than passing per-request).
my $client = REST::Client->new();
$client->setHost('http://192.168.73.1');
$client->addHeader('content-type', 'application/json');
# The first step with the Moku REST API is to claim ownership. A POST to this endpoint
# returns a client key which we also permanently attach to the client so it gets presented
# on each later call. You can also pass the request body '{"force_connect": true}' if you
# want to take over ownership regardless of the current ownership status.
my $key = $client->POST('/api/moku/claim_ownership')->responseHeader('Moku-Client-Key');
$client->addHeader('Moku-Client-Key', $key);
# Do a few operations targeting the Oscilloscope instrument. The bodies can be marshalled/
# /unmarshalled to/from JSON using the JSON library, or can be presented statically as a string
# if you prefer (e.g. if it's all constants anyway).
$client->POST('/api/oscilloscope/set_frontend',
'{"channel": 1, "impedance": "1MOhm", "range": "10Vpp", "coupling": "DC"}'
);
my $responseFrame = from_json $client->POST('/api/oscilloscope/get_data',
'{"wait_reacquire": false}'
)->responseContent();
my %dataFrame = %{$responseFrame->{data}};
# Just print the keys of the returned data frame, in a real program you'd do something with the data!
print Dumper(keys %dataFrame);
# Don't forget to relinquish ownership at the end. If you miss this line, e.g. because a line
# above croaks, then you (and anyone else) will need to force_connect next time around.
$client->POST('/api/moku/relinquish_ownership');
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
# Rust
use std::error::Error;
/**
* Let's Moku!
*
* We're going to poke and prod a little bit at the Moku's API server directly
* using just the `reqwest` and `json` Rust crates. The below code assumes you are connected
* to your Moku's WiFi access point. If this isn't true, replace the IP address
* below with your Moku's address as read out of the Moku desktop app.
*
* We use the `reqwest` crate to do blocking HTTP requests.
* You'll need to add `reqwest` and `json` to your `Cargo.toml` file as follows:
* [dependencies]
* reqwest = { version = "0.11", features = ["blocking"] }
* json = { version = "0.12.4" }
*
* If you're starting a Rust project from scratch, you should:
* 1. Run `cargo new mokurs` and `cd mokurs`
* 2. Replace `src/main.rs` with the contents of this file
* 3. Add the dependencies section above to `Cargo.toml`
* 4. Run `cargo run`
**/
fn main() -> Result<(), Box<dyn Error>> {
/*
* The first thing we need to do is to take ownership of the Moku.
* We do that by sending a `POST` to the `claim_ownership` resource and it
* gives us back a key that we can include in all future requests to prove we
* are the owner.
*/
const IP_ADDRESS: &str = "192.168.73.1";
let client = reqwest::blocking::Client::new();
// We must supply an empty body, otherwise the request will be malformed
let client_key: String = {
let resp = client.post(format!("http://{IP_ADDRESS}/api/moku/claim_ownership"))
.body("").send()?;
let client_key: String = String::from(resp.headers().get("Moku-Client-Key").unwrap().to_str()?);
println!("{}", json::parse(&resp.text()?[..])?); // moves resp
client_key
};
// Get the Moku's name
{
let resp = client.get(format!("http://{IP_ADDRESS}/api/moku/name"))
.header("Moku-Client-Key", client_key.clone()).send()?;
println!("{}", json::parse(&resp.text()?[..])?);
}
/*
* As you can see, all responses from the Moku are formatted as a JSON dictionary
* with four properties. `success` can be true or false depending whether what
* you asked for was valid. It it's true, `data` contains the value(s) you asked for.
* If it's false then `code` and `messages` tell you why.
*
* The first time you access an instrument's resource, that instrument is deployed.
* Here we set the Oscilloscope frontend, implicitly deploying it first.
*/
{
let options = json::object!{
channel: 1,
range: "10Vpp",
coupling: "AC",
impedance: "1MOhm"
};
let resp = client.post(format!("http://{IP_ADDRESS}/api/oscilloscope/set_frontend"))
.header("Moku-Client-Key", client_key.clone())
.body(options.dump())
.send()?;
println!("{}", json::parse(&resp.text()?[..])?);
}
// Get a frame of data
{
let resp = client.post(format!("http://{IP_ADDRESS}/api/oscilloscope/get_data"))
.header("Moku-Client-Key", client_key.clone())
.body("{\"wait_reacquire\": false}")
.send()?;
let result: json::JsonValue = json::parse(&resp.text()?[..])?;
// We print out result['data']['ch1'], which is an array of floats
if let json::JsonValue::Object(res_obj) = result {
if let json::JsonValue::Object(data_obj) = res_obj.get("data").unwrap() {
println!("{}", data_obj.get("ch1").unwrap());
}
}
}
Ok(())
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88