Java for Beginner
672 subscribers
540 photos
155 videos
12 files
827 links
Канал от новичков для новичков!
Изучайте Java вместе с нами!
Здесь мы обмениваемся опытом и постоянно изучаем что-то новое!

Наш YouTube канал - https://www.youtube.com/@Java_Beginner-Dev

Наш канал на RUTube - https://rutube.ru/channel/37896292/
Download Telegram
Что выведет код?

public class Task151124_1 {
public static void main(String[] args) {
int a = 10, b = 5, c = 15;
if (a < b && b > c) {
System.out.println("Case 1");
} else if (a > b || b < c) {
if (a + b > c) {
System.out.println("Case 2");
} else {
System.out.println("Case 3");
}
} else if (a == b) {
System.out.println("Case 4");
} else {
System.out.println("Case 5");
}
}
}


#Tasks
А вот называть грамотно нужно!☝️🧐😂

https://t.me/Java_for_beginner_dev

#Mems
Создание и выполнение CRUD операций через Spring JDBC

Spring JDBC упрощает реализацию CRUD (Create, Read, Update, Delete) операций с базой данных. Для этого используются методы update и query из JdbcTemplate.

Шаги для реализации CRUD операций

1. Создание таблицы

Прежде чем выполнять CRUD операции, необходимо создать таблицу в базе данных.
String sql = """
CREATE TABLE IF NOT EXISTS users (
id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(50),
email VARCHAR(50)
)
""";
jdbcTemplate.execute(sql);


2. Create: Добавление записи


Для добавления записи используется метод update.
public void addUser(String name, String email) {
String sql = "INSERT INTO users (name, email) VALUES (?, ?)";
jdbcTemplate.update(sql, name, email);
}


Пример использования:
addUser("Jane Doe", "jane.doe@example.com");


3. Read: Получение записей


Получение всех записей:
public List<User> getAllUsers() {
String sql = "SELECT * FROM users";
return jdbcTemplate.query(sql, new UserRowMapper());
}


Получение записи по ID:
public User getUserById(int id) {
String sql = "SELECT * FROM users WHERE id = ?";
return jdbcTemplate.queryForObject(sql, new Object[]{id}, new UserRowMapper());
}


4. Update: Обновление записи

Обновление данных пользователя:
public void updateUserEmail(int id, String email) {
String sql = "UPDATE users SET email = ? WHERE id = ?";
jdbcTemplate.update(sql, email, id);
}


Пример использования:
updateUserEmail(1, "updated.email@example.com");


5. Delete: Удаление записи

Удаление пользователя по ID:
public void deleteUserById(int id) {
String sql = "DELETE FROM users WHERE id = ?";
jdbcTemplate.update(sql, id);
}


Пример:
deleteUserById(1);


Реализация CRUD через DAO

Для удобства работы с данными обычно создается слой DAO (Data Access Object), который инкапсулирует CRUD операции.
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Repository;
import java.util.List;

@Repository
public class UserDao {

private final JdbcTemplate jdbcTemplate;

public UserDao(JdbcTemplate jdbcTemplate) {
this.jdbcTemplate = jdbcTemplate;
}

public void addUser(String name, String email) {
String sql = "INSERT INTO users (name, email) VALUES (?, ?)";
jdbcTemplate.update(sql, name, email);
}

public User getUserById(int id) {
String sql = "SELECT * FROM users WHERE id = ?";
return jdbcTemplate.queryForObject(sql, new Object[]{id}, new UserRowMapper());
}

public List<User> getAllUsers() {
String sql = "SELECT * FROM users";
return jdbcTemplate.query(sql, new UserRowMapper());
}

public void updateUserEmail(int id, String email) {
String sql = "UPDATE users SET email = ? WHERE id = ?";
jdbcTemplate.update(sql, email, id);
}

public void deleteUserById(int id) {
String sql = "DELETE FROM users WHERE id = ?";
jdbcTemplate.update(sql, id);
}
}


Тестирование CRUD операций


