Source Code
197 subscribers
30 photos
3 files
80 links
Download Telegram
#algorithms
Двоичная куча

Двоичная куча — ещё одна древовидная структура данных. В ней у каждого узла не более двух потомков. Также она является совершенным деревом: это значит, что в ней полностью заняты данными все уровни, а последний заполнен слева направо.

Двоичная куча может быть минимальной или максимальной. В максимальной куче ключ любого узла всегда больше ключей его потомков или равен им. В минимальной куче всё устроено наоборот: ключ любого узла меньше ключей его потомков или равен им.

Порядок уровней в двоичной куче важен, в отличие от порядка узлов на одном и том же уровне. На иллюстрации видно, что в минимальной куче на третьем уровне значения идут не по порядку: 10, 6 и 12.
#java
Интерфейс Comparable

Comparable обеспечивает единую последовательность сортировки. Другими словами, мы можем отсортировать коллекцию на основе одного элемента, такого как идентификатор, имя и цена.

Comparable влияет на исходный класс, т.е. модифицируется фактический класс.

Comparable предоставляет метод compareTo() для сортировки элементов.

Мы можем отсортировать элементы списка типа Comparable методом Collections.sort(List).
#java
Интерфейс Comparator

Comparator предоставляет несколько последовательностей сортировки. Другими словами, мы можем отсортировать коллекцию по нескольким элементам, таким как идентификатор, имя, цена и т. д.

Comparator не влияет на исходный класс, т.е. фактический класс не изменяется.

Comparator предоставляет метод compare() для сортировки элементов.

Мы можем отсортировать элементы списка типа Comparator методом Collections.sort(List, Comparator).
#history #longRead
Unicode: как человечество пришло к международному стандарту кодирования символов

Еще
в 18 веке существовала потребность в быстрой передаче информации на большие расстояния, для чего использовались так называемые телеграфные коды. Информация кодировалась с помощью оптических, электронных и других средств.

В течение сотен лет, прошедших с момента изобретения первого телеграфного кода, не было никаких реальных попыток международной стандартизации таких схем кодирования. Даже первые десятилетия эры телетайпов и домашних компьютеров мало что изменили. Несмотря на то, что EBCDIC (8-битная кодировка символов IBM, продемонстрированная на перфокарте в заглавной иллюстрации) и ASCII немного улучшили ситуацию, способа кодировать растущую коллекцию символов без значительных затрат памяти все еще не было.

Развитие Юникода началось в конце 1980-х годов, когда рост обмена цифровой информацией во всем мире сделал потребность в единой системе кодирования более насущной.

Удивительно, что всего в 16 битах Unicode удалось охватить не только все западные системы письма, но и многие китайские иероглифы и множество специальных символов, используемых, например, в математике. С 16 битами, допускающими до 65 536 кодовых точек, Unicode 1.0 легко вмещал 7 129 символов. Но к моменту появления Unicode 3.1 в 2001 году он содержал не менее 94 140 символов.

Сейчас, в своей 13 версии, Unicode содержит в общей сложности 143 859 символов, не считая управляющих. Изначально Unicode предполагалось использовать только для кодирования систем записи, которые применяются в настоящее время. Но к релизу Unicode 2.0 в 1996 году стало понятно, что эту цель следует переосмыслить, чтобы кодировать даже редкие и исторические символы. Чтобы достичь этого без обязательной 32-битной кодировки каждого символа, Unicode изменился: он позволил не только кодировать символы напрямую, но и использовать их компоненты, или графемы.

Концепция в чем-то похожа на векторные изображения, где не указывается каждый пиксель, а вместо этого описываются элементы, составляющие рисунок. В результате кодировка Unicode Transformation Format 8 (UTF-8) поддерживает 231 кодовую точку, при этом для большинства символов в текущем наборе символов Unicode обычно требуется один-два байта.
#definition

