Продолжая изучение
Как и массивы,
Таким образом,
В разделе var переменную типа
var <имя_записи>: record <имя_поля1>: <тип_поля1>;
[<имя_поля2>: <тип_поля2>;]
[...]
end;
Имена
Замечание: Имена
<имя_записи>.<имя_поля>.
Поэтому можно записать:
var x: real;
r: record x: real;
y: real
end;
Если несколько подряд идущих
var <имя_записи>: record <имя_поля1>,_,<имя_поляN>: <тип_полей>;
<имя_поляS>: <тип_поляS>;
...
end;
Например:
var zap1: record x,y: real;
i,j,k: integer;
flag: boolean;
s: set of 'a'..'z';
a: array[1..100] of byte;
data: record day:1..31;
month: 1..12;
year: 1900..2100;
end;
end;
Эта
Наиболее распространенный способ использования
var tabl: array[1..100] of zap1;
Как и массивы,
Для того чтобы задать type, а затем воспользоваться им в разделе const:
type <имя_типа> = record <имя_поля1>: <тип_поля1>;
[<имя_поля2>: <тип_поля2>;]
[...]
end;
const <имя_константы>: <имя_типа> = <начальное_значение>;
Начальное значение для переменной типа
(<имя_поля1>: <значение_поля1>; _; <имя_поляN>: <значение_поляN>);
Например:
type data = record day: 1..31;
month: 1..12;
year: 1900..2100;
end;
const my_birthday: data = (day:17; month:3; year:2004);
Можно, конечно, не описывать тип константы отдельно, а объединить оба определения:
const my_birthday: record day: 1..31; month: 1..12; year: 1900..2100; end; = (day:17; month:3; year:2004);
Если описана двумерная таблица, то ее начальные значения задаются как вектор, каждый компонент которого является
type family = (mother, father, child); const birthdays : array[family] of data = ((day: 8; month: 3; year: 1975), (day: 23; month: 2; year: 1970), (day: 1; month: 9; year: 2000));
Обратиться к
<имя_записи>.<имя_поля>
Например:
month:= my_birthday.month +1;
Как уже было упомянуто, коллизий между переменной с именем и my_birthday. не возникает.
Доступ к
<имя_таблицы>[<индекс>].<имя_поля>
Эту
(<имя_таблицы>[<индекс>]).<имя_поля>
Например:
birthdays[mother].day := 9;
Если программе предстоит несколько раз подряд обращаться к
my_birthday.day:= 17; my_birthday.month:= 3; my_birthday.year:= 2004;
Для сокращения таких участков служит оператор with, позволяющий обращаться к
with <имя_записи> do
begin <операторы>
{имена полей здесь используются как <имя_поля>,
а не как <имя_записи>.<имя_поля>}
end;
Например:
with my_birthday do begin day:= 17; month:= 3; year:= 2004; end;
Замечание. Для того чтобы внутри оператора with можно было обратиться не к <имя_программы>.<имя_переменной>.
Например:
with my_birthday do
begin day:= 17;
month:= 3; {поле записи birthday.month}
year:= 2004;
programma.month:= 5; {глобальная переменная month}
end;
Если возникает необходимость расположить один оператор with внутри другого, то любую переменную (если перед ней явно не указано имя with, компилятор пытается интерпретировать в такой последовательности:
with больше, чем два, то поиск ведется последовательно во всех задействованных Например:
type date = record day: 1..31;
month: 1..12;
year: 1900..2005;
end;
student = record name: string[100];
year: 1950..2005; {год поступления}
gruppa: string[5];
birth: date;
end;
var ivanov: student;
begin
...
with ivanov do
begin
...
with birth do
begin
...
year:= 2001; {birth.year}
gruppa:= 'IT01'; {ivanov.gruppa}
...
end;
...
end;
end;
Если заранее известно, что в массиве
Специально для таких случаев существуют
В разделе var
var <имя_записи>: record <поле1>: <тип1>;
[<поле2>: <тип2>;]
[...]
case <поле_переключатель>: <тип> of
<варианты1>: (<поле3>: <тип3>;
<поле4>: <тип4>;
...);
<варианты2>: (<поле5>: <тип5>;
<поле6>: <тип6>;
...);
[...]
end;
Невариантная часть case ) подчиняется тем же правилам, что и обычная
Вариантная часть начинается зарезервированным словом case, после которого указывается то case, переключатель обязан принадлежать к одному из
Пример. Для того чтобы описать содержимое библиотеки, необходима следующая информация:
| Для книг | Для газет | Для журналов |
|---|---|---|
Автор Название Год издания Издательство |
Название Дата выхода (день, месяц, год) Издательство . |
Название Год и месяц издания Номер Издательство |
Графы "Название" и "Издательство" являются общими для всех трех вариантов, а остальные
type biblio = record name,publisher: string[20]; case item: char of 'b': (author: string[20]; year: 0..2004); 'n': (data: date); 'm': (year: 1700..2004; month: 1..12; number: integer); end;
В зависимости от значения item, в
Количество байтов, выделяемых компилятором под
В приведенном выше примере самым "длинным" является вариант ' b ': для него требуется 23 байта (21 байт для строки и 2 байта для целого числа). Для вариантов ' n ' и ' m ' требуется 4 и 5 байт соответственно (см. таблицу).
| name, publisher | item | Вариантная часть | ||||||||||||||||||||
| ... | 'b' | author | year | |||||||||||||||||||
| ... | 'n' | data | ||||||||||||||||||||
| ... | 'm' | year | number | |||||||||||||||||||
| ... | 'b' | author | year | |||||||||||||||||||
Кроме того, текстовые файлы относятся к структурам
Переменные toy информацией об имеющихся в продаже игрушках (название товара,
type toy = record name: string[20];
price: real;
age: set of 0..18; {в файле задано границами}
end;
то придется написать следующий код:
var f: text; c: char; i,j,min,max: integer; a: array[1..100] of toy; begin assign(f,input); reset(f); for i:=1 to 100 do if not eof(f) then with a[i] do begin readln(f,name,price,min,max); age:=[]; for j:= min to max do age:=age+[j]; end; close(f); ... end.
Как видим, такое поэлементное считывание весьма неудобно и трудоемко.
Выход из этой ситуации предлагают
<начало_структуры> + <номер_компонента>*<длина_компонента>
В разделе var
var <файловая_перем>: file of <тип_элементов_файла>;
Никакая файловая переменная не может быть задана константой.
С этого момента и до конца раздела под словом "файл" мы будем подразумевать "
Команда служит для установления связи между файловой переменной f и именем того файла, за работу с которым эта переменная будет отвечать.
Строка ' <имя_файла> ' может содержать полный путь к файлу. Если путь не указан, файл считается расположенным в той же директории, что и исполняемый модуль программы.
В зависимости от того, какие действия ваша программа собирается производить с открываемым файлом, возможно двоякое его открытие:
reset(f); - открытие файла для считывания из него информации и одновременно для
- открытие файла для
Закрываются close(f), общей для всех типов файлов.
Чтение из файла, открытого для считывания, производится с помощью команды read(). В скобках сначала указывается имя файловой переменной, а затем - список
read(f,a,b,c); - читать из файла f три однотипные переменные a, b и c.
Вводить из файла можно только переменные соответствующего объявлению типа, но этот тип данных может быть и структурированным. Cкажем, если вернуться к примеру, приведенному в начале п. "
type toy = record name: string[20];
price: real;
age: set of 0..18; {задано границами}
end;
var f: file of toy;
a: array[1..100] of toy;
begin
assign(f,input);
reset(f);
for i:=1 to 100 do
if not eof(f) then read(f,a[i]);
close(f);
...
end.
Уже знакомая нам функция сообщает о достигнутом конце файла. Все остальные функции "поиска конца" ( eoln(), seekeof() и seekeoln() ), свойственные текстовым файлам, нельзя применять к файлам
Зато существуют специальные подпрограммы, которые позволяют работать с
filepos(f:file):longint сообщит текущее положение указателя в файле f. Если он указывает на самый N элементов, то эта функция выдаст результат N. Это легко объяснимо: элементы файла нумеруются начиная с нуля, поэтому последний элемент имеет номер N-1. А номер N принадлежит, таким образом, "несуществующему" элементу - filesize(f:file):longint вычислит длину файла f.seek (f:file,n:longint) передвинет указатель в файле f на начало N. Если окажется, что n больше фактической длины файла, то указатель будет передвинут и за реальный truncate (f:file) обрежет "хвост" файла f: все элементы начиная с текущего и до конца файла будут из него удалены. На самом же деле произойдет лишь переписывание признака "Сохранять переменные в файл, открытый для write(). Так же как и в случае считывания, первой указывается файловая переменная, а за ней -
write(f,a,b,c); - записать в файл f (предварительно открытый для или reset(f) ) переменные a, b, c.
Выводить в
Например, если нужно заместить пятый элемент файла значением, хранящимся в переменной а, то следует написать следующий отрывок программы:
{указатель будет установлен на начало 5-го элемента}
write(f,a); {указатель будет установлен на начало 6-го элемента}
Замечание: Поскольку и чтение из файла, и
{указатель - на начало 5-го элемента}
read(f,a); {указатель - на начало 6-го элемента}
{указатель - на начало 5-го элемента}
write(f,b); {указатель - на начало 6-го элемента}
А что произойдет, если в файле содержится всего N элементов, а N+k )-й? Тогда начало файла останется прежним, затем в файл будет включен весь тот "мусор", что оказался между его концом и записываемой переменной, и, наконец, последним элементом нового файла станет записанное значение.
Главное преимущество
В разделе var
var g: file;
Никакая файловая переменная не может быть задана константой.
Содержимое этого раздела дословно повторяет все сказанное в разделе " Назначение
В зависимости от того, какие действия ваша программа собирается производить с открываемым файлом, возможно двоякое его открытие:
reset(f[,size]); - открытие файла для считывания из него информации и одновременно для
- открытие файла для
Необязательная переменная size может задать количество байтов, единовременно считываемых из
Закрываются close(f), общей для всех типов файлов.
Все подпрограммы, описанные в разделе " Поиск в size во время открытия файла.
Для осуществления blockread() и blockwrite().
Процедура blockread(f:file; buf,count:word [;result:word]) предназначена для считывания из файла f нескольких элементов разом (их количество указывается в переменной count, а длина устанавливается во время открытия файла) при помощи буфера обмена данными buf. Необязательная переменная result может хранить количество элементов, фактически считанных из файла.
Процедура blockwrite(f:file; buf,count:word [;result:word]) производит buf.
Приведем здесь также несколько стандартных процедур, осуществляющих работу с директориями, а также с файлами, но внешним относительно самих файлов образом (без их открытия).
Процедура удалит файл, связанный с файловой переменной f. Если такого файла нет, произойдет ошибка, реакцию на которую можно отрегулировать при помощи {$I} (см. лекцию 6).
Процедура даст файлу, связанному с файловой переменной f, новое имя, указанное в строке s. Если такого файла нет, произойдет ошибка.
Процедура chdir(s: string) сделает текущей директорию, указанную в строке s. Если такой директории нет, произойдет ошибка.
Процедура getdir(disk: byte; s:string) запишет в строку s имя 0 - текущий диск, 1 - диск А , 2 - диск В и т.д.).
Процедура mkdir(s: string) создаст в s именем. Если в
Процедура rmdir(s: string) удалит пустую директорию с заданным в строке s именем. Если такой директории нет, произойдет ошибка.
Сведем информацию о применимости процедур и функций работы с файлами в единую таблицу.
| Текстовые | Типизированные | Нетипизированные | |
|---|---|---|---|
| + | |||
| + | + | + | |
| blockread | + | ||
| blockwrite | + | ||
| close | + | + | + |
| + | + | + | |
| eoln | + | ||
| filepos | + | + | |
| filesize | + | + | |
| read | + | + | |
| readln | + | ||
| reset | + | + | + |
| + | + | + | |
| + | + | ||
| seekeof | + | ||
| seekeoln | + | ||
| + | + | ||
| write | + | + | |
| writeln | + |
Замечание: Реакция на ошибку, возникающую при выполнении любой из перечисленных здесь подпрограмм, зависит от состояния {$I} (см. лекцию 6).
Продолжая изучение
Как и массивы,
Таким образом,
В разделе var переменную типа
var <имя_записи>: record <имя_поля1>: <тип_поля1>;
[<имя_поля2>: <тип_поля2>;]
[...]
end;
Имена
Замечание: Имена
<имя_записи>.<имя_поля>.
Поэтому можно записать:
var x: real;
r: record x: real;
y: real
end;
Если несколько подряд идущих
var <имя_записи>: record <имя_поля1>,_,<имя_поляN>: <тип_полей>;
<имя_поляS>: <тип_поляS>;
...
end;
Например:
var zap1: record x,y: real;
i,j,k: integer;
flag: boolean;
s: set of 'a'..'z';
a: array[1..100] of byte;
data: record day:1..31;
month: 1..12;
year: 1900..2100;
end;
end;
Эта
Наиболее распространенный способ использования
var tabl: array[1..100] of zap1;
Как и массивы,
Для того чтобы задать type, а затем воспользоваться им в разделе const:
type <имя_типа> = record <имя_поля1>: <тип_поля1>;
[<имя_поля2>: <тип_поля2>;]
[...]
end;
const <имя_константы>: <имя_типа> = <начальное_значение>;
Начальное значение для переменной типа
(<имя_поля1>: <значение_поля1>; _; <имя_поляN>: <значение_поляN>);
Например:
type data = record day: 1..31;
month: 1..12;
year: 1900..2100;
end;
const my_birthday: data = (day:17; month:3; year:2004);
Можно, конечно, не описывать тип константы отдельно, а объединить оба определения:
const my_birthday: record day: 1..31; month: 1..12; year: 1900..2100; end; = (day:17; month:3; year:2004);
Если описана двумерная таблица, то ее начальные значения задаются как вектор, каждый компонент которого является
type family = (mother, father, child); const birthdays : array[family] of data = ((day: 8; month: 3; year: 1975), (day: 23; month: 2; year: 1970), (day: 1; month: 9; year: 2000));
Обратиться к
<имя_записи>.<имя_поля>
Например:
month:= my_birthday.month +1;
Как уже было упомянуто, коллизий между переменной с именем и my_birthday. не возникает.
Доступ к
<имя_таблицы>[<индекс>].<имя_поля>
Эту
(<имя_таблицы>[<индекс>]).<имя_поля>
Например:
birthdays[mother].day := 9;
Если программе предстоит несколько раз подряд обращаться к
my_birthday.day:= 17; my_birthday.month:= 3; my_birthday.year:= 2004;
Для сокращения таких участков служит оператор with, позволяющий обращаться к
with <имя_записи> do
begin <операторы>
{имена полей здесь используются как <имя_поля>,
а не как <имя_записи>.<имя_поля>}
end;
Например:
with my_birthday do begin day:= 17; month:= 3; year:= 2004; end;
Замечание. Для того чтобы внутри оператора with можно было обратиться не к <имя_программы>.<имя_переменной>.
Например:
with my_birthday do
begin day:= 17;
month:= 3; {поле записи birthday.month}
year:= 2004;
programma.month:= 5; {глобальная переменная month}
end;
Если возникает необходимость расположить один оператор with внутри другого, то любую переменную (если перед ней явно не указано имя with, компилятор пытается интерпретировать в такой последовательности:
with больше, чем два, то поиск ведется последовательно во всех задействованных Например:
type date = record day: 1..31;
month: 1..12;
year: 1900..2005;
end;
student = record name: string[100];
year: 1950..2005; {год поступления}
gruppa: string[5];
birth: date;
end;
var ivanov: student;
begin
...
with ivanov do
begin
...
with birth do
begin
...
year:= 2001; {birth.year}
gruppa:= 'IT01'; {ivanov.gruppa}
...
end;
...
end;
end;
Если заранее известно, что в массиве
Специально для таких случаев существуют
В разделе var
var <имя_записи>: record <поле1>: <тип1>;
[<поле2>: <тип2>;]
[...]
case <поле_переключатель>: <тип> of
<варианты1>: (<поле3>: <тип3>;
<поле4>: <тип4>;
...);
<варианты2>: (<поле5>: <тип5>;
<поле6>: <тип6>;
...);
[...]
end;
Невариантная часть case ) подчиняется тем же правилам, что и обычная
Вариантная часть начинается зарезервированным словом case, после которого указывается то case, переключатель обязан принадлежать к одному из
Пример. Для того чтобы описать содержимое библиотеки, необходима следующая информация:
| Для книг | Для газет | Для журналов |
|---|---|---|
Автор Название Год издания Издательство |
Название Дата выхода (день, месяц, год) Издательство . |
Название Год и месяц издания Номер Издательство |
Графы "Название" и "Издательство" являются общими для всех трех вариантов, а остальные
type biblio = record name,publisher: string[20]; case item: char of 'b': (author: string[20]; year: 0..2004); 'n': (data: date); 'm': (year: 1700..2004; month: 1..12; number: integer); end;
В зависимости от значения item, в
Количество байтов, выделяемых компилятором под
В приведенном выше примере самым "длинным" является вариант ' b ': для него требуется 23 байта (21 байт для строки и 2 байта для целого числа). Для вариантов ' n ' и ' m ' требуется 4 и 5 байт соответственно (см. таблицу).
| name, publisher | item | Вариантная часть | ||||||||||||||||||||
| ... | 'b' | author | year | |||||||||||||||||||
| ... | 'n' | data | ||||||||||||||||||||
| ... | 'm' | year | number | |||||||||||||||||||
| ... | 'b' | author | year | |||||||||||||||||||
Кроме того, текстовые файлы относятся к структурам
Переменные toy информацией об имеющихся в продаже игрушках (название товара,
type toy = record name: string[20];
price: real;
age: set of 0..18; {в файле задано границами}
end;
то придется написать следующий код:
var f: text; c: char; i,j,min,max: integer; a: array[1..100] of toy; begin assign(f,input); reset(f); for i:=1 to 100 do if not eof(f) then with a[i] do begin readln(f,name,price,min,max); age:=[]; for j:= min to max do age:=age+[j]; end; close(f); ... end.
Как видим, такое поэлементное считывание весьма неудобно и трудоемко.
Выход из этой ситуации предлагают
<начало_структуры> + <номер_компонента>*<длина_компонента>
В разделе var
var <файловая_перем>: file of <тип_элементов_файла>;
Никакая файловая переменная не может быть задана константой.
С этого момента и до конца раздела под словом "файл" мы будем подразумевать "
Команда служит для установления связи между файловой переменной f и именем того файла, за работу с которым эта переменная будет отвечать.
Строка ' <имя_файла> ' может содержать полный путь к файлу. Если путь не указан, файл считается расположенным в той же директории, что и исполняемый модуль программы.
В зависимости от того, какие действия ваша программа собирается производить с открываемым файлом, возможно двоякое его открытие:
reset(f); - открытие файла для считывания из него информации и одновременно для
- открытие файла для
Закрываются close(f), общей для всех типов файлов.
Чтение из файла, открытого для считывания, производится с помощью команды read(). В скобках сначала указывается имя файловой переменной, а затем - список
read(f,a,b,c); - читать из файла f три однотипные переменные a, b и c.
Вводить из файла можно только переменные соответствующего объявлению типа, но этот тип данных может быть и структурированным. Cкажем, если вернуться к примеру, приведенному в начале п. "
type toy = record name: string[20];
price: real;
age: set of 0..18; {задано границами}
end;
var f: file of toy;
a: array[1..100] of toy;
begin
assign(f,input);
reset(f);
for i:=1 to 100 do
if not eof(f) then read(f,a[i]);
close(f);
...
end.
Уже знакомая нам функция сообщает о достигнутом конце файла. Все остальные функции "поиска конца" ( eoln(), seekeof() и seekeoln() ), свойственные текстовым файлам, нельзя применять к файлам
Зато существуют специальные подпрограммы, которые позволяют работать с
filepos(f:file):longint сообщит текущее положение указателя в файле f. Если он указывает на самый N элементов, то эта функция выдаст результат N. Это легко объяснимо: элементы файла нумеруются начиная с нуля, поэтому последний элемент имеет номер N-1. А номер N принадлежит, таким образом, "несуществующему" элементу - filesize(f:file):longint вычислит длину файла f.seek (f:file,n:longint) передвинет указатель в файле f на начало N. Если окажется, что n больше фактической длины файла, то указатель будет передвинут и за реальный truncate (f:file) обрежет "хвост" файла f: все элементы начиная с текущего и до конца файла будут из него удалены. На самом же деле произойдет лишь переписывание признака "Сохранять переменные в файл, открытый для write(). Так же как и в случае считывания, первой указывается файловая переменная, а за ней -
write(f,a,b,c); - записать в файл f (предварительно открытый для или reset(f) ) переменные a, b, c.
Выводить в
Например, если нужно заместить пятый элемент файла значением, хранящимся в переменной а, то следует написать следующий отрывок программы:
{указатель будет установлен на начало 5-го элемента}
write(f,a); {указатель будет установлен на начало 6-го элемента}
Замечание: Поскольку и чтение из файла, и
{указатель - на начало 5-го элемента}
read(f,a); {указатель - на начало 6-го элемента}
{указатель - на начало 5-го элемента}
write(f,b); {указатель - на начало 6-го элемента}
А что произойдет, если в файле содержится всего N элементов, а N+k )-й? Тогда начало файла останется прежним, затем в файл будет включен весь тот "мусор", что оказался между его концом и записываемой переменной, и, наконец, последним элементом нового файла станет записанное значение.
Главное преимущество
В разделе var
var g: file;
Никакая файловая переменная не может быть задана константой.
Содержимое этого раздела дословно повторяет все сказанное в разделе " Назначение
В зависимости от того, какие действия ваша программа собирается производить с открываемым файлом, возможно двоякое его открытие:
reset(f[,size]); - открытие файла для считывания из него информации и одновременно для
- открытие файла для
Необязательная переменная size может задать количество байтов, единовременно считываемых из
Закрываются close(f), общей для всех типов файлов.
Все подпрограммы, описанные в разделе " Поиск в size во время открытия файла.
Для осуществления blockread() и blockwrite().
Процедура blockread(f:file; buf,count:word [;result:word]) предназначена для считывания из файла f нескольких элементов разом (их количество указывается в переменной count, а длина устанавливается во время открытия файла) при помощи буфера обмена данными buf. Необязательная переменная result может хранить количество элементов, фактически считанных из файла.
Процедура blockwrite(f:file; buf,count:word [;result:word]) производит buf.
Приведем здесь также несколько стандартных процедур, осуществляющих работу с директориями, а также с файлами, но внешним относительно самих файлов образом (без их открытия).
Процедура удалит файл, связанный с файловой переменной f. Если такого файла нет, произойдет ошибка, реакцию на которую можно отрегулировать при помощи {$I} (см. лекцию 6).
Процедура даст файлу, связанному с файловой переменной f, новое имя, указанное в строке s. Если такого файла нет, произойдет ошибка.
Процедура chdir(s: string) сделает текущей директорию, указанную в строке s. Если такой директории нет, произойдет ошибка.
Процедура getdir(disk: byte; s:string) запишет в строку s имя 0 - текущий диск, 1 - диск А , 2 - диск В и т.д.).
Процедура mkdir(s: string) создаст в s именем. Если в
Процедура rmdir(s: string) удалит пустую директорию с заданным в строке s именем. Если такой директории нет, произойдет ошибка.
Сведем информацию о применимости процедур и функций работы с файлами в единую таблицу.
| Текстовые | Типизированные | Нетипизированные | |
|---|---|---|---|
| + | |||
| + | + | + | |
| blockread | + | ||
| blockwrite | + | ||
| close | + | + | + |
| + | + | + | |
| eoln | + | ||
| filepos | + | + | |
| filesize | + | + | |
| read | + | + | |
| readln | + | ||
| reset | + | + | + |
| + | + | + | |
| + | + | ||
| seekeof | + | ||
| seekeoln | + | ||
| + | + | ||
| write | + | + | |
| writeln | + |
Замечание: Реакция на ошибку, возникающую при выполнении любой из перечисленных здесь подпрограмм, зависит от состояния {$I} (см. лекцию 6).
Для получения официальных документов о завершении программы дополнительного профессионального образования (удостоверения о повышении квалификации, дипломов о профессиональной переподготовке и MBA) необходимо предоставить:
Внимание! Вы можете не заказывать доставку бумажной версии официального документы, а скачать его в электронном виде и распечатать самостоятельно. Информация о выданном документе в течение 1 месяца загружается в Федеральную информационную систему «Федеральный реестр сведений о документах об образовании и (или) о квалификации, документах об обучении» - ФИС ФРДО.
Доступ на новый сайт осуществляется с использованием адреса электронной почты, который был указан вами при регистрации на "старом". Мы постарались перенести все ваши данные с прежнего ресурса, однако не исключена вероятность потери части информации.
При возникновении проблемы со входом, воспользуйтесь функцией сброса пароля
Если вы обнаружите несоответствия, пожалуйста, сообщите нам.