Пример использования DAO:
public class Main {
public static void main(String[] args) {
AppConfig config = new AppConfig();
JdbcTemplate jdbcTemplate = config.jdbcTemplate();

UserDao userDao = new UserDao(jdbcTemplate);

// Добавление пользователя
userDao.addUser("John Smith", "john.smith@example.com");

// Получение всех пользователей
List<User> users = userDao.getAllUsers();
users.forEach(System.out::println);

// Обновление данных пользователя
userDao.updateUserEmail(1, "new.email@example.com");

// Удаление пользователя
userDao.deleteUserById(1);
}
}


#Java #Training #Spring #SpringJDBC
Что выведет код?

Задача по Spring JDBC, использование JdbcTemplate, создание и выполнение CRUD операций в Spring. Сложность легкая.

Подробный разбор через 30 минут!🫡

import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;

import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.List;

@SpringBootApplication
public class Main151124_2 {
public static void main(String[] args) {
SpringApplication.run(Main151124_2.class, args);
}

@Bean
public CommandLineRunner demo(JdbcTemplate jdbcTemplate) {
return args -> {
jdbcTemplate.execute("CREATE TABLE users (id INT AUTO_INCREMENT, name VARCHAR(255), age INT, PRIMARY KEY (id))");
jdbcTemplate.update("INSERT INTO users (name, age) VALUES (?, ?)", "Alice", 30);
jdbcTemplate.update("INSERT INTO users (name, age) VALUES (?, ?)", "Bob", 25);
List<String> names = jdbcTemplate.query("SELECT name FROM users WHERE age > ?", new Object[]{20}, new NameRowMapper());
names.forEach(System.out::println);
};
}

static class NameRowMapper implements RowMapper<String> {
@Override
public String mapRow(ResultSet rs, int rowNum) throws SQLException {
return rs.getString("name");
}
}
}


#TasksSpring
Подробный разбор решения задачи Task151124_2

1. Контекст задачи:

Эта задача демонстрирует использование Spring JDBC и JdbcTemplate для выполнения CRUD операций. В частности, в задаче показано, как с помощью JdbcTemplate можно создавать таблицы, вставлять данные, выполнять запросы и обрабатывать результаты с помощью RowMapper.


2. Ключевые элементы кода

Аннотация @SpringBootApplication:
@SpringBootApplication указывает, что Main151124_2 — это основной класс Spring Boot приложения. Она включает в себя @Configuration, @EnableAutoConfiguration и @ComponentScan, автоматически настраивая приложение и его компоненты, включая JdbcTemplate.

Аннотация @Bean и CommandLineRunner:
Метод demo() возвращает CommandLineRunner, который выполняется после запуска приложения. Это удобный способ выполнять код и тестировать логику работы с базой данных сразу после старта приложения.

JdbcTemplate:
JdbcTemplate предоставляет высокоуровневый API для работы с реляционными базами данных. Он упрощает выполнение SQL-запросов, управление соединениями и обработку результатов.
Методы execute и update используются для выполнения SQL-команд и вставки данных в таблицу.


Создание таблицы и вставка данных:
jdbcTemplate.execute("CREATE TABLE users ...") создает таблицу users с полями id, name и age.
jdbcTemplate.update("INSERT INTO users ...") вставляет две записи в таблицу: "Alice", 30 и "Bob", 25.


Запрос и использование RowMapper:
jdbcTemplate.query("SELECT name FROM users WHERE age > ?", new Object[]{20}, new NameRowMapper()) выполняет SELECT-запрос для получения имен пользователей с возрастом больше 20.
NameRowMapper реализует интерфейс RowMapper и используется для маппинга результатов запроса к объектам типа String. В данном случае, метод mapRow извлекает значение колонки name.


3. Сценарий работы программы

Запуск приложения:
Программа запускается с помощью SpringApplication.run(Main151124_2.class, args);, и Spring Boot настраивает встроенные компоненты, включая JdbcTemplate.

Выполнение операций с базой данных:
После запуска приложение создает таблицу users.
Затем добавляет две записи в таблицу:
Alice, возраст 30
Bob, возраст 25
Выполняется запрос SELECT name FROM users WHERE age > 20, который выбирает имена всех пользователей с возрастом больше 20.


