
- •Составление таблицы истинности.
- •Основы алгебры логики.
- •Логические операции с высказываниями: конъюнкция, дизъюнкция, инверсия.
- •Законы логических операций. Таблицы истинности.
- •9.Понятие системы программирования.
- •10. Эволюция языков прогаммирования.
- •11. Элементы языков программирования.
- •12.Исходный, объектный и загрузочный модули.
- •13.Интегрированная среда программирования.
- •14. Методы программирования
- •15. Сущность методов программирования.
- •16. Методы программирования: структурный, модульный, объектно-ориентированный. Достоинства и недостатки методов программирования.
- •17.Общие принципы разработки программного обеспечения. Жизненный цикл программного обеспечения.
- •18. Типы приложений. Консольные приложения.
- •19. Типы приложений. Оконные Windows приложения.
- •20. Типы приложений. Web-приложения
- •21.Типы приложений. Библиотеки.
- •22.Типы приложений. Web-сервисы.
- •23.Константа — это составная часть программы; объект, имеющий значение,неизменная величина.
- •25.К простым типам данных относятся: порядковые и вещественные типы.
- •Int(X) Real, integer Real Целая часть числа
- •27.Структура программы на языке Турбо Паскаль
- •Var………..; {раздел объявления переменных}{±}
- •28.Оператор – инструкция, задающая определенные действия программы. Одним из операторов является оператор присваивания, который присваивает значение некоторого выражения некоторой переменной.
- •29.Оператор присваивания имеет следующую структуру:
- •31.Составной оператор
- •32.Синтаксис оператора if:
- •35.Строковый тип данных.
- •37.Объединение разнородных элементов (Запись)
- •39.Типы файлов Турбо Паскаль
- •41.Доступ к файлу в программе происходит с помощью переменных файлового типа. Переменную файлового типа описывают одним из трех способов:
- •42.Работа с типизированными файлами
- •43.Стандартные процедуры и функции
- •45. Процедуры и функции обработки текстовых файлов.
- •46 Процедуры и функции
- •47 Структура процедуры, описание процедур
- •48 Передача параметров, вызов процедуры
- •49 Локальные и глобальные данные
- •50 Структура функции, описание функции
- •51 Передача параметров, вызов функции
- •52 Модули
- •53 Интерфейсная часть модуля
- •54 Инициирующая часть модуля
- •55 Исполняемая часть модуля
- •56 Обращение к модулю из основной программы
- •57 Объекты
- •58 Основные принципы ооп
- •59 Описание объектов, иерархия объектов
- •60 Наследование записей
- •61 Понятие метода, определение метода, область действия метода
- •62 Стандартные библиотечные модули
- •63 Назначение модуля Dos
- •64 Назначение crt модуля
- •65 Структурное программирование
- •66 Алгоритм
- •67) Способы изображения алгоритмов.
- •68) Элементарные базовые управляющие структуры: линейная последовательность, ветвление.
- •69) Базовые структуры организации цикла: циклы со счётчиком и итерационные циклы.
- •70) Языки программирования.
- •I) машинно-зависимые языки.
- •II) машинно-независимые языки
- •71)Машинно-ориентированные языки и их характеристики.
- •74) Объектно-ориентированные языки программирования. Их достоинства и недостатки.
- •75) Используемые символы.
- •76) Константы.
- •77) Идентификаторы.
- •78) Ключевые слова.
- •79) Комментарии.
- •84) Переменные перечисляемого типа.
- •85) Массивы.
- •86) Структуры.
- •87) Объявления.
- •88) Поля битов.
- •89) Переменные с изменяемой структурой.
- •90.Определение объектов и типов:
- •91.Инициализация данных:
- •Операнды и операции:
- •Преобразования при вычислении выражений:
- •Операции отрицания и дополнения:
- •Операции разадресации и адреса:
- •Операция sizeof:
- •Мультипликативные операции:
- •Аддитивные операции:
- •Операции сдвига:
- •Поразрядные операции:
- •101 Наиболее употребимы двоичная, восьмеричная, десятичная и шестнадцатеричная система исчисления.
- •107 В языке си операции с высшими приоритетами вычисляются первыми. Наивысшим приоритетом является приоритет равный 1. Приоритеты и порядок операций приведены в табл. 8.
- •108 При выполнении операций происходят неявные преобразования типов в следующих случаях:
- •109 Любое выражение, которое заканчивается точкой с запятой, является оператором.
- •1.4.2. Пустой оператор
- •111 Составной оператор представляет собой несколько операторов и объявлений, заключенных в фигурные скобки:
- •Вопрос № 112 (Оператор if)
- •Вопрос №113 (Оператор switch)
- •Вопрос №114 (оператор break)
- •Вопрос №115 (оператор for )
- •Вопрос №116 (оператор while)
- •Вопрос № 117 (оператор do while )
- •Вопрос №118 (оператор continue)
- •Вопрос №119 (оператор return)
- •Вопрос №120 (оператор goto)
- •Вопрос №121 (определение и вызов функций)
- •Вопрос № 122 ( вызов функции с переменным числом параметров)
- •Вопрос № 123 (Передача параметров функции main)
- •Вопрос №124 (Исходные файлы и объявление переменных)
- •Вопрос № 125 (Объявления функций)
- •Вопрос № 126 (Время жизни и область видимости программных объектов)
- •Вопрос №127 (Инициализация глобальных и локальных переменных)
- •Вопрос № 128 (Методы доступа к элементам массива)
- •Вопрос № 129 (Указатели на многомерные массивы)
- •Вопрос № 130 (Операции с указателями)
- •Вопрос № 131 (Массивы указателей)
- •Вопрос № 132 (Динамическое размещение массивов)
- •Вопрос №133 (директива #include)
- •134. Директива #define
- •135. Директива #undef
- •136. Методы организации и хранения линейных списков
- •136. Методы организации и хранения линейных списков
- •137. Операции со списками при последовательном хранении
- •138. Операции со списками при связанном хранении
- •5)Частичное упорядочение списка
- •139. Организация двух связанных списков
- •140. Стеки и очереди
- •141. Пузырьковая сортировка
- •142. Сортировка вставкой
- •143. Сортировка посредством вывода
- •144. Слияние списков
- •145. Сортировка списков путем слияния
- •146.Последовательный поиск
- •147. Бинарный поиск
- •148. Методы вычисления адреса
- •150.Типы данных языка программирования
- •154. Типы данных
- •155. Выражения и оперпции
- •178) Поиск, удаление, замена и добавление символов в строке.
- •Int strcmp(const char *, const char *); лексикографическое сравнение строк
- •Int strncmp(const char *, const char *, size_t); лексикографическое сравнение первых n байтов строк
- •Int strcoll(const char *, const char *); лексикографическое сравнение строк с учетом локали collating order
- •180) Операции со строками
- •181) Объявление множества
- •182) Операции над множествами
- •183) Объявление файла
- •184) Файл последовательного доступа
- •185) Давайте сперва перед файлами произвольного доступа разберем режимы открытия:
- •187,188,189)Операции файла последовательного доступа. ( Открытие и закрытие и т.Д)
- •191) Объектно-ориентированное программирование
- •192) Основные принципы ооп.
- •193) История ооп
- •194)Базовые понятия ооп
- •195)Основные принципы ооп (Инкапсуляция, Наследие, Полиморфизм).
- •196) Событийно управляемое программирование
- •197) Компонентно-ориентированный подход
- •198) Классы объектов. Компоненты и их свойства.
- •199) Требования к аппаратным и программным средствам интегрированной среды разработки разработчика.
- •200)Интерфейс среды разработчика.
- •201. Чтобы использовать в проекте уже созданные ole-элементы управления, необходимо понимать, как создать проект, допускающий встраивание ocx-объектов, и как добавить в проект эти элементы.
- •202. Для добавления элементов к панели, созданную в предыдущей процедуре, перетащите элементы управления из раздела Редактор ленты на панели Панель элементов в представлении конструирования.
- •211. Виды классов:
- •215. Основными механизмами в объекто ориентированном программирование является полиморфизм, наследование и инкапсуляция.
- •220. Компиляция и запуск приложения
- •221. Создание оконных приложений в Visual Studio
- •222. У всех Windows-приложений фиксированная структура, определяемая функцией WinMain. Структура приложения, построенного из объектов классов библиотеки mfc, является еще более определенной.
- •223. При разработке программы использовались перечисленные ниже объекты и их методы.
187,188,189)Операции файла последовательного доступа. ( Открытие и закрытие и т.Д)
#include < stdio.h >
int main( void )
{
/* Переменные*/
char oldname[80], newname[80];
/* Ввод начального имени файла*/
printf("Enter current filename: ");
gets(oldname);
/* Ввод нового имени файла*/
printf("Enter new name for file: ");
gets(newname);
/*Процедура переименования */
if ( rename( oldname, newname ) == 0 )
printf("%s has been renamed %s.n", oldname, newname);
else
/*Ошибка */
fprintf(stderr, "An error has occurred renaming %s.n", oldname);
return 0;
}
Для копирования файлов в С, в отличие от С++ не предусмотрено библиотечных функций, поэтому придется писать свою:
#include < stdio.h >
int file_copy( char *oldname, char *newname );
int main( void )
{
char source[80], destination[80];
/* Получить начальное имя и конечное имя*/
printf("nEnter source file: ");
gets(source);
printf("nEnter destination file: ");
gets(destination);
/* Операция копирования*/
if ( file_copy( source, destination ) == 0 )
puts("Copy operation successful");
else
fprintf(stderr, "Error during copy operation");
return(0);
}
/* Сама функция копирования*/
int file_copy( char *oldname, char *newname )
{
FILE *fold, *fnew;
int c;
if ( ( fold = fopen( oldname, "rb" ) ) == NULL )
return -1;
if ( ( fnew = fopen( newname, "wb" ) ) == NULL )
{
fclose ( fold );
return -1;
}
/* Считывается файл по одному байту,
/*пока не встретится завершающий символ */
while (1)
{
c = fgetc( fold );
if ( !feof( fold ) )
fputc( c, fnew );
else
break;
}
fclose ( fnew );
fclose ( fold );
return 0;
В С++ же, функция CopyFile – библиотечная, что видно в следующем примере:
#include < windows.h >
#include < iostream.h >
int main()
{
// копируем файл
if(!CopyFile("C:demo_file.dat", "C:new_file.dat", FALSE))
{
cerr < < "Copy file failed." < < endl
< < "The last error code: " < < GetLastError() < < endl;
cout < < "Press any key to finish.";
cin.get();
return 0;
}
cout < < "The file is copied." < < endl;
return 0;
}
Далее мы рассмотрим варианты удаления файла, сначала на С:
#include < stdio.h >
int main( void )
{
char filename[80];
printf("Enter the filename to delete: ");
gets(filename);
/* Удаление */
if ( remove(filename) == 0)
printf("The file %s has been deleted.n", filename);
else
fprintf(stderr, "Error deleting the file %s.n", filename);
return 0;
}
Функция DeleteFile в С++ имеет похожее применение:
#include < windows.h >
#include < iostream.h >
int main()
{
// удаляем файл
if(!DeleteFile("C:demo_file.dat"))
{
cerr < < "Delete file failed." < < endl
<< "The last error code: " < < GetLastError() < < endl;
cout < < "Press any key to finish.";
cin.get();
return 0;
}
cout < < "The file is deleted." < < endl;
return 0;
}
Когда же нужно записать информацию в файл на С, используется функция fprintf:
#include < stdlib.h >
#include < stdio.h >
void clear_kb(void);
int main( void )
{
FILE *fp;
char data[50];
int count;
char filename[20];
puts("Enter someting to wrtie into.");
gets(data);
clear_kb();
puts("Enter a name for the file.");
gets(filename);
if ( (fp = fopen(filename, "w")) == NULL)
{
fprintf(stderr, "Error opening file %s.", filename);
exit(1);
}
for (count = 0; count < 5; count++)
{
fprintf(fp, "ndata[%d] = %f", count, data[count]);
fprintf(stdout, "ndata[%d] = %f", count, data[count]);
}
fclose(fp);
printf("n");
return 0;
}
void clear_kb(void)
{
char junk[80];
gets(junk);
}
В С++ же, используется другая функция:
#include < windows.h >
#include < iostream.h >
int main()
{
HANDLE hFile;
// создаем файл для записи данных
hFile = CreateFile(
"C:demo_file.dat", // имя файла
GENERIC_WRITE, // запись в файл
0, // монопольный доступ к файлу
NULL, // защиты нет
CREATE_NEW, // создаем новый файл
FILE_ATTRIBUTE_NORMAL, // обычный файл
NULL // шаблона нет
);
// проверяем на успешное создание
if (hFile == INVALID_HANDLE_VALUE)
{
cerr << "Create file failed." << endl
<< "The last error code: " << GetLastError() << endl;
cout << "Press any key to finish.";
cin.get();
return 0;
}
// пишем данные в файл
for (int i = 0; i < 10; ++i)
{
DWORD dwBytesWrite;
if (!WriteFile(
hFile, // дескриптор файла
&i, // адрес буфера, откуда идет запись
sizeof(i), // количество записываемых байтов
&dwBytesWrite, // количество записанных байтов
(LPOVERLAPPED)NULL // запись синхронная
))
{
cerr << "Write file failed." << endl
<< "The last error code: " << GetLastError() << endl;
CloseHandle(hFile);
cout << "Press any key to finish.";
cin.get();
return 0;
}
}
// закрываем дескриптор файла
CloseHandle(hFile);
cout << "The file is created and written." << endl;
return 0;
}
190) Практически во всех алгоритмических языках имеется возможность программирования функций и процедур - блоков операторов, оформленных в виде подпрограмм. Разработка функций и процедур необходима при многократном использовании в разных местах программы или в нескольких программах блока операторов, выполняющих однотипные действия, например, расчет значений сложной функции при различных значениях аргумента. В Турбо - Паскале имеется также возможность создавать библиотеки (модули), состоящие из специальных процедур и функций, отличных от поставляемых в пакете ( модули System, Crt, Graph).
Процедуры (подпрограммы) и функции, определяемые программистом, приводятся в разделе описания основной программы. Процедуры и функции имеют заголовок, раздел описания и раздел операторов.
Заголовок процедуры состоит из служебного слова Procedure, имени процедуры и списка параметров,
например:
Procedure Name_P(p1, p2,...: "тип"; Var p3, p4,...: "тип";...);
Заголовок функции состоит из служебного слова Function, имени функции и списка параметров, кроме того указывается тип возвращаемого функцией значения,
например:
Function Name_F("список формальных параметров"):"тип результа-та";
Здесь:
Function и Procedure - служебные слова,
Name_F, Name_P - имена функции и процедуры соответственно,
p1, p2 - имена формальных параметров-значений,
p3, p4 - имена формальных параметров-переменных,
. . . - многоточие означает возможность перечисления большего числа параметров.
В дальнейшем, если не оговаривается особо, все сказанное к процедуре относится также и к функции.
Тип возвращаемого функцией значения может быть простым, строковым или типом-указателем. Тип формальных параметров может быть любым, но должен указываться только идентификатором (именем типа). Таким образом, имя типа формального параметра - массива должно быть задано предварительно в операторе Type, например: Type M= array[1..100]of real; Затем тип массива может указываться в заголовке процедуры, например: Procedure Name_P(p: M); Тип формальных параметров описывается только в заголовке процедуры. Список формальных параметров может отсутствовать, например. процедура Randomize; не имеет параметров.
Если в результате выполнения нескольких операторов получается одно значение переменной, то эти операторы можно включить в описание функции. Например, функция Sin(x); возвращает значение, которое присваивается переменной Y:=sin(x); (эта, и другие стандартные функции описаны в модуле System, который подключается к программе автоматически).
Если в результате выполнения нескольких операторов производится некоторое действие или расчет нескольких переменных, то эти операторы лучше включить в описание процедуры. Например, процедура ClrScr; из модуля CRT очищает экран.
Вызов процедуры осуществляется в разделе выполнения основной программы или других процедур (вложенные процедуры). Программа (процедура) внутри которой вызывается другая процедура называется внешней по отношению к вызываемой процедуре.
При вызове процедуры вместо формальных параметров подставляются фактические параметры, значения которых используются в процедуре.
Например:
Name_P(p11, p22,..., p33, p44,...); - вызов процедуры Name_P,
Y:= Name_F("список фактических параметров"): - вызов функции Name_F,
Здесь:
p11, p22, . . . - имена или значения переменных,
p33, p44, . . . - имена переменных, значения которых возвращаются в программу.
Y - переменная, которой присваивается значение возвращаемое функцией.
Типы соответствующих формальных и фактических параметров должны совпадать, а имена могут совпадать или быть различными. Вместо параметров-значений можно подставлять имена переменных, значения переменных или выражения, вместо параметров-переменных подставляются имена переменных. Функция и параметры-переменные возвращают во внешнюю программу значения, полученные после окончания работы функции или процедуры. Изменения параметров-значений в процедуре носит локальный характер, во внешней программе соответствующие фактические параметры не изменяются. Если не требуется передавать во внешнюю программу новые значения, то следует использовать параметры-значения, а не параметры-переменные.
В процедуре можно использовать локальные метки, константы и переменные, описав их в разделе описания процедуры. Локальные имена не должны совпадать с именами формальных параметров, а их значения не передаются во внешнюю программу. Метки, константы и переменные, описанные во внешней программе раньше, чем сама процедура, называются глобальными по отношению к вызываемой процедуре. Если локальные и глобальные имена совпадают, то в процедуре используются локальные значения, а во внешней программе - глобальные значения, т. е. локальные и глобальные идентификаторы независимы. Если имя глобальной переменной уникально (в процедуре не описывается переменная с таким же именем) и ее значение в процедуре изменяется, то оно изменяется и во внешней программе. Вызывая в программе процедуру программист использует ее имя и параметры не анализируя, а часто и не зная содержимого процедуры. Поэтому в целях универсальности процедур следует все значения в процедуру передавать через список параметров, а переменные внутри процедуры описывать, т. е. делать их локальными.
Приведем пример процедуры вывода на экран визитной карточки программиста.
Program NP_1;
Var
Dat, Fam: string; { Fam: глобальная переменная }
Procedure VIZ(D_R :string); { D_R - формальный параметр }
Var
S_t: string;{ S_t: локальная переменная }
Begin
Writeln('| --------------------------------------------- |');
Writeln('| Разработчик программы:', Fam:14,' |');
Writeln('| |');
Writeln('| г. Анжеро-Судженск ', D_R:14,' |');
Writeln('| Телефон: 2-99-76 |');
Writeln('| ----------------------------------------------|');
Write(' Комментарий: ');
Readln(S_t)
end;
Begin
Fam:='И.И.Иванов';
Dat:='06.12.95'; {Dat - фактический параметр}
VIZ(Dat); { вызов процедуры }
Readln;
END.
Если процедура описана в другом файле с именем, например, F_PR. pas, то ее можно подключить к программе, указав в разделе описания директиву: {$I F_PR. pas}
Приведем пример использования стандартных процедур модуля DOS для вывода текущей даты и времени:
uses DOS; { подключение модуля DOS }
Procedure Date_Time;
var y, m, d, d_w:word; h, min, sec, hund: word;{локальные параметры }
begin
GetDate(y,m,d,d_w); {вызов процедуры DOS, возвращающей параметры даты }
GetTime(h,min,sec,hund); { процедура, возвращающая параметры времени }
writeln('сегодня: ' );
writeln('_':10, d, ' число');
writeln('_':10, m, ' месяц');
writeln('_':10, y, ' год' );
writeln('день недели: ', d_w ); { d_w= 0 - воскресенье, и т. д. }
writeln('Время: ' );
writeln('_':6, h, ' часов' );
writeln('_':6, min, ' минут' );
writeln('_':6, sec, ' секунд' ); readln
end;
Begin
Date_Time
end.
В практических задачах часто пишутся процедуры, возвращающие значения элементов массивов. Приведем пример процедуры расчета "N" значений функции, например, Y= 4*Sin(x)+7*Cos(x); в заданном диапазоне x1<=x<=x2, при N<=100 и равномерной разбивке диапазона.
type r_1000= array[1. . 1000] of real; { задается тип r_1000 }
var Z: r_1000; x1, x2: real; n: word;
Procedure Mas_Y(var Y:r_1000; x1,x2:real; n:word); {Y - параметр-перемен-ная}
var i: word; x, dx: real; { локальные параметры }
begin
If (n>1000) or (n<2) then
begin
writeln('Длина массива >1 и не должна превышать 1000');
Readln;
Halt
end;
i:=0;
x:=x1;
dx:=(x2-x1)/(n-1); { dx - шаг изменения аргумента }
If dx<= 0 then
begin
writeln('x2 должно быть больше x1');
Readln;
Halt
end;
While xx1)');
Readln(x1, x2);
Writeln('Введите значение 1
Здесь тип формального параметра "Y" задается в разделе описания типов внешней программы и совпадает с типом фактического параметра "Z", значения элементов которого возвращаются во внешнюю программу.
Оператор Halt прерывает выполнение всей программы, даже если он используется внутри процедуры. Применение оператора Exit внутри процедуры вызывает прерывание процедуры, но не внешней программы.
Приведем пример процедуры вывода массива чисел в файл:
Type M_30х30_r= array[1..30, 1..30] of real; { задается тип M_30х30_r }
var x: M_30х30_r;
i, j, n, m: byte;
{------------------------------------------------------------------------}
Procedure Wr_M(a: M_30х30_r; name_f: string; n, m: byte);
Var
i, j: byte; { a - массив NxM, n<=30, m<=30 }
f: text; { name_f - имя файла }
begin
assign(f, name_f);
rewrite(f);
For i:= 1 to n do
begin
writeln(f);
For j:= 1 to m do write(f, a[i,j]:6:2)
end;
close(f)
end;
{------------------------------------------------------------------------}
Begin
N:= 10; { создание симметричной матрицы }
for i:= 1 to N do
for j:= i to N do
x[i, j]:= 0.5 + random(50); { заполнение верхней треугольной матрицы }
for i:= 1 to N do
for j:= i to N do
x[j,i]:= x[i,j]; { заполнение нижней, симметричной части матрицы }
End.
Для правильного считывания данных, записанных в файл бесформатным выводом необходима запись пробела для разделения чисел.
Приведем пример функции для расчета высоты треугольника по заданным значениям его сторон.
Program TR;
Var a, b, c, ha, hb, hc: real;
{----------------------------------------------------------------------------}
Function H_TR(a, b, c: real): real; { a, b, c - Стороны треугольника }
Var p, s: real;
Begin
If (a<0) or (b<0) or (c<0) Then
begin
Writeln('Стороны треугольника >0 ?');
readln;
Halt
end;
If (a>(b+c)) or (b>(a+c)) or (c>(a+b)) Then
begin
Writeln('a<(b+c), b<(a+c), c<(a+b) ?');
readln;
Halt
end;
p:= (a+b+c)/2; { полупериметр }
s:= Sqrt(p*(p-a)*(p-b)*(p-c)); { площадь }
H_TR:= 2*s/a; { Присвоение функции значения }
End;
{----------------------------------------------------------------}
Begin
Writeln('Введите значения сторон треугольника a,b,c');
Readln(a,b,c);
ha:= H_TR(a, b, c);
hb:= H_TR(b, a, c);
hc:= H_TR(c, b, a);
Writeln('Высоты треугольника:');
Writeln('ha=',ha:-10:4, 'hb=',hb:-10:4, 'hc=',hc:-10:4);
Readln
End.
В программе трижды вызывается функция расчета высоты треугольника для различных комбинаций фактических параметров, что позволяет вычислить все высоты треугольника. Приведем пример использования функции для расчета суммы членов степенного ряда, представляющего тригонометрическую функцию Y= Sin(x).
PROGRAM fun_sin;
var y, y1, x1: real;
{-------------------------------------------------------------------------}
Function Sin_r( x: real): real;
Var a, k, y: real; i: longint;
begin
if abs(x) > 2*Pi Then x:= 2*pi*Frac(x/(2*Pi)); {учет периодичности }
if abs(x) > 2*Pi Then x:= x - 2*pi*Int(x/(2*Pi)); { функции }
if abs(x) > Pi Then x:= Pi - ABS(x); { учет асимметрии функции }
i:= 0; a:= x; y:= a;
while abs(a)>0.0000001 do
begin
i:=i+1;
k:=-x*x/(2*i*(2*i+1));
a:= a*k;
y:= y + a
end;
Sin_r:= y; { присвоение функции ее значения }
end;
{-------------------------------------------------------------------------}
Begin
write('Введите значение аргумента: x1= ');
Readln(x1);
Y:= Sin_r(x1); { вызов функции, разработанной программистом }
Y1:= Sin(x1); { вызов стандартной функции }
writeln('значение аргумента: x1= ', x1);
writeln('расчетное значение функции: Sin_r(x1)= ', y :-11:8);
writeln('контрольный результат: Sin(x1) = ', y1:-11:8);
writeln('Нажмите Enter');
readln;
end.