JavaRush /وبلاگ جاوا /Random-FA /اولین برنامه Hibernate شما

اولین برنامه Hibernate شما

در گروه منتشر شد
در این مقاله با یکی از محبوب ترین فریم ورک های سازمانی برای جاوا آشنا می شوید و اولین اپلیکیشن خود را با استفاده از Hibernate ایجاد می کنید. تا به حال نام Hibernate را نشنیده اید؟ شاید در مورد آن شنیده باشید، اما از آن استفاده نکرده اید؟ یا سعی کردید شروع کنید، اما موفق نشدید؟ در هر سه مورد، به برش خوش آمدید :) اولین برنامه Hibernate شما - 1سلام به همه! در این مقاله، من در مورد ویژگی های اصلی فریم ورک Hibernate صحبت خواهم کرد و به شما در نوشتن اولین مینی برنامه کمک خواهم کرد. برای این ما نیاز داریم:
  1. Intellij Idea Ultimate Edition;
    از وب سایت رسمی دانلود کنید و نسخه آزمایشی 30 روزه را فعال کنید.
  2. PostgeSQL یکی از محبوب ترین سیستم های مدیریت پایگاه داده مدرن (DBMS) است.
  3. Maven (از قبل در IDEA ساخته شده است)؛
  4. اندکی بردباری.
هدف این مقاله در درجه اول کسانی است که هرگز با این فناوری کار نکرده اند، بنابراین مقدار کد تا حد امکان کاهش یافته است. بیا شروع کنیم!

Hibernate چیست؟

این یکی از محبوب ترین پیاده سازی های مدل ORM است. مدل شی-رابطه ای روابط بین اشیاء نرم افزار و رکوردهای موجود در پایگاه داده را توصیف می کند. البته عملکرد Hibernate بسیار گسترده است، اما ما بر روی ساده ترین عملکردها تمرکز خواهیم کرد. هدف ما: ایجاد یک برنامه CRUD (ایجاد، خواندن، به روز رسانی، حذف) که قادر به انجام:
  1. ایجاد کاربران (کاربر) و همچنین جستجوی آنها در پایگاه داده با شناسه، به روز رسانی داده های آنها در پایگاه داده و همچنین حذف آنها از پایگاه داده.
  2. تخصیص اشیاء وسیله نقلیه (Auto) به کاربران. ایجاد، ویرایش، یافتن و حذف خودروها از پایگاه داده.
  3. علاوه بر این، برنامه باید به طور خودکار اتومبیل های "یتیم" را از پایگاه داده حذف کند. آن ها هنگامی که یک کاربر حذف می شود، تمام اتومبیل های متعلق به او نیز باید از پایگاه داده حذف شوند.
