Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Sign in / Register
Toggle navigation
M
magicseteditor
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Locked Files
Issues
0
Issues
0
List
Boards
Labels
Service Desk
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Security & Compliance
Security & Compliance
Dependency List
License Compliance
Packages
Packages
Container Registry
Analytics
Analytics
CI / CD
Code Review
Insights
Issues
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
MyCard
magicseteditor
Commits
9e495e6e
Commit
9e495e6e
authored
Aug 24, 2008
by
twanvl
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Added Package::saveCopy, which is used to implement the write_set_file script function.
parent
04ad01be
Changes
12
Hide whitespace changes
Inline
Side-by-side
Showing
12 changed files
with
119 additions
and
32 deletions
+119
-32
data/magic-spoiler.mse-export-template/export-template
data/magic-spoiler.mse-export-template/export-template
+8
-0
doc/function/index.txt
doc/function/index.txt
+1
-0
doc/function/write_image_file.txt
doc/function/write_image_file.txt
+1
-1
doc/function/write_set_file.txt
doc/function/write_set_file.txt
+23
-0
doc/function/write_text_file.txt
doc/function/write_text_file.txt
+1
-1
src/data/format/formats.cpp
src/data/format/formats.cpp
+3
-3
src/data/format/formats.hpp
src/data/format/formats.hpp
+4
-3
src/data/format/mse2.cpp
src/data/format/mse2.cpp
+8
-4
src/script/functions/export.cpp
src/script/functions/export.cpp
+13
-1
src/util/io/package.cpp
src/util/io/package.cpp
+47
-17
src/util/io/package.hpp
src/util/io/package.hpp
+9
-2
tools/website/drupal/mse-drupal-modules/highlight.inc
tools/website/drupal/mse-drupal-modules/highlight.inc
+1
-0
No files found.
data/magic-spoiler.mse-export-template/export-template
View file @
9e495e6e
...
@@ -11,6 +11,11 @@ depends on: magic.mse-game 2008-05-18
...
@@ -11,6 +11,11 @@ depends on: magic.mse-game 2008-05-18
########################################################################################
########################################################################################
option field:
type: boolean
name: include set file
description: Should a link to the MSE set file be included in the spoiler?
initial: no
option field:
option field:
type: choice
type: choice
name: grouping
name: grouping
...
@@ -203,6 +208,9 @@ script:
...
@@ -203,6 +208,9 @@ script:
<h1>
{ to_html(set.title) }
</h1>
<h1>
{ to_html(set.title) }
</h1>
<div
class=
'copyright'
>
{ to_html(set.copyright) }
</div>
<div
class=
'copyright'
>
{ to_html(set.copyright) }
</div>
<div
class=
'description'
>
{ to_html(set.description) }
</div>
<div
class=
'description'
>
{ to_html(set.description) }
</div>
{ if options.include_set_file then
"
<div
class=
'set-file'
><a
href=
'{ write_set_file(file:"set.mse-set") }'
>
Download set in MSE format
</a></div>
"
}
{ if options.grouping == "group by color" then
{ if options.grouping == "group by color" then
# Codes as by sort_index
# Codes as by sort_index
write_group(title: "White", code:"A") +
write_group(title: "White", code:"A") +
...
...
doc/function/index.txt
View file @
9e495e6e
...
@@ -96,6 +96,7 @@ These functions are built into the program, other [[type:function]]s can be defi
...
@@ -96,6 +96,7 @@ These functions are built into the program, other [[type:function]]s can be defi
| [[fun:copy_file]] Copy a file from the [[type:export template]] to the output directory.
| [[fun:copy_file]] Copy a file from the [[type:export template]] to the output directory.
| [[fun:write_text_file]] Write a text file to the output directory.
| [[fun:write_text_file]] Write a text file to the output directory.
| [[fun:write_image_file]] Write an image file to the output directory.
| [[fun:write_image_file]] Write an image file to the output directory.
| [[fun:write_set_file]] Write a MSE set file to the output directory.
! Other functions <<<
! Other functions <<<
| [[fun:trace]] Output a message for debugging purposes.
| [[fun:trace]] Output a message for debugging purposes.
...
...
doc/function/write_image_file.txt
View file @
9e495e6e
...
@@ -18,7 +18,7 @@ This function can only be used in an [[type:export template]], when <tt>create d
...
@@ -18,7 +18,7 @@ This function can only be used in an [[type:export template]], when <tt>create d
| @height@ [[type:int]] Height in pixels to use for the image, by default the size of the image is used if available.
| @height@ [[type:int]] Height in pixels to use for the image, by default the size of the image is used if available.
--Examples--
--Examples--
> write_image
(
"image_out.png", linear_blend(...)) == "image_out.png" # image_out.png now contains the given image
> write_image
_file(file:
"image_out.png", linear_blend(...)) == "image_out.png" # image_out.png now contains the given image
--See also--
--See also--
| [[fun:write_text_file]] Write a text file to the output directory.
| [[fun:write_text_file]] Write a text file to the output directory.
doc/function/write_set_file.txt
0 → 100644
View file @
9e495e6e
Function: write_set_file
--Usage--
> write_set_file(set:the_set, file: filename)
Write the current set to a file in the output directory.
If a file with the given name already exists it is overwritten.
Returns the name of the file written.
This function can only be used in an [[type:export template]], when <tt>create directory</tt> is true.
--Parameters--
! Parameter Type Description
| @set@ [[type:set]] Set to write to the file.
| @file@ [[type:string]] Name of the file to write to
--Examples--
> write_set_file(file:"the-set.mse-set") == "the-set.mse-set" # the-set.mse-set now contains the set
--See also--
| [[fun:write_image_file]] Write an image file to the output directory.
| [[fun:write_text_file]] Write a text file to the output directory.
doc/function/write_text_file.txt
View file @
9e495e6e
...
@@ -16,7 +16,7 @@ This function can only be used in an [[type:export template]], when <tt>create d
...
@@ -16,7 +16,7 @@ This function can only be used in an [[type:export template]], when <tt>create d
| @file@ [[type:string]] Name of the file to write to
| @file@ [[type:string]] Name of the file to write to
--Examples--
--Examples--
> write_
file(
"index.html", lots_of_html_code) == "index.html" # index.html now contains the given text
> write_
text_file(file:
"index.html", lots_of_html_code) == "index.html" # index.html now contains the given text
--See also--
--See also--
| [[fun:write_image_file]] Write an image file to the output directory.
| [[fun:write_image_file]] Write an image file to the output directory.
src/data/format/formats.cpp
View file @
9e495e6e
...
@@ -48,12 +48,12 @@ String export_formats(const Game& game) {
...
@@ -48,12 +48,12 @@ String export_formats(const Game& game) {
return
type_strings
;
return
type_strings
;
}
}
void
export_set
(
Set
&
set
,
const
String
&
filename
,
size_t
format_
type
)
{
void
export_set
(
Set
&
set
,
const
String
&
filename
,
size_t
format_
index
,
bool
is_copy
)
{
FileFormatP
format
=
file_formats
.
at
(
format_
type
);
FileFormatP
format
=
file_formats
.
at
(
format_
index
);
if
(
!
format
->
canExport
(
*
set
.
game
))
{
if
(
!
format
->
canExport
(
*
set
.
game
))
{
throw
InternalError
(
_
(
"File format doesn't apply to set"
));
throw
InternalError
(
_
(
"File format doesn't apply to set"
));
}
}
format
->
exportSet
(
set
,
filename
);
format
->
exportSet
(
set
,
filename
,
is_copy
);
}
}
SetP
import_set
(
String
name
)
{
SetP
import_set
(
String
name
)
{
...
...
src/data/format/formats.hpp
View file @
9e495e6e
...
@@ -37,7 +37,8 @@ class FileFormat : public IntrusivePtrVirtualBase {
...
@@ -37,7 +37,8 @@ class FileFormat : public IntrusivePtrVirtualBase {
throw
InternalError
(
_
(
"Import not supported by this file format"
));
throw
InternalError
(
_
(
"Import not supported by this file format"
));
}
}
/// Export using this filter
/// Export using this filter
virtual
void
exportSet
(
Set
&
set
,
const
String
&
filename
)
{
/** If is_copy, then the set should not be modified */
virtual
void
exportSet
(
Set
&
set
,
const
String
&
filename
,
bool
is_copy
=
false
)
{
throw
InternalError
(
_
(
"Export not supported by this file format"
));
throw
InternalError
(
_
(
"Export not supported by this file format"
));
}
}
};
};
...
@@ -71,9 +72,9 @@ String export_formats(const Game& game);
...
@@ -71,9 +72,9 @@ String export_formats(const Game& game);
SetP
import_set
(
String
name
);
SetP
import_set
(
String
name
);
/// Save a set under the specified name.
/// Save a set under the specified name.
/** f
ilterType
specifies what format to use for saving, used as index in the list of file formats
/** f
ormat_index
specifies what format to use for saving, used as index in the list of file formats
*/
*/
void
export_set
(
Set
&
set
,
const
String
&
filename
,
size_t
format_
typ
e
);
void
export_set
(
Set
&
set
,
const
String
&
filename
,
size_t
format_
index
,
bool
is_copy
=
fals
e
);
// ----------------------------------------------------------------------------- : The formats
// ----------------------------------------------------------------------------- : The formats
...
...
src/data/format/mse2.cpp
View file @
9e495e6e
...
@@ -26,10 +26,14 @@ class MSE2FileFormat : public FileFormat {
...
@@ -26,10 +26,14 @@ class MSE2FileFormat : public FileFormat {
settings
.
addRecentFile
(
filename
);
settings
.
addRecentFile
(
filename
);
return
set
;
return
set
;
}
}
virtual
void
exportSet
(
Set
&
set
,
const
String
&
filename
)
{
virtual
void
exportSet
(
Set
&
set
,
const
String
&
filename
,
bool
is_copy
)
{
set
.
saveAs
(
filename
);
if
(
is_copy
)
{
settings
.
addRecentFile
(
filename
);
set
.
saveCopy
(
filename
);
set
.
actions
.
setSavePoint
();
}
else
{
set
.
saveAs
(
filename
);
settings
.
addRecentFile
(
filename
);
set
.
actions
.
setSavePoint
();
}
}
}
};
};
...
...
src/script/functions/export.cpp
View file @
9e495e6e
...
@@ -431,6 +431,18 @@ SCRIPT_FUNCTION(write_image_file) {
...
@@ -431,6 +431,18 @@ SCRIPT_FUNCTION(write_image_file) {
SCRIPT_RETURN
(
file
);
SCRIPT_RETURN
(
file
);
}
}
SCRIPT_FUNCTION
(
write_set_file
)
{
guard_export_info
(
_
(
"write_set_file"
));
// output path
SCRIPT_PARAM
(
String
,
file
);
// file to write to
String
out_path
=
get_export_full_path
(
file
);
// export
SCRIPT_PARAM_C
(
Set
*
,
set
);
set
->
saveCopy
(
out_path
);
// TODO: use export_set instead?
SCRIPT_RETURN
(
file
);
}
// ----------------------------------------------------------------------------- : Init
// ----------------------------------------------------------------------------- : Init
void
init_script_export_functions
(
Context
&
ctx
)
{
void
init_script_export_functions
(
Context
&
ctx
)
{
...
@@ -440,5 +452,5 @@ void init_script_export_functions(Context& ctx) {
...
@@ -440,5 +452,5 @@ void init_script_export_functions(Context& ctx) {
ctx
.
setVariable
(
_
(
"copy file"
),
script_copy_file
);
ctx
.
setVariable
(
_
(
"copy file"
),
script_copy_file
);
ctx
.
setVariable
(
_
(
"write text file"
),
script_write_text_file
);
ctx
.
setVariable
(
_
(
"write text file"
),
script_write_text_file
);
ctx
.
setVariable
(
_
(
"write image file"
),
script_write_image_file
);
ctx
.
setVariable
(
_
(
"write image file"
),
script_write_image_file
);
//ctx.setVariable(_("write set file"), script_write_set_file);//TODO
ctx
.
setVariable
(
_
(
"write set file"
),
script_write_set_file
);
}
}
src/util/io/package.cpp
View file @
9e495e6e
...
@@ -86,6 +86,18 @@ void Package::open(const String& n) {
...
@@ -86,6 +86,18 @@ void Package::open(const String& n) {
}
}
}
}
void
Package
::
reopen
()
{
if
(
wxDirExists
(
filename
))
{
// make sure we have no zip open
delete
zipStream
;
zipStream
=
nullptr
;
delete
fileStream
;
fileStream
=
nullptr
;
}
else
{
// reopen only needed for zipfile
openZipfile
();
}
}
void
Package
::
save
(
bool
remove_unused
)
{
void
Package
::
save
(
bool
remove_unused
)
{
assert
(
!
needSaveAs
());
assert
(
!
needSaveAs
());
saveAs
(
filename
,
remove_unused
);
saveAs
(
filename
,
remove_unused
);
...
@@ -94,11 +106,21 @@ void Package::save(bool remove_unused) {
...
@@ -94,11 +106,21 @@ void Package::save(bool remove_unused) {
void
Package
::
saveAs
(
const
String
&
name
,
bool
remove_unused
)
{
void
Package
::
saveAs
(
const
String
&
name
,
bool
remove_unused
)
{
// type of package
// type of package
if
(
wxDirExists
(
name
))
{
if
(
wxDirExists
(
name
))
{
saveToDirectory
(
name
,
remove_unused
);
saveToDirectory
(
name
,
remove_unused
,
false
);
}
else
{
}
else
{
saveToZipfile
(
name
,
remove_unused
);
saveToZipfile
(
name
,
remove_unused
,
false
);
}
}
filename
=
name
;
filename
=
name
;
removeTempFiles
(
remove_unused
);
reopen
();
}
void
Package
::
saveCopy
(
const
String
&
name
)
{
saveToZipfile
(
name
,
true
,
true
);
clearKeepFlag
();
}
void
Package
::
removeTempFiles
(
bool
remove_unused
)
{
// cleanup : remove temp files, remove deleted files from the list
// cleanup : remove temp files, remove deleted files from the list
FileInfos
::
iterator
it
=
files
.
begin
();
FileInfos
::
iterator
it
=
files
.
begin
();
while
(
it
!=
files
.
end
())
{
while
(
it
!=
files
.
end
())
{
...
@@ -108,9 +130,9 @@ void Package::saveAs(const String& name, bool remove_unused) {
...
@@ -108,9 +130,9 @@ void Package::saveAs(const String& name, bool remove_unused) {
}
}
if
(
!
it
->
second
.
keep
&&
remove_unused
)
{
if
(
!
it
->
second
.
keep
&&
remove_unused
)
{
// also remove the record of deleted files
// also remove the record of deleted files
FileInfos
::
iterator
to
R
emove
=
it
;
FileInfos
::
iterator
to
_r
emove
=
it
;
++
it
;
++
it
;
files
.
erase
(
to
R
emove
);
files
.
erase
(
to
_r
emove
);
}
else
{
}
else
{
// free zip entry, we will reopen the file
// free zip entry, we will reopen the file
it
->
second
.
keep
=
false
;
it
->
second
.
keep
=
false
;
...
@@ -120,13 +142,11 @@ void Package::saveAs(const String& name, bool remove_unused) {
...
@@ -120,13 +142,11 @@ void Package::saveAs(const String& name, bool remove_unused) {
++
it
;
++
it
;
}
}
}
}
// reopen only needed for zipfile
}
if
(
!
wxDirExists
(
name
))
{
openZipfile
();
void
Package
::
clearKeepFlag
()
{
}
else
{
FOR_EACH
(
f
,
files
)
{
// make sure we have no zip open
f
.
second
.
keep
=
false
;
delete
zipStream
;
zipStream
=
nullptr
;
delete
fileStream
;
fileStream
=
nullptr
;
}
}
}
}
...
@@ -356,7 +376,7 @@ void Package::openZipfile() {
...
@@ -356,7 +376,7 @@ void Package::openZipfile() {
loadZipStream
();
loadZipStream
();
}
}
void
Package
::
saveToDirectory
(
const
String
&
saveAs
,
bool
remove_unused
)
{
void
Package
::
saveToDirectory
(
const
String
&
saveAs
,
bool
remove_unused
,
bool
is_copy
)
{
// write to a directory
// write to a directory
FOR_EACH
(
f
,
files
)
{
FOR_EACH
(
f
,
files
)
{
if
(
!
f
.
second
.
keep
&&
remove_unused
)
{
if
(
!
f
.
second
.
keep
&&
remove_unused
)
{
...
@@ -366,7 +386,8 @@ void Package::saveToDirectory(const String& saveAs, bool remove_unused) {
...
@@ -366,7 +386,8 @@ void Package::saveToDirectory(const String& saveAs, bool remove_unused) {
}
else
if
(
f
.
second
.
wasWritten
())
{
}
else
if
(
f
.
second
.
wasWritten
())
{
// move files that were updated
// move files that were updated
wxRemoveFile
(
saveAs
+
_
(
"/"
)
+
f
.
first
);
wxRemoveFile
(
saveAs
+
_
(
"/"
)
+
f
.
first
);
if
(
!
wxRenameFile
(
f
.
second
.
tempName
,
saveAs
+
_
(
"/"
)
+
f
.
first
))
{
if
(
!
(
is_copy
?
wxCopyFile
(
f
.
second
.
tempName
,
saveAs
+
_
(
"/"
)
+
f
.
first
)
:
wxRenameFile
(
f
.
second
.
tempName
,
saveAs
+
_
(
"/"
)
+
f
.
first
)))
{
throw
PackageError
(
_ERROR_
(
"unable to store file"
));
throw
PackageError
(
_ERROR_
(
"unable to store file"
));
}
}
}
else
if
(
filename
!=
saveAs
)
{
}
else
if
(
filename
!=
saveAs
)
{
...
@@ -380,7 +401,7 @@ void Package::saveToDirectory(const String& saveAs, bool remove_unused) {
...
@@ -380,7 +401,7 @@ void Package::saveToDirectory(const String& saveAs, bool remove_unused) {
}
}
}
}
void
Package
::
saveToZipfile
(
const
String
&
saveAs
,
bool
remove_unused
)
{
void
Package
::
saveToZipfile
(
const
String
&
saveAs
,
bool
remove_unused
,
bool
is_copy
)
{
// create a temporary zip file name
// create a temporary zip file name
String
tempFile
=
saveAs
+
_
(
".tmp"
);
String
tempFile
=
saveAs
+
_
(
".tmp"
);
wxRemoveFile
(
tempFile
);
wxRemoveFile
(
tempFile
);
...
@@ -395,8 +416,9 @@ void Package::saveToZipfile(const String& saveAs, bool remove_unused) {
...
@@ -395,8 +416,9 @@ void Package::saveToZipfile(const String& saveAs, bool remove_unused) {
FOR_EACH
(
f
,
files
)
{
FOR_EACH
(
f
,
files
)
{
if
(
!
f
.
second
.
keep
&&
remove_unused
)
{
if
(
!
f
.
second
.
keep
&&
remove_unused
)
{
// to remove a file simply don't copy it
// to remove a file simply don't copy it
}
else
if
(
f
.
second
.
zipEntry
&&
!
f
.
second
.
wasWritten
())
{
}
else
if
(
!
is_copy
&&
f
.
second
.
zipEntry
&&
!
f
.
second
.
wasWritten
())
{
// old file, was also in zip, not changed
// old file, was also in zip, not changed
// can't do this when saving a copy, since it destroys the zip entry
zipStream
->
CloseEntry
();
zipStream
->
CloseEntry
();
newZip
->
CopyEntry
(
f
.
second
.
zipEntry
,
*
zipStream
);
newZip
->
CopyEntry
(
f
.
second
.
zipEntry
,
*
zipStream
);
f
.
second
.
zipEntry
=
0
;
f
.
second
.
zipEntry
=
0
;
...
@@ -408,8 +430,10 @@ void Package::saveToZipfile(const String& saveAs, bool remove_unused) {
...
@@ -408,8 +430,10 @@ void Package::saveToZipfile(const String& saveAs, bool remove_unused) {
}
}
}
}
// close the old file
// close the old file
delete
zipStream
;
zipStream
=
nullptr
;
if
(
!
is_copy
)
{
delete
fileStream
;
fileStream
=
nullptr
;
delete
zipStream
;
zipStream
=
nullptr
;
delete
fileStream
;
fileStream
=
nullptr
;
}
}
catch
(
Error
e
)
{
}
catch
(
Error
e
)
{
// when things go wrong delete the temp file
// when things go wrong delete the temp file
wxRemoveFile
(
tempFile
);
wxRemoveFile
(
tempFile
);
...
@@ -540,6 +564,12 @@ void Packaged::saveAs(const String& package, bool remove_unused) {
...
@@ -540,6 +564,12 @@ void Packaged::saveAs(const String& package, bool remove_unused) {
referenceFile
(
typeName
());
referenceFile
(
typeName
());
Package
::
saveAs
(
package
,
remove_unused
);
Package
::
saveAs
(
package
,
remove_unused
);
}
}
void
Packaged
::
saveCopy
(
const
String
&
package
)
{
WITH_DYNAMIC_ARG
(
writing_package
,
this
);
writeFile
(
typeName
(),
*
this
,
fileVersion
());
referenceFile
(
typeName
());
Package
::
saveCopy
(
package
);
}
void
Packaged
::
validate
(
Version
)
{
void
Packaged
::
validate
(
Version
)
{
// a default for the short name
// a default for the short name
...
...
src/util/io/package.hpp
View file @
9e495e6e
...
@@ -83,6 +83,9 @@ class Package : public IntrusivePtrVirtualBase {
...
@@ -83,6 +83,9 @@ class Package : public IntrusivePtrVirtualBase {
/// Saves the package under a different filename
/// Saves the package under a different filename
void
saveAs
(
const
String
&
package
,
bool
remove_unused
=
true
);
void
saveAs
(
const
String
&
package
,
bool
remove_unused
=
true
);
/// Saves the package under a different filename, but keep the old one open
void
saveCopy
(
const
String
&
package
);
// --------------------------------------------------- : Managing the inside of the package
// --------------------------------------------------- : Managing the inside of the package
...
@@ -175,8 +178,11 @@ class Package : public IntrusivePtrVirtualBase {
...
@@ -175,8 +178,11 @@ class Package : public IntrusivePtrVirtualBase {
void
openDirectory
();
void
openDirectory
();
void
openSubdir
(
const
String
&
);
void
openSubdir
(
const
String
&
);
void
openZipfile
();
void
openZipfile
();
void
saveToZipfile
(
const
String
&
,
bool
);
void
reopen
();
void
saveToDirectory
(
const
String
&
,
bool
);
void
removeTempFiles
(
bool
remove_unused
);
void
clearKeepFlag
();
void
saveToZipfile
(
const
String
&
,
bool
remove_unused
,
bool
is_copy
);
void
saveToDirectory
(
const
String
&
,
bool
remove_unused
,
bool
is_copy
);
FileInfos
::
iterator
addFile
(
const
String
&
file
);
FileInfos
::
iterator
addFile
(
const
String
&
file
);
};
};
...
@@ -219,6 +225,7 @@ class Packaged : public Package {
...
@@ -219,6 +225,7 @@ class Packaged : public Package {
void
loadFully
();
void
loadFully
();
void
save
();
void
save
();
void
saveAs
(
const
String
&
package
,
bool
remove_unused
=
true
);
void
saveAs
(
const
String
&
package
,
bool
remove_unused
=
true
);
void
saveCopy
(
const
String
&
package
);
/// Check if this package lists a dependency on the given package
/// Check if this package lists a dependency on the given package
/** This is done to force people to fill in the dependencies */
/** This is done to force people to fill in the dependencies */
...
...
tools/website/drupal/mse-drupal-modules/highlight.inc
View file @
9e495e6e
...
@@ -87,6 +87,7 @@ $built_in_functions = array(
...
@@ -87,6 +87,7 @@ $built_in_functions = array(
'copy_file'
=>
''
,
'copy_file'
=>
''
,
'write_text_file'
=>
''
,
'write_text_file'
=>
''
,
'write_image_file'
=>
''
,
'write_image_file'
=>
''
,
'write_set_file'
=>
''
,
// other
// other
'trace'
=>
''
,
'trace'
=>
''
,
'assert'
=>
''
,
'assert'
=>
''
,
...
...
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