Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Sign in
Toggle navigation
F
Front-End
Project
Project
Details
Activity
Releases
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
abdullh.alsoleman
Front-End
Commits
8d5f08fe
Unverified
Commit
8d5f08fe
authored
Apr 17, 2021
by
Jenn Magder
Committed by
GitHub
Apr 17, 2021
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Migrate pub in flutter_tools to null safety (#80548)
parent
72976f55
Changes
5
Hide whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
57 additions
and
64 deletions
+57
-64
pub.dart
packages/flutter_tools/lib/src/dart/pub.dart
+41
-43
source_test.dart
...er_tools/test/general.shard/build_system/source_test.dart
+1
-1
web_test.dart
...ols/test/general.shard/build_system/targets/web_test.dart
+1
-1
pub_get_test.dart
...s/flutter_tools/test/general.shard/dart/pub_get_test.dart
+3
-5
throwing_pub.dart
packages/flutter_tools/test/src/throwing_pub.dart
+11
-14
No files found.
packages/flutter_tools/lib/src/dart/pub.dart
View file @
8d5f08fe
...
@@ -2,9 +2,6 @@
...
@@ -2,9 +2,6 @@
// Use of this source code is governed by a BSD-style license that can be
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// found in the LICENSE file.
// @dart = 2.8
import
'package:meta/meta.dart'
;
import
'package:package_config/package_config.dart'
;
import
'package:package_config/package_config.dart'
;
import
'package:process/process.dart'
;
import
'package:process/process.dart'
;
...
@@ -22,7 +19,7 @@ import '../dart/package_map.dart';
...
@@ -22,7 +19,7 @@ import '../dart/package_map.dart';
import
'../reporting/reporting.dart'
;
import
'../reporting/reporting.dart'
;
/// The [Pub] instance.
/// The [Pub] instance.
Pub
get
pub
=>
context
.
get
<
Pub
>();
Pub
get
pub
=>
context
.
get
<
Pub
>()
!
;
/// The console environment key used by the pub tool.
/// The console environment key used by the pub tool.
const
String
_kPubEnvironmentKey
=
'PUB_ENVIRONMENT'
;
const
String
_kPubEnvironmentKey
=
'PUB_ENVIRONMENT'
;
...
@@ -77,12 +74,12 @@ class PubContext {
...
@@ -77,12 +74,12 @@ class PubContext {
abstract
class
Pub
{
abstract
class
Pub
{
/// Create a default [Pub] instance.
/// Create a default [Pub] instance.
factory
Pub
({
factory
Pub
({
@
required
FileSystem
fileSystem
,
required
FileSystem
fileSystem
,
@
required
Logger
logger
,
required
Logger
logger
,
@
required
ProcessManager
processManager
,
required
ProcessManager
processManager
,
@
required
Platform
platform
,
required
Platform
platform
,
@
required
BotDetector
botDetector
,
required
BotDetector
botDetector
,
@
required
Usage
usage
,
required
Usage
usage
,
})
=
_DefaultPub
;
})
=
_DefaultPub
;
/// Runs `pub get`.
/// Runs `pub get`.
...
@@ -90,7 +87,7 @@ abstract class Pub {
...
@@ -90,7 +87,7 @@ abstract class Pub {
/// [context] provides extra information to package server requests to
/// [context] provides extra information to package server requests to
/// understand usage.
/// understand usage.
Future
<
void
>
get
({
Future
<
void
>
get
({
@
required
PubContext
context
,
required
PubContext
context
,
String
directory
,
String
directory
,
bool
skipIfAbsent
=
false
,
bool
skipIfAbsent
=
false
,
bool
upgrade
=
false
,
bool
upgrade
=
false
,
...
@@ -114,11 +111,11 @@ abstract class Pub {
...
@@ -114,11 +111,11 @@ abstract class Pub {
/// understand usage.
/// understand usage.
Future
<
void
>
batch
(
Future
<
void
>
batch
(
List
<
String
>
arguments
,
{
List
<
String
>
arguments
,
{
@
required
PubContext
context
,
required
PubContext
context
,
String
directory
,
String
directory
,
MessageFilter
filter
,
MessageFilter
filter
,
String
failureMessage
=
'pub failed'
,
String
failureMessage
=
'pub failed'
,
@
required
bool
retry
,
required
bool
retry
,
bool
showTraceForErrors
,
bool
showTraceForErrors
,
});
});
...
@@ -129,7 +126,7 @@ abstract class Pub {
...
@@ -129,7 +126,7 @@ abstract class Pub {
Future
<
void
>
interactively
(
Future
<
void
>
interactively
(
List
<
String
>
arguments
,
{
List
<
String
>
arguments
,
{
String
directory
,
String
directory
,
@
required
io
.
Stdio
stdio
,
required
io
.
Stdio
stdio
,
bool
touchesPackageConfig
=
false
,
bool
touchesPackageConfig
=
false
,
bool
generateSyntheticPackage
=
false
,
bool
generateSyntheticPackage
=
false
,
});
});
...
@@ -137,12 +134,12 @@ abstract class Pub {
...
@@ -137,12 +134,12 @@ abstract class Pub {
class
_DefaultPub
implements
Pub
{
class
_DefaultPub
implements
Pub
{
_DefaultPub
({
_DefaultPub
({
@
required
FileSystem
fileSystem
,
required
FileSystem
fileSystem
,
@
required
Logger
logger
,
required
Logger
logger
,
@
required
ProcessManager
processManager
,
required
ProcessManager
processManager
,
@
required
Platform
platform
,
required
Platform
platform
,
@
required
BotDetector
botDetector
,
required
BotDetector
botDetector
,
@
required
Usage
usage
,
required
Usage
usage
,
})
:
_fileSystem
=
fileSystem
,
})
:
_fileSystem
=
fileSystem
,
_logger
=
logger
,
_logger
=
logger
,
_platform
=
platform
,
_platform
=
platform
,
...
@@ -162,13 +159,13 @@ class _DefaultPub implements Pub {
...
@@ -162,13 +159,13 @@ class _DefaultPub implements Pub {
@override
@override
Future
<
void
>
get
({
Future
<
void
>
get
({
@
required
PubContext
context
,
required
PubContext
context
,
String
directory
,
String
?
directory
,
bool
skipIfAbsent
=
false
,
bool
skipIfAbsent
=
false
,
bool
upgrade
=
false
,
bool
upgrade
=
false
,
bool
offline
=
false
,
bool
offline
=
false
,
bool
generateSyntheticPackage
=
false
,
bool
generateSyntheticPackage
=
false
,
String
flutterRootOverride
,
String
?
flutterRootOverride
,
bool
checkUpToDate
=
false
,
bool
checkUpToDate
=
false
,
})
async
{
})
async
{
directory
??=
_fileSystem
.
currentDirectory
.
path
;
directory
??=
_fileSystem
.
currentDirectory
.
path
;
...
@@ -179,7 +176,7 @@ class _DefaultPub implements Pub {
...
@@ -179,7 +176,7 @@ class _DefaultPub implements Pub {
final
File
lastVersion
=
_fileSystem
.
file
(
final
File
lastVersion
=
_fileSystem
.
file
(
_fileSystem
.
path
.
join
(
directory
,
'.dart_tool'
,
'version'
));
_fileSystem
.
path
.
join
(
directory
,
'.dart_tool'
,
'version'
));
final
File
currentVersion
=
_fileSystem
.
file
(
final
File
currentVersion
=
_fileSystem
.
file
(
_fileSystem
.
path
.
join
(
Cache
.
flutterRoot
,
'version'
));
_fileSystem
.
path
.
join
(
Cache
.
flutterRoot
!
,
'version'
));
final
File
pubspecYaml
=
_fileSystem
.
file
(
final
File
pubspecYaml
=
_fileSystem
.
file
(
_fileSystem
.
path
.
join
(
directory
,
'pubspec.yaml'
));
_fileSystem
.
path
.
join
(
directory
,
'pubspec.yaml'
));
final
File
pubLockFile
=
_fileSystem
.
file
(
final
File
pubLockFile
=
_fileSystem
.
file
(
...
@@ -249,13 +246,13 @@ class _DefaultPub implements Pub {
...
@@ -249,13 +246,13 @@ class _DefaultPub implements Pub {
@override
@override
Future
<
void
>
batch
(
Future
<
void
>
batch
(
List
<
String
>
arguments
,
{
List
<
String
>
arguments
,
{
@
required
PubContext
context
,
required
PubContext
context
,
String
directory
,
String
?
directory
,
MessageFilter
filter
,
MessageFilter
?
filter
,
String
failureMessage
=
'pub failed'
,
String
failureMessage
=
'pub failed'
,
@
required
bool
retry
,
required
bool
retry
,
bool
showTraceForErrors
,
bool
?
showTraceForErrors
,
String
flutterRootOverride
,
String
?
flutterRootOverride
,
})
async
{
})
async
{
showTraceForErrors
??=
await
_botDetector
.
isRunningOnBot
;
showTraceForErrors
??=
await
_botDetector
.
isRunningOnBot
;
...
@@ -327,8 +324,8 @@ class _DefaultPub implements Pub {
...
@@ -327,8 +324,8 @@ class _DefaultPub implements Pub {
@override
@override
Future
<
void
>
interactively
(
Future
<
void
>
interactively
(
List
<
String
>
arguments
,
{
List
<
String
>
arguments
,
{
String
directory
,
String
?
directory
,
@
required
io
.
Stdio
stdio
,
required
io
.
Stdio
stdio
,
bool
touchesPackageConfig
=
false
,
bool
touchesPackageConfig
=
false
,
bool
generateSyntheticPackage
=
false
,
bool
generateSyntheticPackage
=
false
,
})
async
{
})
async
{
...
@@ -367,14 +364,15 @@ class _DefaultPub implements Pub {
...
@@ -367,14 +364,15 @@ class _DefaultPub implements Pub {
}
}
if
(
touchesPackageConfig
)
{
if
(
touchesPackageConfig
)
{
final
String
targetDirectory
=
directory
??
_fileSystem
.
currentDirectory
.
path
;
final
File
packageConfigFile
=
_fileSystem
.
file
(
final
File
packageConfigFile
=
_fileSystem
.
file
(
_fileSystem
.
path
.
join
(
d
irectory
,
'.dart_tool'
,
'package_config.json'
));
_fileSystem
.
path
.
join
(
targetD
irectory
,
'.dart_tool'
,
'package_config.json'
));
final
Directory
generatedDirectory
=
_fileSystem
.
directory
(
final
Directory
generatedDirectory
=
_fileSystem
.
directory
(
_fileSystem
.
path
.
join
(
d
irectory
,
'.dart_tool'
,
'flutter_gen'
));
_fileSystem
.
path
.
join
(
targetD
irectory
,
'.dart_tool'
,
'flutter_gen'
));
final
File
lastVersion
=
_fileSystem
.
file
(
final
File
lastVersion
=
_fileSystem
.
file
(
_fileSystem
.
path
.
join
(
d
irectory
,
'.dart_tool'
,
'version'
));
_fileSystem
.
path
.
join
(
targetD
irectory
,
'.dart_tool'
,
'version'
));
final
File
currentVersion
=
_fileSystem
.
file
(
final
File
currentVersion
=
_fileSystem
.
file
(
_fileSystem
.
path
.
join
(
Cache
.
flutterRoot
,
'version'
));
_fileSystem
.
path
.
join
(
Cache
.
flutterRoot
!
,
'version'
));
lastVersion
.
writeAsStringSync
(
currentVersion
.
readAsStringSync
());
lastVersion
.
writeAsStringSync
(
currentVersion
.
readAsStringSync
());
await
_updatePackageConfig
(
await
_updatePackageConfig
(
packageConfigFile
,
packageConfigFile
,
...
@@ -388,7 +386,7 @@ class _DefaultPub implements Pub {
...
@@ -388,7 +386,7 @@ class _DefaultPub implements Pub {
List
<
String
>
_pubCommand
(
List
<
String
>
arguments
)
{
List
<
String
>
_pubCommand
(
List
<
String
>
arguments
)
{
// TODO(jonahwilliams): refactor to use artifacts.
// TODO(jonahwilliams): refactor to use artifacts.
final
String
sdkPath
=
_fileSystem
.
path
.
joinAll
(<
String
>[
final
String
sdkPath
=
_fileSystem
.
path
.
joinAll
(<
String
>[
Cache
.
flutterRoot
,
Cache
.
flutterRoot
!
,
'bin'
,
'bin'
,
'cache'
,
'cache'
,
'dart-sdk'
,
'dart-sdk'
,
...
@@ -410,7 +408,7 @@ class _DefaultPub implements Pub {
...
@@ -410,7 +408,7 @@ class _DefaultPub implements Pub {
Future
<
String
>
_getPubEnvironmentValue
(
PubContext
pubContext
)
async
{
Future
<
String
>
_getPubEnvironmentValue
(
PubContext
pubContext
)
async
{
// DO NOT update this function without contacting kevmoo.
// DO NOT update this function without contacting kevmoo.
// We have server-side tooling that assumes the values are consistent.
// We have server-side tooling that assumes the values are consistent.
final
String
existing
=
_platform
.
environment
[
_kPubEnvironmentKey
];
final
String
?
existing
=
_platform
.
environment
[
_kPubEnvironmentKey
];
final
List
<
String
>
values
=
<
String
>[
final
List
<
String
>
values
=
<
String
>[
if
(
existing
!=
null
&&
existing
.
isNotEmpty
)
existing
,
if
(
existing
!=
null
&&
existing
.
isNotEmpty
)
existing
,
if
(
await
_botDetector
.
isRunningOnBot
)
'flutter_bot'
,
if
(
await
_botDetector
.
isRunningOnBot
)
'flutter_bot'
,
...
@@ -420,12 +418,12 @@ class _DefaultPub implements Pub {
...
@@ -420,12 +418,12 @@ class _DefaultPub implements Pub {
return
values
.
join
(
':'
);
return
values
.
join
(
':'
);
}
}
String
_getRootPubCacheIfAvailable
()
{
String
?
_getRootPubCacheIfAvailable
()
{
if
(
_platform
.
environment
.
containsKey
(
_kPubCacheEnvironmentKey
))
{
if
(
_platform
.
environment
.
containsKey
(
_kPubCacheEnvironmentKey
))
{
return
_platform
.
environment
[
_kPubCacheEnvironmentKey
];
return
_platform
.
environment
[
_kPubCacheEnvironmentKey
];
}
}
final
String
cachePath
=
_fileSystem
.
path
.
join
(
Cache
.
flutterRoot
,
'.pub-cache'
);
final
String
cachePath
=
_fileSystem
.
path
.
join
(
Cache
.
flutterRoot
!
,
'.pub-cache'
);
if
(
_fileSystem
.
directory
(
cachePath
).
existsSync
())
{
if
(
_fileSystem
.
directory
(
cachePath
).
existsSync
())
{
_logger
.
printTrace
(
'Using
$cachePath
for the pub cache.'
);
_logger
.
printTrace
(
'Using
$cachePath
for the pub cache.'
);
return
cachePath
;
return
cachePath
;
...
@@ -439,12 +437,12 @@ class _DefaultPub implements Pub {
...
@@ -439,12 +437,12 @@ class _DefaultPub implements Pub {
///
///
/// [context] provides extra information to package server requests to
/// [context] provides extra information to package server requests to
/// understand usage.
/// understand usage.
Future
<
Map
<
String
,
String
>>
_createPubEnvironment
(
PubContext
context
,
[
String
flutterRootOverride
])
async
{
Future
<
Map
<
String
,
String
>>
_createPubEnvironment
(
PubContext
context
,
[
String
?
flutterRootOverride
])
async
{
final
Map
<
String
,
String
>
environment
=
<
String
,
String
>{
final
Map
<
String
,
String
>
environment
=
<
String
,
String
>{
'FLUTTER_ROOT'
:
flutterRootOverride
??
Cache
.
flutterRoot
,
'FLUTTER_ROOT'
:
flutterRootOverride
??
Cache
.
flutterRoot
!
,
_kPubEnvironmentKey:
await
_getPubEnvironmentValue
(
context
),
_kPubEnvironmentKey:
await
_getPubEnvironmentValue
(
context
),
};
};
final
String
pubCache
=
_getRootPubCacheIfAvailable
();
final
String
?
pubCache
=
_getRootPubCacheIfAvailable
();
if
(
pubCache
!=
null
)
{
if
(
pubCache
!=
null
)
{
environment
[
_kPubCacheEnvironmentKey
]
=
pubCache
;
environment
[
_kPubCacheEnvironmentKey
]
=
pubCache
;
}
}
...
...
packages/flutter_tools/test/general.shard/build_system/source_test.dart
View file @
8d5f08fe
...
@@ -13,7 +13,7 @@ import 'package:flutter_tools/src/build_system/exceptions.dart';
...
@@ -13,7 +13,7 @@ import 'package:flutter_tools/src/build_system/exceptions.dart';
import
'package:flutter_tools/src/globals.dart'
as
globals
;
import
'package:flutter_tools/src/globals.dart'
as
globals
;
import
'../../src/common.dart'
;
import
'../../src/common.dart'
;
import
'../../src/
context
.dart'
;
import
'../../src/
fake_process_manager
.dart'
;
import
'../../src/testbed.dart'
;
import
'../../src/testbed.dart'
;
final
Platform
windowsPlatform
=
FakePlatform
(
final
Platform
windowsPlatform
=
FakePlatform
(
...
...
packages/flutter_tools/test/general.shard/build_system/targets/web_test.dart
View file @
8d5f08fe
...
@@ -16,7 +16,7 @@ import 'package:flutter_tools/src/build_system/targets/web.dart';
...
@@ -16,7 +16,7 @@ import 'package:flutter_tools/src/build_system/targets/web.dart';
import
'package:flutter_tools/src/globals_null_migrated.dart'
as
globals
;
import
'package:flutter_tools/src/globals_null_migrated.dart'
as
globals
;
import
'../../../src/common.dart'
;
import
'../../../src/common.dart'
;
import
'../../../src/
context
.dart'
;
import
'../../../src/
fake_process_manager
.dart'
;
import
'../../../src/testbed.dart'
;
import
'../../../src/testbed.dart'
;
const
List
<
String
>
kDart2jsLinuxArgs
=
<
String
>[
const
List
<
String
>
kDart2jsLinuxArgs
=
<
String
>[
...
...
packages/flutter_tools/test/general.shard/dart/pub_get_test.dart
View file @
8d5f08fe
...
@@ -2,8 +2,6 @@
...
@@ -2,8 +2,6 @@
// Use of this source code is governed by a BSD-style license that can be
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// found in the LICENSE file.
// @dart = 2.8
import
'package:file/file.dart'
;
import
'package:file/file.dart'
;
import
'package:file/memory.dart'
;
import
'package:file/memory.dart'
;
import
'package:flutter_tools/src/base/bot_detector.dart'
;
import
'package:flutter_tools/src/base/bot_detector.dart'
;
...
@@ -288,7 +286,7 @@ void main() {
...
@@ -288,7 +286,7 @@ void main() {
});
});
testWithoutContext
(
'pub get 69'
,
()
async
{
testWithoutContext
(
'pub get 69'
,
()
async
{
String
error
;
String
?
error
;
const
FakeCommand
pubGetCommand
=
FakeCommand
(
const
FakeCommand
pubGetCommand
=
FakeCommand
(
command:
<
String
>[
command:
<
String
>[
...
@@ -429,7 +427,7 @@ void main() {
...
@@ -429,7 +427,7 @@ void main() {
});
});
testWithoutContext
(
'pub cache in root is used'
,
()
async
{
testWithoutContext
(
'pub cache in root is used'
,
()
async
{
String
error
;
String
?
error
;
final
FileSystem
fileSystem
=
MemoryFileSystem
.
test
();
final
FileSystem
fileSystem
=
MemoryFileSystem
.
test
();
final
Directory
pubCache
=
fileSystem
.
directory
(
Cache
.
flutterRoot
).
childDirectory
(
'.pub-cache'
)..
createSync
();
final
Directory
pubCache
=
fileSystem
.
directory
(
Cache
.
flutterRoot
).
childDirectory
(
'.pub-cache'
)..
createSync
();
final
FakeProcessManager
processManager
=
FakeProcessManager
.
list
(<
FakeCommand
>[
final
FakeProcessManager
processManager
=
FakeProcessManager
.
list
(<
FakeCommand
>[
...
@@ -503,7 +501,7 @@ void main() {
...
@@ -503,7 +501,7 @@ void main() {
);
);
FakeAsync
().
run
((
FakeAsync
time
)
{
FakeAsync
().
run
((
FakeAsync
time
)
{
String
error
;
String
?
error
;
pub
.
get
(
context:
PubContext
.
flutterTests
).
then
((
void
value
)
{
pub
.
get
(
context:
PubContext
.
flutterTests
).
then
((
void
value
)
{
error
=
'test completed unexpectedly'
;
error
=
'test completed unexpectedly'
;
},
onError:
(
dynamic
thrownError
)
{
},
onError:
(
dynamic
thrownError
)
{
...
...
packages/flutter_tools/test/src/throwing_pub.dart
View file @
8d5f08fe
...
@@ -2,36 +2,33 @@
...
@@ -2,36 +2,33 @@
// Use of this source code is governed by a BSD-style license that can be
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// found in the LICENSE file.
// @dart = 2.8
import
'package:flutter_tools/src/base/io.dart'
;
import
'package:flutter_tools/src/base/io.dart'
;
import
'package:flutter_tools/src/dart/pub.dart'
;
import
'package:flutter_tools/src/dart/pub.dart'
;
import
'package:meta/meta.dart'
;
class
ThrowingPub
implements
Pub
{
class
ThrowingPub
implements
Pub
{
@override
@override
Future
<
void
>
batch
(
List
<
String
>
arguments
,
{
Future
<
void
>
batch
(
List
<
String
>
arguments
,
{
PubContext
context
,
PubContext
?
context
,
String
directory
,
String
?
directory
,
MessageFilter
filter
,
MessageFilter
?
filter
,
String
failureMessage
=
'pub failed'
,
String
?
failureMessage
=
'pub failed'
,
bool
retry
,
bool
?
retry
,
bool
showTraceForErrors
,
bool
?
showTraceForErrors
,
})
{
})
{
throw
UnsupportedError
(
'Attempted to invoke pub during test.'
);
throw
UnsupportedError
(
'Attempted to invoke pub during test.'
);
}
}
@override
@override
Future
<
void
>
get
({
Future
<
void
>
get
({
PubContext
context
,
PubContext
?
context
,
String
directory
,
String
?
directory
,
bool
skipIfAbsent
=
false
,
bool
skipIfAbsent
=
false
,
bool
upgrade
=
false
,
bool
upgrade
=
false
,
bool
offline
=
false
,
bool
offline
=
false
,
bool
checkLastModified
=
true
,
bool
checkLastModified
=
true
,
bool
skipPubspecYamlCheck
=
false
,
bool
skipPubspecYamlCheck
=
false
,
bool
generateSyntheticPackage
=
false
,
bool
generateSyntheticPackage
=
false
,
String
flutterRootOverride
,
String
?
flutterRootOverride
,
bool
checkUpToDate
=
false
,
bool
checkUpToDate
=
false
,
})
{
})
{
throw
UnsupportedError
(
'Attempted to invoke pub during test.'
);
throw
UnsupportedError
(
'Attempted to invoke pub during test.'
);
...
@@ -40,8 +37,8 @@ class ThrowingPub implements Pub {
...
@@ -40,8 +37,8 @@ class ThrowingPub implements Pub {
@override
@override
Future
<
void
>
interactively
(
Future
<
void
>
interactively
(
List
<
String
>
arguments
,
{
List
<
String
>
arguments
,
{
String
directory
,
String
?
directory
,
@
required
Stdio
stdio
,
required
Stdio
stdio
,
bool
touchesPackageConfig
=
false
,
bool
touchesPackageConfig
=
false
,
bool
generateSyntheticPackage
=
false
,
bool
generateSyntheticPackage
=
false
,
})
{
})
{
...
...
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