ساختار پروژه ما به صورت زیر خواهد بود: اولین برنامه Hibernate شما - 2همانطور که می بینید، هیچ چیز پیچیده ای نیست. 6 کلاس + 1 فایل با تنظیمات. ابتدا بیایید یک پروژه maven جدید در Intellij Idea ایجاد کنیم. فایل -> پروژه جدید. از بین انواع پروژه های پیشنهادی، Maven را انتخاب کرده و ادامه دهید. اولین برنامه Hibernate شما - 3Apache Maven چارچوبی برای خودکارسازی مونتاژ پروژه ها بر اساس توضیح ساختار آنها در فایل ها به زبان POM است. کل ساختار پروژه شما در فایل pom.xml توضیح داده خواهد شد که خود IDEA در ریشه پروژه شما ایجاد می کند. در تنظیمات پروژه باید پارامترهای Maven - groupId و artifactId را مشخص کنید. به طور معمول در پروژه ها groupId نام سازمان یا بخش است و نام دامنه سازمان یا سایت پروژه در آنجا نوشته می شود. به نوبه خود، artifactId نام پروژه است. برای groupdId می توانید مشخص کنید com.вашНикнейм.javarush، این به هیچ وجه بر عملکرد برنامه تأثیر نمی گذارد. برای artifactId، هر نام پروژه ای را که دوست دارید انتخاب کنید. همچنین می توانید نسخه را بدون تغییر رها کنید. اولین برنامه Hibernate شما - 4در آخرین صفحه، به سادگی داده های وارد شده قبلی خود را تأیید کنید. اولین برنامه Hibernate شما - 5خب ما پروژه رو ساختیم، فقط میمونه کد رو بنویسیم و کار کنیم :) اول اینکه اگه بخوایم یه اپلیکیشن بسازیم که با دیتابیس کار کنه بدون دیتابیس قطعا نمیتونیم! PostgreSQL را از اینجا دانلود کنید (من از نسخه 9 استفاده می کنم). PostgreSQL دارای یک کاربر پیش‌فرض 'postgres' است، در حین نصب باید برای آن رمز عبور ایجاد کنید. رمز عبور خود را فراموش نکنید، بعداً به آن نیاز خواهیم داشت! (به طور کلی، استفاده از پایگاه داده پیش فرض در برنامه ها عمل بدی است، اما برای کاهش میزان هموروئید، ما به ایجاد پایگاه داده خودمان بسنده می کنیم). اگر با خط فرمان و پرس و جوهای SQL راحت نیستید، خبر خوبی وجود دارد. Intellij IDEA یک رابط کاربری کاملاً مناسب برای کار با پایگاه داده ارائه می دهد. به نظر می رسد: اولین برنامه Hibernate شما - 6(واقع در نوار کناری سمت راست IDEA، تب پایگاه داده) برای ایجاد یک اتصال، روی "+" کلیک کنید، ارائه دهنده ما (PostgeSQL) را انتخاب کنید. فیلدها را با نام کاربری، نام پایگاه داده (هر دو postgres هستند) پر کنید و رمز عبوری را که هنگام نصب PostgreSQL تنظیم کرده اید وارد کنید. در صورت لزوم، درایور Postgres را دانلود کنید، این کار را می توان در همین صفحه انجام داد. برای بررسی اینکه آیا اتصال به پایگاه داده برقرار است، روی "Test Connection" کلیک کنید. اگر کتیبه "موفق" را مشاهده کردید، ادامه می دهیم. حال بیایید جداول مورد نیاز خود را ایجاد کنیم. دو نفر از آنها وجود خواهد داشت - کاربران و خودروها. پارامترهای جدول کاربران: اولین برنامه شما در Hibernate - 7لطفاً توجه داشته باشید که id کلید اصلی است. اگر نمی دانید کلید اصلی در SQL چیست، آن را در گوگل جستجو کنید، مهم است. تنظیم جدول خودروها: اولین برنامه شما در Hibernate - 8برای خودروها باید کلید خارجی - کلید خارجی را پیکربندی کنید. جداول ما را پیوند خواهد داد. به شما توصیه می کنم درباره او بیشتر بخوانید. به بیان ساده، به یک جدول خارجی، در مورد ما، کاربران اشاره دارد. اگر خودرو متعلق به کاربری با id=1 باشد، در قسمت user_id جدول autos دارای 1 خواهد بود. اینگونه است که ما کاربران را با خودروهایشان در اپلیکیشن خود متصل می کنیم. در جدول autos ما، فیلد user_id به عنوان یک کلید خارجی عمل می کند. به فیلد id جدول کاربران اشاره خواهد کرد. اولین برنامه Hibernate شما - 9بنابراین، ما یک پایگاه داده با دو جدول ایجاد کرده ایم. باید بدانیم که چگونه آن را از طریق کد جاوا مدیریت کنیم. ما با فایل pom.xml شروع می کنیم که باید کتابخانه های لازم را در آن قرار دهیم (در زبان Maven به آنها وابستگی می گویند). تمام کتابخانه ها در مخزن مرکزی Maven ذخیره می شوند. آنهایی را که در pom.xml مشخص می کنید، می توانید در پروژه استفاده کنید. pom.xml شما باید شبیه این باشد: اولین برنامه Hibernate شما - 10هیچ چیز پیچیده ای که می بینید وجود ندارد. ما فقط 2 وابستگی اضافه کردیم - برای استفاده از PostgreSQL و Hibernate. حالا بریم سراغ کد جاوا. تمام بسته ها و کلاس های لازم برای پروژه را ایجاد کنید. برای شروع، به مدل‌های داده نیاز داریم - کلاس‌ها Userو Auto.
package models;

