Rename local_data methods/types for less keystrokes
This commit is contained in:
parent
5c3a2e7eeb
commit
cb5b9a477c
|
@ -72,11 +72,11 @@ fn complete_key(_v: @CompletionCb) {}
|
|||
|
||||
/// Bind to the main completion callback
|
||||
pub unsafe fn complete(cb: CompletionCb) {
|
||||
local_data::local_data_set(complete_key, @(cb));
|
||||
local_data::set(complete_key, @(cb));
|
||||
|
||||
extern fn callback(line: *c_char, completions: *()) {
|
||||
unsafe {
|
||||
let cb = *local_data::local_data_get(complete_key)
|
||||
let cb = *local_data::get(complete_key)
|
||||
.get();
|
||||
|
||||
do cb(str::raw::from_c_str(line)) |suggestion| {
|
||||
|
|
|
@ -1204,11 +1204,11 @@ mod big_tests {
|
|||
#[unsafe_destructor]
|
||||
impl<'self> Drop for LVal<'self> {
|
||||
fn drop(&self) {
|
||||
let x = unsafe { local_data::local_data_get(self.key) };
|
||||
let x = unsafe { local_data::get(self.key) };
|
||||
match x {
|
||||
Some(@y) => {
|
||||
unsafe {
|
||||
local_data::local_data_set(self.key, @(y+1));
|
||||
local_data::set(self.key, @(y+1));
|
||||
}
|
||||
}
|
||||
_ => fail!("Expected key to work"),
|
||||
|
|
|
@ -92,7 +92,7 @@ fn task_local_insn_key(_v: @~[&'static str]) {}
|
|||
|
||||
pub fn with_insn_ctxt(blk: &fn(&[&'static str])) {
|
||||
unsafe {
|
||||
let opt = local_data::local_data_get(task_local_insn_key);
|
||||
let opt = local_data::get(task_local_insn_key);
|
||||
if opt.is_some() {
|
||||
blk(*opt.unwrap());
|
||||
}
|
||||
|
@ -101,7 +101,7 @@ pub fn with_insn_ctxt(blk: &fn(&[&'static str])) {
|
|||
|
||||
pub fn init_insn_ctxt() {
|
||||
unsafe {
|
||||
local_data::local_data_set(task_local_insn_key, @~[]);
|
||||
local_data::set(task_local_insn_key, @~[]);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -111,7 +111,7 @@ pub struct _InsnCtxt { _x: () }
|
|||
impl Drop for _InsnCtxt {
|
||||
fn drop(&self) {
|
||||
unsafe {
|
||||
do local_data::local_data_modify(task_local_insn_key) |c| {
|
||||
do local_data::modify(task_local_insn_key) |c| {
|
||||
do c.map_consume |ctx| {
|
||||
let mut ctx = copy *ctx;
|
||||
ctx.pop();
|
||||
|
@ -125,7 +125,7 @@ impl Drop for _InsnCtxt {
|
|||
pub fn push_ctxt(s: &'static str) -> _InsnCtxt {
|
||||
debug!("new InsnCtxt: %s", s);
|
||||
unsafe {
|
||||
do local_data::local_data_modify(task_local_insn_key) |c| {
|
||||
do local_data::modify(task_local_insn_key) |c| {
|
||||
do c.map_consume |ctx| {
|
||||
let mut ctx = copy *ctx;
|
||||
ctx.push(s);
|
||||
|
|
|
@ -241,14 +241,14 @@ impl Drop for CrateContext {
|
|||
|
||||
fn task_local_llcx_key(_v: @ContextRef) {}
|
||||
pub fn task_llcx() -> ContextRef {
|
||||
let opt = unsafe { local_data::local_data_get(task_local_llcx_key) };
|
||||
let opt = unsafe { local_data::get(task_local_llcx_key) };
|
||||
*opt.expect("task-local LLVMContextRef wasn't ever set!")
|
||||
}
|
||||
|
||||
unsafe fn set_task_llcx(c: ContextRef) {
|
||||
local_data::local_data_set(task_local_llcx_key, @c);
|
||||
local_data::set(task_local_llcx_key, @c);
|
||||
}
|
||||
|
||||
unsafe fn unset_task_llcx() {
|
||||
local_data::local_data_pop(task_local_llcx_key);
|
||||
local_data::pop(task_local_llcx_key);
|
||||
}
|
||||
|
|
|
@ -144,7 +144,7 @@ impl Program {
|
|||
let key = ::std::sys::Closure{ code: %? as *(),
|
||||
env: ::std::ptr::null() };
|
||||
let key = ::std::cast::transmute(key);
|
||||
*::std::local_data::local_data_get(key).unwrap()
|
||||
*::std::local_data::get(key).unwrap()
|
||||
};\n", key.code as uint));
|
||||
|
||||
// Using this __tls_map handle, deserialize each variable binding that
|
||||
|
@ -227,7 +227,7 @@ impl Program {
|
|||
map.insert(copy *name, @copy value.data);
|
||||
}
|
||||
unsafe {
|
||||
local_data::local_data_set(tls_key, @map);
|
||||
local_data::set(tls_key, @map);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -236,7 +236,7 @@ impl Program {
|
|||
/// it updates this cache with the new values of each local variable.
|
||||
pub fn consume_cache(&mut self) {
|
||||
let map = unsafe {
|
||||
local_data::local_data_pop(tls_key).expect("tls is empty")
|
||||
local_data::pop(tls_key).expect("tls is empty")
|
||||
};
|
||||
do map.consume |name, value| {
|
||||
match self.local_vars.find_mut(&name) {
|
||||
|
|
|
@ -12,7 +12,6 @@
|
|||
|
||||
#[allow(missing_doc)];
|
||||
|
||||
use local_data::{local_data_pop, local_data_set};
|
||||
use local_data;
|
||||
use prelude::*;
|
||||
|
||||
|
@ -26,14 +25,14 @@ pub struct Handler<T, U> {
|
|||
|
||||
pub struct Condition<'self, T, U> {
|
||||
name: &'static str,
|
||||
key: local_data::LocalDataKey<'self, @Handler<T, U>>
|
||||
key: local_data::Key<'self, @Handler<T, U>>
|
||||
}
|
||||
|
||||
impl<'self, T, U> Condition<'self, T, U> {
|
||||
pub fn trap(&'self self, h: &'self fn(T) -> U) -> Trap<'self, T, U> {
|
||||
unsafe {
|
||||
let p : *RustClosure = ::cast::transmute(&h);
|
||||
let prev = local_data::local_data_get(self.key);
|
||||
let prev = local_data::get(self.key);
|
||||
let h = @Handler { handle: *p, prev: prev };
|
||||
Trap { cond: self, handler: h }
|
||||
}
|
||||
|
@ -46,7 +45,7 @@ impl<'self, T, U> Condition<'self, T, U> {
|
|||
|
||||
pub fn raise_default(&self, t: T, default: &fn() -> U) -> U {
|
||||
unsafe {
|
||||
match local_data_pop(self.key) {
|
||||
match local_data::pop(self.key) {
|
||||
None => {
|
||||
debug!("Condition.raise: found no handler");
|
||||
default()
|
||||
|
@ -55,12 +54,12 @@ impl<'self, T, U> Condition<'self, T, U> {
|
|||
debug!("Condition.raise: found handler");
|
||||
match handler.prev {
|
||||
None => {}
|
||||
Some(hp) => local_data_set(self.key, hp)
|
||||
Some(hp) => local_data::set(self.key, hp)
|
||||
}
|
||||
let handle : &fn(T) -> U =
|
||||
::cast::transmute(handler.handle);
|
||||
let u = handle(t);
|
||||
local_data_set(self.key, handler);
|
||||
local_data::set(self.key, handler);
|
||||
u
|
||||
}
|
||||
}
|
||||
|
@ -78,7 +77,7 @@ impl<'self, T, U> Trap<'self, T, U> {
|
|||
unsafe {
|
||||
let _g = Guard { cond: self.cond };
|
||||
debug!("Trap: pushing handler to TLS");
|
||||
local_data_set(self.cond.key, self.handler);
|
||||
local_data::set(self.cond.key, self.handler);
|
||||
inner()
|
||||
}
|
||||
}
|
||||
|
@ -93,12 +92,12 @@ impl<'self, T, U> Drop for Guard<'self, T, U> {
|
|||
fn drop(&self) {
|
||||
unsafe {
|
||||
debug!("Guard: popping handler from TLS");
|
||||
let curr = local_data_pop(self.cond.key);
|
||||
let curr = local_data::pop(self.cond.key);
|
||||
match curr {
|
||||
None => {}
|
||||
Some(h) => match h.prev {
|
||||
None => {}
|
||||
Some(hp) => local_data_set(self.cond.key, hp)
|
||||
Some(hp) => local_data::set(self.cond.key, hp)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,14 +12,28 @@
|
|||
|
||||
Task local data management
|
||||
|
||||
Allows storing boxes with arbitrary types inside, to be accessed
|
||||
anywhere within a task, keyed by a pointer to a global finaliser
|
||||
function. Useful for dynamic variables, singletons, and interfacing
|
||||
with foreign code with bad callback interfaces.
|
||||
Allows storing boxes with arbitrary types inside, to be accessed anywhere within
|
||||
a task, keyed by a pointer to a global finaliser function. Useful for dynamic
|
||||
variables, singletons, and interfacing with foreign code with bad callback
|
||||
interfaces.
|
||||
|
||||
To use, declare a monomorphic global function at the type to store,
|
||||
and use it as the 'key' when accessing. See the 'tls' tests below for
|
||||
examples.
|
||||
To use, declare a monomorphic (no type parameters) global function at the type
|
||||
to store, and use it as the 'key' when accessing.
|
||||
|
||||
~~~{.rust}
|
||||
use std::local_data;
|
||||
|
||||
fn key_int(_: @int) {}
|
||||
fn key_vector(_: @~[int]) {}
|
||||
|
||||
unsafe {
|
||||
local_data::set(key_int, @3);
|
||||
assert!(local_data::get(key_int) == Some(@3));
|
||||
|
||||
local_data::set(key_vector, @~[3]);
|
||||
assert!(local_data::get(key_vector).unwrap()[0] == 3);
|
||||
}
|
||||
~~~
|
||||
|
||||
Casting 'Arcane Sight' reveals an overwhelming aura of Transmutation
|
||||
magic.
|
||||
|
@ -46,40 +60,37 @@ use task::local_data_priv::{local_get, local_pop, local_set, Handle};
|
|||
*
|
||||
* These two cases aside, the interface is safe.
|
||||
*/
|
||||
pub type LocalDataKey<'self,T> = &'self fn:Copy(v: T);
|
||||
pub type Key<'self,T> = &'self fn:Copy(v: T);
|
||||
|
||||
/**
|
||||
* Remove a task-local data value from the table, returning the
|
||||
* reference that was originally created to insert it.
|
||||
*/
|
||||
pub unsafe fn local_data_pop<T: 'static>(key: LocalDataKey<T>) -> Option<T> {
|
||||
pub unsafe fn pop<T: 'static>(key: Key<T>) -> Option<T> {
|
||||
local_pop(Handle::new(), key)
|
||||
}
|
||||
/**
|
||||
* Retrieve a task-local data value. It will also be kept alive in the
|
||||
* table until explicitly removed.
|
||||
*/
|
||||
pub unsafe fn local_data_get<T: 'static>(key: LocalDataKey<@T>) -> Option<@T> {
|
||||
pub unsafe fn get<T: 'static>(key: Key<@T>) -> Option<@T> {
|
||||
local_get(Handle::new(), key, |loc| loc.map(|&x| *x))
|
||||
}
|
||||
/**
|
||||
* Store a value in task-local data. If this key already has a value,
|
||||
* that value is overwritten (and its destructor is run).
|
||||
*/
|
||||
pub unsafe fn local_data_set<T: 'static>(key: LocalDataKey<@T>, data: @T) {
|
||||
pub unsafe fn set<T: 'static>(key: Key<@T>, data: @T) {
|
||||
local_set(Handle::new(), key, data)
|
||||
}
|
||||
/**
|
||||
* Modify a task-local data value. If the function returns 'None', the
|
||||
* data is removed (and its reference dropped).
|
||||
*/
|
||||
pub unsafe fn local_data_modify<T: 'static>(
|
||||
key: LocalDataKey<@T>,
|
||||
modify_fn: &fn(Option<@T>) -> Option<@T>) {
|
||||
|
||||
let cur = local_data_pop(key);
|
||||
match modify_fn(cur) {
|
||||
Some(next) => { local_data_set(key, next); }
|
||||
pub unsafe fn modify<T: 'static>(key: Key<@T>,
|
||||
f: &fn(Option<@T>) -> Option<@T>) {
|
||||
match f(pop(key)) {
|
||||
Some(next) => { set(key, next); }
|
||||
None => {}
|
||||
}
|
||||
}
|
||||
|
@ -88,19 +99,19 @@ pub unsafe fn local_data_modify<T: 'static>(
|
|||
fn test_tls_multitask() {
|
||||
unsafe {
|
||||
fn my_key(_x: @~str) { }
|
||||
local_data_set(my_key, @~"parent data");
|
||||
set(my_key, @~"parent data");
|
||||
do task::spawn {
|
||||
// TLS shouldn't carry over.
|
||||
assert!(local_data_get(my_key).is_none());
|
||||
local_data_set(my_key, @~"child data");
|
||||
assert!(*(local_data_get(my_key).get()) ==
|
||||
assert!(get(my_key).is_none());
|
||||
set(my_key, @~"child data");
|
||||
assert!(*(get(my_key).get()) ==
|
||||
~"child data");
|
||||
// should be cleaned up for us
|
||||
}
|
||||
// Must work multiple times
|
||||
assert!(*(local_data_get(my_key).get()) == ~"parent data");
|
||||
assert!(*(local_data_get(my_key).get()) == ~"parent data");
|
||||
assert!(*(local_data_get(my_key).get()) == ~"parent data");
|
||||
assert!(*(get(my_key).get()) == ~"parent data");
|
||||
assert!(*(get(my_key).get()) == ~"parent data");
|
||||
assert!(*(get(my_key).get()) == ~"parent data");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -108,9 +119,9 @@ fn test_tls_multitask() {
|
|||
fn test_tls_overwrite() {
|
||||
unsafe {
|
||||
fn my_key(_x: @~str) { }
|
||||
local_data_set(my_key, @~"first data");
|
||||
local_data_set(my_key, @~"next data"); // Shouldn't leak.
|
||||
assert!(*(local_data_get(my_key).get()) == ~"next data");
|
||||
set(my_key, @~"first data");
|
||||
set(my_key, @~"next data"); // Shouldn't leak.
|
||||
assert!(*(get(my_key).get()) == ~"next data");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -118,10 +129,10 @@ fn test_tls_overwrite() {
|
|||
fn test_tls_pop() {
|
||||
unsafe {
|
||||
fn my_key(_x: @~str) { }
|
||||
local_data_set(my_key, @~"weasel");
|
||||
assert!(*(local_data_pop(my_key).get()) == ~"weasel");
|
||||
set(my_key, @~"weasel");
|
||||
assert!(*(pop(my_key).get()) == ~"weasel");
|
||||
// Pop must remove the data from the map.
|
||||
assert!(local_data_pop(my_key).is_none());
|
||||
assert!(pop(my_key).is_none());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -129,20 +140,20 @@ fn test_tls_pop() {
|
|||
fn test_tls_modify() {
|
||||
unsafe {
|
||||
fn my_key(_x: @~str) { }
|
||||
local_data_modify(my_key, |data| {
|
||||
modify(my_key, |data| {
|
||||
match data {
|
||||
Some(@ref val) => fail!("unwelcome value: %s", *val),
|
||||
None => Some(@~"first data")
|
||||
}
|
||||
});
|
||||
local_data_modify(my_key, |data| {
|
||||
modify(my_key, |data| {
|
||||
match data {
|
||||
Some(@~"first data") => Some(@~"next data"),
|
||||
Some(@ref val) => fail!("wrong value: %s", *val),
|
||||
None => fail!("missing value")
|
||||
}
|
||||
});
|
||||
assert!(*(local_data_pop(my_key).get()) == ~"next data");
|
||||
assert!(*(pop(my_key).get()) == ~"next data");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -156,7 +167,7 @@ fn test_tls_crust_automorestack_memorial_bug() {
|
|||
// a stack smaller than 1 MB.
|
||||
fn my_key(_x: @~str) { }
|
||||
do task::spawn {
|
||||
unsafe { local_data_set(my_key, @~"hax"); }
|
||||
unsafe { set(my_key, @~"hax"); }
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -167,9 +178,9 @@ fn test_tls_multiple_types() {
|
|||
fn int_key(_x: @int) { }
|
||||
do task::spawn {
|
||||
unsafe {
|
||||
local_data_set(str_key, @~"string data");
|
||||
local_data_set(box_key, @@());
|
||||
local_data_set(int_key, @42);
|
||||
set(str_key, @~"string data");
|
||||
set(box_key, @@());
|
||||
set(int_key, @42);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -181,12 +192,12 @@ fn test_tls_overwrite_multiple_types() {
|
|||
fn int_key(_x: @int) { }
|
||||
do task::spawn {
|
||||
unsafe {
|
||||
local_data_set(str_key, @~"string data");
|
||||
local_data_set(int_key, @42);
|
||||
set(str_key, @~"string data");
|
||||
set(int_key, @42);
|
||||
// This could cause a segfault if overwriting-destruction is done
|
||||
// with the crazy polymorphic transmute rather than the provided
|
||||
// finaliser.
|
||||
local_data_set(int_key, @31337);
|
||||
set(int_key, @31337);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -199,17 +210,17 @@ fn test_tls_cleanup_on_failure() {
|
|||
fn str_key(_x: @~str) { }
|
||||
fn box_key(_x: @@()) { }
|
||||
fn int_key(_x: @int) { }
|
||||
local_data_set(str_key, @~"parent data");
|
||||
local_data_set(box_key, @@());
|
||||
set(str_key, @~"parent data");
|
||||
set(box_key, @@());
|
||||
do task::spawn {
|
||||
// spawn_linked
|
||||
local_data_set(str_key, @~"string data");
|
||||
local_data_set(box_key, @@());
|
||||
local_data_set(int_key, @42);
|
||||
set(str_key, @~"string data");
|
||||
set(box_key, @@());
|
||||
set(int_key, @42);
|
||||
fail!();
|
||||
}
|
||||
// Not quite nondeterministic.
|
||||
local_data_set(int_key, @31337);
|
||||
set(int_key, @31337);
|
||||
fail!();
|
||||
}
|
||||
}
|
||||
|
@ -219,6 +230,6 @@ fn test_static_pointer() {
|
|||
unsafe {
|
||||
fn key(_x: @&'static int) { }
|
||||
static VALUE: int = 0;
|
||||
local_data_set(key, @&VALUE);
|
||||
set(key, @&VALUE);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1230,7 +1230,7 @@ fn overridden_arg_key(_v: @OverriddenArgs) {}
|
|||
/// `os::set_args` function.
|
||||
pub fn args() -> ~[~str] {
|
||||
unsafe {
|
||||
match local_data::local_data_get(overridden_arg_key) {
|
||||
match local_data::get(overridden_arg_key) {
|
||||
None => real_args(),
|
||||
Some(args) => copy args.val
|
||||
}
|
||||
|
@ -1243,7 +1243,7 @@ pub fn args() -> ~[~str] {
|
|||
pub fn set_args(new_args: ~[~str]) {
|
||||
unsafe {
|
||||
let overridden_args = @OverriddenArgs { val: copy new_args };
|
||||
local_data::local_data_set(overridden_arg_key, overridden_args);
|
||||
local_data::set(overridden_arg_key, overridden_args);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -850,13 +850,13 @@ fn tls_rng_state(_v: @@mut IsaacRng) {}
|
|||
pub fn task_rng() -> @mut IsaacRng {
|
||||
let r : Option<@@mut IsaacRng>;
|
||||
unsafe {
|
||||
r = local_data::local_data_get(tls_rng_state);
|
||||
r = local_data::get(tls_rng_state);
|
||||
}
|
||||
match r {
|
||||
None => {
|
||||
unsafe {
|
||||
let rng = @@mut IsaacRng::new_seeded(seed());
|
||||
local_data::local_data_set(tls_rng_state, rng);
|
||||
local_data::set(tls_rng_state, rng);
|
||||
*rng
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
|
||||
use cast;
|
||||
use libc;
|
||||
use local_data::LocalDataKey;
|
||||
use local_data;
|
||||
use managed::raw::BoxRepr;
|
||||
use prelude::*;
|
||||
use ptr;
|
||||
|
@ -131,7 +131,7 @@ unsafe fn get_local_map(handle: Handle) -> &mut TaskLocalMap {
|
|||
}
|
||||
}
|
||||
|
||||
unsafe fn key_to_key_value<T: 'static>(key: LocalDataKey<T>) -> *libc::c_void {
|
||||
unsafe fn key_to_key_value<T: 'static>(key: local_data::Key<T>) -> *libc::c_void {
|
||||
let pair: sys::Closure = cast::transmute(key);
|
||||
return pair.code as *libc::c_void;
|
||||
}
|
||||
|
@ -155,7 +155,7 @@ unsafe fn transmute_back<'a, T>(data: &'a TLSValue) -> (*BoxRepr, &'a T) {
|
|||
}
|
||||
|
||||
pub unsafe fn local_pop<T: 'static>(handle: Handle,
|
||||
key: LocalDataKey<T>) -> Option<T> {
|
||||
key: local_data::Key<T>) -> Option<T> {
|
||||
// If you've never seen horrendously unsafe code written in rust before,
|
||||
// just feel free to look a bit farther...
|
||||
let map = get_local_map(handle);
|
||||
|
@ -203,7 +203,7 @@ pub unsafe fn local_pop<T: 'static>(handle: Handle,
|
|||
}
|
||||
|
||||
pub unsafe fn local_get<T: 'static, U>(handle: Handle,
|
||||
key: LocalDataKey<T>,
|
||||
key: local_data::Key<T>,
|
||||
f: &fn(Option<&T>) -> U) -> U {
|
||||
// This does in theory take multiple mutable loans on the tls map, but the
|
||||
// references returned are never removed because the map is only increasing
|
||||
|
@ -227,7 +227,7 @@ pub unsafe fn local_get<T: 'static, U>(handle: Handle,
|
|||
|
||||
// FIXME(#7673): This shouldn't require '@', it should use '~'
|
||||
pub unsafe fn local_set<T: 'static>(handle: Handle,
|
||||
key: LocalDataKey<@T>,
|
||||
key: local_data::Key<@T>,
|
||||
data: @T) {
|
||||
let map = get_local_map(handle);
|
||||
let keyval = key_to_key_value(key);
|
||||
|
|
|
@ -698,10 +698,10 @@ pub fn get_sctable() -> @mut SCTable {
|
|||
let sctable_key = (cast::transmute::<(uint, uint),
|
||||
&fn:Copy(v: @@mut SCTable)>(
|
||||
(-4 as uint, 0u)));
|
||||
match local_data::local_data_get(sctable_key) {
|
||||
match local_data::get(sctable_key) {
|
||||
None => {
|
||||
let new_table = @@mut new_sctable_internal();
|
||||
local_data::local_data_set(sctable_key,new_table);
|
||||
local_data::set(sctable_key,new_table);
|
||||
*new_table
|
||||
},
|
||||
Some(intr) => *intr
|
||||
|
|
|
@ -490,11 +490,11 @@ pub fn get_ident_interner() -> @ident_interner {
|
|||
(cast::transmute::<(uint, uint),
|
||||
&fn:Copy(v: @@::parse::token::ident_interner)>(
|
||||
(-3 as uint, 0u)));
|
||||
match local_data::local_data_get(key) {
|
||||
match local_data::get(key) {
|
||||
Some(interner) => *interner,
|
||||
None => {
|
||||
let interner = mk_fresh_ident_interner();
|
||||
local_data::local_data_set(key, @interner);
|
||||
local_data::set(key, @interner);
|
||||
interner
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue