Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
A
adc2019-system
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Commits
Issue Boards
Open sidebar
adc2019
adc2019-system
Commits
a1c46b41
Commit
a1c46b41
authored
Jul 12, 2019
by
Kento HASEGAWA
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Implement host and solver function/GUIs
parent
839d7369
Changes
12
Hide whitespace changes
Inline
Side-by-side
Showing
12 changed files
with
516 additions
and
345 deletions
+516
-345
adc2019system.py
adc2019system.py
+1
-0
main.py
main.py
+13
-2
host.py
roles/host.py
+178
-13
solver.py
roles/solver.py
+84
-0
main.py
solvers/SampleSolver/main.py
+6
-0
adc2019.css
static/css/adc2019.css
+20
-13
adc2019.js
static/js/adc2019.js
+78
-261
index.html
templates/index.html
+2
-26
part_question_status.html
templates/part_question_status.html
+43
-27
part_questions.html
templates/part_questions.html
+3
-3
part_system_summary.html
templates/part_system_summary.html
+43
-0
data.py
utils/data.py
+45
-0
No files found.
adc2019system.py
View file @
a1c46b41
...
...
@@ -33,6 +33,7 @@ def set_role(role_name, config_data):
def
call_api
(
method
,
cmd
,
params
):
print
(
f
'I: API Received: {cmd}'
)
if
role
is
not
None
:
return
role
.
call_api
(
method
,
cmd
,
params
)
else
:
...
...
main.py
View file @
a1c46b41
...
...
@@ -24,6 +24,14 @@ def webui_template_questions():
else
:
return
abort
(
404
)
@
webui
.
route
(
'/template/system-summary'
)
def
webui_template_workers
():
if
(
adc2019system
.
role
is
not
None
)
and
(
adc2019system
.
role
.
type
==
'host'
):
workers
=
adc2019system
.
role
.
get_workers
()
return
render_template
(
'part_system_summary.html'
,
workers
=
workers
)
else
:
return
abort
(
404
)
@
webui
.
route
(
'/template/question/<name>'
)
def
webui_template_question_status
(
name
=
None
):
...
...
@@ -31,8 +39,11 @@ def webui_template_question_status(name=None):
return
abort
(
404
)
if
(
adc2019system
.
role
is
not
None
)
and
(
adc2019system
.
role
.
type
==
'host'
):
questions
=
adc2019system
.
role
.
get_questions
()
return
render_template
(
'part_question_status.html'
,
questions
=
questions
)
question
=
adc2019system
.
role
.
get_question
(
name
)
if
question
is
None
:
return
abort
(
404
)
else
:
return
render_template
(
'part_question_status.html'
,
question
=
question
)
else
:
return
abort
(
404
)
...
...
roles/host.py
View file @
a1c46b41
import
glob
import
json
import
sys
import
threading
import
time
import
requests
from
utils
import
Question
...
...
@@ -10,11 +13,13 @@ class Host(object):
self
.
type
=
'host'
self
.
config
=
config
self
.
questions
=
[]
self
.
_load_questions
(
config
[
'question_path'
])
self
.
questions
=
dict
()
self
.
worker_manager
=
None
self
.
request
=
dict
()
self
.
processing_request
=
None
self
.
worker
=
dict
(
)
self
.
setup_workers
()
self
.
_load_questions
(
config
[
'question_path'
]
)
self
.
_
setup_workers
()
def
__repr__
(
self
):
return
"Host"
...
...
@@ -28,39 +33,199 @@ class Host(object):
for
v
in
questions_path
:
question
=
Question
(
v
)
_key
=
question
.
name
self
.
questions
.
append
(
question
)
self
.
questions
[
_key
]
=
question
def
setup_workers
(
self
):
def
_
setup_workers
(
self
):
self
.
worker_manager
=
WorkerManager
(
self
.
config
[
'address'
])
for
v
in
self
.
config
[
'worker'
]:
worker_name
=
v
[
'name'
]
self
.
worker
[
worker_name
]
=
Worker
(
v
)
self
.
worker_manager
.
add_worker
(
v
)
def
get_workers
(
self
):
return
self
.
worker_manager
.
get_workers
()
def
distribute_question
(
self
,
question_key
):
question
=
self
.
get_question
(
question_key
)
if
question
is
None
:
return
{
'status'
:
'key error'
}
else
:
request
=
Request
(
self
.
worker_manager
,
question
.
get_dict
())
request_id
=
request
.
get_id
()
self
.
request
[
request_id
]
=
request
request
.
broadcast
()
return
{
'status'
:
'processed'
,
'request_id'
:
request_id
,
'timeout'
:
request
.
timeout
}
def
get_questions
(
self
):
return
self
.
questions
def
get_question
(
self
,
_key
):
if
_key
in
self
.
questions
:
return
self
.
questions
[
_key
]
else
:
return
None
def
store_solution
(
self
,
solution
):
# request_idをチェックする機能もつくておく
request_id
=
solution
[
'request_id'
]
if
request_id
in
self
.
request
:
self
.
request
[
request_id
]
.
store_response
(
solution
)
else
:
print
(
f
'W: Unknown request_id: {request_id}'
)
question_key
=
solution
[
'question'
]
if
question_key
in
self
.
questions
:
self
.
questions
[
question_key
]
.
put_solution
(
solution
)
return
{
'status'
:
'registered'
}
else
:
return
{
'status'
:
'error'
}
def
get_request_status
(
self
,
request_id
):
if
request_id
in
self
.
request
:
return
self
.
request
[
request_id
]
.
get_status
()
else
:
return
{
'status'
:
'unknown request'
}
def
call_api
(
self
,
method
,
cmd
,
params
):
if
cmd
==
'role'
:
# サーバの役割確認
return
{
'role'
:
self
.
type
}
elif
cmd
==
'question/solve'
:
# params['question']に指定された問題をworkerに配信
question_key
=
params
[
'question'
]
return
self
.
distribute_question
(
question_key
)
elif
cmd
==
'question/solution'
:
self
.
store_solution
(
params
)
return
{
'status'
:
'received'
}
elif
cmd
==
'request/status'
:
request_id
=
float
(
params
[
'request_id'
])
return
self
.
get_request_status
(
request_id
)
else
:
return
None
class
WorkerManager
(
object
):
def
__init__
(
self
,
host_address
):
self
.
workers
=
dict
()
self
.
host
=
host_address
def
add_worker
(
self
,
conf
):
worker_conf
=
dict
()
worker_conf
.
update
(
conf
)
worker_conf
[
'host'
]
=
self
.
host
worker_address
=
worker_conf
[
'address'
]
self
.
workers
[
worker_address
]
=
Worker
(
worker_conf
)
def
get_workers
(
self
):
return
self
.
workers
def
broadcast
(
self
,
cmd
,
params
):
threads
=
[]
def
_sender
(
_worker
,
_cmd
,
_params
):
_worker
.
post
(
_cmd
,
_params
)
for
k
,
v
in
self
.
workers
.
items
():
_th
=
threading
.
Thread
(
name
=
v
.
address
,
target
=
_sender
,
args
=
(
v
,
cmd
,
params
),
daemon
=
True
)
_th
.
start
()
threads
.
append
(
_th
)
class
Worker
(
object
):
def
__init__
(
self
,
params
):
self
.
address
=
params
[
'address'
]
self
.
name
=
params
[
'name'
]
self
.
host
=
params
[
'host'
]
self
.
role
=
None
self
.
params
=
params
self
.
status
=
'Setting up'
self
.
set_role
(
params
[
'role'
])
def
post
(
self
,
path
,
data
):
response
=
requests
.
post
(
f
'http://{self.address}/api/{path}'
,
json
.
dumps
(
data
),
headers
=
{
'Content-Type'
:
'application/json'
})
try
:
response
=
requests
.
post
(
f
'http://{self.address}/api/{path}'
,
json
.
dumps
(
data
),
headers
=
{
'Content-Type'
:
'application/json'
},
timeout
=
2
)
print
(
f
"I: Post to {self.address}, API Cmd: {path}"
)
except
Exception
as
e
:
# sys.stderr.write(str(e) + "\n")
print
(
f
"W: Failed to connect {self.address}"
)
self
.
status
=
'Not connected'
response
=
None
return
response
def
set_role
(
self
,
role
):
r
=
self
.
post
(
'role'
,
{
'role'
:
role
})
r
=
self
.
post
(
'role'
,
self
.
params
)
class
Request
(
object
):
def
__init__
(
self
,
worker_manager
,
data
,
timeout
=
10
):
self
.
worker_manager
=
worker_manager
self
.
data
=
data
self
.
timeout
=
timeout
self
.
request_id
=
time
.
time
()
self
.
broadcast_time
=
None
self
.
response
=
dict
()
@
property
def
request_data
(
self
):
data
=
self
.
data
data
[
'request_id'
]
=
self
.
request_id
data
[
'timeout'
]
=
self
.
timeout
return
data
def
get_id
(
self
):
return
self
.
request_id
def
get_dict
(
self
):
return
self
.
request_data
def
store_response
(
self
,
data
):
# TODO: 1つのrequest_idに対し同一のworkerから2つ以上答えが返ってきた場合の例外処理
worker
=
data
[
'worker'
]
self
.
response
[
worker
]
=
data
def
get_status
(
self
):
all_workers
=
self
.
worker_manager
.
get_workers
()
.
keys
()
worker_count
=
0
response_count
=
0
for
v
in
all_workers
:
worker_count
+=
1
if
v
in
self
.
response
:
response_count
+=
1
status
=
''
if
worker_count
==
response_count
:
status
=
'done'
elif
time
.
time
()
-
self
.
broadcast_time
>
self
.
timeout
:
status
=
'timeout'
else
:
status
=
'processing'
return
{
'status'
:
status
,
'workers'
:
worker_count
,
'solutions'
:
response_count
}
def
broadcast
(
self
):
self
.
worker_manager
.
broadcast
(
'solve'
,
self
.
request_data
)
self
.
broadcast_time
=
time
.
time
()
roles/solver.py
View file @
a1c46b41
import
importlib
import
json
import
os
import
requests
import
sys
import
time
import
threading
class
StoppableThread
(
threading
.
Thread
):
def
__init__
(
self
,
target
,
args
=
()):
super
(
StoppableThread
,
self
)
.
__init__
(
target
=
target
,
args
=
args
)
self
.
_status
=
'running'
def
stop
(
self
):
if
self
.
_status
==
'running'
:
self
.
_status
=
'stopping'
def
stopped
(
self
):
self
.
_status
=
'stopped'
def
is_running
(
self
):
return
(
self
.
_status
==
'running'
)
def
is_stopping
(
self
):
return
(
self
.
_status
==
'stopping'
)
def
is_stopped
(
self
):
return
(
self
.
_status
==
'stopped'
)
class
Solver
(
object
):
def
__init__
(
self
,
config
):
self
.
type
=
'solver'
self
.
host
=
config
[
'host'
]
self
.
address
=
config
[
'address'
]
self
.
name
=
config
[
'name'
]
self
.
solver
=
importlib
.
import_module
(
f
"solvers.{config['solver']}"
)
self
.
thread
=
None
def
__repr__
(
self
):
return
"Solver"
def
solve
(
self
,
params
):
start_time
=
time
.
time
()
solution
=
self
.
solver
.
solve
(
params
)
end_time
=
time
.
time
()
self
.
thread
.
stopped
()
elapsed_time
=
end_time
-
start_time
if
not
'elapsed_time'
in
solution
:
solution
[
'elapsed_time'
]
=
elapsed_time
self
.
submit_solution
(
params
,
solution
)
self
.
thread
=
None
return
True
def
post
(
self
,
path
,
data
):
response
=
requests
.
post
(
f
'http://{self.host}/api/{path}'
,
json
.
dumps
(
data
),
headers
=
{
'Content-Type'
:
'application/json'
})
print
(
f
"I: Post to {self.host}, API Cmd: {path}"
)
return
response
def
submit_solution
(
self
,
params
,
solution
):
data
=
{
'request_id'
:
params
[
'request_id'
],
'question'
:
params
[
'name'
],
'worker'
:
self
.
address
}
data
.
update
(
solution
)
self
.
post
(
'question/solution'
,
data
)
def
start_solver
(
self
,
params
):
if
self
.
thread
is
None
:
print
(
"I: Solver started"
)
self
.
thread
=
StoppableThread
(
target
=
self
.
solve
,
args
=
(
params
,
))
self
.
thread
.
start
()
return
{
'status'
:
'started'
}
else
:
return
{
'status'
:
'busy'
}
def
stop_solver
():
if
self
.
thread
is
not
None
:
if
self
.
thread
.
is_running
():
self
.
thread
.
stop
()
self
.
thread
.
join
()
self
.
thread
=
None
def
call_api
(
self
,
method
,
cmd
,
params
):
if
cmd
==
'role'
:
return
{
'role'
:
self
.
type
}
elif
cmd
==
'solve'
:
return
self
.
start_solver
(
params
)
else
:
return
None
solvers/SampleSolver/main.py
0 → 100644
View file @
a1c46b41
def
solve
(
params
):
print
(
"This is a sample solver."
)
return
{
'solution'
:
'aaa!'
}
def
main
(
params
):
solve
(
a
)
static/css/adc2019.css
View file @
a1c46b41
...
...
@@ -15,30 +15,30 @@ body{
background-color
:
rgba
(
0
,
0
,
50
,
.5
);
}
#question-
table-wrapp
er
{
#question-
list-contain
er
{
height
:
calc
(
100vh
-
50px
);
overflow-y
:
scroll
;
overflow-x
:
hidden
;
}
#question-
table-wrapp
er
th
.large-cell
,
#question-
table-wrapp
er
td
.large-cell
{
#question-
list-contain
er
th
.large-cell
,
#question-
list-contain
er
td
.large-cell
{
width
:
24%
;
}
#question-
table-wrapp
er
th
.small-cell
,
#question-
table-wrapp
er
td
.small-cell
{
#question-
list-contain
er
th
.small-cell
,
#question-
list-contain
er
td
.small-cell
{
width
:
14%
;
}
#question-
table-wrapp
er
tr
.question-row
,
#question-
table-wrapp
er
tr
.question-row
td
{
#question-
list-contain
er
tr
.question-row
,
#question-
list-contain
er
tr
.question-row
td
{
cursor
:
pointer
;
}
#question-
table-wrapp
er
tr
.question-row.q-selected
{
#question-
list-contain
er
tr
.question-row.q-selected
{
background-color
:
rgba
(
200
,
100
,
100
,
.3
);
}
#question-
table-wrapp
er
tr
.question-row
:hover
{
#question-
list-contain
er
tr
.question-row
:hover
{
background-color
:
rgba
(
200
,
100
,
100
,
.15
);
}
...
...
@@ -60,16 +60,23 @@ body{
display
:
inline-block
;
}
#client-control-pane
tr
.
answer
-detail-row
,
#client-control-pane
tr
.
answer
-detail-row
td
{
#client-control-pane
tr
.
solution
-detail-row
,
#client-control-pane
tr
.
solution
-detail-row
td
{
cursor
:
pointer
;
}
#client-control-pane
tr
.
answer
-detail-row
:hover
{
#client-control-pane
tr
.
solution
-detail-row
:hover
{
background-color
:
rgba
(
200
,
100
,
100
,
.15
);
}
#client-control-pane
tr
.
answer
-detail-row.submit-answer
{
#client-control-pane
tr
.
solution
-detail-row.submit-answer
{
background-color
:
rgba
(
100
,
200
,
100
,
.3
);
}
#content-left
h3
{
display
:
inline-block
;
}
#content-right
h4
.inline-heading
{
display
:
inline-block
;
}
static/js/adc2019.js
View file @
a1c46b41
class
ADC2019Board
{
// 詳細表示画面
class
StatusView
{
constructor
(
selector
)
{
this
.
container
=
$
(
selector
);
this
.
width
=
this
.
container
.
width
();
this
.
height
=
$
(
window
).
height
();
this
.
svg
=
d3
.
select
(
selector
).
append
(
'svg'
);
this
.
view
=
this
.
svg
.
append
(
'g'
).
attr
(
'class'
,
'view'
);
this
.
currentTransform
=
null
;
this
.
cubeResolution
=
50
;
this
.
_init
();
this
.
_draw_slider
();
this
.
question_key
=
null
;
}
get_board_list
(
selector
){
var
_self
=
this
;
var
container
=
$
(
selector
);
container
.
html
(
""
);
// 問題詳細画面を表示
show_question
(
question_key
=
null
){
var
_this
=
this
;
if
(
question_key
!=
null
){
this
.
question_key
=
question_key
;
}
$
.
ajax
({
url
:
'/api/boards'
,
type
:
'GET'
,
}).
done
((
data
)
=>
{
var
$board_list
=
container
.
append
(
"<div class='list-group'></ul>"
);
for
(
var
i
=
0
;
i
<
data
.
length
;
i
++
){
$board_list
.
append
(
"<a href='#"
+
data
[
i
]
+
"' class='list-group-item list-group-item-action'>"
+
data
[
i
]
+
"</a>"
);
}
if
(
data
.
indexOf
(
_self
.
_get_hash
())
>=
0
){
_self
.
draw
(
_self
.
_get_hash
());
}
}).
fail
((
data
)
=>
{
console
.
log
(
"Error"
);
});
}
draw
(
name
){
this
.
_draw_init
();
this
.
_get_board
(
name
);
}
_get_hash
(){
return
location
.
hash
.
replace
(
"#"
,
""
);
}
_init
(){
var
_self
=
this
;
if
(
this
.
currentTransform
){
this
.
view
.
attr
(
'transform'
,
this
.
currentTransform
);
}
dataType
:
'html'
,
url
:
'/template/question/'
+
_this
.
question_key
}).
done
((
d
)
=>
{
_this
.
container
.
empty
();
_this
.
container
.
html
(
d
);
$
(
window
).
on
(
'hashchange'
,
()
=>
{
_self
.
draw
(
_self
.
_get_hash
());
_this
.
container
.
find
(
'.start-button'
).
click
(()
=>
{
_this
.
start_solver
();
});
});
}
_get_board
(
name
){
// 問題を解くのをスタート
start_solver
(){
var
_this
=
this
;
$
.
ajax
({
url
:
'/api/board/'
+
name
,
type
:
'GET'
,
}).
done
((
data
)
=>
{
this
.
_draw_grid
(
data
.
size
[
0
],
data
.
size
[
1
]);
this
.
_draw_blocks
(
data
.
blocks
);
}).
fail
((
data
)
=>
{
console
.
log
(
"Error"
);
type
:
"POST"
,
dataType
:
"json"
,
url
:
"/api/question/solve"
,
data
:
JSON
.
stringify
({
"question"
:
_this
.
question_key
}),
contentType
:
'application/json'
}).
done
((
d
)
=>
{
// TODO: タイムアウトになる時間まで,モーダル表示させる
console
.
log
(
d
);
_this
.
container
.
find
(
'#solver-processing-modal'
).
modal
(
'show'
);
});
}
_draw_init
(){
this
.
view
.
selectAll
(
"g"
).
remove
();
}
_draw_grid
(
x_cnt
,
y_cnt
){
let
_width
=
x_cnt
*
this
.
cubeResolution
;
let
_height
=
y_cnt
*
this
.
cubeResolution
;
this
.
view
.
append
(
"g"
)
.
attr
(
"class"
,
"x axis"
)
.
selectAll
(
"line"
)
.
data
(
d3
.
range
(
0
,
_width
+
1
,
this
.
cubeResolution
))
.
enter
().
append
(
"line"
)
.
attr
(
"x1"
,
function
(
d
)
{
return
d
;
})
.
attr
(
"y1"
,
0
)
.
attr
(
"x2"
,
function
(
d
)
{
return
d
;
})
.
attr
(
"y2"
,
_height
)
.
attr
(
"stroke"
,
"#888"
);
this
.
view
.
append
(
"g"
)
.
attr
(
"class"
,
"y axis"
)
.
selectAll
(
"line"
)
.
data
(
d3
.
range
(
0
,
_height
+
1
,
this
.
cubeResolution
))
.
enter
().
append
(
"line"
)
.
attr
(
"x1"
,
0
)
.
attr
(
"y1"
,
function
(
d
)
{
return
d
;
})
.
attr
(
"x2"
,
_width
)
.
attr
(
"y2"
,
function
(
d
)
{
return
d
;
})
.
attr
(
"stroke"
,
"#888"
);
}
_draw_slider
(){
let
_self
=
this
;
var
zoom
=
d3
.
zoom
()
.
scaleExtent
([
0.5
,
5
])
.
translateExtent
([
[
-
this
.
width
*
2
,
-
this
.
height
*
2
],
[
this
.
width
*
2
,
this
.
height
*
2
]
])
.
on
(
"zoom"
,
zoomed
);
function
zoomed
()
{
this
.
currentTransform
=
d3
.
event
.
transform
;
_self
.
view
.
attr
(
"transform"
,
this
.
currentTransform
);
// this.slider.property("value", d3.event.scale);
}
function
slided
(
d
)
{
zoom
.
scaleTo
(
this
.
svg
,
d3
.
select
(
this
).
property
(
"value"
));
}
// var slider = d3.select("body").append("input")
// .datum({})
// .attr("type", "range")
// .attr("value", 1)
// .attr("min", zoom.scaleExtent()[0])
// .attr("max", zoom.scaleExtent()[1])
// .attr("step", (zoom.scaleExtent()[1] - zoom.scaleExtent()[0]) / 100)
// .on("input", slided);
this
.
svg
.
call
(
zoom
).
on
(
'dblclick.zoom'
,
null
);
}
_draw_blocks
(
blocks
){
let
cubeResolution
=
this
.
cubeResolution
;
function
snapToGrid
(
p
,
r
)
{
return
Math
.
round
(
p
/
r
)
*
r
;
}
function
dragged
(
d
)
{
var
el
=
d3
.
select
(
this
);
var
_x
=
parseInt
(
el
.
attr
(
'data-x'
),
10
)
+
d3
.
event
.
x
;
var
_y
=
parseInt
(
el
.
attr
(
'data-y'
),
10
)
+
d3
.
event
.
y
;
el
.
attr
(
"transform"
,
(
d
)
=>
{
return
'translate('
+
snapToGrid
(
_x
,
cubeResolution
)
+
','
+
snapToGrid
(
_y
,
cubeResolution
)
+
')'
})
}
function
dragended
(
d
)
{
var
el
=
d3
.
select
(
this
).
classed
(
"dragging"
,
false
);
var
_x
=
parseInt
(
el
.
attr
(
'data-x'
),
10
)
+
d3
.
event
.
x
;
var
_y
=
parseInt
(
el
.
attr
(
'data-y'
),
10
)
+
d3
.
event
.
y
;
d3
.
select
(
this
)
.
attr
(
'data-x'
,
snapToGrid
(
_x
,
cubeResolution
))
.
attr
(
'data-y'
,
snapToGrid
(
_y
,
cubeResolution
));
}
function
dragstarted
(
d
)
{
var
el
=
d3
.
select
(
this
);
el
.
raise
().
classed
(
"dragging"
,
true
);
}
let
colors
=
d3
.
schemeCategory10
// Reference
// Grid: https://bl.ocks.org/ngminhtrung/7c5721a1504f3e29a36da9ddd9e5039b
// Snap: https://bl.ocks.org/evanjmg/ea3e59e67b4256c8831d3fc80f71294b
// Nested data structure: https://codeday.me/jp/qa/20190428/720184.html
var
itemContainer
=
this
.
view
.
selectAll
(
"g.itemContainer"
)
.
data
(
blocks
)
.
enter
()
.
append
(
'g'
)
.
attr
(
'class'
,
'itemContainer'
)
.
attr
(
"transform"
,
(
d
)
=>
'translate('
+
d
.
x
+
','
+
d
.
y
+
')'
)
.
attr
(
'data-x'
,
(
d
)
=>
d
.
x
)
.
attr
(
'data-y'
,
(
d
)
=>
d
.
y
)
.
call
(
d3
.
drag
()
.
on
(
"start"
,
dragstarted
)
.
on
(
"drag"
,
dragged
)
.
on
(
"end"
,
dragended
));
var
cellContainer
=
itemContainer
.
append
(
'g'
)
.
attr
(
'class'
,
'cellContainer'
)
.
attr
(
'data-color'
,
(
d
,
i
)
=>
colors
[
i
])
.
attr
(
'x'
,
0
)
.
attr
(
'y'
,
0
)
cellContainer
.
selectAll
(
'g'
)
.
data
((
d
)
=>
d
.
cells
)
.
enter
()
.
append
(
'rect'
)
.
attr
(
'x'
,
(
d
)
=>
d
[
0
]
*
this
.
cubeResolution
)
.
attr
(
'y'
,
(
d
)
=>
d
[
1
]
*
this
.
cubeResolution
)
.
attr
(
'width'
,
this
.
cubeResolution
)
.
attr
(
'height'
,
this
.
cubeResolution
)
.
attr
(
'cursor'
,
'move'
)
.
attr
(
'fill'
,
(
d
,
i
,
nodes
)
=>
{
return
d3
.
select
(
nodes
[
i
].
parentNode
).
attr
(
'data-color'
);
});
cellContainer
.
selectAll
(
'g'
)
.
data
((
d
)
=>
d
.
cells
)
.
enter
()
.
append
(
'text'
)
.
attr
(
'x'
,
(
d
)
=>
d
[
0
]
*
this
.
cubeResolution
+
0.5
*
this
.
cubeResolution
)
.
attr
(
'y'
,
(
d
)
=>
d
[
1
]
*
this
.
cubeResolution
+
0.5
*
this
.
cubeResolution
)
.
attr
(
'width'
,
this
.
cubeResolution
)
.
attr
(
'height'
,
this
.
cubeResolution
)
.
attr
(
'text-anchor'
,
'middle'
)
.
attr
(
'fill'
,
'white'
)
.
attr
(
'font-size'
,
'20px'
)
.
attr
(
'cursor'
,
'move'
)
.
text
((
d
)
=>
d
[
2
]);
}
}
$
(
function
(){
// const board = new ADC2019Board("#board-container");
// board.get_board_list("#board-list-container");
// // board.draw("Q001_10X10_b8_n11.txt");
var
show_question_status
=
function
(
qname
){
// システム詳細画面を表示
show_system
(){
var
_this
=
this
;
$
.
ajax
({
type
:
"GET"
,
dataType
:
"html"
,
url
:
"/template/
question/"
+
qname
,
url
:
"/template/
system-summary"
}).
done
((
d
)
=>
{
$
(
"#status-container"
).
empty
();
$
(
"#status-container"
).
html
(
d
);
_this
.
container
.
empty
();
_this
.
container
.
html
(
d
);
var
button_action_with_ajax
=
function
(
$obj
,
url
){
$obj
.
prop
(
"disabled"
,
"disabled"
);
$
.
ajax
({
type
:
"GET"
,
url
:
url
,
dataType
:
"json"
,
}).
done
((
data
)
=>
{
$obj
.
prop
(
"disabled"
,
false
);
alert
(
data
[
'message'
]);
});
};
$
(
"#adccli-login-button"
).
click
(
function
(){
button_action_with_ajax
(
$
(
this
),
"/adccli-login"
);
});
$
(
"#adccli-logout-button"
).
click
(
function
(){
button_action_with_ajax
(
$
(
this
),
"/adccli-logout"
);
});
$
(
"#adccli-get-all-q"
).
click
(
function
(){
button_action_with_ajax
(
$
(
this
),
"/adccli-get-all-q"
);
});
// $("#status-container").find(".start-button").eq(0).click(function(){
// var qname = $(this).data("qname");
// pm.sendQuestion(qname);
// });
// $("#status-container").find(".stop-button").eq(0).click(function(){
// pm.sendStop();
// });
// $("#status-container").find(".save-button").eq(0).click(function(){
// var qname = $(this).data("qname");
// $.ajax({
// type: "POST",
// dataType: "json",
// url: "/save",
// data: {qname: qname}
// }).done((data) => {
// alert(data['status']);
// });
// });
// $("#status-container").find(".submit-button").eq(0).click(function(){
// var qname = $(this).data("qname");
// $.ajax({
// type: "POST",
// dataType: "json",
// url: "/adccli-put-a",
// data: {qname: qname}
// }).done((data) => {
// alert(data['message']);
// });
// });
$
.
ajax
({
type
:
"GET"
,
url
:
"/adccli-whoami"
,
dataType
:
"json"
,
}).
done
((
data
)
=>
{
if
(
data
[
'status'
])
$
(
"#adccli-status"
).
text
(
"ログイン中"
);
else
$
(
"#adccli-status"
).
text
(
"ログアウト"
);
});
// $(".answer-detail-row td").click(function(){
// var json_name = $(this).parent("tr").data("json");
// var qname = $(this).parent("tr").data("qname");
// var viewer_url = "/board-viewer#" + qname + "," + json_name
// window.open(viewer_url, "_blank");
// })
});
}
}
$
(
function
(){
const
status_view
=
new
StatusView
(
'#status-container'
);
var
refresh_questions
=
function
(){
$
.
ajax
({
...
...
@@ -308,13 +126,12 @@ $(function(){
});
}
$
(
window
).
on
(
'hashchange'
,
function
(){
var
hash
=
location
.
hash
.
replace
(
"#"
,
""
);
if
(
hash
==
""
){
// show_client_table
();
status_view
.
show_system
();
}
else
{
s
how_question_status
(
hash
);
s
tatus_view
.
show_question
(
hash
);
}
}).
trigger
(
'hashchange'
);
...
...
templates/index.html
View file @
a1c46b41
...
...
@@ -12,30 +12,6 @@
<script
src=
"/static/js/bootstrap.bundle.min.js"
></script>
<script
src=
"/static/js/d3.min.js"
></script>
<script
src=
"/static/js/adc2019.js"
></script>
<style>
.axis
path
{
display
:
none
;
}
.axis
line
{
stroke-opacity
:
0.3
;
shape-rendering
:
crispEdges
;
}
input
[
type
=
"range"
]
{
right
:
0
;
top
:
0
;
position
:
absolute
;
}
svg
,
#chart-container
{
width
:
100%
;
height
:
100vh
;
display
:
block
;
}
#content-left
h3
{
display
:
inline-block
;
}
</style>
</head>
<body>
...
...
@@ -44,7 +20,7 @@ svg,
<div
id=
"content-wrapper"
class=
"container-fluid"
>
<div
id=
"content-row"
class=
"row"
>
<div
class=
"col-
4
"
id=
"content-left"
>
<div
class=
"col-
5
"
id=
"content-left"
>
<h3>
問題一覧
</h3>
<span><a
href=
"/#"
id=
"view-server-status-button"
>
システム状況
</a></span>
<div
id=
"question-list-container"
>
...
...
@@ -52,7 +28,7 @@ svg,
</div>
</div>
<div
class=
"col-
8
"
id=
"content-right"
>
<div
class=
"col-
7
"
id=
"content-right"
>
<div
id=
"status-container"
>
</div>
...
...
templates/part_question_status.html
View file @
a1c46b41
<div
class=
"row"
>
<div
class=
"col-4"
>
<h3>
【{{qname}}】
</h3>
{#% # if localmode %#}
<p>
<button
class=
"btn btn-primary btn-lg start-button"
type=
"button"
data-qname=
"{{qname}}"
>
Start
</button>
<button
class=
"btn btn-danger btn-lg stop-button"
type=
"button"
data-qname=
"all"
>
Stop
</button>
</p>
<p>
<button
class=
"btn btn-info btn-lg save-button"
type=
"button"
data-qname=
"{{qname}}"
>
Save
</button>
<button
class=
"btn btn-success btn-lg submit-button"
type=
"button"
data-qname=
"{{qname}}"
>
Up
</button>
</p>
{#% else %#}
<!-- [View Only] -->
{#% endif %#}
</div>
<div
class=
"col-8"
>
<div>
<!-- <div class="col-4"> -->
<h3>
【{{question.name}}】
</h3>
{#% # if localmode %#}
<p>
<button
class=
"btn btn-primary btn-lg start-button"
type=
"button"
data-qname=
"{{question.name}}"
>
Start
</button>
<button
class=
"btn btn-danger btn-lg stop-button"
type=
"button"
data-qname=
"all"
>
Stop
</button>
<button
class=
"btn btn-info btn-lg save-button"
type=
"button"
data-qname=
"{{question.name}}"
>
Save
</button>
<button
class=
"btn btn-success btn-lg submit-button"
type=
"button"
data-qname=
"{{question.name}}"
>
Up
</button>
</p>
{#% else %#}
<!-- [View Only] -->
{#% endif %#}
<!-- <div class="col-8">
<p>処理結果</p>
<table class="table table-bordered">
<tr>
<th>Client (Solver)</th>
<th>Status</th>
</tr>
<!--
{% for c in solvers %}
{% for c in solvers %}
<tr>
<td>
{% if c|length > 3 %}
...
...
@@ -34,9 +31,9 @@
</td>
<td>{{qdata.solver[c[0]]}}</td>
</tr>
{% endfor %}
-->
{% endfor %}
</table>
</div>
</div>
-->
</div>
<div>
...
...
@@ -47,23 +44,42 @@
<th>
Client
</th>
<th>
Score
</th>
</tr>
<!-- {#% for k, v in qdata.answers.items() %#
}
{% for k, v in question.get_solutions().items() %
}
{#% if (qdata.best_json == k) and (v.answer != "") %#}
<
tr class="answer-detail-row submit-answer" data-json="{#{k}#}" data-qname="{#{qname}#}"
>
<
!-- <tr class="answer-detail-row submit-answer" data-json="{#{k}#}" data-qname="{#{qname}#}"> --
>
{#% else %#}
<tr class="
answer-detail-row" data-json="{#{k}#}" data-qname="{#{qname}#
}">
<tr
class=
"
solution-detail-row"
data-json=
"{{k}}"
data-qname=
"{{question.name}
}"
>
{#% endif %#}
<td>{
#{v.timestamp}#
}</td>
<td>{
#{v.solver}#
}</td>
<td>
{
{v.timestamp_str}
}
</td>
<td>
{
{v.worker}
}
</td>
<td>
{#% if v.nlcheck == -1 %#}
Not solved
<!-- Not solved -->
{#% else %#}
{#{v.nlcheck}#}
{#% endif %#}
</td>
</tr>
{
#% endfor %#} -->
{
% endfor %}
</table>
</div>
<div
class=
"modal fade"
id=
"solver-processing-modal"
tabindex=
"-1"
role=
"dialog"
aria-labelledby=
"solver-processing-modal-title"
aria-hidden=
"true"
>
<div
class=
"modal-dialog modal-dialog-centered modal-lg"
role=
"document"
>
<div
class=
"modal-content"
>
<div
class=
"modal-header"
>
<h5
class=
"modal-title"
id=
"solver-processing-modal-title"
>
{{question.name}}
</h5>
<button
type=
"button"
class=
"close"
data-dismiss=
"modal"
aria-label=
"Close"
>
<span
aria-hidden=
"true"
>
×
</span>
</button>
</div>
<div
class=
"modal-body"
>
処理中...
</div>
<div
class=
"modal-footer"
>
<button
type=
"button"
class=
"btn btn-secondary"
data-dismiss=
"modal"
>
Close
</button>
<button
type=
"button"
class=
"btn btn-primary"
>
Save changes
</button>
</div>
</div>
</div>
</div>
templates/part_questions.html
View file @
a1c46b41
...
...
@@ -2,16 +2,16 @@
<thead>
<tr>
<th
class=
"large-cell"
>
File Name
</th>
<th
class=
"
large
-cell"
>
Size
</th>
<th
class=
"
small
-cell"
>
Size
</th>
<th
class=
"small-cell"
>
#Blocks
</th>
<th
class=
"large-cell"
>
Status
</th>
</tr>
</thead>
<tbody>
{% for
v in questions
%}
{% for
k, v in questions.items()
%}
<tr
class=
"question-row"
data-qname=
"{{v.name}}"
>
<td
class=
"large-cell"
>
{{v.name}}
</td>
<td
class=
"
large
-cell"
>
{{v.size_str}}
</td>
<td
class=
"
small
-cell"
>
{{v.size_str}}
</td>
<td
class=
"small-cell"
>
{{v.block_num}}
</td>
<td
class=
"large-cell"
>
{{v.status}}
</td>
</tr>
...
...
templates/part_system_summary.html
0 → 100644
View file @
a1c46b41
<h3>
システム状況
</h3>
<div
class=
"summary-section"
>
<h4
class=
'inline-heading'
>
動作モード
</h4>
<span>
{#% if local_mode %#}
Normal Mode
{#% else %#}
<!-- Viewer Mode -->
{#% endif %#}
</span>
</div>
<div
class=
"summary-section"
>
{#% if local_mode %#}
<h4
class=
'inline-heading'
>
自動運営システム
</h4>
<button
type=
"button"
class=
"btn btn-primary"
id=
"adccli-login-button"
>
Login
</button>
<button
type=
"button"
class=
"btn btn-light"
id=
"adccli-logout-button"
>
Logout
</button>
<button
type=
"button"
class=
"btn btn-info"
id=
"adccli-get-all-q"
>
問題DL
</button>
<span
id=
"adccli-status"
></span>
{#% endif %#}
</div>
<div
class=
"summary-section"
>
<h4>
Worker
</h4>
<table
class=
"table table-bordered"
id=
"workers-table"
>
<tr>
<th
class=
""
>
Worker
</th>
<th
class=
""
>
Role
</th>
<th
class=
""
>
Status
</th>
</tr>
{% for k, w in workers.items() %}
<tr
class=
"worker-status-row"
data-cname=
"{{w.name}}"
>
<td
class=
"worker-status-name"
>
{{w.name}} ({{w.address}})
</td>
<td
class=
""
>
{{w.role}}
</td>
<td
class=
"worker-status-value"
>
{{w.status}}
</td>
</tr>
{% endfor %}
</table>
</div>
utils/data.py
View file @
a1c46b41
import
datetime
import
os
import
time
import
uuid
class
Question
(
object
):
...
...
@@ -9,6 +12,7 @@ class Question(object):
self
.
size
=
(
0
,
0
)
self
.
block_num
=
0
self
.
status
=
'Ready'
self
.
solutions
=
dict
()
self
.
_load_question
(
path
)
...
...
@@ -37,3 +41,44 @@ class Question(object):
self
.
block_num
=
block_num
self
.
name
=
name
self
.
status
=
'Ready'
def
get_dict
(
self
):
return
{
'name'
:
self
.
name
,
'size'
:
self
.
size
,
'size_str'
:
self
.
size_str
,
'block_num'
:
self
.
block_num
,
'status'
:
self
.
status
}
def
put_solution
(
self
,
data
):
solution
=
Solution
(
data
)
solution_id
=
solution
.
get_id
()
print
(
f
'I: Put a solution: {solution_id}'
)
self
.
solutions
[
solution_id
]
=
solution
def
get_solutions
(
self
):
return
self
.
solutions
class
Solution
(
object
):
def
__init__
(
self
,
data
):
self
.
question
=
data
[
'question'
]
self
.
request_id
=
data
[
'request_id'
]
self
.
worker
=
data
[
'worker'
]
self
.
elapsed_time
=
data
[
'elapsed_time'
]
self
.
solution
=
data
[
'solution'
]
self
.
timestamp
=
time
.
time
()
self
.
_id
=
str
(
uuid
.
uuid4
())
def
get_id
(
self
):
return
self
.
_id
@
property
def
timestamp_str
(
self
):
dt
=
datetime
.
datetime
.
fromtimestamp
(
self
.
timestamp
,
datetime
.
timezone
(
datetime
.
timedelta
(
hours
=
9
)))
return
dt
.
strftime
(
'
%
H:
%
M:
%
S.
%
f'
)
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