Fixing stuff
Renamed files due to template changes. Removed the template to avoid possible issues with GPLv3 licensing.
1
3/coursework/.gitignore
vendored
@ -1,3 +1,4 @@
|
||||
/template.typ
|
||||
*.pdf
|
||||
*.drawio.bkp
|
||||
other
|
||||
|
@ -1 +1 @@
|
||||
[Coursework](https://gitea.linerds.us/0x1D8/repo) paper, declared in [typst](https://typst.app/), using [this template](https://gitea.linerds.us/pencelheimer/typst_nure_template]).
|
||||
[Coursework](https://gitea.linerds.us/0x1D8/repo) paper, declared in [typst](https://typst.app/) v0.13, using [this template](https://gitea.linerds.us/pencelheimer/typst_nure_template).
|
||||
|
@ -27,7 +27,7 @@ iced:
|
||||
|
||||
sqlx:
|
||||
type: Web
|
||||
title: "GitHub - launchbadge/sqlx: 🧰 The Rust SQL Toolkit. An async, pure Rust SQL crate featuring compile-time checked queries without a DSL. Supports PostgreSQL, MySQL, and SQLite"
|
||||
title: "GitHub - launchbadge/sqlx: The Rust SQL Toolkit. An async, pure Rust SQL crate featuring compile-time checked queries without a DSL. Supports PostgreSQL, MySQL, and SQLite"
|
||||
author: GitHub
|
||||
url:
|
||||
value: https://github.com/launchbadge/sqlx/
|
||||
@ -115,7 +115,39 @@ aur:
|
||||
author: AUR (en) - Home
|
||||
url:
|
||||
value: https://aur.archlinux.org/
|
||||
date: 2025-02-09
|
||||
date: 2025-02-06
|
||||
|
||||
aur-search:
|
||||
type: Web
|
||||
title: AUR (en) - Packages
|
||||
author: AUR (en) - Home
|
||||
url:
|
||||
value: https://aur.archlinux.org/packages?O=0&K=librewolf
|
||||
date: 2025-02-06
|
||||
|
||||
aur-package:
|
||||
type: Web
|
||||
title: AUR (en) - librewolf-bin
|
||||
author: AUR (en) - Home
|
||||
url:
|
||||
value: https://aur.archlinux.org/packages/librewolf-bin
|
||||
date: 2025-02-06
|
||||
|
||||
aur-user:
|
||||
type: Web
|
||||
title: AUR (en) - Account lsf
|
||||
author: AUR (en) - Home
|
||||
url:
|
||||
value: https://aur.archlinux.org/account/lsf
|
||||
date: 2025-02-06
|
||||
|
||||
aur-search-func:
|
||||
type: Web
|
||||
title: AUR (en) - Packages
|
||||
author: AUR (en) - Home
|
||||
url:
|
||||
value: https://aur.archlinux.org/account/lsf
|
||||
date: 2025-02-06
|
||||
|
||||
archlinux: # I use Arch btw!
|
||||
type: Web
|
||||
|
Before Width: | Height: | Size: 259 KiB After Width: | Height: | Size: 259 KiB |
Before Width: | Height: | Size: 261 KiB After Width: | Height: | Size: 261 KiB |
Before Width: | Height: | Size: 180 KiB After Width: | Height: | Size: 180 KiB |
Before Width: | Height: | Size: 160 KiB After Width: | Height: | Size: 160 KiB |
Before Width: | Height: | Size: 118 KiB After Width: | Height: | Size: 118 KiB |
Before Width: | Height: | Size: 60 KiB After Width: | Height: | Size: 60 KiB |
Before Width: | Height: | Size: 69 KiB After Width: | Height: | Size: 69 KiB |
Before Width: | Height: | Size: 41 KiB After Width: | Height: | Size: 41 KiB |
Before Width: | Height: | Size: 76 KiB After Width: | Height: | Size: 76 KiB |
Before Width: | Height: | Size: 79 KiB After Width: | Height: | Size: 79 KiB |
Before Width: | Height: | Size: 71 KiB After Width: | Height: | Size: 71 KiB |
Before Width: | Height: | Size: 24 KiB After Width: | Height: | Size: 24 KiB |
Before Width: | Height: | Size: 30 KiB After Width: | Height: | Size: 30 KiB |
Before Width: | Height: | Size: 320 KiB After Width: | Height: | Size: 320 KiB |
Before Width: | Height: | Size: 38 KiB After Width: | Height: | Size: 38 KiB |
@ -1,5 +1,4 @@
|
||||
#import "template.typ": *
|
||||
#import "@preview/indenta:0.0.3": fix-indent
|
||||
|
||||
#let author = (
|
||||
name: "Білоус А. А.",
|
||||
@ -15,12 +14,12 @@
|
||||
degree: "Ст. викл. каф. ПІ",
|
||||
),
|
||||
(
|
||||
name: "Черепанова Ю. Ю.",
|
||||
name: "Русакова Н. Є.",
|
||||
gender: "f",
|
||||
degree: "Ст. викл. каф. ПІ",
|
||||
degree: "Доц. каф. ПІ",
|
||||
),
|
||||
(
|
||||
name: "Русакова Н. Є.",
|
||||
name: "Мазурова О.О.",
|
||||
gender: "f",
|
||||
degree: "Доц. каф. ПІ",
|
||||
),
|
||||
@ -28,7 +27,7 @@
|
||||
|
||||
#let task_list = (
|
||||
done_date: datetime(year: 2024, month: 12, day: 27),
|
||||
initial_data: datetime(year: 2024, month: 9, day: 15),
|
||||
initial_date: datetime(year: 2024, month: 9, day: 25),
|
||||
source: "методичні вказівки до виконання курсової роботи, вимоги до інформаційної системи, предметна область, що пов’язана з пакунковим репозиторієм та його менеджментом.",
|
||||
content: "вступ, аналіз предметної області; постановка задачі; проектування бази даних; опис програми; висновки; перелік джерел посилання.",
|
||||
graphics: "загальна діаграма класів, ER-діаграма, UML-діаграми, DFD-діаграма, схема БД в 1НФ, 2НФ, 3НФ, копії екранів (“скриншоти”) прикладної програми, приклади звітів прикладної програми.",
|
||||
@ -36,28 +35,26 @@
|
||||
|
||||
#let calendar_plan = (
|
||||
plan_table: [
|
||||
// thanks Yehor
|
||||
#table(
|
||||
columns: 4,
|
||||
align: (center, left, center, center),
|
||||
[Номер], [Назва етапів курсової роботи], [Строк виконання етапів роботи], [Примітки],
|
||||
[1], [Аналіз предметної області], [15.09.24 – 24.09.24], [Виконано],
|
||||
[2], [Концептуальне моделювання], [24.09.24-30.09.24], [~],
|
||||
[2], [Постановка задачі], [28.09.24 – 2.10.24], [Виконано],
|
||||
[3], [Побудова ER-діаграми та схеми БД], [2.10.24 – 18.10.24], [Виконано],
|
||||
[4], [Оформлення розділів 1, 2 та 3.1, 3.2 пояснювальної записки], [10.10.24 - 18.10.24], [Виконано],
|
||||
[1], [Аналіз предметної області], [25.09.24 - 30.09.24], [Виконано],
|
||||
[2], [Концептуальне моделювання], [30.09.24 - 3.10.24], [Виконано],
|
||||
[2], [Постановка задачі], [3.10.24 - 10.10.24], [Виконано],
|
||||
[3], [Побудова ER-діаграми та схеми БД], [10.10.24 - 15.10.24], [Виконано],
|
||||
[4], [Оформлення розділів 1, 2 та 3.1, 3.2 пояснювальної записки], [15.10.24 - 18.10.24], [Виконано],
|
||||
[5], [Перша контрольна точка з курсової роботи], [20.10.24], [Виконано],
|
||||
[6], [Нормалізація бази даних], [20.10.24 - 15.11.24], [Виконано],
|
||||
[7], [Створення програми], [20.10.24 – 20.11.24], [Виконано],
|
||||
[7], [Створення програми], [20.10.24 - 20.11.24], [Виконано],
|
||||
[8], [Тестування програми, наповнення бази даних], [20.11.24 - 5.12.24], [Виконано],
|
||||
[9], [Друга контрольна точка з курсової роботи], [7.12.24], [Виконано],
|
||||
[10], [Реалізація остаточної версії програми], [7.12.24-15.12.24], [Виконано],
|
||||
[11], [Оформлення інших розділів пояснювальної записки], [1.11.24 – 25.12.24], [Виконано],
|
||||
[10], [Реалізація остаточної версії програми], [7.12.24 - 15.12.24], [Виконано],
|
||||
[11], [Оформлення інших розділів пояснювальної записки], [1.11.24 - 25.12.24], [Виконано],
|
||||
[12], [Третя контрольна точка з курсової роботи], [27.12.24], [Виконано],
|
||||
)
|
||||
|
||||
],
|
||||
approval_date: datetime(year: 2024, month: 12, day: 27),
|
||||
approval_date: datetime(year: 2024, month: 09, day: 25),
|
||||
)
|
||||
|
||||
#let abstract = (
|
||||
@ -71,16 +68,16 @@
|
||||
"SQL",
|
||||
),
|
||||
text: [
|
||||
Мета даної роботи -- проєктування та розробка інформаційної системи "Репозиторій пакунків. Колаборація над пакунками", яка спрямована на створення ефективного середовища для спільної розробки та управління програмними пакунками. Система забезпечує зберігання інформації про програмні пакунки, а також надає інструменти для їх вдосконалення колективною співпрацею користувачів.
|
||||
Мета даної роботи -- проєктування та розробка інформаційної системи "Репозиторій пакунків. Колаборація над пакунками" спрямованої на забезпечення надійного зберігання інформації про програмні пакунки,та надання інструментів для колективної співпраці користувачів, що забезпечить ефективне середовище для спільної розробки та управління програмними пакунками.
|
||||
|
||||
Для реалізації інформаційної системи було обрано сучасний стек технологій, а саме:
|
||||
Rust@rust -- як основна мова програмування для всих частин застосунку,
|
||||
iced@iced -- бібліотека для побудови графічних інтерфейсів з Elm архітектурою,
|
||||
SQLx@sqlx -- бібліотека для низькорівневої роботи з базою даних, що забезпечує коректність і гнучкість,
|
||||
MySQL@mysql -- як СУБД для зберігання інформації про пакунки, користувачів, та їх відносини,
|
||||
Neovim@neovim -- як сучасний редактор коду для швидкої і зручної розробки.
|
||||
Rust -- як основна мова програмування для всих частин застосунку,
|
||||
iced -- бібліотека для побудови графічних інтерфейсів з Elm архітектурою,
|
||||
SQLx -- бібліотека для низькорівневої роботи з базою даних, що забезпечує коректність SQL запитів і гнучкість,
|
||||
MySQL -- як СУБД для зберігання інформації про пакунки, користувачів, та їх відносини,
|
||||
Neovim -- як сучасний редактор коду для швидкої і зручної розробки.
|
||||
|
||||
Результат розробки -- комп'ютерна програма, яка дозволяє зберігати та відображати інформацію про користувачів, пакунки та їх відносини; генерувати статистику про користувача та його пакунки. Застосунок, створений з використанням мови програмування Rust є безпечним, правильним, надійним та швидким.
|
||||
Результат розробки -- комп'ютерна програма, яка дозволяє зберігати та відображати інформацію про користувачів, пакунки, та відносини між ними, а також генерувати статистику про користувача та його пакунки. Застосунок, створений з використанням мови програмування Rust є безпечним, правильним, надійним та швидким.
|
||||
],
|
||||
)
|
||||
|
||||
@ -113,8 +110,6 @@
|
||||
appendices: appendices,
|
||||
)
|
||||
|
||||
#show: fix-indent()
|
||||
|
||||
#nheading("Вступ")
|
||||
У сучасному світі істують мільйони пакунків з програмним забезпеченням, програмними бібліотеками та іншою інформацією.
|
||||
Інформаційні системи управління цими пакунками стали критично важливим елементом сучасної розробки програмного забезпечення. Їх значення особливо зросло з розвитком відкритого програмного забезпечення та модульного підходу до розробки, де кожен проект може залежати від десятків, сотень, або навіть тисяч сторонніх компонентів.
|
||||
@ -125,7 +120,7 @@
|
||||
|
||||
Весь застосунок написано мовою програмування Rust@rust, для графічного інтерфейсу використовується бібліотека iced@iced, для взаємодії з базою даних використвуєтсья бібліотека SQLx@sqlx. Інформація зберігається у базі даних MySQL@mysql. Розробка виконувалася у текстовому редакторі Neovim@neovim.
|
||||
|
||||
= АНАЛІЗ ТА КОНЦЕПТУАЛЬНЕ МОДЕЛЮВАННЯ ПРЕДМЕТНОЇ ОБЛАСТІ
|
||||
= Аналіз та концептуальне моделювання предметної області
|
||||
#v(-spacing)
|
||||
== Аналіз предметної області
|
||||
Дослідження предметної області є ключовим етапом у розробці інформаційної системи "Репозиторій пакунків. Колаборація над пакунками". Основною метою даного аналізу є визначення функціональних вимог та технічних особливостей системи, необхідних для ефективного управління програмними пакунками та забезпечення продуктивної співпраці розробників.
|
||||
@ -138,19 +133,19 @@
|
||||
|
||||
При відвідуванні головної сторінки AUR @aur_main можна побачити статиску свого акаунту, всього репозиторію а також останні оновлення пакунків. За допомогою поля пошуку можна перейти до сторінки пошуку пакунків @aur_search.
|
||||
|
||||
#img("img/aur/aur_main.png", "Головна сторінка AUR")
|
||||
#img("img/aur/main.png", "Головна сторінка AUR", [@aur])
|
||||
|
||||
#img("img/aur/aur_search.png", "Сторінка пошуку AUR")
|
||||
#img("img/aur/search.png", "Сторінка пошуку AUR", [@aur-search])
|
||||
|
||||
Зі сторінки пошуку пакунків можна перейти до сторінки інформації пакунку, або ж до сторінки користувача який супроводжує пакунку. На сторінці інформації пакунку @aur_package можна побачити що пакунок має базу пакунку, пошукові слова, ліцензії, різні ролі користувачів, інформацію про залежності, тощо. На сторінці інформації про користувача @aur_user можна побачити різні атрибути пов'язані з акаунтом.
|
||||
|
||||
#img("img/aur/aur_package.png", "Деталі пакунку в AUR")
|
||||
#img("img/aur/package.png", "Деталі пакунку в AUR", [@aur-package])
|
||||
|
||||
#img("img/aur/aur_user.png", "Деталі користувача в AUR")
|
||||
#img("img/aur/user.png", "Деталі користувача в AUR", [@aur-user])
|
||||
|
||||
Навігація по репозиторію здебільного здійснюється за допомогою гіперпосилань на сторінку пошуку де можна обрати досить багато критерій пошуку. Наприклад, при натисканні посилання "View this user's packages" в профілі користувача lsf, можна побачити всі пакунки котрі цей користувач підтримує @aur_search_func.
|
||||
|
||||
#img("img/aur/aur_search_func.png", "Фунціонал пошуку AUR")
|
||||
#img("img/aur/search_func.png", "Фунціонал пошуку AUR", [@aur-search-func])
|
||||
|
||||
В контексті розробки пакункового репозиторію важливо визначити основні ролі користувачів та їхні потреби. Розробники пакунків виступають основними користувачами системи, створюючи та підтримуючи програмні компоненти, в той час як інші учасники можуть долучатися до процесу тестування, рецензування та вдосконалення пакунків.
|
||||
|
||||
@ -189,9 +184,9 @@
|
||||
|
||||
Всі дані зберігатимуться в базі даних, яка містить пов'язані таблиці спроектовані таким чином, що б забезпечити цілістність і коректність даних в них. Розумне проектування бази даних забезпечить оптимізацію обробку, пошук та оновлення інформації. Кожному об'єкту предметної області, як от користувач, пакунок, база пакунку, залежності пакунків, відносини пакунків та роль користувача, буде відповідати певна таблиця. Для розуміння структури інформаційної системи спроектовано загаліну діаграму класів @class_diagram, яка є основою для проектування бази даних.
|
||||
|
||||
#img("img/class_diagram.png", "Загальна діаграма класів (рисунок виконаний самостійно)")
|
||||
#img("img/class_diagram.png", "Загальна діаграма класів")
|
||||
|
||||
Система буде зберігати наступні дані:
|
||||
Система буде зберігати наступні дані: // TODO: яка система? інформація з реального світу
|
||||
- об'єкт користувача буде зберігати інформацію про користувачів системи. Він буде містити ім'я користувача, електронну пошту, пароль, час останнього використання обілкового запису, та його час створення з оновленням. Ця інформація необхідна для автентифікації та авторизації користувачів, а також для аудиту дій користувачів в системі;
|
||||
- об'єкт бази пакунку буде зберігати базову інформацію про групи пакунків. Він дозволить об'єднувати пакунки зі спільними компонентами та користувачами. Містить ім'я та опис групи пакунків, а також час створення та останнього оновлення. Ця інформація дозволяє групувати пакунки за їх базовою функціональністю;
|
||||
- об'єкт типу ролі користувача буде описувати ролі користувачів у контексті груп пакунків. Містить ідентифікатор ролі, її ім'я та опис. Приклади ролей: submitter (відправник), packager (пакувальник), maintainer (супроводжуючий), flagger (позначник). Цей об'єкт визначає дозволи користувачів на певні дії з групами пакунків;
|
||||
@ -202,42 +197,44 @@
|
||||
- об'єкт виду відносин буде визначати типи відносин між пакунками (наприклад: конфліктує, надає, замінює). Містить ідентифікатор типу відношення та його назву. Цей об'єкт дозволяє класифікувати відносини між пакунками;
|
||||
- об'єкт відносин пакунків буде зберігати інформацію про відносини пакунків (конфлікти, надання, заміна). Містить архітектуру, вимоги, ідентифікатор пакунку, ідентифікатор типу відношення та ім'я пакунку-відношення. Ця інформація дозволяє визначити, які пакунки конфліктують з даним пакунком, які функції він надає, і які пакунки він замінює.
|
||||
|
||||
// TODO: Системи ще не має, тому немає можливості
|
||||
Користувач системи має можливість здійснювати пошук пакунків та перегляди їх інформацію, переходити до профілей користувачів та переглядати їх пакунки. Для наочного представлення процесів та потоків даних в системі під час виконання користувачем поставленої задачі створимо DFD-діаграму @data_diagram, що відображатиме послідовність кроків під час виконання користувачем цільової бізнес-задачі перегляду інформації про пакунок та отримання звіту з цієї інформації.
|
||||
|
||||
#img("img/data_diagram.png", "Діаграма потоків даних (рисунок виконано самостійно)")
|
||||
// Звіт як користувач позначається
|
||||
#img("img/data_diagram.png", "Діаграма потоків даних")
|
||||
|
||||
Для ефективного відображення інформаційних потреб користувачів необхідно побудувати діаграму варіантів використання (Use Case). Ця діаграма @usecase_diagram демонструє взаємодію між різними акторами системи, такими як користувачі, адміністратори та інші учасники, та функціональними можливостями системи, такими як управління пакунками, їх створення, перегляд, отримання інформації та інші операції. Діаграма варіантів використання дозволяє визначити основні сценарії взаємодії користувачів з системою, ідентифікувати ключові функції та процеси, що відбуваються під час цієї взаємодії, та забезпечити розробку системи, яка відповідає реальним потребам користувачів. Крім того, діаграма варіантів використання може бути використана для визначення пріоритетів функціональних можливостей системи, виявлення потенційних проблем та слабких місць у процесах взаємодії з користувачами, а також для оптимізації архітектури системи для забезпечення максимальної ефективності та зручності використання.
|
||||
Для ефективного відображення інформаційних потреб користувачів необхідно побудувати діаграму варіантів використання (Use Case). Ця діаграма @usecase_diagram демонструє взаємодію між різними акторами системи, такими як користувачі, адміністратори та інші учасники, та функціональними можливостями системи, такими як управління пакунками, їх створення, перегляд, отримання інформації та інші операції. Діаграма варіантів використання дозволяє визначити основні сценарії взаємодії користувачів з системою, ідентифікувати ключові функції та процеси, що відбуваються під час цієї взаємодії, та забезпечити розробку системи, яка відповідає реальним потребам користувачів. Крім того, діаграма варіантів використання може бути використана для визначення пріоритетів функціональних можливостей системи, виявлення потенційних проблем та слабких місць у процесах взаємодії з користувачами, а також для оптимізації архітектури системи для забезпечення максимальної ефективності та зручності використання.
|
||||
|
||||
#img("img/usecase_diagram.png", "Use-Case діаграма (рисунок виконаний самостійно)")
|
||||
#img("img/usecase_diagram.png", "Use-Case діаграма")
|
||||
|
||||
= Постановка задачі
|
||||
|
||||
Метою курсової роботи є розробка інформаційної системи "Репозиторій пакунків. Колаборація над пакунками", яка забезпечить ефективне зберігання, пошук, управління та спільну розробку програмних пакунків. Після аналізу предметної області було виділено наступні вимоги щодо функціоналу інформаційної системи:
|
||||
|
||||
+ Підтримка основних процесів управління пакунками та їх метаданими:
|
||||
+ підтримка основних процесів управління пакунками та їх метаданими:
|
||||
+ створення пакунків, їх оновлення та видалення;
|
||||
+ керування метаданими пакунків, включаючи назву, версію, веб-покликання на ресурс, ліцензію, опис та групу;
|
||||
+ додання, оновлення та видалення залежностей між пакунками, а саме: обов'язкова залежність, опціональна залежність, та залежність під час збірки пакунку;
|
||||
+ додання, оновлення та видалення відносин пакунків таких як: надання залежності, конфлікт з залежністю та заміна залежності.
|
||||
|
||||
+ Забезпечення системи користувацьких акаунтів:
|
||||
+ забезпечення системи користувацьких акаунтів:
|
||||
+ надійний механізм реєстрації та автентифікації користувачів;
|
||||
+ можливість видалення свого акаунту та передачі пакунків іншому користувачеві;
|
||||
+ механізм блокування недобросовісних користувачів.
|
||||
|
||||
+ Система прав користувачів над пакунками:
|
||||
+ система прав користувачів над пакунками:
|
||||
+ мітчик пакунку -- будь-який користувач котрий знаходить проблему в пакунку та помічає його з коментарем який описує цю проблему;
|
||||
+ автор пакунку -- користувач який створив пакунок, він володіє пакунком та може здійснювати всі процеси управління пакунком, в тому числі надавати права іншим користувачам;
|
||||
+ пакувальник пакунку -- користувач котрий має дозвіл на завантаження нових збірок пакунку до репозиторію;
|
||||
+ супроводжуючий пакунку -- користувач котрий був назначений автором як його заступник який може здійснювати всі процеси управління пакунком окрім назначення нових авторів і супроводжуючих та видалення пакунку.
|
||||
|
||||
+ Функції пошуку та категоризації:
|
||||
+ функції пошуку та категоризації: // TODO: більше категоризації
|
||||
+ пошук та фільтрація пакунків за веб-покликанням, назвою, групою, описом пакунку, описом групи, навзвою та описом пакунку, користувачем, помітчиком, пакувальником, подавачем та супроводжуючим пакунку;
|
||||
+ можливість точного та довільного пошуку;
|
||||
+ можливість точного та довільного пошуку пакунків в іформаційній системі;
|
||||
+ можливість вибору ліміту кількості результатів пошуку;
|
||||
+ сортування результатів за назвою пакунку, його версією, назвою групи, часом створення та часом останнього оновлення.
|
||||
|
||||
+ Надання аналітичної інформації:
|
||||
+ надання аналітичної інформації:
|
||||
+ статистика користувачів: загальна кількість користувачів, кількість активних та неактивних користувачів;
|
||||
+ статистика репозиторію: загальна кількість пакунків, кількість осиротілих пакунків, кількість пакунків доданих та оновлених за останній тиждень та кількість пакунків котрі ніколи не оновлювалися;
|
||||
+ інформація про залежності та відносини кожного пакунку з іншими пакунками;
|
||||
@ -272,7 +269,7 @@
|
||||
|
||||
Зобразимо визначені сутності та відповідні зв’язки у вигляді ER-діаграми @er_diagram.
|
||||
|
||||
#img("img/er_diagram.png", "ER-діаграма концептуальної моделі (рисунок виконаний самостійно)")
|
||||
#img("img/er_diagram.png", "ER-діаграма концептуальної моделі")
|
||||
|
||||
Отримана ER-діаграма буде використана для обрання та побудови логічної моделі бази даних.
|
||||
|
||||
@ -286,6 +283,8 @@
|
||||
|
||||
Обрана модель також враховує специфіку роботи з пакунками, їх залежностями та відношеннями, що є ключовим аспектом функціонування репозиторію пакунків. Це дозволяє ефективно відстежувати зміни в пакунках, керувати правами доступу користувачів та забезпечувати надійну основу для колаборації над пакунками.
|
||||
|
||||
// TODO: як були додані зовнішні ключі?
|
||||
|
||||
#figure(
|
||||
table(
|
||||
columns: 2,
|
||||
@ -322,7 +321,7 @@
|
||||
caption: [довідник атрибутів (таблиця виконана самостійно)],
|
||||
) <attributes>
|
||||
|
||||
#img("img/logic_model.png", "Логічна модель бази даних (рисунок виконаний самостійно)")
|
||||
#img("img/logic_model.png", "Логічна модель бази даних")
|
||||
|
||||
Побудована база даних відповідає умовам третьої нормальної форм, адже кожна таблиця має первинний ключ, всі атрибути є атомарними, всі не ключові атрибути знаходяться у повній функціональній залежності від відповідних первинних ключів, та у таблицях відсутні транзитивні залежності.
|
||||
|
||||
@ -369,7 +368,7 @@
|
||||
|
||||
Розмір ER-діаграми інформаційної системи містить понад 25 атрибутів, тому згідно з методичними вказівками з курсового проектування було обрано частину, що охоплює 5 взаємопов'язаних сутностей: "Користувач", "Пакунок", "База пакунку", "Тип ролі" та "Роль" @normal_er_frag. Така декомпозиція дозволяє детально опрацювати найбільш критичні аспекти системи, забезпечуючи при цьому можливість подальшого масштабування.
|
||||
|
||||
#img("img/normal/normal_er_frag.png", "Фрагмент ER-діаграми (рисунок виконаний самостійно)")
|
||||
#img("img/normal/er_frag.png", "Фрагмент ER-діаграми")
|
||||
|
||||
Відповідно до теорії реляційних баз даних, відношення вважається нормалізованим до першої нормальної форми (1НФ) за умови дотримання наступних критичних вимог: атомарності даних (кожне поле містить лише одне значення), унікальності ідентифікації записів через первинні ключі, відсутності порожніх значень у ключових полях, та незалежності від фізичного порядку розташування записів.
|
||||
|
||||
@ -377,7 +376,7 @@
|
||||
|
||||
При визначенні первинного ключа особлива увага приділяється семантичному аналізу даних. Зокрема можна помітити потребу бачити яку роль має користувач для кожного пакунку. Тому що найкращим ключовими атрибутами стануть "Пакунок id" та "Роль id". Ці атрибути надають можливість унікально ідентифікувати універсальне відношення та їх сполучення охоплює всі атрибути відношення.
|
||||
|
||||
#img("img/normal/normal_t.png", "Універсальне відношення T (рисунок виконаний самостійно)")
|
||||
#img("img/normal/t.png", "Універсальне відношення T")
|
||||
|
||||
Всі визначені атрибути є неподільними, а значення атомарні. Сполучений первиний ключ який складаєтсья з "Пакунок id" та "Роль id" дозволяє унікально ідентифікувати кожний кортеж. Ключові поля не мають порожніх значень, кортежі не мають фіксованого порядку, тому, універсальне вдношення Т знаходиться в першій нормальній формі.
|
||||
|
||||
@ -386,15 +385,16 @@
|
||||
Для перевірки чи знаходиться відношення Т в другій нормальній формі визначимо функціональні залежності атрибутів @normal_t_dep.
|
||||
|
||||
Можемо зробити висновок, що відношення не знаходиться в другій нормальній формі, адже деякі атрибути мають неповні функціональні залежності (залежать лише від частини ключа). Для приведення універсального відношення Т до другої нормальної форми виділимо з нього три універсальних відношення T1 та T2 виходячи з помічених раніше неповних функціональних залежностей @normal_t12.
|
||||
//TODO: обгрунтувати чому саме t1, t2
|
||||
|
||||
Відношення зберігають першу нормальну форму та не містять неповних функціональних залежностей, оскільки кожне з них має лише один ключовий атрибут. Таким чином, можна зробити висновок, що ці відношення відповідають вимогам другої нормальної форми.
|
||||
|
||||
#img(
|
||||
"img/normal/normal_t_dep.png",
|
||||
"Універсальне відношення T із визначеними залежностями (рисунок виконаний самостійно)",
|
||||
"img/normal/t_dep.png",
|
||||
"Універсальне відношення T із визначеними залежностями",
|
||||
)
|
||||
|
||||
#img("img/normal/normal_t12.png", "Універсальні відношення T1 та Т2 (рисунок виконаний самостійно)")
|
||||
#img("img/normal/t12.png", "Універсальні відношення T1 та Т2")
|
||||
|
||||
Для досягнення третьої нормальної форми (3НФ) таблиці мають бути в другій нормальній формі, a також в відношеннях не має бути транзитивних залежностей, тобто кожен неключовий атрибут повинен залежати безпосередньо від первинного ключа, а не через інші неключові атрибути.
|
||||
|
||||
@ -405,22 +405,22 @@
|
||||
|
||||
Винесемо з відношення Т1 два відношення "Тип ролі" та "Користувач" за допомогою ключів "Тип ролі id" та "Користувач id" відповідно. Після чого сформуємо відношення T3 в котрому залишимо тільки зовнішні ключі "Тип ролі id" та "Користувач id" @normal_t23.
|
||||
|
||||
#img("img/normal/normal_t23.png", [Відношення "Тип ролі", "Користувач", Т2 та Т3 (рисунок виконаний самостійно)])
|
||||
#img("img/normal/t23.png", [Відношення "Тип ролі", "Користувач", Т2 та Т3])
|
||||
|
||||
Можна помітити, що відношення Т2 та Т3 мають спільне відношення "База пакунку id". Утворимо відношення "Пакунок" та "Роль" виділив з відношень Т2 та Т3 відповідно відношення "База пакунку", залишимо на його місці ключ "База пакунку id".
|
||||
|
||||
#img(
|
||||
"img/normal/normal.png",
|
||||
[Відношення "Користувач", "Пакунок", "База пакунку", "Тип ролі" та "Роль" (рисунок виконаний самостійно)],
|
||||
[Відношення "Користувач", "Пакунок", "База пакунку", "Тип ролі" та "Роль"],
|
||||
)
|
||||
|
||||
Тепер необхідно перевірити отримані відношення на відповідність третій нормальній формі.
|
||||
|
||||
Всі відношення мають первинні ключі, їх атрибути є атомарними, тому відношення відповідають вимогам першої нормальної форми. Крім того, всі атрибути кожного відношення повністю функціонально залежать від первинного ключа, що у поєднанні з відповідністю першій нормальній формі дозволяє зробити висновок, що відношення відповідають другій нормальній формі. Оскільки жодне відношення не містить транзитивних залежностей, а також відповідає вимогам другої нормальної форми, можна зробити висновок, що відношення знаходяться у третій нормальній формі.
|
||||
|
||||
Побудуємо схему даних та позначимо зв'язки між сутностями @normal_link. Після цього порівняємо отриману схему даних з початковою ER-діаграмою для подальшого аналізу.
|
||||
Побудуємо схему даних та позначимо зв'язки між сутностями @normal_linked. Після цього порівняємо отриману схему даних з початковою ER-діаграмою для подальшого аналізу.
|
||||
|
||||
#img("img/normal/normal_link.png", "Побудована схема даних (рисунок виконаний самостійно)")
|
||||
#img("img/normal/linked.png", "Побудована схема даних")
|
||||
|
||||
Порівняння отриманої схеми даних з початковою ER-діаграмою @er_diagram показує їхню повну відповідність, що свідчить про успішну нормалізацію схеми даних до третьої нормальної форми. Це значить, що всі сутності, атрибути та зв'язки між ними були правильно ідентифіковані, а всі непотрібні залежності та повторення даних були усунуті. Це забезпечить ефективність та масштабованість інформаційної системи.
|
||||
|
||||
@ -447,7 +447,7 @@
|
||||
- пошу та категоризація пакунків за багатьма факторами;
|
||||
- надання аналітичної інформації про репозиторій, пакунки та користувачів.
|
||||
|
||||
Під час розробки було використано гексагональну архітектуру@hexagonal, також відому як "архітектура портів та адаптерів". Структура проекту складаєтсья з кількох рівнів @project_structure:
|
||||
Під час розробки було використано гексагональну архітектуру@hexagonal, також відому як "архітектура портів та адаптерів". Структура проекту складаєтсья з кількох рівнів @repo_structure:
|
||||
+ Шар взаємодії з базою даних (тека data):
|
||||
+ декларація інтерфейсу взаємодії (тека ports);
|
||||
+ імплементації взаємодії (тека adapters).
|
||||
@ -464,7 +464,7 @@
|
||||
+ запуск сервісів передаючи їм створені репозиторії;
|
||||
+ відображення та менеджмент графічних частин застосунку яким передаються сервіси.
|
||||
|
||||
#img("img/repo/project_structure.png", "Структура проєкту")
|
||||
#img("img/repo/structure.png", "Структура проєкту")
|
||||
|
||||
Проєкт має всі використані під час розробки ресурси, такі як SQL скрипти та Docker Compose@compose файли, за допомогою яких можна створити тестову базу даних та наповнити її даними.
|
||||
|
||||
@ -675,19 +675,19 @@ CREATE TABLE PackageRelations (
|
||||
|
||||
При запуску комп'ютерної програми стартовим екраном є сторінка логіну @repo_login. Користувачі з існуючими акаунтами можуть увійти у свій акаунт за допомогою пошти або юзернема та свого паролю який надійно та безпечно зберігається в базі даних у зашифрованому вигляді.
|
||||
|
||||
#img("img/repo/repo_login.png", "Сторінка логіну")
|
||||
#img("img/repo/login.png", "Сторінка логіну")
|
||||
|
||||
Якщо у користувача немає акаунту, то він може натиснути на кнопку реєстраці для переходу на сторікну реєстарції @repo_register. Щоб створити новий акаунт. Користувач має надати ім'я користувача, електрону пошту та пароль.
|
||||
|
||||
Форми логіну та реєстрації перевіряють дані на валідність та не будуть робити зайвих запитів, якщо надана інформація не відповідає правилам інформаційної системи. У випадку перевірок. які не можуть бути зроблені локально, система надішле запит до бази даних і відобразить результат у графічному інтерфейсі програми.
|
||||
|
||||
#img("img/repo/repo_register.png", "Сторінка реєстрації")
|
||||
#img("img/repo/register.png", "Сторінка реєстрації")
|
||||
|
||||
Після успішного логіну або реєстрації програма перейде на сторінку пошуку @repo_search, яка надає можливість шукати пакунки з багатьма способами фільтрування та сортування результатів. При наведені курсору миші на елементи пошуку можна побачити стисле пояснення їх функціоналу.
|
||||
|
||||
Назва пакунку, його бази та його веб-покликання на ресурс є інтерактивними. Якщо натиснути на назву пакунку, то відкриється вікно з переглядом інформації та статистики про пакунок. Якщо натиснути на назву бази пакунку, то відкриється відкно де буде інформація про базу пакунку. При натисканні на веб-покликання, воно відкриєтсья в веб-браузері, котрий стоїть за замовчуванням в операціній системі користувача.
|
||||
|
||||
#img("img/repo/repo_search.png", "Сторінка пошуку")
|
||||
#img("img/repo/search.png", "Сторінка пошуку")
|
||||
|
||||
Розглянемо на прикладі сторінки пошуку обробку запиту на основі даних з графічного інтерфейсу котрі ввів користувач.
|
||||
|
||||
@ -894,7 +894,7 @@ pub fn view(&self) -> Element<'static, Message> {
|
||||
entry
|
||||
.url
|
||||
.as_ref()
|
||||
.map_or("-".into(), |s|
|
||||
.map_or("-".into(), |s|
|
||||
|
||||
tip(
|
||||
url(&"link", Message::URLPressed(s.clone())),
|
||||
@ -931,3 +931,5 @@ pub fn view(&self) -> Element<'static, Message> {
|
||||
База даних спроектована на основі реляційної моделі та нормалізована до третьої нормальної форми, що забезпечує оптимальну структуру даних та відсутність їх надлишковості. Під час розробки було використано мову програмування Rust@rust, систему управління базами даних MySQL@mysql та графічну бібліотеку iced@iced. Крім того використовуєтсья контейнеризація за допомогою Docker@docker та Docker Compose@compose що забезпечує надійність роботи системи, її масштабованість та простоту розгортання в різних середовищах.
|
||||
|
||||
Розроблена інформаційна система значно спрощує процес управління та отримання інформації про програмні пакунки. Вона відповідає поставленим завданням та має потенціал подальшої реалізації завдяки використанню дуже модульної архітектури моделювання програмного забеспечення, відомої як Гексагональна архітектура@hexagonal.
|
||||
|
||||
// vim:sts=2:sw=2
|
||||
|
@ -1,653 +0,0 @@
|
||||
|
||||
/// numberless heading
|
||||
#let nheading(title) = heading(depth: 1, numbering: none, title)
|
||||
|
||||
/// fill horizontal space with a box and not an empty space
|
||||
#let hfill(width) = box(width: width, repeat(" ")) // NOTE: This is a HAIR SPACE (U+200A), not a regular space
|
||||
|
||||
/// make underlined cell with filled value
|
||||
#let uline(align: center, content) = underline[
|
||||
#if align != left { hfill(1fr) }
|
||||
#content
|
||||
#if align != right { hfill(1fr) }
|
||||
]
|
||||
|
||||
/// bold text
|
||||
#let bold(content) = text(weight: "bold")[#content]
|
||||
|
||||
/// captioned image with label derived from path
|
||||
#let img(path, caption) = [
|
||||
#figure(
|
||||
image(path),
|
||||
caption: caption,
|
||||
)
|
||||
#label(path.split("/").last().split(".").first())
|
||||
]
|
||||
|
||||
/// subjects list
|
||||
#let subjects = (
|
||||
"БД": "Бази даних",
|
||||
"ОПНJ": "Основи програмування на Java",
|
||||
"ОС": "Операційні системи",
|
||||
"ПП": "Проектний практикум",
|
||||
"СПМ": "Скриптові мови програмування",
|
||||
"Ф": "Філософія",
|
||||
)
|
||||
|
||||
/// education programs list
|
||||
#let edu_programs = (
|
||||
"ПЗПІ": (
|
||||
name: "Інженерія програмного забезпечення",
|
||||
number: 121,
|
||||
),
|
||||
)
|
||||
|
||||
#let month_gen(month) = (
|
||||
"січня",
|
||||
"лютого",
|
||||
"березня",
|
||||
"квітня",
|
||||
"травня",
|
||||
"червня",
|
||||
"липня",
|
||||
"серпня",
|
||||
"вересня",
|
||||
"жовтня",
|
||||
"листопада",
|
||||
"грудня",
|
||||
).at(month - 1)
|
||||
|
||||
/// spacing between lines
|
||||
#let spacing = 0.95em
|
||||
|
||||
#let style(it) = {
|
||||
set page(
|
||||
paper: "a4",
|
||||
margin: (top: 20mm, right: 10mm, bottom: 20mm, left: 25mm),
|
||||
number-align: top + right,
|
||||
numbering: (..numbers) => {
|
||||
if numbers.pos().at(0) != 1 {
|
||||
numbering("1", numbers.pos().at(0))
|
||||
}
|
||||
},
|
||||
)
|
||||
|
||||
set text(font: "Liberation Serif", size: 14pt, hyphenate: false, lang: "ua")
|
||||
set par(justify: true, first-line-indent: 1.25cm)
|
||||
set underline(evade: false)
|
||||
|
||||
// set 1.5 line spacing
|
||||
set block(spacing: spacing)
|
||||
set par(spacing: spacing)
|
||||
set par(leading: spacing)
|
||||
|
||||
// enums and lists
|
||||
let ua_alph_numbering() = {
|
||||
// INFO: This alphabet is not full, maybe it should be extended or maybe not.
|
||||
// I cant remember nor find proper formatting rules.
|
||||
// "абвгґдеєжзиіїйклмнопрстуфхцчшщьюя" (full alphabet)
|
||||
|
||||
let alphabet = "абвгдежиклмнпрстуфхцшщюя".split("")
|
||||
i => { alphabet.at(i) + ")" }
|
||||
}
|
||||
|
||||
set enum(numbering: ua_alph_numbering(), indent: 1.25cm, body-indent: 0.5cm)
|
||||
show enum: it => {
|
||||
set enum(indent: 0em, numbering: "1)")
|
||||
it
|
||||
}
|
||||
|
||||
set list(indent: 1.35cm, body-indent: 0.5cm, marker: [--])
|
||||
|
||||
// figures
|
||||
set figure.caption(separator: [ -- ])
|
||||
show figure.where(kind: table): set figure.caption(position: top)
|
||||
show figure.caption.where(kind: table): set align(left)
|
||||
|
||||
let img = counter("image")
|
||||
let tab = counter("table")
|
||||
|
||||
show figure.where(kind: image): set figure(
|
||||
numbering: (..) => {
|
||||
img.step()
|
||||
context str(counter(heading).get().at(0)) + "." + context img.display()
|
||||
},
|
||||
)
|
||||
show figure.where(kind: table): set figure(
|
||||
numbering: (..) => {
|
||||
tab.step()
|
||||
context str(counter(heading).get().at(0)) + "." + context tab.display()
|
||||
},
|
||||
)
|
||||
|
||||
// appearance of references to images and tables
|
||||
show ref: it => {
|
||||
let el = it.element
|
||||
|
||||
if el == none or not el.has("kind") {
|
||||
return it
|
||||
}
|
||||
|
||||
let el_name = if el.kind == image {
|
||||
"рис."
|
||||
} else if el.kind == table {
|
||||
"таблицю"
|
||||
} else {
|
||||
return it
|
||||
}
|
||||
|
||||
link(
|
||||
el.location(),
|
||||
[(див. #el_name #numbering(el.numbering))],
|
||||
)
|
||||
}
|
||||
|
||||
// TODO: Maybe this will be better. Must be investigated.
|
||||
//
|
||||
// set math.equation(numbering: (..num) =>
|
||||
// numbering("(1.1)", counter(heading).get().first(), num.pos().first())
|
||||
// )
|
||||
// set figure(numbering: (..num) =>
|
||||
// numbering("1.1", counter(heading).get().first(), num.pos().first())
|
||||
// )
|
||||
|
||||
show figure: it => {
|
||||
v(spacing * 2, weak: true)
|
||||
it
|
||||
v(spacing * 2, weak: true)
|
||||
}
|
||||
|
||||
// headings
|
||||
set heading(numbering: "1.1")
|
||||
|
||||
show heading.where(level: 1): it => {
|
||||
set align(center)
|
||||
set text(size: 14pt, weight: "semibold")
|
||||
|
||||
pagebreak(weak: true)
|
||||
upper(it)
|
||||
v(spacing * 2, weak: true)
|
||||
}
|
||||
show heading.where(level: 2): it => {
|
||||
set text(size: 14pt, weight: "regular")
|
||||
|
||||
v(spacing * 2, weak: true)
|
||||
block(width: 100%, spacing: 0em)[
|
||||
#h(1.25cm)
|
||||
#counter(heading).display(it.numbering)
|
||||
#it.body
|
||||
]
|
||||
v(spacing * 2, weak: true)
|
||||
}
|
||||
|
||||
// listings
|
||||
show raw: it => {
|
||||
let new_spacing = 0.5em
|
||||
set block(spacing: new_spacing)
|
||||
set par(
|
||||
spacing: new_spacing,
|
||||
leading: new_spacing,
|
||||
)
|
||||
set text(size: 11pt, font: "Courier New", weight: "semibold")
|
||||
|
||||
v(spacing * 2.5, weak: true)
|
||||
pad(it, left: 1.25cm)
|
||||
v(spacing * 2.5, weak: true)
|
||||
}
|
||||
|
||||
it
|
||||
}
|
||||
|
||||
/// DSTU 3008:2015 Template for NURE
|
||||
/// -> content
|
||||
/// - doc (content): Content to apply the template to.
|
||||
/// - title (str): Title of the document.
|
||||
/// - subject_shorthand (str): Subject short name.
|
||||
/// - department_gen (str): Department name in genitive form.
|
||||
/// - authors ((name: str, full_name_gen: str, variant: int, group: str, gender: str),): List of Authors dicts.
|
||||
/// - mentors ((name: str, gender: str, degree: str),): List of mentors dicts.
|
||||
/// - edu_program_shorthand (str): Education program shorthand.
|
||||
/// - task_list (done_date: datetime, initial_data: datetime, source: (content | str), content: (content | str), graphics: (content | str)): Task list object.
|
||||
/// - calendar_plan ( plan_table: (content | str), approval_date: datetime): Calendar plan object.
|
||||
/// - abstract (keywords: (str, ), text: (content | str)): Abstract object.
|
||||
/// - bib_path path: Path to the bibliography yaml file.
|
||||
/// - appendices ((title: str, content: content, ): List of appendices objects.
|
||||
#let cw-template(
|
||||
doc,
|
||||
title: "NONE",
|
||||
subject_shorthand: "NONE",
|
||||
department_gen: "Програмної інженерії",
|
||||
author: (),
|
||||
mentors: (),
|
||||
edu_program_shorthand: "ПЗПІ",
|
||||
task_list: (),
|
||||
calendar_plan: (),
|
||||
abstract: (),
|
||||
bib_path: "bibl.yml",
|
||||
appendices: (),
|
||||
) = {
|
||||
set document(title: title, author: author.name)
|
||||
|
||||
show: style
|
||||
|
||||
let bib-count = state("citation-counter", ())
|
||||
show cite: it => {
|
||||
it
|
||||
bib-count.update(((..c)) => (..c, it.key))
|
||||
}
|
||||
show bibliography: it => {
|
||||
set text(size: 0pt)
|
||||
it
|
||||
}
|
||||
|
||||
|
||||
let head_mentor = mentors.at(0)
|
||||
let edu_program = edu_programs.at(edu_program_shorthand)
|
||||
|
||||
// page 1
|
||||
[
|
||||
#set align(center)
|
||||
МІНІСТЕРСТВО ОСВІТИ І НАУКИ УКРАЇНИ
|
||||
|
||||
ХАРКІВСЬКИЙ НАЦІОНАЛЬНИЙ УНІВЕРСИТЕТ РАДІОЕЛЕКТРОНІКИ
|
||||
|
||||
\
|
||||
|
||||
Кафедра Програмної інженерії
|
||||
|
||||
\
|
||||
|
||||
ПОЯСНЮВАЛЬНА ЗАПИСКА
|
||||
|
||||
ДО КУРСОВОЇ РОБОТИ
|
||||
|
||||
з дисципліни: "#subjects.at(subject_shorthand, default: "NONE")"
|
||||
|
||||
Тема роботи: "#title"
|
||||
|
||||
\ \ \
|
||||
|
||||
#columns(2, gutter: 4cm)[
|
||||
#set align(left)
|
||||
|
||||
#if author.gender == "m" { [Виконав\ ] } else { [Виконала\ ] } ст. гр. #author.group
|
||||
|
||||
\
|
||||
Керівник:\
|
||||
#head_mentor.degree
|
||||
|
||||
\
|
||||
Робота захищена на оцінку
|
||||
|
||||
\
|
||||
Комісія:\
|
||||
#for mentor in mentors {
|
||||
[#mentor.degree\
|
||||
]
|
||||
}
|
||||
|
||||
#colbreak()
|
||||
#set align(left)
|
||||
|
||||
\
|
||||
#author.name
|
||||
|
||||
\ \
|
||||
#head_mentor.name
|
||||
|
||||
\
|
||||
#underline(" " * 35)
|
||||
|
||||
\ \
|
||||
#for mentor in mentors {
|
||||
[#mentor.name\
|
||||
]
|
||||
}
|
||||
]
|
||||
|
||||
#v(1fr)
|
||||
|
||||
Харків -- #task_list.done_date.display("[year]")
|
||||
|
||||
#pagebreak()
|
||||
]
|
||||
//
|
||||
|
||||
// page 2
|
||||
{
|
||||
uline([Харківський національний університет радіоелектроніки])
|
||||
|
||||
linebreak()
|
||||
linebreak()
|
||||
|
||||
grid(
|
||||
columns: (100pt, 1fr),
|
||||
bold([
|
||||
Кафедра
|
||||
Дисципліна
|
||||
Спеціальність
|
||||
]),
|
||||
{
|
||||
uline(align: left, department_gen)
|
||||
linebreak()
|
||||
uline(align: left, subjects.at(subject_shorthand))
|
||||
linebreak()
|
||||
uline(align: left, [#edu_program.number #edu_program.name])
|
||||
},
|
||||
)
|
||||
grid(
|
||||
columns: (1fr, 1fr, 1fr),
|
||||
gutter: 0.3fr,
|
||||
[#bold("Курс") #uline(2)], [#bold("Група") #uline(author.group)], [#bold("Семестр") #uline(3)],
|
||||
)
|
||||
|
||||
linebreak()
|
||||
linebreak()
|
||||
linebreak()
|
||||
|
||||
align(center, bold[ЗАВДАННЯ \ на курсову роботу студента])
|
||||
|
||||
linebreak()
|
||||
|
||||
uline(align: left)[_#author.full_name_gen _]
|
||||
|
||||
linebreak()
|
||||
linebreak()
|
||||
|
||||
bold[\1. Тема роботи:]
|
||||
uline[#title.]
|
||||
|
||||
linebreak()
|
||||
|
||||
{
|
||||
bold[\2. Строк здачі закінченої роботи:]
|
||||
uline(task_list.done_date.display("[day].[month].[year]"))
|
||||
hfill(10fr)
|
||||
}
|
||||
|
||||
linebreak()
|
||||
|
||||
bold[\3. Вихідні дані для роботи:]
|
||||
uline(task_list.source)
|
||||
|
||||
linebreak()
|
||||
|
||||
bold[\4. Зміст розрахунково-пояснювальної записки:]
|
||||
uline(task_list.content)
|
||||
|
||||
linebreak()
|
||||
|
||||
bold[\5. Перелік графічного матеріалу:]
|
||||
uline(task_list.graphics)
|
||||
|
||||
linebreak()
|
||||
|
||||
{
|
||||
bold[\6. Строк здачі закінченої роботи:]
|
||||
uline(task_list.done_date.display("[day].[month].[year]"))
|
||||
hfill(10fr)
|
||||
}
|
||||
|
||||
pagebreak()
|
||||
}
|
||||
|
||||
// page 3
|
||||
{
|
||||
align(center, bold[КАЛЕНДАРНИЙ ПЛАН])
|
||||
|
||||
linebreak()
|
||||
|
||||
calendar_plan.plan_table
|
||||
|
||||
linebreak()
|
||||
|
||||
grid(
|
||||
columns: (5fr, 5fr),
|
||||
grid(
|
||||
columns: (1fr, 2fr, 1fr),
|
||||
gutter: 0.2fr,
|
||||
[
|
||||
Студент \
|
||||
Керівник \
|
||||
#align(center)["#underline[#calendar_plan.approval_date.day()]"]
|
||||
],
|
||||
[
|
||||
#uline(align: center, []) \
|
||||
#uline(align: center, []) \
|
||||
#uline(align: center, month_gen(calendar_plan.approval_date.month()))
|
||||
],
|
||||
[
|
||||
\ \
|
||||
#underline[#calendar_plan.approval_date.year()] р.
|
||||
],
|
||||
),
|
||||
[
|
||||
#author.name, \
|
||||
#head_mentor.degree
|
||||
#head_mentor.name.
|
||||
],
|
||||
)
|
||||
|
||||
pagebreak()
|
||||
}
|
||||
|
||||
// page 4 {{{
|
||||
[
|
||||
#align(center, bold([РЕФЕРАТ])) \
|
||||
|
||||
#context [
|
||||
#let pages = counter(page).final().at(0)
|
||||
#let tables = counter("table").final().at(0)
|
||||
#let images = counter("image").final().at(0)
|
||||
#let bibs = bib-count.final().dedup().len()
|
||||
|
||||
#let counters = ()
|
||||
|
||||
#if pages != 0 { counters.push([#pages с.]) }
|
||||
#if tables != 0 { counters.push([#tables табл.]) }
|
||||
#if images != 0 { counters.push([#images рис.]) }
|
||||
#if bibs != 0 { counters.push([#bibs джерел]) }
|
||||
|
||||
Пояснювальна записка до курсової роботи: #counters.join(", ").
|
||||
]
|
||||
|
||||
\
|
||||
|
||||
#{
|
||||
let keywords = abstract.keywords.map(upper)
|
||||
let is_cyrillic = word => word.split("").any(char => ("А" <= char and char <= "я"))
|
||||
|
||||
let n = keywords.len()
|
||||
for i in range(n) {
|
||||
for j in range(0, n - i - 1) {
|
||||
if (
|
||||
(not is_cyrillic(keywords.at(j)) and is_cyrillic(keywords.at(j + 1)))
|
||||
or (
|
||||
is_cyrillic(keywords.at(j)) == is_cyrillic(keywords.at(j + 1)) and keywords.at(j) > keywords.at(j + 1)
|
||||
)
|
||||
) {
|
||||
(keywords.at(j), keywords.at(j + 1)) = (keywords.at(j + 1), keywords.at(j))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
keywords.join(", ")
|
||||
}
|
||||
|
||||
\
|
||||
|
||||
#abstract.text
|
||||
]
|
||||
// }}}
|
||||
|
||||
// page 5
|
||||
outline(
|
||||
title: [
|
||||
ЗМІСТ
|
||||
#v(spacing * 2, weak: true)
|
||||
],
|
||||
depth: 2,
|
||||
indent: auto,
|
||||
)
|
||||
|
||||
doc
|
||||
|
||||
// bibliography
|
||||
{
|
||||
heading(depth: 1, numbering: none)[Перелік джерел посилання]
|
||||
|
||||
bibliography(
|
||||
bib_path,
|
||||
style: "ieee",
|
||||
full: true,
|
||||
title: none,
|
||||
)
|
||||
|
||||
let bib_data = yaml(bib_path)
|
||||
|
||||
let format-entry(citation) = {
|
||||
if (citation.type == "Web") {
|
||||
let date_array = citation.url.date.split("-")
|
||||
let date = datetime(
|
||||
year: int(date_array.at(0)),
|
||||
month: int(date_array.at(1)),
|
||||
day: int(date_array.at(2)),
|
||||
)
|
||||
[
|
||||
#citation.title.
|
||||
_#{citation.author}_.
|
||||
URL: #citation.url.value (дата звернення: #date.display("[day].[month].[year]")).
|
||||
]
|
||||
} else if citation.type == "Book" [
|
||||
#citation.author
|
||||
#citation.title.
|
||||
#citation.publisher,
|
||||
#citation.date.
|
||||
#citation.page-total c.
|
||||
] else [
|
||||
UNSUPPORTED BIBLIOGRAPHY ENTRY TYPE, PLEASE OPEN THE ISSUE
|
||||
]
|
||||
}
|
||||
|
||||
show enum.item: it => {
|
||||
box(width: 1.25cm)
|
||||
box(width: 1em + 0.5cm)[#it.number.]
|
||||
it.body
|
||||
linebreak()
|
||||
}
|
||||
|
||||
context {
|
||||
for (i, citation) in query(ref.where(element: none)).map(r => str(r.target)).dedup().enumerate() {
|
||||
enum.item(
|
||||
i + 1,
|
||||
format-entry(bib_data.at(citation)),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// appendices
|
||||
{
|
||||
counter(heading).update(0)
|
||||
|
||||
for (i, appendix) in appendices.enumerate() [
|
||||
#set heading(
|
||||
numbering: i => [
|
||||
Додаток #"АБВГДЕЖИКЛМНПРСТУФХЦШЩЮЯ".split("").at(i)
|
||||
],
|
||||
)
|
||||
|
||||
#show heading: it => {
|
||||
set align(center)
|
||||
set text(size: 14pt, weight: "regular")
|
||||
|
||||
pagebreak(weak: true)
|
||||
bold(upper(counter(heading).display(it.numbering)))
|
||||
linebreak()
|
||||
it.body
|
||||
v(spacing * 2, weak: true)
|
||||
}
|
||||
#heading(appendix.title)
|
||||
#appendix.content
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
/// DSTU 3008:2015 Template for NURE
|
||||
/// -> content
|
||||
/// - doc (content): Content to apply the template to.
|
||||
/// - doctype ("ЛБ" | "ПЗ"): Document type.
|
||||
/// - title (str): Title of the document.
|
||||
/// - subject_shorthand (str): Subject short name.
|
||||
/// - department_gen (str): Department name in genitive form.
|
||||
/// - worknumber (int): Number of the work, can be omitted.
|
||||
/// - authors ((name: str, full_name_gen: str, variant: int, group: str, gender: str),): List of Authors dicts.
|
||||
/// - mentor (name: str, gender: str, degree: str): Mentors objects.
|
||||
#let lab-pz-template(
|
||||
doc,
|
||||
doctype: "NONE",
|
||||
title: "NONE",
|
||||
subject_shorthand: "NONE",
|
||||
department_gen: "Програмної інженерії",
|
||||
worknumber: 1,
|
||||
authors: (),
|
||||
mentor: (),
|
||||
) = {
|
||||
set document(title: title, author: authors.at(0).name)
|
||||
|
||||
show: style
|
||||
|
||||
context counter(heading).update(worknumber - 1)
|
||||
|
||||
align(center)[
|
||||
МІНІСТЕРСТВО ОСВІТИ І НАУКИ УКРАЇНИ \
|
||||
ХАРКІВСЬКИЙ НАЦІОНАЛЬНИЙ УНІВЕРСИТЕТ РАДІОЕЛЕКТРОНІКИ
|
||||
|
||||
\ \
|
||||
Кафедра #department_gen
|
||||
|
||||
\ \ \
|
||||
Звіт \
|
||||
з
|
||||
#if doctype == "ЛБ" [лабораторної роботи] else [практичної роботи]
|
||||
#if worknumber != none [№ #worknumber]
|
||||
|
||||
з дисципліни: "#subjects.at(subject_shorthand, default: "UNLNOWN SUBJECT, PLEASE OPEN THE ISSUE")"
|
||||
|
||||
з теми: "#title"
|
||||
|
||||
\ \ \ \
|
||||
|
||||
#columns(2)[
|
||||
#set align(left)
|
||||
|
||||
#if authors.len() == 1 [
|
||||
#let author = authors.at(0)
|
||||
#if author.gender == "m" { [Виконав:\ ] } else { [Виконала:\ ] }
|
||||
ст. гр. #author.group\
|
||||
#author.name\
|
||||
#if author.variant != none { [Варіант: №#author.variant] }
|
||||
] else [
|
||||
Виконали:\
|
||||
ст. гр. #authors.at(0).group\
|
||||
#authors.map(a => [ #a.name\ ])
|
||||
]
|
||||
|
||||
#colbreak()
|
||||
#set align(right)
|
||||
|
||||
#if mentor.gender == "m" { [Перевірив:\ ] } else { [Перевірила:\ ] }
|
||||
#mentor.degree #if mentor.degree.len() >= 15 [\ ]
|
||||
#mentor.name\
|
||||
]
|
||||
|
||||
#v(1fr)
|
||||
|
||||
Харків -- #datetime.today().display("[year]")
|
||||
]
|
||||
|
||||
pagebreak(weak: true)
|
||||
|
||||
heading(title)
|
||||
doc
|
||||
}
|