Skip to content
Projects
Groups
Snippets
Help
Loading...
Sign in / Register
Toggle navigation
Y
yn-health-science
Project
Project
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
徐俊
yn-health-science
Commits
d417aa48
Commit
d417aa48
authored
Feb 26, 2025
by
wangxl
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
1
parent
9c5f747e
Expand all
Show whitespace changes
Inline
Side-by-side
Showing
8 changed files
with
88 additions
and
146 deletions
+88
-146
ComProjectController.java
...ava/com/yiboshi/science/rest/v1/ComProjectController.java
+2
-2
ComProjectTaskController.java
...com/yiboshi/science/rest/v1/ComProjectTaskController.java
+18
-27
PDF.java
...ce-admin/src/main/java/com/yiboshi/science/utils/PDF.java
+0
-115
PdfUtil.java
...dmin/src/main/java/com/yiboshi/science/utils/PdfUtil.java
+61
-0
TaskInfoToPDFUtil.java
...ain/java/com/yiboshi/science/utils/TaskInfoToPDFUtil.java
+0
-0
WordUtil.java
...min/src/main/java/com/yiboshi/science/utils/WordUtil.java
+4
-0
application.yml
science-admin/src/main/resources/application.yml
+1
-1
BaseDAO.java
...-base/src/main/java/com/yiboshi/science/base/BaseDAO.java
+2
-1
No files found.
science-admin/src/main/java/com/yiboshi/science/rest/v1/ComProjectController.java
View file @
d417aa48
...
@@ -15,7 +15,7 @@ import com.yiboshi.science.service.ComFileService;
...
@@ -15,7 +15,7 @@ import com.yiboshi.science.service.ComFileService;
import
com.yiboshi.science.service.ComProjectService
;
import
com.yiboshi.science.service.ComProjectService
;
import
com.yiboshi.science.service.ComProjectTaskService
;
import
com.yiboshi.science.service.ComProjectTaskService
;
import
com.yiboshi.science.service.SystemParameterService
;
import
com.yiboshi.science.service.SystemParameterService
;
import
com.yiboshi.science.utils.P
DF
;
import
com.yiboshi.science.utils.P
dfUtil
;
import
com.yiboshi.science.utils.ProjectInfoToPDF
;
import
com.yiboshi.science.utils.ProjectInfoToPDF
;
import
com.yiboshi.science.utils.StringUtil
;
import
com.yiboshi.science.utils.StringUtil
;
import
io.swagger.annotations.Api
;
import
io.swagger.annotations.Api
;
...
@@ -99,7 +99,7 @@ public class ComProjectController extends BaseController<ComProjectService, ComP
...
@@ -99,7 +99,7 @@ public class ComProjectController extends BaseController<ComProjectService, ComP
@PostMapping
@PostMapping
public
ResponseDataModel
<
byte
[]>
export
(
@PathVariable
String
id
)
{
public
ResponseDataModel
<
byte
[]>
export
(
@PathVariable
String
id
)
{
try
{
try
{
return
ResponseDataModel
.
ok
(
P
DF
.
createPDF
(
response
,
"tmp-report.html"
,
new
ComProject
()));
return
ResponseDataModel
.
ok
(
P
dfUtil
.
createPDF
(
response
,
"tmp-report.html"
,
new
ComProject
()));
}
catch
(
Exception
e
)
{
}
catch
(
Exception
e
)
{
return
new
ResponseDataModel
(
ResponseCode
.
SERVER_ERROR
,
""
);
return
new
ResponseDataModel
(
ResponseCode
.
SERVER_ERROR
,
""
);
}
}
...
...
science-admin/src/main/java/com/yiboshi/science/rest/v1/ComProjectTaskController.java
View file @
d417aa48
package
com
.
yiboshi
.
science
.
rest
.
v1
;
package
com
.
yiboshi
.
science
.
rest
.
v1
;
import
com.
yiboshi.arch.base.ResponseCode
;
import
com.
itextpdf.text.DocumentException
;
import
com.yiboshi.arch.base.ResponseDataModel
;
import
com.yiboshi.arch.base.ResponseDataModel
;
import
com.yiboshi.science.base.Pagination
;
import
com.yiboshi.science.base.Pagination
;
import
com.yiboshi.science.config.annotation.Logs
;
import
com.yiboshi.science.config.annotation.Logs
;
import
com.yiboshi.science.config.security.SecurityUserHolder
;
import
com.yiboshi.science.config.security.SecurityUserHolder
;
import
com.yiboshi.science.entity.ComProject
;
import
com.yiboshi.science.entity.ComProjectAudit
;
import
com.yiboshi.science.entity.ComProjectAudit
;
import
com.yiboshi.science.entity.ComProjectTask
;
import
com.yiboshi.science.entity.ComProjectTask
;
import
com.yiboshi.science.entity.SelectListItem
;
import
com.yiboshi.science.entity.SelectListItem
;
import
com.yiboshi.science.enumeration.CommonEnum
;
import
com.yiboshi.science.enumeration.CommonEnum
;
import
com.yiboshi.science.param.dto.ComDownloadDTO
;
import
com.yiboshi.science.param.dto.ComFileDTO
;
import
com.yiboshi.science.param.dto.ComProjectTaskDTO
;
import
com.yiboshi.science.param.dto.ComProjectTaskDTO
;
import
com.yiboshi.science.param.dto.DataStatisticsDTO
;
import
com.yiboshi.science.param.dto.DataStatisticsDTO
;
import
com.yiboshi.science.param.query.ComProjectTaskQueryVO
;
import
com.yiboshi.science.param.query.ComProjectTaskQueryVO
;
import
com.yiboshi.science.rest.BaseController
;
import
com.yiboshi.science.rest.BaseController
;
import
com.yiboshi.science.service.ComProjectTaskService
;
import
com.yiboshi.science.service.ComProjectTaskService
;
import
com.yiboshi.science.service.SystemParameterService
;
import
com.yiboshi.science.utils.PDF
;
import
com.yiboshi.science.utils.PdfUtil
;
import
com.yiboshi.science.utils.StringUtil
;
import
com.yiboshi.science.utils.StringUtil
;
import
com.yiboshi.science.utils.TaskInfoToPDFUtil
;
import
io.swagger.annotations.Api
;
import
io.swagger.annotations.Api
;
import
io.swagger.annotations.ApiOperation
;
import
io.swagger.annotations.ApiOperation
;
import
org.apache.velocity.VelocityContext
;
import
org.springframework.beans.factory.annotation.Autowired
;
import
org.springframework.beans.factory.annotation.Autowired
;
import
org.springframework.validation.BindingResult
;
import
org.springframework.validation.BindingResult
;
import
org.springframework.validation.annotation.Validated
;
import
org.springframework.validation.annotation.Validated
;
import
org.springframework.web.bind.annotation.*
;
import
org.springframework.web.bind.annotation.*
;
import
org.springframework.web.multipart.MultipartFile
;
import
javax.servlet.ServletOutputStream
;
import
javax.servlet.ServletOutputStream
;
import
java
x.validation.constraints.NotBlank
;
import
java
.io.IOException
;
import
java.util.ArrayList
;
import
java.util.ArrayList
;
import
java.util.Calendar
;
import
java.util.List
;
import
java.util.List
;
/**
/**
...
@@ -152,25 +144,24 @@ public class ComProjectTaskController extends BaseController<ComProjectTaskServi
...
@@ -152,25 +144,24 @@ public class ComProjectTaskController extends BaseController<ComProjectTaskServi
@ApiOperation
(
value
=
"项目导出"
,
httpMethod
=
"POST"
,
notes
=
"项目导出"
)
@ApiOperation
(
value
=
"项目导出"
,
httpMethod
=
"POST"
,
notes
=
"项目导出"
)
@RequestMapping
(
"/export/{id}"
)
@RequestMapping
(
"/export/{id}"
)
@PostMapping
@PostMapping
public
ResponseDataModel
<
byte
[]>
export
(
@PathVariable
String
id
)
{
public
void
export
(
@PathVariable
String
id
)
throws
DocumentException
,
IOException
{
try
{
try
{
try
(
ServletOutputStream
outputStream
=
response
.
getOutputStream
())
{
ComProjectTaskDTO
dto
=
ComProjectTaskService
.
getTaskByProjId
(
id
);
VelocityContext
context
=
new
VelocityContext
();
// 生成PDF文件字节数组
Calendar
calendar
=
Calendar
.
getInstance
(
);
byte
[]
pdfBytes
=
TaskInfoToPDFUtil
.
createContractPdf
(
ComProjectTaskService
.
getTaskByProjId
(
id
)
);
int
month
=
calendar
.
get
(
Calendar
.
MONTH
)
+
1
;
// 设置响应头
int
day
=
calendar
.
get
(
Calendar
.
DATE
);
response
.
setContentType
(
"application/pdf"
);
context
.
put
(
"reportYear"
,
2024
);
String
fileName
=
new
String
((
dto
.
getProjName
()
+
".pdf"
).
getBytes
(
"UTF-8"
),
"ISO-8859-1"
);
context
.
put
(
"year"
,
calendar
.
get
(
Calendar
.
YEAR
)
);
response
.
setHeader
(
"Content-Disposition"
,
"attachment; filename="
+
fileName
);
context
.
put
(
"month"
,
month
>=
10
?
month
:
"0"
+
mon
th
);
response
.
setContentLength
(
pdfBytes
.
leng
th
);
context
.
put
(
"day"
,
day
>=
10
?
day
:
"0"
+
day
);
// 写入响应流
PdfUtil
.
pdfFile
(
context
,
"/template/demo.html"
,
outputStream
);
try
(
ServletOutputStream
out
=
response
.
getOutputStream
())
{
}
catch
(
Exception
e
)
{
out
.
write
(
pdfBytes
);
e
.
printStackTrace
();
out
.
flush
();
}
}
return
ResponseDataModel
.
ok
(
null
);
// return ResponseDataModel.ok(PDF.createPDF(response, "tmp-task.html", ComProjectTaskService.getTaskByProjId(id)));
}
catch
(
Exception
e
)
{
}
catch
(
Exception
e
)
{
return
new
ResponseDataModel
(
ResponseCode
.
SERVER_ERROR
,
""
);
response
.
setContentType
(
"text/plain;charset=UTF-8"
);
response
.
getWriter
().
write
(
"导出PDF失败:"
+
e
.
getMessage
());
}
}
}
}
...
...
science-admin/src/main/java/com/yiboshi/science/utils/PDF.java
deleted
100644 → 0
View file @
9c5f747e
package
com
.
yiboshi
.
science
.
utils
;
import
com.itextpdf.text.pdf.BaseFont
;
import
com.lowagie.text.DocumentException
;
import
freemarker.cache.ClassTemplateLoader
;
import
freemarker.template.Configuration
;
import
freemarker.template.Template
;
import
freemarker.template.TemplateException
;
import
freemarker.template.TemplateExceptionHandler
;
import
org.xhtmlrenderer.pdf.ITextRenderer
;
import
javax.servlet.http.HttpServletResponse
;
import
java.io.*
;
import
java.util.Map
;
import
static
java
.
lang
.
System
.
in
;
public
class
PDF
{
/**
* 将HTML模板转换为PDF输出流
* @return PDF字节数组
*/
public
static
byte
[]
createPDF
(
HttpServletResponse
response
,
String
temp
,
Object
dataModel
)
throws
IOException
,
TemplateException
,
DocumentException
{
Map
<
String
,
Object
>
dataMap
=
HtmlBuilder
.
obj2Map
(
dataModel
);
// 配置FreeMarker
Configuration
cfg
=
new
Configuration
(
Configuration
.
DEFAULT_INCOMPATIBLE_IMPROVEMENTS
);
cfg
.
setDefaultEncoding
(
"utf-8"
);
cfg
.
setClassLoaderForTemplateLoading
(
PDF
.
class
.
getClassLoader
(),
"template"
);
cfg
.
setTemplateLoader
(
new
ClassTemplateLoader
(
PDF
.
class
.
getClassLoader
(),
"/template"
));
cfg
.
setTemplateExceptionHandler
(
TemplateExceptionHandler
.
RETHROW_HANDLER
);
// 获取模板
Template
template
=
cfg
.
getTemplate
(
temp
,
"utf-8"
);
// 处理模板,生成HTML内容
StringWriter
tmpText
=
new
StringWriter
();
template
.
process
(
dataMap
,
tmpText
);
String
htmlContent
=
tmpText
.
toString
();
// 创建PDF渲染器
ITextRenderer
renderer
=
new
ITextRenderer
();
// Java代码示例
// renderer.getSharedContext().setDPI(1); // 提高DPI减少锯齿
// 设置中文字体
String
simPath
=
ResourceFileUtil
.
getAbsolutePath
(
"/fonts/simsun.ttc"
);
String
msyhPath
=
ResourceFileUtil
.
getAbsolutePath
(
"/fonts/msyh.ttc"
);
renderer
.
getFontResolver
().
addFont
(
simPath
,
BaseFont
.
IDENTITY_H
,
BaseFont
.
EMBEDDED
);
renderer
.
getFontResolver
().
addFont
(
msyhPath
,
BaseFont
.
IDENTITY_H
,
BaseFont
.
EMBEDDED
);
// 渲染HTML内容
renderer
.
setDocumentFromString
(
htmlContent
);
renderer
.
layout
();
// 创建一个ByteArrayOutputStream来保存生成的PDF
response
.
setContentType
(
"application/octet-stream;charset=UTF-8"
);
OutputStream
outputStream
=
response
.
getOutputStream
();
// 输出PDF到字节数组
renderer
.
createPDF
(
outputStream
);
//创建存放文件内容的数组
byte
[]
buff
=
new
byte
[
1024
];
//所读取的内容使用n来接收
int
n
;
//当没有读取完时,继续读取,循环
while
((
n
=
in
.
read
(
buff
))
!=
-
1
)
{
//将字节数组的数据全部写入到输出流中
outputStream
.
write
(
buff
,
0
,
n
);
}
//强制将缓存区的数据进行输出
outputStream
.
flush
();
//关流
outputStream
.
close
();
in
.
close
();
// 关闭输出流
return
buff
;
}
public
static
boolean
createPDF
(
String
temp
,
Object
dataModel
,
String
outputPath
)
throws
IOException
,
TemplateException
,
DocumentException
{
Map
<
String
,
Object
>
dataMap
=
HtmlBuilder
.
obj2Map
(
dataModel
);
// 配置FreeMarker
Configuration
cfg
=
new
Configuration
(
Configuration
.
DEFAULT_INCOMPATIBLE_IMPROVEMENTS
);
cfg
.
setDefaultEncoding
(
"utf-8"
);
cfg
.
setClassLoaderForTemplateLoading
(
PDF
.
class
.
getClassLoader
(),
"template"
);
cfg
.
setTemplateLoader
(
new
ClassTemplateLoader
(
PDF
.
class
.
getClassLoader
(),
"/template"
));
cfg
.
setTemplateExceptionHandler
(
TemplateExceptionHandler
.
RETHROW_HANDLER
);
// 获取模板
Template
template
=
cfg
.
getTemplate
(
temp
,
"utf-8"
);
// 处理模板,生成HTML内容
StringWriter
tmpText
=
new
StringWriter
();
template
.
process
(
dataMap
,
tmpText
);
String
htmlContent
=
tmpText
.
toString
();
// 创建PDF渲染器
ITextRenderer
renderer
=
new
ITextRenderer
();
// 设置中文字体
String
simPath
=
ResourceFileUtil
.
getAbsolutePath
(
"/fonts/simsun.ttc"
);
String
msyhPath
=
ResourceFileUtil
.
getAbsolutePath
(
"/fonts/msyh.ttc"
);
renderer
.
getFontResolver
().
addFont
(
simPath
,
BaseFont
.
IDENTITY_H
,
BaseFont
.
EMBEDDED
);
renderer
.
getFontResolver
().
addFont
(
msyhPath
,
BaseFont
.
IDENTITY_H
,
BaseFont
.
EMBEDDED
);
// 渲染HTML内容
renderer
.
setDocumentFromString
(
htmlContent
);
renderer
.
layout
();
// 创建输出文件
File
outputFile
=
new
File
(
outputPath
);
// 确保父目录存在
outputFile
.
getParentFile
().
mkdirs
();
// 创建文件输出流
try
(
OutputStream
outputStream
=
new
FileOutputStream
(
outputFile
))
{
// 输出PDF到文件
renderer
.
createPDF
(
outputStream
);
outputStream
.
flush
();
return
true
;
}
catch
(
Exception
e
)
{
e
.
printStackTrace
();
return
false
;
}
}
}
science-admin/src/main/java/com/yiboshi/science/utils/PdfUtil.java
View file @
d417aa48
...
@@ -8,15 +8,27 @@ import com.itextpdf.kernel.geom.PageSize;
...
@@ -8,15 +8,27 @@ import com.itextpdf.kernel.geom.PageSize;
import
com.itextpdf.kernel.pdf.PdfDocument
;
import
com.itextpdf.kernel.pdf.PdfDocument
;
import
com.itextpdf.kernel.pdf.PdfWriter
;
import
com.itextpdf.kernel.pdf.PdfWriter
;
import
com.itextpdf.layout.font.FontProvider
;
import
com.itextpdf.layout.font.FontProvider
;
import
com.itextpdf.text.pdf.BaseFont
;
import
com.lowagie.text.DocumentException
;
import
freemarker.cache.ClassTemplateLoader
;
import
freemarker.template.Configuration
;
import
freemarker.template.TemplateException
;
import
freemarker.template.TemplateExceptionHandler
;
import
org.apache.velocity.Template
;
import
org.apache.velocity.Template
;
import
org.apache.velocity.app.Velocity
;
import
org.apache.velocity.app.Velocity
;
import
org.apache.velocity.context.Context
;
import
org.apache.velocity.context.Context
;
import
org.apache.velocity.runtime.RuntimeConstants
;
import
org.apache.velocity.runtime.RuntimeConstants
;
import
org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader
;
import
org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader
;
import
org.xhtmlrenderer.pdf.ITextRenderer
;
import
javax.servlet.http.HttpServletResponse
;
import
java.io.IOException
;
import
java.io.OutputStream
;
import
java.io.OutputStream
;
import
java.io.StringWriter
;
import
java.io.StringWriter
;
import
java.nio.charset.StandardCharsets
;
import
java.nio.charset.StandardCharsets
;
import
java.util.Map
;
import
static
java
.
lang
.
System
.
in
;
/**
/**
* PDF工具
* PDF工具
...
@@ -67,4 +79,53 @@ public class PdfUtil {
...
@@ -67,4 +79,53 @@ public class PdfUtil {
}
}
}
}
public
static
byte
[]
createPDF
(
HttpServletResponse
response
,
String
temp
,
Object
dataModel
)
throws
IOException
,
TemplateException
,
DocumentException
{
Map
<
String
,
Object
>
dataMap
=
HtmlBuilder
.
obj2Map
(
dataModel
);
// 配置FreeMarker
Configuration
cfg
=
new
Configuration
(
Configuration
.
DEFAULT_INCOMPATIBLE_IMPROVEMENTS
);
cfg
.
setDefaultEncoding
(
"utf-8"
);
cfg
.
setClassLoaderForTemplateLoading
(
PdfUtil
.
class
.
getClassLoader
(),
"template"
);
cfg
.
setTemplateLoader
(
new
ClassTemplateLoader
(
PdfUtil
.
class
.
getClassLoader
(),
"/template"
));
cfg
.
setTemplateExceptionHandler
(
TemplateExceptionHandler
.
RETHROW_HANDLER
);
// 获取模板
freemarker
.
template
.
Template
template
=
cfg
.
getTemplate
(
temp
,
"utf-8"
);
// 处理模板,生成HTML内容
StringWriter
tmpText
=
new
StringWriter
();
template
.
process
(
dataMap
,
tmpText
);
String
htmlContent
=
tmpText
.
toString
();
// 创建PDF渲染器
ITextRenderer
renderer
=
new
ITextRenderer
();
// Java代码示例
// renderer.getSharedContext().setDPI(1); // 提高DPI减少锯齿
// 设置中文字体
String
simPath
=
ResourceFileUtil
.
getAbsolutePath
(
"/fonts/simsun.ttc"
);
String
msyhPath
=
ResourceFileUtil
.
getAbsolutePath
(
"/fonts/msyh.ttc"
);
renderer
.
getFontResolver
().
addFont
(
simPath
,
BaseFont
.
IDENTITY_H
,
BaseFont
.
EMBEDDED
);
renderer
.
getFontResolver
().
addFont
(
msyhPath
,
BaseFont
.
IDENTITY_H
,
BaseFont
.
EMBEDDED
);
// 渲染HTML内容
renderer
.
setDocumentFromString
(
htmlContent
);
renderer
.
layout
();
// 创建一个ByteArrayOutputStream来保存生成的PDF
response
.
setContentType
(
"application/octet-stream;charset=UTF-8"
);
OutputStream
outputStream
=
response
.
getOutputStream
();
// 输出PDF到字节数组
renderer
.
createPDF
(
outputStream
);
//创建存放文件内容的数组
byte
[]
buff
=
new
byte
[
1024
];
//所读取的内容使用n来接收
int
n
;
//当没有读取完时,继续读取,循环
while
((
n
=
in
.
read
(
buff
))
!=
-
1
)
{
//将字节数组的数据全部写入到输出流中
outputStream
.
write
(
buff
,
0
,
n
);
}
//强制将缓存区的数据进行输出
outputStream
.
flush
();
//关流
outputStream
.
close
();
in
.
close
();
// 关闭输出流
return
buff
;
}
}
}
science-admin/src/main/java/com/yiboshi/science/utils/TaskInfoToPDFUtil.java
0 → 100644
View file @
d417aa48
This diff is collapsed.
Click to expand it.
science-admin/src/main/java/com/yiboshi/science/utils/WordUtil.java
0 → 100644
View file @
d417aa48
package
com
.
yiboshi
.
science
.
utils
;
public
class
WordUtil
{
}
science-admin/src/main/resources/application.yml
View file @
d417aa48
...
@@ -8,7 +8,7 @@ spring:
...
@@ -8,7 +8,7 @@ spring:
application
:
application
:
name
:
science-admin
name
:
science-admin
profiles
:
profiles
:
active
:
'
prod
'
active
:
'
local
'
http
:
http
:
encoding
:
encoding
:
force
:
true
force
:
true
...
...
science-base/src/main/java/com/yiboshi/science/base/BaseDAO.java
View file @
d417aa48
...
@@ -2,6 +2,7 @@
...
@@ -2,6 +2,7 @@
package
com
.
yiboshi
.
science
.
base
;
package
com
.
yiboshi
.
science
.
base
;
import
com.baomidou.mybatisplus.core.conditions.Wrapper
;
import
com.baomidou.mybatisplus.core.conditions.Wrapper
;
import
com.baomidou.mybatisplus.core.mapper.BaseMapper
;
import
com.baomidou.mybatisplus.extension.plugins.pagination.Page
;
import
com.baomidou.mybatisplus.extension.plugins.pagination.Page
;
import
org.apache.ibatis.annotations.Param
;
import
org.apache.ibatis.annotations.Param
;
...
@@ -13,6 +14,6 @@ import org.apache.ibatis.annotations.Param;
...
@@ -13,6 +14,6 @@ import org.apache.ibatis.annotations.Param;
* @version 2018-08
* @version 2018-08
*/
*/
@SuppressWarnings
(
"all"
)
@SuppressWarnings
(
"all"
)
public
interface
BaseDAO
<
V
extends
PaginationVO
,
D
extends
BaseDTO
,
E
>{
public
interface
BaseDAO
<
V
extends
PaginationVO
,
D
extends
BaseDTO
,
E
>
extends
BaseMapper
<
E
>
{
Page
<
D
>
getListByPage
(
Page
<
V
>
page
,
@Param
(
"ew"
)
Wrapper
<
V
>
queryWrapper
);
Page
<
D
>
getListByPage
(
Page
<
V
>
page
,
@Param
(
"ew"
)
Wrapper
<
V
>
queryWrapper
);
}
}
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