Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
A
abc
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
lvzhengyang
abc
Commits
87541198
Commit
87541198
authored
Mar 19, 2017
by
Yen-Sheng Ho
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
%pdra: working on bmc3
parent
51fbf37c
Hide whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
196 additions
and
132 deletions
+196
-132
abclib.dsp
+4
-0
src/base/wlc/module.make
+1
-0
src/base/wlc/wlc.h
+23
-0
src/base/wlc/wlcAbs.c
+16
-132
src/base/wlc/wlcPth.c
+152
-0
No files found.
abclib.dsp
View file @
87541198
...
@@ -787,6 +787,10 @@ SOURCE=.\src\base\wlc\wlcAbs.c
...
@@ -787,6 +787,10 @@ SOURCE=.\src\base\wlc\wlcAbs.c
# End Source File
# End Source File
# Begin Source File
# Begin Source File
SOURCE=.\src\base\wlc\wlcPth.c
# End Source File
# Begin Source File
SOURCE=.\src\base\wlc\wlcAbs2.c
SOURCE=.\src\base\wlc\wlcAbs2.c
# End Source File
# End Source File
# Begin Source File
# Begin Source File
...
...
src/base/wlc/module.make
View file @
87541198
SRC
+=
src/base/wlc/wlcAbs.c
\
SRC
+=
src/base/wlc/wlcAbs.c
\
src/base/wlc/wlcAbs2.c
\
src/base/wlc/wlcAbs2.c
\
src/base/wlc/wlcAbc.c
\
src/base/wlc/wlcAbc.c
\
src/base/wlc/wlcPth.c
\
src/base/wlc/wlcBlast.c
\
src/base/wlc/wlcBlast.c
\
src/base/wlc/wlcCom.c
\
src/base/wlc/wlcCom.c
\
src/base/wlc/wlcGraft.c
\
src/base/wlc/wlcGraft.c
\
...
...
src/base/wlc/wlc.h
View file @
87541198
...
@@ -185,6 +185,29 @@ struct Wlc_Par_t_
...
@@ -185,6 +185,29 @@ struct Wlc_Par_t_
int
fPdrVerbose
;
// verbose output
int
fPdrVerbose
;
// verbose output
};
};
typedef
struct
Wla_Man_t_
Wla_Man_t
;
struct
Wla_Man_t_
{
Wlc_Ntk_t
*
p
;
Wlc_Par_t
*
pPars
;
Vec_Vec_t
*
vClauses
;
Vec_Int_t
*
vBlacks
;
Abc_Cex_t
*
pCex
;
Gia_Man_t
*
pGia
;
Vec_Bit_t
*
vUnmark
;
void
*
pPdrPars
;
void
*
pThread
;
int
nIters
;
int
nTotalCla
;
int
nDisj
;
int
nNDisj
;
abctime
tPdr
;
abctime
tCbr
;
abctime
tPbr
;
};
static
inline
int
Wlc_NtkObjNum
(
Wlc_Ntk_t
*
p
)
{
return
p
->
iObj
-
1
;
}
static
inline
int
Wlc_NtkObjNum
(
Wlc_Ntk_t
*
p
)
{
return
p
->
iObj
-
1
;
}
static
inline
int
Wlc_NtkObjNumMax
(
Wlc_Ntk_t
*
p
)
{
return
p
->
iObj
;
}
static
inline
int
Wlc_NtkObjNumMax
(
Wlc_Ntk_t
*
p
)
{
return
p
->
iObj
;
}
static
inline
int
Wlc_NtkPiNum
(
Wlc_Ntk_t
*
p
)
{
return
Vec_IntSize
(
&
p
->
vPis
);
}
static
inline
int
Wlc_NtkPiNum
(
Wlc_Ntk_t
*
p
)
{
return
Vec_IntSize
(
&
p
->
vPis
);
}
...
...
src/base/wlc/wlcAbs.c
View file @
87541198
...
@@ -25,17 +25,6 @@
...
@@ -25,17 +25,6 @@
#include "aig/gia/giaAig.h"
#include "aig/gia/giaAig.h"
#include "sat/bmc/bmc.h"
#include "sat/bmc/bmc.h"
#ifdef ABC_USE_PTHREADS
#ifdef _WIN32
#include "../lib/pthread.h"
#else
#include <pthread.h>
#include <unistd.h>
#endif
#endif
ABC_NAMESPACE_IMPL_START
ABC_NAMESPACE_IMPL_START
////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////
...
@@ -48,9 +37,10 @@ extern int IPdr_ManSolveInt( Pdr_Man_t * p, int fCheckClauses, int fPu
...
@@ -48,9 +37,10 @@ extern int IPdr_ManSolveInt( Pdr_Man_t * p, int fCheckClauses, int fPu
extern
int
IPdr_ManCheckCombUnsat
(
Pdr_Man_t
*
p
);
extern
int
IPdr_ManCheckCombUnsat
(
Pdr_Man_t
*
p
);
extern
int
IPdr_ManReduceClauses
(
Pdr_Man_t
*
p
,
Vec_Vec_t
*
vClauses
);
extern
int
IPdr_ManReduceClauses
(
Pdr_Man_t
*
p
,
Vec_Vec_t
*
vClauses
);
extern
void
IPdr_ManPrintClauses
(
Vec_Vec_t
*
vClauses
,
int
kStart
,
int
nRegs
);
extern
void
IPdr_ManPrintClauses
(
Vec_Vec_t
*
vClauses
,
int
kStart
,
int
nRegs
);
extern
Abc_Ntk_t
*
Abc_NtkFromAigPhase
(
Aig_Man_t
*
pAig
);
extern
void
Wla_ManJoinThread
(
Wla_Man_t
*
pWla
,
int
RunId
);
extern
int
Abc_NtkDarBmc3
(
Abc_Ntk_t
*
pAbcNtk
,
Saig_ParBmc_t
*
pBmcPars
,
int
fOrDecomp
);
extern
void
Wla_ManConcurrentBmc3
(
Wla_Man_t
*
pWla
,
Aig_Man_t
*
pAig
,
Abc_Cex_t
**
ppCex
);
extern
int
Abs_CallBackToStop
(
int
RunId
);
extern
int
Wla_CallBackToStop
(
int
RunId
);
extern
int
Wla_GetGlobalRunId
();
typedef
struct
Int_Pair_t_
Int_Pair_t
;
typedef
struct
Int_Pair_t_
Int_Pair_t
;
struct
Int_Pair_t_
struct
Int_Pair_t_
...
@@ -59,42 +49,6 @@ struct Int_Pair_t_
...
@@ -59,42 +49,6 @@ struct Int_Pair_t_
int
second
;
int
second
;
};
};
typedef
struct
Wla_Man_t_
Wla_Man_t
;
struct
Wla_Man_t_
{
Wlc_Ntk_t
*
p
;
Wlc_Par_t
*
pPars
;
Pdr_Par_t
*
pPdrPars
;
Vec_Vec_t
*
vClauses
;
Vec_Int_t
*
vBlacks
;
Abc_Cex_t
*
pCex
;
Gia_Man_t
*
pGia
;
Vec_Bit_t
*
vUnmark
;
int
nIters
;
int
nTotalCla
;
int
nDisj
;
int
nNDisj
;
abctime
tPdr
;
abctime
tCbr
;
abctime
tPbr
;
};
// information given to the thread
typedef
struct
Bmc3_ThData_t_
{
Aig_Man_t
*
pAig
;
Abc_Cex_t
**
ppCex
;
int
RunId
;
int
fVerbose
;
}
Bmc3_ThData_t
;
// mutext to control access to shared variables
extern
pthread_mutex_t
g_mutex
;
static
volatile
int
g_nRunIds
=
0
;
// the number of the last prover instance
static
int
Wla_CallBackToStop
(
int
RunId
)
{
assert
(
RunId
<=
g_nRunIds
);
return
RunId
<
g_nRunIds
;
}
int
IntPairPtrCompare
(
Int_Pair_t
**
a
,
Int_Pair_t
**
b
)
int
IntPairPtrCompare
(
Int_Pair_t
**
a
,
Int_Pair_t
**
b
)
{
{
return
(
*
a
)
->
second
<
(
*
b
)
->
second
;
return
(
*
a
)
->
second
<
(
*
b
)
->
second
;
...
@@ -1282,6 +1236,7 @@ Aig_Man_t * Wla_ManBitBlast( Wla_Man_t * pWla, Wlc_Ntk_t * pAbs )
...
@@ -1282,6 +1236,7 @@ Aig_Man_t * Wla_ManBitBlast( Wla_Man_t * pWla, Wlc_Ntk_t * pAbs )
int
Wla_ManCheckCombUnsat
(
Wla_Man_t
*
pWla
,
Aig_Man_t
*
pAig
)
int
Wla_ManCheckCombUnsat
(
Wla_Man_t
*
pWla
,
Aig_Man_t
*
pAig
)
{
{
Pdr_Man_t
*
pPdr
;
Pdr_Man_t
*
pPdr
;
Pdr_Par_t
*
pPdrPars
=
(
Pdr_Par_t
*
)
pWla
->
pPdrPars
;
abctime
clk
;
abctime
clk
;
int
RetValue
=
-
1
;
int
RetValue
=
-
1
;
...
@@ -1316,84 +1271,25 @@ int Wla_ManCheckCombUnsat( Wla_Man_t * pWla, Aig_Man_t * pAig )
...
@@ -1316,84 +1271,25 @@ int Wla_ManCheckCombUnsat( Wla_Man_t * pWla, Aig_Man_t * pAig )
clk
=
Abc_Clock
();
clk
=
Abc_Clock
();
p
Wla
->
p
PdrPars
->
fVerbose
=
0
;
pPdrPars
->
fVerbose
=
0
;
pPdr
=
Pdr_ManStart
(
pAig
,
p
Wla
->
p
PdrPars
,
NULL
);
pPdr
=
Pdr_ManStart
(
pAig
,
pPdrPars
,
NULL
);
RetValue
=
IPdr_ManCheckCombUnsat
(
pPdr
);
RetValue
=
IPdr_ManCheckCombUnsat
(
pPdr
);
Pdr_ManStop
(
pPdr
);
Pdr_ManStop
(
pPdr
);
p
Wla
->
p
PdrPars
->
fVerbose
=
pWla
->
pPars
->
fPdrVerbose
;
pPdrPars
->
fVerbose
=
pWla
->
pPars
->
fPdrVerbose
;
pWla
->
tPdr
+=
Abc_Clock
()
-
clk
;
pWla
->
tPdr
+=
Abc_Clock
()
-
clk
;
return
RetValue
;
return
RetValue
;
}
}
void
*
Wla_Bmc3Thread
(
void
*
pArg
)
{
int
status
;
int
RetValue
=
-
1
;
Bmc3_ThData_t
*
pData
=
(
Bmc3_ThData_t
*
)
pArg
;
Abc_Ntk_t
*
pAbcNtk
=
Abc_NtkFromAigPhase
(
pData
->
pAig
);
Saig_ParBmc_t
BmcPars
,
*
pBmcPars
=
&
BmcPars
;
Saig_ParBmcSetDefaultParams
(
pBmcPars
);
pBmcPars
->
pFuncStop
=
Wla_CallBackToStop
;
pBmcPars
->
RunId
=
pData
->
RunId
;
RetValue
=
Abc_NtkDarBmc3
(
pAbcNtk
,
pBmcPars
,
0
);
if
(
RetValue
==
0
)
{
assert
(
pAbcNtk
->
pSeqModel
);
*
(
pData
->
ppCex
)
=
pAbcNtk
->
pSeqModel
;
pAbcNtk
->
pSeqModel
=
NULL
;
if
(
pData
->
fVerbose
)
Abc_Print
(
1
,
"Bmc3 found CEX. RunId=%d.
\n
"
,
pData
->
RunId
);
status
=
pthread_mutex_lock
(
&
g_mutex
);
assert
(
status
==
0
);
++
g_nRunIds
;
status
=
pthread_mutex_unlock
(
&
g_mutex
);
assert
(
status
==
0
);
}
else
{
if
(
pData
->
fVerbose
)
Abc_Print
(
1
,
"Bmc3 was cancelled. RunId=%d.
\n
"
,
pData
->
RunId
);
}
// free memory
Abc_NtkDelete
(
pAbcNtk
);
Aig_ManStop
(
pData
->
pAig
);
ABC_FREE
(
pData
);
// quit this thread
pthread_exit
(
NULL
);
assert
(
0
);
return
NULL
;
}
void
Wla_ManConcurrentBmc3
(
pthread_t
*
pThread
,
Aig_Man_t
*
pAig
,
Abc_Cex_t
**
ppCex
,
int
fVerbose
)
{
int
status
;
Bmc3_ThData_t
*
pData
;
pData
=
ABC_CALLOC
(
Bmc3_ThData_t
,
1
);
pData
->
pAig
=
pAig
;
pData
->
ppCex
=
ppCex
;
pData
->
RunId
=
g_nRunIds
;
pData
->
fVerbose
=
fVerbose
;
status
=
pthread_create
(
pThread
,
NULL
,
Wla_Bmc3Thread
,
pData
);
assert
(
status
==
0
);
}
int
Wla_ManSolve
(
Wla_Man_t
*
pWla
,
Aig_Man_t
*
pAig
)
int
Wla_ManSolve
(
Wla_Man_t
*
pWla
,
Aig_Man_t
*
pAig
)
{
{
abctime
clk
;
abctime
clk
;
Pdr_Man_t
*
pPdr
;
Pdr_Man_t
*
pPdr
;
Pdr_Par_t
*
pPdrPars
=
(
Pdr_Par_t
*
)
pWla
->
pPdrPars
;
Abc_Cex_t
*
pBmcCex
=
NULL
;
Abc_Cex_t
*
pBmcCex
=
NULL
;
pthread_t
*
pBmc3Thread
=
NULL
;
int
RetValue
=
-
1
;
int
RetValue
=
-
1
;
int
status
;
int
RunId
=
Wla_GetGlobalRunId
();
int
RunId
=
g_nRunIds
;
if
(
pWla
->
vClauses
&&
pWla
->
pPars
->
fCheckCombUnsat
)
if
(
pWla
->
vClauses
&&
pWla
->
pPars
->
fCheckCombUnsat
)
{
{
...
@@ -1413,15 +1309,14 @@ int Wla_ManSolve( Wla_Man_t * pWla, Aig_Man_t * pAig )
...
@@ -1413,15 +1309,14 @@ int Wla_ManSolve( Wla_Man_t * pWla, Aig_Man_t * pAig )
if
(
pWla
->
pPars
->
fUseBmc3
)
if
(
pWla
->
pPars
->
fUseBmc3
)
{
{
p
Wla
->
pPdrPars
->
RunId
=
g_nRunIds
;
p
PdrPars
->
RunId
=
RunId
;
p
Wla
->
p
PdrPars
->
pFuncStop
=
Wla_CallBackToStop
;
pPdrPars
->
pFuncStop
=
Wla_CallBackToStop
;
pBmc3Thread
=
ABC_CALLOC
(
pthread_t
,
1
);
Wla_ManConcurrentBmc3
(
pWla
,
Aig_ManDupSimple
(
pAig
),
&
pBmcCex
);
Wla_ManConcurrentBmc3
(
pBmc3Thread
,
Aig_ManDupSimple
(
pAig
),
&
pBmcCex
,
pWla
->
pPars
->
fVerbose
);
}
}
clk
=
Abc_Clock
();
clk
=
Abc_Clock
();
pPdr
=
Pdr_ManStart
(
pAig
,
p
Wla
->
p
PdrPars
,
NULL
);
pPdr
=
Pdr_ManStart
(
pAig
,
pPdrPars
,
NULL
);
if
(
pWla
->
vClauses
)
{
if
(
pWla
->
vClauses
)
{
assert
(
Vec_VecSize
(
pWla
->
vClauses
)
>=
2
);
assert
(
Vec_VecSize
(
pWla
->
vClauses
)
>=
2
);
IPdr_ManRestore
(
pPdr
,
pWla
->
vClauses
,
NULL
);
IPdr_ManRestore
(
pPdr
,
pWla
->
vClauses
,
NULL
);
...
@@ -1435,18 +1330,7 @@ int Wla_ManSolve( Wla_Man_t * pWla, Aig_Man_t * pAig )
...
@@ -1435,18 +1330,7 @@ int Wla_ManSolve( Wla_Man_t * pWla, Aig_Man_t * pAig )
if
(
pWla
->
pPars
->
fUseBmc3
)
if
(
pWla
->
pPars
->
fUseBmc3
)
{
Wla_ManJoinThread
(
pWla
,
RunId
);
if
(
RunId
==
g_nRunIds
)
{
status
=
pthread_mutex_lock
(
&
g_mutex
);
assert
(
status
==
0
);
++
g_nRunIds
;
status
=
pthread_mutex_unlock
(
&
g_mutex
);
assert
(
status
==
0
);
}
status
=
pthread_join
(
*
pBmc3Thread
,
NULL
);
assert
(
status
==
0
);
ABC_FREE
(
pBmc3Thread
);
}
if
(
pBmcCex
)
if
(
pBmcCex
)
{
{
...
@@ -1551,7 +1435,7 @@ Wla_Man_t * Wla_ManStart( Wlc_Ntk_t * pNtk, Wlc_Par_t * pPars )
...
@@ -1551,7 +1435,7 @@ Wla_Man_t * Wla_ManStart( Wlc_Ntk_t * pNtk, Wlc_Par_t * pPars )
pPdrPars
->
fSkipDown
=
0
;
// use 'pdr -nc' (improved generalization)
pPdrPars
->
fSkipDown
=
0
;
// use 'pdr -nc' (improved generalization)
pPdrPars
->
nRestLimit
=
500
;
// reset queue or proof-obligations when it gets larger than this
pPdrPars
->
nRestLimit
=
500
;
// reset queue or proof-obligations when it gets larger than this
}
}
p
->
pPdrPars
=
pPdrPars
;
p
->
pPdrPars
=
(
void
*
)
pPdrPars
;
p
->
nIters
=
1
;
p
->
nIters
=
1
;
p
->
nTotalCla
=
0
;
p
->
nTotalCla
=
0
;
...
...
src/base/wlc/wlcPth.c
0 → 100644
View file @
87541198
/**CFile****************************************************************
FileName [wlcPth.c]
SystemName [ABC: Logic synthesis and verification system.]
PackageName [Verilog parser.]
Synopsis [Abstraction for word-level networks.]
Author [Yen-Sheng Ho, Alan Mishchenko]
Affiliation [UC Berkeley]
Date [Ver. 1.0. Started - June 20, 2005.]
Revision [$Id: wlcPth.c $]
***********************************************************************/
#include "wlc.h"
#include "sat/bmc/bmc.h"
#ifdef ABC_USE_PTHREADS
#ifdef _WIN32
#include "../lib/pthread.h"
#else
#include <pthread.h>
#include <unistd.h>
#endif
#endif
ABC_NAMESPACE_IMPL_START
////////////////////////////////////////////////////////////////////////
/// DECLARATIONS ///
////////////////////////////////////////////////////////////////////////
extern
Abc_Ntk_t
*
Abc_NtkFromAigPhase
(
Aig_Man_t
*
pAig
);
extern
int
Abc_NtkDarBmc3
(
Abc_Ntk_t
*
pAbcNtk
,
Saig_ParBmc_t
*
pBmcPars
,
int
fOrDecomp
);
static
volatile
int
g_nRunIds
=
0
;
// the number of the last prover instance
int
Wla_CallBackToStop
(
int
RunId
)
{
assert
(
RunId
<=
g_nRunIds
);
return
RunId
<
g_nRunIds
;
}
int
Wla_GetGlobalRunId
()
{
return
g_nRunIds
;
}
#ifndef ABC_USE_PTHREADS
void
Wla_ManJoinThread
(
Wla_Man_t
*
pWla
,
int
RunId
)
{}
void
Wla_ManConcurrentBmc3
(
Wla_Man_t
*
pWla
,
Aig_Man_t
*
pAig
,
Abc_Cex_t
**
ppCex
)
{}
#else // pthreads are used
// information given to the thread
typedef
struct
Bmc3_ThData_t_
{
Aig_Man_t
*
pAig
;
Abc_Cex_t
**
ppCex
;
int
RunId
;
int
fVerbose
;
}
Bmc3_ThData_t
;
// mutext to control access to shared variables
extern
pthread_mutex_t
g_mutex
;
void
Wla_ManJoinThread
(
Wla_Man_t
*
pWla
,
int
RunId
)
{
int
status
;
if
(
RunId
==
g_nRunIds
)
{
status
=
pthread_mutex_lock
(
&
g_mutex
);
assert
(
status
==
0
);
++
g_nRunIds
;
status
=
pthread_mutex_unlock
(
&
g_mutex
);
assert
(
status
==
0
);
}
status
=
pthread_join
(
*
(
pthread_t
*
)(
pWla
->
pThread
),
NULL
);
assert
(
status
==
0
);
ABC_FREE
(
pWla
->
pThread
);
pWla
->
pThread
=
NULL
;
}
void
*
Wla_Bmc3Thread
(
void
*
pArg
)
{
int
status
;
int
RetValue
=
-
1
;
Bmc3_ThData_t
*
pData
=
(
Bmc3_ThData_t
*
)
pArg
;
Abc_Ntk_t
*
pAbcNtk
=
Abc_NtkFromAigPhase
(
pData
->
pAig
);
Saig_ParBmc_t
BmcPars
,
*
pBmcPars
=
&
BmcPars
;
Saig_ParBmcSetDefaultParams
(
pBmcPars
);
pBmcPars
->
pFuncStop
=
Wla_CallBackToStop
;
pBmcPars
->
RunId
=
pData
->
RunId
;
RetValue
=
Abc_NtkDarBmc3
(
pAbcNtk
,
pBmcPars
,
0
);
if
(
RetValue
==
0
)
{
assert
(
pAbcNtk
->
pSeqModel
);
*
(
pData
->
ppCex
)
=
pAbcNtk
->
pSeqModel
;
pAbcNtk
->
pSeqModel
=
NULL
;
if
(
pData
->
fVerbose
)
Abc_Print
(
1
,
"Bmc3 found CEX. RunId=%d.
\n
"
,
pData
->
RunId
);
status
=
pthread_mutex_lock
(
&
g_mutex
);
assert
(
status
==
0
);
++
g_nRunIds
;
status
=
pthread_mutex_unlock
(
&
g_mutex
);
assert
(
status
==
0
);
}
else
{
if
(
pData
->
fVerbose
)
Abc_Print
(
1
,
"Bmc3 was cancelled. RunId=%d.
\n
"
,
pData
->
RunId
);
}
// free memory
Abc_NtkDelete
(
pAbcNtk
);
Aig_ManStop
(
pData
->
pAig
);
ABC_FREE
(
pData
);
// quit this thread
pthread_exit
(
NULL
);
assert
(
0
);
return
NULL
;
}
void
Wla_ManConcurrentBmc3
(
Wla_Man_t
*
pWla
,
Aig_Man_t
*
pAig
,
Abc_Cex_t
**
ppCex
)
{
int
status
;
Bmc3_ThData_t
*
pData
;
assert
(
pWla
->
pThread
==
NULL
);
pWla
->
pThread
=
(
void
*
)
ABC_CALLOC
(
pthread_t
,
1
);
pData
=
ABC_CALLOC
(
Bmc3_ThData_t
,
1
);
pData
->
pAig
=
pAig
;
pData
->
ppCex
=
ppCex
;
pData
->
RunId
=
g_nRunIds
;
pData
->
fVerbose
=
pWla
->
pPars
->
fVerbose
;
status
=
pthread_create
(
(
pthread_t
*
)
pWla
->
pThread
,
NULL
,
Wla_Bmc3Thread
,
pData
);
assert
(
status
==
0
);
}
#endif // pthreads are used
////////////////////////////////////////////////////////////////////////
/// END OF FILE ///
////////////////////////////////////////////////////////////////////////
ABC_NAMESPACE_IMPL_END
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