Обработка результатов:
Запрос возвращает два имени: "Alice" и "Bob".
NameRowMapper преобразует строки результатов в объекты типа String.
Метод forEach выводит имена в консоль.


Вывод программы:
В консоль выводятся имена пользователей:
Alice
Bob


4. Ключевые моменты и выводы

Использование JdbcTemplate для работы с базой данных:
JdbcTemplate предоставляет удобные методы для выполнения SQL-запросов и управления результатами, устраняя необходимость ручного управления соединениями и обработкой исключений.

Создание и выполнение запросов:
execute используется для выполнения SQL-команд, таких как создание таблиц.
update подходит для выполнения операций вставки, обновления и удаления данных.
query используется для выполнения SELECT-запросов с маппингом результатов с помощью RowMapper.


RowMapper для преобразования результатов:
RowMapper преобразует строки результатов SQL-запросов в объекты Java. Это позволяет удобно обрабатывать данные и возвращать их в желаемом формате.

Валидация запросов и данных:
Запрос SELECT name FROM users WHERE age > 20 корректно выбирает всех пользователей, соответствующих условию, и возвращает их имена.

#Solution_TasksSpring
Всем доброго утра! 🔆

И вот, нас посетили очередные выходные! 🫣
Какие у Вас планы на них? Позалипать за компьютером или выезд на зимнюю природу?😏

Кстати есть мысль устроить конкурс пет-проектов, интересно?)🧐

А вот насчет завтра идей пока нет. Думаю порешать задачки какие-нибудь))))
Накидайте идей что полайфкодить?
✌️

А в целом, всем прекрасных и плодотворных выходных😉
This media is not supported in your browser
VIEW IN TELEGRAM
Ну раз никто ничего не предлагает, сегодня отдохнем. ✌️

А вот пока Вам смешной мем😜

#Mems
Введение в ORM и Spring Data JPA

ORM (Object-Relational Mapping) — это технология, которая позволяет разработчикам работать с базами данных на уровне объектов, а не на уровне SQL-запросов. Основная идея заключается в том, чтобы "связать" объектно-ориентированную модель приложения с реляционной моделью базы данных.

Примеры популярных ORM-фреймворков:
Hibernate
JPA (Java Persistence API)


Spring Data JPA — это часть экосистемы Spring, которая предоставляет инструменты для работы с базами данных на основе спецификации JPA. Она упрощает создание репозиториев и выполнение стандартных операций с данными (CRUD).

Преимущества Spring Data JPA:

Упрощение разработки: вам не нужно писать стандартные SQL-запросы.
Автоматическая реализация методов репозиториев: интерфейсы обрабатываются динамически.
Поддержка сложных запросов: с использованием методов
@Query или Criteria API.

Основные компоненты Spring Data JPA

1. EntityManager
Это основной интерфейс для работы с JPA, который управляет состоянием объектов и их отображением в базу данных. С помощью него можно выполнять CRUD-операции и управлять транзакциями.

2. Репозитории
В Spring Data JPA используются интерфейсы репозиториев, которые помогают выполнять операции с базой данных.

CrudRepository — базовый интерфейс для CRUD операций.
JpaRepository — расширяет CrudRepository, добавляя дополнительные возможности.


Подключение Spring Data JPA

Добавьте в файл application.properties или application.yml параметры подключения:
spring.datasource.url=jdbc:h2:mem:testdb
spring.datasource.driverClassName=org.h2.Driver
spring.datasource.username=sa
spring.datasource.password=password
spring.jpa.hibernate.ddl-auto=update


Пример использования Spring Data JPA

Создадим простое приложение для управления данными о пользователях.

1. Модель данных
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;

@Entity
public class User {

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;

private String name;
private String email;

// Getters and Setters
}


2. Репозиторий
import org.springframework.data.jpa.repository.JpaRepository;

public interface UserRepository extends JpaRepository<User, Long> {
}


3. Сервисный слой
import org.springframework.stereotype.Service;
import java.util.List;

