more primitive automatitions
This commit is contained in:
parent
630a5efc29
commit
9993bfdb53
BIN
build/j-spec.pdf
BIN
build/j-spec.pdf
Binary file not shown.
28
j-spec.tex
28
j-spec.tex
|
@ -24,7 +24,7 @@
|
||||||
|
|
||||||
\section{Платформа: история и окружение}
|
\section{Платформа: история и окружение}
|
||||||
\subsection{В этом разделе}
|
\subsection{В этом разделе}
|
||||||
Краткая история (причины возникновения); инструментарий, выбор версии; CLI; структура проекта; документирование;
|
Краткая история (причины возникновения); инструментарий, выбор версии; CLI; структура проекта; документирование; некоторые интересные способы сборки проектов.
|
||||||
|
|
||||||
В этом разделе происходит первое знакомство со внутреннем устройством языка Java и фреймворком разработки приложений с его использованием. Рассматривается примитивный инструментарий и базовые возможности платформы для разработки приложений на языке Java. Разбирается структура проекта, а также происходит ознакомление с базовым инструментарием для разработки на Java.
|
В этом разделе происходит первое знакомство со внутреннем устройством языка Java и фреймворком разработки приложений с его использованием. Рассматривается примитивный инструментарий и базовые возможности платформы для разработки приложений на языке Java. Разбирается структура проекта, а также происходит ознакомление с базовым инструментарием для разработки на Java.
|
||||||
\begin{itemize}
|
\begin{itemize}
|
||||||
|
@ -33,7 +33,9 @@
|
||||||
\item \nom{JVM}{(от англ. Java Virtual Machine) — виртуальная машина Java, основная часть исполняющей системы Java. Виртуальная машина Java исполняет байт-код, предварительно созданный из исходного текста Java-программы компилятором. JVM может также использоваться для выполнения программ, написанных на других языках программирования.}
|
\item \nom{JVM}{(от англ. Java Virtual Machine) — виртуальная машина Java, основная часть исполняющей системы Java. Виртуальная машина Java исполняет байт-код, предварительно созданный из исходного текста Java-программы компилятором. JVM может также использоваться для выполнения программ, написанных на других языках программирования.}
|
||||||
\item \nom{JIT}{(англ. Just-in-Time, компиляция «точно в нужное время»), динамическая компиляция — технология увеличения производительности программных систем, использующих байт-код, путём компиляции байт-кода в машинный код или в другой формат непосредственно во время работы программы. Таким образом достигается высокая скорость выполнения по сравнению с интерпретируемым байт-кодом за счёт увеличения потребления памяти (для хранения результатов компиляции) и затрат времени на компиляцию. Технология JIT базируется на двух более ранних идеях, касающихся среды выполнения: компиляции байт-кода и динамической компиляции.}
|
\item \nom{JIT}{(англ. Just-in-Time, компиляция «точно в нужное время»), динамическая компиляция — технология увеличения производительности программных систем, использующих байт-код, путём компиляции байт-кода в машинный код или в другой формат непосредственно во время работы программы. Таким образом достигается высокая скорость выполнения по сравнению с интерпретируемым байт-кодом за счёт увеличения потребления памяти (для хранения результатов компиляции) и затрат времени на компиляцию. Технология JIT базируется на двух более ранних идеях, касающихся среды выполнения: компиляции байт-кода и динамической компиляции.}
|
||||||
\item \nom{CLI}{(англ. Command line interface, Интерфейс командной строки) — разновидность текстового интерфейса между человеком и компьютером, в котором инструкции компьютеру даются в основном путём ввода с клавиатуры текстовых строк (команд). Также известен под названиями «консоль» и «терминал».}
|
\item \nom{CLI}{(англ. Command line interface, Интерфейс командной строки) — разновидность текстового интерфейса между человеком и компьютером, в котором инструкции компьютеру даются в основном путём ввода с клавиатуры текстовых строк (команд). Также известен под названиями «консоль» и «терминал».}
|
||||||
|
\item \nom{Docker}{программное обеспечение для автоматизации развёртывания и управления приложениями, контейнеризатор приложений. Позволяет «упаковать» приложение со всем его окружением и зависимостями в контейнер, который может быть развёрнут почти на любой системе.}
|
||||||
\end{itemize}
|
\end{itemize}
|
||||||
|
\nomenclature{GPL}{GNU General Public License (чаще всего переводят как Открытое лицензионное соглашение GNU) — лицензия на свободное программное обеспечение, созданная в рамках проекта GNU, по которой автор передаёт программное обеспечение в общественную собственность. Её также сокращённо называют GNU GPL или даже просто GPL, если из контекста понятно, что речь идёт именно о данной лицензии. GNU Lesser General Public License (LGPL) — это ослабленная версия GPL, предназначенная для некоторых библиотек ПО.}
|
||||||
|
|
||||||
\subsection{Краткая история (причины возникновения)}
|
\subsection{Краткая история (причины возникновения)}
|
||||||
\begin{itemize}
|
\begin{itemize}
|
||||||
|
@ -99,6 +101,8 @@
|
||||||
|
|
||||||
Также возможно использовать и другие версии, но не старше 1.8. Это обосновано тем, что основные разработки на данный момент только начинают обновлять инструментарий до более новых версий (часто 11 или 13) или вовсе переходят на другие JVM-языки, такие как Scala, Groovy или Kotlin.
|
Также возможно использовать и другие версии, но не старше 1.8. Это обосновано тем, что основные разработки на данный момент только начинают обновлять инструментарий до более новых версий (часто 11 или 13) или вовсе переходят на другие JVM-языки, такие как Scala, Groovy или Kotlin.
|
||||||
|
|
||||||
|
Иногда для решения вопроса менеджмента версий прибегают к стороннему инструментарию, такому как SDKMan.
|
||||||
|
|
||||||
Для решения некоторых несложных задач курса мы будем писать простые приложения, не содержащие ООП, сложных взаимосвязей и проверок, в этом случае нам понадобится Jupyter notebook с установленным ядром (kernel) IJava.
|
Для решения некоторых несложных задач курса мы будем писать простые приложения, не содержащие ООП, сложных взаимосвязей и проверок, в этом случае нам понадобится Jupyter notebook с установленным ядром (kernel) IJava.
|
||||||
|
|
||||||
\subsubsection{Задания для самопроверки}
|
\subsubsection{Задания для самопроверки}
|
||||||
|
@ -305,6 +309,7 @@ public class OtherClass {
|
||||||
\end{enumerate}
|
\end{enumerate}
|
||||||
|
|
||||||
\subsection{Отложим мышки в сторону (CLI: сборка, пакеты, запуск)}
|
\subsection{Отложим мышки в сторону (CLI: сборка, пакеты, запуск)}
|
||||||
|
\label{subsec:cli}
|
||||||
Простейший проект возможно скомпилировать и запустить без использования тяжеловесных сред разработки, введя в командной строке ОС две команды:
|
Простейший проект возможно скомпилировать и запустить без использования тяжеловесных сред разработки, введя в командной строке ОС две команды:
|
||||||
\begin{itemize}
|
\begin{itemize}
|
||||||
\item javac <Name.java> скомпилирует файл исходников и создаст в этой же папке файл с байт-кодом;
|
\item javac <Name.java> скомпилирует файл исходников и создаст в этой же папке файл с байт-кодом;
|
||||||
|
@ -398,10 +403,27 @@ Here is your number: 4.
|
||||||
\item \code{{@code "public"}} вставка кода в описание
|
\item \code{{@code "public"}} вставка кода в описание
|
||||||
\end{itemize}
|
\end{itemize}
|
||||||
|
|
||||||
|
\subsubsection{Задания для самопроверки}
|
||||||
|
\begin{enumerate}
|
||||||
|
\item Javadoc находится в JDK или JRE?
|
||||||
|
\item Что делает утилита Javadoc?
|
||||||
|
\begin{itemize}
|
||||||
|
\item Создаёт комментарии в коде;
|
||||||
|
\item Создаёт программную документацию;
|
||||||
|
\item Создаёт веб-страницу с документацией из комментариев.
|
||||||
|
\end{itemize}
|
||||||
|
\end{enumerate}
|
||||||
|
|
||||||
|
\subsection{Собери его, если сможешь (Makefile, Docker)}
|
||||||
|
В подразделе \hrf{subsec:cli} мы проговорили о сборке проектов вручную.
|
||||||
|
\begin{frm}
|
||||||
|
Внимание поклонникам войны за пробелы против табов в тексте программы: в Makefile для отступов при описании таргетов нельзя использовать пробелы. Только табы. Иначе make обнаруживает ошибку синтаксиса.
|
||||||
|
\end{frm}
|
||||||
\subsection*{Домашнее задание}
|
\subsection*{Домашнее задание}
|
||||||
\begin{itemize}
|
\begin{itemize}
|
||||||
\item Создать проект из трёх классов (основной с точкой входа и два класса в другом пакете), которые вместе должны составлять одну программу, позволяющую производить четыре основных математических действия и осуществлять форматированный вывод результатов пользователю.
|
\item Создать проект из трёх классов (основной с точкой входа и два класса в другом пакете), которые вместе должны составлять одну программу, позволяющую производить четыре основных математических действия и осуществлять форматированный вывод результатов пользователю;
|
||||||
\item Скомпилировать проект, а также создать для этого проекта стандартную веб-страницу с документацией ко всем пакетам.
|
\item Скомпилировать проект, а также создать для этого проекта стандартную веб-страницу с документацией ко всем пакетам;
|
||||||
|
\item Создать Makefile с задачами сборки, очистки и создания документации на весь проект.
|
||||||
\end{itemize}
|
\end{itemize}
|
||||||
|
|
||||||
\section{Управление проектом: сборщики проектов}
|
\section{Управление проектом: сборщики проектов}
|
||||||
|
|
Binary file not shown.
Binary file not shown.
|
@ -309,6 +309,61 @@
|
||||||
\end{frame}
|
\end{frame}
|
||||||
\note{...}
|
\note{...}
|
||||||
|
|
||||||
|
\begin{frame}
|
||||||
|
\frametitle{Автоматизация сборки в CLI}
|
||||||
|
makefile
|
||||||
|
\end{frame}
|
||||||
|
\note{...}
|
||||||
|
|
||||||
|
\begin{frame}
|
||||||
|
\frametitle{Автоматизация сборки в CLI}
|
||||||
|
SRCDIR := src
|
||||||
|
OUTDIR := out
|
||||||
|
|
||||||
|
JC := javac
|
||||||
|
JCFLAGS := -sourcepath .(SRCDIR)/ -d (OUTDIR)
|
||||||
|
MAINSOURCE := ru/gb/dj/Main
|
||||||
|
MAINCLASS := ru.gb.dj.Main
|
||||||
|
|
||||||
|
all:
|
||||||
|
(JC) (JCFLAGS) {SRCDIR}/{MAINSOURCE}.java
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -R (OUTDIR)
|
||||||
|
|
||||||
|
run:
|
||||||
|
cd out \&\& java {MAINCLASS}
|
||||||
|
|
||||||
|
\end{frame}
|
||||||
|
\note{...}
|
||||||
|
|
||||||
|
\begin{frame}
|
||||||
|
\frametitle{Автоматизация сборки в CLI, контейнеризация}
|
||||||
|
docker
|
||||||
|
\end{frame}
|
||||||
|
\note{...}
|
||||||
|
|
||||||
|
\begin{frame}
|
||||||
|
\frametitle{Автоматизация сборки в CLI, контейнеризация}
|
||||||
|
\# syntax=docker/dockerfile:1
|
||||||
|
|
||||||
|
FROM bellsoft/liberica-openjdk-alpine:11.0.16.1-1
|
||||||
|
|
||||||
|
\# from where (related to Dockerfile) to where
|
||||||
|
COPY ./src ./src
|
||||||
|
|
||||||
|
\# remember that you are root and in / directory
|
||||||
|
RUN mkdir ./out
|
||||||
|
|
||||||
|
\# be sure to use relative paths
|
||||||
|
RUN javac -sourcepath ./src -d out ./src/ru/gb/dj/Main.java
|
||||||
|
|
||||||
|
\# what will we do on a container start
|
||||||
|
CMD java -classpath ./out ru.gb.dj.Main
|
||||||
|
\end{frame}
|
||||||
|
\note{...}
|
||||||
|
|
||||||
|
|
||||||
\begin{frame}
|
\begin{frame}
|
||||||
\frametitle{итоги}
|
\frametitle{итоги}
|
||||||
что изучили и домашка
|
что изучили и домашка
|
||||||
|
|
|
@ -20,7 +20,7 @@
|
||||||
\item изучим простую структуру проекта и способы его запуска
|
\item изучим простую структуру проекта и способы его запуска
|
||||||
\item коротко рассмотрим утилиту джавадок
|
\item коротко рассмотрим утилиту джавадок
|
||||||
\end{itemize}
|
\end{itemize}
|
||||||
Рассмотрим примитивный инструментарий и базовые возможности платформы для разработки приложений на языке Java.
|
Рассмотрим примитивный инструментарий и базовые возможности платформы для разработки приложений на языке Java. В конце урока рассмотрим альтернативные способы сборки проектов, популярные и не очень.
|
||||||
|
|
||||||
% -----------------------------------------------------------------------------------
|
% -----------------------------------------------------------------------------------
|
||||||
\showslide{build/jc-1-b.pdf}
|
\showslide{build/jc-1-b.pdf}
|
||||||
|
@ -86,6 +86,8 @@
|
||||||
\showslide{build/jc-1-b.pdf}
|
\showslide{build/jc-1-b.pdf}
|
||||||
Если внимательно посмотреть на компании, внесшие вклад в развитие открытой части инструментария, начиная с ждк11 и до актуального на сегодня ждк18, конечно, максимально вкладывается оракл, но и беллсофт, производитель либерики, там будет в первой десятке. Повторюсь, я на курсе буду использовать либерику ждк11, благо для неё есть и докер-образ, если нужно как-то автоматизировать сборки вашего приложения, например; вы можете использовать любую другую не старше 8. Все примеры я буду приводить с учётом именно 8й версии языка, чтобы рассмотреть подходящий подавляющему большинству людей инструментарий. Если у вас уже установлена 11я версия от другого вендора - ничего менять не нужно, если установлена более новая версия, есть вероятность, что некоторые примеры будут отмечаться как чрезвычайно устаревшие, возможно, эти предупреждения на этапе обучения следует игнорировать. Для выбора вендора внимательно ознакомьтесь с лицензией, а для выбора версии языка руководствуйтесь здравым смыслом: большинство компаний в России и мире работают на 8, 11 или 13й версиях. Зачем учиться на какой-нибудь 18-й версии, если потом на работе вы не увидите половины каких-нибудь новых фич и фактически, придётся переучиваться?
|
Если внимательно посмотреть на компании, внесшие вклад в развитие открытой части инструментария, начиная с ждк11 и до актуального на сегодня ждк18, конечно, максимально вкладывается оракл, но и беллсофт, производитель либерики, там будет в первой десятке. Повторюсь, я на курсе буду использовать либерику ждк11, благо для неё есть и докер-образ, если нужно как-то автоматизировать сборки вашего приложения, например; вы можете использовать любую другую не старше 8. Все примеры я буду приводить с учётом именно 8й версии языка, чтобы рассмотреть подходящий подавляющему большинству людей инструментарий. Если у вас уже установлена 11я версия от другого вендора - ничего менять не нужно, если установлена более новая версия, есть вероятность, что некоторые примеры будут отмечаться как чрезвычайно устаревшие, возможно, эти предупреждения на этапе обучения следует игнорировать. Для выбора вендора внимательно ознакомьтесь с лицензией, а для выбора версии языка руководствуйтесь здравым смыслом: большинство компаний в России и мире работают на 8, 11 или 13й версиях. Зачем учиться на какой-нибудь 18-й версии, если потом на работе вы не увидите половины каких-нибудь новых фич и фактически, придётся переучиваться?
|
||||||
|
|
||||||
|
Из-за обилия вендоров и версий, которые нужно поддерживать, создаётся необходимость в автоматизации переключения между версиями. На помощь приходят инструменты, наподобие SDKMan, написанные на языке bash, позволяющие осуществить этот самый рутинный и утомительный менеджмент. Очевидным недостатком SDKMan является то, что помимо самого СДКМан нужно установить требующиеся версии и варианты ЖДК специальными внутренними командами. Хотя, например, можно перевести приложение в режим офлайн и попробовать как-то поплясать с бубном вокруг настроек. Думаю, что если в команде используется этот инструмент, для него уже есть все необходимые скрипты настроек и автоматизации. Есть и другие варианты, об одном из них (Docker) мы поговорим позднее в этой лекции.
|
||||||
|
|
||||||
% -----------------------------------------------------------------------------------
|
% -----------------------------------------------------------------------------------
|
||||||
\showslide{build/jc-1-b.pdf}
|
\showslide{build/jc-1-b.pdf}
|
||||||
Для решения некоторых несложных задач курса мы будем писать простые приложения, не содержащие ООП, сложных взаимосвязей и проверок, в этом случае нам понадобится Jupyter notebook с установленным ядром (kernel) IJava. Да, многие думают, что Jupyter ноутбуки - это только для языка пайтон или для скриптовых языков, но это не так. Архитектура юпитер ноутбука позволяет ему работать с любым ядром, главное, чтобы ядро умело корректно интерпретировать написанное в ячейке с кодом. Ядро IJava делает именно это - интерпретирует Java-код, используя установленный на компьютере разработчика JDK.
|
Для решения некоторых несложных задач курса мы будем писать простые приложения, не содержащие ООП, сложных взаимосвязей и проверок, в этом случае нам понадобится Jupyter notebook с установленным ядром (kernel) IJava. Да, многие думают, что Jupyter ноутбуки - это только для языка пайтон или для скриптовых языков, но это не так. Архитектура юпитер ноутбука позволяет ему работать с любым ядром, главное, чтобы ядро умело корректно интерпретировать написанное в ячейке с кодом. Ядро IJava делает именно это - интерпретирует Java-код, используя установленный на компьютере разработчика JDK.
|
||||||
|
@ -244,9 +246,50 @@ javadoc -locale ru_RU -encoding utf-8 -docencoding cp1251 \
|
||||||
\end{verbatim}
|
\end{verbatim}
|
||||||
Поскольку я сейчас не с виндоусом, то такие настройки наоборот, сломают отображение.
|
Поскольку я сейчас не с виндоусом, то такие настройки наоборот, сломают отображение.
|
||||||
|
|
||||||
|
\subsubsection{Задания для самопроверки}
|
||||||
|
\begin{enumerate}
|
||||||
|
\item Javadoc находится в JDK или JRE? (ждк)
|
||||||
|
\item Что делает утилита Javadoc? (3)
|
||||||
|
\begin{itemize}
|
||||||
|
\item Создаёт комментарии в коде;
|
||||||
|
\item Создаёт программную документацию;
|
||||||
|
\item Создаёт веб-страницу с документацией из комментариев.
|
||||||
|
\end{itemize}
|
||||||
|
\end{enumerate}
|
||||||
|
|
||||||
% -----------------------------------------------------------------------------------
|
% -----------------------------------------------------------------------------------
|
||||||
\showslide{build/jc-1-b.pdf}
|
\showslide{build/jc-1-b.pdf}
|
||||||
На этом уроке мы рассмотрели историю и причины создания языка, его окружение и структуру проекта, узнали, что скрывают в себе такие аббревиатуры как JDK JRE JVM SDK JIT CLI. Рассмотрели базовое применение утилит java, javac и javadoc. В качестве домашнего задания попробуйте
|
Компилировать проект руками — занятие весьма утомительное, особенно когда исходных файлов становится больше одного, и для каждого из них надо каждый раз набивать команды компиляции, а ещё не забыть о том, какой файл в проекте главный, какие включены библиотеки и многое другое. Руки так и тянутся куда-то это записать, чтобы не забыть, но говорить о специальных менеджерах проектов ещё рано, поэтому научимся автоматизировать терминальную сборку. Будем учиться создавать и использовать Мейкфайлы.
|
||||||
|
|
||||||
|
Makefile — это набор инструкций для программы make (классически, это GNU Automake), которая помогает собирать программный проект буквально в одну команду. Хотя эта технология и отмирает, но все равно используется как некоторыми отдельными разработчиками, так и в проектах, особенно часто это встречается, когда в Java переквалифицируются бывшие С++ программисты. Если запустить make то программа попытается найти файл с именем по-умолчанию Makefile в текущем каталоге и выполнить инструкции из него. Эти самые мейкфайлы и сохранят для нас все нужные настройки проекта, компиляции, структуры и прочего.
|
||||||
|
|
||||||
|
Не лишним будет напомнить, что мейкфайлы, не привносят ничего принципиально нового в процесс компиляции, а только лишь автоматизируют его, поэтому важно помнить, что все действия, которые мы совершаем при ручной компиляции просто записаны в мейкфайл, и обратно, то что записано в мейкфайле может быть выполнено вручную в терминале.
|
||||||
|
|
||||||
|
В простейшем, то есть нашем, случае, в мейкфайле достаточно описать так называемую цель, таргет, и что нужно сделать для достижения этой цели. Цель, собираемая по-умолчанию называется all, так, для простейшей компиляции нам нужно написать
|
||||||
|
\begin{verbatim}
|
||||||
|
all:
|
||||||
|
javac -sourcepath .src/ -d out src/ru/gb/jcore/sample/Main.java
|
||||||
|
\end{verbatim}
|
||||||
|
|
||||||
|
% -----------------------------------------------------------------------------------
|
||||||
|
\showslide{build/jc-1-b.pdf}
|
||||||
|
По сути, это всё. Но мы же хотим, чтобы вся было гибо и не нужно было запоминать что как называется, чтобы это потом можно было поправить где-то в одном месте. Для этого в мейкфайлах придумали переменные, и они работают как самые обычные переменные, их значение подставляется в то место, где переменная вызывается. Добавив пару таргетов и немного переменных мы получим мейкфайл как на слайде, он позволит нам не только компилировать проект, но также очищать выходные файлы в случае неудачи и запускать его. Также не особенно переживая о ключах, командах и прочем.
|
||||||
|
|
||||||
|
Для того, чтобы утилита мейк сделала своё дело нужно в терминале просто её вызвать без аргументов. Чтобы воспользоваться другими написанными таргетами (автоматизациями, задачами) нужно после имени утилиты написать через пробел название таргета, например, часто пишут задачу clean, рекурсивно очищающую папку с готовыми классами, соответственно, вызов make clean как ни странно, рекурсивно удалит папку с готовыми классами.
|
||||||
|
|
||||||
|
% -----------------------------------------------------------------------------------
|
||||||
|
\showslide{build/jc-1-b.pdf}
|
||||||
|
Docker — программное обеспечение для автоматизации развёртывания и управления приложениями, контейнеризатор приложений. Позволяет «упаковать» приложение со всем его окружением и зависимостями в контейнер, который может быть развёрнут почти на на любой системе, и уж точно на системах большой тройки (линукс виндоус макос).
|
||||||
|
|
||||||
|
Целью этого курса не является рассмотрение всех возможностей докер, поэтому ограничимся только теми, которые нам понадобятся, чтобы увидеть заветное, запущенное джавой, «привет мир» в терминале. Снова не лишним будет напомнить, что мы можем выполнить все те же самые действия в простом терминале. Но докер даёт нам немного преимуществ. Например, не нужно устанавливать JDK и думать о переключении между версиями, достаточно взять контейнер с нужной версией и запустить наше приложение в нём. Помните я буквально полчаса назад упоминал о том, что есть более абстрактный инструмент менеджмента версий языка и инструментария? вот, это он.
|
||||||
|
|
||||||
|
% -----------------------------------------------------------------------------------
|
||||||
|
\showslide{build/jc-1-b.pdf}
|
||||||
|
докерфайл
|
||||||
|
|
||||||
|
% -----------------------------------------------------------------------------------
|
||||||
|
\showslide{build/jc-1-b.pdf}
|
||||||
|
На этом уроке мы рассмотрели историю и причины создания языка, его окружение и структуру проекта, узнали, что скрывают в себе такие аббревиатуры как JDK JRE JVM SDK JIT CLI. Рассмотрели базовое применение утилит java, javac и javadoc. Даже немного посмотрели в сторону автоматизации рутинных задач. В качестве домашнего задания попробуйте
|
||||||
\begin{itemize}
|
\begin{itemize}
|
||||||
\item Создать проект из трёх классов (основной с точкой входа и два класса в другом пакете), которые вместе должны составлять одну программу, позволяющую производить четыре основных математических действия и осуществлять форматированный вывод результатов пользователю.
|
\item Создать проект из трёх классов (основной с точкой входа и два класса в другом пакете), которые вместе должны составлять одну программу, позволяющую производить четыре основных математических действия и осуществлять форматированный вывод результатов пользователю.
|
||||||
\item Скомпилировать проект, а также создать для этого проекта стандартную веб-страницу с документацией ко всем пакетам.
|
\item Скомпилировать проект, а также создать для этого проекта стандартную веб-страницу с документацией ко всем пакетам.
|
||||||
|
|
Loading…
Reference in New Issue