Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
K
kicad-source-mirror
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Commits
Open sidebar
Elphel
kicad-source-mirror
Commits
2b0a25b4
Commit
2b0a25b4
authored
Apr 16, 2008
by
charras
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
In complex hierarchies, multiples parts per packages now should work, without restrictions
parent
c77c3906
Changes
12
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
12 changed files
with
1257 additions
and
1135 deletions
+1257
-1135
change_log.txt
change_log.txt
+8
-1
annotate.cpp
eeschema/annotate.cpp
+17
-15
class_drawsheet.cpp
eeschema/class_drawsheet.cpp
+11
-4
class_drawsheet.h
eeschema/class_drawsheet.h
+16
-1
component_class.cpp
eeschema/component_class.cpp
+84
-15
component_class.h
eeschema/component_class.h
+12
-2
eeredraw.cpp
eeschema/eeredraw.cpp
+7
-3
hierarch.cpp
eeschema/hierarch.cpp
+2
-4
load_one_schematic_file.cpp
eeschema/load_one_schematic_file.cpp
+15
-13
build_version.h
include/build_version.h
+1
-1
kicad.mo
internat/fr/kicad.mo
+0
-0
kicad.po
internat/fr/kicad.po
+1084
-1076
No files found.
change_log.txt
View file @
2b0a25b4
...
...
@@ -5,7 +5,14 @@ Started 2007-June-11
Please add newer entries at the top, list the date and your name with
email address.
2008-Apr-14 UPDATE Jean-Pierre Charras <jean-pierre.charras@inpg.fr>
2008-Apr-16 UPDATE Jean-Pierre Charras <jean-pierre.charras@inpg.fr>
================================================================================
+eeschema
In complex hierarchies, multiples parts per packages now should work,
without restrictions
2008-Apr-15 UPDATE Jean-Pierre Charras <jean-pierre.charras@inpg.fr>
================================================================================
+eeschema
More code cleaning and Files cleaning and reorganization.
...
...
eeschema/annotate.cpp
View file @
2b0a25b4
...
...
@@ -265,7 +265,7 @@ void AnnotateComponents( WinEDA_SchematicFrame* parent,
BaseListeCmp
=
AllocateCmpListStrct
(
NbOfCmp
);
/* Second pass : Int data tables */
/* Second pass : In
i
t data tables */
if
(
annotateSchematic
)
{
ii
=
0
;
...
...
@@ -334,7 +334,7 @@ int ListeComposants( CmpListStruct* BaseListeCmp, DrawSheetPath* sheet )
BaseListeCmp
[
NbrCmp
].
m_Cmp
=
DrawLibItem
;
BaseListeCmp
[
NbrCmp
].
m_NbParts
=
Entry
->
m_UnitCount
;
BaseListeCmp
[
NbrCmp
].
m_Unit
=
DrawLibItem
->
m_Multi
;
BaseListeCmp
[
NbrCmp
].
m_Unit
=
DrawLibItem
->
GetUnitSelection
(
sheet
);
// DrawLibItem->
m_Multi;
BaseListeCmp
[
NbrCmp
].
m_PartsLocked
=
Entry
->
m_UnitSelectionLocked
;
BaseListeCmp
[
NbrCmp
].
m_SheetList
=
*
sheet
;
BaseListeCmp
[
NbrCmp
].
m_IsNew
=
FALSE
;
...
...
@@ -386,6 +386,7 @@ static void ReAnnotateComponents( CmpListStruct* BaseListeCmp, int NbOfCmp )
DrawLibItem
->
SetRef
(
&
(
BaseListeCmp
[
ii
].
m_SheetList
),
CONV_FROM_UTF8
(
Text
)
);
DrawLibItem
->
m_Multi
=
BaseListeCmp
[
ii
].
m_Unit
;
DrawLibItem
->
SetUnitSelection
(
&
(
BaseListeCmp
[
ii
].
m_SheetList
),
DrawLibItem
->
m_Multi
);
}
}
...
...
@@ -587,12 +588,14 @@ int GetLastReferenceNumber( CmpListStruct* Objet,
/*****************************************************************************
* TODO: Translate this to english/
* Recherche dans la liste triee des composants, pour les composants
* multiples s'il existe pour le composant de reference Objet,
* une unite de numero Unit
* Retourne index dans BaseListeCmp si oui
* retourne -1 si non
* Search in the sorted list of components, for a given componen,t an other component
* with the same reference and a given part unit.
* Mainly used to manage multiple parts per package components
* @param Objet = the given CmpListStruct* item to test
* @param Unit = the given unit number to search
* @param BaseListeCmp = list of items to examine
* @param NbOfCmp = size of list
* @return index in BaseListeCmp if found or -1 if not found
*****************************************************************************/
static
int
ExistUnit
(
CmpListStruct
*
Objet
,
int
Unit
,
CmpListStruct
*
BaseListeCmp
,
int
NbOfCmp
)
...
...
@@ -609,16 +612,15 @@ static int ExistUnit( CmpListStruct* Objet, int Unit,
ItemToTest
<
EndList
;
ItemToTest
++
,
ii
++
)
{
if
(
Objet
==
ItemToTest
)
if
(
Objet
==
ItemToTest
)
// Do not compare with itself !
continue
;
if
(
ItemToTest
->
m_IsNew
)
continue
;
/* non affecte */
if
(
ItemToTest
->
m_NumRef
!=
NumRef
)
if
(
ItemToTest
->
m_IsNew
)
// Not already with an updated reference
continue
;
/* Nouveau Identificateur */
if
(
strnicmp
(
RefText
,
ItemToTest
->
m_TextRef
,
32
)
!=
0
)
if
(
ItemToTest
->
m_NumRef
!=
NumRef
)
// Not the same reference number (like 35 in R35)
continue
;
if
(
strnicmp
(
RefText
,
ItemToTest
->
m_TextRef
,
32
)
!=
0
)
// Not the same reference prefix
continue
;
if
(
ItemToTest
->
m_Unit
==
Unit
)
if
(
ItemToTest
->
m_Unit
==
Unit
)
// A part with the same reference and the given unit is found
{
return
ii
;
}
...
...
eeschema/class_drawsheet.cpp
View file @
2b0a25b4
...
...
@@ -772,7 +772,15 @@ wxString DrawSheetPath::PathHumanReadable()
}
/***********************************************/
void
DrawSheetPath
::
UpdateAllScreenReferences
()
/***********************************************/
/** Function UpdateAllScreenReferences
* Update the reference and the m_Multi parameter (part selection) for all components on a screen
* depending on the actual sheet path.
* Mandatory in complex hierarchies sheets use the same screen (basic schematic)
* but with different references and part selection according to the displayed sheet
*/
{
EDA_BaseStruct
*
t
=
LastDrawList
();
...
...
@@ -780,13 +788,12 @@ void DrawSheetPath::UpdateAllScreenReferences()
{
if
(
t
->
Type
()
==
TYPE_SCH_COMPONENT
)
{
SCH_COMPONENT
*
d
=
(
SCH_COMPONENT
*
)
t
;
d
->
m_Field
[
REFERENCE
].
m_Text
=
d
->
GetRef
(
this
);
SCH_COMPONENT
*
component
=
(
SCH_COMPONENT
*
)
t
;
component
->
m_Field
[
REFERENCE
].
m_Text
=
component
->
GetRef
(
this
);
component
->
m_Multi
=
component
->
GetUnitSelection
(
this
);
}
t
=
t
->
Pnext
;
}
printf
(
"on sheet: %s
\n
"
,
CONV_TO_UTF8
(
PathHumanReadable
()
)
);
}
...
...
eeschema/class_drawsheet.h
View file @
2b0a25b4
...
...
@@ -127,7 +127,7 @@ public:
/* class to handle a series of sheets *********/
/* a 'path' so to speak.. *********************/
/**********************************************/
#define DSLSZ 32
#define DSLSZ 32
// Max number of levels for a sheet path
class
DrawSheetPath
{
public
:
...
...
@@ -143,8 +143,23 @@ public:
EDA_BaseStruct
*
LastDrawList
();
void
Push
(
DrawSheetStruct
*
sheet
);
DrawSheetStruct
*
Pop
();
/** Function Path
* the path uses the time stamps which do not changes even when editing sheet parameters
* a path is something like / (root) or /34005677 or /34005677/00AE4523
*/
wxString
Path
();
/** Function PathHumanReadable
* Return the sheet path in a readable form, i.e.
* as a path made from sheet names.
* (the "normal" path uses the time stamps which do not changes even when editing sheet parameters)
*/
wxString
PathHumanReadable
();
/** Function UpdateAllScreenReferences
* Update the reference and the m_Multi parameter (part selection) for all components on a screen
* depending on the actual sheet path.
* Mandatory in complex hierarchies because sheets use the same screen (basic schematic)
* but with different references and part selection according to the displayed sheet
*/
void
UpdateAllScreenReferences
();
bool
operator
=
(
const
DrawSheetPath
&
d1
);
...
...
eeschema/component_class.cpp
View file @
2b0a25b4
...
...
@@ -27,12 +27,14 @@ WX_DEFINE_OBJARRAY( ArrayOfSheetLists );
/** Function AddHierarchicalReference
* Add a full hierachical reference (path + local reference)
* @param path = hierarchical path (/<sheet timestamp>/component timestamp> like /05678E50/A23EF560)
* @param ref = local reference like C45, R56
* @param aPath = hierarchical path (/<sheet timestamp>/component timestamp> like /05678E50/A23EF560)
* @param aRef = local reference like C45, R56
* @param aMulti = part selection, used in multi part per package (0 or 1 for non multi)
*/
void
SCH_COMPONENT
::
AddHierarchicalReference
(
const
wxString
&
path
,
const
wxString
&
ref
)
void
SCH_COMPONENT
::
AddHierarchicalReference
(
const
wxString
&
aPath
,
const
wxString
&
aRef
,
int
aMulti
)
{
wxString
h_path
,
h_ref
;
wxStringTokenizer
tokenizer
;
wxString
separators
(
wxT
(
" "
)
);
...
...
@@ -42,16 +44,16 @@ void SCH_COMPONENT::AddHierarchicalReference( const wxString& path, const wxStri
{
tokenizer
.
SetString
(
m_PathsAndReferences
[
ii
],
separators
);
h_path
=
tokenizer
.
GetNextToken
();
if
(
h_path
.
Cmp
(
p
ath
)
==
0
)
if
(
h_path
.
Cmp
(
aP
ath
)
==
0
)
{
m_PathsAndReferences
.
RemoveAt
(
ii
);
ii
--
;
m_PathsAndReferences
.
RemoveAt
(
ii
);
ii
--
;
}
}
h_ref
=
path
+
wxT
(
" "
)
+
r
ef
;
h_ref
=
aPath
+
wxT
(
" "
)
+
aR
ef
;
h_ref
<<
wxT
(
" "
)
<<
m_
Multi
;
h_ref
<<
wxT
(
" "
)
<<
a
Multi
;
m_PathsAndReferences
.
Add
(
h_ref
);
}
...
...
@@ -156,16 +158,15 @@ const wxString SCH_COMPONENT::GetRef( DrawSheetPath* sheet )
void
SCH_COMPONENT
::
SetRef
(
DrawSheetPath
*
sheet
,
const
wxString
&
ref
)
/***********************************************************************/
{
//check to see if it is already there before inserting it
wxString
path
=
GetPath
(
sheet
);
// printf( "SetRef path: %s ref: %s\n", CONV_TO_UTF8( path ), CONV_TO_UTF8( ref ) ); // Debug
bool
notInArray
=
true
;
wxString
h_path
,
h_ref
;
wxStringTokenizer
tokenizer
;
wxString
separators
(
wxT
(
" "
)
);
//check to see if it is already there before inserting it
for
(
unsigned
ii
=
0
;
ii
<
m_PathsAndReferences
.
GetCount
();
ii
++
)
{
tokenizer
.
SetString
(
m_PathsAndReferences
[
ii
],
separators
);
...
...
@@ -184,7 +185,7 @@ void SCH_COMPONENT::SetRef( DrawSheetPath* sheet, const wxString& ref )
}
if
(
notInArray
)
AddHierarchicalReference
(
path
,
ref
);
AddHierarchicalReference
(
path
,
ref
,
m_Multi
);
if
(
m_Field
[
REFERENCE
].
m_Text
.
IsEmpty
()
||
(
abs
(
m_Field
[
REFERENCE
].
m_Pos
.
x
-
m_Pos
.
x
)
+
...
...
@@ -199,6 +200,74 @@ void SCH_COMPONENT::SetRef( DrawSheetPath* sheet, const wxString& ref )
}
/***********************************************************/
int
SCH_COMPONENT
::
GetUnitSelection
(
DrawSheetPath
*
aSheet
)
/***********************************************************/
//returns the unit selection, for the given sheet path.
{
wxString
path
=
GetPath
(
aSheet
);
wxString
h_path
,
h_multi
;
wxStringTokenizer
tokenizer
;
wxString
separators
(
wxT
(
" "
)
);
for
(
unsigned
ii
=
0
;
ii
<
m_PathsAndReferences
.
GetCount
();
ii
++
)
{
tokenizer
.
SetString
(
m_PathsAndReferences
[
ii
],
separators
);
h_path
=
tokenizer
.
GetNextToken
();
if
(
h_path
.
Cmp
(
path
)
==
0
)
{
tokenizer
.
GetNextToken
();
// Skip reference
h_multi
=
tokenizer
.
GetNextToken
();
long
imulti
=
1
;
h_multi
.
ToLong
(
&
imulti
);
return
imulti
;
}
}
//if it was not found in m_Paths array, then use m_Multi.
// this will happen if we load a version 1 schematic file.
return
m_Multi
;
}
/********************************************************************************/
void
SCH_COMPONENT
::
SetUnitSelection
(
DrawSheetPath
*
aSheet
,
int
aUnitSelection
)
/********************************************************************************/
//Set the unit selection, for the given sheet path.
{
wxString
path
=
GetPath
(
aSheet
);
bool
notInArray
=
true
;
wxString
h_path
,
h_ref
;
wxStringTokenizer
tokenizer
;
wxString
separators
(
wxT
(
" "
)
);
//check to see if it is already there before inserting it
for
(
unsigned
ii
=
0
;
ii
<
m_PathsAndReferences
.
GetCount
();
ii
++
)
{
tokenizer
.
SetString
(
m_PathsAndReferences
[
ii
],
separators
);
h_path
=
tokenizer
.
GetNextToken
();
if
(
h_path
.
Cmp
(
path
)
==
0
)
{
//just update the unit selection.
h_ref
=
h_path
+
wxT
(
" "
);
h_ref
+=
tokenizer
.
GetNextToken
();
// Add reference
h_ref
+=
wxT
(
" "
);
h_ref
<<
aUnitSelection
;
// Add part selection
// Ann the part selection
m_PathsAndReferences
[
ii
]
=
h_ref
;
notInArray
=
false
;
}
}
if
(
notInArray
)
AddHierarchicalReference
(
path
,
m_PrefixString
,
aUnitSelection
);
}
/******************************************************************/
const
wxString
&
SCH_COMPONENT
::
GetFieldValue
(
int
aFieldNdx
)
const
/******************************************************************/
...
...
@@ -992,9 +1061,9 @@ bool SCH_COMPONENT::Save( FILE* f ) const
}
/* If this is a complex hierarchy; save hierarchical references.
* but for simple hierarchies it is not necessary.
* the reference inf is already saved
* this is usefull for old eeschema version compatibility
* but for simple hierarchies it is not necessary.
* the reference inf is already saved
* this is usefull for old eeschema version compatibility
*/
if
(
m_PathsAndReferences
.
GetCount
()
>
1
)
{
...
...
eeschema/component_class.h
View file @
2b0a25b4
...
...
@@ -164,15 +164,25 @@ public:
void
SwapData
(
SCH_COMPONENT
*
copyitem
);
v
irtual
void
Place
(
WinEDA_DrawFrame
*
frame
,
wxDC
*
DC
);
v
oid
Place
(
WinEDA_DrawFrame
*
frame
,
wxDC
*
DC
);
//returns a unique ID, in the form of a path.
wxString
GetPath
(
DrawSheetPath
*
sheet
);
//returns the reference, for the given sheet path.
const
wxString
GetRef
(
DrawSheetPath
*
sheet
);
//Set the reference, for the given sheet path.
void
SetRef
(
DrawSheetPath
*
sheet
,
const
wxString
&
ref
);
void
AddHierarchicalReference
(
const
wxString
&
path
,
const
wxString
&
ref
);
/** Function AddHierarchicalReference
* Add a full hierachical reference (path + local reference)
* @param aPath = hierarchical path (/<sheet timestamp>/component timestamp> like /05678E50/A23EF560)
* @param aRef = local reference like C45, R56
* @param aMulti = part selection, used in multi part per package (0 or 1 for non multi)
*/
void
AddHierarchicalReference
(
const
wxString
&
aPath
,
const
wxString
&
aRef
,
int
aMulti
);
//returns the unit selection, for the given sheet path.
int
GetUnitSelection
(
DrawSheetPath
*
aSheet
);
//Set the unit selection, for the given sheet path.
void
SetUnitSelection
(
DrawSheetPath
*
aSheet
,
int
aUnitSelection
);
#if defined (DEBUG)
...
...
eeschema/eeredraw.cpp
View file @
2b0a25b4
...
...
@@ -87,7 +87,7 @@ void WinEDA_SchematicFrame::RedrawActiveWindow( wxDC* DC, bool EraseBg )
ActiveScreen
=
GetScreen
();
/*
Forcage de la reinit de la brosse et plume courante
*/
/*
Reinit draw and pen parameters
*/
GRResetPenAndBrush
(
DC
);
DC
->
SetBackground
(
*
wxBLACK_BRUSH
);
DC
->
SetBackgroundMode
(
wxTRANSPARENT
);
...
...
@@ -116,7 +116,9 @@ void WinEDA_SchematicFrame::RedrawActiveWindow( wxDC* DC, bool EraseBg )
Affiche_Status_Box
();
GetScreen
()
->
ClrRefreshReq
();
if
(
GetScreen
()
->
m_FileName
==
g_DefaultSchematicFileName
)
// Display the sheet filename, and the sheet path, for non root sheets
if
(
GetScreen
()
->
m_FileName
==
g_DefaultSchematicFileName
)
// This is the root sheet
{
wxString
msg
=
g_Main_Title
+
wxT
(
" "
)
+
GetBuildVersion
();
title
.
Printf
(
wxT
(
"%s [%s]"
),
msg
.
GetData
(),
GetScreen
()
->
m_FileName
.
GetData
()
);
...
...
@@ -124,7 +126,9 @@ void WinEDA_SchematicFrame::RedrawActiveWindow( wxDC* DC, bool EraseBg )
}
else
{
title
.
Printf
(
wxT
(
"[%s]"
),
GetScreen
()
->
m_FileName
.
GetData
()
);
title
=
wxT
(
"["
);
title
<<
GetScreen
()
->
m_FileName
<<
wxT
(
"] "
)
<<
_
(
"Sheet"
)
;
title
<<
wxT
(
" "
)
<<
m_CurrentSheet
->
PathHumanReadable
();
SetTitle
(
title
);
}
}
...
...
eeschema/hierarch.cpp
View file @
2b0a25b4
...
...
@@ -241,8 +241,6 @@ void WinEDA_HierFrame::OnSelect(wxTreeEvent& event)
*
(
m_Parent
->
m_CurrentSheet
)
=
((
TreeItemData
*
)(
m_Tree
->
GetItemData
(
ItemSel
)))
->
m_SheetList
;
wxString
path
=
m_Parent
->
m_CurrentSheet
->
PathHumanReadable
();
printf
(
"changing to sheet %s
\n
"
,
CONV_TO_UTF8
(
path
));
UpdateScreenFromSheet
(
m_Parent
);
Close
(
TRUE
);
}
...
...
@@ -319,14 +317,14 @@ static bool UpdateScreenFromSheet(WinEDA_SchematicFrame * frame)
//update the References
frame
->
m_CurrentSheet
->
UpdateAllScreenReferences
();
frame
->
DrawPanel
->
m_CanStartBlock
=
-
1
;
ActiveScreen
=
frame
->
m_CurrentSheet
->
LastScreen
();
if
(
NewScreen
->
m_FirstRedraw
){
NewScreen
->
m_FirstRedraw
=
FALSE
;
frame
->
Zoom_Automatique
(
TRUE
);
}
else
{
frame
->
ReDrawPanel
();
frame
->
DrawPanel
->
Refresh
();
frame
->
DrawPanel
->
MouseToCursorSchema
();
}
ActiveScreen
=
frame
->
m_CurrentSheet
->
LastScreen
();
return
true
;
}
eeschema/load_one_schematic_file.cpp
View file @
2b0a25b4
...
...
@@ -613,26 +613,29 @@ static int ReadPartDescr( wxWindow* frame, char* Line, FILE* f,
if
(
Line
[
0
]
==
'A'
&&
Line
[
1
]
==
'R'
)
{
/*format:
AR Path="/9086AF6E/67452AA0" Ref="C99"
AR Path="/9086AF6E/67452AA0" Ref="C99"
Part="1"
where 9086AF6E is the unique timestamp of the containing sheet
and 67452AA0 is the timestamp of this component.
C99 is the reference given this path.
*/
int
i
=
2
;
while
(
i
<
256
&&
Line
[
i
]
!=
'"'
){
i
++
;
}
i
++
;
int
i
i
;
ptcar
=
Line
+
2
;
//copy the path.
int
j
=
0
;
while
(
i
<
256
&&
Line
[
i
]
!=
'"'
){
Name1
[
j
]
=
Line
[
i
];
i
++
;
j
++
;}
i
++
;
Name1
[
j
]
=
0
;
ii
=
ReadDelimitedText
(
Name1
,
ptcar
,
255
);
ptcar
+=
ii
+
1
;
wxString
path
=
CONV_FROM_UTF8
(
Name1
);
//i should be one after the closing quote, match the next opening quote
while
(
i
<
256
&&
Line
[
i
]
!=
'"'
){
i
++
;
}
i
++
;
j
=
0
;
while
(
i
<
256
&&
Line
[
i
]
!=
'"'
){
Name1
[
j
]
=
Line
[
i
];
i
++
;
j
++
;}
i
++
;
Name1
[
j
]
=
0
;
// copy the reference
ii
=
ReadDelimitedText
(
Name1
,
ptcar
,
255
);
ptcar
+=
ii
+
1
;
wxString
ref
=
CONV_FROM_UTF8
(
Name1
);
LibItemStruct
->
AddHierarchicalReference
(
path
,
ref
);
// copy the multi, if exists
ii
=
ReadDelimitedText
(
Name1
,
ptcar
,
255
);
if
(
Name1
[
0
]
==
0
)
// Nothing read, put a default value
sprintf
(
Name1
,
"%d"
,
LibItemStruct
->
m_Multi
);
int
multi
=
atoi
(
Name1
);
if
(
multi
<
0
||
multi
>
25
)
multi
=
1
;
LibItemStruct
->
AddHierarchicalReference
(
path
,
ref
,
multi
);
LibItemStruct
->
m_Field
[
REFERENCE
].
m_Text
=
ref
;
}
if
(
Line
[
0
]
==
'F'
)
...
...
@@ -724,7 +727,6 @@ static int ReadPartDescr( wxWindow* frame, char* Line, FILE* f,
LibItemStruct
->
m_Field
[
fieldref
].
m_Name
=
CONV_FROM_UTF8
(
FieldUserName
);
}
// 27 juin 2001: A Supprimer lorsque tous les schemas auront ete traites :
if
(
fieldref
==
REFERENCE
)
if
(
LibItemStruct
->
m_Field
[
fieldref
].
m_Text
[
0
]
==
'#'
)
LibItemStruct
->
m_Field
[
fieldref
].
m_Attributs
|=
TEXT_NO_VISIBLE
;
...
...
include/build_version.h
View file @
2b0a25b4
...
...
@@ -5,7 +5,7 @@
COMMON_GLOBL
wxString
g_BuildVersion
#ifdef EDA_BASE
(
wxT
(
"(20080
313-r890
)"
))
(
wxT
(
"(20080
416-r981
)"
))
#endif
;
...
...
internat/fr/kicad.mo
View file @
2b0a25b4
No preview for this file type
internat/fr/kicad.po
View file @
2b0a25b4
This diff is collapsed.
Click to expand it.
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