import javax.persistence.*;
import java.util.ArrayList;
import java.util.List;

@Entity
@Table (name = "users")
public class User {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private int id;
    @Column(name = "name")
    private String name;
    //you can not specify Column name if it matches the name of the column in the table
    private int age;

    @OneToMany(mappedBy = "user", cascade = CascadeType.ALL, orphanRemoval = true)
    private List<Auto> autos;

    public User() {
    }

    public User(String name, int age) {
        this.name = name;
        this.age = age;
        autos = new ArrayList<>();
    }

    public void addAuto(Auto auto) {
        auto.setUser(this);
        autos.add(auto);
    }

    public void removeAuto(Auto auto) {
        autos.remove(auto);
    }

    public int getId() {
        return id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public List<Auto> getAutos() {
        return autos;
    }

    public void setAutos(List<Auto> autos) {
        this.autos = autos;
    }

    @Override
    public String toString() {
        return "models.User{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}
package models;

import javax.persistence.*;

@Entity
@Table(name = "autos")
public class Auto {

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

    @Column (name = "model")
    private String model;

    //you can not specify Column name if it matches the name of the column in the table
    private String color;


    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "user_id")
    private User user;

    public Auto() {
    }

    public Auto(String model, String color) {
        this.model = model;
        this.color = color;
    }

    public int getId() {
        return id;
    }

    public String getModel() {
        return model;
    }

    public void setModel(String model) {
        this.model = model;
    }

    public String getColor() {
        return color;
    }

    public void setColor(String color) {
        this.color = color;
    }

    public User getUser() {
        return user;
    }

    public void setUser(User user) {
        this.user = user;
    }

    @Override
    public String toString() {
        return color + " " + model;
    }
}
همانطور که می بینید، کلاس ها با یک دسته از حاشیه نویسی هنوز نامشخص مجهز شده اند. بیایید شروع به برخورد با آنها کنیم. حاشیه نویسی اصلی برای ما @Entity است. در مورد آن در ویکی پدیا بخوانید و همه چیز را به خاطر بسپارید، این اساس اصول است. این حاشیه نویسی به اشیاء جاوای کلاس شما اجازه می دهد تا با پایگاه داده مرتبط شوند. برای اینکه یک کلاس یک موجودیت باشد، باید شرایط زیر را داشته باشد:
  • باید یک سازنده خالی ( publicیا protected) داشته باشد.
  • نمی توان تو در تو، رابط یا enum;
  • نمی تواند باشد finalو نمی تواند حاوی final-fields/properties باشد.
  • باید حداقل یک فیلد @Id داشته باشد.
کلاس های موجودیت خود را بررسی کنید، این مکان ها مکانی بسیار محبوب برای شلیک به پای خود هستند. فراموش کردن چیزی بسیار آسان است. در این حالت، نهاد می تواند:
  • شامل سازنده های غیر خالی باشد.
  • به ارث بردن و به ارث بردن;
  • شامل روش های دیگر و پیاده سازی رابط ها.
همانطور که می بینید، کلاس Userبسیار شبیه به جدول کاربران است. فیلدها وجود دارد id, name, age. حاشیه نویسی که در بالای آنها قرار دارد نیازی به توضیح زیادی ندارد: از قبل واضح است که @Id نشانه ای است که فیلد یک شناسه اشیاء این کلاس است. حاشیه‌نویسی Table@ بالای کلاس، نام جدولی را که اشیاء در آن نوشته شده‌اند، مشخص می‌کند. به کامنت بالای فیلد سن توجه کنید: اگر نام فیلد در کلاس و جدول یکسان باشد، لازم نیست حاشیه نویسی @Column را اضافه کنید، به همین صورت عمل می کند. با توجه به "استراتژی = GenerationType.IDENTITY" که در پرانتز نشان داده شده است: چندین استراتژی تولید ID وجود دارد. می توانید آن را در گوگل جستجو کنید، اما در چارچوب برنامه ما نیازی به زحمت نیست. نکته اصلی این است که id برای اشیاء ما به طور خودکار تولید می شود، بنابراین تنظیم کننده ای برای id وجود ندارد و ما آن را در سازنده نیز مشخص نمی کنیم. با این حال، کلاس هنوز از برخی جهات Userبرجسته است . او لیستی از ماشین ها دارد! حاشیه نویسی @OneToMany در بالای لیست ظاهر می شود. به این معنی که یک شی از کلاس کاربر می تواند با چندین ماشین مطابقت داشته باشد. تنظیمات "mappedBY" به فیلد کاربری کلاس اشاره می کند Auto. به این ترتیب ماشین ها و کاربران به یکدیگر متصل می شوند. تنظیم orphanRemoval به خوبی از انگلیسی ترجمه می شود - "حذف یتیمان". اگر کاربر را از پایگاه داده حذف کنیم، تمام خودروهای مرتبط با او نیز حذف خواهند شد. به نوبه خود، در کلاس، Autoفیلد کاربری را با حاشیه نویسی @ManyToOne (بسیاری از Autos می توانند با یک کاربر مطابقت داشته باشند) و حاشیه نویسی @JoinColumn را می بینید. این نشان می دهد که از طریق کدام ستون در جدول autos ارتباط با جدول کاربران انجام می شود (همان کلید خارجی که قبلاً در مورد آن صحبت کردیم). پس از ایجاد یک مدل داده، وقت آن است که به برنامه خود آموزش دهیم تا عملیات روی این داده ها را در پایگاه داده انجام دهد. بیایید با کلاس ابزار HibernateSessionFactoryUtil شروع کنیم. این تنها یک وظیفه دارد - ایجاد یک کارخانه جلسه برای برنامه ما برای کار با پایگاه داده (سلام، الگوی "Factory!"). او کار دیگری نمی تواند بکند.
package utils;

import models.Auto;
import models.User;
import org.hibernate.SessionFactory;
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
import org.hibernate.cfg.Configuration;

public class HibernateSessionFactoryUtil {
    private static SessionFactory sessionFactory;

    private HibernateSessionFactoryUtil() {}

    public static SessionFactory getSessionFactory() {
        if (sessionFactory == null) {
            try {
                Configuration configuration = new Configuration().configure();
                configuration.addAnnotatedClass(User.class);
                configuration.addAnnotatedClass(Auto.class);
                StandardServiceRegistryBuilder builder = new StandardServiceRegistryBuilder().applySettings(configuration.getProperties());
                sessionFactory = configuration.buildSessionFactory(builder.build());

            } catch (Exception e) {
                System.out.println("Exception!" + e);
            }
        }
        return sessionFactory;
    }
}
در این کلاس، یک شیء پیکربندی جدید به نام Configuration ایجاد می کنیم و کلاس هایی را که باید به عنوان موجودیت درک کند - Userو به آن ارسال می کنیم Auto. به روش توجه کنید configuration.getProperties(). چه خواص دیگری؟ جایی که؟ ویژگی ها پارامترهایی برای نحوه عملکرد hibernate هستند که در یک فایل ویژه hibernate.cfg.xml مشخص شده اند. اولین برنامه Hibernate شما - 11Hibernate.cfg.xml در اینجا خوانده می شود: new Configuration().configure(); همانطور که می بینید، چیز خاصی در آن وجود ندارد - پارامترهایی برای اتصال به پایگاه داده و یک پارامتر خاص show_sql. برای اینکه تمام کوئری‌های SQL که در حالت hibernate در مقابل پایگاه داده ما اجرا می‌شوند، به کنسول خروجی داده شوند، لازم است. به این ترتیب، دقیقاً خواهید دید که Hibernate در هر لحظه در حال انجام است و از شر اثر "جادویی" خلاص خواهید شد. بعد ما به کلاس نیاز داریم UserDAO. (به روشی خوب، شما باید از طریق رابط ها برنامه ریزی کنید - یک رابط ایجاد کنید UserDAOو آن را به طور جداگانه پیاده سازی کنید UserDAOImpl، اما برای کاهش مقدار کد، این را حذف می کنم. در پروژه های واقعی این کار را انجام ندهید!). DAO (شیء دسترسی به داده) یکی از رایج ترین الگوهای طراحی، "دسترسی به داده" است. معنای آن ساده است - ایجاد یک لایه در برنامه که فقط مسئول دسترسی به داده ها است و هیچ چیز دیگری. داده ها را از پایگاه داده دریافت کنید، داده ها را به روز کنید، داده ها را حذف کنید - و تمام. درباره DAO ها بیشتر بخوانید؛ شما دائماً از آنها در کار خود استفاده خواهید کرد. کلاس ما چه کاری می تواند انجام دهد UserDao؟ در واقع، مانند همه DAO ها، فقط می تواند با داده کار کند. کاربر را با شناسه پیدا کنید، داده‌های او را به‌روزرسانی کنید، او را حذف کنید، فهرستی از همه کاربران را از پایگاه داده بیرون بکشید یا یک کاربر جدید را در پایگاه داده ذخیره کنید - این همه عملکرد آن است.
package dao;

import models.Auto;
import models.User;
import org.hibernate.Session;
import org.hibernate.Transaction;
import utils.HibernateSessionFactoryUtil;
import java.util.List;

public class UserDao {

    public User findById(int id) {
        return HibernateSessionFactoryUtil.getSessionFactory().openSession().get(User.class, id);
    }

    public void save(User user) {
        Session session = HibernateSessionFactoryUtil.getSessionFactory().openSession();
        Transaction tx1 = session.beginTransaction();
        session.save(user);
        tx1.commit();
        session.close();
    }

    public void update(User user) {
        Session session = HibernateSessionFactoryUtil.getSessionFactory().openSession();
        Transaction tx1 = session.beginTransaction();
        session.update(user);
        tx1.commit();
        session.close();
    }

    public void delete(User user) {
        Session session = HibernateSessionFactoryUtil.getSessionFactory().openSession();
        Transaction tx1 = session.beginTransaction();
        session.delete(user);
        tx1.commit();
        session.close();
    }

    public Auto findAutoById(int id) {
        return HibernateSessionFactoryUtil.getSessionFactory().openSession().get(Auto.class, id);
    }

    public List<User> findAll() {
        List<User> users = (List<User>)  HibernateSessionFactoryUtil.getSessionFactory().openSession().createQuery("From User").list();
        return users;
    }
}
روش ها UserDaoمشابه یکدیگر هستند. در اکثر آنها، ما یک شی Session (یک جلسه اتصال به پایگاه داده ما) را با استفاده از Session Factory دریافت می کنیم، یک تراکنش واحد در این جلسه ایجاد می کنیم، تبدیل داده های لازم را انجام می دهیم، نتیجه تراکنش را در پایگاه داده ذخیره می کنیم و جلسه را می بندیم. خود روش ها، همانطور که می بینید، بسیار ساده هستند. DAO "قلب" برنامه ما است. با این حال، ما DAO را مستقیماً ایجاد نمی کنیم و متدهای آن را در ما فراخوانی نمی کنیم main(). تمام منطق به UserService.
package services;

import dao.UserDao;
import models.Auto;
import models.User;

import java.util.List;

public class UserService {

    private UserDao usersDao = new UserDao();

    public UserService() {
    }

    public User findUser(int id) {
        return usersDao.findById(id);
    }

    public void saveUser(User user) {
        usersDao.save(user);
    }

    public void deleteUser(User user) {
        usersDao.delete(user);
    }

    public void updateUser(User user) {
        usersDao.update(user);
    }

    public List<User> findAllUsers() {
        return usersDao.findAll();
    }

    public Auto findAutoById(int id) {
        return usersDao.findAutoById(id);
    }


}
سرویس یک لایه داده در برنامه است که وظیفه اجرای منطق تجاری را بر عهده دارد. اگر برنامه شما نیاز به اجرای منطق تجاری دارد، آن را از طریق خدمات انجام می دهد. این سرویس شامل درون خود است UserDaoو متدهای DAO را در متدهای خود فراخوانی می کند. این ممکن است برای شما شبیه به تکرار توابع به نظر برسد (چرا نه فقط متدها را از یک شی dao فراخوانی کنید)، اما با تعداد زیادی آبجکت و منطق پیچیده، تقسیم برنامه به لایه ها مزایای زیادی دارد (این تمرین خوبی است، این اطلاعات را به خاطر بسپارید. آینده و در مورد "لایه های برنامه" بخوانید "). در سرویس ما، منطق ساده است، اما در پروژه های واقعی، متدهای سرویس شامل بسیار بیشتر از یک خط کد خواهند بود :) حالا همه چیزهایی که برای کارکرد برنامه نیاز داریم را داریم! بیایید main()یک کاربر و ماشین ها برای او در روش ایجاد کنیم، آنها را به یکدیگر متصل کنیم و در پایگاه داده ذخیره کنیم.
import models.Auto;
import models.User;
import services.UserService;

import java.sql.SQLException;

public class Main {
    public static void main(String[] args) throws SQLException {

        UserService userService = new UserService();
        User user = new User("Masha",26);
        userService.saveUser(user);
        Auto ferrari = new Auto("Ferrari", "red");
        ferrari.setUser(user);
        user.addAuto(ferrari);
        Auto ford = new Auto("Ford", "black");
        ford.setUser(user);
        user.addAuto(ford);
        userService.updateUser(user);
    }
}
همانطور که می بینید، جدول کاربران ورودی خاص خود را دارد و جدول autos ورودی خود را دارد. اولین برنامه Hibernate شما - 13اولین برنامه Hibernate شما - 14بیایید سعی کنیم نام کاربری خود را تغییر دهیم. بیایید جدول کاربران را پاک کنیم و کد را اجرا کنیم
import models.Auto;
import models.User;
import services.UserService;

import java.sql.SQLException;

public class Main {
    public static void main(String[] args) throws SQLException {

        UserService userService = new UserService();
        User user = new User("Masha",26);
        userService.saveUser(user);
        Auto ferrari = new Auto("Ferrari", "red");
        user.addAuto(ferrari);
        Auto ford = new Auto("Ford", "black");
        ford.setUser(user);
        user.addAuto(ford);
        userService.updateUser(user);
        user.setName("Sasha");
        userService.updateUser(user);
    }
}
آثار! اولین برنامه Hibernate شما - 15اگر یک کاربر را حذف کنید چه؟ بیایید جدول کاربران را پاک کنیم (خودکار خود پاک می شود) و کد را اجرا کنیم
import models.Auto;
import models.User;
import services.UserService;

import java.sql.SQLException;

public class Main {
    public static void main(String[] args) throws SQLException {

        UserService userService = new UserService();
        User user = new User("Masha",26);
        userService.saveUser(user);
        Auto ferrari = new Auto("Ferrari", "red");
        user.addAuto(ferrari);
        Auto ford = new Auto("Ford", "black");
        ford.setUser(user);
        user.addAuto(ford);
        userService.updateUser(user);
        user.setName("Sasha");
        userService.updateUser(user);
        userService.deleteUser(user);
    }
}
و جداول ما کاملا خالی هستند (به کنسول توجه کنید، تمام کوئری هایی که Hibernate اجرا کرده است در آنجا نمایش داده می شود). می توانید با برنامه بازی کنید و تمام ویژگی های آن را امتحان کنید. به عنوان مثال، یک کاربر با ماشین ها ایجاد کنید، آن را در پایگاه داده ذخیره کنید، ببینید چه شناسه ای به آن اختصاص داده شده است، و سعی کنید با استفاده از روش، main()کاربر را با این شناسه از پایگاه داده بیرون بکشید و لیستی از ماشین های او را در کنسول نمایش دهید. . البته ما تنها بخش کوچکی از قابلیت هایبرنیت را دیدیم. قابلیت های آن بسیار گسترده است و مدت هاست که یکی از استانداردهای صنعتی برای توسعه جاوا بوده است. اگر می خواهید آن را با جزئیات مطالعه کنید، می توانم کتاب "Java Persistence API and Hibernate" را که در یکی از مقالات قبلی خود بررسی کردم را توصیه کنم. امیدوارم این مقاله برای خوانندگان مفید بوده باشد. اگر سوالی دارید در نظرات بپرسید، خوشحال می شوم پاسخ دهم :) همچنین فراموش نکنید که از نویسنده در مسابقه توسط "لایک" او حمایت کنید. یا بهتر از آن - "من آن را خیلی دوست دارم" :) در مطالعات خود موفق باشید!
نظرات
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION