Гость
Форумы / Программирование [игнор отключен] [закрыт для гостей] / Тяпничная ворчалка и бухтелка по поводу Rust и ООП и типобезопасности / 25 сообщений из 146, страница 1 из 6
14.02.2020, 19:01
    #39926880
mayton
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Тяпничная ворчалка и бухтелка по поводу Rust и ООП и типобезопасности
Котаны-братаны!

Здесь я буду ворчать и бухтеть про Rust.

Впрочем иногда и буду хвалить. Даже больше буду хвалить. Возможно в части ООП и типобезопасности.

Какие вопросы хотелост проговорить (Primary Goals).
- Типы данных. Строгость. ООП.
- Строки
- Коллекции
- Управление памятью (самая вкуснятина)
- Мультипоточка

Secondary Goals
- Репликатор. Если дойдут руки.
- Дрова к БД ORA/PG/Mysql/MSSQL/SQLite.
- Cargo. Репозитарии. Сообщества. Инфо-каналы.

Топики тематически связные (ИМХО).
https://www.sql.ru/forum/1173809/tyapnichnyy-benchmark-cpu-part-1 (здесь впервые потрогали его руками в сравнении)
https://www.sql.ru/forum/1303834/tyapnichnaya-budushhaya-multipotochnost

Просто линки по теме.
https://rust-lang.org
https://github.com/rust-lang

Что мы говорить не будем.

Мы не будем обсуждать мою персону. Это понятно. Нарушение правил как-бе.
Меня тут вообще нету. Я просто как говорящее радио.

Мы не будем обсуждать причины возникновения этого топика. Он возник и возник. И хрен с ним.
...
Рейтинг: 0 / 0
14.02.2020, 23:30
    #39926939
mayton
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Тяпничная ворчалка и бухтелка по поводу Rust и ООП и типобезопасности
Ворчалка типо-данных.

Примитивы. Целые i8, i16, i32, i64, i128 знаковые. Тоже самое с буквочкой u - знаковые.
Строки - почему-то инициализируются через спец-метод.

Самодостаточный код который собирается и работает.

Такой себе сферический ордер на покупку 15 акций IBM.

Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
use std::fs::File;
use std::io::prelude::*;

pub struct Order {
  symbol: String,
  shares: u16,
  price: u32 
}

impl Order {
  fn to_string(&self) -> String {
     return format!("Order: {}/{}@{}", self.symbol, self.shares, self.price);
  }
}

fn main() {
    let order = Order { symbol: String::from("IBM"), shares: 15, price: 229 };
    
}



Я завтыкал восклицательный знаке после format (!) и получил ошибку сборки. Что-то с макросами
надо почитать про его роль.

Интересно что туловище объекта существует отдельно от декларации его методов.
В этом есть как-бы и ООП и одновременно не-ООП. Дуализм.
...
Рейтинг: 0 / 0
14.02.2020, 23:35
    #39926942
mayton
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Тяпничная ворчалка и бухтелка по поводу Rust и ООП и типобезопасности
После let - идут константы. Если нужна перменная - добавляют mut.

Код: java
1.
2.
3.
    let mut x = 5;
    println!("The value of x is: {}", x);
    x = 6;



Хм.. интересно как они поступают со ссылками на данные которые мутируют.
...
Рейтинг: 0 / 0
14.02.2020, 23:38
    #39926943
mayton
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Тяпничная ворчалка и бухтелка по поводу Rust и ООП и типобезопасности
А вот еще интереснее. Shadowing. Не могу перевести. Затенение что-ли.

Код: sql
1.
2.
3.
    let x = 5;
    let x = x + 1;
    let x = x * 2;


Здесь получается декларируются 3 константы x каждая последующая из которых "затеняет" предыдущую.
...
Рейтинг: 0 / 0
14.02.2020, 23:42
    #39926944
mayton
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Тяпничная ворчалка и бухтелка по поводу Rust и ООП и типобезопасности
А вот интересная штучка. Tuples. Я всегда переводил как "кортежи". Не знаю правильно или нет.
Rust различает скалярные и compound типы. Вот кортеж относится ко вторым.

Инициализация кортежа. По нашему это анонимный класс из (int, double, byte) типов.
Код: sql
1.
let tup: (i32, f64, u8) = (500, 6.4, 1);
...
Рейтинг: 0 / 0
14.02.2020, 23:47
    #39926946
mayton
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Тяпничная ворчалка и бухтелка по поводу Rust и ООП и типобезопасности
С массивами вобщем ничего интересного.
Код: sql
1.
let a = [1, 2, 3, 4, 5];


