diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..a7d3c9d
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,5 @@
+.idea/*
+.class
+out/
+target/
+logs/
\ No newline at end of file
diff --git a/Accounting report.iml b/Accounting report.iml
new file mode 100644
index 0000000..7a83844
--- /dev/null
+++ b/Accounting report.iml
@@ -0,0 +1,18 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/pom.xml b/pom.xml
new file mode 100644
index 0000000..9213630
--- /dev/null
+++ b/pom.xml
@@ -0,0 +1,24 @@
+
+
+ 4.0.0
+
+ groupId
+ Accounting report
+ 1.0-SNAPSHOT
+
+
+ mysql
+ mysql-connector-java
+ 8.0.18
+
+
+ org.projectlombok
+ lombok
+ 1.18.10
+
+
+
+
+
\ No newline at end of file
diff --git a/src/main/java/sample/Controller.java b/src/main/java/sample/Controller.java
new file mode 100644
index 0000000..e27c1ed
--- /dev/null
+++ b/src/main/java/sample/Controller.java
@@ -0,0 +1,118 @@
+package sample;
+
+import javafx.collections.FXCollections;
+import javafx.collections.ObservableList;
+import javafx.fxml.FXML;
+import javafx.scene.control.TableView;
+import javafx.scene.control.TextField;
+import javafx.scene.control.cell.PropertyValueFactory;
+import javafx.scene.input.MouseEvent;
+import sample.dao.ProductDao;
+import sample.model.Product;
+import javafx.scene.control.TableColumn;
+public class Controller {
+
+ @FXML
+ public TextField fieldId;
+ @FXML
+ public TextField fieldName;
+ @FXML
+ public TextField fieldType;
+ @FXML
+ public TextField fieldWholesalePrice;
+ @FXML
+ public TextField fieldRetailPrice;
+ @FXML
+ public TextField fieldProvider;
+ @FXML
+ public TextField fieldCount;
+ ProductDao productDao = new ProductDao();
+ private ObservableList productList = FXCollections.observableArrayList();
+ @FXML
+ private TableView tableProduct;
+ @FXML
+ private TableColumn idColumn;
+ @FXML
+ private TableColumn nameColumn;
+ @FXML
+ private TableColumn typeColumn;
+ @FXML
+ private TableColumn wholesalePriceColumn;
+ @FXML
+ private TableColumn retailPriceColumn;
+ @FXML
+ private TableColumn providerColumn;
+ @FXML
+ private TableColumn countColumn;
+
+
+ // инициализируем форму данными
+ @FXML
+ private void initialize() {
+ initData();
+
+ // устанавливаем тип и значение которое должно хранится в колонке
+ idColumn.setCellValueFactory(new PropertyValueFactory("id"));
+ nameColumn.setCellValueFactory(new PropertyValueFactory("name"));
+ typeColumn.setCellValueFactory(new PropertyValueFactory("type"));
+ wholesalePriceColumn.setCellValueFactory(new PropertyValueFactory("wholesale_price"));
+ retailPriceColumn.setCellValueFactory(new PropertyValueFactory("retail_price"));
+ providerColumn.setCellValueFactory(new PropertyValueFactory("provider_id"));
+ countColumn.setCellValueFactory(new PropertyValueFactory("count"));
+
+
+
+ // заполняем таблицу данными
+ tableProduct.setItems(productList);
+
+ }
+
+ // подготавливаем данные для таблицы
+ // вы можете получать их с базы данных
+ private void initData() {
+
+ productList.addAll(productDao.getAll());
+
+/*
+ productList.add(new Product(1, "Xiaomi A1","Телефон",500,600,0,1));
+ productList.add(new Product(2, "Samsung Galaxy S5","Телефон",800,100,0,1));
+ productList.add(new Product(3, "Iphone XS", "Телефон", 1000,1200,0,1));
+ productList.add(new Product(4, "Nokia", "Телефон", 20,21,0,1));
+ productList.add(new Product(5, "Samsung HotBench", "Мікрохвильова піч", 1000,1200,0,1));
+
+ for(Product product:productList)
+ productDao.create(product);
+*/
+ }
+
+ public void onClickTableView(MouseEvent mouseEvent) {
+ int index = tableProduct.getSelectionModel().getSelectedIndex();
+ fieldId.setText(Integer.toString(tableProduct.getSelectionModel().getTableView().getItems().get(index).getId()));
+ fieldName.setText(tableProduct.getSelectionModel().getTableView().getItems().get(index).getName());
+ fieldType.setText(tableProduct.getSelectionModel().getTableView().getItems().get(index).getType());
+ fieldRetailPrice.setText(Integer.toString(tableProduct.getSelectionModel().getTableView().getItems().get(index).getRetail_price()));
+ fieldWholesalePrice.setText(Integer.toString(tableProduct.getSelectionModel().getTableView().getItems().get(index).getWholesale_price()));
+ fieldProvider.setText(Integer.toString(tableProduct.getSelectionModel().getTableView().getItems().get(index).getProvider_id()));
+ fieldCount.setText(Integer.toString(tableProduct.getSelectionModel().getTableView().getItems().get(index).getCount()));
+ }
+
+ public void onClickApply(MouseEvent mouseEvent) {
+ Product product = new Product(Integer.valueOf(fieldId.getText()),fieldName.getText(),fieldType.getText(), Integer.valueOf(fieldWholesalePrice.getText()),Integer.valueOf(fieldRetailPrice.getText()),Integer.valueOf(fieldProvider.getText()),Integer.valueOf(fieldCount.getText()));
+ if(!fieldId.getText().isEmpty() && productDao.findByID(Integer.valueOf(fieldId.getText()))!=null){
+ productDao.updateProduct(product);
+ }else{
+ productDao.create(product);
+ }
+ productList.clear();
+ productList.addAll(productDao.getAll());
+
+ }
+
+ public void onClickDelete(MouseEvent mouseEvent) {
+ if (!fieldId.getText().isEmpty() && productDao.findByID(Integer.valueOf(fieldId.getText())) != null) {
+ productDao.deleteById(Integer.valueOf(fieldId.getText()));
+ }
+ productList.clear();
+ productList.addAll(productDao.getAll());
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/sample/Main.java b/src/main/java/sample/Main.java
new file mode 100644
index 0000000..31e20c6
--- /dev/null
+++ b/src/main/java/sample/Main.java
@@ -0,0 +1,26 @@
+package sample;
+
+import javafx.application.Application;
+import javafx.fxml.FXMLLoader;
+import javafx.scene.Parent;
+import javafx.scene.Scene;
+import javafx.stage.Stage;
+
+public class Main extends Application {
+
+ @Override
+ public void start(Stage primaryStage) throws Exception{
+ String fxmlFile = "/fxml/sample.fxml";
+ FXMLLoader loader = new FXMLLoader();
+ Parent root = (Parent) loader.load(getClass().getResourceAsStream(fxmlFile));
+
+ primaryStage.setTitle("Hello World");
+ primaryStage.setScene(new Scene(root, 750, 300));
+ primaryStage.show();
+ }
+
+
+ public static void main(String[] args) {
+ launch();
+ }
+}
diff --git a/src/main/java/sample/dao/ProductDao.java b/src/main/java/sample/dao/ProductDao.java
new file mode 100644
index 0000000..b2f0271
--- /dev/null
+++ b/src/main/java/sample/dao/ProductDao.java
@@ -0,0 +1,117 @@
+package sample.dao;
+
+import sample.db.ConnectionPool;
+import sample.model.Product;
+import sample.model.Provider;
+
+import java.sql.*;
+import java.util.ArrayList;
+import java.util.List;
+
+public class ProductDao {
+ private ConnectionPool pool = ConnectionPool.getInstance();
+ private final String INSERT_PRODUCT= "INSERT INTO trade_report.product (id, name, type, wholesale_price, retail_price, provider_id, count) VALUES (?, ?, ?, ?, ?, ?, ?)";
+ private final String SELECT_ALL_PRODUCT= "SELECT * FROM trade_report.product";
+ private final String DELETE_PRODUCT= "DELETE FROM trade_report.product WHERE id=?";
+ private final String UPDATE_PRODUCT= "UPDATE trade_report.product SET name=?, type=?, wholesale_price=?, retail_price=?, provider_id=?, count=? WHERE ID=?";
+ private final String SELECT_PRODUCT_BY_ID = "SELECT * FROM trade_report.product WHERE id=?";
+
+ public Integer create(Product product) {
+ int idUser = 0;
+ try (Connection connection = pool.takeConnection();
+ PreparedStatement statement = connection.prepareStatement(INSERT_PRODUCT, Statement.RETURN_GENERATED_KEYS)) {
+ statement.setInt(1, product.getId());
+ statement.setString(2, product.getName());
+ statement.setString(3, String.valueOf(product.getType()));
+ statement.setInt(4, product.getWholesale_price());
+ statement.setInt(5, product.getRetail_price());
+ statement.setInt(6, product.getProvider_id());
+ statement.setInt(7, product.getCount());
+ statement.executeUpdate();
+ ResultSet resultSet = statement.getGeneratedKeys();
+ if(resultSet.next())
+ idUser = resultSet.getInt(1);
+ resultSet.close();
+ } catch (SQLException e) {
+ e.printStackTrace();
+ }
+ return idUser;
+ }
+
+ public List getAll() {
+ List products = new ArrayList<>();
+ try (Connection connection = pool.takeConnection();
+ PreparedStatement statement = connection.prepareStatement(SELECT_ALL_PRODUCT);
+ ResultSet resultSet = statement.executeQuery()) {
+ while (resultSet.next()) {
+ Product product = retrieveEntity(resultSet);
+ products.add(product);
+ }
+ } catch (SQLException e) {
+ e.printStackTrace();
+ }
+ return products;
+ }
+
+ public Product findByID(int id){
+ Product product = null;
+ try (Connection connection = pool.takeConnection();
+ PreparedStatement statement = connection.prepareStatement(SELECT_PRODUCT_BY_ID)) {
+ statement.setInt(1, id);
+ ResultSet resultSet = statement.executeQuery();
+ if (resultSet.next()) {
+ product = retrieveEntity(resultSet);
+ }
+ resultSet.close();
+ } catch (SQLException e) {
+ e.printStackTrace();
+ }
+ return product;
+ }
+
+ public boolean updateProduct(Product product){
+ int idUser = 0;
+ try (Connection connection = pool.takeConnection();
+ PreparedStatement statement = connection.prepareStatement(UPDATE_PRODUCT)) {
+ statement.setString(1, product.getName());
+ statement.setString(2, String.valueOf(product.getType()));
+ statement.setInt(3, product.getWholesale_price());
+ statement.setInt(4, product.getRetail_price());
+ statement.setInt(5, product.getProvider_id());
+ statement.setInt(6, product.getCount());
+ statement.setInt(7, product.getId());
+ statement.executeUpdate();
+ } catch (SQLException e) {
+ e.printStackTrace();
+ }
+
+ return true; ///fix this shit;
+ }
+
+ public void deleteById(Integer id) {
+ try (Connection connection = pool.takeConnection();
+ PreparedStatement statement = connection.prepareStatement(DELETE_PRODUCT)) {
+ statement.setInt(1, id);
+ statement.executeUpdate();
+ } catch (SQLException e) {
+ e.printStackTrace();
+ }
+ }
+
+ public Product retrieveEntity(ResultSet resultSet) {
+ Product product = new Product();
+ try{
+ product.setId(resultSet.getInt("id"));
+ product.setName(resultSet.getString("name"));
+ product.setType(resultSet.getString("type"));
+ product.setWholesale_price(resultSet.getInt("wholesale_price"));
+ product.setRetail_price(resultSet.getInt("retail_price"));
+ product.setProvider_id(resultSet.getInt("provider_id"));
+ product.setCount(resultSet.getInt("count"));
+ } catch (SQLException e) {
+ e.printStackTrace();
+ }
+ return product;
+ }
+
+}
diff --git a/src/main/java/sample/db/ConnectionPool.java b/src/main/java/sample/db/ConnectionPool.java
new file mode 100644
index 0000000..ec0cc04
--- /dev/null
+++ b/src/main/java/sample/db/ConnectionPool.java
@@ -0,0 +1,364 @@
+package sample.db;
+
+import java.sql.*;
+import java.util.Map;
+import java.util.Properties;
+import java.util.concurrent.ArrayBlockingQueue;
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.Executor;
+
+public class ConnectionPool {
+ private static ConnectionPool poolInstance = null;
+ private static volatile boolean isCreated = false;
+
+ private BlockingQueue connections;
+
+ private int poolSize;
+ private String url;
+ private String login;
+ private String password;
+
+ public static ConnectionPool getInstance() {
+ if (!isCreated) {
+ synchronized (ConnectionPool.class) {
+ poolInstance = new ConnectionPool();
+ isCreated = true;
+ }
+ }
+ return poolInstance;
+ }
+
+ private ConnectionPool() {
+ this.poolSize = 10;
+ this.url = "jdbc:mysql://localhost:3306/trade_report?serverTimezone=Europe/Kiev&allowPublicKeyRetrieval=true&useSSL=false&useUnicode=yes&characterEncoding=UTF-8";
+ this.login = "root";
+ this.password = "Aqva3283.";
+ initPoolData();
+ }
+
+ private void initPoolData() {
+ connections = new ArrayBlockingQueue<>(poolSize);
+ for (int i = 0; i < poolSize; i++) {
+ try {
+ DriverManager.registerDriver(new com.mysql.jdbc.Driver());
+ Connection connection = DriverManager.getConnection(url, login, password);
+ connection.setClientInfo("myName", "" + i);
+ connections.add(new PooledConnection(connection));
+ } catch (SQLException e) {
+ }
+ }
+ }
+
+ public Connection takeConnection() throws SQLException {
+ Connection connection;
+ try {
+ connection = connections.take();
+ } catch (InterruptedException e) {
+ throw new SQLException();
+ }
+ return connection;
+ }
+
+ public void dispose() {
+ Connection connection;
+ while ((connection = connections.poll()) != null) {
+ try {
+ connection.commit();
+ ((PooledConnection) connection).connectionClose();
+ } catch (SQLException e) {
+ e.printStackTrace();
+ }
+ }
+
+ }
+
+
+ private class PooledConnection implements Connection {
+
+ private Connection connection;
+
+ PooledConnection(Connection connection) throws SQLException {
+ this.connection = connection;
+ this.connection.setAutoCommit(true);
+ }
+
+ private void connectionClose() throws SQLException{
+ connection.close();
+ }
+
+ @Override
+ public void close() throws SQLException {
+ if (connection.isClosed()) {
+ throw new SQLException("Connection has already been closed.");
+ }
+ if (!connections.offer(this)) {
+ throw new SQLException("Unable to return used connection to the queue of available connections");
+ }
+ }
+
+ @Override
+ public boolean isClosed() throws SQLException {
+ return connection.isClosed();
+ }
+
+ @Override
+ public Statement createStatement() throws SQLException {
+ return connection.createStatement();
+ }
+
+ @Override
+ public PreparedStatement prepareStatement(String sql) throws SQLException {
+ return connection.prepareStatement(sql);
+ }
+
+ @Override
+ public CallableStatement prepareCall(String sql) throws SQLException {
+ return connection.prepareCall(sql);
+ }
+
+ @Override
+ public String nativeSQL(String sql) throws SQLException {
+ return connection.nativeSQL(sql);
+ }
+
+ @Override
+ public void setAutoCommit(boolean autoCommit) throws SQLException {
+ connection.setAutoCommit(autoCommit);
+ }
+
+ @Override
+ public boolean getAutoCommit() throws SQLException {
+ return connection.getAutoCommit();
+ }
+
+ @Override
+ public void commit() throws SQLException {
+ connection.commit();
+ }
+
+ @Override
+ public void rollback() throws SQLException {
+ connection.rollback();
+ }
+
+ @Override
+ public DatabaseMetaData getMetaData() throws SQLException {
+ return connection.getMetaData();
+ }
+
+ @Override
+ public void setReadOnly(boolean readOnly) throws SQLException {
+ connection.setReadOnly(readOnly);
+ }
+
+ @Override
+ public boolean isReadOnly() throws SQLException {
+ return connection.isReadOnly();
+ }
+
+ @Override
+ public void setCatalog(String catalog) throws SQLException {
+ connection.setCatalog(catalog);
+ }
+
+ @Override
+ public String getCatalog() throws SQLException {
+ return connection.getCatalog();
+ }
+
+ @Override
+ public void setTransactionIsolation(int level) throws SQLException {
+ connection.setTransactionIsolation(level);
+ }
+
+ @Override
+ public int getTransactionIsolation() throws SQLException {
+ return connection.getTransactionIsolation();
+ }
+
+ @Override
+ public SQLWarning getWarnings() throws SQLException {
+ return connection.getWarnings();
+ }
+
+ @Override
+ public void clearWarnings() throws SQLException {
+ connection.clearWarnings();
+ }
+
+ @Override
+ public Statement createStatement(int resultSetType, int resultSetConcurrency) throws SQLException {
+ return connection.createStatement();
+ }
+
+ @Override
+ public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency) throws SQLException {
+ return connection.prepareStatement(sql);
+ }
+
+ @Override
+ public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency) throws SQLException {
+ return connection.prepareCall(sql);
+ }
+
+ @Override
+ public Map> getTypeMap() throws SQLException {
+ return connection.getTypeMap();
+ }
+
+ @Override
+ public void setTypeMap(Map> map) throws SQLException {
+ connection.setTypeMap(map);
+ }
+
+ @Override
+ public void setHoldability(int holdability) throws SQLException {
+ connection.setHoldability(holdability);
+ }
+
+ @Override
+ public int getHoldability() throws SQLException {
+ return connection.getHoldability();
+ }
+
+ @Override
+ public Savepoint setSavepoint() throws SQLException {
+ return connection.setSavepoint();
+ }
+
+ @Override
+ public Savepoint setSavepoint(String name) throws SQLException {
+ return setSavepoint(name);
+ }
+
+ @Override
+ public void rollback(Savepoint savepoint) throws SQLException {
+ connection.rollback();
+ }
+
+ @Override
+ public void releaseSavepoint(Savepoint savepoint) throws SQLException {
+ connection.releaseSavepoint(savepoint);
+ }
+
+ @Override
+ public Statement createStatement(int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException {
+ return connection.createStatement();
+ }
+
+ @Override
+ public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException {
+ return connection.prepareStatement(sql, resultSetType, resultSetConcurrency, resultSetHoldability);
+ }
+
+ @Override
+ public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException {
+ return connection.prepareCall(sql, resultSetType, resultSetConcurrency, resultSetHoldability);
+ }
+
+ @Override
+ public PreparedStatement prepareStatement(String sql, int autoGeneratedKeys) throws SQLException {
+ return connection.prepareStatement(sql, autoGeneratedKeys);
+ }
+
+ @Override
+ public PreparedStatement prepareStatement(String sql, int[] columnIndexes) throws SQLException {
+ return connection.prepareStatement(sql, columnIndexes);
+ }
+
+ @Override
+ public PreparedStatement prepareStatement(String sql, String[] columnNames) throws SQLException {
+ return connection.prepareStatement(sql, columnNames);
+ }
+
+ @Override
+ public Clob createClob() throws SQLException {
+ return connection.createClob();
+ }
+
+ @Override
+ public Blob createBlob() throws SQLException {
+ return connection.createBlob();
+ }
+
+ @Override
+ public NClob createNClob() throws SQLException {
+ return connection.createNClob();
+ }
+
+ @Override
+ public SQLXML createSQLXML() throws SQLException {
+ return connection.createSQLXML();
+ }
+
+ @Override
+ public boolean isValid(int timeout) throws SQLException {
+ return connection.isValid(timeout);
+ }
+
+ @Override
+ public void setClientInfo(String name, String value) throws SQLClientInfoException {
+ connection.setClientInfo(name, value);
+ }
+
+ @Override
+ public void setClientInfo(Properties properties) throws SQLClientInfoException {
+ connection.setClientInfo(properties);
+ }
+
+ @Override
+ public String getClientInfo(String name) throws SQLException {
+ return connection.getClientInfo(name);
+ }
+
+ @Override
+ public Properties getClientInfo() throws SQLException {
+ return connection.getClientInfo();
+ }
+
+ @Override
+ public Array createArrayOf(String typeName, Object[] elements) throws SQLException {
+ return connection.createArrayOf(typeName, elements);
+ }
+
+ @Override
+ public Struct createStruct(String typeName, Object[] attributes) throws SQLException {
+ return connection.createStruct(typeName, attributes);
+ }
+
+ @Override
+ public void setSchema(String schema) throws SQLException {
+ connection.setSchema(schema);
+ }
+
+ @Override
+ public String getSchema() throws SQLException {
+ return connection.getSchema();
+ }
+
+ @Override
+ public void abort(Executor executor) throws SQLException {
+ connection.abort(executor);
+ }
+
+ @Override
+ public void setNetworkTimeout(Executor executor, int milliseconds) throws SQLException {
+ connection.setNetworkTimeout(executor, milliseconds);
+ }
+
+ @Override
+ public int getNetworkTimeout() throws SQLException {
+ return connection.getNetworkTimeout();
+ }
+
+ @Override
+ public T unwrap(Class iface) throws SQLException {
+ return unwrap(iface);
+ }
+
+ @Override
+ public boolean isWrapperFor(Class> iface) throws SQLException {
+ return connection.isWrapperFor(iface);
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/sample/model/Product.java b/src/main/java/sample/model/Product.java
new file mode 100644
index 0000000..f12c3b2
--- /dev/null
+++ b/src/main/java/sample/model/Product.java
@@ -0,0 +1,22 @@
+package sample.model;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+
+@Getter
+@Setter
+@AllArgsConstructor
+@NoArgsConstructor
+
+public class Product {
+ private int id;
+ private String name;
+ private String type;
+ private int wholesale_price;
+ private int retail_price;
+ private int provider_id;
+ private int count;
+
+}
diff --git a/src/main/java/sample/model/Provider.java b/src/main/java/sample/model/Provider.java
new file mode 100644
index 0000000..3758aa8
--- /dev/null
+++ b/src/main/java/sample/model/Provider.java
@@ -0,0 +1,16 @@
+package sample.model;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+
+@Getter
+@Setter
+@AllArgsConstructor
+@NoArgsConstructor
+
+public class Provider {
+ private int id;
+ private String name;
+}
diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties
new file mode 100644
index 0000000..c724e8f
--- /dev/null
+++ b/src/main/resources/application.properties
@@ -0,0 +1,10 @@
+spring.datasource.url=jdbc:mysql://localhost:3306/trade_report?serverTimezone=Europe/Kiev&allowPublicKeyRetrieval=true&useSSL=false&useUnicode=yes&characterEncoding=UTF-8
+spring.datasource.username=root
+spring.datasource.password=Aqva3283.
+spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
+spring.jpa.hibernate.ddl-auto=update
+spring.jpa.database-platform=org.hibernate.dialect.MySQL57Dialect
+spring.jpa.generate-ddl=true
+spring.jpa.show-sql=true
+
+
diff --git a/src/main/resources/fxml/sample.fxml b/src/main/resources/fxml/sample.fxml
new file mode 100644
index 0000000..3926405
--- /dev/null
+++ b/src/main/resources/fxml/sample.fxml
@@ -0,0 +1,75 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+