2024-02-14 16:32:01 +01:00
|
|
|
// Use libraries
|
|
|
|
use adw::prelude::*;
|
|
|
|
use adw::*;
|
2024-02-16 22:21:09 +01:00
|
|
|
use glib::*;
|
|
|
|
/// Use all gtk4 libraries (gtk4 -> gtk because cargo)
|
|
|
|
/// Use all libadwaita libraries (libadwaita -> adw because cargo)
|
|
|
|
use gtk::*;
|
2024-02-14 16:32:01 +01:00
|
|
|
|
2024-02-19 18:44:10 +01:00
|
|
|
use gettextrs::gettext;
|
2024-02-18 18:28:14 +01:00
|
|
|
|
2024-02-14 16:32:01 +01:00
|
|
|
use std::io::BufRead;
|
|
|
|
use std::io::BufReader;
|
|
|
|
use std::process::Command;
|
|
|
|
use std::process::Stdio;
|
|
|
|
|
2024-02-16 22:21:09 +01:00
|
|
|
pub fn automatic_partitioning(
|
|
|
|
partitioning_stack: >k::Stack,
|
|
|
|
bottom_next_button: >k::Button,
|
|
|
|
) -> (gtk::TextBuffer, gtk::TextBuffer) {
|
2024-02-14 16:32:01 +01:00
|
|
|
let partition_method_automatic_main_box = gtk::Box::builder()
|
|
|
|
.orientation(Orientation::Vertical)
|
|
|
|
.margin_bottom(15)
|
|
|
|
.margin_top(15)
|
|
|
|
.margin_end(15)
|
|
|
|
.margin_start(15)
|
|
|
|
.build();
|
|
|
|
|
|
|
|
let partition_method_automatic_header_box = gtk::Box::builder()
|
|
|
|
.orientation(Orientation::Horizontal)
|
|
|
|
.build();
|
|
|
|
|
|
|
|
// the header text for the partitioning page
|
|
|
|
let partition_method_automatic_header_text = gtk::Label::builder()
|
2024-02-18 22:21:54 +01:00
|
|
|
.label(gettext("auto_part_installer"))
|
2024-02-14 16:32:01 +01:00
|
|
|
.halign(gtk::Align::End)
|
|
|
|
.hexpand(true)
|
|
|
|
.margin_top(15)
|
|
|
|
.margin_bottom(15)
|
|
|
|
.margin_start(15)
|
|
|
|
.margin_end(5)
|
|
|
|
.build();
|
|
|
|
partition_method_automatic_header_text.add_css_class("header_sized_text");
|
|
|
|
|
|
|
|
// the header icon for the partitioning icon
|
|
|
|
let partition_method_automatic_header_icon = gtk::Image::builder()
|
2024-02-18 20:36:24 +01:00
|
|
|
.icon_name("builder")
|
2024-02-14 16:32:01 +01:00
|
|
|
.halign(gtk::Align::Start)
|
|
|
|
.hexpand(true)
|
|
|
|
.pixel_size(78)
|
|
|
|
.margin_top(15)
|
|
|
|
.margin_bottom(15)
|
|
|
|
.margin_start(0)
|
|
|
|
.margin_end(15)
|
|
|
|
.build();
|
|
|
|
|
|
|
|
let partition_method_automatic_selection_box = gtk::Box::builder()
|
|
|
|
.orientation(Orientation::Vertical)
|
|
|
|
.build();
|
|
|
|
|
|
|
|
let partition_method_automatic_selection_text = gtk::Label::builder()
|
2024-02-18 22:21:54 +01:00
|
|
|
.label(gettext("choose_drive_auto"))
|
2024-02-14 16:32:01 +01:00
|
|
|
.justify(Justification::Center)
|
|
|
|
.halign(gtk::Align::Center)
|
|
|
|
.hexpand(true)
|
|
|
|
.margin_top(15)
|
|
|
|
.margin_bottom(15)
|
|
|
|
.margin_start(15)
|
|
|
|
.margin_end(15)
|
|
|
|
.build();
|
|
|
|
partition_method_automatic_selection_text.add_css_class("medium_sized_text");
|
|
|
|
|
|
|
|
let devices_selection_expander_row = adw::ExpanderRow::builder()
|
2024-02-18 22:21:54 +01:00
|
|
|
.title(gettext("no_drive_auto_selected"))
|
2024-02-14 16:32:01 +01:00
|
|
|
.build();
|
|
|
|
|
2024-02-16 22:21:09 +01:00
|
|
|
let null_checkbutton = gtk::CheckButton::builder().build();
|
2024-02-14 16:32:01 +01:00
|
|
|
|
2024-02-16 22:21:09 +01:00
|
|
|
let devices_selection_expander_row_viewport =
|
|
|
|
gtk::ScrolledWindow::builder().height_request(200).build();
|
2024-02-14 16:32:01 +01:00
|
|
|
|
|
|
|
let devices_selection_expander_row_viewport_box = gtk::Box::builder()
|
|
|
|
.orientation(Orientation::Vertical)
|
|
|
|
.build();
|
|
|
|
|
2024-02-16 22:21:09 +01:00
|
|
|
devices_selection_expander_row_viewport
|
|
|
|
.set_child(Some(&devices_selection_expander_row_viewport_box));
|
2024-02-14 16:32:01 +01:00
|
|
|
|
|
|
|
let devices_selection_expander_row_viewport_listbox = gtk::ListBox::builder()
|
|
|
|
.selection_mode(SelectionMode::None)
|
|
|
|
.margin_top(15)
|
|
|
|
.margin_bottom(15)
|
|
|
|
.margin_start(15)
|
|
|
|
.margin_end(15)
|
|
|
|
.build();
|
|
|
|
devices_selection_expander_row_viewport_listbox.add_css_class("boxed-list");
|
|
|
|
devices_selection_expander_row_viewport_listbox.append(&devices_selection_expander_row);
|
|
|
|
|
|
|
|
devices_selection_expander_row.add_row(&devices_selection_expander_row_viewport);
|
|
|
|
|
|
|
|
let partition_method_automatic_get_devices_cli = Command::new("sudo")
|
|
|
|
.arg("/usr/lib/pika/pika-installer-gtk4/scripts/partition-utility.sh")
|
|
|
|
.arg("get_block_devices")
|
|
|
|
.stdin(Stdio::piped())
|
|
|
|
.stdout(Stdio::piped())
|
|
|
|
.spawn()
|
|
|
|
.unwrap_or_else(|e| panic!("failed {}", e));
|
2024-02-16 22:21:09 +01:00
|
|
|
let partition_method_automatic_get_devices_reader = BufReader::new(
|
|
|
|
partition_method_automatic_get_devices_cli
|
|
|
|
.stdout
|
|
|
|
.expect("could not get stdout"),
|
|
|
|
);
|
2024-02-14 16:32:01 +01:00
|
|
|
|
|
|
|
let partition_method_automatic_disk_error_label = gtk::Label::builder()
|
2024-02-18 22:21:54 +01:00
|
|
|
.label(gettext("no_disk_specified"))
|
2024-02-14 16:32:01 +01:00
|
|
|
.halign(Align::Start)
|
|
|
|
.valign(Align::End)
|
|
|
|
.vexpand(true)
|
|
|
|
.build();
|
|
|
|
partition_method_automatic_disk_error_label.add_css_class("small_error_text");
|
|
|
|
|
|
|
|
let partition_method_automatic_luks_error_label = gtk::Label::builder()
|
2024-02-18 22:21:54 +01:00
|
|
|
.label(gettext("luks_yes_but_empty"))
|
2024-02-14 16:32:01 +01:00
|
|
|
.halign(Align::Start)
|
|
|
|
.valign(Align::End)
|
|
|
|
.vexpand(true)
|
|
|
|
.visible(false)
|
|
|
|
.build();
|
|
|
|
partition_method_automatic_luks_error_label.add_css_class("small_error_text");
|
|
|
|
|
2024-02-19 18:44:10 +01:00
|
|
|
let partition_method_automatic_luks_error2_label = gtk::Label::builder()
|
|
|
|
.label(gettext("luks_not_match"))
|
|
|
|
.halign(Align::Start)
|
|
|
|
.valign(Align::End)
|
|
|
|
.vexpand(true)
|
|
|
|
.visible(false)
|
|
|
|
.build();
|
|
|
|
partition_method_automatic_luks_error2_label.add_css_class("small_error_text");
|
|
|
|
|
2024-02-14 16:32:01 +01:00
|
|
|
let partition_method_automatic_luks_box = gtk::Box::builder()
|
|
|
|
.orientation(Orientation::Horizontal)
|
|
|
|
.build();
|
|
|
|
|
|
|
|
let partition_method_automatic_luks_checkbutton = gtk::CheckButton::builder()
|
2024-02-18 22:21:54 +01:00
|
|
|
.label(gettext("enable_luks2_enc"))
|
2024-02-14 16:32:01 +01:00
|
|
|
.margin_top(15)
|
|
|
|
.margin_bottom(15)
|
|
|
|
.margin_start(15)
|
|
|
|
.margin_end(15)
|
|
|
|
.build();
|
|
|
|
|
|
|
|
let partition_method_automatic_luks_listbox = gtk::ListBox::builder()
|
|
|
|
.margin_top(15)
|
|
|
|
.margin_bottom(15)
|
|
|
|
.margin_start(0)
|
|
|
|
.margin_end(15)
|
|
|
|
.build();
|
|
|
|
partition_method_automatic_luks_listbox.add_css_class("boxed-list");
|
|
|
|
|
|
|
|
let partition_method_automatic_luks_password_entry = adw::PasswordEntryRow::builder()
|
2024-02-18 22:21:54 +01:00
|
|
|
.title(gettext("luks2_password"))
|
2024-02-14 16:32:01 +01:00
|
|
|
.hexpand(true)
|
|
|
|
.sensitive(false)
|
|
|
|
.build();
|
|
|
|
|
2024-02-19 18:44:10 +01:00
|
|
|
let partition_method_automatic_luks_password_confirm_entry = adw::PasswordEntryRow::builder()
|
|
|
|
.title(gettext("luks2_password_confirm"))
|
|
|
|
.hexpand(true)
|
|
|
|
.sensitive(true)
|
|
|
|
.visible(false)
|
|
|
|
.build();
|
|
|
|
|
|
|
|
let _partition_method_automatic_luks_password = partition_method_automatic_luks_password_entry
|
|
|
|
.bind_property(
|
|
|
|
"sensitive",
|
|
|
|
&partition_method_automatic_luks_password_confirm_entry,
|
|
|
|
"visible",
|
|
|
|
)
|
|
|
|
.sync_create()
|
|
|
|
.build();
|
2024-02-16 22:21:09 +01:00
|
|
|
let partition_method_automatic_target_buffer = gtk::TextBuffer::builder().build();
|
2024-02-14 16:32:01 +01:00
|
|
|
|
2024-02-16 22:21:09 +01:00
|
|
|
let partition_method_automatic_luks_buffer = gtk::TextBuffer::builder().build();
|
2024-02-14 16:32:01 +01:00
|
|
|
|
|
|
|
for device in partition_method_automatic_get_devices_reader.lines() {
|
|
|
|
let device = device.unwrap();
|
|
|
|
let device_size_cli = Command::new("sudo")
|
|
|
|
.arg("/usr/lib/pika/pika-installer-gtk4/scripts/partition-utility.sh")
|
|
|
|
.arg("get_block_size")
|
|
|
|
.arg(device.clone())
|
|
|
|
.output()
|
|
|
|
.expect("failed to execute process");
|
2024-02-16 22:21:09 +01:00
|
|
|
let device_size = String::from_utf8(device_size_cli.stdout)
|
|
|
|
.expect("Failed to create float")
|
|
|
|
.trim()
|
|
|
|
.parse::<f64>()
|
|
|
|
.unwrap();
|
2024-02-14 16:32:01 +01:00
|
|
|
let device_button = gtk::CheckButton::builder()
|
|
|
|
.valign(Align::Center)
|
|
|
|
.can_focus(false)
|
|
|
|
.build();
|
|
|
|
device_button.set_group(Some(&null_checkbutton));
|
|
|
|
let device_row = adw::ActionRow::builder()
|
|
|
|
.activatable_widget(&device_button)
|
|
|
|
.title(device.clone())
|
|
|
|
.subtitle(pretty_bytes::converter::convert(device_size))
|
|
|
|
.build();
|
|
|
|
device_row.add_prefix(&device_button);
|
|
|
|
devices_selection_expander_row_viewport_box.append(&device_row);
|
|
|
|
device_button.connect_toggled(clone!(@weak device_button,@weak partition_method_automatic_luks_password_entry, @weak devices_selection_expander_row, @weak bottom_next_button, @weak partition_method_automatic_disk_error_label, @weak partition_method_automatic_luks_error_label, @weak partition_method_automatic_luks_checkbutton, @weak partition_method_automatic_target_buffer, @weak partition_method_automatic_luks_buffer => move |_| {
|
|
|
|
if device_button.is_active() == true {
|
|
|
|
devices_selection_expander_row.set_title(&device);
|
|
|
|
if device_size > 39000000000.0 {
|
|
|
|
partition_method_automatic_disk_error_label.set_visible(false);
|
|
|
|
if partition_method_automatic_luks_checkbutton.is_active() == true {
|
|
|
|
if partition_method_automatic_luks_error_label.get_visible() {
|
|
|
|
//
|
|
|
|
} else {
|
|
|
|
bottom_next_button.set_sensitive(true);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
partition_method_automatic_target_buffer.set_text(&device);
|
|
|
|
partition_method_automatic_luks_buffer.set_text(&partition_method_automatic_luks_password_entry.text().to_string());
|
|
|
|
bottom_next_button.set_sensitive(true);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
partition_method_automatic_disk_error_label.set_visible(true);
|
2024-02-18 22:21:54 +01:00
|
|
|
partition_method_automatic_disk_error_label.set_label(&gettext("disk_auto_target_small"));
|
2024-02-14 16:32:01 +01:00
|
|
|
bottom_next_button.set_sensitive(false);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}));
|
|
|
|
}
|
|
|
|
|
2024-02-19 18:44:10 +01:00
|
|
|
partition_method_automatic_luks_checkbutton.connect_toggled(clone!(@weak partition_method_automatic_luks_error2_label,@weak partition_method_automatic_luks_checkbutton, @weak partition_method_automatic_luks_password_confirm_entry, @weak partition_method_automatic_luks_password_entry, @weak partition_method_automatic_disk_error_label, @weak partition_method_automatic_luks_error_label, @weak bottom_next_button, @weak partition_method_automatic_target_buffer, @weak partition_method_automatic_luks_buffer => move |_| {
|
2024-02-14 16:32:01 +01:00
|
|
|
if partition_method_automatic_luks_checkbutton.is_active() == true {
|
|
|
|
partition_method_automatic_luks_password_entry.set_sensitive(true);
|
2024-02-19 18:44:10 +01:00
|
|
|
if partition_method_automatic_luks_password_entry.text() != partition_method_automatic_luks_password_confirm_entry.text() {
|
|
|
|
partition_method_automatic_luks_error2_label.set_visible(true)
|
|
|
|
} else {
|
|
|
|
partition_method_automatic_luks_error2_label.set_visible(false)
|
|
|
|
}
|
2024-02-14 16:32:01 +01:00
|
|
|
if partition_method_automatic_luks_password_entry.text().to_string().is_empty() {
|
|
|
|
partition_method_automatic_luks_error_label.set_visible(true);
|
|
|
|
bottom_next_button.set_sensitive(false);
|
|
|
|
} else {
|
|
|
|
partition_method_automatic_luks_error_label.set_visible(false);
|
2024-02-19 18:44:10 +01:00
|
|
|
if !partition_method_automatic_disk_error_label.get_visible() && !partition_method_automatic_luks_error_label.get_visible() && !partition_method_automatic_luks_error2_label.get_visible() {
|
|
|
|
bottom_next_button.set_sensitive(true);
|
|
|
|
} else {
|
|
|
|
bottom_next_button.set_sensitive(false);
|
|
|
|
}
|
2024-02-14 16:32:01 +01:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
partition_method_automatic_luks_password_entry.set_sensitive(false);
|
|
|
|
partition_method_automatic_luks_error_label.set_visible(false);
|
2024-02-19 18:44:10 +01:00
|
|
|
partition_method_automatic_luks_error2_label.set_visible(false);
|
|
|
|
if !partition_method_automatic_disk_error_label.get_visible() && !partition_method_automatic_luks_error_label.get_visible() && !partition_method_automatic_luks_error2_label.get_visible() {
|
2024-02-14 16:32:01 +01:00
|
|
|
bottom_next_button.set_sensitive(true);
|
2024-02-19 18:44:10 +01:00
|
|
|
} else {
|
|
|
|
bottom_next_button.set_sensitive(false);
|
2024-02-14 16:32:01 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}));
|
|
|
|
|
2024-02-19 18:44:10 +01:00
|
|
|
partition_method_automatic_luks_password_entry.connect_changed(clone!(@weak partition_method_automatic_luks_error2_label,@weak partition_method_automatic_luks_checkbutton, @weak partition_method_automatic_luks_password_confirm_entry, @weak partition_method_automatic_luks_password_entry, @weak partition_method_automatic_disk_error_label, @weak partition_method_automatic_luks_error_label, @weak bottom_next_button, @weak partition_method_automatic_target_buffer, @weak partition_method_automatic_luks_buffer => move |_| {
|
|
|
|
if partition_method_automatic_luks_checkbutton.is_active() == true {
|
|
|
|
partition_method_automatic_luks_password_entry.set_sensitive(true);
|
|
|
|
if partition_method_automatic_luks_password_entry.text() != partition_method_automatic_luks_password_confirm_entry.text() {
|
|
|
|
partition_method_automatic_luks_error2_label.set_visible(true)
|
|
|
|
} else {
|
|
|
|
partition_method_automatic_luks_error2_label.set_visible(false)
|
|
|
|
}
|
|
|
|
if partition_method_automatic_luks_password_entry.text().to_string().is_empty() {
|
|
|
|
partition_method_automatic_luks_error_label.set_visible(true);
|
|
|
|
bottom_next_button.set_sensitive(false);
|
|
|
|
} else {
|
|
|
|
partition_method_automatic_luks_error_label.set_visible(false);
|
|
|
|
if !partition_method_automatic_disk_error_label.get_visible() && !partition_method_automatic_luks_error_label.get_visible() && !partition_method_automatic_luks_error2_label.get_visible() {
|
|
|
|
bottom_next_button.set_sensitive(true);
|
|
|
|
} else {
|
|
|
|
bottom_next_button.set_sensitive(false);
|
|
|
|
}
|
|
|
|
}
|
2024-02-14 16:32:01 +01:00
|
|
|
} else {
|
2024-02-19 18:44:10 +01:00
|
|
|
partition_method_automatic_luks_password_entry.set_sensitive(false);
|
2024-02-14 16:32:01 +01:00
|
|
|
partition_method_automatic_luks_error_label.set_visible(false);
|
2024-02-19 18:44:10 +01:00
|
|
|
partition_method_automatic_luks_error2_label.set_visible(false);
|
|
|
|
if !partition_method_automatic_disk_error_label.get_visible() && !partition_method_automatic_luks_error_label.get_visible() && !partition_method_automatic_luks_error2_label.get_visible() {
|
2024-02-14 16:32:01 +01:00
|
|
|
bottom_next_button.set_sensitive(true);
|
2024-02-19 18:44:10 +01:00
|
|
|
} else {
|
|
|
|
bottom_next_button.set_sensitive(false);
|
2024-02-14 16:32:01 +01:00
|
|
|
}
|
|
|
|
}
|
2024-02-19 18:44:10 +01:00
|
|
|
}));
|
|
|
|
|
|
|
|
partition_method_automatic_luks_password_confirm_entry.connect_changed(clone!(@weak partition_method_automatic_luks_error2_label,@weak partition_method_automatic_luks_checkbutton, @weak partition_method_automatic_luks_password_confirm_entry, @weak partition_method_automatic_luks_password_entry, @weak partition_method_automatic_disk_error_label, @weak partition_method_automatic_luks_error_label, @weak bottom_next_button, @weak partition_method_automatic_target_buffer, @weak partition_method_automatic_luks_buffer => move |_| {
|
|
|
|
if partition_method_automatic_luks_checkbutton.is_active() == true {
|
|
|
|
partition_method_automatic_luks_password_entry.set_sensitive(true);
|
|
|
|
if partition_method_automatic_luks_password_entry.text() != partition_method_automatic_luks_password_confirm_entry.text() {
|
|
|
|
partition_method_automatic_luks_error2_label.set_visible(true)
|
|
|
|
} else {
|
|
|
|
partition_method_automatic_luks_error2_label.set_visible(false)
|
|
|
|
}
|
|
|
|
if partition_method_automatic_luks_password_entry.text().to_string().is_empty() {
|
|
|
|
partition_method_automatic_luks_error_label.set_visible(true);
|
|
|
|
bottom_next_button.set_sensitive(false);
|
|
|
|
} else {
|
|
|
|
partition_method_automatic_luks_error_label.set_visible(false);
|
|
|
|
if !partition_method_automatic_disk_error_label.get_visible() && !partition_method_automatic_luks_error_label.get_visible() && !partition_method_automatic_luks_error2_label.get_visible() {
|
|
|
|
bottom_next_button.set_sensitive(true);
|
|
|
|
} else {
|
|
|
|
bottom_next_button.set_sensitive(false);
|
|
|
|
}
|
|
|
|
}
|
2024-02-14 16:32:01 +01:00
|
|
|
} else {
|
2024-02-19 18:44:10 +01:00
|
|
|
partition_method_automatic_luks_password_entry.set_sensitive(false);
|
|
|
|
partition_method_automatic_luks_error_label.set_visible(false);
|
|
|
|
partition_method_automatic_luks_error2_label.set_visible(false);
|
|
|
|
if !partition_method_automatic_disk_error_label.get_visible() && !partition_method_automatic_luks_error_label.get_visible() && !partition_method_automatic_luks_error2_label.get_visible() {
|
|
|
|
bottom_next_button.set_sensitive(true);
|
|
|
|
} else {
|
|
|
|
bottom_next_button.set_sensitive(false);
|
|
|
|
}
|
2024-02-14 16:32:01 +01:00
|
|
|
}
|
2024-02-19 18:44:10 +01:00
|
|
|
}));
|
2024-02-14 16:32:01 +01:00
|
|
|
|
|
|
|
partition_method_automatic_luks_listbox.append(&partition_method_automatic_luks_password_entry);
|
2024-02-19 18:44:10 +01:00
|
|
|
partition_method_automatic_luks_listbox
|
|
|
|
.append(&partition_method_automatic_luks_password_confirm_entry);
|
2024-02-14 16:32:01 +01:00
|
|
|
partition_method_automatic_luks_box.append(&partition_method_automatic_luks_checkbutton);
|
|
|
|
partition_method_automatic_luks_box.append(&partition_method_automatic_luks_listbox);
|
|
|
|
partition_method_automatic_header_box.append(&partition_method_automatic_header_text);
|
|
|
|
partition_method_automatic_header_box.append(&partition_method_automatic_header_icon);
|
|
|
|
partition_method_automatic_selection_box.append(&partition_method_automatic_selection_text);
|
|
|
|
partition_method_automatic_main_box.append(&partition_method_automatic_header_box);
|
|
|
|
partition_method_automatic_main_box.append(&partition_method_automatic_selection_box);
|
|
|
|
partition_method_automatic_main_box.append(&devices_selection_expander_row_viewport_listbox);
|
|
|
|
partition_method_automatic_main_box.append(&partition_method_automatic_luks_box);
|
|
|
|
partition_method_automatic_main_box.append(&partition_method_automatic_luks_error_label);
|
2024-02-19 18:44:10 +01:00
|
|
|
partition_method_automatic_main_box.append(&partition_method_automatic_luks_error2_label);
|
2024-02-14 16:32:01 +01:00
|
|
|
partition_method_automatic_main_box.append(&partition_method_automatic_disk_error_label);
|
|
|
|
|
2024-02-16 22:21:09 +01:00
|
|
|
partitioning_stack.add_titled(
|
|
|
|
&partition_method_automatic_main_box,
|
|
|
|
Some("partition_method_automatic_page"),
|
|
|
|
"partition_method_automatic_page",
|
|
|
|
);
|
2024-02-14 16:32:01 +01:00
|
|
|
|
2024-02-16 22:21:09 +01:00
|
|
|
return (
|
|
|
|
partition_method_automatic_target_buffer,
|
|
|
|
partition_method_automatic_luks_buffer,
|
|
|
|
);
|
|
|
|
}
|