Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
J
java_weekendowa_20221008
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Patryk Czarnik
java_weekendowa_20221008
Commits
e9f323b3
Commit
e9f323b3
authored
Nov 26, 2022
by
Patryk Czarnik
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Dodatkowe przykłady JPA na serwerze
parent
04f5afde
Hide whitespace changes
Inline
Side-by-side
Showing
10 changed files
with
483 additions
and
2 deletions
+483
-2
Lista0.java
...ernateNaSerwerze/src/main/java/sklep/serwlety/Lista0.java
+1
-1
Lista1.java
...ernateNaSerwerze/src/main/java/sklep/serwlety/Lista1.java
+53
-0
Lista2.java
...ernateNaSerwerze/src/main/java/sklep/serwlety/Lista2.java
+53
-0
Lista3.java
...ernateNaSerwerze/src/main/java/sklep/serwlety/Lista3.java
+47
-0
Sql1.java
...ibernateNaSerwerze/src/main/java/sklep/serwlety/Sql1.java
+51
-0
Sql2.java
...ibernateNaSerwerze/src/main/java/sklep/serwlety/Sql2.java
+58
-0
Sql3.java
...ibernateNaSerwerze/src/main/java/sklep/serwlety/Sql3.java
+55
-0
Zmiana2.java
...rnateNaSerwerze/src/main/java/sklep/serwlety/Zmiana2.java
+75
-0
Zmiana3.java
...rnateNaSerwerze/src/main/java/sklep/serwlety/Zmiana3.java
+72
-0
index.html
PC29-HibernateNaSerwerze/src/main/webapp/index.html
+18
-1
No files found.
PC29-HibernateNaSerwerze/src/main/java/sklep/serwlety/Lista0.java
View file @
e9f323b3
...
@@ -17,7 +17,7 @@ import javax.servlet.http.HttpServletResponse;
...
@@ -17,7 +17,7 @@ import javax.servlet.http.HttpServletResponse;
import
sklep.model.Product
;
import
sklep.model.Product
;
// http://localhost:8080/PC29-HibernateNaSerwerze-1.0/Lista0
// http://localhost:8080/PC29-HibernateNaSerwerze-1.0/Lista0
@WebServlet
(
"/
L
ista0"
)
@WebServlet
(
"/
l
ista0"
)
public
class
Lista0
extends
HttpServlet
{
public
class
Lista0
extends
HttpServlet
{
private
static
final
long
serialVersionUID
=
1L
;
private
static
final
long
serialVersionUID
=
1L
;
...
...
PC29-HibernateNaSerwerze/src/main/java/sklep/serwlety/Lista1.java
0 → 100644
View file @
e9f323b3
package
sklep
.
serwlety
;
import
java.io.IOException
;
import
java.io.PrintWriter
;
import
java.util.List
;
import
javax.persistence.EntityManager
;
import
javax.persistence.EntityManagerFactory
;
import
javax.persistence.Persistence
;
import
javax.persistence.TypedQuery
;
import
javax.servlet.ServletException
;
import
javax.servlet.annotation.WebServlet
;
import
javax.servlet.http.HttpServlet
;
import
javax.servlet.http.HttpServletRequest
;
import
javax.servlet.http.HttpServletResponse
;
import
sklep.model.Product
;
// Wersja z ręcznym uzyskaniem dostępu do `persistence` - poprzez fabrykę, a nie wstrzykiwanie zależności.
// To jest napisane niemal tak, jak "zwykły program z mainem".
// To serwer zapewnia implementację JPA - my nie dodajemy jej do pom.xml (dodajemy tylko javaee-web-api)
// WildFly użyje Hibernate, a Glassfish użyje Eclipse Link.
// Wersja zadziała także przy konfiguracji połączenia "RESOURCE_LOCAL" z parametrami połączenia podanymi w persistence.xml
@WebServlet
(
"/lista1"
)
public
class
Lista1
extends
HttpServlet
{
private
static
final
long
serialVersionUID
=
1L
;
protected
void
doGet
(
HttpServletRequest
request
,
HttpServletResponse
response
)
throws
ServletException
,
IOException
{
response
.
setContentType
(
"text/plain"
);
response
.
setCharacterEncoding
(
"UTF-8"
);
PrintWriter
out
=
response
.
getWriter
();
EntityManagerFactory
emf
=
null
;
EntityManager
em
=
null
;
try
{
emf
=
Persistence
.
createEntityManagerFactory
(
"sklep"
);
em
=
emf
.
createEntityManager
();
TypedQuery
<
Product
>
query
=
em
.
createNamedQuery
(
"Product.findAll"
,
Product
.
class
);
List
<
Product
>
products
=
query
.
getResultList
();
out
.
println
(
"Odczytano "
+
products
.
size
()
+
" rekordów:"
);
for
(
Product
product
:
products
)
{
out
.
println
(
product
.
getProductName
()
+
" "
+
product
.
getPrice
());
}
}
catch
(
Exception
e
)
{
out
.
println
(
"Wyjątek: "
+
e
);
}
finally
{
if
(
em
!=
null
)
em
.
close
();
if
(
emf
!=
null
)
emf
.
close
();
}
}
}
PC29-HibernateNaSerwerze/src/main/java/sklep/serwlety/Lista2.java
0 → 100644
View file @
e9f323b3
package
sklep
.
serwlety
;
import
java.io.IOException
;
import
java.io.PrintWriter
;
import
java.util.List
;
import
javax.persistence.EntityManager
;
import
javax.persistence.EntityManagerFactory
;
import
javax.persistence.PersistenceUnit
;
import
javax.persistence.TypedQuery
;
import
javax.servlet.ServletException
;
import
javax.servlet.annotation.WebServlet
;
import
javax.servlet.http.HttpServlet
;
import
javax.servlet.http.HttpServletRequest
;
import
javax.servlet.http.HttpServletResponse
;
import
sklep.model.Product
;
// Wersja ze wstrzykiwaniem EntityManagerFactory za pomocą adnotacji @PersistenceUnit.
// Jeśli w aplikacji jest tylko jeden persistence unit, to nazwy można nie podawać, ale ja wolę zawsze podać.
// Ta wersja jest odpowiednia także dla konfiguracji opartej o RESOURCE_LOCAL
@WebServlet
(
"/lista2"
)
public
class
Lista2
extends
HttpServlet
{
private
static
final
long
serialVersionUID
=
1L
;
@PersistenceUnit
(
unitName
=
"sklep"
)
private
EntityManagerFactory
emf
;
protected
void
doGet
(
HttpServletRequest
request
,
HttpServletResponse
response
)
throws
ServletException
,
IOException
{
response
.
setContentType
(
"text/plain"
);
response
.
setCharacterEncoding
(
"UTF-8"
);
PrintWriter
out
=
response
.
getWriter
();
EntityManager
em
=
null
;
try
{
em
=
emf
.
createEntityManager
();
TypedQuery
<
Product
>
query
=
em
.
createNamedQuery
(
"Product.findAll"
,
Product
.
class
);
List
<
Product
>
products
=
query
.
getResultList
();
out
.
println
(
"Odczytano "
+
products
.
size
()
+
" rekordów:"
);
for
(
Product
product
:
products
)
{
out
.
println
(
product
.
getProductName
()
+
" "
+
product
.
getPrice
());
}
}
catch
(
Exception
e
)
{
out
.
println
(
"Wyjątek: "
+
e
+
"\n"
);
e
.
printStackTrace
(
out
);
}
finally
{
if
(
em
!=
null
)
em
.
close
();
}
}
}
PC29-HibernateNaSerwerze/src/main/java/sklep/serwlety/Lista3.java
0 → 100644
View file @
e9f323b3
package
sklep
.
serwlety
;
import
java.io.IOException
;
import
java.io.PrintWriter
;
import
java.util.List
;
import
javax.persistence.EntityManager
;
import
javax.persistence.PersistenceContext
;
import
javax.persistence.TypedQuery
;
import
javax.servlet.ServletException
;
import
javax.servlet.annotation.WebServlet
;
import
javax.servlet.http.HttpServlet
;
import
javax.servlet.http.HttpServletRequest
;
import
javax.servlet.http.HttpServletResponse
;
import
sklep.model.Product
;
// Wersja ze wstrzykiwaniem EntityManager (a nie fabryki) za pomocą adnotacji @PersistenceContext.
// Jeśli w aplikacji jest tylko jeden persistence unit, to nazwy można nie podawać, ale ja wolę zawsze podać.
// Ta wersja jest odpowiednia dla konfiguracji opartej o JTA
//@WebServlet("/lista3")
public
class
Lista3
extends
HttpServlet
{
private
static
final
long
serialVersionUID
=
1L
;
@PersistenceContext
(
unitName
=
"sklep"
)
private
EntityManager
em
;
protected
void
doGet
(
HttpServletRequest
request
,
HttpServletResponse
response
)
throws
ServletException
,
IOException
{
response
.
setContentType
(
"text/plain"
);
response
.
setCharacterEncoding
(
"UTF-8"
);
PrintWriter
out
=
response
.
getWriter
();
try
{
TypedQuery
<
Product
>
query
=
em
.
createNamedQuery
(
"Product.findAll"
,
Product
.
class
);
List
<
Product
>
products
=
query
.
getResultList
();
out
.
println
(
"Odczytano "
+
products
.
size
()
+
" rekordów:"
);
for
(
Product
product
:
products
)
{
out
.
println
(
product
.
getProductName
()
+
" "
+
product
.
getPrice
());
}
}
catch
(
Exception
e
)
{
out
.
println
(
"Wyjątek: "
+
e
+
"\n"
);
e
.
printStackTrace
(
out
);
}
}
}
PC29-HibernateNaSerwerze/src/main/java/sklep/serwlety/Sql1.java
0 → 100644
View file @
e9f323b3
package
sklep
.
serwlety
;
import
java.io.IOException
;
import
java.io.PrintWriter
;
import
java.math.BigDecimal
;
import
java.sql.Connection
;
import
java.sql.DriverManager
;
import
java.sql.PreparedStatement
;
import
java.sql.ResultSet
;
import
java.sql.SQLException
;
import
javax.servlet.ServletException
;
import
javax.servlet.annotation.WebServlet
;
import
javax.servlet.http.HttpServlet
;
import
javax.servlet.http.HttpServletRequest
;
import
javax.servlet.http.HttpServletResponse
;
@WebServlet
(
"/sql1"
)
public
class
Sql1
extends
HttpServlet
{
private
static
final
long
serialVersionUID
=
1L
;
protected
void
doGet
(
HttpServletRequest
request
,
HttpServletResponse
response
)
throws
ServletException
,
IOException
{
response
.
setContentType
(
"text/plain"
);
response
.
setCharacterEncoding
(
"UTF-8"
);
PrintWriter
out
=
response
.
getWriter
();
try
{
final
String
sql
=
"SELECT * FROM products"
;
try
(
Connection
c
=
DriverManager
.
getConnection
(
"jdbc:postgresql://localhost/sklep"
,
"kurs"
,
"abc123"
))
{
out
.
println
(
"Connection połączone: "
+
c
);
try
(
PreparedStatement
stmt
=
c
.
prepareStatement
(
sql
))
{
try
(
ResultSet
rs
=
stmt
.
executeQuery
())
{
while
(
rs
.
next
())
{
int
id
=
rs
.
getInt
(
"product_id"
);
String
productName
=
rs
.
getString
(
"product_name"
);
BigDecimal
price
=
rs
.
getBigDecimal
(
"price"
);
String
description
=
rs
.
getString
(
"description"
);
out
.
printf
(
"\n * Produkt nr %d: %s w cenie %s (%s)\n"
,
id
,
productName
,
price
,
description
);
}
}
}
}
}
catch
(
SQLException
e
)
{
e
.
printStackTrace
(
out
);
}
catch
(
Exception
e
)
{
e
.
printStackTrace
(
out
);
}
}
}
PC29-HibernateNaSerwerze/src/main/java/sklep/serwlety/Sql2.java
0 → 100644
View file @
e9f323b3
package
sklep
.
serwlety
;
import
java.io.IOException
;
import
java.io.PrintWriter
;
import
java.math.BigDecimal
;
import
java.sql.Connection
;
import
java.sql.PreparedStatement
;
import
java.sql.ResultSet
;
import
java.sql.SQLException
;
import
javax.naming.InitialContext
;
import
javax.naming.NamingException
;
import
javax.servlet.ServletException
;
import
javax.servlet.annotation.WebServlet
;
import
javax.servlet.http.HttpServlet
;
import
javax.servlet.http.HttpServletRequest
;
import
javax.servlet.http.HttpServletResponse
;
import
javax.sql.DataSource
;
@WebServlet
(
"/sql2"
)
public
class
Sql2
extends
HttpServlet
{
private
static
final
long
serialVersionUID
=
1L
;
protected
void
doGet
(
HttpServletRequest
request
,
HttpServletResponse
response
)
throws
ServletException
,
IOException
{
response
.
setContentType
(
"text/plain"
);
response
.
setCharacterEncoding
(
"UTF-8"
);
PrintWriter
out
=
response
.
getWriter
();
try
{
// Połączenie z bazą (jako DataSource) pobieramy z rejestru serwera (technologia JNDI - zasoby zarządzane przez serwer Java EE)
InitialContext
ctx
=
new
InitialContext
();
DataSource
ds
=
(
DataSource
)
ctx
.
lookup
(
"java:/SklepDS"
);
out
.
println
(
"DataSource znaleziony: "
+
ds
);
final
String
sql
=
"SELECT * FROM products"
;
try
(
Connection
c
=
ds
.
getConnection
())
{
try
(
PreparedStatement
stmt
=
c
.
prepareStatement
(
sql
))
{
try
(
ResultSet
rs
=
stmt
.
executeQuery
())
{
while
(
rs
.
next
())
{
int
id
=
rs
.
getInt
(
"product_id"
);
String
productName
=
rs
.
getString
(
"product_name"
);
BigDecimal
price
=
rs
.
getBigDecimal
(
"price"
);
String
description
=
rs
.
getString
(
"description"
);
out
.
printf
(
"\n * Produkt nr %d: %s w cenie %s (%s)\n"
,
id
,
productName
,
price
,
description
);
}
}
}
}
}
catch
(
SQLException
e
)
{
e
.
printStackTrace
(
out
);
}
catch
(
NamingException
e
)
{
e
.
printStackTrace
(
out
);
}
catch
(
Exception
e
)
{
e
.
printStackTrace
(
out
);
}
}
}
PC29-HibernateNaSerwerze/src/main/java/sklep/serwlety/Sql3.java
0 → 100644
View file @
e9f323b3
package
sklep
.
serwlety
;
import
java.io.IOException
;
import
java.io.PrintWriter
;
import
java.math.BigDecimal
;
import
java.sql.Connection
;
import
java.sql.PreparedStatement
;
import
java.sql.ResultSet
;
import
java.sql.SQLException
;
import
javax.annotation.Resource
;
import
javax.servlet.ServletException
;
import
javax.servlet.annotation.WebServlet
;
import
javax.servlet.http.HttpServlet
;
import
javax.servlet.http.HttpServletRequest
;
import
javax.servlet.http.HttpServletResponse
;
import
javax.sql.DataSource
;
@WebServlet
(
"/sql3"
)
public
class
Sql3
extends
HttpServlet
{
private
static
final
long
serialVersionUID
=
1L
;
@Resource
(
lookup
=
"java:/SklepDS"
)
private
DataSource
ds
;
protected
void
doGet
(
HttpServletRequest
request
,
HttpServletResponse
response
)
throws
ServletException
,
IOException
{
response
.
setContentType
(
"text/plain"
);
response
.
setCharacterEncoding
(
"UTF-8"
);
PrintWriter
out
=
response
.
getWriter
();
try
{
out
.
println
(
"DataSource wstrzyknięty: "
+
ds
);
final
String
sql
=
"SELECT * FROM products"
;
try
(
Connection
c
=
ds
.
getConnection
())
{
try
(
PreparedStatement
stmt
=
c
.
prepareStatement
(
sql
))
{
try
(
ResultSet
rs
=
stmt
.
executeQuery
())
{
while
(
rs
.
next
())
{
int
id
=
rs
.
getInt
(
"product_id"
);
String
productName
=
rs
.
getString
(
"product_name"
);
BigDecimal
price
=
rs
.
getBigDecimal
(
"price"
);
String
description
=
rs
.
getString
(
"description"
);
out
.
printf
(
"\n * Produkt nr %d: %s w cenie %s (%s)\n"
,
id
,
productName
,
price
,
description
);
}
}
}
}
}
catch
(
SQLException
e
)
{
e
.
printStackTrace
(
out
);
}
catch
(
Exception
e
)
{
e
.
printStackTrace
(
out
);
}
}
}
PC29-HibernateNaSerwerze/src/main/java/sklep/serwlety/Zmiana2.java
0 → 100644
View file @
e9f323b3
package
sklep
.
serwlety
;
import
java.io.IOException
;
import
java.io.PrintWriter
;
import
java.math.BigDecimal
;
import
javax.persistence.EntityManager
;
import
javax.persistence.EntityManagerFactory
;
import
javax.persistence.EntityTransaction
;
import
javax.persistence.PersistenceUnit
;
import
javax.servlet.ServletException
;
import
javax.servlet.annotation.WebServlet
;
import
javax.servlet.http.HttpServlet
;
import
javax.servlet.http.HttpServletRequest
;
import
javax.servlet.http.HttpServletResponse
;
import
sklep.model.Product
;
@WebServlet
(
"/zmiana2"
)
public
class
Zmiana2
extends
HttpServlet
{
private
static
final
long
serialVersionUID
=
1L
;
@PersistenceUnit
(
unitName
=
"sklep"
)
private
EntityManagerFactory
emf
;
protected
void
doGet
(
HttpServletRequest
request
,
HttpServletResponse
response
)
throws
ServletException
,
IOException
{
response
.
setContentType
(
"text/plain"
);
response
.
setCharacterEncoding
(
"utf-8"
);
PrintWriter
out
=
response
.
getWriter
();
if
(
request
.
getParameter
(
"id"
)
==
null
)
{
out
.
println
(
"Trzeba podać id produktu"
);
return
;
}
Integer
id
=
Integer
.
valueOf
(
request
.
getParameter
(
"id"
));
BigDecimal
podwyzka
=
null
;
if
(
request
.
getParameter
(
"podwyzka"
)
!=
null
)
{
podwyzka
=
new
BigDecimal
(
request
.
getParameter
(
"podwyzka"
));
}
EntityManager
em
=
null
;
try
{
em
=
emf
.
createEntityManager
();
EntityTransaction
transaction
=
em
.
getTransaction
();
transaction
.
begin
();
Product
product
=
em
.
find
(
Product
.
class
,
id
);
if
(
product
==
null
)
{
out
.
println
(
"Nie znaleziono produktu o numerze "
+
id
);
return
;
}
out
.
println
(
product
.
getProductName
()
+
" "
+
product
.
getPrice
());
if
(
podwyzka
!=
null
)
{
product
.
setPrice
(
product
.
getPrice
().
add
(
podwyzka
));
}
out
.
println
(
"Po zmianie:"
);
out
.
println
(
product
.
getProductName
()
+
" "
+
product
.
getPrice
());
transaction
.
commit
();
}
catch
(
SecurityException
|
IllegalStateException
e
)
{
throw
new
ServletException
(
"wielka bieda"
,
e
);
}
finally
{
if
(
em
!=
null
)
{
em
.
close
();
}
}
}
}
PC29-HibernateNaSerwerze/src/main/java/sklep/serwlety/Zmiana3.java
0 → 100644
View file @
e9f323b3
package
sklep
.
serwlety
;
import
java.io.IOException
;
import
java.io.PrintWriter
;
import
java.math.BigDecimal
;
import
javax.annotation.Resource
;
import
javax.persistence.EntityManager
;
import
javax.persistence.PersistenceContext
;
import
javax.servlet.ServletException
;
import
javax.servlet.annotation.WebServlet
;
import
javax.servlet.http.HttpServlet
;
import
javax.servlet.http.HttpServletRequest
;
import
javax.servlet.http.HttpServletResponse
;
import
javax.transaction.UserTransaction
;
import
sklep.model.Product
;
//@WebServlet("/zmiana3")
public
class
Zmiana3
extends
HttpServlet
{
private
static
final
long
serialVersionUID
=
1L
;
@PersistenceContext
(
unitName
=
"sklep"
)
private
EntityManager
em
;
@Resource
private
UserTransaction
transaction
;
// konwencja nazw: utx
protected
void
doGet
(
HttpServletRequest
request
,
HttpServletResponse
response
)
throws
ServletException
,
IOException
{
response
.
setContentType
(
"text/plain"
);
response
.
setCharacterEncoding
(
"utf-8"
);
PrintWriter
out
=
response
.
getWriter
();
if
(
request
.
getParameter
(
"id"
)
==
null
)
{
out
.
println
(
"Trzeba podać id produktu"
);
return
;
}
Integer
id
=
Integer
.
valueOf
(
request
.
getParameter
(
"id"
));
BigDecimal
podwyzka
=
null
;
if
(
request
.
getParameter
(
"podwyzka"
)
!=
null
)
{
podwyzka
=
new
BigDecimal
(
request
.
getParameter
(
"podwyzka"
));
}
try
{
transaction
.
begin
();
Product
product
=
em
.
find
(
Product
.
class
,
id
);
if
(
product
==
null
)
{
out
.
println
(
"Nie znaleziono produktu o numerze "
+
id
);
return
;
}
out
.
println
(
product
.
getProductName
()
+
" "
+
product
.
getPrice
());
if
(
podwyzka
!=
null
)
{
product
.
setPrice
(
product
.
getPrice
().
add
(
podwyzka
));
}
out
.
println
(
"Po zmianie:"
);
out
.
println
(
product
.
getProductName
()
+
" "
+
product
.
getPrice
());
transaction
.
commit
();
// } catch (SecurityException | IllegalStateException | RollbackException | HeuristicMixedException | HeuristicRollbackException | SystemException | NotSupportedException e) {
}
catch
(
Exception
e
)
{
throw
new
ServletException
(
"wielka bieda"
,
e
);
}
}
}
PC29-HibernateNaSerwerze/src/main/webapp/index.html
View file @
e9f323b3
...
@@ -6,8 +6,24 @@
...
@@ -6,8 +6,24 @@
</head>
</head>
<body>
<body>
<h1>
Hibernate na serwerze
</h1>
<h1>
Hibernate na serwerze
</h1>
<h2>
Zapytania SQL
</h2>
<ul>
<ul>
<li><a
href=
"Lista0"
>
lista0
</a>
- wersja bez konfiguracji serwera
</li>
<li><a
href=
"sql1"
>
sql1
</a>
- normalne
<code>
getConnection
</code>
- nie zadziała bez sterownika
</li>
<li><a
href=
"sql2"
>
sql2
</a>
- DataSource za pomocą
<code>
ctx.lookup
</code></li>
<li><a
href=
"sql3"
>
sql3
</a>
- wstrzykiwanie DataSource
</li>
</ul>
<h2>
Zapytania JPA/Hibernate
</h2>
<ul>
<li><a
href=
"lista0"
>
lista0
</a>
- wersja bez konfiguracji serwera, później zmieniona na użycie data source typu resource/local
</li>
<li><a
href=
"lista1"
>
lista1
</a>
- stara wersja odstawowa
</li>
<li><a
href=
"lista2"
>
lista2
</a>
- wersja ze wstrzykiwaniem EntityManagerFactory, działająca dla datasource typu resource/local
</li>
<li><a
href=
"lista3"
>
lista3
</a>
- wersja ze wstrzykiwaniem EntityManager, działająca dla datasource typu JTA (wymaga zmiany konfiguracji)
</li>
</ul>
<h2>
Modyfikacja danych JPA/Hibernate
</h2>
<p>
(podwyżka ceny pralki o 500)
</p>
<ul>
<li><a
href=
"zmiana2?id=1&podwyzka=500"
>
zmiana2
</a>
- wersja dla datasource typu resource/local
</li>
<li><a
href=
"zmiana3?id=1&podwyzka=500"
>
zmiana3
</a>
- wersja dla datasource typu JTA (wymaga zmiany konfiguracji)
</li>
</ul>
</ul>
</body>
</body>
</html>
</html>
\ No newline at end of file
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment