Перейти к содержимому

Сколько значений может иметь переменная типа logical

  • автор:

SQL — Урок 2. Типы данных

Этот урок носит больше теоретический характер, но пропустить его нельзя. В дальнейшем вы сможете возвращаться к нему, как к справочному уроку, сейчас же просто ознакомьтесь. В прошлом уроке говорилось, что MySQL поддерживает числовые, строковые, календарные данные и данные типа NULL. Рассмотрим их по очереди.

Числовые типы данных

Тип данных Объем памяти Диапазон Описание
TINYINT (M) 1 байт от -128 до 127 или от 0 до 255 Целое число. Может быть объявлено положительным с помощью ключевого слова UNSIGNED, тогда элементам столбца нельзя будет присвоить отрицательное значение. Необязательный параметр М — количество отводимых под число символов. Необязательный атрибут ZEROFILL позволяет свободные позиции по умолчанию заполнить нулями.

TINYINT — хранит любое число в диапазоне от -128 до 127.

TINYINT UNSIGNED — хранит любое число в диапазоне от 0 до 255.

TINYINT (2) — предполагается, что значения будут двузначными, но по факту будет хранить и трехзначные.

SMALLINT — хранит любое число в диапазоне от -32768 до 32767.

SMALLINT UNSIGNED — хранит любое число в диапазоне от 0 до 65535.

SMALLINT (4) — предполагается, что значения будут четырехзначные, но по факту будет хранить и пятизначные.

MEDIUMINT — хранит любое число в диапазоне от -8388608 до 8388608.

MEDIUMINT UNSIGNED — хранит любое число в диапазоне от 0 до 16777215.

MEDIUMINT (4) — предполагается, что значения будут четырехзначные, но по факту будет хранить и семизначные.

INT — хранит любое число в диапазоне от -2147683648 до 2147683648.

INT UNSIGNED — хранит любое число в диапазоне от 0 до 4294967295.

INT (4) — предполагается, что значения будут четырехзначные, но по факту будет хранить максимально возможные.

BIGINT — хранит любое число в диапазоне от -2 63 до 2 63 -1.

BIGINT UNSIGNED — хранит любое число в диапазоне от 0 до 2 64 .

BIGINT (4) — предполагается, что значения будут четырехзначные, но по факту будет хранить максимально возможные.

Необходимо понимать, чем больше диапазон значений у типа данных, тем больше памяти он занимает. Поэтому, если предполагается, что значения в столбце не будут превышать 100, то используйте тип TINYINT. Если при этом все значения будут положительными, то используйте атрибут UNSIGNED. Правильный выбор типа данных позволяет сэкономить место для хранения этих данных.

Строковые типы данных

Тип данных Объем памяти Максимальный размер Описание
CHAR (M) M символов М символов Позволяет хранить строку фиксированной длины М. Значение М — от 0 до 65535.

Календарные типы данных

Тип данных Объем памяти Диапазон Описание
DATE 3 байта от ‘1000-01-01’ до ‘9999-12-31’ Предназначен для хранения даты. В качестве первого значения указывается год в формате «YYYY», через дефис — месяц в формате «ММ», а затем день в формате «DD». В качестве разделителя может выступать не только дефис, а любой символ отличный от цифры.
TIME 3 байта от ‘-838:59:59’ до ‘838:59:59’ Предназначен для хранения времени суток. Значение вводится и хранится в привычном формате — hh:mm:ss, где hh — часы, mm — минуты, ss — секунды. В качестве разделителя может выступать любой символ отличный от цифры.
DATATIME 8 байт от ‘1000-01-01 00:00:00’ до ‘9999-12-31 23:59:59’ Предназначен для хранения и даты и времени суток. Значение вводится и хранится в формате — YYYY-MM-DD hh:mm:ss. В качестве разделителей могут выступать любые символы отличные от цифры.
TIMESTAMP 4 байта от ‘1970-01-01 00:00:00’ до ‘2037-12-31 23:59:59’ Предназначен для хранения даты и времени суток в виде количества секунд, прошедших с полуночи 1 января 1970 года (начало эпохи UNIX).
YEAR (M) 1 байт от 1970 до 2069 для М=2 и от 1901 до 2155 для М=4 Предназначен для хранения года. М — задает формат года. Например, YEAR (2) — 70, а YEAR (4) — 1970. Если параметр М не указан, то по умолчанию считается, что он равен 4.

