Skip to content
GitLab
Explore
Sign in
Primary navigation
Search or go to…
Project
I
iexcode
Manage
Activity
Members
Labels
Plan
Issues
Issue boards
Milestones
Iterations
Wiki
Code
Merge requests
Repository
Branches
Commits
Tags
Repository graph
Compare revisions
Snippets
Locked files
Build
Pipelines
Jobs
Pipeline schedules
Artifacts
Deploy
Releases
Package Registry
Model registry
Operate
Environments
Terraform modules
Monitor
Incidents
Analyze
Value stream analytics
Contributor analytics
CI/CD analytics
Repository analytics
Code review analytics
Issue analytics
Model experiments
Help
Help
Support
GitLab documentation
Compare GitLab plans
Community forum
Contribute to GitLab
Provide feedback
Terms and privacy
Keyboard shortcuts
?
Snippets
Groups
Projects
Show more breadcrumbs
29id
iexcode
Commits
2ed9d490
Commit
2ed9d490
authored
2 years ago
by
29iduser
Browse files
Options
Downloads
Patches
Plain Diff
fixed table scans
parent
601e6cc8
No related branches found
Branches containing commit
No related tags found
Tags containing commit
No related merge requests found
Changes
2
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
iexcode/instruments/scanRecord.py
+2
-5
2 additions, 5 deletions
iexcode/instruments/scanRecord.py
iexcode/macros/hkl_iex.py
+116
-119
116 additions, 119 deletions
iexcode/macros/hkl_iex.py
with
118 additions
and
124 deletions
iexcode/instruments/scanRecord.py
+
2
−
5
View file @
2ed9d490
...
...
@@ -928,11 +928,8 @@ class ScanRecord:
if
kwargs
[
'
debug
'
]:
print
(
'
fillin:
'
,
val_pv
,
rbv_pv
,
myarray
[
0
],
myarray
[
-
1
])
if
posNum
==
1
:
#clear positioners
self
.
positioners_clear
(
**
kwargs
)
#set to table mode
caput
(
scan_pv
+
"
.P
"
+
str
(
posNum
)
+
"
SM
"
,
"
TABLE
"
)
#set to table mode
caput
(
scan_pv
+
"
.P
"
+
str
(
posNum
)
+
"
SM
"
,
"
TABLE
"
)
#write new positioners
caput
(
scan_pv
+
"
.P
"
+
str
(
posNum
)
+
"
PV
"
,
val_pv
)
#Drive
caput
(
scan_pv
+
"
.R
"
+
str
(
posNum
)
+
"
PV
"
,
rbv_pv
)
#Read
...
...
This diff is collapsed.
Click to expand it.
iexcode/macros/hkl_iex.py
+
116
−
119
View file @
2ed9d490
...
...
@@ -17,6 +17,7 @@ from ophyd import PseudoSingle
from
ophyd
import
SoftPositioner
from
epics
import
caget
,
caput
import
iexcode.instruments.cfg
as
iex
from
iexcode.instruments.conversions_constants
import
Lambda2eV
,
eV2Lambda
from
iexcode.instruments.kappa_angle_calcs
import
EtoK
from
iexcode.instruments.Motors
import
*
...
...
@@ -51,24 +52,14 @@ select_diffractometer(fourc)
print
(
f
"
\n
{
fourc
.
name
}
modes:
{
fourc
.
engine
.
modes
}
"
)
# Define motors RBVs:
"""
kappa_motor_dict = _kappa_motor_dictionary()
kappa_motor_dict
=
_kappa_motor_dictionary
()
tth_rbv
=
EpicsSignalRO
(
kappa_motor_dict
[
'
tth
'
][
0
],
name
=
"
tth_rbv
"
)
omega_rbv
=
EpicsSignalRO
(
kappa_motor_dict
[
'
th
'
][
0
],
name
=
"
omega_rbv
"
)
chi_rbv
=
EpicsSignalRO
(
kappa_motor_dict
[
'
chi
'
][
0
],
name
=
"
chi_rbv
"
)
phi_rbv
=
EpicsSignalRO
(
kappa_motor_dict
[
'
phi
'
][
0
],
name
=
"
phi_rbv
"
)
kth_rbv
=
EpicsSignalRO
(
kappa_motor_dict
[
'
kth
'
][
0
],
name
=
"
kth_rbv
"
)
kap_rbv
=
EpicsSignalRO
(
kappa_motor_dict
[
'
kap
'
][
0
],
name
=
"
kap_rbv
"
)
kphi_rbv =EpicsSignalRO(kappa_motor_dict[
'
kphi
'
][0], name=
"
phi_rbv
"
)
"""
print
(
'
We are here
'
)
tth_rbv
=
EpicsSignalRO
(
'
29idKappa:m9.RBV
'
,
name
=
"
tth_rbv
"
)
omega_rbv
=
EpicsSignalRO
(
'
29idKappa:Euler_ThetaRBV
'
,
name
=
"
omega_rbv
"
)
chi_rbv
=
EpicsSignalRO
(
'
29idKappa:Euler_ChiRBV
'
,
name
=
"
chi_rbv
"
)
phi_rbv
=
EpicsSignalRO
(
'
29idKappa:Euler_PhiRBV
'
,
name
=
"
phi_rbv
"
)
kth_rbv
=
EpicsSignalRO
(
'
29idKappa:m8.RBV
'
,
name
=
"
kth_rbv
"
)
kap_rbv
=
EpicsSignalRO
(
'
29idKappa:m7.RBV
'
,
name
=
"
kap_rbv
"
)
kphi_rbv
=
EpicsSignalRO
(
'
29idKappa:m1.RBV
'
,
name
=
"
tth_rbv
"
)
kphi_rbv
=
EpicsSignalRO
(
kappa_motor_dict
[
'
kphi
'
][
0
],
name
=
"
phi_rbv
"
)
# SPEC equivalent of setmode.
...
...
@@ -164,9 +155,7 @@ UB_update_wavelength()
####### Tools and functions:
## Where motor: wh(fourc)
def
wh
(
E
=
None
,
sync
=
True
,
diffractometer
=
fourc
):
"""
1117.KAPPA29ID_sim> wh
...
...
@@ -501,26 +490,29 @@ def UBcalc(r1,r2,sync=True):
caput
(
'
29idKappa:UBor2
'
,
np
.
array
([
h
,
k
,
l
,
omega
,
chi
,
phi
,
tth
]))
return
fourc
.
calc
.
sample
.
UB
def
UBrbv
():
def
UB_get
():
"""
returns the UB matrix
"""
UB
=
caget
(
'
29idKappa:UBmatrix
'
)
# flattened to a 9x1 matrix
return
(
UB
.
reshape
(
3
,
3
))
# reshape to a 3x3 matrix
def
UBenergy
(
eV
=
getE
()):
"""
Update diffractometer energy.
To sync to beamline energy, use UBenergy(getE())
"""
"""
Updates diffractometer energy.
"""
fourc
.
calc
.
wavelength
=
eV2Lambda
(
eV
)
print
(
"
\n
Current energy:
"
+
str
(
round
(
Lambda2eV
(
fourc
.
calc
.
wavelength
),
2
)))
UB_update_wavelength
def
UBenergy_rbv
():
"""
Return diffractometer energy.
"""
print
(
"
\n
UB_energy:
"
+
str
(
round
(
Lambda2eV
(
fourc
.
calc
.
wavelength
),
2
)))
UB_update_wavelength
()
def
UBenergy_get
():
"""
Returns the diffractometer energy.
"""
eV
=
Lambda2eV
(
fourc
.
calc
.
wavelength
)
print
(
"
\n
Current energy:
"
+
str
(
round
(
eV
,
2
)))
############## start editing here
def
_hkl_scan_detectors
(
scanning
=
True
,
hkl_arrays
=
[],
**
kwargs
):
def
_hkl_scan_detectors_set
(
scanning
=
True
,
hkl_arrays
=
[],
**
kwargs
):
"""
adds/remove hkl detectors from the scanRecord
scanning = True (adds)
...
...
@@ -554,38 +546,60 @@ def _hkl_scan_detectors(scanning=True,hkl_arrays=[],**kwargs):
print
(
caget
(
ArrayCalc
+
"
.DESC
"
)
+
"
= [D
"
+
str
(
Det_h
+
i
)
+
"
]
"
)
def
_scan_hkl_
array
(
my
table
,
**
kwargs
):
def
_scan_hkl_
fillin
(
hkl_
table
s
,
**
kwargs
):
"""
Uses bluesky pyhkl to calculate the motor positions for an hkl scan:
Uses bluesky pyhkl to calculate the motor positions for an hkl scan
and fills in the scanRecord; does not press go
my
table = _hkl_array(hkl1,hkl2,npts,eV)
hkl_
table
s
= _hkl_array(hkl1,hkl2,npts,eV)
= (table_omega, table_chi, table_phi, table_tth)
where hkl_tables = hkl_calc_scan_arrays(hkl1,hkl2,npts,hv)
Save the corresponding table into a txt file (CSV) as scan_####.txt
Logging is automatic
**kwargs are the optional logging arguments see scanlog() for details
scan_dim = 1
"""
iex
.
BL
.
motors
.
scan_table
(
'
phi
'
,
table_phi
,
**
kwargs
)
def
scanhkl
(
hkl1
,
hkl2
,
npts
,
**
kwargs
):
"""
With hkl1=[h1,k1,l1] and hkl2=[h2,k2,l2]
npts = number of point
cts = count time
**kwargs:
energy: changes the photon energy (if execute=False only changes energy in UB)
execute True/False to scan/print trajectory
comment:
scaler_cnts: to change the acquire time
"""
kwargs
.
setdefault
(
'
execute
'
,
True
)
kwargs
.
setdefault
(
'
hv
'
,
getE
())
if
'
comment
'
in
kwargs
:
log_print
(
kwargs
[
'
comment
'
])
hkl_tables
=
hkl_calc_scan_arrays
(
hkl1
,
hkl2
,
npts
,
kwargs
[
'
hv
'
])
print
(
"
Number of accessible reflections:
"
,
str
(
len
(
hkl_tables
[
4
])))
kwargs
.
setdefault
(
'
scan_dim
'
,
1
)
kwargs
.
setdefault
(
'
positioner_settling_time
'
,
0.2
)
kwargs
.
setdefault
(
'
execute
'
,
True
)
# Extract individual arrays:
table_omega
=
my
table
[
0
]
table_chi
=
my
table
[
1
]
table_phi
=
my
table
[
2
]
table_tth
=
my
table
[
3
]
table_hkl
=
my
table
[
4
]
array_h
=
my
table
[
4
][:,
0
]
array_k
=
my
table
[
4
][:,
1
]
array_l
=
my
table
[
4
][:,
2
]
_hkl_scan_detectors
(
scanning
=
True
,
hkl_arrays
=
[
array_h
,
array_k
,
array_l
],
**
kwargs
)
table_omega
=
hkl_
table
s
[
0
]
table_chi
=
hkl_
table
s
[
1
]
table_phi
=
hkl_
table
s
[
2
]
table_tth
=
hkl_
table
s
[
3
]
table_hkl
=
hkl_
table
s
[
4
]
array_h
=
hkl_
table
s
[
4
][:,
0
]
array_k
=
hkl_
table
s
[
4
][:,
1
]
array_l
=
hkl_
table
s
[
4
][:,
2
]
_hkl_scan_detectors
_set
(
scanning
=
True
,
hkl_arrays
=
[
array_h
,
array_k
,
array_l
],
**
kwargs
)
for
motor
in
[
'
tth
'
,
'
th
'
,
'
chi
'
,
'
phi
'
]:
print
(
'
motor = [D
'
+
str
(
kappa_motors_detNum
(
motor
))
+
'
]
'
)
# Fill-in
s
scan
r
ecord:
# Fill-in scan
R
ecord:
execute
=
kwargs
[
'
execute
'
]
kwargs
.
update
({
'
execute
'
:
False
})
iex
.
BL
.
motors
.
scan_table
(
'
tth
'
,
table_tth
,
**
kwargs
)
...
...
@@ -594,63 +608,59 @@ def _scan_hkl_array(mytable,**kwargs):
kwargs
.
update
({
'
positioner_num
'
:
3
})
iex
.
BL
.
motors
.
scan_table
(
'
chi
'
,
table_chi
,
**
kwargs
)
kwargs
.
update
({
'
positioner_num
'
:
4
})
iex
.
BL
.
motors
.
scan_table
(
'
phi
'
,
table_phi
,
**
kwargs
)
# Scanning
if
execute
:
scan_go
(
**
kwargs
)
# Setting everything back
scan_
after_table_reset
(
**
kwargs
)
scan_positioners_clear
(
**
kwargs
)
_hkl_scan_detectors
(
scanning
=
False
,
hkl_arrays
=
[],
**
kwargs
)
# Setting everything back
scan_after_table_reset
(
**
kwargs
)
scan_
positioners_clear
(
**
kwargs
)
_hkl_scan_detectors_set
(
scanning
=
False
,
hkl_arrays
=
[],
**
kwargs
)
else
:
return
hkl_tables
def
scanhkl
(
hkl1
,
hkl2
,
npts
,
cts
,
**
kwargs
):
def
scanhkl
_test
(
hkl1
,
hkl2
,
npts
,
**
kwargs
):
"""
With hkl1=[h1,k1,l1] and hkl2=[h2,k2,l2]
npts = number of point
cts = count time
Print the hkl trajectory for hkl1=[h1,k1,l1] and hkl2=[h2,k2,l2]
**kwargs:
energy: changes the photon energy (if execute=False only changes energy in UB)
execute True/False to scan/print trajectory
comment:
"""
kwargs
.
setdefault
(
'
execute
'
,
True
)
kwargs
[
'
scaler_cts
'
]
=
cts
kwargs
.
setdefault
(
'
hv
'
,
energy
)
hkl_tables
=
hkl_calc_scan_arrays
(
hkl1
,
hkl2
,
npts
,
kwargs
[
'
hv
'
])
return
hkl_tables
if
'
comment
'
in
kwargs
:
log_print
(
kwargs
[
'
comment
'
])
if
'
energy
'
in
kwargs
:
E
=
kwargs
[
'
energy
'
]
else
:
E
=
getE
()
def
hkl_write_array
(
hkl1
,
hkl2
,
npts
,
**
kwargs
):
"""
writes the hkl trajectories to a text file
UBenergy
(
E
)
myarray
=
_hkl_array
(
hkl1
,
hkl2
,
npts
,
E
)
print
(
"
Number of accessible reflections:
"
,
str
(
len
(
myarray
[
4
])))
if
kwargs
[
'
execute
'
]:
_scan_hkl_array
(
myarray
,
**
kwargs
)
else
:
cahkl_table
(
myarray
[
4
])
**kwargs:
energy: changes the photon energy (if execute=False only changes energy in UB)
filepath: default = userpath\hkl
separator: defautl =
'
,
'
"""
kwargs
.
setdefault
(
'
hv
'
,
getE
())
kwargs
.
setdefault
(
'
filepath
'
,
"
/home/beams/29IDUSER/Documents/User_Folders/
"
+
mda_user_name
()
+
'
/hkl/
'
)
kwargs
.
setdefault
(
separator
,
'
,
'
)
#Need to make this smarter to not record unobtainable hkl reflections - data size missmatch
def
scanhkl_test
(
hkl1
,
hkl2
,
npts
,
ct
,
E
=
None
):
'''
Print the hkl trajectory for hkl1=[h1,k1,l1] and hkl2=[h2,k2,l2]
If E = None (default), uses the current beamline energy.
'''
if
E
is
None
:
E
=
getE
()
cahkl_table
(
_hkl_array
(
hkl1
,
hkl2
,
npts
,
E
)[
4
])
fileName
=
'
scan_
'
+
str
.
zfill
(
str
(
mda_fileNum
()),
0
)
+
'
.txt
'
separator
=
kwargs
[
'
separator
'
]
hkl_table
=
hkl_calc_scan_arrays
(
hkl1
,
hkl2
,
npts
,
**
kwargs
)
with
open
(
join
(
kwargs
[
'
filepath
'
],
fileName
),
"
a+
"
)
as
f
:
f
.
write
(
'
h
'
+
separator
+
'
k
'
+
separator
+
'
l
'
+
separator
+
'
tth
'
+
separator
+
'
th
'
+
separator
+
'
chi
'
+
separator
+
'
phi
'
+
'
\n
'
)
for
(
i
)
in
range
(
len
(
hkl_table
[
1
])):
f
.
write
(
str
(
hkl_table
[
1
][
i
])
+
separator
+
str
(
hkl_table
[
2
][
i
])
+
separator
+
str
(
hkl_table
[
3
][
i
])
+
separator
+
str
(
hkl_table
[
4
][
i
])
+
separator
+
str
(
hkl_table
[
5
][
i
])
+
separator
+
str
(
hkl_table
[
6
][
i
])
+
separator
+
str
(
hkl_table
[
7
][
i
])
+
'
\n
'
)
print
(
'
\n
Writing hkl table to:
'
,
join
(
kwargs
[
'
filepath
'
],
fileName
))
def
_hkl_array
(
hkl_start
,
hkl_stop
,
npts
,
eV
):
def
hkl_calc_scan_arrays
(
hkl_start
,
hkl_stop
,
npts
,
hv
=
getE
()):
"""
Uses bluesky pyhkl to calculate a numpy array with the motors
'
trajectory for a given hkl scan.
and returns the hkl_tables=(omega,chi,phi,tth,hkl)
"""
# Set diffractometer energy:
fourc
.
calc
.
wavelength
=
eV2Lambda
(
eV
)
UB_update_wavelength
()
UBenergy
(
hv
)
# Generate a list of hkl position
list_hkl_in
=
fourc
.
calc
.
calc_linear_path
(
hkl_start
,
hkl_stop
,
npts
,
num_params
=
3
)
...
...
@@ -679,57 +689,44 @@ def _hkl_array(hkl_start,hkl_stop,npts,eV):
def
table2csv
(
hkl_table
,
filePath
=
None
,
separator
=
'
,
'
):
#Need to make this smarter to not record unobtainable hkl reflections - data size missmatch
if
filePath
is
None
:
user
=
iex
.
BL
.
mda
.
user_name
()
filePath
=
"
/home/beams/29IDUSER/Documents/User_Folders/
"
+
user
+
'
/hkl/
'
scanNum
=
hkl_table
[
0
]
scanNumstr
=
str
.
zfill
(
str
(
scanNum
),
0
)
fileName
=
'
scan_
'
+
scanNumstr
+
'
.txt
'
with
open
(
join
(
filePath
,
fileName
),
"
a+
"
)
as
f
:
f
.
write
(
'
h
'
+
separator
+
'
k
'
+
separator
+
'
l
'
+
separator
+
'
tth
'
+
separator
+
'
th
'
+
separator
+
'
chi
'
+
separator
+
'
phi
'
+
'
\n
'
)
for
(
i
)
in
range
(
len
(
hkl_table
[
1
])):
f
.
write
(
str
(
hkl_table
[
1
][
i
])
+
separator
+
str
(
hkl_table
[
2
][
i
])
+
separator
+
str
(
hkl_table
[
3
][
i
])
+
separator
+
str
(
hkl_table
[
4
][
i
])
+
separator
+
str
(
hkl_table
[
5
][
i
])
+
separator
+
str
(
hkl_table
[
6
][
i
])
+
separator
+
str
(
hkl_table
[
7
][
i
])
+
'
\n
'
)
print
(
'
\n
Writing hkl table to:
'
,
join
(
filePath
,
fileName
))
def
scanhkl_E
(
StartStopStepL
ist
s
,
hkl
,
cts
,
ID_tracking
,
mono_offset
=
0
,
return_table
=
False
,
**
kwargs
):
def
scanhkl_E
(
hv_l
ist
,
hkl
=
get_hkl
(),
**
kwargs
):
"""
Uses bluesky pyhkl to calculate the motor positions for an energy scan at constant Q:
hkl=(h,k,l); if hkl=None, uses the current hkl position
cts = acquisition time
ID_tracking: if True, scans the ID; if False, scan mono only
mono_offset => if you want to artificially shift the energy for the reciprocal space calulation (eg to match known hkl indexes)
hv_list = [[start1,stop1,step1], [start1,stop1,step1],...]; list of lists for the different scan ranges
Note duplicates are removed and the resulting array is sorted in ascending order
StartStopStepLists is a list of lists for the different scan ranges
StartStopStepList[[start1,stop1,step1],[start2,stop2,step2],...]
Note duplicates are removed and the resulting array is sorted in ascending order
hkl=(h,k,l); if hkl=None, uses the current hkl position
Logging is automatic
**kwargs are the optional logging arguments see scanlog() for details
**kwargs
scaler_cts: to change the acquisition time
ID_tracking: True/False (default=False)
mono_offset: if you want to artificially shift the energy for the reciprocal space calulation (eg to match known hkl indexes)
write_file: True/False to write csv file (default=True)
execute: True/False
"""
kwargs
.
setdefault
(
'
execute
'
,
True
)
kwargs
.
setdefault
(
'
positioner_settling_time
'
,
0.2
)
kwargs
.
setdefault
(
'
positioner_after_scan
'
,
"
STAY
"
)
kwargs
[
'
scaler_cts
'
]
=
cts
kwargs
.
setdefault
(
'
ID_tracking
'
,
False
)
kwargs
.
setdefault
(
'
mono_offset
'
,
0
)
kwargs
.
setdefault
(
'
write_file
'
,
True
)
# caget beamline parameters:
scanIOC
=
iex
.
BL
.
mda
.
ioc
scanIOC
=
mda
_
ioc
()
ID_Mode
,
ID_QP
,
ID_SP
,
ID_RBV
,
hv
,
grt
=
energy_get_all
()
if
hkl
==
None
:
hkl
=
get_hkl
()
print
(
'
hkl =
'
+
str
(
hkl
))
print
(
'
hkl =
'
+
str
(
hkl
))
# Target hkl:
h
,
k
,
l
=
hkl
# Create energy trajectory (can have variable step size):
mytable_hv
=
make_table
(
StartStopStepL
ist
s
)
mytable_hv
=
make_table
(
hv_l
ist
)
UB_update_wavelength
()
...
...
@@ -743,7 +740,7 @@ def scanhkl_E(StartStopStepLists,hkl,cts,ID_tracking,mono_offset=0,return_table=
# Compute motor positions for each energy point & append to the motor tables:
for
eV
in
mytable_hv
:
fourc
.
calc
.
wavelength
=
eV2Lambda
(
eV
+
mono_offset
)
fourc
.
calc
.
wavelength
=
eV2Lambda
(
eV
+
kwargs
[
'
mono_offset
'
]
)
e_omega
=
round
(
fourc
.
calc
.
forward
((
h
,
k
,
l
))[
0
][
0
],
5
)
e_chi
=
round
(
fourc
.
calc
.
forward
((
h
,
k
,
l
))[
0
][
1
],
5
)
e_phi
=
round
(
fourc
.
calc
.
forward
((
h
,
k
,
l
))[
0
][
2
],
5
)
...
...
@@ -764,7 +761,7 @@ def scanhkl_E(StartStopStepLists,hkl,cts,ID_tracking,mono_offset=0,return_table=
kwargs
.
update
({
'
positioner_num
'
:
3
})
iex
.
BL
.
motors
.
scan_table
(
'
th
'
,
mytable_omega
,
**
kwargs
)
if
ID_tracking
:
# moving ID - at the moment this replaces chi:
if
kwargs
[
'
ID_tracking
'
]
:
# moving ID - at the moment this replaces chi:
kwargs
.
update
({
'
positioner_num
'
:
4
})
ID_array
=
np
.
array
([])
ID_mode
,
ID_QP_ratio
,
ID_sp
,
ID_rbv
,
hv
,
grt
=
energy_get_all
(
verbose
=
False
)
...
...
@@ -787,10 +784,10 @@ def scanhkl_E(StartStopStepLists,hkl,cts,ID_tracking,mono_offset=0,return_table=
# Setting everything back
scan_after_table_reset
(
**
kwargs
)
scan_positioners_clear
(
**
kwargs
)
_hkl_scan_detectors
(
scanning
=
False
,
hkl_arrays
=
[],
**
kwargs
)
_hkl_scan_detectors
_set
(
scanning
=
False
,
hkl_arrays
=
[],
**
kwargs
)
# to be saved in text file like scanhkl:
if
return_table
:
if
not
ID_tracking
:
mytable_ID
=
None
if
kwargs
[
'
write_file
'
]
:
if
not
kwargs
[
'
ID_tracking
'
]
:
mytable_ID
=
None
return
FileNum
,
mytable_hv
.
tolist
(),
mytable_ID
.
tolist
(),
mytable_omega
.
tolist
(),
mytable_chi
.
tolist
()
,
mytable_phi
.
tolist
()
,
mytable_tth
.
tolist
()
This diff is collapsed.
Click to expand it.
Preview
0%
Loading
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Save comment
Cancel
Please
register
or
sign in
to comment