JFR – это механизм легковесного профилирования Java-приложения. Он позволяет записывать и в последствии анализировать огромное количество метрик и событий, происходящих внутри JVM, что значительно облегчает анализ проблем. Более того, при определённых настройках его накладные расходы настолько малы, что многие (включая Oracle) рекомендуют держать его постоянно включённым везде, в том числе прод, чтобы в случае возникновения проблем сразу иметь полную картину происходившего с приложением. Просто мечта любого SRE!

Раньше этот механизм был доступен только в коммерческих версиях Java от корпорации Oracle версии 8 и более ранних. В какой-то момент его реимплементировали с нуля в OpenJDK 12, затем бекпортировали в OpenJDK 11, которая является LTS-версией. Однако вот OpenJDK 8 оставалась за бортом этого праздника жизни. Вплоть до выхода апдейта 8u272, в который наконец-то тоже бекпортировали JFR. Теперь все (за редким исключением) пользователи OpenJDK могут начинать использовать эту функциональность.

Активировать JFR можно несколькими путями. Один из них – задать соответствующие параметры при запуске Java-приложения. Для этого необходимо использовать два параметра:

java -XX:StartFlightRecording=filename=/path/to/record/file.jfr

Или:
java -XX:StartFlightRecording:filename=/path/to/record/file.jfr
#general

Однобуквенные языки программирования. Часть І

*Если интересна вторая часть, то проявите активность

А
Язык программирования A+ является потомком APL, как и другие языки на этой странице, потому что сообщество APL любит однобуквенные имена. Артур Уитни (создатель многих диалектов APL) создал A, затем Морган Стенли расширил его до A+.

B
Язык программирования B является предшественником C и в наши дни больше не используется.

C
Нет необходимости представлять C. Мы также можем считать C++ и C #, поскольку разрешены небуквенные и нецифровые символы.

D
D — это улучшенный C++. Если у вас есть возможность выбирать языки, считайте это рекомендацией проверить D!

E
Язык программирования E — довольно уникальный язык. Он ориентирован на распределенное программирование, а также на обеспечение безопасности.

Существует также Amiga E, который часто называли просто E. Воутер ван Оортмерссен задумывал его как язык сценариев для игр и описывает его как «огромный успех, он стал одним из самых популярных языков программирования на amiga.» Он доступен как бесплатная программа.

F
F# относительно хорошо известен. По сути, O'Caml портировали на .NET.

Также существует F, который является подмножеством Fortran. Он должен быть проще в обучении, использовании и откладке, чем полный Fortran.

F* — это функциональный язык программирования типа ML, предназначенный для проверки программ. Основным текущим вариантом использования F* является создание проверенной и удобной замены всего стека HTTPS.

G
G-код также называется языком программирования G, поэтому он подходит. Язык программирования устройств с числовым программным управлением (ЧПУ). Похоже на ассемблеры.

Внутри LabView есть настоящий язык программирования G. Это язык графического потока данных.

H
H — текстовый язык со слабой типизацией. О нём известно не так много.

Есть еще один H, который не менее полезен. H не является продуктивным инструментом. Вы не можете создать ничего полезного с помощью H.

I
I — это язык, вдохновленный J, который хочет расширить фокус с массивов на большее количество структур данных.

J
J — еще один потомок APL и, вероятно, самый популярный. Например, в Rosetta Code J — один из наиболее популярных языков.

K
K — один из главных потомков APL Артура Уитни. Это коммерческий продукт, используемый в банках для финансирования и торговли.

L
L был языком, который дал синтаксис C для TCL.
L является братом E по HP Labs. L — это подмножество Common Lisp.

L — это теоретический язык в книге «Вычислимость, сложность и языки: основы теоретической информатики».

M
Язык M был изобретен Французским Управлением государственных финансов (DGFiP), эквивалентным IRS, для преобразования налогового кода в машиночитаемые инструкции. Это небольшой предметно-ориентированный язык, основанный на объявлениях переменных и арифметических операциях. Реверс-инжиниринг компилятора доступен здесь.

N
Из запейволленой публикации 1989 года:
Ожидая в ближайшем будущем широкого использования алгоритмов нейронных сетей, наша цель — получить полную среду разработки программного обеспечения для программирования и тестирования новых приложений. Мы намерены создать язык высокого уровня для спецификации нейронных сетей как часть такой среды.
Однобуквенные языки программирования. Часть ІІ

