Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Contribute to GitLab
Sign in
Toggle navigation
J
jadx
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
open-source
jadx
Commits
7cdb0318
Commit
7cdb0318
authored
Mar 27, 2019
by
Skylot
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
style: resolve some sonar warnings
parent
17d8516d
Hide whitespace changes
Inline
Side-by-side
Showing
23 changed files
with
218 additions
and
250 deletions
+218
-250
JadxArgs.java
jadx-core/src/main/java/jadx/api/JadxArgs.java
+22
-24
TypeGen.java
jadx-core/src/main/java/jadx/core/codegen/TypeGen.java
+2
-2
CallMthInterface.java
...ain/java/jadx/core/dex/instructions/CallMthInterface.java
+1
-1
FieldArg.java
...c/main/java/jadx/core/dex/instructions/args/FieldArg.java
+3
-1
MethodNode.java
jadx-core/src/main/java/jadx/core/dex/nodes/MethodNode.java
+3
-4
PrepareForCodeGen.java
...c/main/java/jadx/core/dex/visitors/PrepareForCodeGen.java
+0
-1
SimplifyVisitor.java
...src/main/java/jadx/core/dex/visitors/SimplifyVisitor.java
+0
-1
BlockSplitter.java
...ava/jadx/core/dex/visitors/blocksmaker/BlockSplitter.java
+22
-18
TernaryMod.java
.../main/java/jadx/core/dex/visitors/regions/TernaryMod.java
+1
-1
TypeInferenceVisitor.java
...core/dex/visitors/typeinference/TypeInferenceVisitor.java
+13
-13
Utils.java
jadx-core/src/main/java/jadx/core/utils/Utils.java
+0
-1
ResTableParser.java
jadx-core/src/main/java/jadx/core/xmlgen/ResTableParser.java
+7
-14
EntryConfig.java
...ore/src/main/java/jadx/core/xmlgen/entry/EntryConfig.java
+126
-154
TestRedundantBrackets.java
...st/java/jadx/tests/integration/TestRedundantBrackets.java
+1
-1
TestAnnotations.java
...a/jadx/tests/integration/annotations/TestAnnotations.java
+3
-3
TestAnnotationsMix.java
...adx/tests/integration/annotations/TestAnnotationsMix.java
+1
-1
TestTernary.java
...t/java/jadx/tests/integration/conditions/TestTernary.java
+4
-3
TestEnums3.java
...rc/test/java/jadx/tests/integration/enums/TestEnums3.java
+1
-1
TestEnums4.java
...rc/test/java/jadx/tests/integration/enums/TestEnums4.java
+1
-1
TestEnumsInterface.java
...java/jadx/tests/integration/enums/TestEnumsInterface.java
+1
-1
TestInnerClass5.java
...st/java/jadx/tests/integration/inner/TestInnerClass5.java
+3
-3
TestSameMethodsNames.java
...va/jadx/tests/integration/names/TestSameMethodsNames.java
+1
-0
TestTryCatchInIf.java
...ava/jadx/tests/integration/trycatch/TestTryCatchInIf.java
+2
-1
No files found.
jadx-core/src/main/java/jadx/api/JadxArgs.java
View file @
7cdb0318
...
...
@@ -247,29 +247,27 @@ public class JadxArgs {
@Override
public
String
toString
()
{
final
StringBuilder
sb
=
new
StringBuilder
(
"JadxArgs{"
);
sb
.
append
(
"inputFiles="
).
append
(
inputFiles
);
sb
.
append
(
", outDir="
).
append
(
outDir
);
sb
.
append
(
", outDirSrc="
).
append
(
outDirSrc
);
sb
.
append
(
", outDirRes="
).
append
(
outDirRes
);
sb
.
append
(
", threadsCount="
).
append
(
threadsCount
);
sb
.
append
(
", cfgOutput="
).
append
(
cfgOutput
);
sb
.
append
(
", rawCFGOutput="
).
append
(
rawCFGOutput
);
sb
.
append
(
", fallbackMode="
).
append
(
fallbackMode
);
sb
.
append
(
", showInconsistentCode="
).
append
(
showInconsistentCode
);
sb
.
append
(
", useImports="
).
append
(
useImports
);
sb
.
append
(
", isSkipResources="
).
append
(
isSkipResources
);
sb
.
append
(
", isSkipSources="
).
append
(
isSkipSources
);
sb
.
append
(
", isDeobfuscationOn="
).
append
(
isDeobfuscationOn
);
sb
.
append
(
", isDeobfuscationForceSave="
).
append
(
isDeobfuscationForceSave
);
sb
.
append
(
", useSourceNameAsClassAlias="
).
append
(
useSourceNameAsClassAlias
);
sb
.
append
(
", deobfuscationMinLength="
).
append
(
deobfuscationMinLength
);
sb
.
append
(
", deobfuscationMaxLength="
).
append
(
deobfuscationMaxLength
);
sb
.
append
(
", escapeUnicode="
).
append
(
escapeUnicode
);
sb
.
append
(
", replaceConsts="
).
append
(
replaceConsts
);
sb
.
append
(
", respectBytecodeAccModifiers="
).
append
(
respectBytecodeAccModifiers
);
sb
.
append
(
", exportAsGradleProject="
).
append
(
exportAsGradleProject
);
sb
.
append
(
'}'
);
return
sb
.
toString
();
return
"JadxArgs{"
+
"inputFiles="
+
inputFiles
+
", outDir="
+
outDir
+
", outDirSrc="
+
outDirSrc
+
", outDirRes="
+
outDirRes
+
", threadsCount="
+
threadsCount
+
", cfgOutput="
+
cfgOutput
+
", rawCFGOutput="
+
rawCFGOutput
+
", fallbackMode="
+
fallbackMode
+
", showInconsistentCode="
+
showInconsistentCode
+
", useImports="
+
useImports
+
", isSkipResources="
+
isSkipResources
+
", isSkipSources="
+
isSkipSources
+
", isDeobfuscationOn="
+
isDeobfuscationOn
+
", isDeobfuscationForceSave="
+
isDeobfuscationForceSave
+
", useSourceNameAsClassAlias="
+
useSourceNameAsClassAlias
+
", deobfuscationMinLength="
+
deobfuscationMinLength
+
", deobfuscationMaxLength="
+
deobfuscationMaxLength
+
", escapeUnicode="
+
escapeUnicode
+
", replaceConsts="
+
replaceConsts
+
", respectBytecodeAccModifiers="
+
respectBytecodeAccModifiers
+
", exportAsGradleProject="
+
exportAsGradleProject
+
'}'
;
}
}
jadx-core/src/main/java/jadx/core/codegen/TypeGen.java
View file @
7cdb0318
...
...
@@ -97,7 +97,7 @@ public class TypeGen {
if
(
s
==
Short
.
MIN_VALUE
)
{
return
"Short.MIN_VALUE"
;
}
return
"(short) "
+
Short
.
toString
(
s
)
;
return
"(short) "
+
s
;
}
public
static
String
formatByte
(
byte
b
)
{
...
...
@@ -107,7 +107,7 @@ public class TypeGen {
if
(
b
==
Byte
.
MIN_VALUE
)
{
return
"Byte.MIN_VALUE"
;
}
return
"(byte) "
+
Byte
.
toString
(
b
)
;
return
"(byte) "
+
b
;
}
public
static
String
formatInteger
(
int
i
)
{
...
...
jadx-core/src/main/java/jadx/core/dex/instructions/CallMthInterface.java
View file @
7cdb0318
...
...
@@ -4,5 +4,5 @@ import jadx.core.dex.info.MethodInfo;
public
interface
CallMthInterface
{
public
MethodInfo
getCallMth
();
MethodInfo
getCallMth
();
}
jadx-core/src/main/java/jadx/core/dex/instructions/args/FieldArg.java
View file @
7cdb0318
package
jadx
.
core
.
dex
.
instructions
.
args
;
import
java.util.Objects
;
import
org.jetbrains.annotations.Nullable
;
import
jadx.core.dex.info.FieldInfo
;
...
...
@@ -68,7 +70,7 @@ public final class FieldArg extends RegisterArg {
if
(!
field
.
equals
(
fieldArg
.
field
))
{
return
false
;
}
return
instArg
!=
null
?
instArg
.
equals
(
fieldArg
.
instArg
)
:
fieldArg
.
instArg
==
null
;
return
Objects
.
equals
(
instArg
,
fieldArg
.
instArg
)
;
}
@Override
...
...
jadx-core/src/main/java/jadx/core/dex/nodes/MethodNode.java
View file @
7cdb0318
...
...
@@ -151,11 +151,10 @@ public class MethodNode extends LineAttrNode implements ILoadable, ICodeNode {
list
.
add
(
resultArg
);
}
insnNode
.
getRegisterArgs
(
list
);
int
argsCount
=
list
.
size
();
for
(
int
i
=
0
;
i
<
argsCount
;
i
++)
{
if
(
list
.
get
(
i
).
getRegNum
()
>=
regsCount
)
{
for
(
RegisterArg
arg
:
list
)
{
if
(
arg
.
getRegNum
()
>=
regsCount
)
{
throw
new
JadxRuntimeException
(
"Incorrect register number in instruction: "
+
insnNode
+
", expected to be less than "
+
regsCount
);
+
", expected to be less than "
+
regsCount
);
}
}
}
...
...
jadx-core/src/main/java/jadx/core/dex/visitors/PrepareForCodeGen.java
View file @
7cdb0318
...
...
@@ -150,7 +150,6 @@ public class PrepareForCodeGen extends AbstractVisitor {
}
if
(
replace
)
{
insn
.
add
(
AFlag
.
ARITH_ONEARG
);
// insn.getResult().mergeName(arg);
}
}
}
...
...
jadx-core/src/main/java/jadx/core/dex/visitors/SimplifyVisitor.java
View file @
7cdb0318
...
...
@@ -24,7 +24,6 @@ import jadx.core.dex.instructions.args.FieldArg;
import
jadx.core.dex.instructions.args.InsnArg
;
import
jadx.core.dex.instructions.args.InsnWrapArg
;
import
jadx.core.dex.instructions.args.LiteralArg
;
import
jadx.core.dex.instructions.args.RegisterArg
;
import
jadx.core.dex.instructions.mods.ConstructorInsn
;
import
jadx.core.dex.instructions.mods.TernaryInsn
;
import
jadx.core.dex.nodes.BlockNode
;
...
...
jadx-core/src/main/java/jadx/core/dex/visitors/blocksmaker/BlockSplitter.java
View file @
7cdb0318
...
...
@@ -29,15 +29,19 @@ import jadx.core.utils.exceptions.JadxRuntimeException;
public
class
BlockSplitter
extends
AbstractVisitor
{
// leave these instructions alone in block node
p
ublic
static
final
Set
<
InsnType
>
SEPARATE_INSNS
=
EnumSet
.
of
(
InsnType
.
RETURN
,
InsnType
.
IF
,
InsnType
.
SWITCH
,
InsnType
.
MONITOR_ENTER
,
InsnType
.
MONITOR_EXIT
,
InsnType
.
THROW
p
rivate
static
final
Set
<
InsnType
>
SEPARATE_INSNS
=
EnumSet
.
of
(
InsnType
.
RETURN
,
InsnType
.
IF
,
InsnType
.
SWITCH
,
InsnType
.
MONITOR_ENTER
,
InsnType
.
MONITOR_EXIT
,
InsnType
.
THROW
);
public
static
boolean
makeSeparate
(
InsnType
insnType
)
{
return
SEPARATE_INSNS
.
contains
(
insnType
);
}
@Override
public
void
visit
(
MethodNode
mth
)
{
if
(
mth
.
isNoCode
())
{
...
...
@@ -84,8 +88,8 @@ public class BlockSplitter extends AbstractVisitor {
if
(
prevInsn
!=
null
)
{
InsnType
type
=
prevInsn
.
getType
();
if
(
type
==
InsnType
.
GOTO
||
type
==
InsnType
.
THROW
||
SEPARATE_INSNS
.
contains
(
type
))
{
||
type
==
InsnType
.
THROW
||
makeSeparate
(
type
))
{
if
(
type
==
InsnType
.
RETURN
||
type
==
InsnType
.
THROW
)
{
mth
.
addExitBlock
(
curBlock
);
...
...
@@ -98,11 +102,11 @@ public class BlockSplitter extends AbstractVisitor {
startNew
=
true
;
}
else
{
startNew
=
isSplitByJump
(
prevInsn
,
insn
)
||
SEPARATE_INSNS
.
contains
(
insn
.
getType
())
||
isDoWhile
(
blocksMap
,
curBlock
,
insn
)
||
insn
.
contains
(
AType
.
EXC_HANDLER
)
||
prevInsn
.
contains
(
AFlag
.
TRY_LEAVE
)
||
prevInsn
.
getType
()
==
InsnType
.
MOVE_EXCEPTION
;
||
makeSeparate
(
insn
.
getType
())
||
isDoWhile
(
blocksMap
,
curBlock
,
insn
)
||
insn
.
contains
(
AType
.
EXC_HANDLER
)
||
prevInsn
.
contains
(
AFlag
.
TRY_LEAVE
)
||
prevInsn
.
getType
()
==
InsnType
.
MOVE_EXCEPTION
;
if
(
startNew
)
{
curBlock
=
connectNewBlock
(
mth
,
curBlock
,
insn
.
getOffset
());
}
...
...
@@ -326,9 +330,9 @@ public class BlockSplitter extends AbstractVisitor {
static
boolean
removeEmptyDetachedBlocks
(
MethodNode
mth
)
{
return
mth
.
getBasicBlocks
().
removeIf
(
block
->
block
.
getInstructions
().
isEmpty
()
&&
block
.
getPredecessors
().
isEmpty
()
&&
block
.
getSuccessors
().
isEmpty
()
block
.
getInstructions
().
isEmpty
()
&&
block
.
getPredecessors
().
isEmpty
()
&&
block
.
getSuccessors
().
isEmpty
()
);
}
...
...
@@ -353,7 +357,7 @@ public class BlockSplitter extends AbstractVisitor {
int
insnsCount
=
toRemove
.
stream
().
mapToInt
(
block
->
block
.
getInstructions
().
size
()).
sum
();
mth
.
addAttr
(
AType
.
COMMENTS
,
"JADX INFO: unreachable blocks removed: "
+
toRemove
.
size
()
+
", instructions: "
+
insnsCount
);
+
", instructions: "
+
insnsCount
);
}
}
...
...
jadx-core/src/main/java/jadx/core/dex/visitors/regions/TernaryMod.java
View file @
7cdb0318
...
...
@@ -167,7 +167,7 @@ public class TernaryMod {
}
PhiInsn
tPhi
=
t
.
getResult
().
getSVar
().
getUsedInPhi
();
PhiInsn
ePhi
=
e
.
getResult
().
getSVar
().
getUsedInPhi
();
if
(
tPhi
==
null
||
ePhi
==
null
||
tPhi
!=
ePhi
)
{
if
(
ePhi
==
null
||
tPhi
!=
ePhi
)
{
return
false
;
}
Map
<
Integer
,
Integer
>
map
=
new
HashMap
<>(
tPhi
.
getArgsCount
());
...
...
jadx-core/src/main/java/jadx/core/dex/visitors/typeinference/TypeInferenceVisitor.java
View file @
7cdb0318
...
...
@@ -41,12 +41,12 @@ import jadx.core.utils.BlockUtils;
import
jadx.core.utils.Utils
;
@JadxVisitor
(
name
=
"Type Inference"
,
desc
=
"Calculate best types for SSA variables"
,
runAfter
=
{
SSATransform
.
class
,
ConstInlineVisitor
.
class
}
name
=
"Type Inference"
,
desc
=
"Calculate best types for SSA variables"
,
runAfter
=
{
SSATransform
.
class
,
ConstInlineVisitor
.
class
}
)
public
final
class
TypeInferenceVisitor
extends
AbstractVisitor
{
private
static
final
Logger
LOG
=
LoggerFactory
.
getLogger
(
TypeInferenceVisitor
.
class
);
...
...
@@ -76,8 +76,8 @@ public final class TypeInferenceVisitor extends AbstractVisitor {
for
(
SSAVar
var
:
mth
.
getSVars
())
{
ArgType
type
=
var
.
getTypeInfo
().
getType
();
if
(!
type
.
isTypeKnown
()
&&
!
var
.
getAssign
().
isTypeImmutable
()
&&
!
tryDeduceType
(
mth
,
var
,
type
))
{
&&
!
var
.
getAssign
().
isTypeImmutable
()
&&
!
tryDeduceType
(
mth
,
var
,
type
))
{
resolved
=
false
;
}
}
...
...
@@ -101,7 +101,7 @@ public final class TypeInferenceVisitor extends AbstractVisitor {
}
long
time
=
System
.
currentTimeMillis
()
-
startTime
;
mth
.
addComment
(
"JADX DEBUG: Multi-variable type inference result: "
+
(
success
?
"success"
:
"failure"
)
+
", time: "
+
time
+
" ms"
);
+
", time: "
+
time
+
" ms"
);
}
private
boolean
setImmutableType
(
SSAVar
ssaVar
)
{
...
...
@@ -178,9 +178,9 @@ public final class TypeInferenceVisitor extends AbstractVisitor {
private
Optional
<
ArgType
>
selectBestTypeFromBounds
(
Set
<
ITypeBound
>
bounds
)
{
return
bounds
.
stream
()
.
map
(
ITypeBound:
:
getType
)
.
filter
(
Objects:
:
nonNull
)
.
max
(
typeUpdate
.
getArgTypeComparator
());
.
map
(
ITypeBound:
:
getType
)
.
filter
(
Objects:
:
nonNull
)
.
max
(
typeUpdate
.
getArgTypeComparator
());
}
private
void
attachBounds
(
SSAVar
var
)
{
...
...
@@ -321,7 +321,7 @@ public final class TypeInferenceVisitor extends AbstractVisitor {
if
(
reg
.
getSVar
()
==
var
)
{
BlockNode
blockNode
=
entry
.
getValue
();
InsnNode
lastInsn
=
BlockUtils
.
getLastInsn
(
blockNode
);
if
(
lastInsn
!=
null
&&
BlockSplitter
.
SEPARATE_INSNS
.
contains
(
lastInsn
.
getType
()))
{
if
(
lastInsn
!=
null
&&
BlockSplitter
.
makeSeparate
(
lastInsn
.
getType
()))
{
if
(
Consts
.
DEBUG
)
{
LOG
.
warn
(
"Can't insert move for PHI in block with separate insn: {}"
,
lastInsn
);
}
...
...
jadx-core/src/main/java/jadx/core/utils/Utils.java
View file @
7cdb0318
...
...
@@ -154,7 +154,6 @@ public class Utils {
}
}
@SuppressWarnings
(
"unchecked"
)
public
static
<
T
>
List
<
T
>
lockList
(
List
<
T
>
list
)
{
if
(
list
.
isEmpty
())
{
return
Collections
.
emptyList
();
...
...
jadx-core/src/main/java/jadx/core/xmlgen/ResTableParser.java
View file @
7cdb0318
...
...
@@ -18,11 +18,8 @@ import jadx.core.xmlgen.entry.ResourceEntry;
import
jadx.core.xmlgen.entry.ValuesParser
;
public
class
ResTableParser
extends
CommonBinaryParser
{
private
static
final
Logger
LOG
=
LoggerFactory
.
getLogger
(
ResTableParser
.
class
);
private
static
final
int
KNOWN_CONFIG_BYTES
=
56
;
private
static
final
class
PackageChunk
{
private
final
int
id
;
private
final
String
name
;
...
...
@@ -83,7 +80,7 @@ public class ResTableParser extends CommonBinaryParser {
for
(
ResourceEntry
ri
:
resStorage
.
getResources
())
{
if
(
addedValues
.
add
(
ri
.
getTypeName
()
+
'.'
+
ri
.
getKeyName
()))
{
String
format
=
String
.
format
(
"<public type=\"%s\" name=\"%s\" id=\"%s\" />"
,
ri
.
getTypeName
(),
ri
.
getKeyName
(),
ri
.
getId
());
ri
.
getTypeName
(),
ri
.
getKeyName
(),
ri
.
getId
());
writer
.
startLine
(
format
);
}
}
...
...
@@ -150,9 +147,7 @@ public class ResTableParser extends CommonBinaryParser {
}
PackageChunk
pkg
=
new
PackageChunk
(
id
,
name
,
typeStrings
,
keyStrings
);
//if (id == 0x7F) {
resStorage
.
setAppPackage
(
name
);
//}
while
(
is
.
getPos
()
<
endPos
)
{
long
chunkStart
=
is
.
getPos
();
...
...
@@ -198,7 +193,7 @@ public class ResTableParser extends CommonBinaryParser {
if
(
config
.
isInvalid
)
{
String
typeName
=
pkg
.
getTypeStrings
()[
id
-
1
];
LOG
.
warn
(
"Invalid config flags detected:
"
+
typeName
+
config
.
getQualifiers
());
LOG
.
warn
(
"Invalid config flags detected:
{}{}"
,
typeName
,
config
.
getQualifiers
());
}
int
[]
entryIndexes
=
new
int
[
entryCount
];
...
...
@@ -260,8 +255,6 @@ public class ResTableParser extends CommonBinaryParser {
throw
new
IOException
(
"Config size < 28"
);
}
boolean
isInvalid
=
false
;
short
mcc
=
(
short
)
is
.
readInt16
();
short
mnc
=
(
short
)
is
.
readInt16
();
...
...
@@ -317,11 +310,11 @@ public class ResTableParser extends CommonBinaryParser {
is
.
skipToPos
(
start
+
size
,
"Config skip trailing bytes"
);
return
new
EntryConfig
(
mcc
,
mnc
,
language
,
country
,
orientation
,
touchscreen
,
density
,
keyboard
,
navigation
,
inputFlags
,
screenWidth
,
screenHeight
,
sdkVersion
,
screenLayout
,
uiMode
,
smallestScreenWidthDp
,
screenWidthDp
,
screenHeightDp
,
localeScript
,
localeVariant
,
screenLayout2
,
colorMode
,
isInvalid
,
size
);
orientation
,
touchscreen
,
density
,
keyboard
,
navigation
,
inputFlags
,
screenWidth
,
screenHeight
,
sdkVersion
,
screenLayout
,
uiMode
,
smallestScreenWidthDp
,
screenWidthDp
,
screenHeightDp
,
localeScript
,
localeVariant
,
screenLayout2
,
colorMode
,
false
,
size
);
}
private
char
[]
unpackLocaleOrRegion
(
byte
in0
,
byte
in1
,
char
base
)
{
...
...
jadx-core/src/main/java/jadx/core/xmlgen/entry/EntryConfig.java
View file @
7cdb0318
...
...
@@ -63,34 +63,6 @@ public class EntryConfig {
private
final
int
size
;
public
EntryConfig
()
{
mcc
=
0
;
mnc
=
0
;
language
=
new
char
[]{
'\
00
'
,
'\
00
'
};
region
=
new
char
[]{
'\
00
'
,
'\
00
'
};
orientation
=
ORIENTATION_ANY
;
touchscreen
=
TOUCHSCREEN_ANY
;
density
=
DENSITY_DEFAULT
;
keyboard
=
KEYBOARD_ANY
;
navigation
=
NAVIGATION_ANY
;
inputFlags
=
KEYSHIDDEN_ANY
|
NAVHIDDEN_ANY
;
screenWidth
=
0
;
screenHeight
=
0
;
sdkVersion
=
0
;
screenLayout
=
SCREENLONG_ANY
|
SCREENSIZE_ANY
;
uiMode
=
UI_MODE_TYPE_ANY
|
UI_MODE_NIGHT_ANY
;
smallestScreenWidthDp
=
0
;
screenWidthDp
=
0
;
screenHeightDp
=
0
;
localeScript
=
null
;
localeVariant
=
null
;
screenLayout2
=
0
;
colorMode
=
COLOR_WIDE_UNDEFINED
;
isInvalid
=
false
;
mQualifiers
=
""
;
size
=
0
;
}
public
EntryConfig
(
short
mcc
,
short
mnc
,
char
[]
language
,
char
[]
region
,
byte
orientation
,
byte
touchscreen
,
int
density
,
byte
keyboard
,
byte
navigation
,
...
...
@@ -450,7 +422,7 @@ public class EntryConfig {
// allows values-xx-rXX, values-xx, values-xxx-rXX
// denies values-xxx, anything else
if
(
localeVariant
==
null
&&
localeScript
==
null
&&
(
region
[
0
]
!=
'\
00
'
||
language
[
0
]
!=
'\
00
'
)
&&
region
.
length
!=
3
)
{
region
.
length
!=
3
)
{
sb
.
append
(
'-'
).
append
(
language
);
if
(
region
[
0
]
!=
'\
00
'
)
{
sb
.
append
(
"-r"
).
append
(
region
);
...
...
@@ -512,138 +484,138 @@ public class EntryConfig {
// but it would be hard right now and this feature is very rarely used.
private
static
int
sErrCounter
=
0
;
public
final
static
byte
SDK_BASE
=
1
;
public
final
static
byte
SDK_BASE_1_1
=
2
;
public
final
static
byte
SDK_CUPCAKE
=
3
;
public
final
static
byte
SDK_DONUT
=
4
;
public
final
static
byte
SDK_ECLAIR
=
5
;
public
final
static
byte
SDK_ECLAIR_0_1
=
6
;
public
final
static
byte
SDK_ECLAIR_MR1
=
7
;
public
final
static
byte
SDK_FROYO
=
8
;
public
final
static
byte
SDK_GINGERBREAD
=
9
;
public
final
static
byte
SDK_GINGERBREAD_MR1
=
10
;
public
final
static
byte
SDK_HONEYCOMB
=
11
;
public
final
static
byte
SDK_HONEYCOMB_MR1
=
12
;
public
final
static
byte
SDK_HONEYCOMB_MR2
=
13
;
public
final
static
byte
SDK_ICE_CREAM_SANDWICH
=
14
;
public
final
static
byte
SDK_ICE_CREAM_SANDWICH_MR1
=
15
;
public
final
static
byte
SDK_JELLY_BEAN
=
16
;
public
final
static
byte
SDK_JELLY_BEAN_MR1
=
17
;
public
final
static
byte
SDK_JELLY_BEAN_MR2
=
18
;
public
final
static
byte
SDK_KITKAT
=
19
;
public
final
static
byte
SDK_LOLLIPOP
=
21
;
public
final
static
byte
SDK_LOLLIPOP_MR1
=
22
;
public
final
static
byte
SDK_MNC
=
23
;
public
final
static
byte
SDK_NOUGAT
=
24
;
public
final
static
byte
SDK_NOUGAT_MR1
=
25
;
public
final
static
byte
SDK_OREO
=
26
;
public
final
static
byte
SDK_OREO_MR1
=
27
;
public
final
static
byte
SDK_P
=
28
;
public
final
static
byte
ORIENTATION_ANY
=
0
;
public
final
static
byte
ORIENTATION_PORT
=
1
;
public
final
static
byte
ORIENTATION_LAND
=
2
;
public
final
static
byte
ORIENTATION_SQUARE
=
3
;
public
final
static
byte
TOUCHSCREEN_ANY
=
0
;
public
final
static
byte
TOUCHSCREEN_NOTOUCH
=
1
;
public
final
static
byte
TOUCHSCREEN_STYLUS
=
2
;
public
final
static
byte
TOUCHSCREEN_FINGER
=
3
;
public
final
static
int
DENSITY_DEFAULT
=
0
;
public
final
static
int
DENSITY_LOW
=
120
;
public
final
static
int
DENSITY_MEDIUM
=
160
;
public
final
static
int
DENSITY_400
=
190
;
public
final
static
int
DENSITY_TV
=
213
;
public
final
static
int
DENSITY_HIGH
=
240
;
public
final
static
int
DENSITY_XHIGH
=
320
;
public
final
static
int
DENSITY_XXHIGH
=
480
;
public
final
static
int
DENSITY_XXXHIGH
=
640
;
public
final
static
int
DENSITY_ANY
=
0xFFFE
;
public
final
static
int
DENSITY_NONE
=
0xFFFF
;
public
final
static
int
MNC_ZERO
=
-
1
;
public
final
static
short
MASK_LAYOUTDIR
=
0xc0
;
public
final
static
short
SCREENLAYOUT_LAYOUTDIR_ANY
=
0x00
;
public
final
static
short
SCREENLAYOUT_LAYOUTDIR_LTR
=
0x40
;
public
final
static
short
SCREENLAYOUT_LAYOUTDIR_RTL
=
0x80
;
public
final
static
short
SCREENLAYOUT_LAYOUTDIR_SHIFT
=
0x06
;
public
final
static
short
MASK_SCREENROUND
=
0x03
;
public
final
static
short
SCREENLAYOUT_ROUND_ANY
=
0
;
public
final
static
short
SCREENLAYOUT_ROUND_NO
=
0x1
;
public
final
static
short
SCREENLAYOUT_ROUND_YES
=
0x2
;
public
final
static
byte
KEYBOARD_ANY
=
0
;
public
final
static
byte
KEYBOARD_NOKEYS
=
1
;
public
final
static
byte
KEYBOARD_QWERTY
=
2
;
public
final
static
byte
KEYBOARD_12KEY
=
3
;
public
final
static
byte
NAVIGATION_ANY
=
0
;
public
final
static
byte
NAVIGATION_NONAV
=
1
;
public
final
static
byte
NAVIGATION_DPAD
=
2
;
public
final
static
byte
NAVIGATION_TRACKBALL
=
3
;
public
final
static
byte
NAVIGATION_WHEEL
=
4
;
public
final
static
byte
MASK_KEYSHIDDEN
=
0x3
;
public
final
static
byte
KEYSHIDDEN_ANY
=
0x0
;
public
final
static
byte
KEYSHIDDEN_NO
=
0x1
;
public
final
static
byte
KEYSHIDDEN_YES
=
0x2
;
public
final
static
byte
KEYSHIDDEN_SOFT
=
0x3
;
public
final
static
byte
MASK_NAVHIDDEN
=
0xc
;
public
final
static
byte
NAVHIDDEN_ANY
=
0x0
;
public
final
static
byte
NAVHIDDEN_NO
=
0x4
;
public
final
static
byte
NAVHIDDEN_YES
=
0x8
;
public
final
static
byte
MASK_SCREENSIZE
=
0x0f
;
public
final
static
byte
SCREENSIZE_ANY
=
0x00
;
public
final
static
byte
SCREENSIZE_SMALL
=
0x01
;
public
final
static
byte
SCREENSIZE_NORMAL
=
0x02
;
public
final
static
byte
SCREENSIZE_LARGE
=
0x03
;
public
final
static
byte
SCREENSIZE_XLARGE
=
0x04
;
public
final
static
byte
MASK_SCREENLONG
=
0x30
;
public
final
static
byte
SCREENLONG_ANY
=
0x00
;
public
final
static
byte
SCREENLONG_NO
=
0x10
;
public
final
static
byte
SCREENLONG_YES
=
0x20
;
public
final
static
byte
MASK_UI_MODE_TYPE
=
0x0f
;
public
final
static
byte
UI_MODE_TYPE_ANY
=
0x00
;
public
final
static
byte
UI_MODE_TYPE_NORMAL
=
0x01
;
public
final
static
byte
UI_MODE_TYPE_DESK
=
0x02
;
public
final
static
byte
UI_MODE_TYPE_CAR
=
0x03
;
public
final
static
byte
UI_MODE_TYPE_TELEVISION
=
0x04
;
public
final
static
byte
UI_MODE_TYPE_APPLIANCE
=
0x05
;
public
final
static
byte
UI_MODE_TYPE_WATCH
=
0x06
;
public
final
static
byte
UI_MODE_TYPE_VR_HEADSET
=
0x07
;
public
static
final
byte
SDK_BASE
=
1
;
public
static
final
byte
SDK_BASE_1_1
=
2
;
public
static
final
byte
SDK_CUPCAKE
=
3
;
public
static
final
byte
SDK_DONUT
=
4
;
public
static
final
byte
SDK_ECLAIR
=
5
;
public
static
final
byte
SDK_ECLAIR_0_1
=
6
;
public
static
final
byte
SDK_ECLAIR_MR1
=
7
;
public
static
final
byte
SDK_FROYO
=
8
;
public
static
final
byte
SDK_GINGERBREAD
=
9
;
public
static
final
byte
SDK_GINGERBREAD_MR1
=
10
;
public
static
final
byte
SDK_HONEYCOMB
=
11
;
public
static
final
byte
SDK_HONEYCOMB_MR1
=
12
;
public
static
final
byte
SDK_HONEYCOMB_MR2
=
13
;
public
static
final
byte
SDK_ICE_CREAM_SANDWICH
=
14
;
public
static
final
byte
SDK_ICE_CREAM_SANDWICH_MR1
=
15
;
public
static
final
byte
SDK_JELLY_BEAN
=
16
;
public
static
final
byte
SDK_JELLY_BEAN_MR1
=
17
;
public
static
final
byte
SDK_JELLY_BEAN_MR2
=
18
;
public
static
final
byte
SDK_KITKAT
=
19
;
public
static
final
byte
SDK_LOLLIPOP
=
21
;
public
static
final
byte
SDK_LOLLIPOP_MR1
=
22
;
public
static
final
byte
SDK_MNC
=
23
;
public
static
final
byte
SDK_NOUGAT
=
24
;
public
static
final
byte
SDK_NOUGAT_MR1
=
25
;
public
static
final
byte
SDK_OREO
=
26
;
public
static
final
byte
SDK_OREO_MR1
=
27
;
public
static
final
byte
SDK_P
=
28
;
public
static
final
byte
ORIENTATION_ANY
=
0
;
public
static
final
byte
ORIENTATION_PORT
=
1
;
public
static
final
byte
ORIENTATION_LAND
=
2
;
public
static
final
byte
ORIENTATION_SQUARE
=
3
;
public
static
final
byte
TOUCHSCREEN_ANY
=
0
;
public
static
final
byte
TOUCHSCREEN_NOTOUCH
=
1
;
public
static
final
byte
TOUCHSCREEN_STYLUS
=
2
;
public
static
final
byte
TOUCHSCREEN_FINGER
=
3
;
public
static
final
int
DENSITY_DEFAULT
=
0
;
public
static
final
int
DENSITY_LOW
=
120
;
public
static
final
int
DENSITY_MEDIUM
=
160
;
public
static
final
int
DENSITY_400
=
190
;
public
static
final
int
DENSITY_TV
=
213
;
public
static
final
int
DENSITY_HIGH
=
240
;
public
static
final
int
DENSITY_XHIGH
=
320
;
public
static
final
int
DENSITY_XXHIGH
=
480
;
public
static
final
int
DENSITY_XXXHIGH
=
640
;
public
static
final
int
DENSITY_ANY
=
0xFFFE
;
public
static
final
int
DENSITY_NONE
=
0xFFFF
;
public
static
final
int
MNC_ZERO
=
-
1
;
public
static
final
short
MASK_LAYOUTDIR
=
0xc0
;
public
static
final
short
SCREENLAYOUT_LAYOUTDIR_ANY
=
0x00
;
public
static
final
short
SCREENLAYOUT_LAYOUTDIR_LTR
=
0x40
;
public
static
final
short
SCREENLAYOUT_LAYOUTDIR_RTL
=
0x80
;
public
static
final
short
SCREENLAYOUT_LAYOUTDIR_SHIFT
=
0x06
;
public
static
final
short
MASK_SCREENROUND
=
0x03
;
public
static
final
short
SCREENLAYOUT_ROUND_ANY
=
0
;
public
static
final
short
SCREENLAYOUT_ROUND_NO
=
0x1
;
public
static
final
short
SCREENLAYOUT_ROUND_YES
=
0x2
;
public
static
final
byte
KEYBOARD_ANY
=
0
;
public
static
final
byte
KEYBOARD_NOKEYS
=
1
;
public
static
final
byte
KEYBOARD_QWERTY
=
2
;
public
static
final
byte
KEYBOARD_12KEY
=
3
;
public
static
final
byte
NAVIGATION_ANY
=
0
;
public
static
final
byte
NAVIGATION_NONAV
=
1
;
public
static
final
byte
NAVIGATION_DPAD
=
2
;
public
static
final
byte
NAVIGATION_TRACKBALL
=
3
;
public
static
final
byte
NAVIGATION_WHEEL
=
4
;
public
static
final
byte
MASK_KEYSHIDDEN
=
0x3
;
public
static
final
byte
KEYSHIDDEN_ANY
=
0x0
;
public
static
final
byte
KEYSHIDDEN_NO
=
0x1
;
public
static
final
byte
KEYSHIDDEN_YES
=
0x2
;
public
static
final
byte
KEYSHIDDEN_SOFT
=
0x3
;
public
static
final
byte
MASK_NAVHIDDEN
=
0xc
;
public
static
final
byte
NAVHIDDEN_ANY
=
0x0
;
public
static
final
byte
NAVHIDDEN_NO
=
0x4
;
public
static
final
byte
NAVHIDDEN_YES
=
0x8
;
public
static
final
byte
MASK_SCREENSIZE
=
0x0f
;
public
static
final
byte
SCREENSIZE_ANY
=
0x00
;
public
static
final
byte
SCREENSIZE_SMALL
=
0x01
;
public
static
final
byte
SCREENSIZE_NORMAL
=
0x02
;
public
static
final
byte
SCREENSIZE_LARGE
=
0x03
;
public
static
final
byte
SCREENSIZE_XLARGE
=
0x04
;
public
static
final
byte
MASK_SCREENLONG
=
0x30
;
public
static
final
byte
SCREENLONG_ANY
=
0x00
;
public
static
final
byte
SCREENLONG_NO
=
0x10
;
public
static
final
byte
SCREENLONG_YES
=
0x20
;
public
static
final
byte
MASK_UI_MODE_TYPE
=
0x0f
;
public
static
final
byte
UI_MODE_TYPE_ANY
=
0x00
;
public
static
final
byte
UI_MODE_TYPE_NORMAL
=
0x01
;
public
static
final
byte
UI_MODE_TYPE_DESK
=
0x02
;
public
static
final
byte
UI_MODE_TYPE_CAR
=
0x03
;
public
static
final
byte
UI_MODE_TYPE_TELEVISION
=
0x04
;
public
static
final
byte
UI_MODE_TYPE_APPLIANCE
=
0x05
;
public
static
final
byte
UI_MODE_TYPE_WATCH
=
0x06
;
public
static
final
byte
UI_MODE_TYPE_VR_HEADSET
=
0x07
;
// start - miui
public
final
static
byte
UI_MODE_TYPE_GODZILLAUI
=
0x0b
;
public
final
static
byte
UI_MODE_TYPE_SMALLUI
=
0x0c
;
public
final
static
byte
UI_MODE_TYPE_MEDIUMUI
=
0x0d
;
public
final
static
byte
UI_MODE_TYPE_LARGEUI
=
0x0e
;
public
final
static
byte
UI_MODE_TYPE_HUGEUI
=
0x0f
;
public
static
final
byte
UI_MODE_TYPE_GODZILLAUI
=
0x0b
;
public
static
final
byte
UI_MODE_TYPE_SMALLUI
=
0x0c
;
public
static
final
byte
UI_MODE_TYPE_MEDIUMUI
=
0x0d
;
public
static
final
byte
UI_MODE_TYPE_LARGEUI
=
0x0e
;
public
static
final
byte
UI_MODE_TYPE_HUGEUI
=
0x0f
;
// end - miui
public
final
static
byte
MASK_UI_MODE_NIGHT
=
0x30
;
public
final
static
byte
UI_MODE_NIGHT_ANY
=
0x00
;
public
final
static
byte
UI_MODE_NIGHT_NO
=
0x10
;
public
final
static
byte
UI_MODE_NIGHT_YES
=
0x20
;
public
static
final
byte
MASK_UI_MODE_NIGHT
=
0x30
;
public
static
final
byte
UI_MODE_NIGHT_ANY
=
0x00
;
public
static
final
byte
UI_MODE_NIGHT_NO
=
0x10
;
public
static
final
byte
UI_MODE_NIGHT_YES
=
0x20
;
public
final
static
byte
COLOR_HDR_MASK
=
0xC
;
public
final
static
byte
COLOR_HDR_NO
=
0x4
;
public
final
static
byte
COLOR_HDR_SHIFT
=
0x2
;
public
final
static
byte
COLOR_HDR_UNDEFINED
=
0x0
;
public
final
static
byte
COLOR_HDR_YES
=
0x8
;
public
static
final
byte
COLOR_HDR_MASK
=
0xC
;
public
static
final
byte
COLOR_HDR_NO
=
0x4
;
public
static
final
byte
COLOR_HDR_SHIFT
=
0x2
;
public
static
final
byte
COLOR_HDR_UNDEFINED
=
0x0
;
public
static
final
byte
COLOR_HDR_YES
=
0x8
;
public
final
static
byte
COLOR_UNDEFINED
=
0x0
;
public
static
final
byte
COLOR_UNDEFINED
=
0x0
;
public
final
static
byte
COLOR_WIDE_UNDEFINED
=
0x0
;
public
final
static
byte
COLOR_WIDE_NO
=
0x1
;
public
final
static
byte
COLOR_WIDE_YES
=
0x2
;
public
final
static
byte
COLOR_WIDE_MASK
=
0x3
;
public
static
final
byte
COLOR_WIDE_UNDEFINED
=
0x0
;
public
static
final
byte
COLOR_WIDE_NO
=
0x1
;
public
static
final
byte
COLOR_WIDE_YES
=
0x2
;
public
static
final
byte
COLOR_WIDE_MASK
=
0x3
;
private
static
final
Logger
LOG
=
LoggerFactory
.
getLogger
(
EntryConfig
.
class
);
}
jadx-core/src/test/java/jadx/tests/integration/TestRedundantBrackets.java
View file @
7cdb0318
...
...
@@ -39,7 +39,7 @@ public class TestRedundantBrackets extends IntegrationTest {
}
}
public
void
method5
(
int
a
[]
,
int
n
)
{
public
void
method5
(
int
[]
a
,
int
n
)
{
a
[
1
]
=
n
*
2
;
a
[
n
-
1
]
=
1
;
}
...
...
jadx-core/src/test/java/jadx/tests/integration/annotations/TestAnnotations.java
View file @
7cdb0318
...
...
@@ -13,7 +13,7 @@ import static org.hamcrest.MatcherAssert.assertThat;
public
class
TestAnnotations
extends
IntegrationTest
{
public
static
class
TestCls
{
private
static
@interface
A
{
private
@interface
A
{
int
a
();
}
...
...
@@ -29,7 +29,7 @@ public class TestAnnotations extends IntegrationTest {
public
void
methodA3
()
{
}
private
static
@interface
V
{
private
@interface
V
{
boolean
value
();
}
...
...
@@ -37,7 +37,7 @@ public class TestAnnotations extends IntegrationTest {
public
void
methodV
()
{
}
private
static
@interface
D
{
private
@interface
D
{
float
value
()
default
1.1f
;
}
...
...
jadx-core/src/test/java/jadx/tests/integration/annotations/TestAnnotationsMix.java
View file @
7cdb0318
...
...
@@ -41,7 +41,7 @@ public class TestAnnotationsMix extends IntegrationTest {
assertTrue
(
ma
.
getAnnotations
().
length
>
0
);
MyAnnotation
a
=
(
MyAnnotation
)
ma
.
getAnnotations
()[
0
];
assertEquals
(
7
,
a
.
num
());
assertSame
(
a
.
state
(),
Thread
.
State
.
TERMINATED
);
assertSame
(
Thread
.
State
.
TERMINATED
,
a
.
state
()
);
return
true
;
}
...
...
jadx-core/src/test/java/jadx/tests/integration/conditions/TestTernary.java
View file @
7cdb0318
...
...
@@ -8,7 +8,6 @@ import jadx.tests.api.IntegrationTest;
import
static
org
.
hamcrest
.
CoreMatchers
.
containsString
;
import
static
org
.
hamcrest
.
CoreMatchers
.
not
;
import
static
org
.
hamcrest
.
MatcherAssert
.
assertThat
;
import
static
org
.
junit
.
jupiter
.
api
.
Assertions
.
assertTrue
;
public
class
TestTernary
extends
IntegrationTest
{
...
...
@@ -18,12 +17,14 @@ public class TestTernary extends IntegrationTest {
}
public
void
test2
(
int
a
)
{
assert
True
(
a
==
3
);
check
True
(
a
==
3
);
}
public
int
test3
(
int
a
)
{
return
a
>
0
?
a
:
(
a
+
2
)
*
3
;
}
private
static
void
checkTrue
(
boolean
v
)
{}
}
@Test
...
...
@@ -33,7 +34,7 @@ public class TestTernary extends IntegrationTest {
assertThat
(
code
,
not
(
containsString
(
"else"
)));
assertThat
(
code
,
containsString
(
"return a != 2;"
));
assertThat
(
code
,
containsString
(
"
assert
True(a == 3)"
));
assertThat
(
code
,
containsString
(
"
check
True(a == 3)"
));
assertThat
(
code
,
containsString
(
"return a > 0 ? a : (a + 2) * 3;"
));
}
}
jadx-core/src/test/java/jadx/tests/integration/enums/TestEnums3.java
View file @
7cdb0318
...
...
@@ -20,7 +20,7 @@ public class TestEnums3 extends IntegrationTest {
private
final
int
num
;
private
Numbers
(
int
n
)
{
Numbers
(
int
n
)
{
this
.
num
=
n
;
}
...
...
jadx-core/src/test/java/jadx/tests/integration/enums/TestEnums4.java
View file @
7cdb0318
...
...
@@ -24,7 +24,7 @@ public class TestEnums4 extends IntegrationTest {
private
final
String
[]
exts
;
private
ResType
(
String
...
extensions
)
{
ResType
(
String
...
extensions
)
{
this
.
exts
=
extensions
;
}
...
...
jadx-core/src/test/java/jadx/tests/integration/enums/TestEnumsInterface.java
View file @
7cdb0318
...
...
@@ -22,7 +22,7 @@ public class TestEnumsInterface extends IntegrationTest {
public
int
apply
(
int
x
,
int
y
)
{
return
x
-
y
;
}
}
;
}
}
public
interface
IOperation
{
...
...
jadx-core/src/test/java/jadx/tests/integration/inner/TestInnerClass5.java
View file @
7cdb0318
...
...
@@ -7,7 +7,7 @@ import jadx.tests.api.IntegrationTest;
import
static
jadx
.
tests
.
api
.
utils
.
JadxMatchers
.
containsOne
;
import
static
org
.
hamcrest
.
MatcherAssert
.
assertThat
;
import
static
org
.
junit
.
jupiter
.
api
.
Assertions
.
assert
True
;
import
static
org
.
junit
.
jupiter
.
api
.
Assertions
.
assert
Equals
;
public
class
TestInnerClass5
extends
IntegrationTest
{
...
...
@@ -83,8 +83,8 @@ public class TestInnerClass5 extends IntegrationTest {
}
public
void
check
()
throws
Exception
{
assert
True
(
new
I0
().
i
().
equals
(
"i-i0i1i0i1i2i0i1i2i1i2i3i1i2i3a"
));
assert
True
(
i0
.
equals
(
"i1"
)
);
assert
Equals
(
"i-i0i1i0i1i2i0i1i2i1i2i3i1i2i3a"
,
new
I0
().
i
(
));
assert
Equals
(
"i1"
,
i0
);
}
}
...
...
jadx-core/src/test/java/jadx/tests/integration/names/TestSameMethodsNames.java
View file @
7cdb0318
...
...
@@ -21,6 +21,7 @@ public class TestSameMethodsNames extends IntegrationTest {
System
.
out
.
println
(
"constructor"
);
}
@SuppressWarnings
(
"MethodNameSameAsClassName"
)
void
Bug
()
{
System
.
out
.
println
(
"Bug"
);
}
...
...
jadx-core/src/test/java/jadx/tests/integration/trycatch/TestTryCatchInIf.java
View file @
7cdb0318
...
...
@@ -8,6 +8,7 @@ import jadx.tests.api.IntegrationTest;
import
static
jadx
.
tests
.
api
.
utils
.
JadxMatchers
.
containsOne
;
import
static
org
.
hamcrest
.
MatcherAssert
.
assertThat
;
import
static
org
.
junit
.
jupiter
.
api
.
Assertions
.
assertEquals
;
import
static
org
.
junit
.
jupiter
.
api
.
Assertions
.
assertNull
;
public
class
TestTryCatchInIf
extends
IntegrationTest
{
...
...
@@ -33,7 +34,7 @@ public class TestTryCatchInIf extends IntegrationTest {
}
public
void
check
()
{
assert
Equals
(
null
,
test
(
"n"
,
null
));
assert
Null
(
test
(
"n"
,
null
));
assertEquals
(
"n=7"
,
test
(
"n"
,
"7"
));
assertEquals
(
"n=77"
,
test
(
"n"
,
"0x"
+
Integer
.
toHexString
(
77
)));
assertEquals
(
"Failed to parse number"
,
test
(
"n"
,
"abc"
));
...
...
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