Но контроль за вылет за границы - присутствует.

Даже в режиме релиза. Я собрал cargo build --release и получил стандартную ошибку проверки диапазона массива.
...
Рейтинг: 0 / 0
14.02.2020, 23:56
    #39926948
mayton
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Тяпничная ворчалка и бухтелка по поводу Rust и ООП и типобезопасности
А вот штука похожая на тернарную операцию C++/Java

Код: javascript
1.
2.
3.
4.
5.
6.
    let condition = true;
    let number = if condition {
        5
    } else {
        6
    };
...
Рейтинг: 0 / 0
15.02.2020, 00:04
    #39926950
mayton
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Тяпничная ворчалка и бухтелка по поводу Rust и ООП и типобезопасности
А вот еще интересная тема.

Функция возвращает "пару"
Код: sql
1.
2.
3.
fn parse_money(input: &str) -> (i32, String) {
   return (145, String::from("$"));
}


Удобная штука.
...
Рейтинг: 0 / 0
15.02.2020, 00:09
    #39926951
mayton
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Тяпничная ворчалка и бухтелка по поводу Rust и ООП и типобезопасности
Далее. Пойдет Borrowing and Ownership.
Относится к контролю за памятью и ссылками.
Наверное отложу на завтра.
...
Рейтинг: 0 / 0
15.02.2020, 00:11
    #39926952
ViPRos
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Тяпничная ворчалка и бухтелка по поводу Rust и ООП и типобезопасности
mayton,

В Rust главное понять работу с памятью (владение, заимствование,...), остальное не существенно.
...
Рейтинг: 0 / 0
15.02.2020, 09:38
    #39926977
mayton
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Тяпничная ворчалка и бухтелка по поводу Rust и ООП и типобезопасности
Надеюсь что это будет наиболее мясная часть меню.
...
Рейтинг: 0 / 0
15.02.2020, 12:16
    #39926992
ViPRos
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Тяпничная ворчалка и бухтелка по поводу Rust и ООП и типобезопасности
mayton,

А там больше ничего и нет
...
Рейтинг: 0 / 0
15.02.2020, 16:04
    #39927026
полудух
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Тяпничная ворчалка и бухтелка по поводу Rust и ООП и типобезопасности
mayton , ты же знаешь C/C++, чем он тебя не устраивает?
зачем плодить зоопарк языков в голове?

mayton
Но контроль за вылет за границы - присутствует.

не бесплатно же.
...
Рейтинг: 0 / 0
15.02.2020, 16:37
    #39927031
mayton
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Тяпничная ворчалка и бухтелка по поводу Rust и ООП и типобезопасности
Есть интерес посмотреть на модель памяти Rust. Принять к сведению best practices.
...
Рейтинг: 0 / 0
15.02.2020, 16:53
    #39927032
mayton
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Тяпничная ворчалка и бухтелка по поводу Rust и ООП и типобезопасности
полудух, по поводу выхода за границы массива. Да. Думаю есть такой пункт.
Не бесплатно. Но высокий перформанс работы с массивами бывает редко.
Я помню я разрабатывал в студенчестве алгортмы машинной графики.
Например заштриховать полигон из пикселов в SVGA-режиме. Там я использовал
прямой доступ к памяти.

Это всё - достаточно low-level функций и таковые обычно в прикладном коде
не используются. В прикладно (бизнес-коде) обычно мы не работаем с байтами
или словами или двойными словами а с сущностями (Entity). Они - довольно
крупные. И редко лежат в массивах. Чаще под покрытием итератора или стрима
или еще бох знает каких абстракций.

Вобщем .. индексый доступ - это достаточно low-level. А Rust насколько я понимаю
создавался как язык безопасный - поэтому его поведение при выскакивании
за границы array предсказуемо. В данном примере - у меня код не собрался.
Компиллятор доказал что он - неработоспособен. Как глубоко (насколько ходов вперед)
видит компиллятор - мы в топике проверим.

Код: sql
1.
2.
3.
4.
fn main() {

    let a:[u32; 3] = [1,2,3];
    let y = a[3];


Код: sql
1.
2.
3.
4.
error: index out of bounds: the len is 3 but the index is 3
  --> src/main.rs:20:13
   |
20 |     let y = a[3];
...
Рейтинг: 0 / 0
15.02.2020, 18:05
    #39927041
полудух
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Тяпничная ворчалка и бухтелка по поводу Rust и ООП и типобезопасности
кому нужны эти массивы, когда есть <vector>
и <array> (модуль, где всё учтено)
...
Рейтинг: 0 / 0
15.02.2020, 18:10
    #39927042
полудух
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Тяпничная ворчалка и бухтелка по поводу Rust и ООП и типобезопасности
mayton
Но высокий перформанс работы с массивами бывает редко.

по-моему ты неправильно относишься к массивам.
это же map-to-hardware
массив = ячейки памяти, 1 в 1
в C/C++, а вот в остальных языках - нет
в ПХП там вообще дикие абстракции, такие, что массив занимает в X раз больше размер
там и int = 40 байт
а вот в C/C++ это именно память и есть, и какой такой "высокий перформанс" может быть выше этого - загадка.
...
Рейтинг: 0 / 0
15.02.2020, 18:34
    #39927045
mayton
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Тяпничная ворчалка и бухтелка по поводу Rust и ООП и типобезопасности
полудух
кому нужны эти массивы, когда есть <vector>
и <array> (модуль, где всё учтено)

Ценное замечание. До классов коллекций я еще не дошел. Дойдем здесь https://doc.rust-lang.org/book/ch08-01-vectors.html

Но я хочу закрыть тему работы с массивами тем что UB не удалось получить.
Либо не будет компилляции. Либо будет зафиксирована ошибка. Об ошибках - тоже чуть позже.
...
Рейтинг: 0 / 0
15.02.2020, 18:48
    #39927046
mayton
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Тяпничная ворчалка и бухтелка по поводу Rust и ООП и типобезопасности
На сегодня - тема Ownership, Borrowing.
Я попробую перевести как Владение и Одалживание в рамках данной технической доки
Но ради чистоты терминологии я их оставлю as is.

https://doc.rust-lang.org/book/ch04-00-understanding-ownership.html

Насколько я понял.

Владение (Ownership) - это наиболее уникальная фича Rust, которая позволяет создавать гарантии
безопасности памяти без необходимости Garbage Collector. Поэтому очень важно понять как ownership
работает в Rust.
...
Рейтинг: 0 / 0
15.02.2020, 18:57
    #39927049
mayton
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Тяпничная ворчалка и бухтелка по поводу Rust и ООП и типобезопасности
Далее по тексту. Я двигаюсь длинными прыжками и буду постить только наиболе значимые фрагменты КМК.

Правила Ownership .

  • Каждое значение (value) в Rust имеет переменную которая зовётся владельцем (owner).
  • Может существовать только 1 owner в один момент времени.
  • Когда owner покидает scope - значение удаляется (When the owner goes out of scope, the value will be dropped).
...
Рейтинг: 0 / 0
15.02.2020, 19:00
    #39927050
mayton
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Тяпничная ворчалка и бухтелка по поводу Rust и ООП и типобезопасности
Работа со scope знакома всем по C++. Я не буду пересказывать. Просто фрагмент кода с каментами.


Код: sql
1.
2.
3.
4.
5.
{                      // s is not valid here, it’s not yet declared
    let s = "hello";   // s is valid from this point forward

    // do stuff with s
}                      // this scope is now over, and s is no longer valid
...
Рейтинг: 0 / 0
15.02.2020, 20:25
    #39927059
mayton
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Тяпничная ворчалка и бухтелка по поводу Rust и ООП и типобезопасности
Хм.. забавно crate - переводится как клетка или деревянный ящик. Смысловой паревод я пока не улавливаю.
Есть варианты. Модуль. Пакет. Зависимость. Единица публикации. Пока не определился.

Впервые вроде как здесь упоминается https://doc.rust-lang.org/cargo/reference/publishing.html
...
Рейтинг: 0 / 0
15.02.2020, 20:48
    #39927061
mayton
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Тяпничная ворчалка и бухтелка по поводу Rust и ООП и типобезопасности
Щас на пару часиков вернёмся в родительскую задачу.
https://www.sql.ru/forum/1173809/tyapnichnyy-benchmark-cpu-part-1

Там как раз сборщик упал по причине каких-то эволюций пакетов.

Код: javascript
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
71.
72.
73.
74.
75.
76.
77.
78.
79.
80.
81.
82.
83.
84.
85.
86.
87.
88.
89.
90.
91.
92.
93.
94.
95.
96.
97.
98.
99.
100.
101.
102.
103.
104.
105.
106.
107.
108.
109.
110.
111.
112.
113.
114.
115.
116.
117.
118.
119.
120.
121.
122.
123.
124.
125.
126.
127.
128.
129.
130.
131.
132.
133.
134.
135.
136.
137.
138.
139.
140.
141.
142.
143.
144.
145.
146.
147.
148.
149.
150.
151.
152.
153.
154.
155.
156.
157.
158.
159.
160.
161.
162.
163.
164.
165.
166.
167.
168.
169.
170.
171.
172.
173.
174.
175.
176.
177.
178.
179.
180.
181.
182.
183.
184.
185.
186.
187.
188.
189.
190.
extern crate num;
extern crate rand;
extern crate time;

use rand::Rng;
use rand::ThreadRng;
use rand::prelude::*;

use std::env;
use std::error::Error;
use std::fs::File;
use std::io::Write;
use std::ops::*;


const WIDTH: i32 = 512;
const HEIGHT: i32 = 512;


#[derive(Copy)]
struct Vector {
	x: f64,
	y: f64,
	z: f64
}

impl Clone for Vector {
	fn clone(&self) -> Self {
		Vector { x: self.x, y: self.y, z: self.z }
	}
}

impl Add for Vector {
    type Output = Vector;

    fn add(self, rhs: Vector) -> Vector {
        Vector { x: self.x + rhs.x, y: self.y + rhs.y, z: self.z + rhs.z }
    }
}

impl Mul<f64> for Vector {
    type Output = Vector;

    fn mul(self: Vector, rhs: f64) -> Vector {
        Vector {x: self.x * rhs, y: self.y * rhs, z: self.z * rhs}
    }
}

impl Rem for Vector {
    type Output = f64;

    fn rem(self, rhs: Vector) -> f64 {
        self.x * rhs.x + self.y * rhs.y + self.z * rhs.z
    }
}

impl BitXor for Vector {
    type Output = Vector;

    fn bitxor(self, rhs: Vector) -> Vector {
        Vector {x: self.y * rhs.z - self.z * rhs.y, y: self.z * rhs.x - self.x * rhs.z, z: self.x * rhs.y - self.y * rhs.x}
    }
}

impl Not for Vector {
    type Output = Vector;

    fn not(self: Vector) -> Vector {
        self * (1.0 / (self % self).sqrt())
    }
}

static G:[i32; 9] = [
	0x0003C712,  // 00111100011100010010 
	0x00044814,  // 01000100100000010100
	0x00044818,  // 01000100100000011000
	0x0003CF94,  // 00111100111110010100
	0x00004892,  // 00000100100010010010
	0x00004891,  // 00000100100010010001
	0x00038710,  // 00111000011100010000
	0x00000010,  // 00000000000000010000
	0x00000010,  // 00000000000000010000
];

fn tracer(o: Vector, d: Vector, t: &mut f64, n:&mut Vector) -> i32 {
	*t = 1e9;
	let mut m: i32 = 0;
	let p: f64 = -o.z / d.z;
	if 0.01 < p {
		*t = p;
		*n = Vector {x: 0.0, y: 0.0, z: 1.0};
		m = 1;
	}
	let mut k: i32 = 20;
	while k != 0 {
		k = k - 1;
		let mut j: usize = 9;
		while j != 0 {
			j = j - 1;
			if (G[j] & 1 << k) != 0 {
				let p: Vector = o + Vector {x: -k as f64, y: 0.0, z: -(j as f64) - 4.0};
				let b = p % d; 
                                let c = p % p - 1.0; 
                                let q = b * b - c;
				if q > 0.0 {
					let s = -b - q.sqrt();
					if s < *t && s > 0.01 {
						*t = s; 
						*n = !(p + ((d) * (*t)));
						m = 2;
					}
				}
			}
		}
	}
	return m;
}

fn sampler(o: Vector, d: Vector, rng: &mut ThreadRng) -> Vector {
	let mut t: f64 = 0.0;
	let mut n: Vector = Vector {x: 0.0, y: 0.0, z: 0.0};
	let m: i32 = tracer(o, d, &mut t, &mut n);
	if m == 0 {
		return Vector {x: 0.7, y: 0.6, z: 1.0} * num::pow(1.0 - d.z, 4);
	}
	let mut h: Vector = o + (d * t);
        let l: Vector = !(Vector {x: 9.0 + rng.gen::<f64>(), y: 9.0 + rng.gen::<f64>(), z: 16.0} + (h * -1.0) );
        let r: Vector = d + (n * ((n % (d)) * -2.0));
	let mut b: f64 = l % n;
	if b < 0.0 || tracer(h, l, &mut t, &mut n) != 0 {
		b = 0.0;
	}
	let p: f64 = num::pow((l % r) * (if b > 0.0 {1.0} else {0.0}), 99);
	if (m & 1) != 0 {
		h = h * 0.2;
		return (
			if ((h.x.ceil() + h.y.ceil()) as i32) & 1 != 0 {
				Vector {x: 3.0, y: 1.0, z: 1.0}
			}
			else {
				Vector {x: 3.0, y: 3.0, z: 3.0}
			}
			) *
			(b * 0.2 + 0.1);
	}
	return Vector {x: p, y: p, z: p} + (sampler(h, r, rng) * 0.5);
}

fn main() {
	let mut rng: ThreadRng = thread_rng();
	let args: Vec<String> = env::args().collect();
	if args.len() == 1 {
		panic!("\n\nUsage: card-raytracer <filename>.ppm\n");
	}
	let start = time::precise_time_s();
	let mut out = match File::create(&args[1]) {
        	Err(why) => panic!("couldn't create {}: {}",
        			args[1],
        			Error::description(&why)),
	        Ok(file) => file,
	};
	write!(out,"P6 {} {} 255 ", WIDTH, HEIGHT).unwrap();
	let g: Vector = !(Vector {x: -6.0, y: -16.0, z: 0.0});
	let a: Vector = !(Vector {x: 0.0, y: 0.0, z: 1.0} ^ g) * 0.002;
	let b: Vector = !(g ^ a) * 0.002;
	let c: Vector = ((a + b) * -256.0) + g;
	let mut y: i32 = HEIGHT;
	while y != 0 {
		y = y - 1;
		let mut x: i32 = WIDTH;
		while x != 0 {
			x = x - 1;
			let mut p = Vector {x: 13.0, y: 13.0, z: 13.0};
			let mut r: i32 = 64;
			while r != 0 {
				r = r - 1;
				let t: Vector = (a * (rng.gen::<f64>() - 0.5) * 99.0) + (b * (rng.gen::<f64>() - 0.5) * 99.0);
				p = sampler(Vector {x: 17.0, y: 16.0, z: 8.0} + t, 
					!(t * -1.0 + (a * (rng.gen::<f64>() + x as f64) + b * (y as f64 + rng.gen::<f64>()) + c) * 16.0), 
					&mut rng) * 3.5 + p;
			} 
			match out.write_all(&[p.x as u8, p.y as u8, p.z as u8]) {
				Err(why) => panic!("couldn't write to {}: {}", args[1],
					Error::description(&why)),
        			Ok(_) => {},
			}
		}
	}
	println!("Time elapsed: {} s", time::precise_time_s() - start);
}




Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
   Compiling card-raytracer v0.1.0 (/home/mayton/git/CardRaytracerBenchmark/rust)
error[E0432]: unresolved import `rand::ThreadRng`
 --> src/card-raytracer.rs:6:5
  |
6 | use rand::ThreadRng;
  |     ^^^^^^---------
  |     |     |
  |     |     help: a similar name exists in the module: `thread_rng`
  |     no `ThreadRng` in the root

error: aborting due to previous error

For more information about this error, try `rustc --explain E0432`.
error: could not compile `card-raytracer`.

To learn more, run the command again with --verbose.



Хм... тут надо понять что это за пакет. И зачем он нужен. Предположительно - это генератор случайных чисел.
Попробую пофиксить.
...
Рейтинг: 0 / 0
15.02.2020, 21:15
    #39927064
mayton
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Тяпничная ворчалка и бухтелка по поводу Rust и ООП и типобезопасности
Просто позакоментарил и компиляция прошла.

Код: sql
1.
2.
3.
4.
5.
6.
7.
-use rand::Rng;
-use rand::ThreadRng;
+//use rand::Rng;
+//use rand::ThreadRng;
 use rand::prelude::*;
 
 use std::env;



15 секунд на рендеринг картинки на стареньком Intel Core i3. Это в 1 поток.
Шикарно. Щас переползу на рабочую станцию посмотрю как сработает в AMD/Ryzen-5.

Заодно обновим статистику по бенчмаркам.
...
Рейтинг: 0 / 0
15.02.2020, 22:09
    #39927068
mayton
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Тяпничная ворчалка и бухтелка по поводу Rust и ООП и типобезопасности
8 секунд на AMD.

Я ничего не понимаю. Мы перегнали "C" в 2 раза. Я щас просто сиду перепроверяю цифры.
Конфигурация не менялась с год.

Патчился Линукс и патчился сам Rust c зависимостями.
...
Рейтинг: 0 / 0
Форумы / Программирование [игнор отключен] [закрыт для гостей] / Тяпничная ворчалка и бухтелка по поводу Rust и ООП и типобезопасности / 25 сообщений из 146, страница 1 из 6
Целевая тема:
Создать новую тему:
Автор:
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]