О
O — это стековый язык с однобуквенными командами. Например, «io» читает строку ввода (i), а затем выводит ее (o).

P
Язык программирования P предназначен для асинхронного программирования, управляемого событиями. Он использовался для реализации и проверки стека драйверов USB-устройств, поставляемого с Microsoft Windows 8 и Windows Phone.

P′′ — это примитивный формальный язык с 1964 года. Это был первый язык без GOTO, подтверждённо полный по Тьюрингу. Brainfuck — это P ′′ плюс IO.

P# — это интерпретатор Пролога для .NET.

Q
Q — это оболочка вокруг K и базы данных kdb+, чтобы сделать ее более читаемой.

Другой язык Q — это функциональный язык программирования, основанный на переписывании терминов. Его сменил Pure.

Существует также Q#, «предметно-ориентированный язык программирования, используемый для выражения квантовых алгоритмов. Он должен использоваться для написания подпрограмм, которые выполняются на дополнительном квантовом процессоре под управлением классической главной программы и компьютера».

R
R — хорошо известный язык статистического программирования. Он считается наравне с коммерческими инструментами, такими как SAS.

S
S — это язык статистического программирования, а R считается реализацией. Большая часть кода S работает в R.

Т
T — диалект Scheme или Lisp. Последний релиз был в 1984 году, так что его можно считать мертвым.

U
Язык программирования U — личный проект Роба Апкрафта. Он хотел простой C-подобный язык для написания собственной операционной системы.

V
В сводке за 1985 год упоминается язык программирования V.

W
W был создан Виктором Тотом в 2001 году для программирования двух старинных компьютеров от HP. Это очень простой язык, описываемый как C, без ключевых слов, типов и стандартной библиотеки.

X
X# — это язык программирования низкого уровня, где-то между сборкой x86 и C. Он разработан в рамках Cosmos, набора инструментов для операционной системы с открытым исходным кодом.

X++ — это язык программирования, используемый в одном из программных продуктов Microsoft для планирования ресурсов предприятия. Он является производным от C++ и добавляет сборщик мусора и синтаксис запросов SQL.

Y
https://dl.acm.org/doi/10.1145/954269.954278

Z
Z-нотация — это формальный язык спецификаций, стандартизированный как ISO/IEC13568:2002.

Другой Z — крошечный, строгий, нечистый, каррированный, частично прикладной язык программирования с довольно своеобразным синтаксисом.
#java
Методы Stream API (1/n)

filter
Отфильтровывает записи, возвращает только записи, соответствующие условию.

skip
Позволяет пропустить N первых элементов.

distinct
Возвращает стрим без дубликатов (для метода equals)

map
Преобразует каждый элемент стрима

limit
Позволяет ограничить выборку определенным количеством первых элементов

sorted
Позволяет сортировать значения либо в натуральном порядке, либо задавая Comparator
#java
Многопоточность (1/n)

Многопоточность — это свойство системы выполнять несколько вычислений одновременно, тем самым ускоряя процесс этого вычисления. Например, когда Вы играете в компьютерные игры, вы видите, что Ваш персонаж выполняет определенное действие, другие персонажи, анимация, звук. Это все отдельные потоки если говорить примитивно.

В языке Java есть стандартный класс, который реализует многопоточность: Thread, который имплементирует Runable интерфейс. Для того, чтобы реализовать многопоточность в своей программе нужно унаследовать свой класс от Thread или имплементировать интерфейс Runable.

В классе Thread есть метод run() и start(), которые созданы чтобы делать вычисления и запускать выполнение кода соответственно. То есть в методе run() мы пишем, что хотим выполнить, а когда вызываем метод start(), он автоматически запускает наш код в run.

Потоки имеют определенные состояния. Всего их 4:

создание (когда мы написали new Thread();
старт (thread1.start());
выполнение (пока выполняется метод run());
завершение (когда поток выполнил свою работу).
Стоит публиковать различные технические книги в канал?
Anonymous Poll
91%
Да
9%
Нет
#java
Многопоточность (2/n)

Как видим на рисунке (пред. пост), поток может еще и ожидать. Для того, чтобы на время заставить поток прекратить свою работу в классе есть метод wait(), который приостанавливает выполнение пока не будет вызван метод notify(). Неправильно говорить, что это методы класса потока. Это методы объекта. Может у Вас когда то будет вопрос на тесте или собеседовании назвать методы класса Object; тогда к тем методам что Вы вспомните можете смело называть wait() и notify().

Из статических методов есть метод sleep(), который принимает целочисленную переменную в качестве миллисекунд на который следует приостановить поток. Вызов этого метода можно осуществлять в любом месте кода, где Вы желаете приостановить или замедлить выполнение. Я часто использовал этот метод в циклах, когда нужно было в консоли увидеть большое количество данных и найти нужное.

Есть еще метод yield(), при вызове которого, поток на время прекращает работу, позволяя другим потокам тоже выполниться.

Чтобы уничтожить потоки есть методы stop() и destroy(). Разница между ними в том, что при вызове destroy() поток уже нельзя возобновить. Можно прервать выполнение потока вызвав метод interrupt().
Чистый_код_Создание,_анализ_и_рефакторинг_Роберт_Мартин_Роберт_Мартин
6 MB
#books
Чистый код. Создание, анализ и рефакторинг. Роберт Мартин

Прочитав книгу, вы узнаете много нового о коде. Более того, вы научитесь отличать хороший код от плохого. Вы узнаете, как писать хороший код и как преобразовать плохой код в хороший.

Книга состоит из трех частей. В первой части излагаются принципы, паттерны и приемы написания чистого кода; приводится большой объем примеров кода.
Вторая часть состоит из практических сценариев нарастающей сложности. Каждый сценарий представляет собой упражнение по чистке кода или преобразованию проблемного кода в код с меньшим количеством проблем.
Третья часть книги - концентрированное выражение ее сути. Она состоит из одной главы с перечнем эвристических правил и "запахов кода", собранных во время анализа. Эта часть представляет собой базу знаний, описывающую наш путь мышления в процессе чтения, написания и чистки кода.
#news

Автономный мягкий робот впервые погрузился в Марианскую впадину

Автономный мягкий робот, прообразом которого является рыба Pseudoliparis swirei, выдержал невероятное давление глубин Марианской впадины.

Бездна Челленджера – глубочайшая из глубин Мирового океана. Она уходит примерно на 10990 метров ниже уровня моря. В этом месте огромный слой воды оказывает на морское дно колоссальное давление, более чем в тысячу раз превышающие показатели атмосферного давления на уровне моря, что соответствует приблизительно 108,6 МПа. Это сравнимо с давлением веса целого слона, который балансирует на кончике Вашего большого пальца.

https://www.youtube.com/watch?v=gkuL4AYlExE
#backEnd #NodeJS

Релиз Node.js 16

20 апреля состоялся релиз новой 16 версии Node.js. Среди основных изменений обновление движка JavaScript V8 до версии 9.0, встроенные бинарники (двоичные файлы) для Apple Silicon и несколько API, но обо всем по порядку.

Из основных изменений движка можно назвать поддержку индексов соответствия в регулярных выражениях (regexp match indices), а также улучшение (повышение скорости) доступа к свойству «super».

Идексы соответствия позволяют разработчикам получать массив подмассивов, содержащих начальные и конечные позиции (индексы) групп захвата (capture groups) в регулярном выражении при наличии совпадения (или нескольких совпадений). Данный массив доступен через свойство «indices» объекта с совпадениями. Обратите внимание, что регулярное выражение, используемое для поиска совпадений, должно иметь флаг «/d».

const re = /(a)(b)/d // Регулярное выражение. Обратите внимание на наличие флага /d

const m = re.exec('ab') // Объект с совпадениями

console.log(m.indices[0]) // Первый подмассив — это полное совпадение

// [0, 2]

console.log(m.indices[1]) // Второй подмассив — первая группа захвата

// [0, 1]

console.log(m.indices[2]) // Третий подмассив — вторая группа захвата

// [1, 2]

Доступ к свойству «super» был улучшен за счет использования системы встроенного кэша и оптимизации генерации кода в «TurboFan» (TurboFan — это компилятор, за интепретацию кода в V8 отвечает Ignition). Как утверждают разработчики V8, скорость доступа к super стала почти такой же, как скорость доступа к обычному свойству.

Timers Promises API предоставляет альтернативный набор таймеров, возвращающих объект «Promise», что избавляет от необходимости использования util.promisify().

import { setTimeout } from 'timers/promises'

async function run() {

const greet = await setTimeout(3000, 'Hi!')

console.log(greet) // Hi!

}

run()

Timers Promises API был представлен в Node.js 15 в качестве экспериментальной возможности. Теперь он приобрел статус стабильного интерфейса.
#news #science #space

NASA выбрало SpaceX для полета на Луну, и это ключевой момент в истории космонавтики

Через несколько лет астронавты NASA собираются вернуться на Луну. И условия возвращения куда более комфортабельны, чем те, что были у первопроходцев. Все потому, что возвращаться они будут на Starship, длина которого от хвоста до носа составляет 50 метров. А вот Базз Олдрин с Нилом Армстронгом довольствовались всего 7 метрами. Им было не просто тесно, а очень тесно, что можно видеть на фотографиях того времени.

Отличает эту экспедицию еще и то, что она будет реализована силами частной компании — SpaceX.

Частная компания — и только она — ответственна за проектирование, тестирование и реализацию двух полетов на Луну. Один из них, пилотируемый, должен состояться уже в 2024 году.

Конечно, все это далеко не бесплатно: SpaceX получила $2,89 млрд на реализацию проекта. Это огромные средства, но потрачены они во благо — компания Илона Маска сможет значительно ускорить процесс подготовки полета. Частная компания более свободна в своих действиях, чем государственное агентство, а Маск известен тем, что, хотя и с задержкой, но успешно реализует большинство намеченных планов.
#math #longRead

Как выглядит самое красивое математическое уравнение?

Давайте вспомним о тождестве Эйлера — по праву самом красивом уравнении, важное место в котором занимает число e, но не только оно. Представьте на секунду, что вы почти ничего не знаете о математике, только начинаете открывать её бесконечную красоту — и наслаждайтесь.

Все мы знаем о числе π — магическом отношении длины окружности к её диаметру. Число π можно приближённо представить в виде дроби 22/7. Особенность числа π состоит в том, что в его десятичной записи знаки после запятой никогда не заканчиваются. Его приближённое значение — 3,141592653589793238… Вот почему π называют иррациональным числом — его нельзя записать в виде конечного числа цифр после запятой. А вот другое интересное иррациональное число — e. Число e — это "число Эйлера" (от Euler). Вот первые несколько цифр числа e: 2,7182818284590…

Поговорим теперь о другом интересном математическом объекте. Он называется просто: i. Разберёмся, что это такое.

Если умножить 2 на 2, получится 4. То есть 2 в квадрате равняется 4. Квадрат положительного числа — это положительное число. Но, если возвести в квадрат –2, также получится 4, то есть положительное число. Другими словами, ни один квадрат действительного числа не может быть отрицательным числом. Вот тут-то и возникает понятие мнимого числа.

Число √-1 записывается буквой i. i означает мнимую (imaginary) единицу. То есть запись √-5 можно заменить записью √5 i. Отсюда следует, что i² = -1. Число i формирует множество комплексных чисел, то есть комбинаций действительных и мнимых чисел. Например, запись 8 + i√5 является комплексным числом. Для визуализации комплексных чисел используется плоскость мнимых чисел.

Изучать свойства комплексных чисел математики начали примерно с середины XVIII века. Однажды Эйлер развлекался с женой Тейлора... ох, простите... с рядом Тейлора.

https://numl.org/Hxd

Этому сумасброду просто стало интересно, как будет вести себя ряд Тейлора, если подставить в него число i (а что, вполне нормальная мысль для любого сумасброда).

Одни члены ряда, содержащие i, сводятся в одну группу, а другие, не содержащие мнимую часть, то есть без числа i, — в другую. Получаются два ряда Тейлора: один — для косинуса, другой — для синуса.

Мы получили знаменитую формулу Эйлера. Различные значения x и e^(ix) можно отразить на комплексной плоскости.

Это комплексное число, которое может быть представлено на комплексной плоскости. Если продолжить наносить на график точки e^(ix) для разных значений x, получится окружность.

https://numl.org/Hxe

Если нужно узнать радиус r в любой точке (например, в точке 5 + 7i), рассчитывается значение x и берётся действительная часть re^(ix).

Объединив три самых необыкновенных математических символа, получаем магическое уравнение:
#network

New IP — следующий этап развития Интернета или ужесточение контроля над пользователями

В
марте 2021 года Китай опубликовал свой 14-й пятилетний план экономического развития, включая намеченные следующие шаги в области технологий. В проекте чётко говорится, что Китай и его сетевой гигант Huawei готовятся к тому, чтобы их видение Интернета стало глобальным.

Планы Huawei в отношении 6G и выше делают озабоченность США по поводу 5G ничтожной: Huawei предлагает фундаментальный редизайн Интернета, которое называется «New IP», призванный обеспечить «внутреннюю безопасность» в сети. Внутренняя безопасность означает, что отдельные лица должны зарегистрироваться для использования Интернета, а органы власти могут в любой момент отключить доступ к Интернету отдельного пользователя. Короче говоря, Huawei стремится интегрировать китайские режимы «социального кредита», слежки и цензуры в архитектуру Интернета. А по замыслу разработчиков новый протокол выведет интернет на новый уровень и позволит быстрее развивать существующие телекоммуникационные сервисы и внедрять новые, в том числе технологию голографического присутствия.

В New IP реализован специальный алгоритм «отключения» (killswitch), позволяющий блокировать все данные, поступающие из сети на определенный адрес или с него в сеть. Делать это можно будет в любой момент времени, и это означает, что регуляторы интернета смогут не только моментально отключать неугодные ресурсы, но и блокировать доступ к интернету конкретных людей, в буквальном смысле вычисляя их по IP-адресу. Переход на New IP также может потребовать авторизации и аутентификации как новых интернет-адресов, так и людей, связанных с ними. Другими словами, New IP подразумевает полное отсутствие анонимности и приватности в интернете и напоминает глобальную версию «Великого китайского файервола», блокирующего жителям КНР доступ ко многим международным ресурсам.

New IP имеет три ключевые особенности:

Изменяемая длина IP-адреса для беспрепятственной поддержки межсетевого взаимодействия;
Семантическое определение IP-адреса для идентификации физических и виртуальных объектов;
Определяемый пользователем IP-заголовок, позволяющий конечным пользователям указывать настраиваемые функции, выполняемые с пакетами данных.

https://www.huawei.com/us/industry-insights/innovation/new-ip
#principles
Внедрение зависимостей (Dependency injection, DI)

Внедрение зависимостей — это стиль настройки объекта, при котором поля объекта задаются внешней сущностью. Другими словами, объекты настраиваются внешними объектами. DI — это альтернатива самонастройке объектов.

Эта концепция состоит в том, чтобы перенести ответственность за создание экземпляра объекта из тела метода за пределы класса и передать уже созданный экземпляр объекта обратно.

Звучит это все довольно абстрактно, так что вот пример:

Представьте себе очень простую зависимость между двумя классами: класс «Автомобиль» (Car) зависит от класса «Двигатель» (CarEngine).

Однако, мы знаем, что это стоит программировать с помощью интерфейса: (№1)

Но, чтобы изолировать класс Car, недостаточно ввести интерфейс Engine. В коде класса Car также должно быть невозможным создание нового экземпляра класса CarEngine: (№2)

Теперь с помощью этого дизайна можно создавать экземпляры класса Car: (№3)
#backEnd

Личный сервер shadowsocks за 10 минут без затрат

shadowsocks
- это шифрованный сетевой туннель, клиентская часть которого предоставляет доступ приложениям к сети как SOCKS-прокси, запущенный на этом же устройстве. В некотором смысле его можно использовать как VPN, потому что клиенты поддерживают прозрачное перенаправление трафика приложений в туннель

В этом руководстве используется замечательный проект готового приложения для Heroku, которое реализует всё необходимое автоматически.

Ссылка на GitHub проекта. https://github.com/aditya-shri/VPN

Шаг 1. Регистрация в сервисе Heroku
Для этого нужно зайти на сайт Heroku, нажать Sign up и заполнить требуемые сведения. Для регистрации нужна только электронная почта.

Шаг 2. Начало развёртывания
Нажмите на эту ссылку.
https://dashboard.heroku.com/new?template=https%3A%2F%2Fgithub.com%2Faditya-shri%2FVPN%2Ftree%2Fmain

Шаг 3. Конфигурирование
В появившейся форме заполните все поля как показано на скриншоте:

В качестве значений "App Name" и AppName впишите какое-то уникальное имя приложения, одинаковое в обоих полях. Это имя станет частью доменного имени appname.herokuapp.com, по которому станет доступен сервис.

Вместо PASSWORD задайте свой пароль. Можно задать подлиннее и понадёжнее - Вам, скорее всего, не придётся вводить его вручную.

Кроме того, желательно поменять пути QR и путь обработчика прокси V2_Path на какое-нибудь трудноугадываемое значение.

Шаг 4
Заполнив форму, нажмите Deploy app.

После завершения сборки и запуска QR-код с конфигурацией для мобильных устройств будет доступен по адресу

https://APPNAME.herokuapp.com/qr/vpn.png

а строка с конфигурацией в виде URL будет доступна по адресу

https://APPNAME.herokuapp.com/qr/

где APPNAME - выбранное Вами имя приложения. Если Вы меняли путь к QR-коду, то ссылка изменится в соответственно. Во второй ссылке косая черта на конце обязательна.

Всё, можно пользоваться!
#java
Интерфейс Comparable ♨️

Небольшое вступление. Мы создали класс ArrayList в котором хранятся объекты класса String - имена ваших коллег. Вы захотели отсортировать вашу коллекцию, написав Collections.sort(ваш ArrayList с именами), хорошо. Оно их действительно отсортирует, но как?

String реализует интерфейс Comparable (сравнимый, который поддается сравнению). В этом методе описывается как именно объекты должны сравниваться друг с другом. Поскольку это строка, объекты класса String сравниваются лексикографически, если не ошибаюсь, то есть по алфавиту.

Другое дело, мы создали наш собственный клас, к примеру, Person (человек), и хотим как то их сравнивать, но как? Если мы создадим список наших объектов, и захотим их отсортировать у нас будет ошибка, так как метод sort не будет знать как именно это делать. Для этого и существует интерфейс Comparable.

(№1) Мы создали класс Person, у него есть поле height, за которым будет производится сравнивание. Имплементируем метод compareTo(), он возвращает целое число. Единица, если текущий объект больше за другой, 0 если объекты равны, -1 если текущий объект меньше.

То есть этим методом мы показываем как именно и за каким "свойством" будут сравнивается объекты "нашего" типа.

(№2) Тестируем сортировку объектов нашего класса.
#java
Разница между equals() и compareTo()

Метод equals() проверяет объекты на равенство, то есть возвращает просто логическое значение - true/false.

compareTo() сравнивает объекты, и возвращает 0 если объекты равны, 1(или другое положительное число) если объект больше другого объекта, -1(или другое отрицательное число) - объект меньше другого объекта.

♨️ При реализации интерфейсного метода Comparable compareTo, мы решаем как именно наши объекты будут сравниваться с друг с другом.
♨️В свою очередь, equals просто говорит нам, равны ли 2 объекта.