Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
W
wendelin
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Jérome Perrin
wendelin
Commits
5921e600
Commit
5921e600
authored
Jul 07, 2020
by
Ivan Tyagov
Browse files
Options
Browse Files
Download
Plain Diff
Remove override of standar renderJS gadget and Fix datalake test
See merge request
nexedi/wendelin!50
parents
98ce2b32
86f57956
Changes
6
Show whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
4 additions
and
608 deletions
+4
-608
bt5/erp5_wendelin_data_lake_ingestion/TestTemplateItem/portal_components/test.erp5.testDataLakeIngestion.py
...Item/portal_components/test.erp5.testDataLakeIngestion.py
+2
-1
bt5/erp5_wendelin_data_lake_ui/PathTemplateItem/web_page_module/rjs_gadget_erp5_pt_form_dialog_js.js
...Item/web_page_module/rjs_gadget_erp5_pt_form_dialog_js.js
+0
-337
bt5/erp5_wendelin_data_lake_ui/PathTemplateItem/web_page_module/rjs_gadget_erp5_pt_form_dialog_js.xml
...tem/web_page_module/rjs_gadget_erp5_pt_form_dialog_js.xml
+0
-265
bt5/erp5_wendelin_data_lake_ui/bt/template_keep_last_workflow_history_only_path_list
..._ui/bt/template_keep_last_workflow_history_only_path_list
+1
-2
bt5/erp5_wendelin_data_lake_ui/bt/template_keep_workflow_path_list
...wendelin_data_lake_ui/bt/template_keep_workflow_path_list
+1
-2
bt5/erp5_wendelin_data_lake_ui/bt/template_path_list
bt5/erp5_wendelin_data_lake_ui/bt/template_path_list
+0
-1
No files found.
bt5/erp5_wendelin_data_lake_ingestion/TestTemplateItem/portal_components/test.erp5.testDataLakeIngestion.py
View file @
5921e600
...
...
@@ -244,7 +244,8 @@ class TestDataIngestion(SecurityTestCase):
self
.
tic
()
# ingest new file
data_set
,
data_stream_list
=
self
.
stepIngest
(
self
.
CSV
,
","
)
data_set
,
data_stream_list
=
self
.
stepIngest
(
self
.
CSV
,
","
,
randomize_ingestion_reference
=
False
,
data_set_reference
=
data_set_reference
)
self
.
tic
()
second_file_stream
=
data_stream_list
[
0
]
...
...
bt5/erp5_wendelin_data_lake_ui/PathTemplateItem/web_page_module/rjs_gadget_erp5_pt_form_dialog_js.js
deleted
100644 → 0
View file @
98ce2b32
/*jslint nomen: true, indent: 2, maxerr: 3 */
/*global window, rJS, RSVP, calculatePageTitle, Handlebars, ensureArray */
(
function
(
window
,
rJS
,
RSVP
,
calculatePageTitle
,
Handlebars
,
ensureArray
)
{
"
use strict
"
;
function
checkValidity
()
{
return
this
.
getDeclaredGadget
(
"
erp5_form
"
)
.
push
(
function
(
declared_gadget
)
{
return
declared_gadget
.
checkValidity
();
});
}
function
getContent
()
{
return
this
.
getDeclaredGadget
(
"
erp5_form
"
)
.
push
(
function
(
sub_gadget
)
{
return
sub_gadget
.
getContent
();
});
}
function
submitDialog
(
is_updating
)
{
var
gadget
=
this
,
button_container
=
gadget
.
element
.
querySelector
(
'
.dialog_button_container
'
),
update_button
=
button_container
.
querySelector
(
'
button
'
),
submit_input
=
button_container
.
querySelector
(
'
input
'
);
submit_input
.
disabled
=
true
;
if
(
update_button
!==
null
)
{
update_button
.
disabled
=
true
;
}
function
enableButton
()
{
submit_input
.
disabled
=
false
;
if
(
update_button
!==
null
)
{
update_button
.
disabled
=
false
;
}
}
return
getContent
.
apply
(
this
)
.
push
(
function
(
content_dict
)
{
var
data
=
{},
key
;
// create a copy of sub_data so we do not modify them in-place
for
(
key
in
content_dict
)
{
if
(
content_dict
.
hasOwnProperty
(
key
))
{
data
[
key
]
=
content_dict
[
key
];
}
}
// ERP5 expects target Script name in dialog_method field
data
.
dialog_method
=
gadget
.
state
.
form_definition
.
action
;
// For Update Action - override the default value from "action"
if
(
is_updating
)
{
data
.
dialog_method
=
gadget
.
state
.
form_definition
.
update_action
;
data
.
update_method
=
gadget
.
state
.
form_definition
.
update_action
;
}
return
data
;
})
.
push
(
function
(
data
)
{
return
gadget
.
submitContent
(
gadget
.
state
.
jio_key
,
gadget
.
state
.
erp5_document
.
_embedded
.
_view
.
_actions
.
put
.
href
,
// most likely points to Base_callDialogMethod
data
);
})
.
push
(
function
(
jio_key
)
{
// success redirect handler
var
splitted_jio_key_list
,
splitted_current_jio_key_list
,
command
,
i
;
if
(
is_updating
||
!
jio_key
)
{
return
;
}
if
(
gadget
.
state
.
redirect_to_parent
)
{
return
gadget
.
redirect
({
command
:
'
history_previous
'
});
}
if
(
gadget
.
state
.
jio_key
===
jio_key
)
{
// don't update navigation history when not really redirecting
var
return_page
=
gadget
.
state
.
return_page_confirm
;
return
gadget
.
redirect
({
command
:
'
change
'
,
options
:
{
"
jio_key
"
:
jio_key
,
"
view
"
:
"
view
"
,
"
page
"
:
return_page
// do not mingle with editable because it isn't necessary
}
});
}
// Check if the redirection goes to a same parent's subdocument.
// In this case, do not add current document to the history
// example: when cloning, do not keep the original document in history
splitted_jio_key_list
=
jio_key
.
split
(
'
/
'
);
splitted_current_jio_key_list
=
gadget
.
state
.
jio_key
.
split
(
'
/
'
);
command
=
'
display_with_history
'
;
if
(
splitted_jio_key_list
.
length
===
splitted_current_jio_key_list
.
length
)
{
for
(
i
=
0
;
i
<
splitted_jio_key_list
.
length
-
1
;
i
+=
1
)
{
if
(
splitted_jio_key_list
[
i
]
!==
splitted_current_jio_key_list
[
i
])
{
command
=
'
push_history
'
;
}
}
}
else
{
command
=
'
push_history
'
;
}
// forced document change thus we update history
return
gadget
.
redirect
({
command
:
command
,
options
:
{
"
jio_key
"
:
jio_key
// do not mingle with editable because it isn't necessary
}
});
})
.
push
(
function
(
result
)
{
enableButton
();
return
result
;
},
function
(
error
)
{
enableButton
();
throw
error
;
});
// We do not handle submit failures because Page Form handles them well
// If any error bubbles here we do not know what to do with it anyway
}
var
gadget_klass
=
rJS
(
window
),
dialog_button_source
=
gadget_klass
.
__template_element
.
getElementById
(
"
dialog-button-template
"
)
.
innerHTML
,
dialog_button_template
=
Handlebars
.
compile
(
dialog_button_source
);
gadget_klass
.
setState
({
'
redirect_to_parent
'
:
false
,
// set by a presence of special field
'
has_update_action
'
:
undefined
// default "submit" issue update in case of its presence
})
/////////////////////////////////////////////////////////////////
// acquisition
/////////////////////////////////////////////////////////////////
.
declareAcquiredMethod
(
"
redirect
"
,
"
redirect
"
)
.
declareAcquiredMethod
(
"
getUrlFor
"
,
"
getUrlFor
"
)
.
declareAcquiredMethod
(
"
getUrlParameter
"
,
"
getUrlParameter
"
)
.
declareAcquiredMethod
(
"
updateHeader
"
,
"
updateHeader
"
)
.
declareAcquiredMethod
(
"
translate
"
,
"
translate
"
)
.
declareAcquiredMethod
(
"
translateHtml
"
,
"
translateHtml
"
)
.
declareAcquiredMethod
(
"
submitContent
"
,
"
submitContent
"
)
/////////////////////////////////////////////////////////////////
// Proxy methods to the child gadget
/////////////////////////////////////////////////////////////////
.
declareMethod
(
'
checkValidity
'
,
checkValidity
,
{
mutex
:
'
changestate
'
})
.
declareMethod
(
'
getContent
'
,
getContent
,
{
mutex
:
'
changestate
'
})
/////////////////////////////////////////////////////////////////
// declared methods
/////////////////////////////////////////////////////////////////
.
declareMethod
(
'
triggerSubmit
'
,
function
triggerSubmit
()
{
this
.
element
.
querySelector
(
'
input[type="submit"]
'
).
click
();
},
{
mutex
:
'
changestate
'
})
.
declareMethod
(
'
render
'
,
function
render
(
options
)
{
var
gadget
=
this
,
isFifDataSite
=
options
.
erp5_document
.
_links
.
self
.
href
.
indexOf
(
"
fif_data_runner
"
)
!==
-
1
,
return_page_cancel
,
return_page_confirm
;
// XXX hardcoded...
if
(
isFifDataSite
)
{
return_page_cancel
=
"
data_set
"
;
return_page_confirm
=
"
fifdata
"
;
if
(
options
.
jio_key
.
indexOf
(
"
data_stream
"
)
!==
-
1
)
{
return_page_cancel
=
"
file_fif
"
;
}
}
if
(
options
.
form_definition
.
title
===
"
Validate Workflow Action
"
)
{
options
.
form_definition
.
title
=
"
Validate deletion
"
;
}
var
gadget
=
this
;
// copy out wanted items from options and pass it to `changeState`
return
gadget
.
getUrlParameter
(
'
extended_search
'
)
.
push
(
function
(
extended_search
)
{
return
gadget
.
changeState
({
jio_key
:
options
.
jio_key
,
view
:
options
.
view
,
// ignore options.editable because dialog is always editable
erp5_document
:
options
.
erp5_document
,
form_definition
:
options
.
form_definition
,
erp5_form
:
options
.
erp5_form
||
{},
// editable: true, // ignore global editable state (be always editable)
has_update_action
:
Boolean
(
options
.
form_definition
.
update_action
),
// pass extended_search from previous view in case any gadget is curious
extended_search
:
extended_search
,
isFifDataSite
:
isFifDataSite
,
return_page_cancel
:
return_page_cancel
,
return_page_confirm
:
return_page_confirm
,
// XXX Hack of ERP5 how to express redirect to parent after success
redirect_to_parent
:
options
.
erp5_document
.
_embedded
.
_view
.
field_your_redirect_to_parent
!==
undefined
});
});
})
// .declareMethod('submitDialog', submitDialog, {mutex: 'changestate'})
.
onStateChange
(
function
onStateChange
(
modification_dict
)
{
var
form_gadget
=
this
,
selector
=
form_gadget
.
element
.
querySelector
(
"
h3
"
),
view_list
=
ensureArray
(
this
.
state
.
erp5_document
.
_links
.
action_workflow
),
icon
,
title
,
return_page_confirm
=
this
.
state
.
return_page_confirm
,
return_page_cancel
=
this
.
state
.
return_page_cancel
,
i
;
title
=
this
.
state
.
form_definition
.
title
;
// XXX hardcoded...
switch
(
title
)
{
case
"
Create User
"
:
icon
=
"
ui-icon-user
"
;
break
;
case
"
Create Document
"
:
icon
=
"
ui-icon-file-o
"
;
break
;
case
"
Validate Workflow Action
"
:
icon
=
"
ui-icon-share-alt
"
;
break
;
case
"
Submit
"
:
icon
=
"
ui-icon-check
"
;
break
;
default
:
icon
=
"
ui-icon-random
"
;
break
;
}
// By default we display dialog form title
for
(
i
=
0
;
i
<
view_list
.
length
;
i
+=
1
)
{
if
(
this
.
state
.
view
===
view_list
[
i
].
href
)
{
title
=
view_list
[
i
].
title
;
}
}
return
new
RSVP
.
Queue
()
.
push
(
function
()
{
// Set the dialog button
if
(
modification_dict
.
hasOwnProperty
(
'
has_update_action
'
))
{
return
form_gadget
.
translateHtml
(
dialog_button_template
({
show_update_button
:
form_gadget
.
state
.
has_update_action
}))
.
push
(
function
(
html
)
{
form_gadget
.
element
.
querySelector
(
'
.dialog_button_container
'
)
.
innerHTML
=
html
;
});
}
})
.
push
(
function
()
{
// Calculate the h3 properties
return
RSVP
.
all
([
form_gadget
.
translate
(
form_gadget
.
state
.
form_definition
.
title
),
form_gadget
.
translate
(
title
)
]);
})
.
push
(
function
(
translated_title_list
)
{
form_gadget
.
element
.
querySelector
(
'
input.dialogconfirm
'
).
value
=
translated_title_list
[
1
];
selector
.
textContent
=
"
\
u00A0
"
+
translated_title_list
[
0
];
selector
.
className
=
"
ui-content-title ui-body-c ui-icon ui-icon-custom
"
+
icon
;
// Render the erp5_from
return
form_gadget
.
getDeclaredGadget
(
"
erp5_form
"
);
})
.
push
(
function
(
erp5_form
)
{
var
form_options
=
form_gadget
.
state
.
erp5_form
;
// pass own form options to the embedded form
form_options
.
erp5_document
=
form_gadget
.
state
.
erp5_document
;
form_options
.
form_definition
=
form_gadget
.
state
.
form_definition
;
form_options
.
view
=
form_gadget
.
state
.
view
;
form_options
.
jio_key
=
form_gadget
.
state
.
jio_key
;
form_options
.
editable
=
true
;
// dialog is always editable
// this might cause problems if the listbox in the dialog is not curious
// about the previous search
if
(
form_gadget
.
state
.
extended_search
)
{
form_options
.
form_definition
.
extended_search
=
form_gadget
.
state
.
extended_search
;
}
return
erp5_form
.
render
(
form_options
);
})
.
push
(
function
()
{
// Render the headers
return
RSVP
.
all
([
form_gadget
.
getUrlFor
({
command
:
'
change
'
,
options
:
{
page
:
return_page_cancel
,
view
:
undefined
}}),
calculatePageTitle
(
form_gadget
,
form_gadget
.
state
.
erp5_document
)
]);
})
.
push
(
function
(
all_result
)
{
form_gadget
.
element
.
querySelector
(
'
a.dialogcancel
'
).
href
=
all_result
[
0
];
return
form_gadget
.
updateHeader
({
cancel_url
:
all_result
[
0
],
page_title
:
all_result
[
1
]
});
});
})
.
onEvent
(
'
submit
'
,
function
submit
()
{
if
(
this
.
state
.
has_update_action
===
true
)
{
// default action on submit is update in case of its existence
return
submitDialog
.
apply
(
this
,
[
true
]);
}
return
submitDialog
.
apply
(
this
,
[
false
]);
},
false
,
true
)
.
onEvent
(
'
click
'
,
function
click
(
evt
)
{
if
(
evt
.
target
.
name
===
"
action_confirm
"
)
{
evt
.
preventDefault
();
return
submitDialog
.
apply
(
this
,
[
false
]);
}
if
(
evt
.
target
.
name
===
"
action_update
"
)
{
evt
.
preventDefault
();
return
submitDialog
.
apply
(
this
,
[
true
]);
}
},
false
,
false
)
.
declareService
(
function
enableButton
()
{
// click event listener is now activated
// Change the state of the gadget
var
gadget
=
this
,
button_container
=
gadget
.
element
.
querySelector
(
'
.dialog_button_container
'
),
update_button
=
button_container
.
querySelector
(
'
button
'
),
submit_input
=
button_container
.
querySelector
(
'
input
'
);
submit_input
.
disabled
=
false
;
if
(
update_button
!==
null
)
{
update_button
.
disabled
=
false
;
}
});
}(
window
,
rJS
,
RSVP
,
calculatePageTitle
,
Handlebars
,
ensureArray
));
\ No newline at end of file
bt5/erp5_wendelin_data_lake_ui/PathTemplateItem/web_page_module/rjs_gadget_erp5_pt_form_dialog_js.xml
deleted
100644 → 0
View file @
98ce2b32
<?xml version="1.0"?>
<ZopeData>
<record
id=
"1"
aka=
"AAAAAAAAAAE="
>
<pickle>
<global
name=
"Web Script"
module=
"erp5.portal_type"
/>
</pickle>
<pickle>
<dictionary>
<item>
<key>
<string>
_Access_contents_information_Permission
</string>
</key>
<value>
<tuple>
<string>
Anonymous
</string>
<string>
Assignee
</string>
<string>
Assignor
</string>
<string>
Associate
</string>
<string>
Auditor
</string>
<string>
Manager
</string>
<string>
Owner
</string>
</tuple>
</value>
</item>
<item>
<key>
<string>
_Add_portal_content_Permission
</string>
</key>
<value>
<tuple>
<string>
Assignee
</string>
<string>
Assignor
</string>
<string>
Manager
</string>
</tuple>
</value>
</item>
<item>
<key>
<string>
_Change_local_roles_Permission
</string>
</key>
<value>
<tuple>
<string>
Assignor
</string>
<string>
Manager
</string>
</tuple>
</value>
</item>
<item>
<key>
<string>
_Modify_portal_content_Permission
</string>
</key>
<value>
<tuple>
<string>
Assignee
</string>
<string>
Assignor
</string>
<string>
Manager
</string>
</tuple>
</value>
</item>
<item>
<key>
<string>
_View_Permission
</string>
</key>
<value>
<tuple>
<string>
Anonymous
</string>
<string>
Assignee
</string>
<string>
Assignor
</string>
<string>
Associate
</string>
<string>
Auditor
</string>
<string>
Manager
</string>
<string>
Owner
</string>
</tuple>
</value>
</item>
<item>
<key>
<string>
content_md5
</string>
</key>
<value>
<none/>
</value>
</item>
<item>
<key>
<string>
default_reference
</string>
</key>
<value>
<string>
gadget_erp5_pt_form_dialog.js
</string>
</value>
</item>
<item>
<key>
<string>
description
</string>
</key>
<value>
<none/>
</value>
</item>
<item>
<key>
<string>
id
</string>
</key>
<value>
<string>
rjs_gadget_erp5_pt_form_dialog_js
</string>
</value>
</item>
<item>
<key>
<string>
language
</string>
</key>
<value>
<string>
en
</string>
</value>
</item>
<item>
<key>
<string>
portal_type
</string>
</key>
<value>
<string>
Web Script
</string>
</value>
</item>
<item>
<key>
<string>
short_title
</string>
</key>
<value>
<none/>
</value>
</item>
<item>
<key>
<string>
title
</string>
</key>
<value>
<string>
Gadget ERP5 Form Dialog JS
</string>
</value>
</item>
<item>
<key>
<string>
version
</string>
</key>
<value>
<string>
001
</string>
</value>
</item>
<item>
<key>
<string>
workflow_history
</string>
</key>
<value>
<persistent>
<string
encoding=
"base64"
>
AAAAAAAAAAI=
</string>
</persistent>
</value>
</item>
</dictionary>
</pickle>
</record>
<record
id=
"2"
aka=
"AAAAAAAAAAI="
>
<pickle>
<global
name=
"PersistentMapping"
module=
"Persistence.mapping"
/>
</pickle>
<pickle>
<dictionary>
<item>
<key>
<string>
data
</string>
</key>
<value>
<dictionary>
<item>
<key>
<string>
document_publication_workflow
</string>
</key>
<value>
<persistent>
<string
encoding=
"base64"
>
AAAAAAAAAAM=
</string>
</persistent>
</value>
</item>
<item>
<key>
<string>
edit_workflow
</string>
</key>
<value>
<persistent>
<string
encoding=
"base64"
>
AAAAAAAAAAQ=
</string>
</persistent>
</value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</pickle>
</record>
<record
id=
"3"
aka=
"AAAAAAAAAAM="
>
<pickle>
<global
name=
"WorkflowHistoryList"
module=
"Products.ERP5Type.Workflow"
/>
</pickle>
<pickle>
<dictionary>
<item>
<key>
<string>
_log
</string>
</key>
<value>
<list>
<dictionary>
<item>
<key>
<string>
action
</string>
</key>
<value>
<string>
publish_alive
</string>
</value>
</item>
<item>
<key>
<string>
actor
</string>
</key>
<value>
<string>
zope
</string>
</value>
</item>
<item>
<key>
<string>
comment
</string>
</key>
<value>
<string></string>
</value>
</item>
<item>
<key>
<string>
error_message
</string>
</key>
<value>
<string></string>
</value>
</item>
<item>
<key>
<string>
time
</string>
</key>
<value>
<object>
<klass>
<global
name=
"DateTime"
module=
"DateTime.DateTime"
/>
</klass>
<tuple>
<none/>
</tuple>
<state>
<tuple>
<float>
1509008879.94
</float>
<string>
UTC
</string>
</tuple>
</state>
</object>
</value>
</item>
<item>
<key>
<string>
validation_state
</string>
</key>
<value>
<string>
published_alive
</string>
</value>
</item>
</dictionary>
</list>
</value>
</item>
</dictionary>
</pickle>
</record>
<record
id=
"4"
aka=
"AAAAAAAAAAQ="
>
<pickle>
<global
name=
"WorkflowHistoryList"
module=
"Products.ERP5Type.Workflow"
/>
</pickle>
<pickle>
<dictionary>
<item>
<key>
<string>
_log
</string>
</key>
<value>
<list>
<dictionary>
<item>
<key>
<string>
action
</string>
</key>
<value>
<string>
edit
</string>
</value>
</item>
<item>
<key>
<string>
actor
</string>
</key>
<value>
<string>
zope
</string>
</value>
</item>
<item>
<key>
<string>
comment
</string>
</key>
<value>
<none/>
</value>
</item>
<item>
<key>
<string>
error_message
</string>
</key>
<value>
<string></string>
</value>
</item>
<item>
<key>
<string>
serial
</string>
</key>
<value>
<string>
969.16457.56234.60791
</string>
</value>
</item>
<item>
<key>
<string>
state
</string>
</key>
<value>
<string>
current
</string>
</value>
</item>
<item>
<key>
<string>
time
</string>
</key>
<value>
<object>
<klass>
<global
name=
"DateTime"
module=
"DateTime.DateTime"
/>
</klass>
<tuple>
<none/>
</tuple>
<state>
<tuple>
<float>
1532968990.23
</float>
<string>
UTC
</string>
</tuple>
</state>
</object>
</value>
</item>
</dictionary>
</list>
</value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
bt5/erp5_wendelin_data_lake_ui/bt/template_keep_last_workflow_history_only_path_list
View file @
5921e600
...
...
@@ -5,4 +5,3 @@ web_site_module/default_wendelin_data_lake
web_site_module/default_wendelin_data_lake/**
web_page_module/fif_*
web_page_module/gadget_fif_*
\ No newline at end of file
web_page_module/rjs_gadget_erp5_pt_form_dialog_js
\ No newline at end of file
bt5/erp5_wendelin_data_lake_ui/bt/template_keep_workflow_path_list
View file @
5921e600
...
...
@@ -5,4 +5,3 @@ web_site_module/default_wendelin_data_lake
web_site_module/default_wendelin_data_lake/**
web_page_module/fif_*
web_page_module/gadget_fif_*
\ No newline at end of file
web_page_module/rjs_gadget_erp5_pt_form_dialog_js
\ No newline at end of file
bt5/erp5_wendelin_data_lake_ui/bt/template_path_list
View file @
5921e600
...
...
@@ -3,6 +3,5 @@ web_page_module/*_wendelin_*
web_page_module/*fif_*
web_page_module/fif_*
web_page_module/gadget_fif_*
web_page_module/rjs_gadget_erp5_pt_form_dialog_js
web_site_module/default_wendelin_data_lake
web_site_module/default_wendelin_data_lake/**
\ No newline at end of file
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