Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
G
gitlab-ce
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
1
Merge Requests
1
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
nexedi
gitlab-ce
Commits
563cb60e
Commit
563cb60e
authored
Jul 28, 2017
by
Tim Zallmann
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'ph-inline-js' into 'master'
Removed inline JS in shared HAML files See merge request !13073
parents
fa1e41ea
795a63d8
Changes
23
Hide whitespace changes
Inline
Side-by-side
Showing
23 changed files
with
135 additions
and
112 deletions
+135
-112
app/assets/javascripts/dispatcher.js
app/assets/javascripts/dispatcher.js
+31
-6
app/assets/javascripts/init_issuable_sidebar.js
app/assets/javascripts/init_issuable_sidebar.js
+18
-0
app/assets/javascripts/init_legacy_filters.js
app/assets/javascripts/init_legacy_filters.js
+15
-0
app/assets/javascripts/init_notes.js
app/assets/javascripts/init_notes.js
+14
-0
app/assets/javascripts/issuable_context.js
app/assets/javascripts/issuable_context.js
+3
-3
app/assets/javascripts/main.js
app/assets/javascripts/main.js
+10
-1
app/assets/javascripts/merge_conflicts/merge_conflicts_bundle.js
...ets/javascripts/merge_conflicts/merge_conflicts_bundle.js
+3
-0
app/assets/javascripts/milestone_select.js
app/assets/javascripts/milestone_select.js
+1
-1
app/assets/javascripts/project.js
app/assets/javascripts/project.js
+15
-14
app/assets/javascripts/sidebar/sidebar_bundle.js
app/assets/javascripts/sidebar/sidebar_bundle.js
+2
-1
app/assets/javascripts/snippets_list.js
app/assets/javascripts/snippets_list.js
+0
-9
app/assets/javascripts/todos.js
app/assets/javascripts/todos.js
+0
-4
app/helpers/issuables_helper.rb
app/helpers/issuables_helper.rb
+10
-0
app/helpers/notes_helper.rb
app/helpers/notes_helper.rb
+10
-0
app/views/shared/_clone_panel.html.haml
app/views/shared/_clone_panel.html.haml
+0
-8
app/views/shared/_label.html.haml
app/views/shared/_label.html.haml
+0
-8
app/views/shared/_personal_access_tokens_form.html.haml
app/views/shared/_personal_access_tokens_form.html.haml
+0
-15
app/views/shared/issuable/_filter.html.haml
app/views/shared/issuable/_filter.html.haml
+0
-10
app/views/shared/issuable/_participants.html.haml
app/views/shared/issuable/_participants.html.haml
+0
-2
app/views/shared/issuable/_search_bar.html.haml
app/views/shared/issuable/_search_bar.html.haml
+0
-9
app/views/shared/issuable/_sidebar.html.haml
app/views/shared/issuable/_sidebar.html.haml
+1
-14
app/views/shared/notes/_notes_with_form.html.haml
app/views/shared/notes/_notes_with_form.html.haml
+1
-2
app/views/snippets/_snippets.html.haml
app/views/snippets/_snippets.html.haml
+1
-5
No files found.
app/assets/javascripts/dispatcher.js
View file @
563cb60e
...
...
@@ -64,6 +64,9 @@ import initSettingsPanels from './settings_panels';
import
initExperimentalFlags
from
'
./experimental_flags
'
;
import
OAuthRememberMe
from
'
./oauth_remember_me
'
;
import
PerformanceBar
from
'
./performance_bar
'
;
import
initNotes
from
'
./init_notes
'
;
import
initLegacyFilters
from
'
./init_legacy_filters
'
;
import
initIssuableSidebar
from
'
./init_issuable_sidebar
'
;
import
GpgBadges
from
'
./gpg_badges
'
;
(
function
()
{
...
...
@@ -159,6 +162,8 @@ import GpgBadges from './gpg_badges';
new
Issue
();
shortcut_handler
=
new
ShortcutsIssuable
();
new
ZenMode
();
initIssuableSidebar
();
initNotes
();
break
;
case
'
dashboard:milestones:index
'
:
new
ProjectSelect
();
...
...
@@ -169,10 +174,12 @@ import GpgBadges from './gpg_badges';
new
Milestone
();
new
Sidebar
();
break
;
case
'
dashboard:issues
'
:
case
'
dashboard:merge_requests
'
:
case
'
groups:issues
'
:
case
'
groups:merge_requests
'
:
new
UsersSelect
();
new
ProjectSelect
();
initLegacyFilters
();
break
;
case
'
dashboard:todos:index
'
:
new
Todos
();
...
...
@@ -253,6 +260,9 @@ import GpgBadges from './gpg_badges';
new
gl
.
GLForm
(
$
(
'
.tag-form
'
),
true
);
new
RefSelectDropdown
(
$
(
'
.js-branch-select
'
),
window
.
gl
.
availableRefs
);
break
;
case
'
projects:snippets:show
'
:
initNotes
();
break
;
case
'
projects:snippets:new
'
:
case
'
projects:snippets:edit
'
:
case
'
projects:snippets:create
'
:
...
...
@@ -273,6 +283,10 @@ import GpgBadges from './gpg_badges';
new
gl
.
Diff
();
shortcut_handler
=
new
ShortcutsIssuable
(
true
);
new
ZenMode
();
initIssuableSidebar
();
initNotes
();
const
mrShowNode
=
document
.
querySelector
(
'
.merge-request
'
);
window
.
mergeRequest
=
new
MergeRequest
({
action
:
mrShowNode
.
dataset
.
mrAction
,
...
...
@@ -281,11 +295,6 @@ import GpgBadges from './gpg_badges';
case
'
dashboard:activity
'
:
new
gl
.
Activities
();
break
;
case
'
dashboard:issues
'
:
case
'
dashboard:merge_requests
'
:
new
ProjectSelect
();
new
UsersSelect
();
break
;
case
'
projects:commit:show
'
:
new
Commit
();
new
gl
.
Diff
();
...
...
@@ -294,6 +303,7 @@ import GpgBadges from './gpg_badges';
new
MiniPipelineGraph
({
container
:
'
.js-commit-pipeline-graph
'
,
}).
bindEvents
();
initNotes
();
break
;
case
'
projects:commit:pipelines
'
:
new
MiniPipelineGraph
({
...
...
@@ -390,10 +400,20 @@ import GpgBadges from './gpg_badges';
case
'
projects:labels:edit
'
:
new
Labels
();
break
;
case
'
groups:labels:index
'
:
case
'
projects:labels:index
'
:
if
(
$
(
'
.prioritized-labels
'
).
length
)
{
new
gl
.
LabelManager
();
}
$
(
'
.label-subscription
'
).
each
((
i
,
el
)
=>
{
const
$el
=
$
(
el
);
if
(
$el
.
find
(
'
.dropdown-group-label
'
).
length
)
{
new
gl
.
GroupLabelSubscription
(
$el
);
}
else
{
new
gl
.
ProjectLabelSubscription
(
$el
);
}
});
break
;
case
'
projects:network:show
'
:
// Ensure we don't create a particular shortcut handler here. This is
...
...
@@ -438,10 +458,15 @@ import GpgBadges from './gpg_badges';
case
'
snippets:show
'
:
new
LineHighlighter
();
new
BlobViewer
();
initNotes
();
break
;
case
'
import:fogbugz:new_user_map
'
:
new
UsersSelect
();
break
;
case
'
profiles:personal_access_tokens:index
'
:
case
'
admin:impersonation_tokens:index
'
:
new
gl
.
DueDateSelectors
();
break
;
}
switch
(
path
.
first
())
{
case
'
sessions
'
:
...
...
app/assets/javascripts/init_issuable_sidebar.js
0 → 100644
View file @
563cb60e
/* eslint-disable no-new */
/* global MilestoneSelect */
/* global LabelsSelect */
/* global IssuableContext */
/* global Sidebar */
export
default
()
=>
{
const
sidebarOptions
=
JSON
.
parse
(
document
.
querySelector
(
'
.js-sidebar-options
'
).
innerHTML
);
new
MilestoneSelect
({
full_path
:
sidebarOptions
.
fullPath
,
});
new
LabelsSelect
();
new
IssuableContext
(
sidebarOptions
.
currentUser
);
gl
.
Subscription
.
bindAll
(
'
.subscription
'
);
new
gl
.
DueDateSelectors
();
window
.
sidebar
=
new
Sidebar
();
};
app/assets/javascripts/init_legacy_filters.js
0 → 100644
View file @
563cb60e
/* eslint-disable no-new */
/* global LabelsSelect */
/* global MilestoneSelect */
/* global IssueStatusSelect */
/* global SubscriptionSelect */
import
UsersSelect
from
'
./users_select
'
;
export
default
()
=>
{
new
UsersSelect
();
new
LabelsSelect
();
new
MilestoneSelect
();
new
IssueStatusSelect
();
new
SubscriptionSelect
();
};
app/assets/javascripts/init_notes.js
0 → 100644
View file @
563cb60e
/* global Notes */
export
default
()
=>
{
const
dataEl
=
document
.
querySelector
(
'
.js-notes-data
'
);
const
{
notesUrl
,
notesIds
,
now
,
diffView
,
autocomplete
,
}
=
JSON
.
parse
(
dataEl
.
innerHTML
);
window
.
notes
=
new
Notes
(
notesUrl
,
notesIds
,
now
,
diffView
,
autocomplete
);
};
app/assets/javascripts/issuable_context.js
View file @
563cb60e
...
...
@@ -4,6 +4,8 @@
import
Cookies
from
'
js-cookie
'
;
import
UsersSelect
from
'
./users_select
'
;
const
PARTICIPANTS_ROW_COUNT
=
7
;
(
function
()
{
this
.
IssuableContext
=
(
function
()
{
function
IssuableContext
(
currentUser
)
{
...
...
@@ -50,11 +52,9 @@ import UsersSelect from './users_select';
}
IssuableContext
.
prototype
.
initParticipants
=
function
()
{
var
_this
;
_this
=
this
;
$
(
document
).
on
(
"
click
"
,
"
.js-participants-more
"
,
this
.
toggleHiddenParticipants
);
return
$
(
"
.js-participants-author
"
).
each
(
function
(
i
)
{
if
(
i
>=
_this
.
PARTICIPANTS_ROW_COUNT
)
{
if
(
i
>=
PARTICIPANTS_ROW_COUNT
)
{
return
$
(
this
).
addClass
(
"
js-participants-hidden
"
).
hide
();
}
});
...
...
app/assets/javascripts/main.js
View file @
563cb60e
...
...
@@ -145,7 +145,6 @@ import './right_sidebar';
import
'
./search
'
;
import
'
./search_autocomplete
'
;
import
'
./smart_interval
'
;
import
'
./snippets_list
'
;
import
'
./star
'
;
import
'
./subscription
'
;
import
'
./subscription_select
'
;
...
...
@@ -354,4 +353,14 @@ $(function () {
gl
.
utils
.
renderTimeago
();
$
(
document
).
trigger
(
'
init.scrolling-tabs
'
);
$
(
'
form.filter-form
'
).
on
(
'
submit
'
,
function
(
event
)
{
const
link
=
document
.
createElement
(
'
a
'
);
link
.
href
=
this
.
action
;
const
action
=
`
${
this
.
action
}${
link
.
search
===
''
?
'
?
'
:
'
&
'
}
`
;
event
.
preventDefault
();
gl
.
utils
.
visitUrl
(
`
${
action
}${
$
(
this
).
serialize
()}
`
);
});
});
app/assets/javascripts/merge_conflicts/merge_conflicts_bundle.js
View file @
563cb60e
...
...
@@ -2,6 +2,7 @@
/* global Flash */
import
Vue
from
'
vue
'
;
import
initIssuableSidebar
from
'
../init_issuable_sidebar
'
;
import
'
./merge_conflict_store
'
;
import
'
./merge_conflict_service
'
;
import
'
./mixins/line_conflict_utils
'
;
...
...
@@ -19,6 +20,8 @@ $(() => {
resolveConflictsPath
:
conflictsEl
.
dataset
.
resolveConflictsPath
});
initIssuableSidebar
();
gl
.
MergeConflictsResolverApp
=
new
Vue
({
el
:
'
#conflicts
'
,
data
:
mergeConflictsStore
.
state
,
...
...
app/assets/javascripts/milestone_select.js
View file @
563cb60e
...
...
@@ -8,7 +8,7 @@
var
_this
,
$els
;
if
(
currentProject
!=
null
)
{
_this
=
this
;
this
.
currentProject
=
JSON
.
parse
(
currentProject
)
;
this
.
currentProject
=
typeof
currentProject
===
'
string
'
?
JSON
.
parse
(
currentProject
)
:
currentProject
;
}
$els
=
$
(
els
);
...
...
app/assets/javascripts/project.js
View file @
563cb60e
...
...
@@ -6,21 +6,22 @@ import Cookies from 'js-cookie';
(
function
()
{
this
.
Project
=
(
function
()
{
function
Project
()
{
$
(
'
ul.clone-options-dropdown a
'
).
click
(
function
()
{
var
url
;
if
(
$
(
this
).
hasClass
(
'
active
'
))
{
return
;
}
$
(
'
.active
'
).
not
(
$
(
this
)).
removeClass
(
'
active
'
);
$
(
this
).
toggleClass
(
'
active
'
);
url
=
$
(
"
#project_clone
"
).
val
();
$
(
'
#project_clone
'
).
val
(
url
);
const
$cloneOptions
=
$
(
'
ul.clone-options-dropdown
'
);
const
$projectCloneField
=
$
(
'
#project_clone
'
);
const
$cloneBtnText
=
$
(
'
a.clone-dropdown-btn span
'
);
$
(
'
a
'
,
$cloneOptions
).
on
(
'
click
'
,
(
e
)
=>
{
const
$this
=
$
(
e
.
currentTarget
);
const
url
=
$this
.
attr
(
'
href
'
);
e
.
preventDefault
();
$
(
'
.active
'
,
$cloneOptions
).
not
(
$this
).
removeClass
(
'
active
'
);
$this
.
toggleClass
(
'
active
'
);
$projectCloneField
.
val
(
url
);
$cloneBtnText
.
text
(
$this
.
text
());
return
$
(
'
.clone
'
).
text
(
url
);
// Git protocol switcher
// Remove the active class for all buttons (ssh, http, kerberos if shown)
// Add the active class for the clicked button
// Update the input field
// Update the command line instructions
});
// Ref switcher
this
.
initRefSwitcher
();
...
...
app/assets/javascripts/sidebar/sidebar_bundle.js
View file @
563cb60e
...
...
@@ -5,7 +5,8 @@ import sidebarAssignees from './components/assignees/sidebar_assignees';
import
Mediator
from
'
./sidebar_mediator
'
;
function
domContentLoaded
()
{
const
mediator
=
new
Mediator
(
gl
.
sidebarOptions
);
const
sidebarOptions
=
JSON
.
parse
(
document
.
querySelector
(
'
.js-sidebar-options
'
).
innerHTML
);
const
mediator
=
new
Mediator
(
sidebarOptions
);
mediator
.
fetch
();
const
sidebarAssigneesEl
=
document
.
querySelector
(
'
#js-vue-sidebar-assignees
'
);
...
...
app/assets/javascripts/snippets_list.js
deleted
100644 → 0
View file @
fa1e41ea
function
SnippetsList
()
{
const
$holder
=
$
(
'
.snippets-list-holder
'
);
$holder
.
find
(
'
.pagination
'
).
on
(
'
ajax:success
'
,
(
e
,
data
)
=>
{
$holder
.
replaceWith
(
data
.
html
);
});
}
window
.
gl
.
SnippetsList
=
SnippetsList
;
app/assets/javascripts/todos.js
View file @
563cb60e
...
...
@@ -37,10 +37,6 @@ export default class Todos {
this
.
initFilterDropdown
(
$
(
'
.js-type-search
'
),
'
type
'
);
this
.
initFilterDropdown
(
$
(
'
.js-action-search
'
),
'
action_id
'
);
$
(
'
form.filter-form
'
).
on
(
'
submit
'
,
function
applyFilters
(
event
)
{
event
.
preventDefault
();
gl
.
utils
.
visitUrl
(
`
${
this
.
action
}
&
${
$
(
this
).
serialize
()}
`
);
});
return
new
UsersSelect
();
}
...
...
app/helpers/issuables_helper.rb
View file @
563cb60e
...
...
@@ -354,4 +354,14 @@ module IssuablesHelper
params
[
:format
]
=
:json
if
issuable
.
is_a?
(
Issue
)
end
end
def
issuable_sidebar_options
(
issuable
,
can_edit_issuable
)
{
endpoint:
"
#{
issuable_json_path
(
issuable
)
}
?basic=true"
,
editable:
can_edit_issuable
,
currentUser:
current_user
.
as_json
(
only:
[
:username
,
:id
,
:name
],
methods: :avatar_url
),
rootPath:
root_path
,
fullPath:
@project
.
full_path
}
end
end
app/helpers/notes_helper.rb
View file @
563cb60e
...
...
@@ -130,4 +130,14 @@ module NotesHelper
can?
(
current_user
,
:create_note
,
@project
)
end
end
def
initial_notes_data
(
autocomplete
)
{
notesUrl:
notes_url
,
notesIds:
@notes
.
map
(
&
:id
),
now:
Time
.
now
.
to_i
,
diffView:
diff_view
,
autocomplete:
autocomplete
}
end
end
app/views/shared/_clone_panel.html.haml
View file @
563cb60e
...
...
@@ -20,11 +20,3 @@
=
text_field_tag
:project_clone
,
default_url_to_repo
(
project
),
class:
"js-select-on-focus form-control"
,
readonly:
true
,
aria:
{
label:
'Project clone URL'
}
.input-group-btn
=
clipboard_button
(
target:
'#project_clone'
,
title:
_
(
"Copy URL to clipboard"
),
class:
"btn-default btn-clipboard"
)
:javascript
$
(
'
ul.clone-options-dropdown a
'
).
on
(
'
click
'
,
function
(
e
){
e
.
preventDefault
();
var
$this
=
$
(
this
);
$
(
'
a.clone-dropdown-btn span
'
).
text
(
$this
.
text
());
$
(
'
#project_clone
'
).
val
(
$this
.
attr
(
'
href
'
));
});
app/views/shared/_label.html.haml
View file @
563cb60e
...
...
@@ -76,11 +76,3 @@
=
link_to
destroy_label_path
(
label
),
title:
"Delete"
,
class:
'btn btn-transparent btn-action remove-row'
,
method: :delete
,
data:
{
confirm:
label_deletion_confirm_text
(
label
),
toggle:
"tooltip"
}
do
%span
.sr-only
Delete
=
icon
(
'trash-o'
)
-
if
current_user
-
if
can_subscribe_to_label_in_different_levels?
(
label
)
:javascript
new
gl
.
GroupLabelSubscription
(
'
##{dom_id(label)} .label-subscription
'
);
-
else
:javascript
new
gl
.
ProjectLabelSubscription
(
'
##{dom_id(label)} .label-subscription
'
);
app/views/shared/_personal_access_tokens_form.html.haml
View file @
563cb60e
...
...
@@ -23,18 +23,3 @@
.prepend-top-default
=
f
.
submit
"Create
#{
type
}
token"
,
class:
"btn btn-create"
:javascript
var
$dateField
=
$
(
'
.datepicker
'
);
var
date
=
$dateField
.
val
();
new
Pikaday
({
field
:
$dateField
.
get
(
0
),
theme
:
'
gitlab-theme animate-picker
'
,
format
:
'
yyyy-mm-dd
'
,
minDate
:
new
Date
(),
container
:
$dateField
.
parent
().
get
(
0
),
onSelect
:
function
(
dateText
)
{
$dateField
.
val
(
dateFormat
(
new
Date
(
dateText
),
'
yyyy-mm-dd
'
));
}
});
app/views/shared/issuable/_filter.html.haml
View file @
563cb60e
...
...
@@ -36,13 +36,3 @@
.row-content-block.second-block.filtered-labels
{
class:
(
"hidden"
unless
has_labels
)
}
-
if
has_labels
=
render
'shared/labels_row'
,
labels:
@labels
:javascript
new
LabelsSelect
();
new
MilestoneSelect
();
new
IssueStatusSelect
();
new
SubscriptionSelect
();
$
(
'
form.filter-form
'
).
on
(
'
submit
'
,
function
(
event
)
{
event
.
preventDefault
();
gl
.
utils
.
visitUrl
(
this
.
action
+
'
&
'
+
$
(
this
).
serialize
());
});
app/views/shared/issuable/_participants.html.haml
View file @
563cb60e
...
...
@@ -16,5 +16,3 @@
.hide-collapsed.participants-more
%a
.js-participants-more
{
href:
"#"
,
data:
{
original_text:
"+ #{participants_size - 7} more"
,
less_text:
"- show less"
}
}
+
#{
participants_extra
}
more
:javascript
IssuableContext
.
prototype
.
PARTICIPANTS_ROW_COUNT
=
#{
participants_row
}
;
app/views/shared/issuable/_search_bar.html.haml
View file @
563cb60e
...
...
@@ -108,12 +108,3 @@
#js-add-issues-btn
.prepend-left-10
-
elsif
type
!=
:boards_modal
=
render
'shared/sort_dropdown'
-
unless
type
===
:boards_modal
:javascript
$
(
document
).
off
(
'
page:restore
'
).
on
(
'
page:restore
'
,
function
(
event
)
{
if
(
gl
.
FilteredSearchManager
)
{
const
filteredSearchManager
=
new
gl
.
FilteredSearchManager
();
filteredSearchManager
.
setup
();
}
});
app/views/shared/issuable/_sidebar.html.haml
View file @
563cb60e
...
...
@@ -138,17 +138,4 @@
=
project_ref
=
clipboard_button
(
text:
project_ref
,
title:
"Copy reference to clipboard"
,
placement:
"left"
)
:javascript
gl
.
sidebarOptions
=
{
endpoint
:
"
#{
issuable_json_path
(
issuable
)
}
?basic=true
"
,
editable
:
#{
can_edit_issuable
?
true
:
false
}
,
currentUser
:
#{
current_user
.
to_json
(
only:
[
:username
,
:id
,
:name
],
methods: :avatar_url
)
}
,
rootPath
:
"
#{
root_path
}
"
};
new
MilestoneSelect
(
'
{"full_path":"
#{
@project
.
full_path
}
"}
'
);
new
LabelsSelect
();
new
IssuableContext
(
'
#{
escape_javascript
(
current_user
.
to_json
(
only:
[
:username
,
:id
,
:name
]))
}
'
);
gl
.
Subscription
.
bindAll
(
'
.subscription
'
);
new
gl
.
DueDateSelectors
();
window
.
sidebar
=
new
Sidebar
();
%script
.js-sidebar-options
{
type:
"application/json"
}=
issuable_sidebar_options
(
issuable
,
can_edit_issuable
).
to_json
.
html_safe
app/views/shared/notes/_notes_with_form.html.haml
View file @
563cb60e
...
...
@@ -22,5 +22,4 @@
=
link_to
"sign in"
,
new_session_path
(
:user
,
redirect_to_referer:
'yes'
)
to comment
:javascript
var
notes
=
new
Notes
(
"
#{
notes_url
}
"
,
#{
@notes
.
map
(
&
:id
).
to_json
}
,
#{
Time
.
now
.
to_i
}
,
"
#{
diff_view
}
"
,
#{
autocomplete
}
)
%script
.js-notes-data
{
type:
"application/json"
}=
initial_notes_data
(
autocomplete
).
to_json
.
html_safe
app/views/snippets/_snippets.html.haml
View file @
563cb60e
-
remote
=
local_assigns
.
fetch
(
:remote
,
false
)
-
link_project
=
local_assigns
.
fetch
(
:link_project
,
false
)
.snippets-list-holder
...
...
@@ -8,7 +7,4 @@
%li
.nothing-here-block
Nothing here.
=
paginate
@snippets
,
theme:
'gitlab'
,
remote:
remote
:javascript
gl
.
SnippetsList
();
=
paginate
@snippets
,
theme:
'gitlab'
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