Тип данных NULL

Вообще-то это лишь условно можно назвать типом данных. По сути это скорее указатель возможности отсутствия значения. Например, когда вы регистрируетесь на каком-либо сайте, вам предлагается заполнить форму, в которой присутствуют, как обязательные, так и необязательные поля. Понятно, что регистрация пользователя невозможна без указания логина и пароля, а вот дату рождения и пол пользователь может указать по желанию. Для того, чтобы хранить такую информацию в БД и используют два значения:

NOT NULL (значение не может отсутствовать) для полей логин и пароль,

NULL (значение может отсутствовать) для полей дата рождения и пол.

По умолчанию всем столбцам присваивается тип NOT NULL, поэтому его можно явно не указывать.

create table users (login varchar(20), password varchar(15), sex enum(‘man’, ‘woman’) NULL, date_birth date NULL);

Таким образом, мы создаем таблицу с 4 столбцами: логин (не более 20 символов) обязательное, пароль (не более 15 символов) обязательное, пол (мужской или женский) не обязательное, дата рождения (тип дата) необязательное.

Все, на этом урок, посвященный типам данных, закончен. У вас, возможно, остались вопросы, но они исчезнут по мере освоения дальнейшего материала, т.к. на практике все становится более понятно, чем в теории.

Научись программировать на Python прямо сейчас!

  • Научись программировать на Python прямо сейчас
  • Бесплатный курс

Если этот сайт оказался вам полезен, пожалуйста, посмотрите другие наши статьи и разделы.

Сколько значений может иметь переменная типа logical

Как и во многих языках программирования, в C# есть своя система типов данных, которая используется для создания переменных. Тип данных определяет внутреннее представление данных, множество значений, которые может принимать объект, а также допустимые действия, которые можно применять над объектом.

В языке C# есть следующие базовые типы данных:

    bool : хранит значение true или false (логические литералы). Представлен системным типом System.Boolean

bool alive = true; bool isDead = false;
byte bit1 = 1; byte bit2 = 102;
sbyte bit1 = -101; sbyte bit2 = 102;
short n1 = 1; short n2 = 102;
ushort n1 = 1; ushort n2 = 102;
int a = 10; int b = 0b101; // бинарная форма b =5 int c = 0xFF; // шестнадцатеричная форма c = 255
uint a = 10; uint b = 0b101; uint c = 0xFF;
long a = -10; long b = 0b101; long c = 0xFF;
ulong a = 10; ulong b = 0b101; ulong c = 0xFF;
char a = 'A'; char b = '\x5A'; char c = '\u0420';
string hello = "Hello"; string word = "world";
object a = 22; object b = 3.14; object c = "hello code";

Например, определим несколько переменных разных типов и выведем их значения на консоль:

string name = "Tom"; int age = 33; bool isEmployed = false; double weight = 78.65; Console.WriteLine($"Имя: "); Console.WriteLine($"Возраст: "); Console.WriteLine($"Вес: "); Console.WriteLine($"Работает: ");

Для вывода данных на консоль здесь применяется интерполяция: перед строкой ставится знак $ и после этого мы можем вводить в строку в фигурных скобках значения переменных. Консольный вывод программы:

Имя: Tom Возраст: 33 Вес: 78,65 Работает: False

Использование суффиксов

При присвоении значений надо иметь в виду следующую тонкость: все вещественные литералы (дробные числа) рассматриваются как значения типа double . И чтобы указать, что дробное число представляет тип float или тип decimal , необходимо к литералу добавлять суффикс: F/f — для float и M/m — для decimal.

float a = 3.14F; float b = 30.6f; decimal c = 1005.8M; decimal d = 334.8m;

Подобным образом все целочисленные литералы рассматриваются как значения типа int . Чтобы явным образом указать, что целочисленный литерал представляет значение типа uint, надо использовать суффикс U/u , для типа long — суффикс L/l , а для типа ulong — суффикс UL/ul :

uint a = 10U; long b = 20L; ulong c = 30UL;

Использование системных типов

Выше при перечислении всех базовых типов данных для каждого упоминался системный тип. Потому что название встроенного типа по сути представляет собой сокращенное обозначение системного типа. Например, следующие переменные будут эквивалентны по типу:

int a = 4; System.Int32 b = 4;

Неявная типизация

Ранее мы явным образом указывали тип переменных, например, int x; . И компилятор при запуске уже знал, что x хранит целочисленное значение.

Однако мы можем использовать и модель неявной типизации:

var hello = "Hell to World"; var c = 20;

Для неявной типизации вместо названия типа данных используется ключевое слово var . Затем уже при компиляции компилятор сам выводит тип данных исходя из присвоенного значения. Так как по умолчанию все целочисленные значения рассматриваются как значения типа int , то поэтому в итоге переменная c будет иметь тип int . Аналогично переменной hello присваивается строка, поэтому эта переменная будет иметь тип string

Эти переменные подобны обычным, однако они имеют некоторые ограничения.

Во-первых, мы не можем сначала объявить неявно типизируемую переменную, а затем инициализировать:

// этот код работает int a; a = 20; // этот код не работает var c; c= 20;

Во-вторых, мы не можем указать в качестве значения неявно типизируемой переменной null :

// этот код не работает var c=null;

Так как значение null, то компилятор не сможет вывести тип данных.

Типы данных в моделях данных

В модели данных у каждого столбца есть связанный тип данных, который определяет тип данных, которые могут в нем быть: целые числа, десятичных числа, текст, денежные данные, даты и время и так далее. Тип данных также определяет, какие виды операций можно делать со столбцом и сколько памяти требуется для хранения значений в столбце.

Если вы используете надстройки Power Pivot, вы можете изменить тип данных столбца. Это может потребоваться сделать, если столбец даты был импортирован как строка, но он должен быть другим. Дополнительные сведения см. в статье Настройка типа данных столбца вPower Pivot.

