Skip to content
GitLab
Explore
Sign in
Primary navigation
Search or go to…
Project
F
frama-c
Manage
Activity
Members
Labels
Plan
Issues
Issue boards
Milestones
Wiki
Code
Merge requests
Repository
Branches
Commits
Tags
Repository graph
Compare revisions
Deploy
Releases
Container Registry
Model registry
Monitor
Incidents
Analyze
Value stream analytics
Contributor analytics
Repository analytics
Model experiments
Help
Help
Support
GitLab documentation
Compare GitLab plans
Community forum
Contribute to GitLab
Provide feedback
Keyboard shortcuts
?
Snippets
Groups
Projects
Show more breadcrumbs
pub
frama-c
Commits
6110f220
Commit
6110f220
authored
3 years ago
by
Loïc Correnson
Browse files
Options
Downloads
Patches
Plain Diff
[ivette] more types in dome main process
# Conflicts: # ivette/src/dome/main/dome.ts
parent
763e1262
No related branches found
No related tags found
No related merge requests found
Changes
1
Hide whitespace changes
Inline
Side-by-side
Showing
1 changed file
ivette/src/dome/main/dome.ts
+69
-42
69 additions, 42 deletions
ivette/src/dome/main/dome.ts
with
69 additions
and
42 deletions
ivette/src/dome/main/dome.ts
+
69
−
42
View file @
6110f220
...
@@ -20,7 +20,6 @@
...
@@ -20,7 +20,6 @@
/* */
/* */
/* ************************************************************************ */
/* ************************************************************************ */
/* eslint-disable @typescript-eslint/explicit-function-return-type */
/* eslint-disable no-console */
/* eslint-disable no-console */
/**
/**
...
@@ -50,6 +49,7 @@ import {
...
@@ -50,6 +49,7 @@ import {
shell
,
shell
,
dialog
,
dialog
,
nativeTheme
,
nativeTheme
,
Rectangle
,
}
from
'
electron
'
;
}
from
'
electron
'
;
import
installExtension
,
{
REACT_DEVELOPER_TOOLS
}
from
'
dome/devtools
'
;
import
installExtension
,
{
REACT_DEVELOPER_TOOLS
}
from
'
dome/devtools
'
;
import
SYS
,
*
as
System
from
'
dome/system
'
;
import
SYS
,
*
as
System
from
'
dome/system
'
;
...
@@ -65,7 +65,7 @@ import * as Menubar from './menubar';
...
@@ -65,7 +65,7 @@ import * as Menubar from './menubar';
// --- System Helpers
// --- System Helpers
// --------------------------------------------------------------------------
// --------------------------------------------------------------------------
function
fstat
(
p
:
string
)
{
function
fstat
(
p
:
string
)
:
fs
.
Stats
|
undefined
{
try
{
try
{
return
fs
.
statSync
(
p
);
return
fs
.
statSync
(
p
);
}
catch
(
_error
)
{
}
catch
(
_error
)
{
...
@@ -97,7 +97,7 @@ nativeTheme.on('updated', () => {
...
@@ -97,7 +97,7 @@ nativeTheme.on('updated', () => {
broadcast
(
'
dome.theme.updated
'
);
broadcast
(
'
dome.theme.updated
'
);
});
});
function
setNativeTheme
(
theme
:
string
|
undefined
)
{
function
setNativeTheme
(
theme
:
string
|
undefined
)
:
void
{
switch
(
theme
)
{
switch
(
theme
)
{
case
'
dark
'
:
case
'
dark
'
:
case
'
light
'
:
case
'
light
'
:
...
@@ -113,7 +113,13 @@ function setNativeTheme(theme: string | undefined) {
...
@@ -113,7 +113,13 @@ function setNativeTheme(theme: string | undefined) {
// --- Settings
// --- Settings
// --------------------------------------------------------------------------
// --------------------------------------------------------------------------
function
loadSettings
(
file
:
string
)
{
type
json
=
|
undefined
|
null
|
boolean
|
number
|
string
|
{
[
key
:
string
]:
json
};
type
Store
=
{
[
key
:
string
]:
json
};
type
Frame
=
{
x
:
number
,
y
:
number
,
width
:
number
,
height
:
number
};
function
loadSettings
(
file
:
string
):
Store
{
try
{
try
{
if
(
!
fstat
(
file
))
if
(
!
fstat
(
file
))
return
{};
return
{};
...
@@ -125,7 +131,7 @@ function loadSettings(file: string) {
...
@@ -125,7 +131,7 @@ function loadSettings(file: string) {
}
}
}
}
function
saveSettings
(
file
:
string
,
data
=
{})
{
function
saveSettings
(
file
:
string
,
data
:
Store
=
{}):
void
{
try
{
try
{
const
text
=
JSON
.
stringify
(
data
,
undefined
,
DEVEL
?
2
:
0
);
const
text
=
JSON
.
stringify
(
data
,
undefined
,
DEVEL
?
2
:
0
);
fs
.
writeFileSync
(
file
,
text
,
{
encoding
:
'
utf8
'
});
fs
.
writeFileSync
(
file
,
text
,
{
encoding
:
'
utf8
'
});
...
@@ -144,7 +150,7 @@ const APP_DIR = app.getPath('userData');
...
@@ -144,7 +150,7 @@ const APP_DIR = app.getPath('userData');
const
PATH_WINDOW_SETTINGS
=
path
.
join
(
APP_DIR
,
'
WindowSettings.json
'
);
const
PATH_WINDOW_SETTINGS
=
path
.
join
(
APP_DIR
,
'
WindowSettings.json
'
);
const
PATH_GLOBAL_SETTINGS
=
path
.
join
(
APP_DIR
,
'
GlobalSettings.json
'
);
const
PATH_GLOBAL_SETTINGS
=
path
.
join
(
APP_DIR
,
'
GlobalSettings.json
'
);
function
saveGlobalSettings
()
{
function
saveGlobalSettings
()
:
void
{
try
{
try
{
if
(
!
fstat
(
APP_DIR
))
fs
.
mkdirSync
(
APP_DIR
);
if
(
!
fstat
(
APP_DIR
))
fs
.
mkdirSync
(
APP_DIR
);
saveSettings
(
PATH_GLOBAL_SETTINGS
,
GlobalSettings
);
saveSettings
(
PATH_GLOBAL_SETTINGS
,
GlobalSettings
);
...
@@ -153,7 +159,7 @@ function saveGlobalSettings() {
...
@@ -153,7 +159,7 @@ function saveGlobalSettings() {
}
}
}
}
function
obtainGlobalSettings
()
{
function
obtainGlobalSettings
()
:
Store
{
if
(
_
.
isEmpty
(
GlobalSettings
))
{
if
(
_
.
isEmpty
(
GlobalSettings
))
{
GlobalSettings
=
loadSettings
(
PATH_GLOBAL_SETTINGS
);
GlobalSettings
=
loadSettings
(
PATH_GLOBAL_SETTINGS
);
}
}
...
@@ -164,12 +170,10 @@ function obtainGlobalSettings() {
...
@@ -164,12 +170,10 @@ function obtainGlobalSettings() {
// --- Window Settings & Frames
// --- Window Settings & Frames
// --------------------------------------------------------------------------
// --------------------------------------------------------------------------
type
Store
=
{
[
key
:
string
]:
unknown
};
interface
Handle
{
interface
Handle
{
primary
:
boolean
;
// Primary window
primary
:
boolean
;
// Primary window
window
:
BrowserWindow
;
// Also prevents Gc
window
:
BrowserWindow
;
// Also prevents Gc
frame
:
Electron
.
Rectangle
;
// Window frame
frame
:
Electron
.
Rectangle
|
undefined
;
// Window frame
devtools
:
boolean
;
// Developper tools visible
devtools
:
boolean
;
// Developper tools visible
reloaded
:
boolean
;
// Reloaded window
reloaded
:
boolean
;
// Reloaded window
config
:
string
;
// Path to config file
config
:
string
;
// Path to config file
...
@@ -179,9 +183,29 @@ interface Handle {
...
@@ -179,9 +183,29 @@ interface Handle {
const
WindowHandles
=
new
Map
<
number
,
Handle
>
();
// Indexed by *webContents* id
const
WindowHandles
=
new
Map
<
number
,
Handle
>
();
// Indexed by *webContents* id
function
saveWindowConfig
(
handle
:
Handle
)
{
function
jInt
(
v
:
json
):
number
{
const
configData
=
{
return
_
.
toSafeInteger
(
v
);
frame
:
handle
.
frame
,
}
function
jFrame
(
obj
:
json
|
Rectangle
):
Frame
|
undefined
{
if
(
obj
&&
typeof
(
obj
)
===
'
object
'
)
return
{
x
:
jInt
(
obj
.
x
),
y
:
jInt
(
obj
.
y
),
width
:
jInt
(
obj
.
width
),
height
:
jInt
(
obj
.
height
),
};
return
undefined
;
}
function
jStore
(
obj
:
json
):
Store
{
return
obj
!==
null
&&
typeof
(
obj
)
===
'
object
'
?
obj
:
{};
}
function
saveWindowConfig
(
handle
:
Handle
):
void
{
const
frame
=
jFrame
(
handle
.
frame
);
const
configData
:
Store
=
{
frame
,
settings
:
handle
.
settings
,
settings
:
handle
.
settings
,
storage
:
handle
.
storage
,
storage
:
handle
.
storage
,
devtools
:
handle
.
devtools
,
devtools
:
handle
.
devtools
,
...
@@ -189,7 +213,7 @@ function saveWindowConfig(handle: Handle) {
...
@@ -189,7 +213,7 @@ function saveWindowConfig(handle: Handle) {
saveSettings
(
handle
.
config
,
configData
);
saveSettings
(
handle
.
config
,
configData
);
}
}
function
windowSyncSettings
(
event
:
IpcMainEvent
)
{
function
windowSyncSettings
(
event
:
IpcMainEvent
)
:
void
{
const
handle
=
WindowHandles
.
get
(
event
.
sender
.
id
);
const
handle
=
WindowHandles
.
get
(
event
.
sender
.
id
);
event
.
returnValue
=
{
event
.
returnValue
=
{
globals
:
obtainGlobalSettings
(),
globals
:
obtainGlobalSettings
(),
...
@@ -209,9 +233,9 @@ function applyThemeSettings(settings: Store) {
...
@@ -209,9 +233,9 @@ function applyThemeSettings(settings: Store) {
// --- Patching Settings
// --- Patching Settings
// --------------------------------------------------------------------------
// --------------------------------------------------------------------------
type
Patch
=
{
key
:
string
;
value
:
unknow
n
};
type
Patch
=
{
key
:
string
;
value
:
jso
n
};
function
applyPatches
(
data
:
Store
,
args
:
Patch
[])
{
function
applyPatches
(
data
:
Store
,
args
:
Patch
[])
:
void
{
args
.
forEach
(({
key
,
value
})
=>
{
args
.
forEach
(({
key
,
value
})
=>
{
if
(
value
===
null
)
{
if
(
value
===
null
)
{
delete
data
[
key
];
delete
data
[
key
];
...
@@ -221,7 +245,7 @@ function applyPatches(data: Store, args: Patch[]) {
...
@@ -221,7 +245,7 @@ function applyPatches(data: Store, args: Patch[]) {
});
});
}
}
function
applyWindowSettings
(
event
:
IpcMainEvent
,
args
:
Patch
[])
{
function
applyWindowSettings
(
event
:
IpcMainEvent
,
args
:
Patch
[])
:
void
{
const
handle
=
WindowHandles
.
get
(
event
.
sender
.
id
);
const
handle
=
WindowHandles
.
get
(
event
.
sender
.
id
);
if
(
handle
)
{
if
(
handle
)
{
applyPatches
(
handle
.
settings
,
args
);
applyPatches
(
handle
.
settings
,
args
);
...
@@ -229,7 +253,7 @@ function applyWindowSettings(event: IpcMainEvent, args: Patch[]) {
...
@@ -229,7 +253,7 @@ function applyWindowSettings(event: IpcMainEvent, args: Patch[]) {
}
}
}
}
function
applyStorageSettings
(
event
:
IpcMainEvent
,
args
:
Patch
[])
{
function
applyStorageSettings
(
event
:
IpcMainEvent
,
args
:
Patch
[])
:
void
{
const
handle
=
WindowHandles
.
get
(
event
.
sender
.
id
);
const
handle
=
WindowHandles
.
get
(
event
.
sender
.
id
);
if
(
handle
)
{
if
(
handle
)
{
applyPatches
(
handle
.
storage
,
args
);
applyPatches
(
handle
.
storage
,
args
);
...
@@ -237,7 +261,7 @@ function applyStorageSettings(event: IpcMainEvent, args: Patch[]) {
...
@@ -237,7 +261,7 @@ function applyStorageSettings(event: IpcMainEvent, args: Patch[]) {
}
}
}
}
function
applyGlobalSettings
(
event
:
IpcMainEvent
,
args
:
Patch
[])
{
function
applyGlobalSettings
(
event
:
IpcMainEvent
,
args
:
Patch
[])
:
void
{
const
settings
:
Store
=
obtainGlobalSettings
();
const
settings
:
Store
=
obtainGlobalSettings
();
applyPatches
(
settings
,
args
);
applyPatches
(
settings
,
args
);
applyThemeSettings
(
settings
);
applyThemeSettings
(
settings
);
...
@@ -258,7 +282,7 @@ ipcMain.on('dome.ipc.settings.storage', applyStorageSettings);
...
@@ -258,7 +282,7 @@ ipcMain.on('dome.ipc.settings.storage', applyStorageSettings);
// --- Renderer-Process Communication
// --- Renderer-Process Communication
// --------------------------------------------------------------------------
// --------------------------------------------------------------------------
function
broadcast
(
event
:
string
,
...
args
:
unknown
[])
{
function
broadcast
(
event
:
string
,
...
args
:
unknown
[])
:
void
{
BrowserWindow
.
getAllWindows
().
forEach
((
w
)
=>
{
BrowserWindow
.
getAllWindows
().
forEach
((
w
)
=>
{
w
.
webContents
.
send
(
event
,
...
args
);
w
.
webContents
.
send
(
event
,
...
args
);
});
});
...
@@ -274,16 +298,16 @@ const MODIFIED = '(*) ';
...
@@ -274,16 +298,16 @@ const MODIFIED = '(*) ';
/**
/**
Sets application window name
Sets application window name
*/
*/
export
function
setName
(
title
:
string
)
{
export
function
setName
(
title
:
string
)
:
void
{
appName
=
title
;
appName
=
title
;
}
}
function
setTitle
(
event
:
IpcMainEvent
,
title
:
string
)
{
function
setTitle
(
event
:
IpcMainEvent
,
title
:
string
)
:
void
{
const
handle
=
WindowHandles
.
get
(
event
.
sender
.
id
);
const
handle
=
WindowHandles
.
get
(
event
.
sender
.
id
);
if
(
handle
)
handle
.
window
.
setTitle
(
title
||
appName
);
if
(
handle
)
handle
.
window
.
setTitle
(
title
||
appName
);
}
}
function
setModified
(
event
:
IpcMainEvent
,
modified
:
boolean
)
{
function
setModified
(
event
:
IpcMainEvent
,
modified
:
boolean
)
:
void
{
const
handle
=
WindowHandles
.
get
(
event
.
sender
.
id
);
const
handle
=
WindowHandles
.
get
(
event
.
sender
.
id
);
if
(
handle
)
{
if
(
handle
)
{
const
w
=
handle
.
window
;
const
w
=
handle
.
window
;
...
@@ -303,7 +327,7 @@ function setModified(event: IpcMainEvent, modified: boolean) {
...
@@ -303,7 +327,7 @@ function setModified(event: IpcMainEvent, modified: boolean) {
ipcMain
.
on
(
'
dome.ipc.window.title
'
,
setTitle
);
ipcMain
.
on
(
'
dome.ipc.window.title
'
,
setTitle
);
ipcMain
.
on
(
'
dome.ipc.window.modified
'
,
setModified
);
ipcMain
.
on
(
'
dome.ipc.window.modified
'
,
setModified
);
function
getURL
()
{
function
getURL
()
:
string
{
if
(
DEVEL
)
if
(
DEVEL
)
return
`http://localhost:
${
process
.
env
.
ELECTRON_WEBPACK_WDS_PORT
}
`
;
return
`http://localhost:
${
process
.
env
.
ELECTRON_WEBPACK_WDS_PORT
}
`
;
if
(
LOCAL
)
if
(
LOCAL
)
...
@@ -328,7 +352,7 @@ function navigateURL(sender: Electron.WebContents) {
...
@@ -328,7 +352,7 @@ function navigateURL(sender: Electron.WebContents) {
// --- Lookup for config file
// --- Lookup for config file
// --------------------------------------------------------------------------
// --------------------------------------------------------------------------
function
lookupConfig
(
pwd
=
'
.
'
)
{
function
lookupConfig
(
pwd
=
'
.
'
)
:
string
{
const
wdir
=
path
.
resolve
(
pwd
);
const
wdir
=
path
.
resolve
(
pwd
);
let
cwd
=
wdir
;
let
cwd
=
wdir
;
const
cfg
=
`.
${
appName
.
toLowerCase
()}
`
;
const
cfg
=
`.
${
appName
.
toLowerCase
()}
`
;
...
@@ -353,7 +377,7 @@ function createBrowserWindow(
...
@@ -353,7 +377,7 @@ function createBrowserWindow(
config
:
BrowserWindowConstructorOptions
,
config
:
BrowserWindowConstructorOptions
,
argv
?:
string
[],
argv
?:
string
[],
wdir
?:
string
,
wdir
?:
string
,
)
{
)
:
BrowserWindow
{
const
isAppWindow
=
(
argv
!==
undefined
&&
wdir
!==
undefined
);
const
isAppWindow
=
(
argv
!==
undefined
&&
wdir
!==
undefined
);
...
@@ -375,13 +399,16 @@ function createBrowserWindow(
...
@@ -375,13 +399,16 @@ function createBrowserWindow(
const
configFile
=
isAppWindow
?
lookupConfig
(
wdir
)
:
PATH_WINDOW_SETTINGS
;
const
configFile
=
isAppWindow
?
lookupConfig
(
wdir
)
:
PATH_WINDOW_SETTINGS
;
const
configData
=
loadSettings
(
configFile
);
const
configData
=
loadSettings
(
configFile
);
const
{
frame
,
devtools
,
settings
=
{},
storage
=
{}
}
=
configData
;
const
frame
=
jFrame
(
configData
.
frame
);
const
settings
=
jStore
(
configData
.
settings
);
const
storage
=
jStore
(
configData
.
storage
);
const
devtools
=
!!
configData
.
devtools
;
if
(
frame
)
{
if
(
frame
)
{
const
getInt
=
<
A
>
(
v
:
A
)
=>
v
&&
_
.
toSafeInteger
(
v
);
options
.
x
=
frame
.
x
;
options
.
x
=
getInt
(
frame
.
x
);
options
.
y
=
frame
.
y
;
options
.
y
=
getInt
(
frame
.
y
);
options
.
width
=
frame
.
width
;
options
.
width
=
getInt
(
frame
.
width
);
options
.
height
=
frame
.
height
;
options
.
height
=
getInt
(
frame
.
height
);
}
}
const
theWindow
=
new
BrowserWindow
(
options
);
const
theWindow
=
new
BrowserWindow
(
options
);
...
@@ -468,11 +495,11 @@ function createBrowserWindow(
...
@@ -468,11 +495,11 @@ function createBrowserWindow(
// --- Application Window(s) & Command Line
// --- Application Window(s) & Command Line
// --------------------------------------------------------------------------
// --------------------------------------------------------------------------
function
stripElectronArgv
(
argv
:
string
[])
{
function
stripElectronArgv
(
argv
:
string
[])
:
string
[]
{
return
argv
.
slice
(
DEVEL
?
3
:
(
LOCAL
?
2
:
1
)).
filter
((
p
)
=>
!!
p
);
return
argv
.
slice
(
DEVEL
?
3
:
(
LOCAL
?
2
:
1
)).
filter
((
p
)
=>
!!
p
);
}
}
function
createPrimaryWindow
()
{
function
createPrimaryWindow
()
:
void
{
// Initialize Menubar
// Initialize Menubar
Menubar
.
install
();
Menubar
.
install
();
...
@@ -511,7 +538,7 @@ function createSecondaryWindow(
...
@@ -511,7 +538,7 @@ function createSecondaryWindow(
}
}
}
}
function
createDesktopWindow
()
{
function
createDesktopWindow
()
:
void
{
const
wdir
=
app
.
getPath
(
'
home
'
);
const
wdir
=
app
.
getPath
(
'
home
'
);
const
title
=
`
${
appName
}
#
${
++
appCount
}
`
;
const
title
=
`
${
appName
}
#
${
++
appCount
}
`
;
createBrowserWindow
(
false
,
{
title
},
[],
wdir
);
createBrowserWindow
(
false
,
{
title
},
[],
wdir
);
...
@@ -521,7 +548,7 @@ function createDesktopWindow() {
...
@@ -521,7 +548,7 @@ function createDesktopWindow() {
// --- Activate Windows (macOS)
// --- Activate Windows (macOS)
// --------------------------------------------------------------------------
// --------------------------------------------------------------------------
function
activateWindows
()
{
function
activateWindows
()
:
void
{
let
isFocused
=
false
;
let
isFocused
=
false
;
let
toFocus
:
BrowserWindow
|
undefined
;
let
toFocus
:
BrowserWindow
|
undefined
;
BrowserWindow
.
getAllWindows
().
forEach
((
w
)
=>
{
BrowserWindow
.
getAllWindows
().
forEach
((
w
)
=>
{
...
@@ -544,7 +571,7 @@ function activateWindows() {
...
@@ -544,7 +571,7 @@ function activateWindows() {
let
PreferenceWindow
:
BrowserWindow
|
undefined
;
let
PreferenceWindow
:
BrowserWindow
|
undefined
;
function
showSettingsWindow
()
{
function
showSettingsWindow
()
:
void
{
if
(
!
PreferenceWindow
)
if
(
!
PreferenceWindow
)
PreferenceWindow
=
createBrowserWindow
(
PreferenceWindow
=
createBrowserWindow
(
false
,
{
false
,
{
...
@@ -560,7 +587,7 @@ function showSettingsWindow() {
...
@@ -560,7 +587,7 @@ function showSettingsWindow() {
PreferenceWindow
.
on
(
'
closed
'
,
()
=>
{
PreferenceWindow
=
undefined
;
});
PreferenceWindow
.
on
(
'
closed
'
,
()
=>
{
PreferenceWindow
=
undefined
;
});
}
}
function
restoreDefaultSettings
()
{
function
restoreDefaultSettings
()
:
void
{
GlobalSettings
=
{};
GlobalSettings
=
{};
nativeTheme
.
themeSource
=
'
system
'
;
nativeTheme
.
themeSource
=
'
system
'
;
if
(
DEVEL
)
saveGlobalSettings
();
if
(
DEVEL
)
saveGlobalSettings
();
...
@@ -592,7 +619,7 @@ ipcMain.on('dome.app.paths', (event) => {
...
@@ -592,7 +619,7 @@ ipcMain.on('dome.app.paths', (event) => {
// --------------------------------------------------------------------------
// --------------------------------------------------------------------------
/** Starts the main process. */
/** Starts the main process. */
export
function
start
()
{
export
function
start
()
:
void
{
// Workaround to recover the original commandline of a second instance
// Workaround to recover the original commandline of a second instance
// after chromium messes with the argument order.
// after chromium messes with the argument order.
...
@@ -633,21 +660,21 @@ export function start() {
...
@@ -633,21 +660,21 @@ export function start() {
/**
/**
Define a custom main window menu.
Define a custom main window menu.
*/
*/
export
function
addMenu
(
label
:
string
)
{
export
function
addMenu
(
label
:
string
)
:
void
{
Menubar
.
addMenu
(
label
);
Menubar
.
addMenu
(
label
);
}
}
/**
/**
Define a custom menu item.
Define a custom menu item.
*/
*/
export
function
addMenuItem
(
spec
:
Menubar
.
CustomMenuItemSpec
)
{
export
function
addMenuItem
(
spec
:
Menubar
.
CustomMenuItemSpec
)
:
void
{
Menubar
.
addMenuItem
(
spec
);
Menubar
.
addMenuItem
(
spec
);
}
}
/**
/**
Update a menu item.
Update a menu item.
*/
*/
export
function
setMenuItem
(
spec
:
Menubar
.
CustomMenuItem
)
{
export
function
setMenuItem
(
spec
:
Menubar
.
CustomMenuItem
)
:
void
{
Menubar
.
setMenuItem
(
spec
);
Menubar
.
setMenuItem
(
spec
);
}
}
...
...
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