[{"content":"","date":null,"permalink":"https://blog.vladmykhailenko.com/ua/","section":"Vlad Mykhailenko","summary":"","title":"Vlad Mykhailenko"},{"content":"Збірка нотаток, посилань, постів.\n2026-07-10 # Catlantean 3D - Making Graphics Like It\u0026rsquo;s 1993 I wanted a camera that doesn’t exist — so I built it 2024-06-03 # The Big LLM Architecture Comparison 2024-06-03 # Reverse Engineering a Neural Network\u0026rsquo;s Clever Solution to Binary Addition A Mechanistic Interpretability Analysis of Grokking What We Learned from a Year of Building with LLMs (Part I) What We Learned from a Year of Building with LLMs (Part II) 2023-09-09 # Style your RSS feed The Erland Runtime System 2023-06-11 # m15o projets Doom engine code review 2023-05-07 # Most interesting tech you built for just yourself? Knowledge Retrieval Architecture for LLM’s (2023) Spycraft: The Great Game Bartosz Ciechanowski Bicycle 2023-04-08 # FastAI stable dissusion course Bridging the synchronization gap on Linux 2023-03-11 # Mars after midnight gameplay loop Ditherpunk Single File Elixir Scripts 2023-02-21 # What is ChatGPT doing and why does it work 2023-02-19 # home setup - v4.0 How I Replaced Dropbox with Rsync and Why 2023-02-04 # Ask HN: Those making $500+/month on side projects in 2023 – Show and tell 2023-01-26 # Hundreds of quant papers from #QuantLinkADay in 2022 2023-01-22 # Golang 1.20 changes Golang 1.20 changes part 2 2022-01-10 # Serverless Video Transcription inspired by Cyberpunk 207 2022-10-11 # How Wine works 101 2022-10-01 # GIFs Without the .gif: The Most Performant Image and Video Options Right Now 2022-09-17 # S3 glacier backup 2022-09-06 # 9front plan9port 2022-09-02 # fast.ai Practical Deep Learning 2022-08-24 # xit.nvim nvim plugin ","date":"10 July 2026","permalink":"https://blog.vladmykhailenko.com/ua/notes/","section":"Vlad Mykhailenko","summary":"","title":"Нотатки"},{"content":"","date":null,"permalink":"https://blog.vladmykhailenko.com/ua/posts/","section":"Posts","summary":"","title":"Posts"},{"content":"Нещодавно я експериментував із донавчанням моделей в elixir. Я вирішив відтворити туторіал fast.ai який донавчає модель для розпізнавання птахів. Разом з мовою та livebook це дуже просто зробити.\nЦей пост це збірка нотаток про його розробку.\nСпочатку я хотів використати бібліотеку EMLX для використання MLX як бекенд для NX. Але мені вдалося змусити його працювати лише для класифікації без файн тюнінгу, тож це залишеться на майбутне. У виклику chunk_every я використовую discard, щоб уникнути додаткового заповнення даних для навчання/тестування, оскільки мої набори даних не розділені рівномірно. Оскільки специфікація моделі вже мала класи, все що мені потрібно було зробити, це замінити їх на свої власні. Зображення в датасеті вже мають розмір 224x224, тому нема потреби змінювати їх розмір. Якщо ваші зображення відрізняються, вам потрібно використати Nx.reshape або змінити їх розмір. Я витратив багато часу на дебаг, щоб з’ясувати, що проблема полягала у формі потоку даних який я завантажував. Це має бути stream з частинами/чанками. Livebook на github та датасет на huggingface\n","date":"21 January 2025","permalink":"https://blog.vladmykhailenko.com/ua/posts/model-fine-tuning-with-elixir/","section":"Posts","summary":"","title":"Донавчання моделі за допомогою Elixir"},{"content":"Після тривалого використання готових конфігурацій Neovim, таких як NvChad, LunarVim, я вирішив переглянути які плагіни вони використовують, які із них мені потрібні, та налаштувати все самостійно. Проблема яку я помітив при використанні готових конфігурацій це те що незнаючи їх конфігурації плагінів важко налаштувати редактор під себе. Тому якщо мені потрібно читати документацію плагінів щоб побачити що вони роблять і як вони працюють, то у такому випадку я можу налаштувати все самостійно. Отже, у цьому дописі я опишу свою конфігурацію neovim.\nХоча я не використовую vim як основний текстовий редактор, його знання може бути дуже корисною навичкою. Комбінації клавіш vim можна використовувати в будь-якому редакторі (IDEA, VS Code і т.д.) та у інших програмах (наприклад у браузері, файловому менеджері). На роботі я використовую Intelij IDEA з vim плагіном, і моя мета полягала в тому, щоб мати стільки ж основних функцій у vim. Ось цей список.\nВідсутність вкладок - при використанні вкладок доводиться витрачати додатковий час на їх менеджмень (закриття/переупорядкування). Глобальний пошук. Швидке перемикання між файлами/буферами. Автодоповнення. Насправді нічого надзвичайного.\nСписок плагінів # Packer - менеджер плагінів NvimTree - файловий менеджер TreeSitter - підсвічування синтаксису Telescope - пошук файлів, перемикач буферів lspconfig - конфігурації для lsp nvim-cmp - автозаповнення cmp-nvim-lsp nvim-snippy - менеджер фрагментів, дозволяє вставляти шаблони коду cmp-snippy Структура папок #. ├── init.lua ├── lua │ └── vladmyh │ ├── lspconfig.lua │ ├── nvim-tree.lua │ ├── nvimcmp.lua │ ├── telescope.lua │ └── treesitter.lua ├── plugin │ └── packer_compiled.lua ├── undodir └── ~ init.lua - основний конфігураційний файл. Каталог lua/vladmyh містить конфігураційні файли для плагінів. Причина існування ще однієї теки всередині lua полягає в тому, щоб запобігти зіткненням просторів імен між плагінами. Наприклад, якщо плагін telescope має файл з назвою lua/telescope.lua, то буде неоднозначно, який файл завантажувати. Ви можете знайти більше інформації про простори імен тут.\nГоловний файл конфігурації #Це основний файл init.lua. Neovim підтримує як vimscript, так і lua для конфігурації, я обрав lua. Тут я розмістив деякі допоміжні функції, загальні налаштування та оголошення плагінів.\n-- Helpers function map(mode, shortcut, command) vim.api.nvim_set_keymap(mode, shortcut, command, { noremap = true, silent = true }) end function map_func(shortcut, command) vim.keymap.set(\u0026#39;n\u0026#39;, shortcut, command, { noremap = true, silent = true}) end local o = vim.o local wo = vim.wo local bo = vim.bo -- Settings vim.g.mapleader = \u0026#34; \u0026#34; o.ignorecase = true o.undodir = \u0026#39;~/.config/nvim/undodir\u0026#39; o.undofile = true o.smartcase = true o.splitbelow = true o.splitright = true o.scrolloff = 4 o.mouse = \u0026#39;a\u0026#39; o.relativenumber = true wo.number = true bo.tabstop = 4 bo.softtabstop = 4 bo.expandtab = true bo.smartindent = true -- Keys vim.g.mapleader = \u0026#39; \u0026#39; map(\u0026#39;n\u0026#39;, \u0026#39;\u0026lt;leader\u0026gt;j\u0026#39;, \u0026#39;:wincmd j\u0026lt;cr\u0026gt;\u0026#39;) map(\u0026#39;n\u0026#39;, \u0026#39;\u0026lt;leader\u0026gt;k\u0026#39;, \u0026#39;:wincmd k\u0026lt;cr\u0026gt;\u0026#39;) map(\u0026#39;n\u0026#39;, \u0026#39;\u0026lt;leader\u0026gt;h\u0026#39;, \u0026#39;:wincmd h\u0026lt;cr\u0026gt;\u0026#39;) map(\u0026#39;n\u0026#39;, \u0026#39;\u0026lt;leader\u0026gt;l\u0026#39;, \u0026#39;:wincmd l\u0026lt;cr\u0026gt;\u0026#39;) -- Plugins require(\u0026#39;packer\u0026#39;).startup(function() use { \u0026#39;kyazdani42/nvim-tree.lua\u0026#39;, requires = { \u0026#39;kyazdani42/nvim-web-devicons\u0026#39;, -- optional, for file icons } } use { \u0026#39;nvim-treesitter/nvim-treesitter\u0026#39;, run = \u0026#39;:TSUpdate\u0026#39; } use \u0026#39;nvim-treesitter/playground\u0026#39; use \u0026#39;neovim/nvim-lspconfig\u0026#39; use { \u0026#39;nvim-telescope/telescope.nvim\u0026#39;, requires = { {\u0026#39;nvim-lua/plenary.nvim\u0026#39;} } } use \u0026#39;hrsh7th/nvim-cmp\u0026#39; use \u0026#39;hrsh7th/cmp-nvim-lsp\u0026#39; use \u0026#39;dcampos/nvim-snippy\u0026#39; use \u0026#39;dcampos/cmp-snippy\u0026#39; use { \u0026#39;rose-pine/neovim\u0026#39;, as = \u0026#39;rose-pine\u0026#39;, config = function() vim.cmd(\u0026#39;colorscheme rose-pine\u0026#39;) end } end) require(\u0026#39;vladmyh/telescope\u0026#39;) require(\u0026#39;vladmyh/lspconfig\u0026#39;) require(\u0026#39;vladmyh/nvimcmp\u0026#39;) require(\u0026#39;vladmyh/treesitter\u0026#39;) require(\u0026#39;vladmyh/nvim-tree\u0026#39;) -- NvimTree map(\u0026#39;n\u0026#39;, \u0026#39;\u0026lt;leader\u0026gt;n\u0026#39;, \u0026#39;:NvimTreeToggle\u0026lt;cr\u0026gt;\u0026#39;) -- Telescope map(\u0026#39;n\u0026#39;, \u0026#39;\u0026lt;leader\u0026gt;ff\u0026#39;, \u0026#39;:Telescope find_files\u0026lt;cr\u0026gt;\u0026#39;) map(\u0026#39;n\u0026#39;, \u0026#39;\u0026lt;leader\u0026gt;fb\u0026#39;, \u0026#39;:Telescope buffers\u0026lt;cr\u0026gt;\u0026#39;) map(\u0026#39;n\u0026#39;, \u0026#39;\u0026lt;leader\u0026gt;fg\u0026#39;, \u0026#39;:Telescope git_files\u0026lt;cr\u0026gt;\u0026#39;) map(\u0026#39;n\u0026#39;, \u0026#39;\u0026lt;leader\u0026gt;fp\u0026#39;, \u0026#39;:Telescope grep_string\u0026lt;cr\u0026gt;\u0026#39;) Конфігурація LSP #Тут ми визначаємо ряд прив\u0026rsquo;язок клавіш у функції on_attach, які використовуються тільки на буферах з активним lsp. Це означає, що якщо я відкрию файл, для якого у мене не налаштовано lsp, то прив\u0026rsquo;язка клавіш не буде встановлена. Я використовую прив\u0026rsquo;язку клавіш за замовчуванням і використовую map_func з основного файла init.lua.\nmap_func(\u0026#39;\u0026lt;leader\u0026gt;e\u0026#39;, vim.diagnostic.open_float) --map_func(\u0026#39;\u0026lt;C-e\u0026gt;\u0026#39;, vim.diagnostic.open_float) map_func(\u0026#39;[d\u0026#39;, vim.diagnostic.goto_prev, opts) map_func(\u0026#39;]d\u0026#39;, vim.diagnostic.goto_next, opts) map_func(\u0026#39;\u0026lt;leader\u0026gt;q\u0026#39;, vim.diagnostic.setloclist, opts) local on_attach = function(client, bufnr) -- Enable completion triggered by \u0026lt;c-x\u0026gt;\u0026lt;c-o\u0026gt; vim.api.nvim_buf_set_option(bufnr, \u0026#39;omnifunc\u0026#39;, \u0026#39;v:lua.vim.lsp.omnifunc\u0026#39;) -- See `:help vim.lsp.*` for documentation on any of the below functions local bufopts = { noremap=true, silent=true, buffer=bufnr } map_func(\u0026#39;gD\u0026#39;, vim.lsp.buf.declaration, bufopts) map_func(\u0026#39;gd\u0026#39;, vim.lsp.buf.definition, bufopts) map_func(\u0026#39;K\u0026#39;, vim.lsp.buf.hover, bufopts) map_func(\u0026#39;gi\u0026#39;, vim.lsp.buf.implementation, bufopts map_func(\u0026#39;\u0026lt;C-k\u0026gt;\u0026#39;, vim.lsp.buf.signature_help, bufopts) map_func(\u0026#39;\u0026lt;leader\u0026gt;wa\u0026#39;, vim.lsp.buf.add_workspace_folder, bufopts) map_func(\u0026#39;\u0026lt;leader\u0026gt;wr\u0026#39;, vim.lsp.buf.remove_workspace_folder, bufopts) map_func(\u0026#39;\u0026lt;leader\u0026gt;wl\u0026#39;, function() print(vim.inspect(vim.lsp.buf.list_workspace_folders())) end, bufopts) map_func(\u0026#39;\u0026lt;leader\u0026gt;D\u0026#39;, vim.lsp.buf.type_definition, bufopts) map_func(\u0026#39;\u0026lt;leader\u0026gt;vrn\u0026#39;, vim.lsp.buf.rename, bufopts) map_func(\u0026#39;\u0026lt;leader\u0026gt;ca\u0026#39;, vim.lsp.buf.code_action, bufopts) map_func(\u0026#39;gr\u0026#39;, vim.lsp.buf.references, bufopts) map_func(\u0026#39;\u0026lt;leader\u0026gt;f\u0026#39;, vim.lsp.buf.formatting, bufopts) end -- -- Setup lspconfig. local capabilities = require(\u0026#39;cmp_nvim_lsp\u0026#39;).default_capabilities(vim.lsp.protocol.make_client_capabilities()) local lsp_flags = { -- This is the default in Nvim 0.7+ debounce_text_changes = 150, } require(\u0026#39;lspconfig\u0026#39;)[\u0026#39;gopls\u0026#39;].setup{ on_attach = on_attach, flags = lsp_flags, capabilities = capabilities } require(\u0026#39;lspconfig\u0026#39;)[\u0026#39;elixirls\u0026#39;].setup{ on_attach = on_attach, flags = lsp_flags, capabilities = capabilities, cmd = {\u0026#34;/usr/bin/elixir-ls\u0026#34;} } Nvim tree #require(\u0026#39;nvim-tree\u0026#39;).setup() Nvimcmp #local cmp = require(\u0026#39;cmp\u0026#39;) cmp.setup{ snippet = { expand = function(args) require(\u0026#39;snippy\u0026#39;).expand_snippet(args.body) end, }, window = { -- completion = cmp.config.window.bordered(), -- documentation = cmp.config.window.bordered(), }, mapping = cmp.mapping.preset.insert({ [\u0026#39;\u0026lt;C-b\u0026gt;\u0026#39;] = cmp.mapping.scroll_docs(-4), [\u0026#39;\u0026lt;C-f\u0026gt;\u0026#39;] = cmp.mapping.scroll_docs(4), [\u0026#39;\u0026lt;C-Space\u0026gt;\u0026#39;] = cmp.mapping.complete(), [\u0026#39;\u0026lt;C-e\u0026gt;\u0026#39;] = cmp.mapping.abort(), [\u0026#39;\u0026lt;CR\u0026gt;\u0026#39;] = cmp.mapping.confirm({ select = true }), -- Accept currently selected item. Set `select` to `false` to only confirm explicitly selected items. }), sources = cmp.config.sources({ { name = \u0026#39;nvim_lsp\u0026#39; }, { name = \u0026#39;snippy\u0026#39; }, -- For snippy users. }, { { name = \u0026#39;buffer\u0026#39; }, }) } Telescope #Крім налаштування клавіш я встановив властивість sort_mru в true, щоб отримати список буферів з останніх використаних, та властивість initial_mode в normal для того щоб відкривати вікно буферів у нормальному режимі (по замовченню режим редагування). Опис параметру можна знайти тут.\nrequire(\u0026#39;telescope\u0026#39;).setup { pickers = { buffers = { sort_mru = true, --sort buffers by mru initial_mode = \u0026#34;normal\u0026#34; --start buffer picker in normal mode } } } Treesitter #require\u0026#39;nvim-treesitter.configs\u0026#39;.setup { ensure_installed = { \u0026#39;lua\u0026#39;, \u0026#39;go\u0026#39;, \u0026#39;rust\u0026#39;, \u0026#39;elixir\u0026#39;, \u0026#39;erlang\u0026#39; }, sync_install = false, auto_install = true, highlight = { enable = true, additional_vim_regex_highlighting = false, }, } Корисні скорочення клавіш #Ось список деяких корисних комбінацій клавіш, які я намагаюся додавати в свою роботу.\nyap копіювати до символа нового рядка dap видалити до символа нового рядка вниз vap/kvap виділення вниз/вгору до символа нового рядка va{ виділити до закриття \u0026lsquo;}\u0026rsquo; (va(, va\u0026rsquo;, va\u0026quot; і т.д.) o вставити і редагувати рядок нижче, O - вище I перейти на початок рядка і почати редагувати A перейти в кінець рядка і почати редагувати VY скопіювати весь рядок Ctrl + a інкрементувати число під курсором Ctrl + x декрементувати число під курсором Ctrl + v виділити кілька рядків, I перейти в режим редагування '{'/'}' перехід вгору/вниз між символами нового рядка ","date":"28 January 2023","permalink":"https://blog.vladmykhailenko.com/ua/posts/my-nvim-setup/","section":"Posts","summary":"","title":"Моя конфігурація Neovim"},{"content":"На початку 2021 року під впливом мого друга та /r/Homelab я вирішив збудувати домашній сервер. У мене не було якоїсь конкретної мети, окрім бажання повозитися з залізом та програмним забезпеченням, а також отримати більше досвіду з інфраструктурними речами, з якими мені зазвичай не доводиться взаємодіяти. Тому в цьому пості я опишу апаратне та програмне забезпечення, яке я використовую на своєму домашньому сервері.\nПерш ніж ми почнемо, мій вибір заліза та ПО аж ніяк не є оптимальним. Усе що я роблю можна досягти на будь-якому обладнанні або навіть на Raspberry Pi.\nHardware #Ось список заліза яке я обрав, крім ECC RAM, все досить стандартне.\nМатеринська плата: Asus Prime B550-Plus\nПроцесор: AMD Ryzen 7 3800X\nRAM: Samsung 32 GB ECC DDR4 2666 MHz (M391A4G43MB1-CTD)\nSSD: Samsung 970 Evo series 500GB M.2 PCIe 3.0\nHDD: Western Digital Red Pro 2TB 7200rpm 64MB\nКорпус: Fractal Design Define R5 (Я також розглядав Silverstone GD07)\nКулер: Noctua NH-U12A\nДжерело живлення: Corsair RM650\nОбираючи процесор одинм із головних параметрів, на який я звертав увагу, це кількість ядер/потоків, а також доступність, і те, що я міг би перенести на свій ігровий ПК, у разі невдачі із сервером. Як виявилося, для робочих навантажень, які я запускаю, навантаження на ЦП досить низьке, тому я міг би обрати процесор нижчого класу.\nОднією з головних причин, чому я вибрав AMD, це підтримка ECC. Хоча AMD явно не рекламує підтримку ECC, воно підтримується на всіх їхніх сучасних процесорах. Якщо материнська плата також підтримує ECC, то все повинно працювати. Я перевірив характеристики материнської плати, щоб переконатися, що вона підтримує частоту оперативної пам’яті та ECC. Але слід пам\u0026rsquo;ятати, що на не серверному залізі підтримується лише небуферизований ECC, для буферизованої ECC потрібно мати серверні процесори такі як Threadripper або EPYC.\nЯкщо ви обрали Intel, то вам, скоріш за все, потрібно купувати Xenon для підтримки ECC.\nІ, звичайно, процесор повинен підтримувати віртуалізацію, всі сучасні процесори повинні підтримувати її. Для Intel - це VT-x, для AMD - AMD-V.\nДля корпусу я шукав відносно простий дизайн та достатньо місця для кількох жорстких дисків на випадок, якщо я захочу розширити об\u0026rsquo;єм сховищя пізніше. Define R5 може вмістити 2 SSD і 8 3,5-дюймових жорстких дисків, цього мені вистачить на довгий час.\nSoftware #Основна ОС на сервері це Proxmox, система із відкритим кодом для керування віртуалізацією. Він має дуже гарний веб-інтерфейс для керування віртуальними машинами. Налаштування було досить простим, і я не зіткнувся із жодними проблемами в довгостроковій єксплуатації під час оновленнями та обслуговуванням системи.\nНа серверї запущено 4 віртуальні машини:\nTrueNAS Nomad PostgreSQL Віртуальна машина для розробки (у мережі також є pihole, що працює на raspberry pi 3)\nTrueNAS #Ця VM має жорсткий диск ємністю 2 ТБ, переданий на нього від ProxMox, який вона використовує для зберігання даних. Також на ній запущено два плагіни.\nTransmission - торрент-клієнт, який завантажує торренти на TrueNAS.\nPLEX - медіа-сервер, який дозволяє розміщувати власні медіа файли, він транслює файли з TrueNAS.\nNomad #Nomad — це оркестратор накшталт Kubernetes, який використовується для запуску і керування програмами. Я використовую його для запуску докер-додатків, але він підтримує Podman, Java додатки та навіть довільні команди для завдань (docs). Я запускаю Nomad лише у одному екземплярі (звісно, не використовуйте таку конфігурацію у проді).\nНа Nomad я запускаю:\nHeimdal - гарна інформаційна панель для швидкого доступу до всіх сервісів у моїй мережі.\nWireguard - VPN-сервер, до якого я можу підключитися щоб отримати доступ до моєї мережі. Я отримав статичний IP від свого провайдера, щоб зробити це.\nNextCloud - хмара для самостійного хостингу, я в основному використовую його для зберігання файлів і календаря. Усі дані зберігаються на NFS розділі із TrueNAS, який я монтую до Nomad VM, а потім створюю розділ для докера.\nЯ також хочу зазначити, що перед тим як зупинитися на Nomad, я спробував Kubernetes та Rancher. Kubernetes вимагав занадто багато підтримки для мого використання, а Rancher зламався під час оновлень (це змусило мене ще більше цінувати девопсів), що звичайно було моєю помилкою, але саме тому я перейшов до Nomad. Він ідеально підходть для моїх потреб, оскільки вимагав мінімального налаштування/обслуговування, адже для мене зараз сервер це лише хобі, тому я хочу мати гарний баланс між часом, який я вкладаю в нього, і результатами, які я отримаю.\nPostgrSQL #Віртуальна машина Debian, на якій працює PostgreSQL. Зазвичай я використовую його для хобі проектів, які працюють на Nomad.\nDev VM #Я тестую віртуальну машину із середовищем розробки до якої я можу отримати доступ через Wireguard по SSH або RDP. В основному я займаюся розробкою на Java і трохи на Go, тому все програмне забезпечення на ньому досить стандартне: jdk, go, git, Idea, Goland, nvim, jq.\nПлани на майбутнє #Деякі речі які я хочу зробити в майбутньому:\nДодати моніторинг та сповіщеня до всіх сервісів. Автоматизувати деякі процеси за допомогою Ansible. Додати RAID або ZFS mirrors. Отримати доменне ім\u0026rsquo;я та розмістити деякі служи публічно. Загалом покращують безпеку. Додати резервне копіювання за допомогою rsync. Запустити кластер Nomad на декількох Raspberry Pi, я планую придбати принаймні 3 RPi і перенести більшість сервісів на них. ","date":"10 April 2022","permalink":"https://blog.vladmykhailenko.com/ua/posts/my-home-server-setup/","section":"Posts","summary":"","title":"Мій домашній сервер"},{"content":"","date":null,"permalink":"https://blog.vladmykhailenko.com/ua/categories/","section":"Categories","summary":"","title":"Categories"},{"content":"","date":null,"permalink":"https://blog.vladmykhailenko.com/ua/tags/","section":"Tags","summary":"","title":"Tags"}]