В этой статье

  • Сводка типов данных
    • Тип данных таблицы
    • Таблица неявных преобразований данных
      • С дополнением (+)
      • Вычитание (-)
      • Умножение (*)
      • Деление (/)
      • Операторы сравнения

      Сводка типов данных

      В таблице ниже перечислены типы данных, поддерживаемые в модели данных. При импорте данных или использовании значения в формуле, даже если исходный источник данных содержит другой тип данных, данные преобразуются в один из этих типов данных. Значения, полученные из формул, также используют эти типы данных.

      Тип данных в Excel

      Тип данных в DAX

      64-битное (восемьбайт) значение 1, 2

      Числа, не заметимые числа. Целые числа могут быть положительными или отрицательными, но должны быть целыми числами в период от -9 223 372 036 854 775 808 (-2^63) и 9 223 372 036 854 775 807 (2^63-1).

      64-битное (восемьбайт) реальное число 1, 2

      Реальные числа — это числа, которые могут иметь десятичных знаках. Реальные числа охватывают широкий диапазон значений:

      Отрицательные значения от -1,79E +308 до -2,23E-308

      Положительные значения от 2,23E -308 до 1,79E + 308

      Однако количество значимых разрядов ограничено 15 десятичной частью.

      Значение True или False.

      Строка данных символов Юникода. Могут быть строками, числами или датами, представленными в текстовом формате.

      Максимальная длина строки составляет 268 435 456 символов Юникода (256 мега знаков) или 536 870 912 bytes.

      Функции даты и времени

      Даты и время в принятом представлении даты и времени.

      Допустимые даты — это все даты после 1 января 1900 г.

      Тип данных «Валюта» позволяет получить значения от -922 337 203 685 477,5808 до 922 337 203 685 477,5807 с точностью до четырех десятичных разрядов.

      Пустое — это тип данных в DAX, который представляет и заменяет SQL NULL. Вы можете создать пустое с помощью функции BLANK и проверить пустые функциональность с помощью логической функции ЕПУСТО.

      1 формулы DAX не поддерживают типы данных, меньшие, чем перечисленные в таблице.

      2 Если попытаться импортировать данные с очень большими числными значениями, импорт может привести к ошибке со следующей ошибкой:

      Ошибка базы данных в памяти: столбец таблицы <> содержит значение «1,7976931348623157e+308», которое не поддерживается. Операция была отменена.

      Эта ошибка возникает потому, Power Pivot использует это значение для представления NULL. Значения в следующем списке являются синонимами значения NULL:

      Удалите значение из данных и попробуйте импортировать снова.

      Тип данных таблицы

      DAX использует тип данных таблицы во многих функциях, таких как агрегаты и вычисления, основанные на аналитике времени. Для некоторых функций требуется ссылка на таблицу; другие функции возвращают таблицу, которую затем можно использовать в качестве входных данных для других функций. В некоторых функциях, которые требуют в качестве входных данных таблицу, можно указать выражение, которое высмеется в таблицу; для некоторых функций требуется ссылка на базовую таблицу. Сведения о требованиях к определенным функциям см. в справочнике по функциям DAX.

      Неявное и явное преобразование типов данных в формулах DAX

      У каждой функции DAX есть определенные требования к типам данных, которые используются в качестве входных и выходных данных. Например, для одних функций одни аргументы и даты требуются в несколько разных. для других функций требуется текст или таблицы.

      Если данные в столбце, который вы указываете в качестве аргумента, несовместимы с типом данных, требуемым функцией, DAX во многих случаях возвращает ошибку. Однако DAX по возможности попытается неявно преобразовать данные в необходимый тип данных. Например:

      • Вы можете ввести дату в виде строки, и DAX разменит строку и попытается отвести ее как один из форматов Windows даты и времени.
      • Вы можете добавить true+ 1 и получить результат 2, так как истина неявно преобразуется в число 1 и выполняется операция 1+1.
      • При добавлении значений в двух столбцах одно из них будет представлено как текст («12»), а другое — как число (12), DAX неявно преобразует строку в число, а затем добавит его для числового результата. Следующее выражение возвращает 44: = «22» + 22
      • Если попытаться согнуть два числа, Excel выведет их в качестве строк, а затем согнуть. Следующее выражение возвращает «1234»: = 12 & 34.

      В следующей таблице общаются неявные преобразования типов данных, выполняемые в формулах. Excel выполняет неявные преобразования по возможности, как требуется указанной операцией.

      Таблица неявных преобразований данных

      Тип выполненного преобразования определяется оператором, который определяет требуемую величину перед выполнением нужной операции. Эти таблицы указывают на операторы и преобразование, выполняемые для каждого типа данных в столбце, если он сопряжен с типом данных в пересекаемой строке.

      Примечание: Текстовые типы данных не включаются в эти таблицы. Если число представлено в текстовом формате, Power Pivot пытается определить его тип и представить его как число.

      Типы данных

      Значение в JavaScript всегда относится к данным определённого типа. Например, это может быть строка или число.

      Есть восемь основных типов данных в JavaScript. В этой главе мы рассмотрим их в общем, а в следующих главах поговорим подробнее о каждом.

      Переменная в JavaScript может содержать любые данные. В один момент там может быть строка, а в другой – число:

      // Не будет ошибкой let message = "hello"; message = 123456;

      Языки программирования, в которых такое возможно, называются «динамически типизированными». Это значит, что типы данных есть, но переменные не привязаны ни к одному из них.

      Число

      let n = 123; n = 12.345;

      Числовой тип данных ( number ) представляет как целочисленные значения, так и числа с плавающей точкой.

      Существует множество операций для чисел, например, умножение * , деление / , сложение + , вычитание — и так далее.

      Кроме обычных чисел, существуют так называемые «специальные числовые значения», которые относятся к этому типу данных: Infinity , -Infinity и NaN .

        Infinity представляет собой математическую бесконечность ∞. Это особое значение, которое больше любого числа. Мы можем получить его в результате деления на ноль:

      alert( 1 / 0 ); // Infinity

      Или задать его явно:

      alert( Infinity ); // Infinity
      alert( "не число" / 2 ); // NaN, такое деление является ошибкой

      Значение NaN «прилипчиво». Любая математическая операция с NaN возвращает NaN :

      alert( NaN + 1 ); // NaN alert( 3 * NaN ); // NaN alert( "не число" / 2 - 1 ); // NaN

      Математические операции – безопасны

      Математические операции в JavaScript «безопасны». Мы можем делать что угодно: делить на ноль, обращаться с нечисловыми строками как с числами и т.д.

      Скрипт никогда не остановится с фатальной ошибкой (не «умрёт»). В худшем случае мы получим NaN как результат выполнения.

      Специальные числовые значения относятся к типу «число». Конечно, это не числа в привычном значении этого слова.

      Подробнее о работе с числами мы поговорим в главе Числа.

      BigInt

      В JavaScript тип number не может безопасно работать с числами, большими, чем (2 53 -1) (т. е. 9007199254740991 ) или меньшими, чем -(2 53 -1) для отрицательных чисел.

      Если говорить совсем точно, то, технически, тип number может хранить большие целые числа (до 1.7976931348623157 * 10 308 ), но за пределами безопасного диапазона целых чисел ±(2 53 -1) будет ошибка точности, так как не все цифры помещаются в фиксированную 64-битную память. Поэтому можно хранить «приблизительное» значение.

      Например, эти два числа (прямо за пределами безопасного диапазона) совпадают:

      console.log(9007199254740991 + 1); // 9007199254740992 console.log(9007199254740991 + 2); // 9007199254740992

      То есть все нечетные целые числа, большие чем (2 53 -1) , вообще не могут храниться в типе number .

      В большинстве случаев безопасного диапазона чисел от -(2 53 -1) до (2 53 -1) вполне достаточно, но иногда нам требуется весь диапазон действительно гигантских целых чисел без каких-либо ограничений или пропущенных значений внутри него. Например, в криптографии или при использовании метки времени («timestamp») с микросекундами.

      Тип BigInt был добавлен в JavaScript, чтобы дать возможность работать с целыми числами произвольной длины.

      Чтобы создать значение типа BigInt , необходимо добавить n в конец числового литерала:

      // символ "n" в конце означает, что это BigInt const bigInt = 1234567890123456789012345678901234567890n;

      Так как необходимость в использовании BigInt –чисел появляется достаточно редко, мы рассмотрим их в отдельной главе BigInt. Ознакомьтесь с ней, когда вам понадобятся настолько большие числа.

      В данный момент BigInt поддерживается только в браузерах Firefox, Chrome, Edge и Safari, но не поддерживается в IE.

      Строка

      Строка ( string ) в JavaScript должна быть заключена в кавычки.

      let str = "Привет"; let str2 = 'Одинарные кавычки тоже подойдут'; let phrase = `Обратные кавычки позволяют встраивать переменные $`;

      В JavaScript существует три типа кавычек.

      1. Двойные кавычки: «Привет» .
      2. Одинарные кавычки: ‘Привет’ .
      3. Обратные кавычки: `Привет` .

      Двойные или одинарные кавычки являются «простыми», между ними нет разницы в JavaScript.

      Обратные же кавычки имеют расширенную функциональность. Они позволяют нам встраивать выражения в строку, заключая их в $ . Например:

      let name = "Иван"; // Вставим переменную alert( `Привет, $!` ); // Привет, Иван! // Вставим выражение alert( `результат: $` ); // результат: 3

      Выражение внутри $ вычисляется, и его результат становится частью строки. Мы можем положить туда всё, что угодно: переменную name , или выражение 1 + 2 , или что-то более сложное.

      Обратите внимание, что это можно делать только в обратных кавычках. Другие кавычки не имеют такой функциональности встраивания!

      alert( "результат: $" ); // результат: $ (двойные кавычки ничего не делают)

      Мы рассмотрим строки более подробно в главе Строки.

      Нет отдельного типа данных для одного символа.

      В некоторых языках, например C и Java, для хранения одного символа, например «a» или «%» , существует отдельный тип. В языках C и Java это char .

      В JavaScript подобного типа нет, есть только тип string . Строка может содержать ноль символов (быть пустой), один символ или множество.

      Булевый (логический) тип

      Булевый тип ( boolean ) может принимать только два значения: true (истина) и false (ложь).

      Такой тип, как правило, используется для хранения значений да/нет: true значит «да, правильно», а false значит «нет, не правильно».

      let nameFieldChecked = true; // да, поле отмечено let ageFieldChecked = false; // нет, поле не отмечено

      Булевые значения также могут быть результатом сравнений:

      let isGreater = 4 > 1; alert( isGreater ); // true (результатом сравнения будет "да")

      Мы рассмотрим булевые значения более подробно в главе Логические операторы.

      Значение «null»

      Специальное значение null не относится ни к одному из типов, описанных выше.

      Оно формирует отдельный тип, который содержит только значение null :

      let age = null;

      В JavaScript null не является «ссылкой на несуществующий объект» или «нулевым указателем», как в некоторых других языках.

      Это просто специальное значение, которое представляет собой «ничего», «пусто» или «значение неизвестно».

      В приведённом выше коде указано, что значение переменной age неизвестно.

      Значение «undefined»

      Специальное значение undefined также стоит особняком. Оно формирует тип из самого себя так же, как и null .

      Оно означает, что «значение не было присвоено».

      Если переменная объявлена, но ей не присвоено никакого значения, то её значением будет undefined :

      let age; alert(age); // выведет "undefined"

      Технически мы можем присвоить значение undefined любой переменной:

      let age = 123; // изменяем значение на undefined age = undefined; alert(age); // "undefined"

      …Но так делать не рекомендуется. Обычно null используется для присвоения переменной «пустого» или «неизвестного» значения, а undefined – для проверок, была ли переменная назначена.

      Объекты и символы

      Тип object (объект) – особенный.

      Все остальные типы называются «примитивными», потому что их значениями могут быть только простые значения (будь то строка, или число, или что-то ещё). В объектах же хранят коллекции данных или более сложные структуры.

      Объекты занимают важное место в языке и требуют особого внимания. Мы разберёмся с ними в главе Объекты после того, как узнаем больше о примитивах.

      Тип symbol (символ) используется для создания уникальных идентификаторов в объектах. Мы упоминаем здесь о нём для полноты картины, изучим этот тип после объектов.

      Оператор typeof

      Оператор typeof возвращает тип аргумента. Это полезно, когда мы хотим обрабатывать значения различных типов по-разному или просто хотим сделать проверку.

      У него есть две синтаксические формы:

      // Обычный синтаксис typeof 5 // Выведет "number" // Синтаксис, напоминающий вызов функции (встречается реже) typeof(5) // Также выведет "number"

      Если передается выражение, то нужно заключать его в скобки, т.к. typeof имеет более высокий приоритет, чем бинарные операторы:

      typeof 50 + " Квартир"; // Выведет "number Квартир" typeof (50 + " Квартир"); // Выведет "string"

      Другими словами, скобки необходимы для определения типа значения, которое получилось в результате выполнения выражения в них.

      Вызов typeof x возвращает строку с именем типа:

      typeof undefined // "undefined" typeof 0 // "number" typeof 10n // "bigint" typeof true // "boolean" typeof "foo" // "string" typeof Symbol("id") // "symbol" typeof Math // "object" (1) typeof null // "object" (2) typeof alert // "function" (3)

      Последние три строки нуждаются в пояснении:

      1. Math — это встроенный объект, который предоставляет математические операции и константы. Мы рассмотрим его подробнее в главе Числа. Здесь он служит лишь примером объекта.
      2. Результатом вызова typeof null является «object» . Это официально признанная ошибка в typeof , ведущая начало с времён создания JavaScript и сохранённая для совместимости. Конечно, null не является объектом. Это специальное значение с отдельным типом.
      3. Вызов typeof alert возвращает «function» , потому что alert является функцией. Мы изучим функции в следующих главах, где заодно увидим, что в JavaScript нет специального типа «функция». Функции относятся к объектному типу. Но typeof обрабатывает их особым образом, возвращая «function» . Так тоже повелось от создания JavaScript. Формально это неверно, но может быть удобным на практике.

      Итого

      В JavaScript есть 8 основных типов данных.

      • Семь из них называют «примитивными» типами данных:
        • number для любых чисел: целочисленных или чисел с плавающей точкой; целочисленные значения ограничены диапазоном ±(2 53 -1) .
        • bigint для целых чисел произвольной длины.
        • string для строк. Строка может содержать ноль или больше символов, нет отдельного символьного типа.
        • boolean для true / false .
        • null для неизвестных значений – отдельный тип, имеющий одно значение null .
        • undefined для неприсвоенных значений – отдельный тип, имеющий одно значение undefined .
        • symbol для уникальных идентификаторов.
        • object для более сложных структур данных.

        Оператор typeof позволяет нам увидеть, какой тип данных сохранён в переменной.

        • Имеет две формы: typeof x или typeof(x) .
        • Возвращает строку с именем типа. Например, «string» .
        • Для null возвращается «object» – это ошибка в языке, на самом деле это не объект.

        В следующих главах мы сконцентрируемся на примитивных значениях, а когда познакомимся с ними, перейдём к объектам.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *