3. Пример использования переменных окружения
Объяснение:
Мы добавляем переменную окружения VAR_NAME и используем ее в команде echo.
4. Пример наследования ввода-вывода
Объяснение:
Мы используем inheritIO(), чтобы вывод и ошибки процесса отображались в консоли текущего процесса.
5. Пример обработки ошибок и вывода
Объяснение:
Мы читаем как стандартный вывод, так и вывод ошибок, чтобы обработать все возможные сценарии.
#Java #Training #Medium #Process_API #ProcessBuilder
import java.io.IOException;
import java.util.Map;
public class ProcessBuilderEnvironmentExample {
public static void main(String[] args) {
try {
ProcessBuilder processBuilder = new ProcessBuilder("echo", "$VAR_NAME");
// Получаем переменные окружения
Map<String, String> env = processBuilder.environment();
env.put("VAR_NAME", "Hello, World!");
// Запускаем процесс
Process process = processBuilder.start();
// Чтение вывода
BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
String line;
while ((line = reader.readLine()) != null) {
System.out.println("Вывод: " + line);
}
int exitCode = process.waitFor();
System.out.println("Процесс завершен с кодом: " + exitCode);
} catch (IOException | InterruptedException e) {
e.printStackTrace();
}
}
}
Объяснение:
Мы добавляем переменную окружения VAR_NAME и используем ее в команде echo.
4. Пример наследования ввода-вывода
import java.io.IOException;
public class ProcessBuilderInheritIOExample {
public static void main(String[] args) {
try {
ProcessBuilder processBuilder = new ProcessBuilder("ls", "-l");
// Наследуем ввод, вывод и ошибки
processBuilder.inheritIO();
// Запускаем процесс
Process process = processBuilder.start();
// Ждем завершения процесса
int exitCode = process.waitFor();
System.out.println("Процесс завершен с кодом: " + exitCode);
} catch (IOException | InterruptedException e) {
e.printStackTrace();
}
}
}
Объяснение:
Мы используем inheritIO(), чтобы вывод и ошибки процесса отображались в консоли текущего процесса.
5. Пример обработки ошибок и вывода
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
public class ProcessBuilderErrorHandling {
public static void main(String[] args) {
try {
ProcessBuilder processBuilder = new ProcessBuilder("invalid_command");
// Запускаем процесс
Process process = processBuilder.start();
// Чтение вывода ошибок
BufferedReader errorReader = new BufferedReader(new InputStreamReader(process.getErrorStream()));
String line;
while ((line = errorReader.readLine()) != null) {
System.out.println("Ошибка: " + line);
}
// Чтение стандартного вывода
BufferedReader outputReader = new BufferedReader(new InputStreamReader(process.getInputStream()));
while ((line = outputReader.readLine()) != null) {
System.out.println("Вывод: " + line);
}
int exitCode = process.waitFor();
System.out.println("Процесс завершен с кодом: " + exitCode);
} catch (IOException | InterruptedException e) {
e.printStackTrace();
}
}
}
Объяснение:
Мы читаем как стандартный вывод, так и вывод ошибок, чтобы обработать все возможные сценарии.
#Java #Training #Medium #Process_API #ProcessBuilder
👍1
This media is not supported in your browser
VIEW IN TELEGRAM
Всем доброго субботнего утра! ☀️
Как ваше настроение?
А я сижу над недописанным сервисом доставки, и понимаю что не хочу его дописывать...😏
Скорее потому, что его проще переписать сначала🤓
Да и готовиться надо, чтобы радовать Вас контентом, а не своими размышлениями и поисками правильного решения🫢
Поэтому я принял решение убрать этот недописанный сервис из видео. Когда-нибудь мы обязательно к нему вернемся и напишем полностью за один присест😎
Ну и чтобы нам было для чего встречаться по воскресениям, я решил разбить создание подобных сервисов на максимально глубокое, пошаговое изучение:
⚡ Аннотаций в контроллере
⚡ Работу JPA-аннотаций
⚡ Мапперы и все то с ними связано
⚡ Спецификаций и пагинации для вывода данных
Ну и еще что-нибудь)) Пока накидал так, что сразу в голову пришло😉
Как Вам план?🤨
А в остальном всем прекрасных выходных!✌️
Как ваше настроение?
А я сижу над недописанным сервисом доставки, и понимаю что не хочу его дописывать...
Скорее потому, что его проще переписать сначала
Да и готовиться надо, чтобы радовать Вас контентом, а не своими размышлениями и поисками правильного решения
Поэтому я принял решение убрать этот недописанный сервис из видео. Когда-нибудь мы обязательно к нему вернемся и напишем полностью за один присест
Ну и чтобы нам было для чего встречаться по воскресениям, я решил разбить создание подобных сервисов на максимально глубокое, пошаговое изучение:
Ну и еще что-нибудь)) Пока накидал так, что сразу в голову пришло
Как Вам план?
А в остальном всем прекрасных выходных!
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥8
Всем привет!
Предлагаю сегодня в 16:00 по МСК собраться и наполнить наши головы пониманием, что же такое Mappers😉
Что мы узнаем:
- Зачем нам вообще нужны Mappers?
- Какие наиболее популярные Mappers есть?
- Рассмотрим часто встречающуюся реализацию - MapStruct.
- Напишем мини-проект в котором реализуем разные варианты настроек MapStruct, рассмотрим варианты реализаций и взаимодействий.
Как всегда жду всех! 🫵
Но увижу все тех же 🤪
Предлагаю сегодня в 16:00 по МСК собраться и наполнить наши головы пониманием, что же такое Mappers
Что мы узнаем:
- Зачем нам вообще нужны Mappers?
- Какие наиболее популярные Mappers есть?
- Рассмотрим часто встречающуюся реализацию - MapStruct.
- Напишем мини-проект в котором реализуем разные варианты настроек MapStruct, рассмотрим варианты реализаций и взаимодействий.
Как всегда жду всех! 🫵
Please open Telegram to view this post
VIEW IN TELEGRAM
👍6
Please open Telegram to view this post
VIEW IN TELEGRAM
Mapper MapStruct. Коротко о важном. Встреча от 16.02.2025
Запись нашей встречи -
YOUTUBE
RUTUBE
На сегодняшней встрече мы разобрали на примере работу мапперов - библиотек которые помогают преобразовывать объекты в друг друга. А также:
- Зачем нам вообще нужны Mappers?
- Какие наиболее популярные Mappers есть?
- Рассмотрели часто встречающуюся реализацию - MapStruct.
- Написали немного кода, посмотрели как все это работает, изучили разные варианты взаимодействий.
Смотрите, комментируйте, задавайте вопросы! Обязательно подписывайтесь на ютуб и рутюб каналы!!!
Всем хорошего настроения!🤘 🔫
Запись нашей встречи -
YOUTUBE
RUTUBE
На сегодняшней встрече мы разобрали на примере работу мапперов - библиотек которые помогают преобразовывать объекты в друг друга. А также:
- Зачем нам вообще нужны Mappers?
- Какие наиболее популярные Mappers есть?
- Рассмотрели часто встречающуюся реализацию - MapStruct.
- Написали немного кода, посмотрели как все это работает, изучили разные варианты взаимодействий.
Смотрите, комментируйте, задавайте вопросы! Обязательно подписывайтесь на ютуб и рутюб каналы!!!
Всем хорошего настроения!
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3
"Если вы будете делать то же, что и все, вы никогда не сможете быть лучше других."
Эллисон сказал это в речи для сотрудников Oracle в 1990 году.
Почитать короткую биографию
https://habr.com/ru/articles/462827/
#Citation #Biography
Please open Telegram to view this post
VIEW IN TELEGRAM
Wikipedia
Эллисон, Ларри
американский предприниматель
🔥2
Класс BigInteger в Java — основы и внутреннее устройство
В Java для работы с целыми числами, которые выходят за пределы диапазона long (от -2⁶³ до 2⁶³-1), используется класс BigInteger. Этот класс позволяет работать с числами произвольной длины, что делает его незаменимым для задач, требующих высокой точности, таких как криптография, научные вычисления и финансы.
Внутреннее устройство
Класс BigInteger хранит число в виде массива целых чисел (int[]), где каждый элемент массива представляет часть большого числа. Это позволяет BigInteger работать с числами, которые могут быть сколь угодно большими, ограничиваясь только доступной памятью.
Хранение данных: Число хранится в виде массива int[], где каждый элемент массива представляет 32 бита числа. Это позволяет эффективно использовать память и выполнять операции над большими числами.
Знак: Отдельно хранится знак числа (положительное или отрицательное).
Пример внутреннего представления числа:
Основные методы класса BigInteger
Конструкторы:
BigInteger(String val) — создает объект BigInteger из строки.
BigInteger(byte[] val) — создает объект BigInteger из массива байт.
BigInteger(int signum, byte[] magnitude) — создает объект BigInteger с указанным знаком и массивом байт.
Пример:
Арифметические операции:
add(BigInteger val) — сложение.
subtract(BigInteger val) — вычитание.
multiply(BigInteger val) — умножение.
divide(BigInteger val) — деление.
mod(BigInteger val) — остаток от деления.
Пример:
Сравнение:
compareTo(BigInteger val) — сравнивает два числа. Возвращает -1, 0 или 1, если текущее число меньше, равно или больше переданного.
equals(Object x) — проверяет равенство двух объектов BigInteger.
Пример:
Битовые операции:
and(BigInteger val) — побитовое И.
or(BigInteger val) — побитовое ИЛИ.
xor(BigInteger val) — побитовое исключающее ИЛИ.
shiftLeft(int n) — сдвиг влево на n бит.
shiftRight(int n) — сдвиг вправо на n бит.
Пример:
Другие полезные методы:
pow(int exponent) — возведение в степень.
gcd(BigInteger val) — наибольший общий делитель.
isProbablePrime(int certainty) — проверка на простоту.
Пример:
Плюсы и минусы BigInteger
Плюсы:
Поддержка чисел произвольной длины.
Высокая точность вычислений.
Богатый набор методов для арифметических и битовых операций.
Минусы:
Медленнее, чем примитивные типы данных (int, long).
Требует больше памяти для хранения больших чисел.
Пример использования
#Java #Training #Medium #BigInteger
В Java для работы с целыми числами, которые выходят за пределы диапазона long (от -2⁶³ до 2⁶³-1), используется класс BigInteger. Этот класс позволяет работать с числами произвольной длины, что делает его незаменимым для задач, требующих высокой точности, таких как криптография, научные вычисления и финансы.
Внутреннее устройство
Класс BigInteger хранит число в виде массива целых чисел (int[]), где каждый элемент массива представляет часть большого числа. Это позволяет BigInteger работать с числами, которые могут быть сколь угодно большими, ограничиваясь только доступной памятью.
Хранение данных: Число хранится в виде массива int[], где каждый элемент массива представляет 32 бита числа. Это позволяет эффективно использовать память и выполнять операции над большими числами.
Знак: Отдельно хранится знак числа (положительное или отрицательное).
Пример внутреннего представления числа:
BigInteger bigInt = new BigInteger("123456789012345678901234567890");
Внутри это число будет представлено как массив int[], где каждый элемент массива хранит часть числа.
Основные методы класса BigInteger
Конструкторы:
BigInteger(String val) — создает объект BigInteger из строки.
BigInteger(byte[] val) — создает объект BigInteger из массива байт.
BigInteger(int signum, byte[] magnitude) — создает объект BigInteger с указанным знаком и массивом байт.
Пример:
BigInteger bigInt = new BigInteger("12345678901234567890");
Арифметические операции:
add(BigInteger val) — сложение.
subtract(BigInteger val) — вычитание.
multiply(BigInteger val) — умножение.
divide(BigInteger val) — деление.
mod(BigInteger val) — остаток от деления.
Пример:
BigInteger a = new BigInteger("10000000000000000000");
BigInteger b = new BigInteger("20000000000000000000");
BigInteger sum = a.add(b); // 30000000000000000000
Сравнение:
compareTo(BigInteger val) — сравнивает два числа. Возвращает -1, 0 или 1, если текущее число меньше, равно или больше переданного.
equals(Object x) — проверяет равенство двух объектов BigInteger.
Пример:
BigInteger a = new BigInteger("100");
BigInteger b = new BigInteger("200");
int result = a.compareTo(b); // -1, так как a < b
Битовые операции:
and(BigInteger val) — побитовое И.
or(BigInteger val) — побитовое ИЛИ.
xor(BigInteger val) — побитовое исключающее ИЛИ.
shiftLeft(int n) — сдвиг влево на n бит.
shiftRight(int n) — сдвиг вправо на n бит.
Пример:
BigInteger a = new BigInteger("10"); // 1010 в двоичной системе
BigInteger b = a.shiftLeft(2); // 101000 (40 в десятичной)
Другие полезные методы:
pow(int exponent) — возведение в степень.
gcd(BigInteger val) — наибольший общий делитель.
isProbablePrime(int certainty) — проверка на простоту.
Пример:
BigInteger a = new BigInteger("17");
boolean isPrime = a.isProbablePrime(100); // true, так как 17 — простое число
Плюсы и минусы BigInteger
Плюсы:
Поддержка чисел произвольной длины.
Высокая точность вычислений.
Богатый набор методов для арифметических и битовых операций.
Минусы:
Медленнее, чем примитивные типы данных (int, long).
Требует больше памяти для хранения больших чисел.
Пример использования
import java.math.BigInteger;
public class BigIntegerExample {
public static void main(String[] args) {
BigInteger a = new BigInteger("12345678901234567890");
BigInteger b = new BigInteger("98765432109876543210");
BigInteger sum = a.add(b);
BigInteger product = a.multiply(b);
System.out.println("Сумма: " + sum);
System.out.println("Произведение: " + product);
}
}
#Java #Training #Medium #BigInteger
👍2
Что выведет код?
#Tasks
public class Task170225 {
public static void main(String[] args) {
int x = 5;
int y = 0;
if (x > 0) {
while (x > 0) {
y += x;
x--;
}
}
System.out.println(y);
}
}
#Tasks
👍2
👍1
Вопросы с собеседования 👩💻
Что делает оператор continue?
Что делает оператор continue?
Anonymous Quiz
2%
Завершает выполнение программы
94%
Пропускает текущую итерацию цикла
4%
Возвращает значение из метода
0%
Перехватывает исключения
👍2
Класс BigDecimal в Java
Класс BigDecimal в Java используется для выполнения точных арифметических операций с числами с плавающей точкой. В отличие от примитивных типов double и float, которые могут терять точность из-за особенностей двоичного представления, BigDecimal обеспечивает полный контроль над точностью и округлением. Это делает его идеальным выбором для финансовых расчетов, где важна каждая копейка.
Внутреннее устройство
BigDecimal хранит число в виде двух компонентов:
Мантисса (unscaled value): Целое число типа BigInteger, представляющее значимые цифры числа.
Масштаб (scale): Целое число, указывающее количество цифр после десятичной точки.
Пример:
Здесь:
Мантисса: 123456
Масштаб: 3 (три цифры после точки).
Основные методы класса BigDecimal
Конструкторы:
BigDecimal(String val) — создает объект BigDecimal из строки.
BigDecimal(double val) — создает объект BigDecimal из числа double (не рекомендуется из-за потери точности).
BigDecimal(BigInteger val) — создает объект BigDecimal из BigInteger.
Пример:
Арифметические операции:
add(BigDecimal val) — сложение.
subtract(BigDecimal val) — вычитание.
multiply(BigDecimal val) — умножение.
divide(BigDecimal val) — деление.
remainder(BigDecimal val) — остаток от деления.
Пример:
Округление:
setScale(int newScale, RoundingMode roundingMode) — устанавливает новый масштаб (количество знаков после точки) и применяет указанный режим округления.
RoundingMode — перечисление, определяющее стратегию округления (например, RoundingMode.HALF_UP для округления до ближайшего числа).
Пример:
Сравнение:
compareTo(BigDecimal val) — сравнивает два числа. Возвращает -1, 0 или 1, если текущее число меньше, равно или больше переданного.
equals(Object x) — проверяет равенство двух объектов BigDecimal (учитывает масштаб).
Пример:
Другие полезные методы:
abs() — возвращает абсолютное значение.
pow(int n) — возведение в степень.
stripTrailingZeros() — удаляет незначащие нули после точки.
Пример:
Плюсы и минусы BigDecimal
Плюсы:
Высокая точность вычислений.
Полный контроль над округлением.
Подходит для финансовых расчетов.
Минусы:
Медленнее, чем примитивные типы (double, float).
Требует больше памяти.
Пример использования
#Java #Training #Medium #BigDecimal
Класс BigDecimal в Java используется для выполнения точных арифметических операций с числами с плавающей точкой. В отличие от примитивных типов double и float, которые могут терять точность из-за особенностей двоичного представления, BigDecimal обеспечивает полный контроль над точностью и округлением. Это делает его идеальным выбором для финансовых расчетов, где важна каждая копейка.
Внутреннее устройство
BigDecimal хранит число в виде двух компонентов:
Мантисса (unscaled value): Целое число типа BigInteger, представляющее значимые цифры числа.
Масштаб (scale): Целое число, указывающее количество цифр после десятичной точки.
Пример:
BigDecimal decimal = new BigDecimal("123.456");
Здесь:
Мантисса: 123456
Масштаб: 3 (три цифры после точки).
Основные методы класса BigDecimal
Конструкторы:
BigDecimal(String val) — создает объект BigDecimal из строки.
BigDecimal(double val) — создает объект BigDecimal из числа double (не рекомендуется из-за потери точности).
BigDecimal(BigInteger val) — создает объект BigDecimal из BigInteger.
Пример:
BigDecimal a = new BigDecimal("123.456");
BigDecimal b = new BigDecimal(123.456); // Не рекомендуется
Арифметические операции:
add(BigDecimal val) — сложение.
subtract(BigDecimal val) — вычитание.
multiply(BigDecimal val) — умножение.
divide(BigDecimal val) — деление.
remainder(BigDecimal val) — остаток от деления.
Пример:
BigDecimal a = new BigDecimal("100.50");
BigDecimal b = new BigDecimal("20.25");
BigDecimal sum = a.add(b); // 120.75
Округление:
setScale(int newScale, RoundingMode roundingMode) — устанавливает новый масштаб (количество знаков после точки) и применяет указанный режим округления.
RoundingMode — перечисление, определяющее стратегию округления (например, RoundingMode.HALF_UP для округления до ближайшего числа).
Пример:
BigDecimal a = new BigDecimal("123.456789");
BigDecimal rounded = a.setScale(2, RoundingMode.HALF_UP); // 123.46
Сравнение:
compareTo(BigDecimal val) — сравнивает два числа. Возвращает -1, 0 или 1, если текущее число меньше, равно или больше переданного.
equals(Object x) — проверяет равенство двух объектов BigDecimal (учитывает масштаб).
Пример:
BigDecimal a = new BigDecimal("100.00");
BigDecimal b = new BigDecimal("100.0");
boolean isEqual = a.equals(b); // false, так как масштабы разные
int comparison = a.compareTo(b); // 0, так как числовые значения равны
Другие полезные методы:
abs() — возвращает абсолютное значение.
pow(int n) — возведение в степень.
stripTrailingZeros() — удаляет незначащие нули после точки.
Пример:
BigDecimal a = new BigDecimal("123.4500");
BigDecimal stripped = a.stripTrailingZeros(); // 123.45
Плюсы и минусы BigDecimal
Плюсы:
Высокая точность вычислений.
Полный контроль над округлением.
Подходит для финансовых расчетов.
Минусы:
Медленнее, чем примитивные типы (double, float).
Требует больше памяти.
Пример использования
import java.math.BigDecimal;
import java.math.RoundingMode;
public class BigDecimalExample {
public static void main(String[] args) {
BigDecimal a = new BigDecimal("100.50");
BigDecimal b = new BigDecimal("20.25");
BigDecimal sum = a.add(b);
BigDecimal product = a.multiply(b);
BigDecimal rounded = product.setScale(2, RoundingMode.HALF_UP);
System.out.println("Сумма: " + sum);
System.out.println("Произведение: " + product);
System.out.println("Округленное произведение: " + rounded);
}
}
#Java #Training #Medium #BigDecimal
👍1
А вы знали, что "Hello, World!" впервые появилось в 1974 году?
Это была демонстрация языка программирования C. Теперь же без него не начинается ни одно знакомство с кодингом.
#facts
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2
"Ценность сети растет пропорционально квадрату числа подключенных устройств."
Меткалф, изобретатель Ethernet, сформулировал этот закон в 1980 году.
Почитать короткую биографию
https://habr.com/ru/companies/edison/articles/277827/
#Citation #Biography
Please open Telegram to view this post
VIEW IN TELEGRAM
Wikipedia
Robert Metcalfe
American electrical engineer
👍1
Чтение ZIP-архивов с использованием ZipInputStream
ZIP-архивы — это популярный формат сжатия данных, который позволяет объединять несколько файлов в один архив. В Java для работы с ZIP-архивами используются классы ZipInputStream и ZipOutputStream. Начнем с чтения ZIP-архивов.
Класс ZipInputStream
ZipInputStream — это класс, который позволяет читать содержимое ZIP-архива. Он наследуется от InflaterInputStream и использует алгоритм сжатия DEFLATE для распаковки данных.
Как это работает под капотом?
Чтение структуры ZIP-архива: ZIP-архив состоит из записей (entries), каждая из которых представляет отдельный файл. Каждая запись содержит метаданные (имя, размер, метод сжатия и т.д.) и сами данные.
Распаковка данных: ZipInputStream читает каждую запись по очереди и распаковывает данные с использованием алгоритма DEFLATE.
Пример чтения ZIP-архива
Плюсы и минусы ZipInputStream
Плюсы:
Простота использования.
Поддержка потокового чтения, что позволяет работать с большими архивами без загрузки всего содержимого в память.
Минусы:
Низкоуровневый API: требует ручного управления данными и записями.
Нет встроенной поддержки для работы с паролями или шифрованием.
Нюансы использования
Всегда закрывайте ZipInputStream после использования, чтобы освободить ресурсы.
Используйте буфер для чтения данных, чтобы минимизировать количество операций ввода-вывода.
#Java #Training #Medium #ZipInputStream
ZIP-архивы — это популярный формат сжатия данных, который позволяет объединять несколько файлов в один архив. В Java для работы с ZIP-архивами используются классы ZipInputStream и ZipOutputStream. Начнем с чтения ZIP-архивов.
Класс ZipInputStream
ZipInputStream — это класс, который позволяет читать содержимое ZIP-архива. Он наследуется от InflaterInputStream и использует алгоритм сжатия DEFLATE для распаковки данных.
Как это работает под капотом?
Чтение структуры ZIP-архива: ZIP-архив состоит из записей (entries), каждая из которых представляет отдельный файл. Каждая запись содержит метаданные (имя, размер, метод сжатия и т.д.) и сами данные.
Распаковка данных: ZipInputStream читает каждую запись по очереди и распаковывает данные с использованием алгоритма DEFLATE.
Пример чтения ZIP-архива
import java.io.FileInputStream;
import java.io.IOException;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
public class ZipReaderExample {
public static void main(String[] args) {
String zipFilePath = "example.zip";
try (FileInputStream fis = new FileInputStream(zipFilePath);
ZipInputStream zis = new ZipInputStream(fis)) {
ZipEntry entry;
while ((entry = zis.getNextEntry()) != null) {
System.out.println("File: " + entry.getName());
System.out.println("Size: " + entry.getSize() + " bytes");
// Чтение содержимого файла
byte[] buffer = new byte[1024];
int len;
while ((len = zis.read(buffer)) > 0) {
// Здесь можно обработать данные, например, записать в другой файл
System.out.write(buffer, 0, len);
}
System.out.println("\n-------------------");
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
Плюсы и минусы ZipInputStream
Плюсы:
Простота использования.
Поддержка потокового чтения, что позволяет работать с большими архивами без загрузки всего содержимого в память.
Минусы:
Низкоуровневый API: требует ручного управления данными и записями.
Нет встроенной поддержки для работы с паролями или шифрованием.
Нюансы использования
Всегда закрывайте ZipInputStream после использования, чтобы освободить ресурсы.
Используйте буфер для чтения данных, чтобы минимизировать количество операций ввода-вывода.
#Java #Training #Medium #ZipInputStream
👍3
Что выведет код?
#Tasks
public class Task180225 {
public static void main(String[] args) {
int a = 5;
int b = 3;
int result = a & b | a ^ b;
System.out.println(result);
}
}
#Tasks
👍2
👍1