JavaRush /Java Blog /Random-TK /Ilkinji Gibernate programmaňyz

Ilkinji Gibernate programmaňyz

Toparda çap edildi
Bu makalada Java üçin iň meşhur kärhana çarçuwalarynyň biri bilen tanyşarsyňyz we “Hibernate” ulanyp ilkinji programmaňyzy döredersiňiz. Gibernate hakda eşitmediňizmi? Belki, bu hakda eşitdiňiz, ýöne ulanmadyňyzmy? Starta-da başlamaga synanyşdyňyz, ýöne başarmadyňyzmy? Üç ýagdaýda-da, kesilenlere hoş geldiňiz :) Ilkinji Gibernate programmaňyz - 1Hemmelere salam! Bu makalada, Gibernate çarçuwasynyň esasy aýratynlyklary barada gürleşerin we ilkinji kiçi programmaňyzy ýazmaga kömek ederin. Munuň üçin bize zerur:
  1. Intellij Idea Ultimate Edition; Resmi web sahypasyndan
    göçürip alyň we 30 günlük synag wersiýasyny işjeňleşdiriň.
  2. PostgeSQL iň meşhur häzirki zaman maglumatlar binýadyny dolandyrmak ulgamlaryndan biridir (DBMS);
  3. Maven (eýýäm IDEA-da gurlan);
  4. Biraz sabyr.
Makala, esasan, bu tehnologiýa bilen hiç wagt işlemediklere gönükdirilendir, şonuň üçin koduň mukdary mümkin boldugyça azaldyldy. Başlalyň!

Gibernate näme?

Bu ORM modeliniň iň meşhur durmuşa geçirişlerinden biridir. Obýekt bilen baglanyşykly model, maglumatlar bazasyndaky programma üpjünçiliginiň obýektleri bilen ýazgylaryň arasyndaky gatnaşyklary suratlandyrýar. Elbetde, Gibernate-iň işleýşi gaty giň, ýöne iň ýönekeý funksiýalara üns bereris. Maksadymyz: başarjak CRUD programmasyny döretmek (Dörediň, okaň, täzeläň, pozuň):
  1. Ulanyjylary (Ulanyjy) dörediň, şeýle hem olary ID-den maglumat bazasynda gözläň, maglumatlar bazasyndaky maglumatlary täzeläň we maglumat bazasyndan pozuň.
  2. Ulanyjylara ulag serişdelerini (Awto) belläň. Maglumatlar bazasyndan awtoulag dörediň, redaktirläň, tapyň we pozuň.
  3. Mundan başga-da, programma "ýetim" awtoulaglary maglumatlar bazasyndan awtomatiki aýyrmaly. Bular. Ulanyjy öçürilende, oňa degişli awtoulaglaryň hemmesi maglumatlar bazasyndan pozulmalydyr.
Taslamamyzyň gurluşy aşakdaky ýaly bolar: Ilkinji Gibernate programmaňyz - 2Görşüňiz ýaly çylşyrymly zat ýok. 6 synp + sazlaýjy faýl. Ilki bilen, “Intellij Idea” -da täze bir taslama döredeliň. Faýl -> Täze taslama. Teklip edilýän taslama görnüşlerinden Maven saýlaň we dowam ediň. Ilkinji Gibernate programmaňyz - 3Apache Maven, POM dilindäki faýllardaky gurluşynyň beýany esasynda taslamalary ýygnamagy awtomatlaşdyrmak üçin çarçuwadyr. Taslamaňyzyň ähli gurluşy, IDEA-nyň taslamaňyzyň düýbünde döredjek pom.xml faýlynda beýan ediler. Taslama sazlamalarynda Maven parametrlerini - groupId we artifactId görkezmeli bolarsyňyz. Adatça groupId taslamalarynda guramanyň ýa-da bölümiň ady bolup, guramanyň ýa-da taslama sahypasynyň domen ady şol ýerde ýazylýar. Öz gezeginde artifactId taslamanyň adydyr. GroupdId üçin kesgitläp bilersiňiz com.вашНикнейм.javarush, bu programmanyň işine hiç hili täsir etmez. ArtifactId üçin halaýan islendik taslama adyňyzy saýlaň. Şeýle hem wersiýasyny üýtgetmän goýup bilersiňiz. Ilkinji Gibernate programmaňyz - 4Iň soňky ekranda, ozal girizilen maglumatlaryňyzy tassyklaň. Ilkinji Gibernate programmaňyz - 5Şeýlelik bilen, taslamany döretdik, galan zat kod ýazmak we ony işletmek :) Ilki bilen, maglumatlar bazasy bilen işleýän programma döretmek islesek, maglumatlar bazasyz hökman edip bilmeris! PostgreSQL-i şu ýerden göçürip alyň (9-njy wersiýasyny ulanýaryn). PostgreSQL-de deslapky ulanyjy 'postgres' bar, gurmak wagtynda onuň üçin parol döretmeli bolarsyňyz. Parolyňyzy ýatdan çykarmaň, soňrak gerek bolar! (Umuman aýdanyňda, programmalarda deslapky maglumat bazasyny ulanmak erbet tejribe, ýöne gemorroý mukdaryny azaltmak üçin öz maglumatlar bazamyzy döretmek bilen meşgullanarys). Buýruk setiri we SQL talaplary bilen oňaýly däl bolsaňyz, gowy habar bar. Intellij IDEA maglumat bazasy bilen işlemek üçin gaty amatly ulanyjy interfeýsini üpjün edýär. Görnüşi ýaly: Ilkinji Gibernate programmaňyz - 6(IDEA-nyň sag gapdalynda ýerleşýär, Maglumat bazasy goýmasy) Baglanyşyk döretmek üçin "+" düwmesine basyň, üpjün edijimizi saýlaň (PostgeSQL). Ulanyjy, maglumat bazasynyň ady (ikisem postgres) bilen dolduryň we PostgreSQL guranyňyzda bellän parolyňyzy giriziň. Zerur bolsa, “Postgres” sürüjisini göçürip alyň, bu şol sahypada edilip bilner. Maglumat bazasyna birikmäniň gurlandygyny barlamak üçin "Synag birikmesi" -e basyň. “Üstünlikli” ýazgyny görseňiz, dowam ederis. Indi zerur tablisalary döredeliň. Olardan ikisi bolar - ulanyjylar we awtoulaglar. Ulanyjylar tablisasynyň parametrleri: Gibernate-de ilkinji programmaňyz - 7idiň esasy açardygyny ýadyňyzdan çykarmaň. SQL-de esasy açaryň nämedigini bilmeseňiz, Google-dan möhümdir. Awtoulag tablisasyny düzmek: Gibernate-da ilkinji programmaňyz - 8Awtoulaglar üçin Daşary ýurt açary - daşary ýurt açary sazlamaly. Bu biziň tablisalarymyzy baglanyşdyrar. Ol hakda has köp okamagyňyzy maslahat berýärin; Simplyönekeý söz bilen aýdylanda, bu, ulanyjylara daşarky tablisa degişlidir. Awtoulag id = 1 ulanyjysyna degişli bolsa, awtoulag tablisasynyň ulanyjy_id meýdanynda 1 bolar. Ulanyjylary öz awtoulaglary bilen programmamyzda şeýle baglanyşdyrýarys. Awtoulag tablisamyzda user_id meýdançasy daşary ýurt açary bolup hyzmat eder. Ulanyjylar tablisasynyň id meýdanyna salgylanar. Ilkinji Gibernate programmaňyz - 9Şeýlelikde, iki tablisaly maglumat bazasyny döretdik. Java kodundan nädip dolandyrmalydygyna düşünmek galýar. Pom.xml faýly bilen başlarys, onda zerur kitaphanalary goşmalydyrys (Maven dilinde olara garaşlylyk diýilýär). Allhli kitaphanalar merkezi Maven ammarynda saklanýar. Pom.xml-de görkezenleriňiz, taslamada ulanyp bilersiňiz. Pom.xml-iňiz şeýle bolmaly: Ilkinji Gibernate programmaňyz - 10Görşüňiz ýaly çylşyrymly zat ýok. Diňe 2 baglylyk goşduk - PostgreSQL we Gibernate ulanmak üçin. Indi Java koduna geçeliň. Taslama üçin ähli zerur paketleri we synplary dörediň. Ilki bilen bize maglumat modelleri - synplar Userwe 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;
    }
}
Görşüňiz ýaly, sapaklar bir topar düşnüksiz düşündirişler bilen enjamlaşdyrylandyr. Geliň, olar bilen iş salyşalyň. Biziň üçin esasy düşündiriş @Entity. Wikipediýada okaň we hemme zady ýatda saklaň, bu esaslaryň esasyny düzýär. Bu düşündiriş, synpyňyzyň Java obýektlerini maglumat bazasy bilen baglanyşdyrmaga mümkinçilik berýär. Synpyň subýekt bolmagy üçin aşakdaky talaplara laýyk gelmelidir:
  • Boş konstruktor bolmaly ( publicýa-da protected);
  • Höwürtge, interfeýs ýa-da enum;
  • Meýdanlar / häsiýetler bolup bilmez finalwe bolup bilmez ;final
  • Iň azyndan bir @Id meýdançasy bolmaly.
Gurluş sapaklaryňyzy barlaň, bular özüňizi aýakda oklamak üçin iň meşhur ýer. Bir zady ýatdan çykarmak gaty aňsat. Bu ýagdaýda edara:
  • Boş däl konstruktorlary öz içine alyň;
  • Miras almak we miras almak;
  • Beýleki usullary öz içine alyň we interfeýsleri durmuşa geçiriň.
Görşüňiz ýaly, synp Userulanyjylaryň tablisasyna gaty meňzeýär. Meýdanlar bar id, name. ageAboveokarda ýerleşdirilen düşündirişlere kän bir düşündiriş gerek däl: @Id meýdançanyň bu synpyň obýektlerini kesgitleýjidigini görkezýän eýýäm düşnükli. Synpyň üstündäki @Table düşündirişinde obýektleriň ýazylan tablisasynyň ady görkezilýär. Fieldaş meýdanyndaky düşündirişe üns beriň: synpdaky we tablisadaky meýdan ady birmeňzeş bolsa, @ Sütün belligini goşmaly dälsiňiz, ol şeýle işlär. Gaplaňda görkezilen “strategiýa = GenerationType.IDENTITY” barada: birnäçe ID döretmek strategiýasy bar. Ony google edip bilersiňiz, emma programmamyzyň çäginde biynjalyk bolmak hökman däl. Esasy zat, obýektlerimiz üçin ID-ler awtomatiki usulda dörediler, şonuň üçin id kesgitleýji ýok, biz ony konstruktorda-da görkezmeýäris. Şeýle-de bolsa, synp henizem käbir ugurlarda Usertapawutlanýar . Maşynlaryň sanawy bar! @OneToMany düşündiriş sanawyň ýokarsynda görkezilýär. Ulanyjy synpynyň bir obýektiniň birnäçe maşyna gabat gelip biljekdigini aňladýar. "MappedBY" sazlamasy synpyň ulanyjy meýdanyny görkezýär Auto. Şeýlelik bilen, maşynlar we ulanyjylar biri-birine baglanýar. “PetimRemoval” sazlamasy iňlis dilinden gaty gowy terjime edýär - “ýetimleri aýyryň”. Ulanyjyny maglumatlar bazasyndan pozsak, onuň bilen baglanyşykly ähli awtoulaglar hem pozular. Öz gezegiňizde, synpda Auto@ManyToOne düşündirişi (köp awtoulag bir ulanyja gabat gelip biler) we @JoinColumn düşündirişi bilen ulanyjy meýdançasyny görersiňiz. Awtoulag tablisasyndaky haýsy sütüniň üsti bilen ulanyjylaryň tablisasy bilen baglanyşygyň bardygyny görkezýär (öňem aýdyp geçen şol bir daşary ýurt açary). Maglumat modelini döredenimizden soň, maglumatlar bazamyzda bu maglumatlar boýunça amallary ýerine ýetirmegi öwretmegiň wagty geldi. “HibernateSessionFactoryUtil” peýdaly synpyndan başlalyň. Diňe ýekeje wezipe bar - maglumatlar bazamyz bilen işlemek üçin programmamyz üçin sessiýa zawody döretmek (salam, "Zawod!" Nusgasy). Başga hiç zat edip bilmez.
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;
    }
}
Bu synpda täze konfigurasiýa obýekti, Konfigurasiýa döredýäris we oňa subýektler hökmünde kabul etmeli sapaklaryny geçirýäris - Userwe Auto. Usula üns beriň configuration.getProperties(). Başga haýsy häsiýetler? Nirede? Aýratynlyklar, gibernate.cfg.xml ýörite faýlynda görkezilen gibernatyň işleýşiniň parametrleri. Ilkinji Gibernate programmaňyz - 11Hibernate.cfg.xml şu ýerde okalýar: new Configuration().configure(); Görşüňiz ýaly, onda üýtgeşik zat ýok - maglumat bazasyna birikmegiň parametrleri we show_sql ýörite parametri. Gibernasiýa edýän maglumatlar bazamyza garşy ýerine ýetirjek ähli SQL talaplarynyň konsola çykmagy üçin zerurdyr. Şeýlelik bilen, Gibernate-iň her pursatda näme edýändigini anyk görersiňiz we “jadyly” täsirden dynarsyňyz. Ondan soň synp gerek UserDAO. (Gowy tarapdan, interfeýsler arkaly programma düzmeli - interfeýs döretmeli UserDAOwe ony aýratyn durmuşa geçirmeli UserDAOImpl, ýöne kod mukdaryny azaltmak üçin muny taşlaryn. Muny hakyky taslamalarda etme!). DAO (maglumatlara giriş obýekti) iň köp ýaýran dizaýn nusgalarynyň biri, “Maglumatlara elýeterlilik”. Onuň manysy ýönekeý - programmada diňe maglumatlara girmek üçin jogapkär we başga hiç zat bolmadyk gatlak döretmek. Maglumat bazasyndan maglumat alyň, maglumatlary täzeläň, maglumatlary pozuň - we hut şu. DAO-lar hakda has giňişleýin okaň, olary işiňizde yzygiderli ulanarsyňyz. Biziň synpymyz näme edip biler UserDao? Aslynda, ähli DAO-lar ýaly, diňe maglumatlar bilen işläp biler. Ulanyjyny id boýunça tapyň, maglumatlaryny täzeläň, pozuň, maglumatlar bazasyndan ähli ulanyjylaryň sanawyny çykaryň ýa-da maglumat bazasynda täze ulanyjyny ýatda saklaň - bu onuň işleýşi.
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;
    }
}
Usullar UserDaobiri-birine meňzeýär. Olaryň köpüsinde Sessiýa zawodymyzy ulanyp, Sessiýa obýektini (maglumatlar bazamyza birikdirilen sessiýa) alýarys, bu sessiýanyň içinde ýekeje geleşik döredýäris, zerur maglumatlary üýtgetmeleri amala aşyrýarys, amallaryň netijesini maglumatlar bazasynda saklaýarys we sessiýany ýapýarys. Görşüňiz ýaly usullaryň özi gaty ýönekeý. DAO programmamyzyň “ýüregi”. Şeýle-de bolsa, biz DAO-ny gönüden-göni döredip bilmeris we usullaryny özümizde çagyrarys main(). Loghli logika göçüriler 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);
    }


}
Hyzmat, iş logikasyny ýerine ýetirmek üçin jogapkär programmada maglumat gatlagydyr. Programmaňyz käbir iş logikasyny ýerine ýetirmeli bolsa, ony hyzmatlar arkaly ýerine ýetirýär. Hyzmat içini öz içine alýar UserDaowe usullarynda DAO usullaryny çagyrýar. Bu size funksiýalaryň köpeldilmegi ýaly bolup görünmegi mümkin (näme üçin diňe bir dao obýektinden usullary çagyrmaly däl), ýöne köp sanly obýekt we çylşyrymly logika bilen programmany gatlaklara bölmegiň uly peýdasy bar (bu gowy tejribe, şu maglumatlary ýatda saklaň gelejek we “amaly gatlaklar” hakda okaň). Hyzmatymyzda logika ýönekeý, ýöne hakyky taslamalarda hyzmat usullary birden köp setir koduny öz içine alar :) Indi programmanyň işlemegi üçin zerur zatlar bar! main()Usulda ulanyjy we maşyn döredeliň , olary biri-birine birikdiriň we maglumatlar bazasynda saklalyň.
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);
    }
}
Görşüňiz ýaly, ulanyjylaryň tablisasynyň öz ýazgysy, awtoulag tablisasynyň bolsa öz ýazgysy bar. Ilkinji Gibernate programmaňyz - 13Ilkinji Gibernate programmaňyz - 14Ulanyjymyzyň adyny üýtgetmäge synanyşalyň. Ulanyjylaryň tablisasyny arassalap, kody işledeliň
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);
    }
}
Işleýär! Ilkinji Gibernate programmaňyz - 15Ulanyjyny pozsaňyz näme etmeli? Ulanyjylaryň tablisasyny arassalalyň (awtoulaglar özüni arassalaýar) we kody ýerine ýetireliň
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);
    }
}
Stollarymyz düýbünden boş (konsola üns beriň, Gibernate-iň ýerine ýetiren ähli talaplary şol ýerde görkeziler). Programma bilen oýnap, ähli aýratynlyklaryny synap bilersiňiz. Mysal üçin, maşynlar bilen ulanyjy dörediň, maglumat bazasynda saklaň, haýsy ID-e berilendigini görüň we main()ulanyjyny bu id arkaly maglumat bazasyndan “çekmek” we konsolda enjamlarynyň sanawyny görkezmek üçin usuly ulanyp görüň. . Elbetde, Gibernate-iň işleýşiniň diňe kiçi bölegini gördük. Onuň mümkinçilikleri örän giň we Java-ny ösdürmek üçin köpden bäri pudak standartlaryndan biri bolup gelýär. Jikme-jik öwrenmek isleseňiz, öňki makalalarymyň birinde gözden geçiren “Java Persistence API we Gibernate” kitabyny maslahat berip bilerin. Bu makala okyjylar üçin peýdaly bolar diýip umyt edýärin. Soraglaryňyz bar bolsa, teswirlerde soraň, jogap bermäge şat bolaryn :) Şeýle hem, awtory "Ony halamak" bilen ýaryşda goldamagy ýatdan çykarmaň. Bettera-da has gowusy - “Gaty haladym” :) Okuwyňyzda üstünlik!
Teswirler
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION