mirror of https://github.com/dirtbags/moth.git
Tanks now using HTML template
This commit is contained in:
parent
1f9d735832
commit
93c9306ea5
4
Makefile
4
Makefile
|
@ -26,6 +26,10 @@ target: $(PYC)
|
||||||
$(INSTALL) -d $(PYCDIR)/ctf
|
$(INSTALL) -d $(PYCDIR)/ctf
|
||||||
$(INSTALL) $(PYC) $(PYCDIR)/ctf
|
$(INSTALL) $(PYC) $(PYCDIR)/ctf
|
||||||
|
|
||||||
|
$(INSTALL) -d $(DESTDIR)/usr/lib/python2.6/site-packages/ctf
|
||||||
|
$(INSTALL) ctf/__init__.py $(DESTDIR)/usr/lib/python2.6/site-packages/ctf
|
||||||
|
$(INSTALL) ctf/config.py $(DESTDIR)/usr/lib/python2.6/site-packages/ctf
|
||||||
|
|
||||||
$(INSTALL) -d $(DESTDIR)/usr/sbin
|
$(INSTALL) -d $(DESTDIR)/usr/sbin
|
||||||
$(INSTALL) ctfd.py $(DESTDIR)/usr/sbin
|
$(INSTALL) ctfd.py $(DESTDIR)/usr/sbin
|
||||||
$(INSTALL) new-contest $(DESTDIR)/usr/sbin
|
$(INSTALL) new-contest $(DESTDIR)/usr/sbin
|
||||||
|
|
30
ctf.css
30
ctf.css
|
@ -7,7 +7,7 @@ html {
|
||||||
body {
|
body {
|
||||||
font-family: sans-serif;
|
font-family: sans-serif;
|
||||||
color: #fff;
|
color: #fff;
|
||||||
margin: 50px 0 0 100px;
|
margin: 50px 0 0 110px;
|
||||||
padding: 10px;
|
padding: 10px;
|
||||||
max-width: 700px;
|
max-width: 700px;
|
||||||
}
|
}
|
||||||
|
@ -33,7 +33,7 @@ h1:first-child:before {
|
||||||
/*** left side bar ***/
|
/*** left side bar ***/
|
||||||
|
|
||||||
#navigation {
|
#navigation {
|
||||||
position: fixed;
|
position: absolute;
|
||||||
background: #222;
|
background: #222;
|
||||||
opacity: 0.9;
|
opacity: 0.9;
|
||||||
top: 80px;
|
top: 80px;
|
||||||
|
@ -41,6 +41,11 @@ h1:first-child:before {
|
||||||
padding: 0;
|
padding: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#navigation h3 {
|
||||||
|
font-size: 100%;
|
||||||
|
border-bottom: 2px solid #444;
|
||||||
|
}
|
||||||
|
|
||||||
#navigation ul {
|
#navigation ul {
|
||||||
list-style: none;
|
list-style: none;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
|
@ -113,6 +118,27 @@ p {
|
||||||
color: #f4f4f4;
|
color: #f4f4f4;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
hr {
|
||||||
|
border: 1px solid #444;
|
||||||
|
}
|
||||||
|
|
||||||
|
dt {
|
||||||
|
white-space: pre;
|
||||||
|
background-color: #333;
|
||||||
|
padding: 5px;
|
||||||
|
border: 2px solid green;
|
||||||
|
border-bottom: none;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
dd {
|
||||||
|
border: 2px solid green;
|
||||||
|
margin: 0px;
|
||||||
|
padding: 5px;
|
||||||
|
background-color: #282828;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**** special cases ****/
|
/**** special cases ****/
|
||||||
|
|
||||||
.wide {
|
.wide {
|
||||||
|
|
|
@ -77,7 +77,7 @@ def datafile(filename):
|
||||||
def url(path):
|
def url(path):
|
||||||
return base_url + path
|
return base_url + path
|
||||||
|
|
||||||
def start_html(title, hdr='', cls=''):
|
def start_html(title, hdr='', cls='', links=[], links_title=None):
|
||||||
ret = []
|
ret = []
|
||||||
if os.environ.get('GATEWAY_INTERFACE'):
|
if os.environ.get('GATEWAY_INTERFACE'):
|
||||||
ret.append('Content-type: text/html')
|
ret.append('Content-type: text/html')
|
||||||
|
@ -98,16 +98,24 @@ def start_html(title, hdr='', cls=''):
|
||||||
<ul>
|
<ul>
|
||||||
<li><a href="%(base)s">Home</a></li>
|
<li><a href="%(base)s">Home</a></li>
|
||||||
<li><a href="%(base)sintro.html">Intro/Rules</a></li>
|
<li><a href="%(base)sintro.html">Intro/Rules</a></li>
|
||||||
<li><a href="%(base)sservices.html">Service flags</a></li>
|
<li><a href="%(base)sservices.html">Svc flags</a></li>
|
||||||
|
<li><a href="%(base)s/tanks/results.cgi">Tanks</a></li>
|
||||||
<li><a href="%(base)spuzzler.cgi">Puzzles</a></li>
|
<li><a href="%(base)spuzzler.cgi">Puzzles</a></li>
|
||||||
<li><a href="%(base)sscoreboard.cgi">Scoreboard</a></li>
|
<li><a href="%(base)sscoreboard.cgi">Scoreboard</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
|
||||||
''' % {'title': title,
|
''' % {'title': title,
|
||||||
'css': css,
|
'css': css,
|
||||||
'hdr': hdr,
|
'hdr': hdr,
|
||||||
'base': base_url,
|
'base': base_url,
|
||||||
'class': cls})
|
'class': cls})
|
||||||
|
if links:
|
||||||
|
if links_title:
|
||||||
|
ret.append('<h3>%s</h3>' % links_title)
|
||||||
|
else:
|
||||||
|
ret.append('<hr/>')
|
||||||
|
for url, name in links:
|
||||||
|
ret.append('<li><a href="%s">%s</a></li>' % (url, name))
|
||||||
|
ret.append(' </div>')
|
||||||
return '\n'.join(ret)
|
return '\n'.join(ret)
|
||||||
|
|
||||||
def end_html():
|
def end_html():
|
||||||
|
|
|
@ -7,7 +7,7 @@ skills at designing those wits to survive.
|
||||||
|
|
||||||
<H2>Programming Your Tank</H2>
|
<H2>Programming Your Tank</H2>
|
||||||
Your tanks are programmed using the Super Useful Command and Kontrol language,
|
Your tanks are programmed using the Super Useful Command and Kontrol language,
|
||||||
the very best in laser tank AI languages. It includes amazing feature such
|
the very best in laser tank AI languages. It includes amazing features such
|
||||||
as comments (Started by a #, ended at EOL), logic, versatility, and
|
as comments (Started by a #, ended at EOL), logic, versatility, and
|
||||||
semi-colons (all lines must end in one). As with all new military systems
|
semi-colons (all lines must end in one). As with all new military systems
|
||||||
it utilizes only integers; we must never rest in our
|
it utilizes only integers; we must never rest in our
|
||||||
|
|
|
@ -4,9 +4,8 @@ def mkDocTable(objects):
|
||||||
objects.sort(lambda o1, o2: cmp(o1.__doc__, o2.__doc__))
|
objects.sort(lambda o1, o2: cmp(o1.__doc__, o2.__doc__))
|
||||||
|
|
||||||
for object in objects:
|
for object in objects:
|
||||||
print '<table class="docs">'
|
|
||||||
if object.__doc__ is None:
|
if object.__doc__ is None:
|
||||||
print '<tr><th>%s<tr><td colspan=2>Bad object' % \
|
print '<table><tr><th>%s<tr><td colspan=2>Bad object</table>' % \
|
||||||
xml.sax.saxutils.escape(str(object))
|
xml.sax.saxutils.escape(str(object))
|
||||||
continue
|
continue
|
||||||
text = object.__doc__
|
text = object.__doc__
|
||||||
|
@ -23,5 +22,5 @@ def mkDocTable(objects):
|
||||||
body = '\n'.join(body)
|
body = '\n'.join(body)
|
||||||
print '<DL><DT><DIV class="tab">%s</DIV></DT><DD>%s</DD></DL>' % (head, body)
|
print '<DL><DT><DIV class="tab">%s</DIV></DT><DD>%s</DD></DL>' % (head, body)
|
||||||
#print '<tr><th>%s<th>Intentionally blank<th><tr><td colspan=3>%s' % (head, body)
|
#print '<tr><th>%s<th>Intentionally blank<th><tr><td colspan=3>%s' % (head, body)
|
||||||
print '</table>'
|
|
||||||
|
|
||||||
|
|
|
@ -1,104 +0,0 @@
|
||||||
/**** document ****/
|
|
||||||
|
|
||||||
html {
|
|
||||||
background: #222 url(grunge.png) repeat-x;
|
|
||||||
}
|
|
||||||
|
|
||||||
body {
|
|
||||||
font-family: sans-serif;
|
|
||||||
color: #eee;
|
|
||||||
margin: 50px 0 0 100px;
|
|
||||||
padding: 10px;
|
|
||||||
max-width: 700px;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**** heading ****/
|
|
||||||
|
|
||||||
h1:first-child {
|
|
||||||
text-transform: lowercase;
|
|
||||||
font-size: 1.6em;
|
|
||||||
/* background-color: #222; */
|
|
||||||
/* opacity: 0.9; */
|
|
||||||
padding: 3px;
|
|
||||||
color: #2a2;
|
|
||||||
margin: 0 0 1em 70px;
|
|
||||||
}
|
|
||||||
|
|
||||||
h1:first-child:before {
|
|
||||||
color: #fff;
|
|
||||||
letter-spacing: -0.1em;
|
|
||||||
content: "Capture The Flag: ";
|
|
||||||
}
|
|
||||||
|
|
||||||
/**** body ****/
|
|
||||||
|
|
||||||
a img {
|
|
||||||
border: 0px;
|
|
||||||
}
|
|
||||||
|
|
||||||
a {
|
|
||||||
text-decoration: none;
|
|
||||||
color: #2a2;
|
|
||||||
font-weight: bold;
|
|
||||||
}
|
|
||||||
|
|
||||||
a:hover {
|
|
||||||
color: #fff;
|
|
||||||
background: #2a2;
|
|
||||||
font-weight: bold;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
h1, h2, h3 {
|
|
||||||
color: #999;
|
|
||||||
letter-spacing: -0.05em;
|
|
||||||
}
|
|
||||||
|
|
||||||
code, pre, .readme, div.errors {
|
|
||||||
color: #fff;
|
|
||||||
background-color: #555;
|
|
||||||
margin: 1em;
|
|
||||||
}
|
|
||||||
|
|
||||||
th, td {
|
|
||||||
vertical-align: top;
|
|
||||||
}
|
|
||||||
|
|
||||||
.scoreboard td {
|
|
||||||
height: 400px;
|
|
||||||
}
|
|
||||||
|
|
||||||
p {
|
|
||||||
line-height: 1.4em;
|
|
||||||
margin-bottom: 20px;
|
|
||||||
color: #f4f4f4;
|
|
||||||
}
|
|
||||||
|
|
||||||
dt {
|
|
||||||
white-space: pre;
|
|
||||||
}
|
|
||||||
|
|
||||||
dt div.tab {
|
|
||||||
background-color: #333;
|
|
||||||
display: inline-block;
|
|
||||||
padding: 5px;
|
|
||||||
border: 3px solid green;
|
|
||||||
border-bottom: none;
|
|
||||||
font-weight: bold;
|
|
||||||
}
|
|
||||||
|
|
||||||
dd {
|
|
||||||
border: 3px solid green;
|
|
||||||
margin: 0px;
|
|
||||||
padding: 5px;
|
|
||||||
background-color: #282828;
|
|
||||||
}
|
|
||||||
|
|
||||||
fieldset * {
|
|
||||||
margin: 3px;
|
|
||||||
}
|
|
||||||
|
|
||||||
table.results td, th{
|
|
||||||
padding : 3px;
|
|
||||||
font-weight : bold;
|
|
||||||
}
|
|
|
@ -1,10 +1,9 @@
|
||||||
#!/usr/bin/python
|
#!/usr/bin/python
|
||||||
|
|
||||||
print """Content-Type: text/html\n\n"""
|
|
||||||
print """<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">\n\n"""
|
|
||||||
import cgitb; cgitb.enable()
|
import cgitb; cgitb.enable()
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
|
from ctf import config
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from tanks import Program, setup, conditions, actions, docs
|
from tanks import Program, setup, conditions, actions, docs
|
||||||
|
@ -15,10 +14,13 @@ except:
|
||||||
sys.path.append(os.path.join('/', *path))
|
sys.path.append(os.path.join('/', *path))
|
||||||
import Program, setup, conditions, actions, docs
|
import Program, setup, conditions, actions, docs
|
||||||
|
|
||||||
print open('head.html').read() % "Documentation"
|
print(config.start_html('Tanks Documentation',
|
||||||
print '<BODY>'
|
links_title='Tanks',
|
||||||
print '<H1>Pflanzarr Documentation</H1>'
|
links=[('docs.cgi', 'Docs'),
|
||||||
print open('links.html').read()
|
('results.cgi', 'Results'),
|
||||||
|
('submit.html', 'Submit'),
|
||||||
|
('errors.cgi', 'My Errors')]))
|
||||||
|
|
||||||
print Program.__doc__
|
print Program.__doc__
|
||||||
|
|
||||||
print '<H3>Setup Actions:</H3>'
|
print '<H3>Setup Actions:</H3>'
|
||||||
|
@ -34,4 +36,4 @@ print '<H3>Actions:</H3>'
|
||||||
print 'These actions are not for cowards. Remember, if actions contradict, your tank will simply do the last thing it was told in a turn. If ordered to hop on a plane to hell it will gladly do so. If order to make tea shortly afterwards, it will serve it politely and with cookies instead.<P>'
|
print 'These actions are not for cowards. Remember, if actions contradict, your tank will simply do the last thing it was told in a turn. If ordered to hop on a plane to hell it will gladly do so. If order to make tea shortly afterwards, it will serve it politely and with cookies instead.<P>'
|
||||||
docs.mkDocTable(actions.actions.values())
|
docs.mkDocTable(actions.actions.values())
|
||||||
|
|
||||||
print '</body></html>'
|
print(config.end_html())
|
||||||
|
|
|
@ -1,7 +1,5 @@
|
||||||
#!/usr/bin/python3
|
#!/usr/bin/python3
|
||||||
|
|
||||||
print("""Content-Type: text/html\n\n""")
|
|
||||||
print("""<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Strict//EN">\n\n""")
|
|
||||||
import cgi
|
import cgi
|
||||||
import cgitb; cgitb.enable()
|
import cgitb; cgitb.enable()
|
||||||
import sys
|
import sys
|
||||||
|
@ -20,15 +18,18 @@ except:
|
||||||
path = '/home/pflarr/repos/gctf/'
|
path = '/home/pflarr/repos/gctf/'
|
||||||
sys.path.append(path)
|
sys.path.append(path)
|
||||||
from ctf import teams
|
from ctf import teams
|
||||||
|
from ctf import config
|
||||||
teams.build_teams()
|
teams.build_teams()
|
||||||
|
|
||||||
head = open('head.html').read() % "Error Report"
|
print(config.start_html('Tanks Errors',
|
||||||
print(head)
|
links_title='Tanks',
|
||||||
print('<H1>Your Errors</H1>')
|
links=[('docs.cgi', 'Docs'),
|
||||||
print(open('links.html').read())
|
('results.cgi', 'Results'),
|
||||||
|
('submit.html', 'Submit'),
|
||||||
|
('errors.cgi', 'My Errors')]))
|
||||||
|
|
||||||
def done():
|
def done():
|
||||||
print('</body></html>')
|
print(config.end_html())
|
||||||
sys.exit(0)
|
sys.exit(0)
|
||||||
|
|
||||||
fields = cgi.FieldStorage()
|
fields = cgi.FieldStorage()
|
||||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 5.8 KiB |
|
@ -1,5 +0,0 @@
|
||||||
<html>
|
|
||||||
<head>
|
|
||||||
<link href="ctf.css" rel="stylesheet" type="text/css">
|
|
||||||
<title>%s</title>
|
|
||||||
</head>
|
|
|
@ -1,4 +0,0 @@
|
||||||
<a href="docs.cgi">Documentation</a> |
|
|
||||||
<a href="results.cgi">Results</a> |
|
|
||||||
<a href="submit.html">Submit</a> |
|
|
||||||
<a href="errors.cgi">My Errors</a>
|
|
|
@ -2,16 +2,16 @@
|
||||||
|
|
||||||
import cgitb; cgitb.enable()
|
import cgitb; cgitb.enable()
|
||||||
import os
|
import os
|
||||||
|
from ctf import config
|
||||||
|
|
||||||
import Config
|
import Config
|
||||||
|
|
||||||
print """Content-Type: text/html\n\n"""
|
print(config.start_html('Tanks Results',
|
||||||
print """<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">\n\n"""
|
links_title='Tanks',
|
||||||
head = open('head.html').read() % "Pflanzarr Results"
|
links=[('docs.cgi', 'Docs'),
|
||||||
print head
|
('results.cgi', 'Results'),
|
||||||
print "<H1>Results</H1>"
|
('submit.html', 'Submit'),
|
||||||
print open('links.html').read()
|
('errors.cgi', 'My Errors')]))
|
||||||
|
|
||||||
try:
|
try:
|
||||||
winner = open(os.path.join(Config.DATA_PATH, 'winner')).read()
|
winner = open(os.path.join(Config.DATA_PATH, 'winner')).read()
|
||||||
except:
|
except:
|
||||||
|
@ -52,4 +52,4 @@ for num in gameNums:
|
||||||
print '<a href="results/%d/game.avi">v</a>' % num,
|
print '<a href="results/%d/game.avi">v</a>' % num,
|
||||||
print '<a href="results/%d/results.html">r</a>' % num
|
print '<a href="results/%d/results.html">r</a>' % num
|
||||||
|
|
||||||
print '</body></html>'
|
print(config.end_html())
|
||||||
|
|
|
@ -1,7 +1,5 @@
|
||||||
#!/usr/bin/python3
|
#!/usr/bin/python3
|
||||||
|
|
||||||
print("Content-Type: text/html\n\n")
|
|
||||||
print("""<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Strict//EN">\n\n""")
|
|
||||||
import cgi
|
import cgi
|
||||||
import cgitb; cgitb.enable()
|
import cgitb; cgitb.enable()
|
||||||
import os
|
import os
|
||||||
|
@ -20,15 +18,18 @@ except:
|
||||||
path = '/home/pflarr/repos/gctf/'
|
path = '/home/pflarr/repos/gctf/'
|
||||||
sys.path.append(path)
|
sys.path.append(path)
|
||||||
from ctf import teams
|
from ctf import teams
|
||||||
|
from ctf import config
|
||||||
teams.build_teams()
|
teams.build_teams()
|
||||||
|
|
||||||
head = open('head.html').read() % "Submission Results"
|
print(config.start_html('Tanks Submission',
|
||||||
print(head)
|
links_title='Tanks',
|
||||||
print("<H1>Results</H1>")
|
links=[('docs.cgi', 'Docs'),
|
||||||
print(open('links.html').read())
|
('results.cgi', 'Results'),
|
||||||
|
('submit.html', 'Submit'),
|
||||||
|
('errors.cgi', 'My Errors')]))
|
||||||
|
|
||||||
def done():
|
def done():
|
||||||
print('</body></html>')
|
print(config.end_html())
|
||||||
sys.exit(0)
|
sys.exit(0)
|
||||||
|
|
||||||
fields = cgi.FieldStorage()
|
fields = cgi.FieldStorage()
|
||||||
|
@ -36,23 +37,23 @@ team = fields.getfirst('team', '').strip()
|
||||||
passwd = fields.getfirst('passwd', '').strip()
|
passwd = fields.getfirst('passwd', '').strip()
|
||||||
code = fields.getfirst('code', '')
|
code = fields.getfirst('code', '')
|
||||||
if not team:
|
if not team:
|
||||||
print('<p>No team specified'); done()
|
print('<p>No team specified</p>'); done()
|
||||||
elif not passwd:
|
elif not passwd:
|
||||||
print('<p>No password given'); done()
|
print('<p>No password given</p>'); done()
|
||||||
elif not code:
|
elif not code:
|
||||||
print('<p>No program given.'); done()
|
print('<p>No program given.</p>'); done()
|
||||||
|
|
||||||
if team not in teams.teams:
|
if team not in teams.teams:
|
||||||
print('<p>Team is not registered.'); done()
|
print('<p>Team is not registered.</p>'); done()
|
||||||
|
|
||||||
if passwd != teams.teams[team][0]:
|
if passwd != teams.teams[team][0]:
|
||||||
print('<p>Invalid password.'); done()
|
print('<p>Invalid password.</p>'); done()
|
||||||
|
|
||||||
path = os.path.join(Config.DATA_PATH, 'ai/players', quote(team) )
|
path = os.path.join(Config.DATA_PATH, 'ai/players', quote(team) )
|
||||||
file = open(path, 'w')
|
file = open(path, 'w')
|
||||||
file.write(code)
|
file.write(code)
|
||||||
file.close()
|
file.close()
|
||||||
|
|
||||||
print("<P>Submission Successful")
|
print("<p>Submission successful.</p>")
|
||||||
|
|
||||||
done()
|
done()
|
||||||
|
|
|
@ -1,16 +1,33 @@
|
||||||
<html>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE html PUBLIC
|
||||||
|
"-//W3C//DTD XHTML 1.0 Strict//EN"
|
||||||
|
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
|
||||||
|
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||||
<head>
|
<head>
|
||||||
<link href="ctf.css" rel="stylesheet" type="text/css">'
|
<title>Tanks Submission</title>
|
||||||
<title>Program Submission</title>"
|
<link rel="stylesheet" href="/ctf.css" type="text/css" />
|
||||||
</head>
|
|
||||||
|
</head>
|
||||||
|
<body class="">
|
||||||
|
<h1>Tanks Submission</h1>
|
||||||
|
|
||||||
|
<div id="navigation">
|
||||||
|
<ul>
|
||||||
|
<li><a href="/">Home</a></li>
|
||||||
|
<li><a href="/intro.html">Intro/Rules</a></li>
|
||||||
|
<li><a href="/services.html">Svc flags</a></li>
|
||||||
|
<li><a href="/puzzler.cgi">Puzzles</a></li>
|
||||||
|
<li><a href="/scoreboard.cgi">Scoreboard</a></li>
|
||||||
|
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<h3>Tanks</h3>
|
||||||
|
<li><a href="docs.cgi">Docs</a></li>
|
||||||
|
<li><a href="results.cgi">Results</a></li>
|
||||||
|
<li><a href="submit.html">Submit</a></li>
|
||||||
|
<li><a href="errors.cgi">My Errors</a></li>
|
||||||
|
</div>
|
||||||
|
|
||||||
<body>
|
|
||||||
<H1>Program Submission</H1>
|
|
||||||
<p>
|
|
||||||
<a href="docs.cgi">Documentation</a> |
|
|
||||||
<a href="results.cgi">Results</a> |
|
|
||||||
<a href="submit.html">Submit</a> |
|
|
||||||
<a href="errors.cgi">My Errors</a>
|
|
||||||
<form action="submit.cgi" method="post">
|
<form action="submit.cgi" method="post">
|
||||||
<fieldset>
|
<fieldset>
|
||||||
<legend>Your program:</legend>
|
<legend>Your program:</legend>
|
||||||
|
|
Loading…
Reference in New Issue