mirror of
				https://github.com/valentineus/popov.link.git
				synced 2025-11-04 06:49:45 +03:00 
			
		
		
		
	Moved all posts
This commit is contained in:
		
							
								
								
									
										224
									
								
								_posts/2012-01-30-getting-source-code-of-chromium.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										224
									
								
								_posts/2012-01-30-getting-source-code-of-chromium.md
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,224 @@
 | 
				
			|||||||
 | 
					---
 | 
				
			||||||
 | 
					description: >-
 | 
				
			||||||
 | 
					    Изучение исходных кодов Chromium: подготовка системы и установка необходимых программных компонентов. Руководство для начинающих разработчиков. Получите инструкции по установке Microsoft Visual Studio, Cygwin, Python и других инструментов. Действительно на январь-февраль 2012 года.
 | 
				
			||||||
 | 
					title: Получение исходного кода "Chromium Projects"
 | 
				
			||||||
 | 
					layout: post
 | 
				
			||||||
 | 
					---
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					> Перенос [оригинальной статьи](https://adeptus-mechanicus.blogspot.com/2012/01/chromium-projects.html) 2012 года из моего [старого блога](https://adeptus-mechanicus.blogspot.com/) ([зеркало](https://web.archive.org/web/20160217052148/http://adeptus-mechanicus.blogspot.com/)).
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					__Добрый день, уважаемые читатели!__
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					В последние дни выдалось свободное время, и я решил изучить исходные коды "[The Chromium Projects](http://www.chromium.org/)".
 | 
				
			||||||
 | 
					Чтобы посмотреть исходники, оказалось недостаточным просто скачать архив с исходным кодом и начать работать с ним в "Visual Studio 2010".
 | 
				
			||||||
 | 
					Я был крайне опечален отсутствием нормальной русской документации для начинающих, поэтому восполню пробел и переведу всю инструкцию по получению исходных кодов.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					___P.S.__ Chromium является быстроразвивающимся Open Sources проектом._
 | 
				
			||||||
 | 
					_Данная инструкция актуальна на январь-февраль 2012 года._
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Для начала немного введения.
 | 
				
			||||||
 | 
					Весь процесс от подготовки системы, до работы с исходными кодами я условно разделю на четыре пункта, это:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- Подготовка операционной системы, установка стандартных программных комплектов разработчика;
 | 
				
			||||||
 | 
					- Установка и настройка программы "Cygwin";
 | 
				
			||||||
 | 
					- Установка и настройка пакета "depot\_tools";
 | 
				
			||||||
 | 
					- Получение и подготовка для работы исходных кодов "Chromium";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## Подготовка начального набора программ
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Ниже приведу список и краткое описание программного обеспечения, которое требуется установить перед работой с исходными кодами:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- "__Microsoft Visual Studio 2010__" — Среда разработки, требуется для работы с исходным кодом. Имеется возможность использовать Microsoft Visual Studio 2008 и Microsoft Visual C++ Express 2010'го и 2008'го годов соответственно. Бесплатные Express версии продуктов можно взять на [официальном сайте](http://www.microsoft.com/express) Microsoft.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- "__Microsoft Windows SDK__" — Пакет для предоставления заголовочных файлов, библиотек, компиляторов и пр. для разработчиков программного обеспечения под операционную систему Windows. Требуется для успешной сборки и компиляции проекта под Windows систему. Бесплатно можно скачать с [официальной страницы](https://www.microsoft.com/downloads/en/details.aspx?FamilyID=6b6c21d2-2006-4afa-9702-529fa782d63b).
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- "__Microsoft DirectX SDK__" — Пакет с библиотеками мультимедийной подсистемы DirectX. Требуется для успешной сборки и компиляции проекта. Бесплатно доступен на [официальном сайте](http://msdn.microsoft.com/en-us/directx/default.aspx).
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- "__Python 2.x__" — Высокоуровневый язык программирования. Требуется для начальной подготовки исходных кодов. Установка не обязательная, но желательная. Про третью версию Python официальной информации нет, у меня установлены обе версии для опытов и "Path" системы направлен на вторую версию. Установку Python коротко разберу ниже. Python бесплатно можно взять на [официальном сайте](http://python.org/).
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- "__Cygwin__" — Unix-подобная среда и интерфейс командной строки для систем Microsoft Windows. Требуется для работы с исходными кодами, их подготовки, обновлением и проверки на ошибки. Сам инструмент бесплатно доступен на [официальной странице](http://www.cygwin.com/). Его установку я распишу в следующих пунктах.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- "__TortoiseSVN__" — Клиент Subversion под систему Windows. Установка не обязательная, но желательная. Требуется для более простого обновления пакета "depot\_tools" из официального репозитория SVN от корпорации Google. Бесплатно доступен на [официальной странице](http://tortoisesvn.net/).
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Над установкой Microsoft Visual Studio, Microsoft Windows SDK и Microsoft DirectX SDK я подробно останавливаться не буду.
 | 
				
			||||||
 | 
					Установка данных программных комплектов проста, и особой сложности вызывать не должна.
 | 
				
			||||||
 | 
					В случае возникновения каких-либо проблем, имеются огромные сообщества разработчиков, которые помогут с установкой.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					__На установке пакета Python'а я остановлюсь поподробнее:__
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Во-первых, путь установки Python'а не должен содержать русскоязычный текст, это может вызвать много ошибок.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Во-вторых, после установки основного пакета, не забудьте добавить имя каталога в список путей, по которому операционная система ищет исполняемые файлы.
 | 
				
			||||||
 | 
					Чтобы это сделать, требуется:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					1. Запустите "_Панель Управления_" и выберите пиктограмму "_Система_";
 | 
				
			||||||
 | 
					2. Выберите "_Дополнительные настройки системы_";
 | 
				
			||||||
 | 
					3. Перейдите во вкладку "_Дополнительно_" и щёлкните на кнопке "_Переменные среды_";
 | 
				
			||||||
 | 
					4. В содержимом окна "_Системные переменные_" найдите строку "_Path_";
 | 
				
			||||||
 | 
					5. Добавьте туда путь до вашего каталога Python.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					В моём случае этот путь выглядел так:
 | 
				
			||||||
 | 
					`C:\Program Files (x86)\Python2`.
 | 
				
			||||||
 | 
					Пути каталогов должны разделяться знаком `;`, по этому не забудьте перед последним записанным каталогом дописать `;` (без кавычек);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Чтобы проверить работоспособность языка Python в Вашей системе сразу после установки, откройте командную строку Windows и введите команду:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```bash
 | 
				
			||||||
 | 
					python --version
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					На экране должно появиться сообщение с версией Python, которая используется в Вашей системе по-умолчанию.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					__Теперь подготовим каталоги.__
 | 
				
			||||||
 | 
					Каталог исходных кодов в моём случае располагается на диске `C:\`, потому что желательно не использовать пробелы в пути адреса до исходных кодов и мой пользователь в операционной системе состоит из русскоязычных символов.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					На диске `C:\` я создал каталог `OpenSource`, в нём я создал каталог `ChromiumProjects`, в котором появилось два подкаталога `depot_tools` и `trunk`.
 | 
				
			||||||
 | 
					Т.е. система каталогов выглядит так:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- `C:\OpenSource\ChromiumProjects\depot_tools` — Пакет для работы с исходным кодом;
 | 
				
			||||||
 | 
					- `C:\OpenSource\ChromiumProjects\trunk` — Место хранения исходных кодов;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					В случае использование других каталогов в вашей системе, используйте собственные пути, подставляя их в мои примеры.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Так же крайне рекомендуется отключить индексирование системы в данных каталогах, потому что это вызовет фатальные ошибки работы пакета "depot\_tools".
 | 
				
			||||||
 | 
					Чтобы это сделать, откройте "_Панель управления_", выберите пиктограмму "_Параметры индексирования_", нажмите на кнопку "_Изменить_" и снимите галочку с каталога, содержащий утилиту "depot\_tools".
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Первоначальную установку и настройку системы можно считать оконченной.
 | 
				
			||||||
 | 
					Переходим к следующему шагу.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## Установка программы "Cygwin"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Первым делом получите установочный файл последней версии по этой [ссылке](http://cygwin.com/setup.exe).
 | 
				
			||||||
 | 
					Установочный файл во время установки скачивает необходимые пакеты из интернета.
 | 
				
			||||||
 | 
					Когда запустите файл, следуйте инструкциям.
 | 
				
			||||||
 | 
					После выбор зеркала пакетов, Вам покажут список доступных пакетов с зеркала.
 | 
				
			||||||
 | 
					Требуется найти и отметить для установки следующие пакеты:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- `apache`;
 | 
				
			||||||
 | 
					- `bc`;
 | 
				
			||||||
 | 
					- `bison`;
 | 
				
			||||||
 | 
					- `curl`;
 | 
				
			||||||
 | 
					- `diffutils`;
 | 
				
			||||||
 | 
					- `e2fsprogs`;
 | 
				
			||||||
 | 
					- `emacs`;
 | 
				
			||||||
 | 
					- `flex`;
 | 
				
			||||||
 | 
					- `gcc`;
 | 
				
			||||||
 | 
					- `gperf`;
 | 
				
			||||||
 | 
					- `keychain`;
 | 
				
			||||||
 | 
					- `make`;
 | 
				
			||||||
 | 
					- `nano`;
 | 
				
			||||||
 | 
					- `openssh`;
 | 
				
			||||||
 | 
					- `patch`;
 | 
				
			||||||
 | 
					- `perl`;
 | 
				
			||||||
 | 
					- `perl-libwin32`;
 | 
				
			||||||
 | 
					- `python`;
 | 
				
			||||||
 | 
					- `rebase`;
 | 
				
			||||||
 | 
					- `rsync`;
 | 
				
			||||||
 | 
					- `ruby`;
 | 
				
			||||||
 | 
					- `subversion`;
 | 
				
			||||||
 | 
					- `unzip`;
 | 
				
			||||||
 | 
					- `vim`;
 | 
				
			||||||
 | 
					- `zip`;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Имена пакетов должны полностью совпадать.
 | 
				
			||||||
 | 
					Воспользуйтесь поиском по пакетам, включённым в саму программу установки.
 | 
				
			||||||
 | 
					Это должно сильно облегчить задачу.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Актуальный список пакетов, требующихся для установки, Вы всегда можете найти в [официальном скрипте](http://trac.webkit.org/browser/trunk/Tools/CygwinDownloader/cygwin-downloader.py) установки, в поле `required_packages`.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					После установки приложения, требуется внести путь до папки с исполняемыми файлами в переменную "Path".
 | 
				
			||||||
 | 
					Сделать это можно в точности, как после установки пакета Python'а, описанного чуть выше в данной статье.
 | 
				
			||||||
 | 
					Только в отличии от Python'а, требуется указать путь до папки `bin`, находящейся в корневом каталоге приложения "Cygwin".
 | 
				
			||||||
 | 
					В моём случае этот путь выглядел так:
 | 
				
			||||||
 | 
					`C:\Program Files (x86)\Cygwin\bin`.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					После установки и проверки приложения "Cygwin", можно переходить к следующему шагу, настройке и установки пакета "depot\_tools".
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## Установка пакета "depot\_tools"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					1. Перейдите в каталог, который Вы определили для хранения пакета "depot\_tools";
 | 
				
			||||||
 | 
					2. Находясь в папке, нажмите правую кнопку мыши в любом свободном месте и контекстном меню выберите пункт "_SVN Checkout_";
 | 
				
			||||||
 | 
					3. В пути URL репозитория, указывайте путь: `http://src.chromium.org/svn/trunk/tools/depot_tools`;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Если проблем не возникнет, пойдёт установка последней ревизии данного пакета.
 | 
				
			||||||
 | 
					По окончанию скачивания пакета, путь до исполняемых файлов пакета следует указать в переменной "Path", по аналогии с программой "Cygwin" и пакетом "Python".
 | 
				
			||||||
 | 
					В моём случае, путь выглядел так:
 | 
				
			||||||
 | 
					`C:\OpenSource\ChromiumProjects\depot_tools`.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Если всё прошло успешно, можно перейти к заключительной части статьи, получения и подготовка исходных кодов браузера "Chromium".
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## Получение и подготовка исходных кодов
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Перейдите по данной [ссылке](http://chromium-browser-source.commondatastorage.googleapis.com/chromium_tarball.html) и скачайте архив с исходными кодами.
 | 
				
			||||||
 | 
					Вы получите архив с именем "_chromium.r**XXXXX**.tgz_", где __XXXXX__ — номер стабильной последней версии.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Распакуйте из архива папку `src` в наш каталог `trunk`.
 | 
				
			||||||
 | 
					Процесс займёт продолжительное время, потому что объём исходных кодов ~4 Гб.
 | 
				
			||||||
 | 
					По окончанию распаковки, откройте терминал "Cygwin".
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					В открытом терминале теперь необходимо пройти в каталог `src`, который получится после распаковки исходных кодов.
 | 
				
			||||||
 | 
					Переход по каталогам в терминале осуществляется программой `cd`.
 | 
				
			||||||
 | 
					Чтобы попасть на диск `C:\`, требуется в терминале набрать команду:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```bash
 | 
				
			||||||
 | 
					cd "C:/"
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Чтобы вернуться на каталог выше, требуется набрать команду:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```bash
 | 
				
			||||||
 | 
					cd ..
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					В Unix-терминалах для работы с каталогами используется обратная косая черта.
 | 
				
			||||||
 | 
					По этому, чтобы перейти в требуемый каталог, на моём примере, команда будет выглядеть так:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```bash
 | 
				
			||||||
 | 
					cd "C:/OpenSource/ChromiumProjects/trunk/src"
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Теперь, когда мы в требуемой папке, надо применить команду для первоначальной настройки исходных кодов.
 | 
				
			||||||
 | 
					Для этого ведите команду:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```bash
 | 
				
			||||||
 | 
					gclient sync --force
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					После выполнения данной команды, требуется подготовить исходные коды для работы с "_Visual Studio 2010_".
 | 
				
			||||||
 | 
					Для этого вводим команду:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```bash
 | 
				
			||||||
 | 
					gclient runhooks --force
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					По окончанию выполнения данной команды, мы получаем готовые к работе исходные коды.
 | 
				
			||||||
 | 
					Чтобы начать с ними работу, откройте Вашу "Visual Studio", выберите "_Открыть проект_" и откройте файл `chrome.sln`, который находится в папке `chrome`, находящейся в папке исходных кодов.
 | 
				
			||||||
 | 
					В моём случае, полный путь до файла выглядит так:
 | 
				
			||||||
 | 
					`C:\OpenSource\ChromiumProjects\trunk\src\chrome\chrome.sln`.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					На этом работу можно считать законченной.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## Обновление
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Чтобы обновить пакет "depot\_tools", требуется зайти в каталог, содержащий данный пакет, щёлкнуть правой кнопкой мыши и в контекстном меню выбрать "_SVN Update_".
 | 
				
			||||||
 | 
					"TortoiseSVN" обновит данные каталога до последней ревизии пакета.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Для обновления исходных кодов "Chromium", требуется открыть терминал "Cygwin", перейти в каталог с исходными кодами и ввести команду:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```bash
 | 
				
			||||||
 | 
					gclient sync
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## Заключение
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Спасибо, что прочитали и большое спасибо, если воспользовались моей инструкцией.
 | 
				
			||||||
 | 
					Я всегда рад Вашим комментариям с вопросами, уточнениями и предложениями.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## Полезные ссылки
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- [http://dev.chromium.org/Home](http://dev.chromium.org/Home) — Официальная страница проекта "The Chromium Projects";
 | 
				
			||||||
 | 
					- [http://dev.chromium.org/developers/how-tos/build-instructions-windows](http://dev.chromium.org/developers/how-tos/build-instructions-windows) — Официальная страница по подготовке операционной системы Windows, перед работой с исходными кодами;
 | 
				
			||||||
 | 
					- [http://dev.chromium.org/developers/how-tos/get-the-code](http://dev.chromium.org/developers/how-tos/get-the-code) — Официальная инструкция по получению, настройке и подготовке исходных кодов проекта "The Chromium Projects";
 | 
				
			||||||
 | 
					- [http://dev.chromium.org/developers/how-tos/install-depot-tools](http://dev.chromium.org/developers/how-tos/install-depot-tools) — Официальная инструкция по установке и настройке пакета "depot\_tools";
 | 
				
			||||||
 | 
					- [http://dev.chromium.org/developers/how-tos/cygwin](http://dev.chromium.org/developers/how-tos/cygwin) — Страница по установки и настройке терминала "Cygwin";
 | 
				
			||||||
 | 
					- [http://groups.google.com/a/chromium.org/group/chromium-discuss/topics](http://groups.google.com/a/chromium.org/group/chromium-discuss/topics) — Официальная дискуссия разработчиков браузера "Chromium";
 | 
				
			||||||
@@ -1,11 +1,12 @@
 | 
				
			|||||||
---
 | 
					---
 | 
				
			||||||
description: "Настройка SELinux в операционной системе Fedora для корректной работы Moodle."
 | 
					description: >-
 | 
				
			||||||
title: "Установка Moodle в Fedora"
 | 
					    Решение проблем установки Moodle из-за SELinux: как настроить правила доступа для устранения ошибок в веб-интерфейсе и при работе с cURL. Практические советы и команды.
 | 
				
			||||||
 | 
					title: Установка Moodle в Fedora
 | 
				
			||||||
layout: post
 | 
					layout: post
 | 
				
			||||||
issue: 1
 | 
					 | 
				
			||||||
---
 | 
					---
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Во время установки Moodle, сталкиваешься со следующими проблемами:
 | 
					Во время установки Moodle, сталкиваешься со следующими проблемами:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
- Веб-интерфейс не продолжает установку после настройки базы данных;
 | 
					- Веб-интерфейс не продолжает установку после настройки базы данных;
 | 
				
			||||||
- Если установить через консольный интерфейс, проявляются артефакты;
 | 
					- Если установить через консольный интерфейс, проявляются артефакты;
 | 
				
			||||||
- Нет доступа к сети, появляется ошибка `unexpected cURL error`.
 | 
					- Нет доступа к сети, появляется ошибка `unexpected cURL error`.
 | 
				
			||||||
@@ -13,6 +14,7 @@ issue: 1
 | 
				
			|||||||
Главная причина, это
 | 
					Главная причина, это
 | 
				
			||||||
[SELinux](https://en.wikipedia.org/wiki/Security-Enhanced_Linux).
 | 
					[SELinux](https://en.wikipedia.org/wiki/Security-Enhanced_Linux).
 | 
				
			||||||
Решение, это настроить правила доступа:
 | 
					Решение, это настроить правила доступа:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
```bash
 | 
					```bash
 | 
				
			||||||
# Доступ к сторонним каталогам и сети
 | 
					# Доступ к сторонним каталогам и сети
 | 
				
			||||||
/usr/sbin/setsebool -P httpd_can_network_connect true
 | 
					/usr/sbin/setsebool -P httpd_can_network_connect true
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,16 +1,16 @@
 | 
				
			|||||||
---
 | 
					---
 | 
				
			||||||
description: "Способы и варианты горячей перезагрузки ElectronJS приложения."
 | 
					description: >-
 | 
				
			||||||
title: "Перезагрузка ElectronJS приложения"
 | 
					    Руководство по автоматической перезагрузке приложений на Electron с помощью пакетов electron-reload и electron-webpack. Обход проблем с совместимостью и использование HMR для renderer процесса.
 | 
				
			||||||
 | 
					title: Горячая перезагрузка ElectronJS приложения
 | 
				
			||||||
layout: post
 | 
					layout: post
 | 
				
			||||||
---
 | 
					---
 | 
				
			||||||
 | 
					
 | 
				
			||||||
## Main процесс
 | 
					## Main процесс
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Для перезагрузки основного процесса можно использовать готовый пакет [electron-reload].
 | 
					Для перезагрузки основного процесса можно использовать готовый пакет [electron-reload]. Или перезагружать приложение средствами пакета [electron-webpack].
 | 
				
			||||||
Или перезагружать приложение средствами пакета [electron-webpack].
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
Если сборщик кода отличный от WebPack или нет возможности использовать вышеуказанные пакеты, можно обойтись инструментом [nodemon].
 | 
					Если сборщик кода отличный от WebPack или нет возможности использовать вышеуказанные пакеты, можно обойтись инструментом [nodemon]. Команда запуска будет
 | 
				
			||||||
Команда запуска будет выглядеть следующим образом:
 | 
					выглядеть следующим образом:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
```bash
 | 
					```bash
 | 
				
			||||||
nodemon --watch ./assets/main.js --exec 'electron .'
 | 
					nodemon --watch ./assets/main.js --exec 'electron .'
 | 
				
			||||||
@@ -20,14 +20,12 @@ nodemon --watch ./assets/main.js --exec 'electron .'
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
## Renderer процесс
 | 
					## Renderer процесс
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Для обновления renderer процесса, перезагружать полностью приложение нет необходимости.
 | 
					Для обновления renderer процесса, перезагружать полностью приложение нет необходимости. Достаточно обновить страницу. Самый простой способ, горячие
 | 
				
			||||||
Достаточно обновить страницу.
 | 
					клавиши: `Ctrl` + `F5`. Так как рендер процесс по своей сути является обычным окном браузера, можно настроить [HMR] технологию. Конечно, если используются
 | 
				
			||||||
Самый простой способ, горячие клавиши: `Ctrl` + `F5`.
 | 
					соответствующие инструменты.
 | 
				
			||||||
Так как рендер процесс по своей сути является обычным окном браузера, можно настроить [HMR] технологию.
 | 
					 | 
				
			||||||
Конечно, если используются соответствующие инструменты.
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
Мне симпатичен способ использования пакета [electron-reload].
 | 
					Мне симпатичен способ использования пакета [electron-reload]. В алгоритме пакета лежит простое слежение за каталогом файлов и обновление активных окон
 | 
				
			||||||
В алгоритме пакета лежит простое слежение за каталогом файлов и обновление активных окон приложения.
 | 
					приложения.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Но мною была найдена досадная [проблема], не позволяющая использовать версии `1.5.0` и `1.4.1` со сборщиком WebPack, который используется в проекте.
 | 
					Но мною была найдена досадная [проблема], не позволяющая использовать версии `1.5.0` и `1.4.1` со сборщиком WebPack, который используется в проекте.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -60,7 +58,11 @@ if (process.env.NODE_ENV !== 'production') {
 | 
				
			|||||||
```
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[HMR]: https://webpack.js.org/concepts/hot-module-replacement/
 | 
					[HMR]: https://webpack.js.org/concepts/hot-module-replacement/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[electron-reload]: https://www.npmjs.com/package/electron-reload
 | 
					[electron-reload]: https://www.npmjs.com/package/electron-reload
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[electron-webpack]: https://www.npmjs.com/package/electron-webpack
 | 
					[electron-webpack]: https://www.npmjs.com/package/electron-webpack
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[nodemon]: https://www.npmjs.com/package/nodemon
 | 
					[nodemon]: https://www.npmjs.com/package/nodemon
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[проблема]: https://github.com/yan-foto/electron-reload/issues/66
 | 
					[проблема]: https://github.com/yan-foto/electron-reload/issues/66
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										188
									
								
								_posts/2023-05-01-rust-and-tl-mr3020.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										188
									
								
								_posts/2023-05-01-rust-and-tl-mr3020.md
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,188 @@
 | 
				
			|||||||
 | 
					---
 | 
				
			||||||
 | 
					description: >-
 | 
				
			||||||
 | 
					    Как настроить и оптимизировать проект Rust для кросс-компиляции на TP-Link TL-MR3020 с использованием Fedora Linux 38 и OpenWrt 22.03.4. Шаг за шагом от базового "Hello, World!" до асинхронного TCP сервера.
 | 
				
			||||||
 | 
					title: Компиляция Rust на TL-MR3020
 | 
				
			||||||
 | 
					layout: post
 | 
				
			||||||
 | 
					---
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Информация в статье актуальна для дистрибутива [Fedora Linux 38](https://docs.fedoraproject.org/en-US/releases/f38/), прошивки [OpenWrt 22.03.4](https://openwrt.org/releases/22.03/notes-22.03.4) и устройства [TP-Link TL-MR3020](https://www.tp-link.com/en/home-networking/3g-4g-router/tl-mr3020/) ревизии v3.20.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Потребуется:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- Установленный [rustup](https://rustup.rs/) инструментарий.
 | 
				
			||||||
 | 
					- Установленный пакет [cross-rs](https://github.com/cross-rs/cross) для кросс-компиляции.
 | 
				
			||||||
 | 
					- Упаковщик исполняемых файлов [upx](https://github.com/upx/upx).
 | 
				
			||||||
 | 
					- Контейнеризатор [Docker](https://docs.docker.com/engine/install/) (рекомендуется) или [Podman](https://podman.io/getting-started/installation).
 | 
				
			||||||
 | 
					- SSH подключение к маршрутизатору.
 | 
				
			||||||
 | 
					- Установленный [SFTP сервер](https://openwrt.org/docs/guide-user/services/nas/sftp.server) на TL-MR3020.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					> Требуется rustup инструментарий с официального сайта.
 | 
				
			||||||
 | 
					Rust и Cargo из репозитория дистрибутива не подойдут.
 | 
				
			||||||
 | 
					Пакет кросс-компиляции требует rustup, который в репозиториях дистрибутива отсутствует.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## "Hello, World!" ver. 1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Начнем с базы.
 | 
				
			||||||
 | 
					Соберем и запустим "Hello, World" на маршрутизаторе.
 | 
				
			||||||
 | 
					Инициализируем проект на Rust:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```bash
 | 
				
			||||||
 | 
					cargo init --bin ramips-rs
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Далее, чтобы выполнить кросс-компиляцию, определим архитектуру процессора:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```bash
 | 
				
			||||||
 | 
					cat /proc/cpuinfo
 | 
				
			||||||
 | 
					# system type               : MediaTek MT7628AN ver:1 eco:2
 | 
				
			||||||
 | 
					# machine                   : TP-Link TL-MR3020 v3
 | 
				
			||||||
 | 
					# processor                 : 0
 | 
				
			||||||
 | 
					# cpu model                 : MIPS 24KEc V5.5
 | 
				
			||||||
 | 
					# BogoMIPS                  : 385.84
 | 
				
			||||||
 | 
					# wait instruction          : yes
 | 
				
			||||||
 | 
					# microsecond timers        : yes
 | 
				
			||||||
 | 
					# tlb_entries               : 32
 | 
				
			||||||
 | 
					# extra interrupt vector    : yes
 | 
				
			||||||
 | 
					# hardware watchpoint       : yes, count: 4, address/irw mask: [0x0ffc, 0x0ffc, 0x0ffb, 0x0ffb]
 | 
				
			||||||
 | 
					# isa                       : mips1 mips2 mips32r1 mips32r2
 | 
				
			||||||
 | 
					# ASEs implemented          : mips16 dsp
 | 
				
			||||||
 | 
					# Options implemented       : tlb 4kex 4k_cache prefetch mcheck ejtag llsc pindexed_dcache userlocal vint perf_cntr_intr_bit perf
 | 
				
			||||||
 | 
					# shadow register sets      : 1
 | 
				
			||||||
 | 
					# kscratch registers        : 0
 | 
				
			||||||
 | 
					# package                   : 0
 | 
				
			||||||
 | 
					# core                      : 0
 | 
				
			||||||
 | 
					# VCED exceptions           : not available
 | 
				
			||||||
 | 
					# VCEI exceptions           : not available
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Видим, что процессор архитектуры MIPS.
 | 
				
			||||||
 | 
					Теперь определим целевую архитектуру для компиляции:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```bash
 | 
				
			||||||
 | 
					rustup target list | grep mips
 | 
				
			||||||
 | 
					# mips-unknown-linux-gnu
 | 
				
			||||||
 | 
					# mips-unknown-linux-musl
 | 
				
			||||||
 | 
					# mips64-unknown-linux-gnuabi64
 | 
				
			||||||
 | 
					# mips64-unknown-linux-muslabi64
 | 
				
			||||||
 | 
					# mips64el-unknown-linux-gnuabi64
 | 
				
			||||||
 | 
					# mips64el-unknown-linux-muslabi64
 | 
				
			||||||
 | 
					# mipsel-unknown-linux-gnu
 | 
				
			||||||
 | 
					# mipsel-unknown-linux-musl
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Опытным путем определяем, что в случае с TL-MR3020 v3.20 подходит архитектура `mipsel-unknown-linux-musl`.
 | 
				
			||||||
 | 
					Далее компилируем проект под целевую архитектуру:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```bash
 | 
				
			||||||
 | 
					cross build --release --target mipsel-unknown-linux-musl
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Получаем исполняемый бинарный файл, который загружаем и запускаем на маршрутизаторе.
 | 
				
			||||||
 | 
					Выгружаем в раздел `/tmp`, потому что доступной памяти на основном разделе меньше двух мегабайт.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```bash
 | 
				
			||||||
 | 
					scp ./target/mipsel-unknown-linux-musl/release/ramips-rs openwrt:/tmp/
 | 
				
			||||||
 | 
					ssh openwrt /tmp/ramips-rs
 | 
				
			||||||
 | 
					# Hello, world!
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## Оптимизация размера бинарника
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					После сборки и запуска "Hello, World" можно обратить внимание, что исполняемый файл весит __4.1 мегабайта__.
 | 
				
			||||||
 | 
					Для устройства с 8 мегабайтами постоянной памяти это катастрофически много.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Уменьшим размер исполняемого файла до приемлемого минимума.
 | 
				
			||||||
 | 
					Для этого настроим release профиль сборки и компиляции проекта.
 | 
				
			||||||
 | 
					Дополним Cargo.toml файл:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```toml
 | 
				
			||||||
 | 
					[profile.release]
 | 
				
			||||||
 | 
					strip = true        # Уменьшает бинарник до 383K
 | 
				
			||||||
 | 
					lto = "fat"         # Уменьшает бинарник до 334K
 | 
				
			||||||
 | 
					opt-level = "z"     # Уменьшает бинарник до 326K
 | 
				
			||||||
 | 
					panic = "abort"     # Уменьшает бинарник да 332K
 | 
				
			||||||
 | 
					codegen-units = 1   # Включает дополнительные оптимизации кода
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Получаем исполняемый файл размером в __332 килобайта__.
 | 
				
			||||||
 | 
					Далее сжимаем исполняемый файл инструментом upx:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```bash
 | 
				
			||||||
 | 
					upx --best --lzma target/mipsel-unknown-linux-musl/release/ramips-rs
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					И получаем исходный файл размером в __118 килобайт__.
 | 
				
			||||||
 | 
					Приемлемый результат.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Сильнее уменьшить бинарник можно отказом от стандартной std библиотеки и другими экстремальными unsafe приемами, что не подходит в моем случае.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## "Hello, World!" ver. 2
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Теперь сделаем пример посерьезней.
 | 
				
			||||||
 | 
					Например, асинхронный TCP сервер.
 | 
				
			||||||
 | 
					Подключаем зависимости:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```toml
 | 
				
			||||||
 | 
					[dependencies]
 | 
				
			||||||
 | 
					hyper = { version = "1.0.0-rc.3", features = ["full"] }
 | 
				
			||||||
 | 
					tokio = { version = "1", features = ["full"] }
 | 
				
			||||||
 | 
					http-body-util = "0.1.0-rc.2"
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Пишем код:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```rust
 | 
				
			||||||
 | 
					use std::convert::Infallible;
 | 
				
			||||||
 | 
					use std::net::SocketAddr;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use http_body_util::Full;
 | 
				
			||||||
 | 
					use hyper::body::Bytes;
 | 
				
			||||||
 | 
					use hyper::server::conn::http1;
 | 
				
			||||||
 | 
					use hyper::service::service_fn;
 | 
				
			||||||
 | 
					use hyper::{Request, Response};
 | 
				
			||||||
 | 
					use tokio::net::TcpListener;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					async fn hello(_: Request<hyper::body::Incoming>) -> Result<Response<Full<Bytes>>, Infallible> {
 | 
				
			||||||
 | 
					    Ok(Response::new(Full::new(Bytes::from("Hello, World!"))))
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[tokio::main]
 | 
				
			||||||
 | 
					async fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
 | 
				
			||||||
 | 
					    let addr = SocketAddr::from(([0, 0, 0, 0], 3000));
 | 
				
			||||||
 | 
					    let listener = TcpListener::bind(addr).await?;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    loop {
 | 
				
			||||||
 | 
					        let (stream, _) = listener.accept().await?;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        tokio::task::spawn(async move {
 | 
				
			||||||
 | 
					            if let Err(err) = http1::Builder::new()
 | 
				
			||||||
 | 
					                .serve_connection(stream, service_fn(hello))
 | 
				
			||||||
 | 
					                .await
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                println!("Error serving connection: {:?}", err);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Проверяем, компилируем и сжимаем.
 | 
				
			||||||
 | 
					Получаем бинарник размером в __236 килобайт__.
 | 
				
			||||||
 | 
					Теперь загружаем в устройство, запускаем и проверяем:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```bash
 | 
				
			||||||
 | 
					scp ./target/mipsel-unknown-linux-musl/release/ramips-rs openwrt:/tmp/
 | 
				
			||||||
 | 
					ssh openwrt /tmp/ramips-rs
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					curl -L "http://10.0.0.2:3000"
 | 
				
			||||||
 | 
					# Hello, World!
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Работает как и задумано.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## Полезные ссылки и источники
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- [Building Rust code for my OpenWrt Wi-Fi router](https://blog.dend.ro/building-rust-for-routers/)
 | 
				
			||||||
 | 
					- [Cross Compile Rust For OpenWRT](https://www.kiloleaf.com/posts/cross-compile-rust-for-openwrt/)
 | 
				
			||||||
 | 
					- [Minimizing Rust Binary Size](https://github.com/johnthagen/min-sized-rust)
 | 
				
			||||||
 | 
					- [Кросс-компиляция программ Rust для запуска на маршрутизаторе](https://dzen.ru/media/nuancesprog.ru/krosskompiliaciia-programm-rust-dlia-zapuska-na-marshrutizatore-5f6457b8bdfa745d402cd1ec)
 | 
				
			||||||
							
								
								
									
										59
									
								
								_posts/2023-05-04-create-lib-file-from-dll.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										59
									
								
								_posts/2023-05-04-create-lib-file-from-dll.md
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,59 @@
 | 
				
			|||||||
 | 
					---
 | 
				
			||||||
 | 
					description: >-
 | 
				
			||||||
 | 
					    Learn how to generate a *.lib file from a *.dll with this comprehensive guide. Using the Visual Studio Command Prompt and Microsoft's recommended tools, this article walks you through the steps for a seamless process. Perfect for developers working with 3rd party win dll's.
 | 
				
			||||||
 | 
					title: Create ".lib" file from ".dll" (archive)
 | 
				
			||||||
 | 
					layout: post
 | 
				
			||||||
 | 
					---
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					> This's a copy of a non-my post.
 | 
				
			||||||
 | 
					> The original article [is here](https://adrianhenke.wordpress.com/2008/12/05/create-lib-file-from-dll/) ([archive](https://web.archive.org/web/20161118122539/https://adrianhenke.wordpress.com/2008/12/05/create-lib-file-from-dll/)).
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					When working with 3rd party win dll's you sometimes miss the according to the `*.lib` file required to compile against it.
 | 
				
			||||||
 | 
					There is an [Microsoft KB-Q131313](http://support.microsoft.com/?scid=kb%3Ben-us%3B131313&x=1&y=15) ([archive](https://jeffpar.github.io/kbarchive/kb/131/Q131313/)) article showing how to generate a `*.lib` file from a `*.dll` however the required steps are not described detailed enough I think.
 | 
				
			||||||
 | 
					So here is my quick guide.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Open the "Visual Studio Command Prompt", you find its shortcut in "_Start_" -> "_Programs_" -> "_Microsoft Visual Studio Tools_".
 | 
				
			||||||
 | 
					Now run the `dumpbin` command to get a list of all exported functions of your dll:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```bash
 | 
				
			||||||
 | 
					dumpbin /exports C:\\yourpath\\yourlib.dll
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					This will print quite a bit of text to the console.
 | 
				
			||||||
 | 
					However, we are only interested in the functions:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					ordinal hint RVA      name
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					1    0 00017770 jcopy_block_row
 | 
				
			||||||
 | 
					2    1 00017710 jcopy_sample_rows
 | 
				
			||||||
 | 
					3    2 000176C0 jdiv_round_up
 | 
				
			||||||
 | 
					4    3 000156D0 jinit_1pass_quantizer
 | 
				
			||||||
 | 
					5    4 00016D90 jinit_2pass_quantizer
 | 
				
			||||||
 | 
					6    5 00005750 jinit_c_coef_controller
 | 
				
			||||||
 | 
					...etc
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Now copy all those function names (only the names!) and paste them into a new text file.
 | 
				
			||||||
 | 
					Name the next file `yourlib.def` and put the line "EXPORTS" at its top.
 | 
				
			||||||
 | 
					My `yourlib.def` file looks like this:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					EXPORTS
 | 
				
			||||||
 | 
					jcopy_block_row
 | 
				
			||||||
 | 
					jcopy_sample_rows
 | 
				
			||||||
 | 
					jdiv_round_up
 | 
				
			||||||
 | 
					jinit_1pass_quantizer
 | 
				
			||||||
 | 
					jinit_2pass_quantizer
 | 
				
			||||||
 | 
					jinit_c_coef_controller
 | 
				
			||||||
 | 
					...
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Now from that definition file, we can finally create the `*.lib` file.
 | 
				
			||||||
 | 
					We use the `lib` tool for this, so run this command in your "Visual Studio Command Prompt":
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```bash
 | 
				
			||||||
 | 
					lib /def:C:\\mypath\\mylib.def /OUT:C:\\mypath\\mylib.lib
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					That's it, happy coding 🙂
 | 
				
			||||||
		Reference in New Issue
	
	Block a user