|
|
|
|
@ -18,54 +18,114 @@ fn main() {
|
|
|
|
|
}),
|
|
|
|
|
GameUiPlugin,
|
|
|
|
|
))
|
|
|
|
|
.init_resource::<Icon>()
|
|
|
|
|
.add_systems(Startup, init_ui)
|
|
|
|
|
.add_systems(Update, (cursors, container))
|
|
|
|
|
// .init_resource::<Icon>()
|
|
|
|
|
.add_systems(Startup, init_ui2)
|
|
|
|
|
.add_systems(Update, toggle)
|
|
|
|
|
// .add_systems(Startup, init_ui)
|
|
|
|
|
// .add_systems(Update, (cursors, container()))
|
|
|
|
|
.run();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const CURSORS: [CursorIcon; 35] = [
|
|
|
|
|
CursorIcon::Default,
|
|
|
|
|
CursorIcon::Crosshair,
|
|
|
|
|
CursorIcon::Hand,
|
|
|
|
|
CursorIcon::Arrow,
|
|
|
|
|
CursorIcon::Move,
|
|
|
|
|
CursorIcon::Text,
|
|
|
|
|
CursorIcon::Wait,
|
|
|
|
|
CursorIcon::Help,
|
|
|
|
|
CursorIcon::Progress,
|
|
|
|
|
CursorIcon::NotAllowed,
|
|
|
|
|
CursorIcon::ContextMenu,
|
|
|
|
|
CursorIcon::Cell,
|
|
|
|
|
CursorIcon::VerticalText,
|
|
|
|
|
CursorIcon::Alias,
|
|
|
|
|
CursorIcon::Copy,
|
|
|
|
|
CursorIcon::NoDrop,
|
|
|
|
|
CursorIcon::Grab,
|
|
|
|
|
CursorIcon::Grabbing,
|
|
|
|
|
CursorIcon::AllScroll,
|
|
|
|
|
CursorIcon::ZoomIn,
|
|
|
|
|
CursorIcon::ZoomOut,
|
|
|
|
|
CursorIcon::EResize,
|
|
|
|
|
CursorIcon::NResize,
|
|
|
|
|
CursorIcon::NeResize,
|
|
|
|
|
CursorIcon::NwResize,
|
|
|
|
|
CursorIcon::SResize,
|
|
|
|
|
CursorIcon::SeResize,
|
|
|
|
|
CursorIcon::SwResize,
|
|
|
|
|
CursorIcon::WResize,
|
|
|
|
|
CursorIcon::EwResize,
|
|
|
|
|
CursorIcon::NsResize,
|
|
|
|
|
CursorIcon::NeswResize,
|
|
|
|
|
CursorIcon::NwseResize,
|
|
|
|
|
CursorIcon::ColResize,
|
|
|
|
|
CursorIcon::RowResize,
|
|
|
|
|
];
|
|
|
|
|
fn container() -> NodeBundle {
|
|
|
|
|
NodeBundle {
|
|
|
|
|
style: Style {
|
|
|
|
|
border: UiRect::all(Val::Px(2.0)),
|
|
|
|
|
right: Val::Percent(-100.0),
|
|
|
|
|
top: Val::Px(-4.0),
|
|
|
|
|
flex_direction: FlexDirection::Column,
|
|
|
|
|
display: Display::None,
|
|
|
|
|
..default()
|
|
|
|
|
},
|
|
|
|
|
background_color: BackgroundColor(Color::PURPLE),
|
|
|
|
|
border_color: BorderColor(Color::BLACK),
|
|
|
|
|
..default()
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[derive(Debug, Component, Resource, Default)]
|
|
|
|
|
struct Icon(CursorIcon);
|
|
|
|
|
fn spec(color: Color) -> ButtonBundle {
|
|
|
|
|
ButtonBundle {
|
|
|
|
|
style: Style {
|
|
|
|
|
border: UiRect::all(Val::Px(2.0)),
|
|
|
|
|
width: Val::Px(100.0),
|
|
|
|
|
height: Val::Px(50.0),
|
|
|
|
|
flex_direction: FlexDirection::Column,
|
|
|
|
|
..default()
|
|
|
|
|
},
|
|
|
|
|
background_color: BackgroundColor(color),
|
|
|
|
|
border_color: BorderColor(Color::BLACK),
|
|
|
|
|
..default()
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn init_ui(mut commands: Commands) {
|
|
|
|
|
fn toggle(
|
|
|
|
|
mut events: Query<
|
|
|
|
|
(&mut BackgroundColor, &Interaction, &Children),
|
|
|
|
|
(Changed<Interaction>, With<Button>),
|
|
|
|
|
>,
|
|
|
|
|
mut styles: Query<&mut Style>,
|
|
|
|
|
) {
|
|
|
|
|
events
|
|
|
|
|
.iter_mut()
|
|
|
|
|
.for_each(|(mut bg_color, interaction, children)| match interaction {
|
|
|
|
|
Interaction::Pressed => {
|
|
|
|
|
bg_color.0 = Color::RED;
|
|
|
|
|
children.iter().for_each(|&child| {
|
|
|
|
|
if let Ok(mut style) = styles.get_mut(child) {
|
|
|
|
|
style.display = match style.display {
|
|
|
|
|
Display::Flex => Display::None,
|
|
|
|
|
Display::None | _ => Display::Flex,
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
Interaction::Hovered => {
|
|
|
|
|
bg_color.0 = Color::RED;
|
|
|
|
|
}
|
|
|
|
|
Interaction::None => {
|
|
|
|
|
bg_color.0 = Color::PINK;
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// const CURSORS: [CursorIcon; 35] = [
|
|
|
|
|
// CursorIcon::Default,
|
|
|
|
|
// CursorIcon::Crosshair,
|
|
|
|
|
// CursorIcon::Hand,
|
|
|
|
|
// CursorIcon::Arrow,
|
|
|
|
|
// CursorIcon::Move,
|
|
|
|
|
// CursorIcon::Text,
|
|
|
|
|
// CursorIcon::Wait,
|
|
|
|
|
// CursorIcon::Help,
|
|
|
|
|
// CursorIcon::Progress,
|
|
|
|
|
// CursorIcon::NotAllowed,
|
|
|
|
|
// CursorIcon::ContextMenu,
|
|
|
|
|
// CursorIcon::Cell,
|
|
|
|
|
// CursorIcon::VerticalText,
|
|
|
|
|
// CursorIcon::Alias,
|
|
|
|
|
// CursorIcon::Copy,
|
|
|
|
|
// CursorIcon::NoDrop,
|
|
|
|
|
// CursorIcon::Grab,
|
|
|
|
|
// CursorIcon::Grabbing,
|
|
|
|
|
// CursorIcon::AllScroll,
|
|
|
|
|
// CursorIcon::ZoomIn,
|
|
|
|
|
// CursorIcon::ZoomOut,
|
|
|
|
|
// CursorIcon::EResize,
|
|
|
|
|
// CursorIcon::NResize,
|
|
|
|
|
// CursorIcon::NeResize,
|
|
|
|
|
// CursorIcon::NwResize,
|
|
|
|
|
// CursorIcon::SResize,
|
|
|
|
|
// CursorIcon::SeResize,
|
|
|
|
|
// CursorIcon::SwResize,
|
|
|
|
|
// CursorIcon::WResize,
|
|
|
|
|
// CursorIcon::EwResize,
|
|
|
|
|
// CursorIcon::NsResize,
|
|
|
|
|
// CursorIcon::NeswResize,
|
|
|
|
|
// CursorIcon::NwseResize,
|
|
|
|
|
// CursorIcon::ColResize,
|
|
|
|
|
// CursorIcon::RowResize,
|
|
|
|
|
// ];
|
|
|
|
|
|
|
|
|
|
fn init_ui2(mut commands: Commands) {
|
|
|
|
|
commands.spawn((
|
|
|
|
|
Camera2dBundle { ..default() },
|
|
|
|
|
UiCameraConfig { show_ui: true },
|
|
|
|
|
@ -74,118 +134,217 @@ fn init_ui(mut commands: Commands) {
|
|
|
|
|
commands
|
|
|
|
|
.spawn(NodeBundle {
|
|
|
|
|
style: Style {
|
|
|
|
|
height: Val::Percent(100.0),
|
|
|
|
|
width: Val::Percent(100.0),
|
|
|
|
|
justify_content: JustifyContent::Start,
|
|
|
|
|
align_items: AlignItems::Start,
|
|
|
|
|
border: UiRect::all(Val::Px(2.0)),
|
|
|
|
|
flex_direction: FlexDirection::Column,
|
|
|
|
|
..default()
|
|
|
|
|
},
|
|
|
|
|
background_color: BackgroundColor(Color::GRAY),
|
|
|
|
|
background_color: BackgroundColor(Color::PURPLE),
|
|
|
|
|
border_color: BorderColor(Color::BLACK),
|
|
|
|
|
..default()
|
|
|
|
|
})
|
|
|
|
|
.with_children(|parent| {
|
|
|
|
|
parent
|
|
|
|
|
.spawn((
|
|
|
|
|
GameUi::Nav,
|
|
|
|
|
// Name::new("Game Nav"),
|
|
|
|
|
NodeBundle { ..default() },
|
|
|
|
|
))
|
|
|
|
|
.with_children(|parent| {
|
|
|
|
|
parent
|
|
|
|
|
.spawn((
|
|
|
|
|
GameUi::Tab,
|
|
|
|
|
Name::new("Grow/Shrink Tab"),
|
|
|
|
|
NodeBundle { ..default() },
|
|
|
|
|
))
|
|
|
|
|
.with_children(|parent| {
|
|
|
|
|
parent.spawn((
|
|
|
|
|
Container,
|
|
|
|
|
GameUi::Set,
|
|
|
|
|
// Name::new("Grow/Shrink Set"),
|
|
|
|
|
NodeBundle { ..default() },
|
|
|
|
|
));
|
|
|
|
|
parent.spawn(spec(Color::PINK)).with_children(|parent| {
|
|
|
|
|
parent.spawn(container()).with_children(|parent| {
|
|
|
|
|
parent.spawn(spec(Color::PINK)).with_children(|parent| {
|
|
|
|
|
parent.spawn(container()).with_children(|parent| {
|
|
|
|
|
parent.spawn(spec(Color::PINK));
|
|
|
|
|
parent.spawn(spec(Color::PINK));
|
|
|
|
|
parent.spawn(spec(Color::PINK));
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
parent
|
|
|
|
|
.spawn((
|
|
|
|
|
GameUi::Tab,
|
|
|
|
|
Name::new("Cursor Icons Tab"),
|
|
|
|
|
NodeBundle { ..default() },
|
|
|
|
|
))
|
|
|
|
|
.with_children(|parent| {
|
|
|
|
|
parent
|
|
|
|
|
.spawn((
|
|
|
|
|
GameUi::Set,
|
|
|
|
|
// Name::new("Cursor Icons Set"),
|
|
|
|
|
NodeBundle { ..default() },
|
|
|
|
|
))
|
|
|
|
|
.with_children(|parent| {
|
|
|
|
|
CURSORS.iter().for_each(|&icon| {
|
|
|
|
|
parent.spawn((
|
|
|
|
|
GameUi::Button,
|
|
|
|
|
Name::new(format!("{:?}", icon)),
|
|
|
|
|
NodeBundle { ..default() },
|
|
|
|
|
Icon(icon),
|
|
|
|
|
));
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
parent.spawn(spec(Color::PINK)).with_children(|parent| {
|
|
|
|
|
parent.spawn(container()).with_children(|parent| {
|
|
|
|
|
parent.spawn(spec(Color::PINK));
|
|
|
|
|
parent.spawn(spec(Color::PINK));
|
|
|
|
|
parent.spawn(spec(Color::PINK));
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
parent.spawn(spec(Color::PINK)).with_children(|parent| {
|
|
|
|
|
parent.spawn(container()).with_children(|parent| {
|
|
|
|
|
parent.spawn(spec(Color::PINK));
|
|
|
|
|
parent.spawn(spec(Color::PINK));
|
|
|
|
|
parent.spawn(spec(Color::PINK));
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn cursors(
|
|
|
|
|
events: Query<(&Interaction, &Icon), (Changed<Interaction>, With<Button>)>,
|
|
|
|
|
mut primary_window: Query<&mut Window, With<PrimaryWindow>>,
|
|
|
|
|
mut curr: ResMut<Icon>,
|
|
|
|
|
) {
|
|
|
|
|
events.iter().for_each(|(&interaction, &ref icon)| {
|
|
|
|
|
let mut window = primary_window.single_mut();
|
|
|
|
|
|
|
|
|
|
match interaction {
|
|
|
|
|
Interaction::Hovered => {
|
|
|
|
|
(*window).cursor.icon = icon.0.clone();
|
|
|
|
|
}
|
|
|
|
|
Interaction::Pressed => {
|
|
|
|
|
curr.0 = icon.0.clone();
|
|
|
|
|
}
|
|
|
|
|
Interaction::None => {
|
|
|
|
|
(*window).cursor.icon = curr.0.clone();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[derive(Debug, Component)]
|
|
|
|
|
struct Container;
|
|
|
|
|
|
|
|
|
|
fn container(
|
|
|
|
|
mut events: EventReader<KeyboardInput>,
|
|
|
|
|
mut commands: Commands,
|
|
|
|
|
root: Query<Entity, With<Container>>,
|
|
|
|
|
children: Query<&Children, With<Container>>,
|
|
|
|
|
) {
|
|
|
|
|
events.iter().for_each(
|
|
|
|
|
|KeyboardInput {
|
|
|
|
|
key_code, state, ..
|
|
|
|
|
}| {
|
|
|
|
|
match (key_code, state) {
|
|
|
|
|
(Some(KeyCode::Up), ButtonState::Pressed) => {
|
|
|
|
|
commands.entity(root.single()).with_children(|parent| {
|
|
|
|
|
parent.spawn((
|
|
|
|
|
GameUi::Button,
|
|
|
|
|
Name::new("asdfwtf"),
|
|
|
|
|
NodeBundle { ..default() },
|
|
|
|
|
));
|
|
|
|
|
});
|
|
|
|
|
parent.spawn(spec(Color::PINK)).with_children(|parent| {
|
|
|
|
|
parent.spawn(container()).with_children(|parent| {
|
|
|
|
|
parent.spawn(spec(Color::PINK)).with_children(|parent| {
|
|
|
|
|
parent.spawn(container()).with_children(|parent| {
|
|
|
|
|
parent.spawn(spec(Color::PINK));
|
|
|
|
|
parent.spawn(spec(Color::PINK));
|
|
|
|
|
parent.spawn(spec(Color::PINK));
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
(Some(KeyCode::Down), ButtonState::Pressed) => {
|
|
|
|
|
children.single().iter().last().iter().for_each(|&&child| {
|
|
|
|
|
commands.entity(child).despawn_recursive();
|
|
|
|
|
parent.spawn(spec(Color::PINK)).with_children(|parent| {
|
|
|
|
|
parent.spawn(container()).with_children(|parent| {
|
|
|
|
|
parent.spawn(spec(Color::PINK));
|
|
|
|
|
parent.spawn(spec(Color::PINK));
|
|
|
|
|
parent.spawn(spec(Color::PINK));
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
_ => (),
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
)
|
|
|
|
|
parent.spawn(spec(Color::PINK)).with_children(|parent| {
|
|
|
|
|
parent.spawn(container()).with_children(|parent| {
|
|
|
|
|
parent.spawn(spec(Color::PINK));
|
|
|
|
|
parent.spawn(spec(Color::PINK));
|
|
|
|
|
parent.spawn(spec(Color::PINK));
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
parent.spawn(spec(Color::PINK)).with_children(|parent| {
|
|
|
|
|
parent.spawn(container()).with_children(|parent| {
|
|
|
|
|
parent.spawn(spec(Color::PINK)).with_children(|parent| {
|
|
|
|
|
parent.spawn(container()).with_children(|parent| {
|
|
|
|
|
parent.spawn(spec(Color::PINK));
|
|
|
|
|
parent.spawn(spec(Color::PINK));
|
|
|
|
|
parent.spawn(spec(Color::PINK));
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
parent.spawn(spec(Color::PINK)).with_children(|parent| {
|
|
|
|
|
parent.spawn(container()).with_children(|parent| {
|
|
|
|
|
parent.spawn(spec(Color::PINK));
|
|
|
|
|
parent.spawn(spec(Color::PINK));
|
|
|
|
|
parent.spawn(spec(Color::PINK));
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
parent.spawn(spec(Color::PINK)).with_children(|parent| {
|
|
|
|
|
parent.spawn(container()).with_children(|parent| {
|
|
|
|
|
parent.spawn(spec(Color::PINK));
|
|
|
|
|
parent.spawn(spec(Color::PINK));
|
|
|
|
|
parent.spawn(spec(Color::PINK));
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// #[derive(Debug, Component, Resource, Default)]
|
|
|
|
|
// struct Icon(CursorIcon);
|
|
|
|
|
//
|
|
|
|
|
// fn init_ui(mut commands: Commands) {
|
|
|
|
|
// commands.spawn((
|
|
|
|
|
// Camera2dBundle { ..default() },
|
|
|
|
|
// UiCameraConfig { show_ui: true },
|
|
|
|
|
// ));
|
|
|
|
|
//
|
|
|
|
|
// commands
|
|
|
|
|
// .spawn(NodeBundle {
|
|
|
|
|
// style: Style {
|
|
|
|
|
// height: Val::Percent(100.0),
|
|
|
|
|
// width: Val::Percent(100.0),
|
|
|
|
|
// justify_content: JustifyContent::Start,
|
|
|
|
|
// align_items: AlignItems::Start,
|
|
|
|
|
// ..default()
|
|
|
|
|
// },
|
|
|
|
|
// background_color: BackgroundColor(Color::GRAY),
|
|
|
|
|
// ..default()
|
|
|
|
|
// })
|
|
|
|
|
// .with_children(|parent| {
|
|
|
|
|
// parent
|
|
|
|
|
// .spawn((
|
|
|
|
|
// GameUiNav,
|
|
|
|
|
// // Name::new("Game Nav"),
|
|
|
|
|
// NodeBundle { ..default() },
|
|
|
|
|
// ))
|
|
|
|
|
// .with_children(|parent| {
|
|
|
|
|
// parent
|
|
|
|
|
// .spawn((
|
|
|
|
|
// GameUiTab,
|
|
|
|
|
// Name::new("Grow/Shrink Tab"),
|
|
|
|
|
// NodeBundle { ..default() },
|
|
|
|
|
// ))
|
|
|
|
|
// .with_children(|parent| {
|
|
|
|
|
// parent.spawn((
|
|
|
|
|
// container,
|
|
|
|
|
// GameUiSet,
|
|
|
|
|
// // Name::new("Grow/Shrink Set"),
|
|
|
|
|
// NodeBundle { ..default() },
|
|
|
|
|
// ));
|
|
|
|
|
// });
|
|
|
|
|
//
|
|
|
|
|
// parent
|
|
|
|
|
// .spawn((
|
|
|
|
|
// GameUiTab,
|
|
|
|
|
// Name::new("Cursor Icons Tab"),
|
|
|
|
|
// NodeBundle { ..default() },
|
|
|
|
|
// ))
|
|
|
|
|
// .with_children(|parent| {
|
|
|
|
|
// parent
|
|
|
|
|
// .spawn((
|
|
|
|
|
// GameUiSet,
|
|
|
|
|
// // Name::new("Cursor Icons Set"),
|
|
|
|
|
// NodeBundle { ..default() },
|
|
|
|
|
// ))
|
|
|
|
|
// .with_children(|parent| {
|
|
|
|
|
// CURSORS.iter().for_each(|&icon| {
|
|
|
|
|
// parent.spawn((
|
|
|
|
|
// GameUiButton,
|
|
|
|
|
// Name::new(format!("{:?}", icon)),
|
|
|
|
|
// NodeBundle { ..default() },
|
|
|
|
|
// Icon(icon),
|
|
|
|
|
// ));
|
|
|
|
|
// });
|
|
|
|
|
// });
|
|
|
|
|
// });
|
|
|
|
|
// });
|
|
|
|
|
// });
|
|
|
|
|
// }
|
|
|
|
|
//
|
|
|
|
|
// fn cursors(
|
|
|
|
|
// events: Query<(&Interaction, &Icon), (Changed<Interaction>, With<Button>)>,
|
|
|
|
|
// mut primary_window: Query<&mut Window, With<PrimaryWindow>>,
|
|
|
|
|
// mut curr: ResMut<Icon>,
|
|
|
|
|
// ) {
|
|
|
|
|
// events.iter().for_each(|(&interaction, &ref icon)| {
|
|
|
|
|
// let mut window = primary_window.single_mut();
|
|
|
|
|
//
|
|
|
|
|
// match interaction {
|
|
|
|
|
// Interaction::Hovered => {
|
|
|
|
|
// (*window).cursor.icon = icon.0.clone();
|
|
|
|
|
// }
|
|
|
|
|
// Interaction::Pressed => {
|
|
|
|
|
// curr.0 = icon.0.clone();
|
|
|
|
|
// }
|
|
|
|
|
// Interaction::None => {
|
|
|
|
|
// (*window).cursor.icon = curr.0.clone();
|
|
|
|
|
// }
|
|
|
|
|
// }
|
|
|
|
|
// })
|
|
|
|
|
// }
|
|
|
|
|
//
|
|
|
|
|
// #[derive(Debug, Component)]
|
|
|
|
|
// struct container;
|
|
|
|
|
//
|
|
|
|
|
// fn container(
|
|
|
|
|
// mut events: EventReader<KeyboardInput>,
|
|
|
|
|
// mut commands: Commands,
|
|
|
|
|
// root: Query<Entity, With<container>>,
|
|
|
|
|
// children: Query<&Children, With<container>>,
|
|
|
|
|
// ) {
|
|
|
|
|
// events.iter().for_each(
|
|
|
|
|
// |KeyboardInput {
|
|
|
|
|
// key_code, state, ..
|
|
|
|
|
// }| {
|
|
|
|
|
// match (key_code, state) {
|
|
|
|
|
// (Some(KeyCode::Up), ButtonState::Pressed) => {
|
|
|
|
|
// commands.entity(root.single()).with_children(|parent| {
|
|
|
|
|
// parent.spawn((
|
|
|
|
|
// GameUiButton,
|
|
|
|
|
// Name::new("asdfwtf"),
|
|
|
|
|
// NodeBundle { ..default() },
|
|
|
|
|
// ));
|
|
|
|
|
// });
|
|
|
|
|
// }
|
|
|
|
|
// (Some(KeyCode::Down), ButtonState::Pressed) => {
|
|
|
|
|
// children.single().iter().last().iter().for_each(|&&child| {
|
|
|
|
|
// commands.entity(child).despawn_recursive();
|
|
|
|
|
// });
|
|
|
|
|
// }
|
|
|
|
|
// _ => (),
|
|
|
|
|
// }
|
|
|
|
|
// },
|
|
|
|
|
// )
|
|
|
|
|
// }
|
|
|
|
|
|