@Service
public class UserService {

private final UserRepository userRepository;

public UserService(UserRepository userRepository) {
this.userRepository = userRepository;
}

public List<User> getAllUsers() {
return userRepository.findAll();
}

public User saveUser(User user) {
return userRepository.save(user);
}
}


4. Контроллер
import org.springframework.web.bind.annotation.*;

import java.util.List;

@RestController
@RequestMapping("/users")
public class UserController {

private final UserService userService;

public UserController(UserService userService) {
this.userService = userService;
}

@GetMapping
public List<User> getUsers() {
return userService.getAllUsers();
}

@PostMapping
public User createUser(@RequestBody User user) {
return userService.saveUser(user);
}
}


#Java #Training #Spring #SpringDataJPA
Что выведет код?

public class Task181124_1 {
public static void main(String[] args) {
int result = 0;
for (int i = 0; i < 3; i++) { // Внешний цикл
for (int j = i; j < 3; j++) { // Внутренний цикл
result += i + j;
}
}
System.out.println(result);
}
}


#Tasks
Варианты ответа:
Anonymous Quiz
68%
12
5%
15
16%
18
11%
22
"А еще у них код грязный, потому что не моются месяцами" 🤪😂😂😂

https://t.me/Java_for_beginner_dev

#Mems
Основные аннотации JPA: @Entity, @Table, @Id

1. Аннотация @Entity
@Entity указывает, что класс представляет собой сущность базы данных. Каждая сущность соответствует таблице в базе данных.

Пример:
import jakarta.persistence.Entity;

@Entity
public class Product {
private Long id;
private String name;
private Double price;
}
Если класс помечен как @Entity, но таблица не указана явно, Spring автоматически использует название класса для создания таблицы в базе данных.


2. Аннотация @Table

@Table используется для настройки имени таблицы и схемы, к которой относится сущность.

Пример:
import jakarta.persistence.Entity;
import jakarta.persistence.Table;

@Entity
@Table(name = "products", schema = "shop")
public class Product {
private Long id;
private String name;
private Double price;
}
Если имя таблицы не указано, то по умолчанию используется имя класса.


3. Аннотация @Id

@Id используется для указания первичного ключа таблицы.

Пример:
import jakarta.persistence.Entity;
import jakarta.persistence.Id;

@Entity
public class Product {

@Id
private Long id;

private String name;
private Double price;
}


Другие полезные аннотации

1.
@GeneratedValue

Используется вместе с @Id для автоматической генерации значения первичного ключа.
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;


Стратегии генерации:
AUTO — автоматически выбирает стратегию, зависящую от базы данных.
IDENTITY — использует автоинкремент в базе данных.
SEQUENCE — использует специальную таблицу для генерации уникальных значений.
TABLE — сохраняет последовательности значений в отдельной таблице.


2. @Column

Позволяет указать имя столбца, его уникальность, длину и другие параметры.
import jakarta.persistence.Column;

@Column(name = "product_name", nullable = false, unique = true)
private String name;


3. @Transient

Позволяет исключить поле из отображения в базе данных.
@Transient
private String tempData;


Пример полной конфигурации
import jakarta.persistence.*;

@Entity
@Table(name = "products")
public class Product {

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;

@Column(name = "product_name", nullable = false)
private String name;

private Double price;

@Transient
private String tempData;

// Getters and Setters
}


#Java #Training #Spring #Entity #Table #Id #GeneratedValue #Column #Transient
Аннотации JPA для полей: @Column, @GeneratedValue, @ManyToOne

1. Аннотация @Column

Аннотация @Column используется для настройки маппинга поля сущности на столбец таблицы базы данных. С её помощью можно задать имя столбца, его длину, уникальность, возможность быть NULL и другие атрибуты.

Основные параметры:
name — имя столбца в базе данных.
nullable — допускает ли столбец значение NULL.
unique — устанавливает, должны ли значения в столбце быть уникальными.
length — длина для столбцов типа VARCHAR.
columnDefinition — SQL-выражение для явного указания типа столбца.


Пример использования:
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.Id;

@Entity
public class User {

@Id
private Long id;

@Column(name = "username", nullable = false, unique = true, length = 50)
private String username;

@Column(name = "email", nullable = false, unique = true)
private String email;

@Column(name = "age", columnDefinition = "INTEGER DEFAULT 18")
private int age;

// Геттеры и сеттеры
}


В этом примере мы видим, что:
Поле username будет связано со столбцом username, не допускающим NULL и с максимальной длиной 50 символов.
Поле age связано со столбцом с SQL-типом INTEGER, по умолчанию равным 18.


2. Аннотация @GeneratedValue

Аннотация @GeneratedValue используется для указания стратегии генерации значений первичного ключа. Она применима к полям, помеченным как @Id.

Основные стратегии:
AUTO — выбор стратегии определяется провайдером JPA.
IDENTITY — генерация значения средствами базы данных.
SEQUENCE — использование последовательности, определенной в базе данных.
TABLE — использование таблицы для хранения значений идентификаторов.


Пример использования:
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;

@Entity
public class Product {

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;

private String name;

private double price;

// Геттеры и сеттеры
}
Здесь id будет автоматически генерироваться базой данных.


3. Аннотация @ManyToOne

Аннотация @ManyToOne используется для определения связи "многие к одному". Она обозначает, что текущее поле является ссылкой на другую сущность.

Пример использования:
import jakarta.persistence.Entity;
import jakarta.persistence.Id;
import jakarta.persistence.ManyToOne;

@Entity
public class Order {

@Id
private Long id;

private String description;

@ManyToOne
private Customer customer;

// Геттеры и сеттеры
}
Эта аннотация указывает, что множество заказов (Order) могут быть связаны с одним клиентом (Customer).


#Java #Training #Spring #Column #GeneratedValue #ManyToOne
Недавнее обсуждение многопоточности в нашем чате, подтолкнуло меня восполнить недостатки знаний в этой области Java. 🧐

Дополняю темы про распространенные ошибки многопоточности.

Распространенные ошибки многопоточности

Race Condition (Состояние гонки)

Race Condition — это ситуация, когда поведение программы зависит от порядка или своевременности выполнения потоков. Оно возникает, когда несколько потоков одновременно обращаются к одному и тому же ресурсу (например, переменной или объекту), и хотя бы один из них изменяет его.

Пример Race Condition:
public class Counter {
private int count = 0;

public void increment() {
count++; // Неатомарная операция: чтение, увеличение, запись
}

public int getCount() {
return count;
}
}

public class RaceConditionExample {
public static void main(String[] args) throws InterruptedException {
Counter counter = new Counter();

Thread t1 = new Thread(() -> {
for (int i = 0; i < 1000; i++) {
counter.increment();
}
});

Thread t2 = new Thread(() -> {
for (int i = 0; i < 1000; i++) {
counter.increment();
}
});

t1.start();
t2.start();
t1.join();
t2.join();

System.out.println("Final count: " + counter.getCount()); // Ожидаем 2000, но результат может быть меньше
}
}


Почему Race Condition?

count++ не является атомарной операцией.

Она состоит из трех шагов:
Чтение текущего значения count.
Увеличение значения.
Запись нового значения обратно в переменную.


Если оба потока прочитают одно и то же значение до записи, итоговое значение будет некорректным.

Deadlock (Взаимная блокировка)

Deadlock — ситуация, при которой два или более потоков блокируют друг друга, ожидая освобождения ресурсов.

Пример Deadlock:
public class DeadlockExample {

private final Object lock1 = new Object();
private final Object lock2 = new Object();

public void method1() {
synchronized (lock1) {
System.out.println("Thread 1: Holding lock1...");
try { Thread.sleep(50); } catch (InterruptedException e) {}

synchronized (lock2) {
System.out.println("Thread 1: Acquired lock2.");
}
}
}

public void method2() {
synchronized (lock2) {
System.out.println("Thread 2: Holding lock2...");
try { Thread.sleep(50); } catch (InterruptedException e) {}

synchronized (lock1) {
System.out.println("Thread 2: Acquired lock1.");
}
}
}

public static void main(String[] args) {
DeadlockExample demo = new DeadlockExample();

Thread t1 = new Thread(demo::method1);
Thread t2 = new Thread(demo::method2);

t1.start();
t2.start();
}
}


