feat: add initial projects
Signed-off-by: kjuulh <contact@kjuulh.io>
This commit is contained in:
commit
be4d755d51
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
||||
target/
|
9
alloy/.rust-toolchain.toml
Normal file
9
alloy/.rust-toolchain.toml
Normal file
@ -0,0 +1,9 @@
|
||||
[toolchain]
|
||||
# Specify the Rust version to ensure consistency across environments
|
||||
channel = "stable" # You can use "nightly" if your project requires nightly features
|
||||
|
||||
# Add required components
|
||||
components = ["rust-src", "rust-std", "wasm32-wasi"]
|
||||
|
||||
# Specify the target
|
||||
targets = ["wasm32-wasip1"]
|
10
alloy/.vscode/settings.json
vendored
Normal file
10
alloy/.vscode/settings.json
vendored
Normal file
@ -0,0 +1,10 @@
|
||||
{
|
||||
"rust-analyzer.check.overrideCommand": [
|
||||
"cargo",
|
||||
"component",
|
||||
"check",
|
||||
"--workspace",
|
||||
"--all-targets",
|
||||
"--message-format=json"
|
||||
],
|
||||
}
|
25
alloy/Cargo.lock
generated
Normal file
25
alloy/Cargo.lock
generated
Normal file
@ -0,0 +1,25 @@
|
||||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
version = 4
|
||||
|
||||
[[package]]
|
||||
name = "alloy"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"wit-bindgen-rt",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "2.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de"
|
||||
|
||||
[[package]]
|
||||
name = "wit-bindgen-rt"
|
||||
version = "0.36.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7947d0131c7c9da3f01dfde0ab8bd4c4cf3c5bd49b6dba0ae640f1fa752572ea"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
]
|
25
alloy/Cargo.toml
Normal file
25
alloy/Cargo.toml
Normal file
@ -0,0 +1,25 @@
|
||||
[package]
|
||||
name = "alloy"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
wit-bindgen-rt = { version = "0.36.0", features = ["bitflags"] }
|
||||
|
||||
[lib]
|
||||
crate-type = ["cdylib"]
|
||||
|
||||
[profile.release]
|
||||
codegen-units = 1
|
||||
opt-level = "s"
|
||||
debug = false
|
||||
strip = true
|
||||
lto = true
|
||||
|
||||
[package.metadata.component]
|
||||
package = "component:alloy"
|
||||
|
||||
[package.metadata.component.target.dependencies]
|
||||
"component:churn-tasks" = { path = "../churn-tasks/wit" }
|
||||
|
||||
[package.metadata.component.dependencies]
|
144
alloy/src/bindings.rs
Normal file
144
alloy/src/bindings.rs
Normal file
@ -0,0 +1,144 @@
|
||||
#[allow(dead_code)]
|
||||
pub mod exports {
|
||||
#[allow(dead_code)]
|
||||
pub mod component {
|
||||
#[allow(dead_code)]
|
||||
pub mod churn_tasks {
|
||||
#[allow(dead_code, clippy::all)]
|
||||
pub mod task {
|
||||
#[used]
|
||||
#[doc(hidden)]
|
||||
static __FORCE_SECTION_REF: fn() = super::super::super::super::__link_custom_section_describing_imports;
|
||||
use super::super::super::super::_rt;
|
||||
#[doc(hidden)]
|
||||
#[allow(non_snake_case)]
|
||||
pub unsafe fn _export_id_cabi<T: Guest>() -> *mut u8 {
|
||||
#[cfg(target_arch = "wasm32")] _rt::run_ctors_once();
|
||||
let result0 = T::id();
|
||||
let ptr1 = _RET_AREA.0.as_mut_ptr().cast::<u8>();
|
||||
let vec2 = (result0.into_bytes()).into_boxed_slice();
|
||||
let ptr2 = vec2.as_ptr().cast::<u8>();
|
||||
let len2 = vec2.len();
|
||||
::core::mem::forget(vec2);
|
||||
*ptr1.add(4).cast::<usize>() = len2;
|
||||
*ptr1.add(0).cast::<*mut u8>() = ptr2.cast_mut();
|
||||
ptr1
|
||||
}
|
||||
#[doc(hidden)]
|
||||
#[allow(non_snake_case)]
|
||||
pub unsafe fn __post_return_id<T: Guest>(arg0: *mut u8) {
|
||||
let l0 = *arg0.add(0).cast::<*mut u8>();
|
||||
let l1 = *arg0.add(4).cast::<usize>();
|
||||
_rt::cabi_dealloc(l0, l1, 1);
|
||||
}
|
||||
#[doc(hidden)]
|
||||
#[allow(non_snake_case)]
|
||||
pub unsafe fn _export_should_run_cabi<T: Guest>() -> i32 {
|
||||
#[cfg(target_arch = "wasm32")] _rt::run_ctors_once();
|
||||
let result0 = T::should_run();
|
||||
match result0 {
|
||||
true => 1,
|
||||
false => 0,
|
||||
}
|
||||
}
|
||||
#[doc(hidden)]
|
||||
#[allow(non_snake_case)]
|
||||
pub unsafe fn _export_execute_cabi<T: Guest>() {
|
||||
#[cfg(target_arch = "wasm32")] _rt::run_ctors_once();
|
||||
T::execute();
|
||||
}
|
||||
pub trait Guest {
|
||||
fn id() -> _rt::String;
|
||||
fn should_run() -> bool;
|
||||
fn execute();
|
||||
}
|
||||
#[doc(hidden)]
|
||||
macro_rules! __export_component_churn_tasks_task_0_1_0_cabi {
|
||||
($ty:ident with_types_in $($path_to_types:tt)*) => {
|
||||
const _ : () = { #[export_name =
|
||||
"component:churn-tasks/task@0.1.0#id"] unsafe extern "C" fn
|
||||
export_id() -> * mut u8 { $($path_to_types)*::
|
||||
_export_id_cabi::<$ty > () } #[export_name =
|
||||
"cabi_post_component:churn-tasks/task@0.1.0#id"] unsafe extern
|
||||
"C" fn _post_return_id(arg0 : * mut u8,) { $($path_to_types)*::
|
||||
__post_return_id::<$ty > (arg0) } #[export_name =
|
||||
"component:churn-tasks/task@0.1.0#should-run"] unsafe extern "C"
|
||||
fn export_should_run() -> i32 { $($path_to_types)*::
|
||||
_export_should_run_cabi::<$ty > () } #[export_name =
|
||||
"component:churn-tasks/task@0.1.0#execute"] unsafe extern "C" fn
|
||||
export_execute() { $($path_to_types)*::
|
||||
_export_execute_cabi::<$ty > () } };
|
||||
};
|
||||
}
|
||||
#[doc(hidden)]
|
||||
pub(crate) use __export_component_churn_tasks_task_0_1_0_cabi;
|
||||
#[repr(align(4))]
|
||||
struct _RetArea([::core::mem::MaybeUninit<u8>; 8]);
|
||||
static mut _RET_AREA: _RetArea = _RetArea(
|
||||
[::core::mem::MaybeUninit::uninit(); 8],
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
mod _rt {
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
pub fn run_ctors_once() {
|
||||
wit_bindgen_rt::run_ctors_once();
|
||||
}
|
||||
pub unsafe fn cabi_dealloc(ptr: *mut u8, size: usize, align: usize) {
|
||||
if size == 0 {
|
||||
return;
|
||||
}
|
||||
let layout = alloc::Layout::from_size_align_unchecked(size, align);
|
||||
alloc::dealloc(ptr, layout);
|
||||
}
|
||||
pub use alloc_crate::string::String;
|
||||
pub use alloc_crate::alloc;
|
||||
extern crate alloc as alloc_crate;
|
||||
}
|
||||
/// Generates `#[no_mangle]` functions to export the specified type as the
|
||||
/// root implementation of all generated traits.
|
||||
///
|
||||
/// For more information see the documentation of `wit_bindgen::generate!`.
|
||||
///
|
||||
/// ```rust
|
||||
/// # macro_rules! export{ ($($t:tt)*) => (); }
|
||||
/// # trait Guest {}
|
||||
/// struct MyType;
|
||||
///
|
||||
/// impl Guest for MyType {
|
||||
/// // ...
|
||||
/// }
|
||||
///
|
||||
/// export!(MyType);
|
||||
/// ```
|
||||
#[allow(unused_macros)]
|
||||
#[doc(hidden)]
|
||||
macro_rules! __export_alloy_impl {
|
||||
($ty:ident) => {
|
||||
self::export!($ty with_types_in self);
|
||||
};
|
||||
($ty:ident with_types_in $($path_to_types_root:tt)*) => {
|
||||
$($path_to_types_root)*::
|
||||
exports::component::churn_tasks::task::__export_component_churn_tasks_task_0_1_0_cabi!($ty
|
||||
with_types_in $($path_to_types_root)*:: exports::component::churn_tasks::task);
|
||||
};
|
||||
}
|
||||
#[doc(inline)]
|
||||
pub(crate) use __export_alloy_impl as export;
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
#[link_section = "component-type:wit-bindgen:0.35.0:component:alloy:alloy:encoded world"]
|
||||
#[doc(hidden)]
|
||||
pub static __WIT_BINDGEN_COMPONENT_TYPE: [u8; 244] = *b"\
|
||||
\0asm\x0d\0\x01\0\0\x19\x16wit-component-encoding\x04\0\x07y\x01A\x02\x01A\x02\x01\
|
||||
B\x06\x01@\0\0s\x04\0\x02id\x01\0\x01@\0\0\x7f\x04\0\x0ashould-run\x01\x01\x01@\0\
|
||||
\x01\0\x04\0\x07execute\x01\x02\x04\0\x20component:churn-tasks/task@0.1.0\x05\0\x04\
|
||||
\0\x15component:alloy/alloy\x04\0\x0b\x0b\x01\0\x05alloy\x03\0\0\0G\x09producers\
|
||||
\x01\x0cprocessed-by\x02\x0dwit-component\x070.220.0\x10wit-bindgen-rust\x060.35\
|
||||
.0";
|
||||
#[inline(never)]
|
||||
#[doc(hidden)]
|
||||
pub fn __link_custom_section_describing_imports() {
|
||||
wit_bindgen_rt::maybe_link_cabi_realloc();
|
||||
}
|
22
alloy/src/lib.rs
Normal file
22
alloy/src/lib.rs
Normal file
@ -0,0 +1,22 @@
|
||||
use bindings::exports::component::churn_tasks::task::Guest;
|
||||
|
||||
#[allow(warnings)]
|
||||
mod bindings;
|
||||
|
||||
struct Component;
|
||||
|
||||
impl Guest for Component {
|
||||
fn id() -> String {
|
||||
"grafana/alloy".into()
|
||||
}
|
||||
|
||||
fn should_run() -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
fn execute() {
|
||||
println!("I was run");
|
||||
}
|
||||
}
|
||||
|
||||
bindings::export!(Component with_types_in bindings);
|
6
alloy/wit/world.wit
Normal file
6
alloy/wit/world.wit
Normal file
@ -0,0 +1,6 @@
|
||||
package component:alloy;
|
||||
|
||||
/// An example world for the component to target.
|
||||
world alloy {
|
||||
export component:churn-tasks/task@0.1.0;
|
||||
}
|
10
churn-tasks/.vscode/settings.json
vendored
Normal file
10
churn-tasks/.vscode/settings.json
vendored
Normal file
@ -0,0 +1,10 @@
|
||||
{
|
||||
"rust-analyzer.check.overrideCommand": [
|
||||
"cargo",
|
||||
"component",
|
||||
"check",
|
||||
"--workspace",
|
||||
"--all-targets",
|
||||
"--message-format=json"
|
||||
],
|
||||
}
|
25
churn-tasks/Cargo.lock
generated
Normal file
25
churn-tasks/Cargo.lock
generated
Normal file
@ -0,0 +1,25 @@
|
||||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
version = 4
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "2.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de"
|
||||
|
||||
[[package]]
|
||||
name = "churn-tasks"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"wit-bindgen-rt",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wit-bindgen-rt"
|
||||
version = "0.36.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7947d0131c7c9da3f01dfde0ab8bd4c4cf3c5bd49b6dba0ae640f1fa752572ea"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
]
|
22
churn-tasks/Cargo.toml
Normal file
22
churn-tasks/Cargo.toml
Normal file
@ -0,0 +1,22 @@
|
||||
[package]
|
||||
name = "churn-tasks"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
wit-bindgen-rt = { version = "0.36.0", features = ["bitflags"] }
|
||||
|
||||
[lib]
|
||||
crate-type = ["cdylib"]
|
||||
|
||||
[profile.release]
|
||||
codegen-units = 1
|
||||
opt-level = "s"
|
||||
debug = false
|
||||
strip = true
|
||||
lto = true
|
||||
|
||||
[package.metadata.component]
|
||||
package = "component:churn-tasks"
|
||||
|
||||
[package.metadata.component.dependencies]
|
148
churn-tasks/src/bindings.rs
Normal file
148
churn-tasks/src/bindings.rs
Normal file
@ -0,0 +1,148 @@
|
||||
#[doc(hidden)]
|
||||
#[allow(non_snake_case)]
|
||||
pub unsafe fn _export_id_cabi<T: Guest>() -> *mut u8 {
|
||||
#[cfg(target_arch = "wasm32")] _rt::run_ctors_once();
|
||||
let result0 = T::id();
|
||||
let ptr1 = _RET_AREA.0.as_mut_ptr().cast::<u8>();
|
||||
let vec2 = (result0.into_bytes()).into_boxed_slice();
|
||||
let ptr2 = vec2.as_ptr().cast::<u8>();
|
||||
let len2 = vec2.len();
|
||||
::core::mem::forget(vec2);
|
||||
*ptr1.add(4).cast::<usize>() = len2;
|
||||
*ptr1.add(0).cast::<*mut u8>() = ptr2.cast_mut();
|
||||
ptr1
|
||||
}
|
||||
#[doc(hidden)]
|
||||
#[allow(non_snake_case)]
|
||||
pub unsafe fn __post_return_id<T: Guest>(arg0: *mut u8) {
|
||||
let l0 = *arg0.add(0).cast::<*mut u8>();
|
||||
let l1 = *arg0.add(4).cast::<usize>();
|
||||
_rt::cabi_dealloc(l0, l1, 1);
|
||||
}
|
||||
#[doc(hidden)]
|
||||
#[allow(non_snake_case)]
|
||||
pub unsafe fn _export_should_run_cabi<T: Guest>() -> *mut u8 {
|
||||
#[cfg(target_arch = "wasm32")] _rt::run_ctors_once();
|
||||
let result0 = T::should_run();
|
||||
let ptr1 = _RET_AREA.0.as_mut_ptr().cast::<u8>();
|
||||
let vec2 = (result0.into_bytes()).into_boxed_slice();
|
||||
let ptr2 = vec2.as_ptr().cast::<u8>();
|
||||
let len2 = vec2.len();
|
||||
::core::mem::forget(vec2);
|
||||
*ptr1.add(4).cast::<usize>() = len2;
|
||||
*ptr1.add(0).cast::<*mut u8>() = ptr2.cast_mut();
|
||||
ptr1
|
||||
}
|
||||
#[doc(hidden)]
|
||||
#[allow(non_snake_case)]
|
||||
pub unsafe fn __post_return_should_run<T: Guest>(arg0: *mut u8) {
|
||||
let l0 = *arg0.add(0).cast::<*mut u8>();
|
||||
let l1 = *arg0.add(4).cast::<usize>();
|
||||
_rt::cabi_dealloc(l0, l1, 1);
|
||||
}
|
||||
#[doc(hidden)]
|
||||
#[allow(non_snake_case)]
|
||||
pub unsafe fn _export_execute_cabi<T: Guest>() -> *mut u8 {
|
||||
#[cfg(target_arch = "wasm32")] _rt::run_ctors_once();
|
||||
let result0 = T::execute();
|
||||
let ptr1 = _RET_AREA.0.as_mut_ptr().cast::<u8>();
|
||||
let vec2 = (result0.into_bytes()).into_boxed_slice();
|
||||
let ptr2 = vec2.as_ptr().cast::<u8>();
|
||||
let len2 = vec2.len();
|
||||
::core::mem::forget(vec2);
|
||||
*ptr1.add(4).cast::<usize>() = len2;
|
||||
*ptr1.add(0).cast::<*mut u8>() = ptr2.cast_mut();
|
||||
ptr1
|
||||
}
|
||||
#[doc(hidden)]
|
||||
#[allow(non_snake_case)]
|
||||
pub unsafe fn __post_return_execute<T: Guest>(arg0: *mut u8) {
|
||||
let l0 = *arg0.add(0).cast::<*mut u8>();
|
||||
let l1 = *arg0.add(4).cast::<usize>();
|
||||
_rt::cabi_dealloc(l0, l1, 1);
|
||||
}
|
||||
pub trait Guest {
|
||||
fn id() -> _rt::String;
|
||||
fn should_run() -> _rt::String;
|
||||
fn execute() -> _rt::String;
|
||||
}
|
||||
#[doc(hidden)]
|
||||
macro_rules! __export_world_task_cabi {
|
||||
($ty:ident with_types_in $($path_to_types:tt)*) => {
|
||||
const _ : () = { #[export_name = "id"] unsafe extern "C" fn export_id() -> * mut
|
||||
u8 { $($path_to_types)*:: _export_id_cabi::<$ty > () } #[export_name =
|
||||
"cabi_post_id"] unsafe extern "C" fn _post_return_id(arg0 : * mut u8,) {
|
||||
$($path_to_types)*:: __post_return_id::<$ty > (arg0) } #[export_name =
|
||||
"should-run"] unsafe extern "C" fn export_should_run() -> * mut u8 {
|
||||
$($path_to_types)*:: _export_should_run_cabi::<$ty > () } #[export_name =
|
||||
"cabi_post_should-run"] unsafe extern "C" fn _post_return_should_run(arg0 : * mut
|
||||
u8,) { $($path_to_types)*:: __post_return_should_run::<$ty > (arg0) }
|
||||
#[export_name = "execute"] unsafe extern "C" fn export_execute() -> * mut u8 {
|
||||
$($path_to_types)*:: _export_execute_cabi::<$ty > () } #[export_name =
|
||||
"cabi_post_execute"] unsafe extern "C" fn _post_return_execute(arg0 : * mut u8,)
|
||||
{ $($path_to_types)*:: __post_return_execute::<$ty > (arg0) } };
|
||||
};
|
||||
}
|
||||
#[doc(hidden)]
|
||||
pub(crate) use __export_world_task_cabi;
|
||||
#[repr(align(4))]
|
||||
struct _RetArea([::core::mem::MaybeUninit<u8>; 8]);
|
||||
static mut _RET_AREA: _RetArea = _RetArea([::core::mem::MaybeUninit::uninit(); 8]);
|
||||
mod _rt {
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
pub fn run_ctors_once() {
|
||||
wit_bindgen_rt::run_ctors_once();
|
||||
}
|
||||
pub unsafe fn cabi_dealloc(ptr: *mut u8, size: usize, align: usize) {
|
||||
if size == 0 {
|
||||
return;
|
||||
}
|
||||
let layout = alloc::Layout::from_size_align_unchecked(size, align);
|
||||
alloc::dealloc(ptr, layout);
|
||||
}
|
||||
pub use alloc_crate::string::String;
|
||||
pub use alloc_crate::alloc;
|
||||
extern crate alloc as alloc_crate;
|
||||
}
|
||||
/// Generates `#[no_mangle]` functions to export the specified type as the
|
||||
/// root implementation of all generated traits.
|
||||
///
|
||||
/// For more information see the documentation of `wit_bindgen::generate!`.
|
||||
///
|
||||
/// ```rust
|
||||
/// # macro_rules! export{ ($($t:tt)*) => (); }
|
||||
/// # trait Guest {}
|
||||
/// struct MyType;
|
||||
///
|
||||
/// impl Guest for MyType {
|
||||
/// // ...
|
||||
/// }
|
||||
///
|
||||
/// export!(MyType);
|
||||
/// ```
|
||||
#[allow(unused_macros)]
|
||||
#[doc(hidden)]
|
||||
macro_rules! __export_task_impl {
|
||||
($ty:ident) => {
|
||||
self::export!($ty with_types_in self);
|
||||
};
|
||||
($ty:ident with_types_in $($path_to_types_root:tt)*) => {
|
||||
$($path_to_types_root)*:: __export_world_task_cabi!($ty with_types_in
|
||||
$($path_to_types_root)*);
|
||||
};
|
||||
}
|
||||
#[doc(inline)]
|
||||
pub(crate) use __export_task_impl as export;
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
#[link_section = "component-type:wit-bindgen:0.35.0:component:churn-tasks:task:encoded world"]
|
||||
#[doc(hidden)]
|
||||
pub static __WIT_BINDGEN_COMPONENT_TYPE: [u8; 198] = *b"\
|
||||
\0asm\x0d\0\x01\0\0\x19\x16wit-component-encoding\x04\0\x07L\x01A\x02\x01A\x04\x01\
|
||||
@\0\0s\x04\0\x02id\x01\0\x04\0\x0ashould-run\x01\0\x04\0\x07execute\x01\0\x04\0\x1a\
|
||||
component:churn-tasks/task\x04\0\x0b\x0a\x01\0\x04task\x03\0\0\0G\x09producers\x01\
|
||||
\x0cprocessed-by\x02\x0dwit-component\x070.220.0\x10wit-bindgen-rust\x060.35.0";
|
||||
#[inline(never)]
|
||||
#[doc(hidden)]
|
||||
pub fn __link_custom_section_describing_imports() {
|
||||
wit_bindgen_rt::maybe_link_cabi_realloc();
|
||||
}
|
22
churn-tasks/src/lib.rs
Normal file
22
churn-tasks/src/lib.rs
Normal file
@ -0,0 +1,22 @@
|
||||
#[allow(warnings)]
|
||||
mod bindings;
|
||||
|
||||
use bindings::Guest;
|
||||
|
||||
struct Component;
|
||||
|
||||
impl Guest for Component {
|
||||
fn id() -> String {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn should_run() -> String {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn execute() -> String {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
bindings::export!(Component with_types_in bindings);
|
11
churn-tasks/wit/world.wit
Normal file
11
churn-tasks/wit/world.wit
Normal file
@ -0,0 +1,11 @@
|
||||
package component:churn-tasks@0.1.0;
|
||||
|
||||
interface task {
|
||||
id: func() -> string;
|
||||
should-run: func() -> bool;
|
||||
execute: func();
|
||||
}
|
||||
|
||||
world churn {
|
||||
export task;
|
||||
}
|
Loading…
Reference in New Issue
Block a user