functionalscript 0.0.413 → 0.0.416
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.
- package/Cargo.lock +0 -7
- package/Cargo.toml +1 -2
- package/com/rust/nanocom/README.md +54 -1
- package/com/rust/nanocom/src/cobject.rs +3 -3
- package/com/rust/nanocom/src/iunknown.rs +3 -3
- package/com/rust/nanocom/tests/it.rs +188 -0
- package/package.json +1 -1
- package/com/rust/nanocom/rstest/Cargo.lock +0 -14
- package/com/rust/nanocom/rstest/Cargo.toml +0 -9
- package/com/rust/nanocom/rstest/src/lib.rs +0 -191
package/Cargo.lock
CHANGED
package/Cargo.toml
CHANGED
|
@@ -1,3 +1,56 @@
|
|
|
1
1
|
# Nano-COM
|
|
2
2
|
|
|
3
|
-
See [Nano-COM](https://en.wikipedia.org/wiki/Component_Object_Model#Nano-COM_(a.k.a_XPCOM)).
|
|
3
|
+
See [Nano-COM](https://en.wikipedia.org/wiki/Component_Object_Model#Nano-COM_(a.k.a_XPCOM)).
|
|
4
|
+
|
|
5
|
+
## Function Stack
|
|
6
|
+
|
|
7
|
+
- a public function.
|
|
8
|
+
```rust
|
|
9
|
+
let o: Object<IMy> = ...;
|
|
10
|
+
// calling a public function
|
|
11
|
+
let i: u32 = o.B();
|
|
12
|
+
```
|
|
13
|
+
```rust
|
|
14
|
+
trait IMyEx {
|
|
15
|
+
// a definition
|
|
16
|
+
fn B(&self) -> u32;
|
|
17
|
+
}
|
|
18
|
+
impl IMyEx for Object<IMy> {
|
|
19
|
+
// an implementation of the public function
|
|
20
|
+
fn B(&self) -> u32 {
|
|
21
|
+
// calling a virtual function.
|
|
22
|
+
unsafe { (self.interface().B()(self) }
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
```
|
|
26
|
+
- a virtual function.
|
|
27
|
+
```rust
|
|
28
|
+
#[repr(C)]
|
|
29
|
+
pub struct IMy {
|
|
30
|
+
// a definiton of the virtual function
|
|
31
|
+
pub B: unsafe extern "stdcall" fn(this: &Object<IMy>) -> u32
|
|
32
|
+
}
|
|
33
|
+
trait IMyVmtFn: Class<Interface = IMy>
|
|
34
|
+
where
|
|
35
|
+
CObject<Self>: IMyEx
|
|
36
|
+
{
|
|
37
|
+
// an implementation of the virtual function
|
|
38
|
+
extern "stdcall" fn B(this: &Object<IMy>) -> u32 {
|
|
39
|
+
// calling a function implementation
|
|
40
|
+
unsafe { Self::to_cobject(this) }.B()
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
```
|
|
44
|
+
- a function implementation.
|
|
45
|
+
```rust
|
|
46
|
+
trait IMyEx {
|
|
47
|
+
// a definition
|
|
48
|
+
fn B(&self) -> u32;
|
|
49
|
+
}
|
|
50
|
+
impl IMyEx for CObject<X> {
|
|
51
|
+
// an implementation of the function.
|
|
52
|
+
fn B(&self) -> u32 {
|
|
53
|
+
self.value.0
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
```
|
|
@@ -35,7 +35,7 @@ impl<T: Class> CObject<T> {
|
|
|
35
35
|
};
|
|
36
36
|
|
|
37
37
|
#[allow(non_snake_case)]
|
|
38
|
-
extern "
|
|
38
|
+
extern "system" fn QueryInterface(
|
|
39
39
|
this: &Object<T::Interface>,
|
|
40
40
|
riid: &u128,
|
|
41
41
|
ppv_object: &mut *const Object,
|
|
@@ -51,7 +51,7 @@ impl<T: Class> CObject<T> {
|
|
|
51
51
|
}
|
|
52
52
|
|
|
53
53
|
#[allow(non_snake_case)]
|
|
54
|
-
extern "
|
|
54
|
+
extern "system" fn AddRef(this: &Object<T::Interface>) -> u32 {
|
|
55
55
|
unsafe { T::to_cobject(this) }
|
|
56
56
|
.counter
|
|
57
57
|
.fetch_add(1, Ordering::Relaxed)
|
|
@@ -59,7 +59,7 @@ impl<T: Class> CObject<T> {
|
|
|
59
59
|
}
|
|
60
60
|
|
|
61
61
|
#[allow(non_snake_case)]
|
|
62
|
-
extern "
|
|
62
|
+
extern "system" fn Release(this: &Object<T::Interface>) -> u32 {
|
|
63
63
|
let t = unsafe { T::to_cobject(this) };
|
|
64
64
|
match t.counter.fetch_sub(1, Ordering::Relaxed) {
|
|
65
65
|
1 => {
|
|
@@ -3,11 +3,11 @@ use crate::{hresult::HRESULT, Object, GUID};
|
|
|
3
3
|
#[allow(non_snake_case)]
|
|
4
4
|
#[repr(C)]
|
|
5
5
|
pub struct IUnknown<I: 'static> {
|
|
6
|
-
pub QueryInterface: unsafe extern "
|
|
6
|
+
pub QueryInterface: unsafe extern "system" fn(
|
|
7
7
|
this: &Object<I>,
|
|
8
8
|
riid: &GUID,
|
|
9
9
|
ppv_object: &mut *const Object,
|
|
10
10
|
) -> HRESULT,
|
|
11
|
-
pub AddRef: unsafe extern "
|
|
12
|
-
pub Release: unsafe extern "
|
|
11
|
+
pub AddRef: unsafe extern "system" fn(this: &Object<I>) -> u32,
|
|
12
|
+
pub Release: unsafe extern "system" fn(this: &Object<I>) -> u32,
|
|
13
13
|
}
|
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
// interface definition:
|
|
2
|
+
|
|
3
|
+
mod library {
|
|
4
|
+
use nanocom::{CObject, Class, Interface, Object, Ref, GUID};
|
|
5
|
+
|
|
6
|
+
#[allow(non_snake_case)]
|
|
7
|
+
#[repr(C)]
|
|
8
|
+
pub struct IMy {
|
|
9
|
+
pub A: unsafe extern "stdcall" fn(this: &Object<IMy>) -> Ref<IMy>,
|
|
10
|
+
pub B: unsafe extern "stdcall" fn(this: &Object<IMy>) -> u32,
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
impl Interface for IMy {
|
|
14
|
+
const GUID: GUID = 0x01234567_89AB_CDEF_0123_456789ABCDEF;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
#[allow(non_snake_case)]
|
|
18
|
+
pub trait IMyEx {
|
|
19
|
+
fn A(&self) -> Ref<IMy>;
|
|
20
|
+
fn B(&self) -> u32;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
#[allow(non_snake_case)]
|
|
24
|
+
impl IMyEx for Object<IMy> {
|
|
25
|
+
fn A(&self) -> Ref<IMy> {
|
|
26
|
+
unsafe { (self.interface().A)(self) }
|
|
27
|
+
}
|
|
28
|
+
fn B(&self) -> u32 {
|
|
29
|
+
unsafe { (self.interface().B)(self) }
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
pub trait IMyVmt: Class<Interface = IMy>
|
|
34
|
+
where
|
|
35
|
+
CObject<Self>: IMyEx,
|
|
36
|
+
{
|
|
37
|
+
const INTERFACE: IMy = IMy {
|
|
38
|
+
A: Self::A,
|
|
39
|
+
B: Self::B,
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
impl<T: Class<Interface = IMy>> IMyVmt for T where CObject<T>: IMyEx {}
|
|
44
|
+
|
|
45
|
+
#[allow(non_snake_case)]
|
|
46
|
+
trait IMyVmtFn: Class<Interface = IMy>
|
|
47
|
+
where
|
|
48
|
+
CObject<Self>: IMyEx,
|
|
49
|
+
{
|
|
50
|
+
extern "stdcall" fn A(this: &Object<IMy>) -> Ref<IMy> {
|
|
51
|
+
unsafe { Self::to_cobject(this) }.A()
|
|
52
|
+
}
|
|
53
|
+
extern "stdcall" fn B(this: &Object<IMy>) -> u32 {
|
|
54
|
+
unsafe { Self::to_cobject(this) }.B()
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
impl<T: Class<Interface = IMy>> IMyVmtFn for T where CObject<T>: IMyEx {}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// interface implementation
|
|
62
|
+
mod number {
|
|
63
|
+
use nanocom::{CObject, Class, Ref, Vmt};
|
|
64
|
+
|
|
65
|
+
use super::library::{IMy, IMyEx, IMyVmt};
|
|
66
|
+
|
|
67
|
+
pub struct X(pub u32);
|
|
68
|
+
|
|
69
|
+
impl Class for X {
|
|
70
|
+
type Interface = IMy;
|
|
71
|
+
fn static_vmt() -> &'static Vmt<Self::Interface> {
|
|
72
|
+
static V: Vmt<IMy> = Vmt {
|
|
73
|
+
iunknown: X::IUNKNOWN,
|
|
74
|
+
interface: X::INTERFACE,
|
|
75
|
+
};
|
|
76
|
+
&V
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
#[allow(non_snake_case)]
|
|
81
|
+
impl IMyEx for CObject<X> {
|
|
82
|
+
fn A(&self) -> Ref<IMy> {
|
|
83
|
+
self.to_interface().into()
|
|
84
|
+
}
|
|
85
|
+
fn B(&self) -> u32 {
|
|
86
|
+
self.value.0
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
mod use_number {
|
|
92
|
+
use nanocom::Class;
|
|
93
|
+
|
|
94
|
+
use super::{library::IMyEx, number::X};
|
|
95
|
+
|
|
96
|
+
#[test]
|
|
97
|
+
fn test() {
|
|
98
|
+
let a = X(42).cobject_new();
|
|
99
|
+
let a1 = a.A();
|
|
100
|
+
assert_eq!(a, a1);
|
|
101
|
+
assert_eq!(a.B(), 42);
|
|
102
|
+
let b = X(43).cobject_new();
|
|
103
|
+
assert_ne!(a, b);
|
|
104
|
+
assert_eq!(b.B(), 43);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
mod destructor {
|
|
109
|
+
use std::{
|
|
110
|
+
rc::Rc,
|
|
111
|
+
sync::atomic::{AtomicU32, Ordering},
|
|
112
|
+
};
|
|
113
|
+
|
|
114
|
+
use nanocom::{CObject, Class, Ref, Vmt};
|
|
115
|
+
|
|
116
|
+
use super::library::{IMy, IMyEx, IMyVmt};
|
|
117
|
+
|
|
118
|
+
pub struct X {
|
|
119
|
+
p: Rc<AtomicU32>,
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
impl X {
|
|
123
|
+
pub fn new(p: Rc<AtomicU32>) -> Self {
|
|
124
|
+
p.fetch_add(1, Ordering::Relaxed);
|
|
125
|
+
Self { p }
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
impl Drop for X {
|
|
130
|
+
fn drop(&mut self) {
|
|
131
|
+
self.p.fetch_sub(1, Ordering::Relaxed);
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
impl Class for X {
|
|
136
|
+
type Interface = IMy;
|
|
137
|
+
fn static_vmt() -> &'static Vmt<Self::Interface> {
|
|
138
|
+
static V: Vmt<IMy> = Vmt {
|
|
139
|
+
iunknown: X::IUNKNOWN,
|
|
140
|
+
interface: X::INTERFACE,
|
|
141
|
+
};
|
|
142
|
+
&V
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
#[allow(non_snake_case)]
|
|
147
|
+
impl IMyEx for CObject<X> {
|
|
148
|
+
fn A(&self) -> Ref<IMy> {
|
|
149
|
+
self.to_interface().into()
|
|
150
|
+
}
|
|
151
|
+
fn B(&self) -> u32 {
|
|
152
|
+
self.value.p.load(Ordering::Relaxed)
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
mod use_destructor {
|
|
158
|
+
use std::{
|
|
159
|
+
rc::Rc,
|
|
160
|
+
sync::atomic::{AtomicU32, Ordering},
|
|
161
|
+
};
|
|
162
|
+
|
|
163
|
+
use nanocom::Class;
|
|
164
|
+
|
|
165
|
+
use super::{destructor::X, library::IMyEx};
|
|
166
|
+
|
|
167
|
+
#[test]
|
|
168
|
+
fn test() {
|
|
169
|
+
let p = Rc::new(AtomicU32::default());
|
|
170
|
+
{
|
|
171
|
+
assert_eq!(p.load(Ordering::Relaxed), 0);
|
|
172
|
+
let a = X::new(p.clone()).cobject_new();
|
|
173
|
+
assert_eq!(p.load(Ordering::Relaxed), 1);
|
|
174
|
+
let a1 = a.A();
|
|
175
|
+
assert_eq!(p.load(Ordering::Relaxed), 1);
|
|
176
|
+
assert_eq!(a, a1);
|
|
177
|
+
assert_eq!(a.B(), 1);
|
|
178
|
+
{
|
|
179
|
+
let b = X::new(p.clone()).cobject_new();
|
|
180
|
+
assert_eq!(p.load(Ordering::Relaxed), 2);
|
|
181
|
+
assert_ne!(a, b);
|
|
182
|
+
assert_eq!(b.B(), 2);
|
|
183
|
+
}
|
|
184
|
+
assert_eq!(p.load(Ordering::Relaxed), 1);
|
|
185
|
+
}
|
|
186
|
+
assert_eq!(p.load(Ordering::Relaxed), 0);
|
|
187
|
+
}
|
|
188
|
+
}
|
package/package.json
CHANGED
|
@@ -1,191 +0,0 @@
|
|
|
1
|
-
#[cfg(test)]
|
|
2
|
-
mod test {
|
|
3
|
-
// interface definition:
|
|
4
|
-
|
|
5
|
-
mod library {
|
|
6
|
-
use nanocom::{CObject, Class, Interface, Object, Ref, GUID};
|
|
7
|
-
|
|
8
|
-
#[allow(non_snake_case)]
|
|
9
|
-
#[repr(C)]
|
|
10
|
-
pub struct IMy {
|
|
11
|
-
pub A: unsafe extern "stdcall" fn(this: &Object<IMy>) -> Ref<IMy>,
|
|
12
|
-
pub B: unsafe extern "stdcall" fn(this: &Object<IMy>) -> u32,
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
impl Interface for IMy {
|
|
16
|
-
const GUID: GUID = 0x01234567_89AB_CDEF_0123_456789ABCDEF;
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
#[allow(non_snake_case)]
|
|
20
|
-
pub trait IMyEx {
|
|
21
|
-
fn A(&self) -> Ref<IMy>;
|
|
22
|
-
fn B(&self) -> u32;
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
#[allow(non_snake_case)]
|
|
26
|
-
impl IMyEx for Object<IMy> {
|
|
27
|
-
fn A(&self) -> Ref<IMy> {
|
|
28
|
-
unsafe { (self.interface().A)(self) }
|
|
29
|
-
}
|
|
30
|
-
fn B(&self) -> u32 {
|
|
31
|
-
unsafe { (self.interface().B)(self) }
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
pub trait IMyVmt: Class<Interface = IMy>
|
|
36
|
-
where
|
|
37
|
-
CObject<Self>: IMyEx,
|
|
38
|
-
{
|
|
39
|
-
const INTERFACE: IMy = IMy {
|
|
40
|
-
A: Self::A,
|
|
41
|
-
B: Self::B,
|
|
42
|
-
};
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
impl<T: Class<Interface = IMy>> IMyVmt for T where CObject<T>: IMyEx {}
|
|
46
|
-
|
|
47
|
-
#[allow(non_snake_case)]
|
|
48
|
-
trait IMyVmtFn: Class<Interface = IMy>
|
|
49
|
-
where
|
|
50
|
-
CObject<Self>: IMyEx,
|
|
51
|
-
{
|
|
52
|
-
extern "stdcall" fn A(this: &Object<IMy>) -> Ref<IMy> {
|
|
53
|
-
unsafe { Self::to_cobject(this) }.A()
|
|
54
|
-
}
|
|
55
|
-
extern "stdcall" fn B(this: &Object<IMy>) -> u32 {
|
|
56
|
-
unsafe { Self::to_cobject(this) }.B()
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
impl<T: Class<Interface = IMy>> IMyVmtFn for T where CObject<T>: IMyEx {}
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
// interface implementation
|
|
64
|
-
mod number {
|
|
65
|
-
use nanocom::{CObject, Class, Ref, Vmt};
|
|
66
|
-
|
|
67
|
-
use super::library::{IMy, IMyEx, IMyVmt};
|
|
68
|
-
|
|
69
|
-
pub struct X(pub u32);
|
|
70
|
-
|
|
71
|
-
impl Class for X {
|
|
72
|
-
type Interface = IMy;
|
|
73
|
-
fn static_vmt() -> &'static Vmt<Self::Interface> {
|
|
74
|
-
static V: Vmt<IMy> = Vmt {
|
|
75
|
-
iunknown: X::IUNKNOWN,
|
|
76
|
-
interface: X::INTERFACE,
|
|
77
|
-
};
|
|
78
|
-
&V
|
|
79
|
-
}
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
#[allow(non_snake_case)]
|
|
83
|
-
impl IMyEx for CObject<X> {
|
|
84
|
-
fn A(&self) -> Ref<IMy> {
|
|
85
|
-
self.to_interface().into()
|
|
86
|
-
}
|
|
87
|
-
fn B(&self) -> u32 {
|
|
88
|
-
self.value.0
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
mod use_number {
|
|
94
|
-
use nanocom::Class;
|
|
95
|
-
|
|
96
|
-
use crate::test::{library::IMyEx, number::X};
|
|
97
|
-
|
|
98
|
-
#[test]
|
|
99
|
-
fn test() {
|
|
100
|
-
let a = X(42).cobject_new();
|
|
101
|
-
let a1 = a.A();
|
|
102
|
-
assert_eq!(a, a1);
|
|
103
|
-
assert_eq!(a.B(), 42);
|
|
104
|
-
let b = X(43).cobject_new();
|
|
105
|
-
assert_ne!(a, b);
|
|
106
|
-
assert_eq!(b.B(), 43);
|
|
107
|
-
}
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
mod destructor {
|
|
111
|
-
use std::{
|
|
112
|
-
rc::Rc,
|
|
113
|
-
sync::atomic::{AtomicU32, Ordering},
|
|
114
|
-
};
|
|
115
|
-
|
|
116
|
-
use nanocom::{CObject, Class, Ref, Vmt};
|
|
117
|
-
|
|
118
|
-
use super::library::{IMy, IMyEx, IMyVmt};
|
|
119
|
-
|
|
120
|
-
pub struct X {
|
|
121
|
-
p: Rc<AtomicU32>,
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
impl X {
|
|
125
|
-
pub fn new(p: Rc<AtomicU32>) -> Self {
|
|
126
|
-
p.fetch_add(1, Ordering::Relaxed);
|
|
127
|
-
Self { p }
|
|
128
|
-
}
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
impl Drop for X {
|
|
132
|
-
fn drop(&mut self) {
|
|
133
|
-
self.p.fetch_sub(1, Ordering::Relaxed);
|
|
134
|
-
}
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
impl Class for X {
|
|
138
|
-
type Interface = IMy;
|
|
139
|
-
fn static_vmt() -> &'static Vmt<Self::Interface> {
|
|
140
|
-
static V: Vmt<IMy> = Vmt {
|
|
141
|
-
iunknown: X::IUNKNOWN,
|
|
142
|
-
interface: X::INTERFACE,
|
|
143
|
-
};
|
|
144
|
-
&V
|
|
145
|
-
}
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
#[allow(non_snake_case)]
|
|
149
|
-
impl IMyEx for CObject<X> {
|
|
150
|
-
fn A(&self) -> Ref<IMy> {
|
|
151
|
-
self.to_interface().into()
|
|
152
|
-
}
|
|
153
|
-
fn B(&self) -> u32 {
|
|
154
|
-
self.value.p.load(Ordering::Relaxed)
|
|
155
|
-
}
|
|
156
|
-
}
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
mod use_destructor {
|
|
160
|
-
use std::{
|
|
161
|
-
rc::Rc,
|
|
162
|
-
sync::atomic::{AtomicU32, Ordering},
|
|
163
|
-
};
|
|
164
|
-
|
|
165
|
-
use nanocom::Class;
|
|
166
|
-
|
|
167
|
-
use crate::test::{destructor::X, library::IMyEx};
|
|
168
|
-
|
|
169
|
-
#[test]
|
|
170
|
-
fn test() {
|
|
171
|
-
let p = Rc::new(AtomicU32::default());
|
|
172
|
-
{
|
|
173
|
-
assert_eq!(p.load(Ordering::Relaxed), 0);
|
|
174
|
-
let a = X::new(p.clone()).cobject_new();
|
|
175
|
-
assert_eq!(p.load(Ordering::Relaxed), 1);
|
|
176
|
-
let a1 = a.A();
|
|
177
|
-
assert_eq!(p.load(Ordering::Relaxed), 1);
|
|
178
|
-
assert_eq!(a, a1);
|
|
179
|
-
assert_eq!(a.B(), 1);
|
|
180
|
-
{
|
|
181
|
-
let b = X::new(p.clone()).cobject_new();
|
|
182
|
-
assert_eq!(p.load(Ordering::Relaxed), 2);
|
|
183
|
-
assert_ne!(a, b);
|
|
184
|
-
assert_eq!(b.B(), 2);
|
|
185
|
-
}
|
|
186
|
-
assert_eq!(p.load(Ordering::Relaxed), 1);
|
|
187
|
-
}
|
|
188
|
-
assert_eq!(p.load(Ordering::Relaxed), 0);
|
|
189
|
-
}
|
|
190
|
-
}
|
|
191
|
-
}
|