Compare commits
3 Commits
548b9d70a6
...
9fb9f66f27
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9fb9f66f27 | ||
|
|
4c01c2fe11 | ||
|
|
dbea0e87fd |
1
.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
*build*
|
||||
BIN
semester-4/ОС/lb-1/Лр_1_Ситник_ПЗПІ_23_2.pdf
Normal file
@@ -1,4 +1,5 @@
|
||||
#import "@local/nure:0.0.0": *
|
||||
// #import "@local/nure:0.0.0": *
|
||||
#import "lib.typ": *
|
||||
|
||||
#show: lab-pz-template.with(
|
||||
doctype: "ЛБ",
|
||||
|
||||
BIN
semester-4/ОС/lb-2/Лр_2_Ситник_ПЗПІ_23_2.pdf
Normal file
@@ -1,4 +1,5 @@
|
||||
#import "@local/nure:0.0.0": *
|
||||
// #import "@local/nure:0.0.0": *
|
||||
#import "lib.typ": *
|
||||
|
||||
#show: lab-pz-template.with(
|
||||
doctype: "ЛБ",
|
||||
|
||||
692
semester-4/ОС/lb-3/lib.typ
Normal file
@@ -0,0 +1,692 @@
|
||||
|
||||
// Academic aliases {{{1
|
||||
|
||||
/// subject abbreviations to full names
|
||||
#let subjects = (
|
||||
"БД": "Бази даних",
|
||||
"ОПНJ": "Основи програмування на Java",
|
||||
"ОС": "Операційні системи",
|
||||
"ПП": "Проектний практикум",
|
||||
"СПМ": "Скриптові мови програмування",
|
||||
"Ф": "Філософія",
|
||||
)
|
||||
|
||||
/// education program abbreviations to name & number
|
||||
#let edu_programs = (
|
||||
"ПЗПІ": (
|
||||
name: "Інженерія програмного забезпечення",
|
||||
number: 121, // TODO: ПЗПІ is "F2" now
|
||||
),
|
||||
)
|
||||
|
||||
// Template formatting functions {{{1
|
||||
|
||||
/// 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]
|
||||
|
||||
/// month name from its number
|
||||
#let month_gen(month) = (
|
||||
"січня",
|
||||
"лютого",
|
||||
"березня",
|
||||
"квітня",
|
||||
"травня",
|
||||
"червня",
|
||||
"липня",
|
||||
"серпня",
|
||||
"вересня",
|
||||
"жовтня",
|
||||
"листопада",
|
||||
"грудня",
|
||||
).at(month - 1)
|
||||
|
||||
// Helper functions {{{1
|
||||
|
||||
/// captioned image with label derived from path:
|
||||
/// - "image.png" = @image
|
||||
/// - "img/image.png" = @image
|
||||
/// - "img/foo/image.png" = @foo_image
|
||||
/// - "img/foo/foo_image.png" = @foo_image
|
||||
/// the caption will be modified based on a conditional positional value:
|
||||
/// - `none`: no change
|
||||
/// - some value: "`caption` (за даними `value`)"
|
||||
/// - no value: "`caption` (рисунок виконано самостійно)"
|
||||
/// additional named arguments will be passed to original `image` function
|
||||
#let img(path, caption, ..sink) = {
|
||||
let parts = path.split(".").first().split("/")
|
||||
|
||||
let label_string = if parts.len() <= 2 or parts.at(-1).starts-with(parts.at(-2)) {
|
||||
// ("image",), (_, "image") and (.., "img", "img_image")
|
||||
parts.last()
|
||||
} else {
|
||||
// (.., "img", "image") = "img_image"
|
||||
parts.at(-2) + "_" + parts.at(-1)
|
||||
}.replace(" ", "_")
|
||||
|
||||
let caption = if sink.pos().len() == 0 {
|
||||
caption + " (рисунок виконано самостійно)"
|
||||
} else if sink.pos().first() == none {
|
||||
caption
|
||||
} else {
|
||||
[#caption (за даними #sink.pos().first())]
|
||||
}
|
||||
|
||||
[#figure(image(path, ..sink.named()), caption: caption) #label(label_string)]
|
||||
}
|
||||
|
||||
// Styling {{{1
|
||||
/// NOTE: may be wrong
|
||||
#let ua_alpha_numbering = "абвгдежиклмнпрстуфхцшщюя".split("") // 0 = "", 1 = "а"
|
||||
|
||||
// general outlook {{{2
|
||||
// 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: ("Times New Roman", "Liberation Serif"), size: 14pt, hyphenate: false, lang: "uk")
|
||||
set par(justify: true, first-line-indent: (amount: 1.25cm, all: true))
|
||||
set underline(evade: false)
|
||||
|
||||
// set 1.5 line spacing
|
||||
set block(spacing: spacing)
|
||||
set par(spacing: spacing)
|
||||
set par(leading: spacing)
|
||||
|
||||
// enums and lists {{{2
|
||||
set enum(numbering: i => { ua_alpha_numbering.at(i) + ")" }, 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 {{{2
|
||||
show figure: it => {
|
||||
v(spacing * 2, weak: true)
|
||||
it
|
||||
v(spacing * 2, weak: true)
|
||||
}
|
||||
|
||||
set figure.caption(separator: [ -- ])
|
||||
show figure.where(kind: table): set figure.caption(position: top)
|
||||
show figure.caption.where(kind: table): set align(left)
|
||||
|
||||
// figure numbering
|
||||
show heading.where(level: 1): it => {
|
||||
counter(math.equation).update(0)
|
||||
counter(figure.where(kind: image)).update(0)
|
||||
counter(figure.where(kind: table)).update(0)
|
||||
counter(figure.where(kind: raw)).update(0)
|
||||
it
|
||||
}
|
||||
set math.equation(numbering: (..num) => numbering("(1.1)", counter(heading).get().at(0), num.pos().first()))
|
||||
set figure(numbering: (..num) => numbering("1.1", counter(heading).get().at(0), num.pos().first()))
|
||||
|
||||
// appearance of references to images and tables {{{2
|
||||
set ref(
|
||||
supplement: it => {
|
||||
if it == none or not it.has("kind") {
|
||||
it
|
||||
} else if it.kind == image {
|
||||
"див. рис."
|
||||
} else if it.kind == table {
|
||||
"див. таблицю"
|
||||
} else {
|
||||
it
|
||||
}
|
||||
},
|
||||
)
|
||||
show ref: it => {
|
||||
let el = it.element
|
||||
|
||||
if el == none or not el.has("kind") {
|
||||
return it
|
||||
}
|
||||
if el.kind != image and el.kind != table {
|
||||
return it
|
||||
}
|
||||
|
||||
[(#it)]
|
||||
}
|
||||
|
||||
// headings {{{2
|
||||
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)
|
||||
}
|
||||
|
||||
show heading.where(level: 3): 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)
|
||||
}
|
||||
|
||||
it
|
||||
}
|
||||
|
||||
// Coursework template {{{1
|
||||
|
||||
/// 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_date: 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 (content): Content with appendices.
|
||||
#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 {{{2
|
||||
[
|
||||
#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 {{{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.initial_date.display("[day].[month].[year]"))
|
||||
hfill(10fr)
|
||||
}
|
||||
|
||||
pagebreak()
|
||||
}
|
||||
|
||||
// page 3 {{{2
|
||||
{
|
||||
align(center, bold[КАЛЕНДАРНИЙ ПЛАН])
|
||||
set par(first-line-indent: 0pt)
|
||||
|
||||
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 {{{2
|
||||
[
|
||||
#align(center, bold[РЕФЕРАТ]) \
|
||||
|
||||
#context [
|
||||
#let pages = counter(page).final().at(0)
|
||||
#let images = query(figure.where(kind: image)).len()
|
||||
#let tables = query(figure.where(kind: table)).len()
|
||||
#let bibs = bib-count.final().dedup().len()
|
||||
/* TODO: why this stopped working?
|
||||
#let tables = counter(figure.where(kind: table)).final().at(0)
|
||||
#let images = counter(figure.where(kind: image)).final().at(0)*/
|
||||
|
||||
#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 {{{2
|
||||
outline(
|
||||
title: [
|
||||
ЗМІСТ
|
||||
#v(spacing * 2, weak: true)
|
||||
],
|
||||
depth: 2,
|
||||
indent: auto,
|
||||
)
|
||||
|
||||
doc
|
||||
|
||||
// bibliography {{{2
|
||||
{
|
||||
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 AN ISSUE
|
||||
]
|
||||
}
|
||||
|
||||
show enum.item: it => {
|
||||
set par(first-line-indent: 0pt)
|
||||
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 {{{2
|
||||
{
|
||||
counter(heading).update(0)
|
||||
|
||||
set heading(
|
||||
numbering: (i, ..nums) => {
|
||||
let char = upper(ua_alpha_numbering.at(i))
|
||||
if nums.pos().len() == 0 { char } else {
|
||||
char + "." + nums.pos().map(str).join(".")
|
||||
}
|
||||
},
|
||||
)
|
||||
|
||||
show heading.where(level: 1): it => {
|
||||
set align(center)
|
||||
set text(size: 14pt, weight: "regular")
|
||||
|
||||
pagebreak(weak: true)
|
||||
bold[ДОДАТОК #counter(heading).display(it.numbering)]
|
||||
linebreak()
|
||||
it.body
|
||||
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)
|
||||
}
|
||||
|
||||
appendices
|
||||
}
|
||||
}
|
||||
|
||||
// Laboratory work template {{{1
|
||||
|
||||
/// 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)
|
||||
|
||||
// page 1 {{{2
|
||||
align(center)[
|
||||
МІНІСТЕРСТВО ОСВІТИ І НАУКИ УКРАЇНИ \
|
||||
ХАРКІВСЬКИЙ НАЦІОНАЛЬНИЙ УНІВЕРСИТЕТ РАДІОЕЛЕКТРОНІКИ
|
||||
|
||||
\ \
|
||||
Кафедра #department_gen
|
||||
|
||||
\ \ \
|
||||
Звіт \
|
||||
з
|
||||
#if doctype == "ЛБ" [лабораторної роботи] else [практичної роботи]
|
||||
#if worknumber != none [№ #worknumber]
|
||||
|
||||
з дисципліни: "#subjects.at(subject_shorthand, default: "UNLNOWN SUBJECT, PLEASE OPEN AN ISSUE")"
|
||||
|
||||
з теми: "#title"
|
||||
|
||||
\ \ \ \
|
||||
|
||||
#columns(2)[
|
||||
#set align(left)
|
||||
#set par(first-line-indent: 0pt)
|
||||
#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
|
||||
}
|
||||
|
||||
// vim:sts=2:sw=2:fdl=0:fdm=marker:cms=/*%s*/
|
||||
BIN
semester-4/ОС/lb-3/Лр_3_Ситник_ПЗПІ_23_2.pdf
Normal file
@@ -1,4 +1,5 @@
|
||||
#import "@local/nure:0.0.0": *
|
||||
// #import "@local/nure:0.0.0": *
|
||||
#import "lib.typ": *
|
||||
|
||||
#show: lab-pz-template.with(
|
||||
doctype: "ЛБ",
|
||||
|
||||
BIN
semester-4/ОС/lb-4/Лр_4_Ситник_Малишкін_ПЗПІ_23_2.pdf
Normal file
BIN
semester-4/ОС/lb-5/Лр_5_Ситник_Малишкін_ПЗПІ_23_2.pdf
Normal file
7
semester-4/ОС/lb-6/README.md
Normal file
@@ -0,0 +1,7 @@
|
||||
> [!NOTE]
|
||||
> Викладач: Мельникова Р. В.
|
||||
>
|
||||
> Оцінка: -
|
||||
|
||||
> [!TIP]
|
||||
> Виконано для Linux в команді.
|
||||
21
semester-4/ОС/lb-6/doc.yaml
Normal file
@@ -0,0 +1,21 @@
|
||||
title: Керування пам'яттю. Частина 2
|
||||
subject: ОС
|
||||
doctype: ЛБ
|
||||
worknumber: 6
|
||||
mentors:
|
||||
- name: Мельнікова Р. В.,
|
||||
gender: f,
|
||||
degree: доц. каф. ПІ,
|
||||
edu_program: &EDU ПЗПІ
|
||||
university: ХНУРЕ
|
||||
authors:
|
||||
- name: Ситник Є. С.
|
||||
course: 2
|
||||
edu: *EDU
|
||||
gender: m
|
||||
group: 23-2
|
||||
- name: Малишкін. А. С.
|
||||
course: 2
|
||||
edu: *EDU
|
||||
gender: m
|
||||
group: 23-2
|
||||
BIN
semester-4/ОС/lb-6/img/cache-lru.png
Normal file
|
After Width: | Height: | Size: 309 KiB |
BIN
semester-4/ОС/lb-6/img/cache-result.png
Normal file
|
After Width: | Height: | Size: 51 KiB |
BIN
semester-4/ОС/lb-6/img/cache-test.png
Normal file
|
After Width: | Height: | Size: 248 KiB |
BIN
semester-4/ОС/lb-6/img/pages-clock.png
Normal file
|
After Width: | Height: | Size: 366 KiB |
BIN
semester-4/ОС/lb-6/img/pages-lru.png
Normal file
|
After Width: | Height: | Size: 410 KiB |
BIN
semester-4/ОС/lb-6/img/pages-optimal.png
Normal file
|
After Width: | Height: | Size: 398 KiB |
BIN
semester-4/ОС/lb-6/img/pages-result.png
Normal file
|
After Width: | Height: | Size: 9.3 KiB |
BIN
semester-4/ОС/lb-6/img/pages-test.png
Normal file
|
After Width: | Height: | Size: 167 KiB |
BIN
semester-4/ОС/lb-6/img/pass-check.png
Normal file
|
After Width: | Height: | Size: 231 KiB |
BIN
semester-4/ОС/lb-6/img/pass-hash.png
Normal file
|
After Width: | Height: | Size: 213 KiB |
BIN
semester-4/ОС/lb-6/img/pass-lock.png
Normal file
|
After Width: | Height: | Size: 187 KiB |
BIN
semester-4/ОС/lb-6/img/pass-table.png
Normal file
|
After Width: | Height: | Size: 968 KiB |
17
semester-4/ОС/lb-6/src/.clangd
Normal file
@@ -0,0 +1,17 @@
|
||||
CompileFlags:
|
||||
Add: [-Wall, -Wextra, -std=c++23, -DBUILD_SHARED]
|
||||
CompilationDatabase: build/
|
||||
|
||||
Diagnostics:
|
||||
UnusedIncludes: Strict
|
||||
|
||||
InlayHints:
|
||||
Enabled: Yes
|
||||
ParameterNames: Yes
|
||||
DeducedTypes: Yes
|
||||
|
||||
Index:
|
||||
Background: Build
|
||||
|
||||
Hover:
|
||||
ShowAKA: Yes
|
||||
15
semester-4/ОС/lb-6/src/Makefile
Normal file
@@ -0,0 +1,15 @@
|
||||
CXX := clang++
|
||||
CXXFLAGS := -std=c++23 -Iinclude -Wall -Wextra
|
||||
LDFLAGS := -lcrypto
|
||||
|
||||
TARGET := build/app
|
||||
SRC := main.cpp
|
||||
|
||||
.PHONY: all clean
|
||||
|
||||
all:
|
||||
@mkdir -p $(dir $(TARGET))
|
||||
@$(CXX) $(CXXFLAGS) $(SRC) -o $(TARGET) $(LDFLAGS)
|
||||
|
||||
clean:
|
||||
rm -rf build
|
||||
37
semester-4/ОС/lb-6/src/include/cache.hpp
Normal file
@@ -0,0 +1,37 @@
|
||||
#pragma once
|
||||
|
||||
#ifndef CACHE_LRU_HPP
|
||||
#define CACHE_LRU_HPP
|
||||
|
||||
#include <cstdint>
|
||||
#include <list>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
namespace cache {
|
||||
|
||||
class lru {
|
||||
public:
|
||||
lru(int32_t line_count, int32_t associativity);
|
||||
~lru() = default;
|
||||
|
||||
bool access(uint64_t address);
|
||||
|
||||
private:
|
||||
struct block_entry {
|
||||
uint64_t tag;
|
||||
};
|
||||
|
||||
int32_t _lines;
|
||||
int32_t _assoc;
|
||||
|
||||
std::vector<std::list<block_entry>> _cache_lines;
|
||||
std::vector<std::unordered_map<uint64_t, std::list<block_entry>::iterator>>
|
||||
_lookup;
|
||||
};
|
||||
|
||||
} // namespace cache
|
||||
|
||||
#include "../src/cache.cpp"
|
||||
|
||||
#endif
|
||||
84
semester-4/ОС/lb-6/src/include/locked_buffer.hpp
Normal file
@@ -0,0 +1,84 @@
|
||||
#pragma once
|
||||
|
||||
#ifndef SEC_LOCKED_BUFFER_HPP
|
||||
#define SEC_LOCKED_BUFFER_HPP
|
||||
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <stdexcept>
|
||||
#include <sys/mman.h>
|
||||
#include <unistd.h>
|
||||
|
||||
namespace sec {
|
||||
|
||||
template <typename T, std::size_t N> class locked_buffer {
|
||||
public:
|
||||
locked_buffer() {
|
||||
this->size_ = N * sizeof(T);
|
||||
this->ptr_ = static_cast<T *>(std::malloc(this->size_));
|
||||
if (!this->ptr_)
|
||||
throw std::bad_alloc();
|
||||
if (mlock(this->ptr_, this->size_) != 0) {
|
||||
std::free(this->ptr_);
|
||||
throw std::runtime_error("mlock failed");
|
||||
}
|
||||
}
|
||||
|
||||
~locked_buffer() noexcept {
|
||||
cleanse();
|
||||
if (this->ptr_) {
|
||||
munlock(this->ptr_, this->size_);
|
||||
std::free(this->ptr_);
|
||||
}
|
||||
}
|
||||
|
||||
locked_buffer(const locked_buffer &) = delete;
|
||||
locked_buffer &operator=(const locked_buffer &) = delete;
|
||||
|
||||
locked_buffer(locked_buffer &&other) noexcept
|
||||
: ptr_(other.ptr_), size_(other.size_) {
|
||||
other.ptr_ = nullptr;
|
||||
other.size_ = 0;
|
||||
}
|
||||
|
||||
locked_buffer &operator=(locked_buffer &&other) noexcept {
|
||||
if (this != &other) {
|
||||
cleanse();
|
||||
if (this->ptr_) {
|
||||
munlock(this->ptr_, this->size_);
|
||||
std::free(this->ptr_);
|
||||
}
|
||||
this->ptr_ = other.ptr_;
|
||||
this->size_ = other.size_;
|
||||
other.ptr_ = nullptr;
|
||||
other.size_ = 0;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
T *data() noexcept { return this->ptr_; }
|
||||
const T *data() const noexcept { return this->ptr_; }
|
||||
std::size_t size() const noexcept { return N; }
|
||||
|
||||
T &operator[](std::size_t i) { return this->ptr_[i]; }
|
||||
const T &operator[](std::size_t i) const { return this->ptr_[i]; }
|
||||
|
||||
T *begin() noexcept { return this->ptr_; }
|
||||
T *end() noexcept { return this->ptr_ + N; }
|
||||
const T *begin() const noexcept { return this->ptr_; }
|
||||
const T *end() const noexcept { return this->ptr_ + N; }
|
||||
|
||||
private:
|
||||
void cleanse() noexcept {
|
||||
if (this->ptr_) {
|
||||
std::memset(this->ptr_, 0, this->size_);
|
||||
}
|
||||
}
|
||||
|
||||
T *ptr_{nullptr};
|
||||
std::size_t size_{0};
|
||||
};
|
||||
|
||||
} // namespace sec
|
||||
|
||||
#endif
|
||||
44
semester-4/ОС/lb-6/src/include/paging.hpp
Normal file
@@ -0,0 +1,44 @@
|
||||
#pragma once
|
||||
|
||||
#ifndef PAGE_REPLACEMENT_HPP
|
||||
#define PAGE_REPLACEMENT_HPP
|
||||
|
||||
#include <cstdint>
|
||||
#include <vector>
|
||||
|
||||
namespace paging {
|
||||
|
||||
class replacer {
|
||||
public:
|
||||
explicit replacer(int32_t frame_count) : _frames(frame_count) {}
|
||||
virtual ~replacer() = default;
|
||||
|
||||
virtual int32_t run(const std::vector<int32_t> &pages) = 0;
|
||||
|
||||
protected:
|
||||
int32_t _frames;
|
||||
};
|
||||
|
||||
class optimal_replacer : public replacer {
|
||||
public:
|
||||
using replacer::replacer;
|
||||
int32_t run(const std::vector<int32_t> &pages) override;
|
||||
};
|
||||
|
||||
class clock_replacer : public replacer {
|
||||
public:
|
||||
using replacer::replacer;
|
||||
int32_t run(const std::vector<int32_t> &pages) override;
|
||||
};
|
||||
|
||||
class lru_replacer : public replacer {
|
||||
public:
|
||||
using replacer::replacer;
|
||||
int32_t run(const std::vector<int32_t> &pages) override;
|
||||
};
|
||||
|
||||
} // namespace paging
|
||||
|
||||
#include "../src/paging.cpp"
|
||||
|
||||
#endif
|
||||
68
semester-4/ОС/lb-6/src/include/password.hpp
Normal file
@@ -0,0 +1,68 @@
|
||||
#pragma once
|
||||
|
||||
#ifndef PASSWORD_HPP
|
||||
#define PASSWORD_HPP
|
||||
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
|
||||
#include "locked_buffer.hpp"
|
||||
|
||||
namespace sec {
|
||||
|
||||
enum class strength_t : uint8_t {
|
||||
very_weak = 0,
|
||||
weak,
|
||||
moderate,
|
||||
strong,
|
||||
very_strong
|
||||
};
|
||||
|
||||
class password_hash;
|
||||
|
||||
class password {
|
||||
public:
|
||||
explicit password(std::string pass);
|
||||
|
||||
std::string_view view() const noexcept;
|
||||
|
||||
static sec::password from_console();
|
||||
static sec::password from_string(const std::string &pass);
|
||||
|
||||
sec::password_hash to_hash() const;
|
||||
|
||||
private:
|
||||
sec::locked_buffer<char, 128> _buf;
|
||||
std::size_t _len{};
|
||||
};
|
||||
|
||||
class password_hash {
|
||||
public:
|
||||
explicit password_hash(std::string hash);
|
||||
const std::string &get() const noexcept;
|
||||
|
||||
bool verify(const sec::password &pwd) const;
|
||||
|
||||
private:
|
||||
std::string _hash;
|
||||
};
|
||||
|
||||
class manager {
|
||||
public:
|
||||
static bool has_lower(const sec::password &pwd);
|
||||
static bool has_upper(const sec::password &pwd);
|
||||
static bool has_digit(const sec::password &pwd);
|
||||
static bool has_spec_symbol(const sec::password &pwd);
|
||||
|
||||
static std::string hash_password(const sec::password &pwd);
|
||||
static sec::strength_t evaluate_strength(const sec::password &pwd);
|
||||
static uint64_t time_to_crack(const sec::password &pwd);
|
||||
static std::string format_duration(uint64_t seconds);
|
||||
};
|
||||
|
||||
} // namespace sec
|
||||
|
||||
#include "../src/password.cpp"
|
||||
|
||||
#endif
|
||||
73
semester-4/ОС/lb-6/src/main.cpp
Normal file
@@ -0,0 +1,73 @@
|
||||
#include <iostream>
|
||||
#include <print>
|
||||
#include <vector>
|
||||
|
||||
#include "include/cache.hpp"
|
||||
#include "include/paging.hpp"
|
||||
#include "include/password.hpp"
|
||||
|
||||
#include <openssl/sha.h>
|
||||
|
||||
int main() {
|
||||
std::vector<int> pages = {7, 0, 1, 2, 0, 3, 0, 4, 2, 3, 0, 3};
|
||||
int frames = 3;
|
||||
|
||||
paging::optimal_replacer opt(frames);
|
||||
paging::clock_replacer clk(frames);
|
||||
paging::lru_replacer lru(frames);
|
||||
|
||||
std::println("Optimal faults: {}", opt.run(pages));
|
||||
std::println("Clock faults: {}", clk.run(pages));
|
||||
std::println("LRU faults: {}", lru.run(pages));
|
||||
|
||||
std::println("\nCache LRU Simulation:");
|
||||
cache::lru cache(128, 4);
|
||||
std::vector<uint64_t> addresses = {
|
||||
0, 1024, 2048, 3072, 4096, 5120, 6144, 7168, 8192,
|
||||
};
|
||||
int32_t hits = 0, misses = 0;
|
||||
for (auto addr : addresses) {
|
||||
if (cache.access(addr)) {
|
||||
++hits;
|
||||
std::println("Address 0x{:x}:\t HIT", addr);
|
||||
} else {
|
||||
++misses;
|
||||
std::println("Address 0x{:x}:\t MISS", addr);
|
||||
}
|
||||
}
|
||||
std::println("Hits: {}, Misses: {}\n", hits, misses);
|
||||
|
||||
auto pwd = sec::password::from_console();
|
||||
auto strength = sec::manager::evaluate_strength(pwd);
|
||||
auto crack_time = sec::manager::time_to_crack(pwd);
|
||||
auto crack_str = sec::manager::format_duration(crack_time);
|
||||
|
||||
std::print("Password strength: ");
|
||||
switch (strength) {
|
||||
case sec::strength_t::very_weak:
|
||||
std::print("Very Weak");
|
||||
break;
|
||||
case sec::strength_t::weak:
|
||||
std::print("Weak");
|
||||
break;
|
||||
case sec::strength_t::moderate:
|
||||
std::print("Moderate");
|
||||
break;
|
||||
case sec::strength_t::strong:
|
||||
std::print("Strong");
|
||||
break;
|
||||
case sec::strength_t::very_strong:
|
||||
std::print("Very Strong");
|
||||
break;
|
||||
}
|
||||
std::print("\nEstimated time to crack: {} secs\n({})\n", crack_time,
|
||||
crack_str);
|
||||
|
||||
std::string input;
|
||||
std::print("\nEnter password to verify: ");
|
||||
std::getline(std::cin, input);
|
||||
auto input_pwd = sec::password::from_string(input);
|
||||
if (pwd.to_hash().verify(input_pwd)) {
|
||||
std::print("Password verified successfully.\n");
|
||||
}
|
||||
}
|
||||
38
semester-4/ОС/lb-6/src/src/cache.cpp
Normal file
@@ -0,0 +1,38 @@
|
||||
#pragma once
|
||||
|
||||
#include "../include/cache.hpp"
|
||||
|
||||
#include <cmath>
|
||||
|
||||
namespace cache {
|
||||
|
||||
cache::lru::lru(int32_t line_count, int32_t associativity)
|
||||
: _lines(line_count), _assoc(associativity), _cache_lines(line_count),
|
||||
_lookup(line_count) {}
|
||||
|
||||
bool cache::lru::access(uint64_t address) {
|
||||
uint64_t line = (address >> 6) % this->_lines;
|
||||
uint64_t tag =
|
||||
address >> (6 + static_cast<uint64_t>(std::log2(this->_lines)));
|
||||
|
||||
auto &line_list = this->_cache_lines[line];
|
||||
auto &line_map = this->_lookup[line];
|
||||
|
||||
auto it = line_map.find(tag);
|
||||
if (it != line_map.end()) {
|
||||
line_list.splice(line_list.begin(), line_list, it->second);
|
||||
line_map[tag] = line_list.begin();
|
||||
return true;
|
||||
}
|
||||
|
||||
if (static_cast<int32_t>(line_list.size()) >= this->_assoc) {
|
||||
auto last = line_list.back();
|
||||
line_map.erase(last.tag);
|
||||
line_list.pop_back();
|
||||
}
|
||||
line_list.push_front({tag});
|
||||
line_map[tag] = line_list.begin();
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace cache
|
||||
115
semester-4/ОС/lb-6/src/src/paging.cpp
Normal file
@@ -0,0 +1,115 @@
|
||||
#pragma once
|
||||
|
||||
#include "../include/paging.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
#include <limits>
|
||||
#include <ranges>
|
||||
#include <unordered_map>
|
||||
|
||||
namespace paging {
|
||||
|
||||
int32_t paging::optimal_replacer::run(const std::vector<int32_t> &pages) {
|
||||
int32_t faults = 0;
|
||||
std::vector<int32_t> frames;
|
||||
frames.reserve(static_cast<size_t>(this->_frames));
|
||||
for (size_t i : std::views::iota(size_t(0), pages.size())) {
|
||||
int32_t p = pages[i];
|
||||
if (std::find(frames.begin(), frames.end(), p) != frames.end())
|
||||
continue;
|
||||
++faults;
|
||||
if (static_cast<int32_t>(frames.size()) < this->_frames) {
|
||||
frames.push_back(p);
|
||||
} else {
|
||||
int32_t idx_to_replace = 0;
|
||||
size_t farthest = 0;
|
||||
for (int32_t j : std::views::iota(0, this->_frames)) {
|
||||
size_t k = i + 1;
|
||||
while (k < pages.size() && pages[k] != frames[j])
|
||||
++k;
|
||||
size_t dist =
|
||||
(k < pages.size() ? k : std::numeric_limits<size_t>::max());
|
||||
if (dist > farthest) {
|
||||
farthest = dist;
|
||||
idx_to_replace = j;
|
||||
}
|
||||
}
|
||||
frames[idx_to_replace] = p;
|
||||
}
|
||||
}
|
||||
return faults;
|
||||
}
|
||||
|
||||
int32_t paging::clock_replacer::run(const std::vector<int32_t> &pages) {
|
||||
int32_t faults = 0;
|
||||
struct entry {
|
||||
int32_t page;
|
||||
bool ref;
|
||||
};
|
||||
std::vector<entry> frames;
|
||||
frames.reserve(static_cast<size_t>(this->_frames));
|
||||
int32_t hand = 0;
|
||||
|
||||
for (int32_t p : pages) {
|
||||
bool hit = false;
|
||||
for (auto &e : frames) {
|
||||
if (e.page == p) {
|
||||
e.ref = true;
|
||||
hit = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (hit)
|
||||
continue;
|
||||
++faults;
|
||||
if (static_cast<int32_t>(frames.size()) < this->_frames) {
|
||||
frames.push_back({p, true});
|
||||
} else {
|
||||
while (true) {
|
||||
if (!frames[hand].ref) {
|
||||
frames[hand] = {p, true};
|
||||
hand = (hand + 1) % this->_frames;
|
||||
break;
|
||||
}
|
||||
frames[hand].ref = false;
|
||||
hand = (hand + 1) % this->_frames;
|
||||
}
|
||||
}
|
||||
}
|
||||
return faults;
|
||||
}
|
||||
|
||||
int32_t paging::lru_replacer::run(const std::vector<int32_t> &pages) {
|
||||
int32_t faults = 0;
|
||||
std::vector<int32_t> frames;
|
||||
std::unordered_map<int32_t, int32_t> last_used;
|
||||
frames.reserve(static_cast<size_t>(this->_frames));
|
||||
|
||||
for (int32_t i : std::views::iota(0, static_cast<int32_t>(pages.size()))) {
|
||||
int32_t p = pages[i];
|
||||
if (std::find(frames.begin(), frames.end(), p) != frames.end()) {
|
||||
last_used[p] = i;
|
||||
continue;
|
||||
}
|
||||
++faults;
|
||||
if (static_cast<int32_t>(frames.size()) < this->_frames) {
|
||||
frames.push_back(p);
|
||||
} else {
|
||||
int32_t lru_page = frames[0];
|
||||
int32_t min_idx = last_used[lru_page];
|
||||
for (int32_t q : frames) {
|
||||
if (last_used[q] < min_idx) {
|
||||
min_idx = last_used[q];
|
||||
lru_page = q;
|
||||
}
|
||||
}
|
||||
auto it = std::find(frames.begin(), frames.end(), lru_page);
|
||||
if (it != frames.end())
|
||||
*it = p;
|
||||
}
|
||||
last_used[p] = i;
|
||||
}
|
||||
return faults;
|
||||
}
|
||||
|
||||
} // namespace paging
|
||||
151
semester-4/ОС/lb-6/src/src/password.cpp
Normal file
@@ -0,0 +1,151 @@
|
||||
#pragma once
|
||||
|
||||
#include "../include/password.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
#include <iomanip>
|
||||
#include <iostream>
|
||||
#include <openssl/sha.h>
|
||||
#include <print>
|
||||
#include <ranges>
|
||||
#include <sstream>
|
||||
|
||||
namespace sec {
|
||||
|
||||
sec::password::password(std::string pass) {
|
||||
if (pass.size() > _buf.size()) {
|
||||
throw std::length_error("Password too long");
|
||||
}
|
||||
_len = pass.size();
|
||||
std::copy(pass.data(), pass.data() + _len, _buf.begin());
|
||||
}
|
||||
|
||||
std::string_view sec::password::view() const noexcept {
|
||||
return std::string_view(_buf.data(), _len);
|
||||
}
|
||||
|
||||
sec::password sec::password::from_console() {
|
||||
std::string p1, p2;
|
||||
while (true) {
|
||||
std::print("Enter password: ");
|
||||
std::getline(std::cin, p1);
|
||||
std::print("Re-enter password: ");
|
||||
std::getline(std::cin, p2);
|
||||
if (p1 != p2) {
|
||||
std::print("Passwords do not match. Try again.\n");
|
||||
continue;
|
||||
}
|
||||
if (sec::manager::evaluate_strength(sec::password(p1)) ==
|
||||
sec::strength_t::very_weak) {
|
||||
std::print("Password is too weak. Try again.\n");
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
return sec::password(p1);
|
||||
}
|
||||
|
||||
sec::password sec::password::from_string(const std::string &pass) {
|
||||
if (sec::manager::evaluate_strength(sec::password(pass)) ==
|
||||
sec::strength_t::very_weak) {
|
||||
std::print("Password is too weak. Try again.\n\n");
|
||||
throw std::invalid_argument("Weak password");
|
||||
}
|
||||
return sec::password(pass);
|
||||
}
|
||||
|
||||
sec::password_hash::password_hash(std::string hash) : _hash(std::move(hash)) {}
|
||||
|
||||
const std::string &sec::password_hash::get() const noexcept { return _hash; }
|
||||
|
||||
bool sec::password_hash::verify(const sec::password &pwd) const {
|
||||
return sec::manager::hash_password(pwd) == _hash;
|
||||
}
|
||||
|
||||
sec::password_hash sec::password::to_hash() const {
|
||||
return sec::password_hash(sec::manager::hash_password(*this));
|
||||
}
|
||||
|
||||
bool sec::manager::has_lower(const sec::password &pwd) {
|
||||
auto sv = pwd.view();
|
||||
return std::any_of(sv.begin(), sv.end(), ::islower);
|
||||
}
|
||||
|
||||
bool sec::manager::has_upper(const sec::password &pwd) {
|
||||
auto sv = pwd.view();
|
||||
return std::any_of(sv.begin(), sv.end(), ::isupper);
|
||||
}
|
||||
|
||||
bool sec::manager::has_digit(const sec::password &pwd) {
|
||||
auto sv = pwd.view();
|
||||
return std::any_of(sv.begin(), sv.end(), ::isdigit);
|
||||
}
|
||||
|
||||
bool sec::manager::has_spec_symbol(const sec::password &pwd) {
|
||||
auto sv = pwd.view();
|
||||
return std::any_of(sv.begin(), sv.end(),
|
||||
[](unsigned char c) { return std::ispunct(c); });
|
||||
}
|
||||
|
||||
sec::strength_t sec::manager::evaluate_strength(const sec::password &pwd) {
|
||||
uint8_t score = 0;
|
||||
|
||||
if (has_lower(pwd))
|
||||
++score;
|
||||
if (has_upper(pwd))
|
||||
++score;
|
||||
if (has_digit(pwd))
|
||||
++score;
|
||||
if (has_spec_symbol(pwd))
|
||||
++score;
|
||||
if (pwd.view().size() >= 8)
|
||||
++score;
|
||||
|
||||
if (score != 0)
|
||||
score--;
|
||||
|
||||
uint8_t max_val = static_cast<uint8_t>(sec::strength_t::very_strong);
|
||||
uint8_t idx = std::min(score, max_val);
|
||||
|
||||
return static_cast<sec::strength_t>(idx);
|
||||
}
|
||||
|
||||
uint64_t sec::manager::time_to_crack(const sec::password &pwd) {
|
||||
auto sv = pwd.view();
|
||||
if (sv.empty())
|
||||
return 0;
|
||||
int charset = (has_lower(pwd) ? 26 : 0) + (has_upper(pwd) ? 26 : 0) +
|
||||
(has_digit(pwd) ? 10 : 0) + (has_spec_symbol(pwd) ? 33 : 0);
|
||||
constexpr double RATE = 1e7;
|
||||
double combos = std::pow(static_cast<double>(charset), sv.size());
|
||||
return static_cast<uint64_t>(combos / 2.0 / RATE);
|
||||
}
|
||||
|
||||
std::string sec::manager::format_duration(uint64_t seconds) {
|
||||
const uint64_t u[] = {31536000, 2592000, 86400, 3600, 60, 1};
|
||||
const char *lbl[] = {"years", "months", "days", "hours", "mins", "secs"};
|
||||
std::string s;
|
||||
for (int i : std::views::iota(0, 6)) {
|
||||
uint64_t v = seconds / u[i];
|
||||
if (v) {
|
||||
s += std::to_string(v) + " " + lbl[i] + ((i == 5) ? "" : " ");
|
||||
seconds %= u[i];
|
||||
}
|
||||
}
|
||||
return s.empty() ? "0 secs" : s;
|
||||
}
|
||||
|
||||
std::string sec::manager::hash_password(const sec::password &pwd) {
|
||||
auto sv = pwd.view();
|
||||
unsigned char hash[SHA256_DIGEST_LENGTH];
|
||||
SHA256(reinterpret_cast<const unsigned char *>(sv.data()), sv.size(), hash);
|
||||
std::ostringstream oss;
|
||||
for (int32_t i : std::views::iota(0, SHA256_DIGEST_LENGTH)) {
|
||||
oss << std::hex << std::setw(2) << std::setfill('0')
|
||||
<< static_cast<int32_t>(hash[i]);
|
||||
}
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
} // namespace sec
|
||||
BIN
semester-4/ОС/lb-6/Лр_6_Ситник_Малишкін_ПЗПІ_23_2.pdf
Normal file
60
semester-4/ОС/lb-6/Лр_6_Ситник_Малишкін_ПЗПІ_23_2.typ
Normal file
@@ -0,0 +1,60 @@
|
||||
#import "@local/nure:0.1.0": *
|
||||
|
||||
#show: pz-lb.with(..yaml("doc.yaml"))
|
||||
|
||||
#v(-spacing)
|
||||
|
||||
== Мета роботи
|
||||
Вивчити особливості захисту критичних даних, використання динамічної та кеш пам'яті.
|
||||
|
||||
== Хід роботи
|
||||
#v(-spacing)
|
||||
=== Порівняти алгоритми заміщення сторінок (оптимальний, годинник, LRU).
|
||||
Заміщення сторінок - це процес, який використовується в операційних системах для керування віртуальною пам'яттю, коли фізичної пам'яті недостатньо. Коли потрібна сторінка, якої немає в оперативній пам'яті, операційна система вибирає одну зі сторінок, що вже знаходяться в пам'яті, і замінює її потрібною сторінкою.
|
||||
|
||||
Сучасні операційні системи використовують різні підходи для визначення сторінок, які можна замістити.
|
||||
|
||||
Розглянемо деякі алгоритми заміщення сторінок:
|
||||
+ оптимальний алгоритм (також відомий як алгоритм Беладі) -- теоретичний алгоритм, який досягає найменшої кількості промахів сторінок. Він працює, замінюючи сторінку, яка не буде використовуватися найдовший період часу в майбутньому. Хоча цей алгоритм є оптимальним, він не може бути реалізований на практиці, оскільки вимагає знання майбутньої послідовності звернень до сторінок;
|
||||
+ алгоритм годинник (також відомий як алгоритм "другого шансу") -- зберігає список сторінок у пам'яті, кожна з яких має біт використання. Коли відбувається промах сторінки і потрібно замінити сторінку, алгоритм перевіряє біт використання поточної сторінки, на яку вказує покажчик. Якщо біт використання дорівнює 1, він скидається до 0, і покажчик переміщується до наступної сторінки. Цей процес повторюється до тих пір, поки не буде знайдено сторінку з бітом використання, що дорівнює 0, яка і замінюється. Такий підхід надає "другий шанс" сторінкам, які нещодавно використовувалися, запобігаючи їхньому швидкому витісненню;
|
||||
+ алгоритм LRU (Least Recently Used) -- замінює сторінку, яка найдовше не використовувалася. Він базується на припущенні, що сторінки, які використовувалися нещодавно, ймовірно, будуть використовуватися знову в найближчому майбутньому, а ті, що давно не використовувалися, мають меншу ймовірність повторного звернення. Для реалізації LRU необхідно відстежувати час останнього звернення до кожної сторінки в пам'яті. Коли виникає потреба у заміщенні, вибирається сторінка з найдавнішим часом останнього використання.
|
||||
|
||||
#figure(image("img/pages-optimal.png", width: 90%), caption: [Оптимальний алгоритм заміщення сторінок])
|
||||
#figure(image("img/pages-clock.png", width: 100%), caption: [Алгоритм заміщення сторінок "Годинник"])
|
||||
#figure(image("img/pages-lru.png", width: 80%), caption: [Алгоритм заміщення сторінок "LRU"])
|
||||
|
||||
Протестуємо всі алгоритми із однаковими тестовими даними.
|
||||
|
||||
#figure(image("img/pages-test.png", width: 80%), caption: [Код тестування алгоритмів])
|
||||
|
||||
#figure(image("img/pages-result.png"), caption: [Результати тестування])
|
||||
|
||||
Можемо побачити, що оптимальний алгоритм показує найкращі результати.
|
||||
|
||||
=== Реалізувати алгоритм LRU для роботи з кешем для стандартних параметрів кешу
|
||||
Кешування - це техніка збереження часто використовуваних даних у швидшій пам'яті (кеші) для зменшення часу доступу. Оскільки кеш має обмежений розмір, при його заповненні виникає потреба у визначенні того, які дані слід видалити для звільнення місця для нових.
|
||||
|
||||
#figure(image("img/cache-lru.png", width: 87%), caption: [Алгоритм "LRU" для доступу до кешу])
|
||||
#figure(image("img/cache-test.png", width: 90%), caption: [Код тестування])
|
||||
#figure(image("img/cache-result.png", width: 45%), caption: [Результати тестування])
|
||||
|
||||
=== Реалізувати функції встановлення паролю та перевірки паролю. При складанні функцій забезпечте безпечне зберігання паролів.
|
||||
|
||||
Безпечність пароля можна визначити за часом, що потрібен для його зламу. Чим більше часу необхідно на злам, тим безпечніший пароль.
|
||||
#figure(
|
||||
image("img/pass-table.png", width: 70%),
|
||||
caption: [Таблиця відповідності складності паролю до часу, що необхідний на злам],
|
||||
)
|
||||
Критерії надійності паролю зазначені в таблиці детально обговорюються в дослідженні Hive Systems, яке оновлюється кожен рік починаючи з 2020 (#link("https://www.hivesystems.com/blog/are-your-passwords-in-the-green"))
|
||||
#figure(image("img/pass-check.png", width: 70%), caption: [Функція перевірки надійності пароля])
|
||||
|
||||
Для забезпечення безпеки пароля в пам'яті під час гешування було використано стандартні POSIX функції "mlock" та "munlock".
|
||||
#figure(image("img/pass-lock.png", width: 74%), caption: [Функції блокування та розблокування пам'яті])
|
||||
|
||||
Для гешування паролю ми використали алгоритм "SHA256" із бібліотеки "openssl", яка є стандартним вибором для всього, що так чи інакше пов'язано із криптографією.
|
||||
#figure(image("img/pass-hash.png", width: 74%), caption: [Функція гешування паролю])
|
||||
|
||||
== Висновки
|
||||
Під час даної лабораторної роботи ми вивчили особливості захисту критичних даних, використання динамічної та кеш пам'яті.
|
||||
|
||||
#show: appendices_style
|
||||