Что происходит:
Поток 1 захватывает lock1 и ждет lock2.
Поток 2 захватывает lock2 и ждет lock1.
Оба потока застревают, ожидая освобождения ресурсов друг от друга.


#Java #Training #Multithreading #Medium #Race_Condition #Livelock #Starvation #Thread_Interference #Memory_Consistency_Errors #Multithreading_errors
Livelock (Живая блокировка)

Livelock похож на Deadlock, но здесь потоки не блокируются, а продолжают изменять свое состояние в попытке избежать конфликта, не продвигаясь дальше.

Пример Livelock:

public class LivelockExample {

static class Worker {
private boolean active = true;

public synchronized void work(Worker other) {
while (active) {
System.out.println(Thread.currentThread().getName() + " is working...");
try { Thread.sleep(50); } catch (InterruptedException e) {}

if (other.isActive()) {
System.out.println(Thread.currentThread().getName() + " is waiting...");
continue;
}
break;
}
}

public synchronized void setActive(boolean active) {
this.active = active;
}

public synchronized boolean isActive() {
return active;
}
}

public static void main(String[] args) {
Worker w1 = new Worker();
Worker w2 = new Worker();

Thread t1 = new Thread(() -> w1.work(w2), "Worker 1");
Thread t2 = new Thread(() -> w2.work(w1), "Worker 2");

t1.start();
t2.start();
}
}


Что происходит:
Оба потока продолжают "уступать" друг другу, не завершив работу.

Starvation (Голодание)

Starvation — ситуация, когда поток постоянно лишается доступа к ресурсу из-за того, что другие потоки с более высоким приоритетом занимают его.

Причина: Использование приоритетов потоков, где высокоприоритетные потоки блокируют низкоприоритетные.

Thread Interference (Конфликт потоков)

Это ситуация, похожая на Race Condition, когда несколько потоков одновременно читают и изменяют общие данные, приводя к непредсказуемым результатам.

Пример:
Потоки выполняют операции на одной переменной без синхронизации, что приводит к некорректным итоговым значениям.

Memory Consistency Errors (Ошибки согласованности памяти)

Эти ошибки возникают, когда один поток изменяет данные, но другие потоки видят устаревшее состояние этих данных.

Причина: Использование кэша процессора.
Переменная, измененная в одном потоке, может не быть видимой для других потоков.

Решение:
Использование volatile для обеспечения видимости изменений.
private static volatile boolean running = true;

public void run() {
while (running) {
// Выполняем задачу
}
}


Как предотвратить ошибки многопоточности

Использование синхронизации:
synchronized блоки или методы.
ReentrantLock для более гибкого управления блокировкой.


Использование атомарных типов:
Классы из пакета java.util.concurrent.atomic:
AtomicInteger, AtomicBoolean, AtomicReference.


Использование высокоуровневых утилит:
ExecutorService для управления потоками.
CountDownLatch, Semaphore, CyclicBarrier.


Избегание Deadlock:
Всегда захватывать блокировки в одном и том же порядке.
Использование таймаутов при ожидании захвата.


Проверка и отладка:
Инструменты отладки (например, jstack, VisualVM) для анализа состояния потоков.
Логирование текущих блокировок и их владельцев.


#Java #Training #Multithreading #Medium #Race_Condition #Livelock #Starvation #Thread_Interference #Memory_Consistency_Errors #Multithreading_errors
Что выведет код?

class Parent { }

class Child extends Parent { }

public class Task191124_1 {
public static void main(String[] args) {
Parent obj1 = new Parent();
Parent obj2 = new Child();
Child obj3 = new Child();

System.out.println(obj1 instanceof Parent);
System.out.println(obj2 instanceof Child);
System.out.println(obj3 instanceof Parent);
System.out.println(obj1 instanceof Child);
}
}


#Tasks
И это за три часа в день?😱🤪😂

https://t.me/Java_for_beginner_dev

#Mems