act-cli 0.7.0__tar.gz → 0.7.2__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {act_cli-0.7.0 → act_cli-0.7.2}/Cargo.lock +2 -2
- {act_cli-0.7.0 → act_cli-0.7.2}/Cargo.toml +1 -1
- {act_cli-0.7.0 → act_cli-0.7.2}/PKG-INFO +1 -1
- {act_cli-0.7.0 → act_cli-0.7.2}/act-cli/src/main.rs +146 -142
- {act_cli-0.7.0 → act_cli-0.7.2}/README.md +0 -0
- {act_cli-0.7.0 → act_cli-0.7.2}/act-cli/Cargo.toml +0 -0
- {act_cli-0.7.0 → act_cli-0.7.2}/act-cli/README.md +0 -0
- {act_cli-0.7.0 → act_cli-0.7.2}/act-cli/build.rs +0 -0
- {act_cli-0.7.0 → act_cli-0.7.2}/act-cli/src/config.rs +0 -0
- {act_cli-0.7.0 → act_cli-0.7.2}/act-cli/src/format.rs +0 -0
- {act_cli-0.7.0 → act_cli-0.7.2}/act-cli/src/http.rs +0 -0
- {act_cli-0.7.0 → act_cli-0.7.2}/act-cli/src/resolve.rs +0 -0
- {act_cli-0.7.0 → act_cli-0.7.2}/act-cli/src/rmcp_bridge.rs +0 -0
- {act_cli-0.7.0 → act_cli-0.7.2}/act-cli/src/runtime/bindings/mod.rs +0 -0
- {act_cli-0.7.0 → act_cli-0.7.2}/act-cli/src/runtime/effective.rs +0 -0
- {act_cli-0.7.0 → act_cli-0.7.2}/act-cli/src/runtime/fs_matcher.rs +0 -0
- {act_cli-0.7.0 → act_cli-0.7.2}/act-cli/src/runtime/fs_policy.rs +0 -0
- {act_cli-0.7.0 → act_cli-0.7.2}/act-cli/src/runtime/http_client.rs +0 -0
- {act_cli-0.7.0 → act_cli-0.7.2}/act-cli/src/runtime/http_policy.rs +0 -0
- {act_cli-0.7.0 → act_cli-0.7.2}/act-cli/src/runtime/mod.rs +0 -0
- {act_cli-0.7.0 → act_cli-0.7.2}/act-cli/src/runtime/network.rs +0 -0
- {act_cli-0.7.0 → act_cli-0.7.2}/act-cli/src/runtime/sessions.rs +0 -0
- {act_cli-0.7.0 → act_cli-0.7.2}/act-cli/wit/deps/act-core/act-core.wit +0 -0
- {act_cli-0.7.0 → act_cli-0.7.2}/act-cli/wit/deps/act-tools/act-tools.wit +0 -0
- {act_cli-0.7.0 → act_cli-0.7.2}/act-cli/wit/deps.lock +0 -0
- {act_cli-0.7.0 → act_cli-0.7.2}/act-cli/wit/deps.toml +0 -0
- {act_cli-0.7.0 → act_cli-0.7.2}/act-cli/wit/world.wit +0 -0
- {act_cli-0.7.0 → act_cli-0.7.2}/pyproject.toml +0 -0
|
@@ -4,7 +4,7 @@ version = 4
|
|
|
4
4
|
|
|
5
5
|
[[package]]
|
|
6
6
|
name = "act-build"
|
|
7
|
-
version = "0.7.
|
|
7
|
+
version = "0.7.2"
|
|
8
8
|
dependencies = [
|
|
9
9
|
"act-types",
|
|
10
10
|
"anyhow",
|
|
@@ -25,7 +25,7 @@ dependencies = [
|
|
|
25
25
|
|
|
26
26
|
[[package]]
|
|
27
27
|
name = "act-cli"
|
|
28
|
-
version = "0.7.
|
|
28
|
+
version = "0.7.2"
|
|
29
29
|
dependencies = [
|
|
30
30
|
"act-types",
|
|
31
31
|
"anyhow",
|
|
@@ -104,6 +104,16 @@ enum Command {
|
|
|
104
104
|
#[arg(long, default_value = "{}")]
|
|
105
105
|
args: String,
|
|
106
106
|
|
|
107
|
+
/// Session args as a JSON object. When set, the host opens a
|
|
108
|
+
/// session before the call (`open-session(args, metadata)`),
|
|
109
|
+
/// injects the returned id as `std:session-id` metadata for
|
|
110
|
+
/// the tool call, and closes the session before exit. Use
|
|
111
|
+
/// this when the component requires a session — bridges,
|
|
112
|
+
/// stateful components — and you want the whole open/call/
|
|
113
|
+
/// close cycle in one process.
|
|
114
|
+
#[arg(long)]
|
|
115
|
+
session_args: Option<String>,
|
|
116
|
+
|
|
107
117
|
#[command(flatten)]
|
|
108
118
|
opts: CommonOpts,
|
|
109
119
|
},
|
|
@@ -146,7 +156,12 @@ enum Command {
|
|
|
146
156
|
#[arg(short = 'O', conflicts_with = "output")]
|
|
147
157
|
output_from_ref: bool,
|
|
148
158
|
},
|
|
149
|
-
///
|
|
159
|
+
/// Inspect `act:sessions/session-provider` — currently only
|
|
160
|
+
/// `open-args-schema`, since opening or closing a session from a
|
|
161
|
+
/// one-shot CLI invocation cannot keep the underlying wasm state
|
|
162
|
+
/// alive. For real session work, use `act run --http` or
|
|
163
|
+
/// `act run --mcp` (the host process holds the wasm instance and
|
|
164
|
+
/// the session lives as long as the host).
|
|
150
165
|
#[command(subcommand)]
|
|
151
166
|
Session(SessionCommand),
|
|
152
167
|
}
|
|
@@ -159,22 +174,6 @@ enum SessionCommand {
|
|
|
159
174
|
#[command(flatten)]
|
|
160
175
|
opts: CommonOpts,
|
|
161
176
|
},
|
|
162
|
-
/// Open a new session, print the session record (id + metadata) as JSON.
|
|
163
|
-
Open {
|
|
164
|
-
component: ComponentRef,
|
|
165
|
-
/// JSON object with session-args.
|
|
166
|
-
#[arg(long, default_value = "{}")]
|
|
167
|
-
args: String,
|
|
168
|
-
#[command(flatten)]
|
|
169
|
-
opts: CommonOpts,
|
|
170
|
-
},
|
|
171
|
-
/// Close a session by id.
|
|
172
|
-
Close {
|
|
173
|
-
component: ComponentRef,
|
|
174
|
-
session_id: String,
|
|
175
|
-
#[command(flatten)]
|
|
176
|
-
opts: CommonOpts,
|
|
177
|
-
},
|
|
178
177
|
}
|
|
179
178
|
|
|
180
179
|
#[tokio::main]
|
|
@@ -198,9 +197,7 @@ async fn main() -> Result<()> {
|
|
|
198
197
|
}
|
|
199
198
|
Command::Skill { .. } | Command::Pull { .. } => None,
|
|
200
199
|
Command::Session(sub) => match sub {
|
|
201
|
-
SessionCommand::OpenArgsSchema { opts, .. }
|
|
202
|
-
| SessionCommand::Open { opts, .. }
|
|
203
|
-
| SessionCommand::Close { opts, .. } => opts.config.as_deref(),
|
|
200
|
+
SessionCommand::OpenArgsSchema { opts, .. } => opts.config.as_deref(),
|
|
204
201
|
},
|
|
205
202
|
};
|
|
206
203
|
let log_level = config::load_config(config_path)
|
|
@@ -230,8 +227,9 @@ async fn main() -> Result<()> {
|
|
|
230
227
|
component,
|
|
231
228
|
tool,
|
|
232
229
|
args,
|
|
230
|
+
session_args,
|
|
233
231
|
opts,
|
|
234
|
-
} => cmd_call(component, tool, args, opts).await,
|
|
232
|
+
} => cmd_call(component, tool, args, session_args, opts).await,
|
|
235
233
|
Command::Info {
|
|
236
234
|
component,
|
|
237
235
|
tools,
|
|
@@ -248,16 +246,6 @@ async fn main() -> Result<()> {
|
|
|
248
246
|
SessionCommand::OpenArgsSchema { component, opts } => {
|
|
249
247
|
cmd_session_open_args_schema(component, opts).await
|
|
250
248
|
}
|
|
251
|
-
SessionCommand::Open {
|
|
252
|
-
component,
|
|
253
|
-
args,
|
|
254
|
-
opts,
|
|
255
|
-
} => cmd_session_open(component, args, opts).await,
|
|
256
|
-
SessionCommand::Close {
|
|
257
|
-
component,
|
|
258
|
-
session_id,
|
|
259
|
-
opts,
|
|
260
|
-
} => cmd_session_close(component, session_id, opts).await,
|
|
261
249
|
},
|
|
262
250
|
}
|
|
263
251
|
}
|
|
@@ -442,6 +430,7 @@ async fn cmd_call(
|
|
|
442
430
|
component: ComponentRef,
|
|
443
431
|
tool: String,
|
|
444
432
|
args: String,
|
|
433
|
+
session_args: Option<String>,
|
|
445
434
|
opts: CommonOpts,
|
|
446
435
|
) -> Result<()> {
|
|
447
436
|
let pc = prepare_component(&component, &opts).await?;
|
|
@@ -450,109 +439,113 @@ async fn cmd_call(
|
|
|
450
439
|
serde_json::from_str(&args).context("invalid --args JSON")?;
|
|
451
440
|
let cbor_args = cbor::json_to_cbor(&arguments).context("encoding args as CBOR")?;
|
|
452
441
|
|
|
442
|
+
// If --session-args is set, open a session before the call and
|
|
443
|
+
// close it on the way out. session-id is injected into the call's
|
|
444
|
+
// metadata under `std:session-id`.
|
|
445
|
+
let session_id = match session_args {
|
|
446
|
+
Some(json) => {
|
|
447
|
+
if !pc.has_sessions {
|
|
448
|
+
anyhow::bail!(
|
|
449
|
+
"--session-args was set, but the component does not export \
|
|
450
|
+
act:sessions/session-provider"
|
|
451
|
+
);
|
|
452
|
+
}
|
|
453
|
+
Some(open_session_for_call(&pc, &json).await?)
|
|
454
|
+
}
|
|
455
|
+
None => None,
|
|
456
|
+
};
|
|
457
|
+
|
|
458
|
+
let mut metadata = pc.metadata.clone();
|
|
459
|
+
if let Some(ref id) = session_id {
|
|
460
|
+
metadata.insert(
|
|
461
|
+
act_types::constants::META_SESSION_ID,
|
|
462
|
+
serde_json::Value::String(id.clone()),
|
|
463
|
+
);
|
|
464
|
+
}
|
|
465
|
+
|
|
453
466
|
let (reply_tx, reply_rx) = tokio::sync::oneshot::channel();
|
|
454
467
|
let request = runtime::ComponentRequest::CallTool {
|
|
455
468
|
name: tool,
|
|
456
469
|
arguments: cbor_args,
|
|
457
|
-
metadata:
|
|
470
|
+
metadata: metadata.into(),
|
|
458
471
|
reply: reply_tx,
|
|
459
472
|
};
|
|
460
473
|
|
|
461
|
-
pc.handle
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
474
|
+
let send_result = pc.handle.send(request).await;
|
|
475
|
+
let call_result = match send_result {
|
|
476
|
+
Err(_) => Err(anyhow::anyhow!("component actor unavailable")),
|
|
477
|
+
Ok(()) => match reply_rx.await {
|
|
478
|
+
Err(_) => Err(anyhow::anyhow!("component actor dropped reply")),
|
|
479
|
+
Ok(r) => Ok(r),
|
|
480
|
+
},
|
|
481
|
+
};
|
|
465
482
|
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
}
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
483
|
+
// Best-effort close before returning the call result, so the
|
|
484
|
+
// session is closed even if the call errored.
|
|
485
|
+
if let Some(id) = session_id {
|
|
486
|
+
close_session_best_effort(&pc, id).await;
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
let result = call_result?.map_err(|e| match e {
|
|
490
|
+
runtime::ComponentError::Tool(te) => {
|
|
491
|
+
let ls = act_types::types::LocalizedString::from(&te.message);
|
|
492
|
+
anyhow::anyhow!("{}: {}", te.kind, ls.any_text())
|
|
493
|
+
}
|
|
494
|
+
runtime::ComponentError::Internal(e) => e,
|
|
495
|
+
})?;
|
|
496
|
+
|
|
497
|
+
for event in &result.events {
|
|
498
|
+
match event {
|
|
499
|
+
runtime::exports::act::tools::tool_provider::ToolEvent::Content(part) => {
|
|
500
|
+
let mime = part.mime_type.as_deref().unwrap_or("application/cbor");
|
|
501
|
+
if mime.starts_with("text/")
|
|
502
|
+
|| mime == "application/json"
|
|
503
|
+
|| mime == "application/xml"
|
|
504
|
+
{
|
|
505
|
+
let text = String::from_utf8_lossy(&part.data);
|
|
506
|
+
println!("{text}");
|
|
507
|
+
} else if mime == "application/cbor" {
|
|
508
|
+
let json_val = act_types::cbor::cbor_to_json(&part.data).unwrap_or_else(|_| {
|
|
509
|
+
serde_json::Value::String(format!(
|
|
510
|
+
"[binary: {}, {} bytes]",
|
|
511
|
+
mime,
|
|
512
|
+
part.data.len()
|
|
513
|
+
))
|
|
514
|
+
});
|
|
515
|
+
match json_val {
|
|
516
|
+
serde_json::Value::String(s) => println!("{s}"),
|
|
517
|
+
other => println!("{}", serde_json::to_string_pretty(&other)?),
|
|
501
518
|
}
|
|
519
|
+
} else if std::io::IsTerminal::is_terminal(&std::io::stdout()) {
|
|
520
|
+
println!("[binary: {}, {} bytes]", mime, part.data.len());
|
|
521
|
+
} else {
|
|
522
|
+
use std::io::Write;
|
|
523
|
+
std::io::stdout().write_all(&part.data)?;
|
|
502
524
|
}
|
|
503
525
|
}
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
let ls = act_types::types::LocalizedString::from(&te.message);
|
|
508
|
-
anyhow::bail!("{}: {}", te.kind, ls.any_text());
|
|
509
|
-
}
|
|
510
|
-
Err(runtime::ComponentError::Internal(e)) => Err(e),
|
|
511
|
-
}
|
|
512
|
-
}
|
|
513
|
-
|
|
514
|
-
// ── Session subcommands ────────────────────────────────────────────────────
|
|
515
|
-
|
|
516
|
-
async fn cmd_session_open_args_schema(component: ComponentRef, opts: CommonOpts) -> Result<()> {
|
|
517
|
-
let pc = prepare_component(&component, &opts).await?;
|
|
518
|
-
let (reply_tx, reply_rx) = tokio::sync::oneshot::channel();
|
|
519
|
-
pc.handle
|
|
520
|
-
.send(runtime::ComponentRequest::GetOpenSessionArgsSchema {
|
|
521
|
-
metadata: pc.metadata.clone().into(),
|
|
522
|
-
reply: reply_tx,
|
|
523
|
-
})
|
|
524
|
-
.await
|
|
525
|
-
.map_err(|_| anyhow::anyhow!("component actor unavailable"))?;
|
|
526
|
-
match reply_rx.await? {
|
|
527
|
-
Ok(schema) => {
|
|
528
|
-
// Pretty-print if it's valid JSON; otherwise print as-is.
|
|
529
|
-
match serde_json::from_str::<serde_json::Value>(&schema) {
|
|
530
|
-
Ok(v) => println!("{}", serde_json::to_string_pretty(&v)?),
|
|
531
|
-
Err(_) => println!("{schema}"),
|
|
526
|
+
runtime::exports::act::tools::tool_provider::ToolEvent::Error(err) => {
|
|
527
|
+
let ls = act_types::types::LocalizedString::from(&err.message);
|
|
528
|
+
anyhow::bail!("{}: {}", err.kind, ls.any_text());
|
|
532
529
|
}
|
|
533
|
-
Ok(())
|
|
534
530
|
}
|
|
535
|
-
Err(runtime::ComponentError::Tool(te)) => {
|
|
536
|
-
let ls = act_types::types::LocalizedString::from(&te.message);
|
|
537
|
-
anyhow::bail!("{}: {}", te.kind, ls.any_text());
|
|
538
|
-
}
|
|
539
|
-
Err(runtime::ComponentError::Internal(e)) => Err(e),
|
|
540
531
|
}
|
|
532
|
+
Ok(())
|
|
541
533
|
}
|
|
542
534
|
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
let
|
|
548
|
-
serde_json::from_str(
|
|
549
|
-
let serde_json::Value::Object(args_obj) =
|
|
550
|
-
anyhow::bail!("--args must be a JSON object");
|
|
535
|
+
/// Marshal a JSON object of session args into the WIT shape and call
|
|
536
|
+
/// `open-session` against the prepared component. Returns the
|
|
537
|
+
/// allocated session-id.
|
|
538
|
+
async fn open_session_for_call(pc: &PreparedComponent, json: &str) -> Result<String> {
|
|
539
|
+
let value: serde_json::Value =
|
|
540
|
+
serde_json::from_str(json).context("invalid --session-args JSON")?;
|
|
541
|
+
let serde_json::Value::Object(args_obj) = value else {
|
|
542
|
+
anyhow::bail!("--session-args must be a JSON object");
|
|
551
543
|
};
|
|
552
544
|
let mut wit_args: Vec<(String, Vec<u8>)> = Vec::with_capacity(args_obj.len());
|
|
553
545
|
for (key, value) in args_obj {
|
|
554
|
-
let
|
|
555
|
-
|
|
546
|
+
let bytes =
|
|
547
|
+
act_types::cbor::json_to_cbor(&value).context("encoding session arg as CBOR")?;
|
|
548
|
+
wit_args.push((key, bytes));
|
|
556
549
|
}
|
|
557
550
|
|
|
558
551
|
let (reply_tx, reply_rx) = tokio::sync::oneshot::channel();
|
|
@@ -566,47 +559,58 @@ async fn cmd_session_open(component: ComponentRef, args: String, opts: CommonOpt
|
|
|
566
559
|
.map_err(|_| anyhow::anyhow!("component actor unavailable"))?;
|
|
567
560
|
|
|
568
561
|
match reply_rx.await? {
|
|
569
|
-
Ok(session) =>
|
|
570
|
-
// Re-emit metadata as JSON object for human consumption.
|
|
571
|
-
let metadata_json: serde_json::Map<String, serde_json::Value> = session
|
|
572
|
-
.metadata
|
|
573
|
-
.iter()
|
|
574
|
-
.filter_map(|(k, v)| {
|
|
575
|
-
let val = act_types::cbor::cbor_to_json(v).ok()?;
|
|
576
|
-
Some((k.clone(), val))
|
|
577
|
-
})
|
|
578
|
-
.collect();
|
|
579
|
-
let out = serde_json::json!({
|
|
580
|
-
"id": session.id,
|
|
581
|
-
"metadata": metadata_json,
|
|
582
|
-
});
|
|
583
|
-
println!("{}", serde_json::to_string_pretty(&out)?);
|
|
584
|
-
Ok(())
|
|
585
|
-
}
|
|
562
|
+
Ok(session) => Ok(session.id),
|
|
586
563
|
Err(runtime::ComponentError::Tool(te)) => {
|
|
587
564
|
let ls = act_types::types::LocalizedString::from(&te.message);
|
|
588
|
-
anyhow::bail!("{}: {}", te.kind, ls.any_text());
|
|
565
|
+
anyhow::bail!("open-session failed: {}: {}", te.kind, ls.any_text());
|
|
589
566
|
}
|
|
590
|
-
Err(runtime::ComponentError::Internal(e)) => Err(e),
|
|
567
|
+
Err(runtime::ComponentError::Internal(e)) => Err(e.context("open-session failed")),
|
|
591
568
|
}
|
|
592
569
|
}
|
|
593
570
|
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
)
|
|
571
|
+
/// Best-effort close. Logs failures at debug; never propagates errors,
|
|
572
|
+
/// because the call result is what the user asked for and a failed
|
|
573
|
+
/// close should not surface as the command's exit code.
|
|
574
|
+
async fn close_session_best_effort(pc: &PreparedComponent, session_id: String) {
|
|
575
|
+
let (reply_tx, reply_rx) = tokio::sync::oneshot::channel();
|
|
576
|
+
if pc
|
|
577
|
+
.handle
|
|
578
|
+
.send(runtime::ComponentRequest::CloseSession {
|
|
579
|
+
session_id: session_id.clone(),
|
|
580
|
+
reply: reply_tx,
|
|
581
|
+
})
|
|
582
|
+
.await
|
|
583
|
+
.is_err()
|
|
584
|
+
{
|
|
585
|
+
tracing::debug!(%session_id, "actor unavailable for close-session");
|
|
586
|
+
return;
|
|
587
|
+
}
|
|
588
|
+
if let Err(e) = reply_rx.await {
|
|
589
|
+
tracing::debug!(%session_id, error = %e, "close-session reply dropped");
|
|
590
|
+
}
|
|
591
|
+
}
|
|
592
|
+
|
|
593
|
+
// ── Session subcommands ────────────────────────────────────────────────────
|
|
594
|
+
|
|
595
|
+
async fn cmd_session_open_args_schema(component: ComponentRef, opts: CommonOpts) -> Result<()> {
|
|
599
596
|
let pc = prepare_component(&component, &opts).await?;
|
|
600
597
|
let (reply_tx, reply_rx) = tokio::sync::oneshot::channel();
|
|
601
598
|
pc.handle
|
|
602
|
-
.send(runtime::ComponentRequest::
|
|
603
|
-
|
|
599
|
+
.send(runtime::ComponentRequest::GetOpenSessionArgsSchema {
|
|
600
|
+
metadata: pc.metadata.clone().into(),
|
|
604
601
|
reply: reply_tx,
|
|
605
602
|
})
|
|
606
603
|
.await
|
|
607
604
|
.map_err(|_| anyhow::anyhow!("component actor unavailable"))?;
|
|
608
605
|
match reply_rx.await? {
|
|
609
|
-
Ok(
|
|
606
|
+
Ok(schema) => {
|
|
607
|
+
// Pretty-print if it's valid JSON; otherwise print as-is.
|
|
608
|
+
match serde_json::from_str::<serde_json::Value>(&schema) {
|
|
609
|
+
Ok(v) => println!("{}", serde_json::to_string_pretty(&v)?),
|
|
610
|
+
Err(_) => println!("{schema}"),
|
|
611
|
+
}
|
|
612
|
+
Ok(())
|
|
613
|
+
}
|
|
610
614
|
Err(runtime::ComponentError::Tool(te)) => {
|
|
611
615
|
let ls = act_types::types::LocalizedString::from(&te.message);
|
|
612
616
|
anyhow::bail!("{}: {}", te.kind, ls.any_text());
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|