Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Sign in / Register
Toggle navigation
M
Mycard Mobile
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Locked Files
Issues
0
Issues
0
List
Boards
Labels
Service Desk
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Security & Compliance
Security & Compliance
Dependency List
License Compliance
Packages
Packages
List
Container Registry
Analytics
Analytics
CI / CD
Code Review
Insights
Issues
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
GaiaXalter
Mycard Mobile
Commits
e349c038
Commit
e349c038
authored
Jul 21, 2017
by
神楽坂玲奈
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
clean
parent
631f4741
Changes
19
Hide whitespace changes
Inline
Side-by-side
Showing
19 changed files
with
85 additions
and
107 deletions
+85
-107
.angular-cli.json
.angular-cli.json
+1
-1
src/app/app-routing.module.ts
src/app/app-routing.module.ts
+0
-2
src/app/app.component.ts
src/app/app.component.ts
+1
-7
src/app/auth.guard.ts
src/app/auth.guard.ts
+0
-1
src/app/lobby/lobby.component.html
src/app/lobby/lobby.component.html
+6
-6
src/app/lobby/lobby.component.ts
src/app/lobby/lobby.component.ts
+10
-18
src/app/login.service.ts
src/app/login.service.ts
+3
-6
src/app/match/match.component.html
src/app/match/match.component.html
+1
-1
src/app/match/match.component.ts
src/app/match/match.component.ts
+3
-2
src/app/new-room/new-room.component.ts
src/app/new-room/new-room.component.ts
+2
-2
src/app/room-list/room-list.component.html
src/app/room-list/room-list.component.html
+7
-7
src/app/room-list/room-list.component.ts
src/app/room-list/room-list.component.ts
+2
-3
src/app/toolbar/toolbar.component.html
src/app/toolbar/toolbar.component.html
+1
-1
src/app/toolbar/toolbar.component.ts
src/app/toolbar/toolbar.component.ts
+4
-4
src/app/watch/watch.component.html
src/app/watch/watch.component.html
+7
-7
src/app/watch/watch.component.ts
src/app/watch/watch.component.ts
+2
-3
src/app/windbot/windbot.component.ts
src/app/windbot/windbot.component.ts
+1
-1
src/app/ygopro.service.ts
src/app/ygopro.service.ts
+33
-34
src/index.html
src/index.html
+1
-1
No files found.
.angular-cli.json
View file @
e349c038
...
...
@@ -18,7 +18,7 @@
"tsconfig"
:
"tsconfig.app.json"
,
"testTsconfig"
:
"tsconfig.spec.json"
,
"prefix"
:
"app"
,
"serviceWorker"
:
tru
e
,
"serviceWorker"
:
fals
e
,
"styles"
:
[
"styles.css"
],
...
...
src/app/app-routing.module.ts
View file @
e349c038
...
...
@@ -18,10 +18,8 @@ const routes: Routes = [
{
path
:
'
ygopro/rooms/new
'
,
component
:
NewRoomComponent
},
{
path
:
'
ygopro/rooms
'
,
component
:
RoomListComponent
},
{
path
:
'
ygopro/lobby
'
,
component
:
LobbyComponent
},
{
path
:
'
ygopro/match/:arena
'
,
component
:
MatchDialog
},
{
path
:
'
ygopro/windbot
'
,
component
:
WindbotComponent
},
{
path
:
'
ygopro/watch
'
,
component
:
WatchComponent
},
// { path: 'ygopro/rooms/join', component: JoinComponent }
]
},
];
...
...
src/app/app.component.ts
View file @
e349c038
...
...
@@ -2,14 +2,8 @@ import { Component } from '@angular/core';
@
Component
({
selector
:
'
app-root
'
,
template
:
`
<!--<h1>-->
<!--Welcome to {{title}}!!-->
<!--</h1>-->
<router-outlet></router-outlet>
`
,
template
:
`<router-outlet></router-outlet>`
,
styles
:
[]
})
export
class
AppComponent
{
title
=
'
app
'
;
}
src/app/auth.guard.ts
View file @
e349c038
...
...
@@ -9,7 +9,6 @@ export class AuthGuard implements CanActivate {
canActivate
(
next
:
ActivatedRouteSnapshot
,
state
:
RouterStateSnapshot
)
{
const
token
=
state
.
root
.
queryParamMap
.
get
(
'
sso
'
)
||
new
URL
(
location
.
href
).
searchParams
.
get
(
'
sso
'
)
||
localStorage
.
getItem
(
'
login
'
);
console
.
log
(
token
)
if
(
!
token
)
{
alert
(
'
login required
'
);
return
false
;
...
...
src/app/lobby/lobby.component.html
View file @
e349c038
...
...
@@ -52,12 +52,12 @@
<md-grid-tile><a
md-raised-button
routerLink=
"/ygopro/watch"
>
<md-icon>
remove_red_eye
</md-icon>
<br>
观战
</a></md-grid-tile>
<
md-grid-tile
>
<
button
md-raised-button
(click)=
"ygopro.watch_replay()"
>
<
md-icon>
history
</md-icon
>
<
br>
观看录像
<
/button
>
<
/md-grid-tile
>
<
!--<md-grid-tile>--
>
<
!--<button md-raised-button (click)="ygopro.watch_replay()">--
>
<
!--<md-icon>history</md-icon>--
>
<
!--<br>观看录像-->
<
!--</button>--
>
<
!--</md-grid-tile>--
>
<md-grid-tile>
<button
md-raised-button
(click)=
"ygopro.edit_deck()"
>
<md-icon>
edit
</md-icon>
...
...
src/app/lobby/lobby.component.ts
View file @
e349c038
...
...
@@ -17,33 +17,20 @@ import { YGOProService } from '../ygopro.service';
})
export
class
LobbyComponent
{
searchCtrl
:
FormControl
;
suggestion
:
any
;
searchCtrl
=
new
FormControl
();
suggestion
=
this
.
searchCtrl
.
valueChanges
.
filter
(
name
=>
name
).
flatMap
(
name
=>
this
.
jsonp
.
get
(
'
http://www.ourocg.cn/Suggest.aspx
'
,
{
params
:
{
callback
:
'
JSONP_CALLBACK
'
,
key
:
name
}
}).
map
(
response
=>
response
.
json
().
result
));
key
:
string
;
arena_url
:
string
;
constructor
(
public
login
:
LoginService
,
public
ygopro
:
YGOProService
,
public
dialog
:
MdDialog
,
private
http
:
Http
,
private
jsonp
:
Jsonp
,
private
route
:
ActivatedRoute
)
{
this
.
searchCtrl
=
new
FormControl
();
this
.
suggestion
=
this
.
searchCtrl
.
valueChanges
.
flatMap
(
name
=>
name
?
this
.
jsonp
.
get
(
'
http://www.ourocg.cn/Suggest.aspx
'
,
{
params
:
{
callback
:
'
JSONP_CALLBACK
'
,
key
:
name
}
}).
map
(
response
=>
response
.
json
().
result
)
:
[]);
// this.jsonp.get('http://www.ourocg.cn/Suggest.aspx', {
// params: {
// callback: 'JSONP_CALLBACK',
// key: 'xy'
// }
// }).map(response => response.json().result).toPromise().then(data => console.log(data));
const
arena_url
=
new
URL
(
'
https://mycard.moe/ygopro/arena
'
);
arena_url
.
searchParams
.
set
(
'
sso
'
,
login
.
token
);
this
.
arena_url
=
arena_url
.
toString
();
}
async
request_match
(
arena
:
string
)
{
this
.
dialog
.
open
(
MatchDialog
,
{
data
:
arena
,
disableClose
:
true
});
}
...
...
@@ -53,4 +40,9 @@ export class LobbyComponent {
open
(
url
.
toString
());
}
async
request_match
(
arena
:
string
)
{
this
.
dialog
.
open
(
MatchDialog
,
{
data
:
arena
,
disableClose
:
true
});
}
}
src/app/login.service.ts
View file @
e349c038
import
{
Injectable
}
from
'
@angular/core
'
;
import
{
fromPairs
}
from
'
lodash
'
;
import
{
User
}
from
'
./ygopro.service
'
;
@
Injectable
()
export
class
LoginService
{
user
:
User
;
token
;
token
:
string
;
sso
(
token
:
string
)
{
this
.
token
=
token
;
let
user
=
<
User
>
{};
for
(
let
[
key
,
value
]
of
new
URLSearchParams
(
Buffer
.
from
(
token
,
'
base64
'
).
toString
()))
{
user
[
key
]
=
value
;
}
this
.
user
=
user
;
this
.
user
=
fromPairs
(
Array
.
from
(
new
URLSearchParams
(
Buffer
.
from
(
token
,
'
base64
'
).
toString
())));
localStorage
.
setItem
(
'
login
'
,
token
);
}
...
...
src/app/match/match.component.html
View file @
e349c038
...
...
@@ -6,7 +6,7 @@
<md-icon
*ngIf=
"arena == 'entertain'"
class=
"fa-spin"
>
toys
</md-icon>
<ul>
<dt>
预计等待时间
</dt>
<dd>
{{expect_wait | date: 'mm:ss'}}
</dd>
<dd>
{{expect_wait |
async |
date: 'mm:ss'}}
</dd>
<dt>
实际等待时间
</dt>
<dd>
{{actual_wait | async | date: 'mm:ss'}}
</dd>
</ul>
...
...
src/app/match/match.component.ts
View file @
e349c038
import
{
Component
,
Inject
}
from
'
@angular/core
'
;
import
{
Http
}
from
'
@angular/http
'
;
import
{
MD_DIALOG_DATA
}
from
'
@angular/material
'
;
import
{
Observable
}
from
'
rxjs/Observable
'
;
...
...
@@ -9,10 +10,10 @@ import { Observable } from 'rxjs/Observable';
})
export
class
MatchDialog
{
expect_wait
=
new
Date
(
1
);
expect_wait
=
this
.
http
.
get
(
'
https://api.mycard.moe/ygopro/match/stats/
'
+
this
.
arena
).
map
(
response
=>
new
Date
(
response
.
json
()
*
1000
)
);
actual_wait
=
Observable
.
timer
(
0
,
1000
).
map
(
timestamp
=>
new
Date
(
timestamp
*
1000
));
constructor
(@
Inject
(
MD_DIALOG_DATA
)
public
arena
:
string
)
{
constructor
(@
Inject
(
MD_DIALOG_DATA
)
public
arena
:
string
,
private
http
:
Http
)
{
}
}
src/app/new-room/new-room.component.ts
View file @
e349c038
import
{
Component
,
ElementRef
,
ViewChild
}
from
'
@angular/core
'
;
import
{
MdSnackBar
}
from
'
@angular/material
'
;
import
{
LoginService
}
from
'
../login.service
'
;
import
{
default_options
,
YGOProService
}
from
'
../ygopro.service
'
;
import
{
YGOProService
}
from
'
../ygopro.service
'
;
@
Component
({
...
...
@@ -19,7 +19,7 @@ export class NewRoomComponent {
room
=
{
title
:
this
.
login
.
user
.
username
+
'
的房间
'
,
'
private
'
:
false
,
options
:
{
...
default_options
}
options
:
{
...
this
.
ygopro
.
default_options
}
};
constructor
(
public
ygopro
:
YGOProService
,
private
login
:
LoginService
,
private
snackBar
:
MdSnackBar
)
{
...
...
src/app/room-list/room-list.component.html
View file @
e349c038
...
...
@@ -33,13 +33,13 @@
<ng-container
cdkColumnDef=
"extra"
>
<md-header-cell
*cdkHeaderCellDef
>
额外选项
</md-header-cell>
<md-cell
*cdkCellDef=
"let room"
>
<span
*ngIf=
"room.options.rule != default_options.rule"
>
{{{'0': 'OCG', '1': 'TCG', '2': 'O/T', '3': '专有卡禁止'}[room.options.rule]}}
</span>
<span
*ngIf=
"room.options.start_lp != default_options.start_lp"
>
{{room.options.start_lp}} LP
</span>
<span
*ngIf=
"room.options.start_hand != default_options.start_hand"
>
{{room.options.start_hand}} 初始
</span>
<span
*ngIf=
"room.options.draw_count != default_options.draw_count"
>
{{room.options.draw_count}} 抽卡
</span>
<span
*ngIf=
"room.options.enable_priority != default_options.enable_priority"
>
旧规则
</span>
<span
*ngIf=
"room.options.no_check_deck != default_options.no_check_deck"
>
不检查
</span>
<span
*ngIf=
"room.options.no_shuffle_deck != default_options.no_shuffle_deck"
>
不洗卡
</span>
<span
*ngIf=
"room.options.rule !=
ygopro.
default_options.rule"
>
{{{'0': 'OCG', '1': 'TCG', '2': 'O/T', '3': '专有卡禁止'}[room.options.rule]}}
</span>
<span
*ngIf=
"room.options.start_lp !=
ygopro.
default_options.start_lp"
>
{{room.options.start_lp}} LP
</span>
<span
*ngIf=
"room.options.start_hand !=
ygopro.
default_options.start_hand"
>
{{room.options.start_hand}} 初始
</span>
<span
*ngIf=
"room.options.draw_count !=
ygopro.
default_options.draw_count"
>
{{room.options.draw_count}} 抽卡
</span>
<span
*ngIf=
"room.options.enable_priority !=
ygopro.
default_options.enable_priority"
>
旧规则
</span>
<span
*ngIf=
"room.options.no_check_deck !=
ygopro.
default_options.no_check_deck"
>
不检查
</span>
<span
*ngIf=
"room.options.no_shuffle_deck !=
ygopro.
default_options.no_shuffle_deck"
>
不洗卡
</span>
</md-cell>
</ng-container>
...
...
src/app/room-list/room-list.component.ts
View file @
e349c038
...
...
@@ -3,7 +3,7 @@ import 'rxjs/add/observable/merge';
import
'
rxjs/add/operator/map
'
;
import
'
rxjs/add/operator/startWith
'
;
import
'
rxjs/Rx
'
;
import
{
default_options
,
RoomListDataSource
,
servers
,
YGOProService
}
from
'
../ygopro.service
'
;
import
{
RoomListDataSource
,
YGOProService
}
from
'
../ygopro.service
'
;
@
Component
({
selector
:
'
app-room-list
'
,
...
...
@@ -12,8 +12,7 @@ import { default_options, RoomListDataSource, servers, YGOProService } from '../
})
export
class
RoomListComponent
{
displayedColumns
=
[
'
title
'
,
'
users
'
,
'
mode
'
,
'
extra
'
];
dataSource
=
new
RoomListDataSource
(
servers
.
filter
(
server
=>
server
.
custom
));
default_options
=
default_options
;
dataSource
=
new
RoomListDataSource
(
this
.
ygopro
.
servers
.
filter
(
server
=>
server
.
custom
));
constructor
(
public
ygopro
:
YGOProService
,
private
changeDetector
:
ChangeDetectorRef
)
{
}
...
...
src/app/toolbar/toolbar.component.html
View file @
e349c038
<md-toolbar
color=
"primary"
>
<button
md-icon-button
(click)=
"back()"
><md-icon>
arrow_back
</md-icon></button>
<button
md-icon-button
(click)=
"
history.
back()"
><md-icon>
arrow_back
</md-icon></button>
<span><ng-content></ng-content></span>
</md-toolbar>
src/app/toolbar/toolbar.component.ts
View file @
e349c038
import
{
Component
,
OnInit
}
from
'
@angular/core
'
;
import
{
Component
}
from
'
@angular/core
'
;
@
Component
({
selector
:
'
app-toolbar
'
,
...
...
@@ -7,9 +7,9 @@ import { Component, OnInit } from '@angular/core';
})
export
class
ToolbarComponent
{
constructor
()
{
}
history
=
history
;
back
()
{
history
.
back
();
constructor
()
{
}
}
src/app/watch/watch.component.html
View file @
e349c038
...
...
@@ -40,13 +40,13 @@
<ng-container
cdkColumnDef=
"extra"
>
<md-header-cell
*cdkHeaderCellDef
>
额外选项
</md-header-cell>
<md-cell
*cdkCellDef=
"let room"
>
<span
*ngIf=
"room.options.rule != default_options.rule"
>
{{{'0': 'OCG', '1': 'TCG', '2': 'O/T', '3': '专有卡禁止'}[room.options.rule]}}
</span>
<span
*ngIf=
"room.options.start_lp != default_options.start_lp"
>
{{room.options.start_lp}} LP
</span>
<span
*ngIf=
"room.options.start_hand != default_options.start_hand"
>
{{room.options.start_hand}} 初始
</span>
<span
*ngIf=
"room.options.draw_count != default_options.draw_count"
>
{{room.options.draw_count}} 抽卡
</span>
<span
*ngIf=
"room.options.enable_priority != default_options.enable_priority"
>
旧规则
</span>
<span
*ngIf=
"room.options.no_check_deck != default_options.no_check_deck"
>
不检查
</span>
<span
*ngIf=
"room.options.no_shuffle_deck != default_options.no_shuffle_deck"
>
不洗卡
</span>
<span
*ngIf=
"room.options.rule !=
ygopro.
default_options.rule"
>
{{{'0': 'OCG', '1': 'TCG', '2': 'O/T', '3': '专有卡禁止'}[room.options.rule]}}
</span>
<span
*ngIf=
"room.options.start_lp !=
ygopro.
default_options.start_lp"
>
{{room.options.start_lp}} LP
</span>
<span
*ngIf=
"room.options.start_hand !=
ygopro.
default_options.start_hand"
>
{{room.options.start_hand}} 初始
</span>
<span
*ngIf=
"room.options.draw_count !=
ygopro.
default_options.draw_count"
>
{{room.options.draw_count}} 抽卡
</span>
<span
*ngIf=
"room.options.enable_priority !=
ygopro.
default_options.enable_priority"
>
旧规则
</span>
<span
*ngIf=
"room.options.no_check_deck !=
ygopro.
default_options.no_check_deck"
>
不检查
</span>
<span
*ngIf=
"room.options.no_shuffle_deck !=
ygopro.
default_options.no_shuffle_deck"
>
不洗卡
</span>
</md-cell>
</ng-container>
...
...
src/app/watch/watch.component.ts
View file @
e349c038
import
{
ChangeDetectorRef
,
Component
,
OnInit
}
from
'
@angular/core
'
;
import
{
default_options
,
RoomListDataSource
,
servers
,
YGOProService
}
from
'
../ygopro.service
'
;
import
{
RoomListDataSource
,
YGOProService
}
from
'
../ygopro.service
'
;
@
Component
({
selector
:
'
app-watch
'
,
...
...
@@ -9,8 +9,7 @@ import { default_options, RoomListDataSource, servers, YGOProService } from '../
export
class
WatchComponent
implements
OnInit
{
displayedColumns
=
[
'
mode
'
,
'
title
'
,
'
users
'
,
'
extra
'
];
dataSource
=
new
RoomListDataSource
(
servers
,
'
started
'
);
default_options
=
default_options
;
dataSource
=
new
RoomListDataSource
(
this
.
ygopro
.
servers
,
'
started
'
);
constructor
(
public
ygopro
:
YGOProService
,
private
changeDetector
:
ChangeDetectorRef
)
{
}
...
...
src/app/windbot/windbot.component.ts
View file @
e349c038
import
{
Component
,
OnInit
}
from
'
@angular/core
'
;
import
{
Component
}
from
'
@angular/core
'
;
import
{
YGOProService
}
from
'
../ygopro.service
'
;
@
Component
({
...
...
src/app/ygopro.service.ts
View file @
e349c038
...
...
@@ -47,34 +47,6 @@ export interface Server {
replay
?:
boolean
;
}
export
const
servers
:
Server
[]
=
[{
id
:
'
tiramisu
'
,
url
:
'
wss://tiramisu.mycard.moe:7923
'
,
address
:
'
112.124.105.11
'
,
port
:
7911
,
custom
:
true
,
replay
:
true
},
{
id
:
'
tiramisu-athletic
'
,
url
:
'
wss://tiramisu.mycard.moe:8923
'
,
address
:
'
112.124.105.11
'
,
port
:
8911
,
custom
:
false
,
replay
:
true
}];
export
const
default_options
:
Options
=
{
mode
:
1
,
rule
:
0
,
start_lp
:
8000
,
start_hand
:
5
,
draw_count
:
1
,
enable_priority
:
false
,
no_check_deck
:
false
,
no_shuffle_deck
:
false
,
lflist
:
0
,
time_limit
:
180
};
class
News
{
title
:
string
;
text
:
string
;
...
...
@@ -100,6 +72,35 @@ export class YGOProService {
news
:
News
[];
windbot
:
string
[];
readonly
default_options
:
Options
=
{
mode
:
1
,
rule
:
0
,
start_lp
:
8000
,
start_hand
:
5
,
draw_count
:
1
,
enable_priority
:
false
,
no_check_deck
:
false
,
no_shuffle_deck
:
false
,
lflist
:
0
,
time_limit
:
180
};
readonly
servers
:
Server
[]
=
[{
id
:
'
tiramisu
'
,
url
:
'
wss://tiramisu.mycard.moe:7923
'
,
address
:
'
112.124.105.11
'
,
port
:
7911
,
custom
:
true
,
replay
:
true
},
{
id
:
'
tiramisu-athletic
'
,
url
:
'
wss://tiramisu.mycard.moe:8923
'
,
address
:
'
112.124.105.11
'
,
port
:
8911
,
custom
:
false
,
replay
:
true
}];
constructor
(
private
login
:
LoginService
,
private
http
:
Http
)
{
this
.
load
().
catch
(
alert
);
}
...
...
@@ -145,7 +146,7 @@ export class YGOProService {
// body: `房间密码是 ${this.host_password}, 您的对手可在自定义游戏界面输入密码与您对战。`
// });
// }
this
.
join
(
password
,
servers
[
0
]);
this
.
join
(
password
,
this
.
servers
[
0
]);
}
join_room
(
room
:
Room
)
{
...
...
@@ -183,14 +184,14 @@ export class YGOProService {
let
name
=
options_buffer
.
toString
(
'
base64
'
)
+
password
.
replace
(
/
\s
/
,
String
.
fromCharCode
(
0xFEFF
));
this
.
join
(
name
,
servers
[
0
]);
this
.
join
(
name
,
this
.
servers
[
0
]);
}
join_windbot
(
name
?:
string
)
{
if
(
!
name
)
{
name
=
this
.
windbot
[
Math
.
floor
(
Math
.
random
()
*
this
.
windbot
.
length
)];
}
return
this
.
join
(
'
AI#
'
+
name
,
servers
[
0
]);
return
this
.
join
(
'
AI#
'
+
name
,
this
.
servers
[
0
]);
}
join
(
password
,
server
)
{
...
...
@@ -250,15 +251,13 @@ export class RoomListDataSource extends DataSource<any> {
/** Connect function called by the table to retrieve one stream containing the data to render. */
connect
():
Observable
<
Room
[]
>
{
return
Observable
.
combineLatest
(
servers
.
map
(
server
=>
{
return
Observable
.
combineLatest
(
this
.
servers
.
map
(
server
=>
{
const
url
=
new
URL
(
server
.
url
);
url
.
searchParams
.
set
(
'
filter
'
,
this
.
filter
);
return
Observable
.
webSocket
({
url
:
url
.
toString
()
})
.
scan
((
rooms
:
Room
[],
message
:
Message
)
=>
{
console
.
log
(
message
);
switch
(
message
.
event
)
{
case
'
init
'
:
console
.
log
(
message
.
data
.
map
(
room
=>
({
server
:
server
,
...
room
})));
return
message
.
data
.
map
(
room
=>
({
server
:
server
,
...
room
}));
case
'
create
'
:
return
rooms
.
concat
({
server
:
server
,
...
message
.
data
});
...
...
src/index.html
View file @
e349c038
...
...
@@ -4,7 +4,7 @@
<meta
charset=
"utf-8"
>
<title>
MyCard Mobile
</title>
<base
href=
"/mobile/index.html"
>
<meta
name=
"theme-color"
content=
"#4285f4"
>
<meta
name=
"viewport"
content=
"width=device-width, initial-scale=1"
>
<style>
...
...
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