mirror of https://github.com/dirtbags/tanks.git
Working CGI
This commit is contained in:
parent
a7969c9edb
commit
e7eca89844
|
@ -1,3 +1,11 @@
|
|||
*~
|
||||
*#
|
||||
*.o
|
||||
round-*.html
|
||||
run-tanks
|
||||
forf.c
|
||||
forf.h
|
||||
forf.html
|
||||
designer.cgi
|
||||
next-round
|
||||
summary.html
|
||||
|
|
1
Makefile
1
Makefile
|
@ -15,6 +15,7 @@ forf.html: forf.html.sh forf/forf.txt
|
|||
|
||||
forf.%: forf/forf.%
|
||||
cp forf/$@ $@
|
||||
.PRECIOUS: forf/%
|
||||
forf/%:
|
||||
git submodule update --init
|
||||
|
||||
|
|
300
designer.cgi.c
300
designer.cgi.c
|
@ -1,45 +1,35 @@
|
|||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#define BASE_PATH "/tmp/"
|
||||
#define BASE_PATH "/tmp/tanks/"
|
||||
|
||||
struct string {
|
||||
char *s;
|
||||
struct {
|
||||
char *name;
|
||||
size_t size;
|
||||
size_t len;
|
||||
} entries[] = {
|
||||
{"name", 20},
|
||||
{"author", 40},
|
||||
{"color", 10},
|
||||
{"program", 8192},
|
||||
{NULL, 0}
|
||||
};
|
||||
|
||||
void
|
||||
string_append(struct string *str, char c)
|
||||
{
|
||||
if (str->len < str->size) {
|
||||
str->s[str->len++] = c;
|
||||
}
|
||||
}
|
||||
|
||||
size_t inlen;
|
||||
|
||||
int
|
||||
string_cmp(struct string *a, char *b, size_t blen)
|
||||
read_char()
|
||||
{
|
||||
if (a->len > blen) {
|
||||
return 1;
|
||||
} else if (a->len < blen) {
|
||||
return -1;
|
||||
} else {
|
||||
return memcmp(a->s, b, blen);
|
||||
if (inlen) {
|
||||
inlen -= 1;
|
||||
return getchar();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
string_cpy(struct string *dst, struct string *src)
|
||||
{
|
||||
if (dst->size < src->len) {
|
||||
dst->len = dst->size;
|
||||
} else {
|
||||
dst->len = src->len;
|
||||
}
|
||||
memcpy(dst->s, src->s, dst->len);
|
||||
return EOF;
|
||||
}
|
||||
|
||||
char
|
||||
|
@ -58,10 +48,10 @@ tonum(int c)
|
|||
}
|
||||
|
||||
char
|
||||
read_hex(FILE *f)
|
||||
read_hex()
|
||||
{
|
||||
int a = fgetc(f);
|
||||
int b = fgetc(f);
|
||||
int a = read_char();
|
||||
int b = read_char();
|
||||
|
||||
return tonum(a)*16 + tonum(b);
|
||||
}
|
||||
|
@ -69,90 +59,149 @@ read_hex(FILE *f)
|
|||
/* Read a key or a value. Since & and = aren't supposed to appear
|
||||
outside of boundaries, we can use the same function for both.
|
||||
*/
|
||||
int
|
||||
read_item(FILE *f, struct string *str)
|
||||
size_t
|
||||
read_item(char *str, size_t maxlen)
|
||||
{
|
||||
int c;
|
||||
|
||||
str->len = 0;
|
||||
int c;
|
||||
size_t pos = 0;
|
||||
|
||||
while (1) {
|
||||
c = fgetc(f);
|
||||
c = read_char();
|
||||
switch (c) {
|
||||
case EOF:
|
||||
return 0;
|
||||
break;
|
||||
case '=':
|
||||
case '&':
|
||||
return 1;
|
||||
break;
|
||||
str[pos] = '\0';
|
||||
return pos;
|
||||
case '%':
|
||||
string_append(str, read_hex(f));
|
||||
c = read_hex();
|
||||
break;
|
||||
default:
|
||||
string_append(str, c);
|
||||
case '+':
|
||||
c = ' ';
|
||||
break;
|
||||
}
|
||||
if (pos < maxlen - 1) {
|
||||
str[pos] = c;
|
||||
pos += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
size_t
|
||||
copy_item(char *filename, size_t maxlen)
|
||||
{
|
||||
FILE *f;
|
||||
char path[132];
|
||||
int c;
|
||||
size_t pos = 0;
|
||||
|
||||
snprintf(path, sizeof(path),
|
||||
BASE_PATH "%05d.%s",
|
||||
getpid(), filename);
|
||||
f = fopen(path, "w");
|
||||
if (! f) {
|
||||
/* Just send it to the bit bucket */
|
||||
maxlen = 0;
|
||||
}
|
||||
|
||||
while (1) {
|
||||
c = read_char();
|
||||
switch (c) {
|
||||
case EOF:
|
||||
case '=':
|
||||
case '&':
|
||||
if (f) fclose(f);
|
||||
return pos;
|
||||
case '%':
|
||||
c = read_hex();
|
||||
break;
|
||||
case '+':
|
||||
c = ' ';
|
||||
break;
|
||||
}
|
||||
if (pos < maxlen) {
|
||||
fputc(c, f);
|
||||
pos += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
read_pair(FILE *f, struct string *key, struct string *val)
|
||||
croak(char *msg)
|
||||
{
|
||||
if (! read_item(f, key)) {
|
||||
return 0;
|
||||
}
|
||||
return read_item(f, val);
|
||||
}
|
||||
int i;
|
||||
char path[132];
|
||||
|
||||
/* This is ugly and I dislike it. */
|
||||
#define new_string(name, size) \
|
||||
char _##name[size]; \
|
||||
struct string name = {_##name, size, 0 }
|
||||
for (i = 0; entries[i].name; i += 1) {
|
||||
snprintf(path, sizeof(path),
|
||||
BASE_PATH "%05d.%s",
|
||||
getpid(), entries[i].name);
|
||||
unlink(path);
|
||||
}
|
||||
|
||||
printf("Content-type: text/html\n\n");
|
||||
printf("<html><head>\n");
|
||||
printf("<link rel=\"stylesheet\" href=\"dirtbags.css\" type=\"text/css\">\n");
|
||||
printf("<title>Tank submission error</title>\n");
|
||||
printf("</head><body><h1>Tank submission error</h1>\n");
|
||||
if (msg) {
|
||||
printf("<p>%s.</p>\n", msg);
|
||||
} else {
|
||||
printf("<p>Something went wrong.</p>.\n");
|
||||
}
|
||||
printf("<p>Sorry it didn't work out.</p>\n");
|
||||
printf("<p>You could go back and try again, though.</p>\n");
|
||||
printf("</body></html>\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
int sensor[10][4];
|
||||
int sensor[10][4];
|
||||
char key[20];
|
||||
char token[40];
|
||||
size_t len;
|
||||
|
||||
new_string(key, 20);
|
||||
new_string(val, 8192);
|
||||
new_string(token, 40);
|
||||
new_string(name, 20);
|
||||
new_string(author, 60);
|
||||
new_string(color, 10);
|
||||
new_string(program, 8192);
|
||||
memset(sensor, 0, sizeof(sensor));
|
||||
token[0] = '\0';
|
||||
|
||||
printf("Content-type: text/plain\n\n");
|
||||
{
|
||||
char *rm = getenv("REQUEST_METHOD");
|
||||
|
||||
while (! feof(stdin)) {
|
||||
read_pair(stdin, &key, &val);
|
||||
if (0 == string_cmp(&key, "token", 5)) {
|
||||
string_cpy(&token, &key);
|
||||
} else if (0 == string_cmp(&key, "name", 4)) {
|
||||
string_cpy(&name, &key);
|
||||
} else if (0 == string_cmp(&key, "author", 6)) {
|
||||
string_cpy(&author, &key);
|
||||
} else if (0 == string_cmp(&key, "color", 5)) {
|
||||
string_cpy(&color, &key);
|
||||
} else if (0 == string_cmp(&key, "program", 7)) {
|
||||
string_cpy(&program, &key);
|
||||
} else if ((3 == key.len) && ('s' == key.s[0])) {
|
||||
if (! (rm && (0 == strcmp(rm, "POST")))) {
|
||||
printf("405 Method not allowed\n");
|
||||
printf("Allow: POST\n");
|
||||
printf("Content-type: text/html\n");
|
||||
printf("\n");
|
||||
printf("<h1>Method not allowed</h1>\n");
|
||||
printf("<p>I only speak POST. Sorry.</p>\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
inlen = atoi(getenv("CONTENT_LENGTH"));
|
||||
}
|
||||
|
||||
while (inlen) {
|
||||
len = read_item(key, sizeof(key));
|
||||
if (0 == strcmp(key, "token")) {
|
||||
read_item(token, sizeof(token));
|
||||
} else if ((3 == len) && ('s' == key[0])) {
|
||||
/* sensor dealie, key = "s[0-9][rawt]" */
|
||||
int n = key.s[1] - '0';
|
||||
int i;
|
||||
int p;
|
||||
char val[5];
|
||||
int n = key[1] - '0';
|
||||
int i;
|
||||
int p;
|
||||
|
||||
read_item(val, sizeof(val));
|
||||
|
||||
if (! (n >= 0) && (n <= 9)) {
|
||||
break;
|
||||
}
|
||||
if (val.len > 3) {
|
||||
break;
|
||||
}
|
||||
val.s[val.len] = '\0';
|
||||
i = atoi(val.s);
|
||||
i = atoi(val);
|
||||
|
||||
switch (key.s[2]) {
|
||||
switch (key[2]) {
|
||||
case 'r':
|
||||
p = 0;
|
||||
break;
|
||||
|
@ -164,16 +213,87 @@ main(int argc, char *argv[])
|
|||
break;
|
||||
default:
|
||||
p = 3;
|
||||
i = (val[0] != '\0');
|
||||
break;
|
||||
}
|
||||
|
||||
sensor[n][p] = i;
|
||||
} else {
|
||||
int i;
|
||||
|
||||
for (i = 0; entries[i].name; i += 1) {
|
||||
if (0 == strcmp(key, entries[i].name)) {
|
||||
len = copy_item(key, entries[i].size);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
write(1, key.s, key.len);
|
||||
write(1, "=", 1);
|
||||
write(1, val.s, val.len);
|
||||
write(1, "\n", 1);
|
||||
}
|
||||
|
||||
/* Sanitize token */
|
||||
{
|
||||
char *p = token;
|
||||
|
||||
while (*p) {
|
||||
if (! isalnum(*p)) {
|
||||
*p = '_';
|
||||
}
|
||||
p += 1;
|
||||
}
|
||||
|
||||
if ('\0' == token[0]) {
|
||||
token[0] = '_';
|
||||
token[1] = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
/* Move files into their directory */
|
||||
{
|
||||
char path[132];
|
||||
char dest[132];
|
||||
struct stat st;
|
||||
int i;
|
||||
|
||||
snprintf(path, sizeof(path), BASE_PATH "%s/", token);
|
||||
if (-1 == stat(path, &st)) return croak("Invalid token");
|
||||
if (! S_ISDIR(st.st_mode)) return croak("Invalid token");
|
||||
for (i = 0; entries[i].name; i += 1) {
|
||||
snprintf(path, sizeof(path),
|
||||
BASE_PATH "%05d.%s",
|
||||
getpid(), entries[i].name);
|
||||
snprintf(dest, sizeof(dest),
|
||||
BASE_PATH "%s/%s",
|
||||
token, entries[i].name);
|
||||
rename(path, dest);
|
||||
}
|
||||
|
||||
for (i = 0; i < 10; i += 1) {
|
||||
FILE *f;
|
||||
|
||||
snprintf(dest, sizeof(dest),
|
||||
BASE_PATH "%s/sensor%d",
|
||||
token, i);
|
||||
f = fopen(dest, "w");
|
||||
if (! f) break;
|
||||
|
||||
fprintf(f, "%d %d %d %d\n",
|
||||
sensor[i][0],
|
||||
sensor[i][1],
|
||||
sensor[i][2],
|
||||
sensor[i][3]);
|
||||
fclose(f);
|
||||
}
|
||||
}
|
||||
|
||||
printf("Content-type: text/html\n\n");
|
||||
printf("<!DOCTYPE html>\n");
|
||||
printf("<html><head>\n");
|
||||
printf("<link rel=\"stylesheet\" href=\"dirtbags.css\" type=\"text/css\">\n");
|
||||
printf("<title>Tank submitted</title>\n");
|
||||
printf("</head><body><h1>Tank submitted</h1>\n");
|
||||
printf("<p>You just uploaded a tank!</p>\n");
|
||||
printf("<p>Let's hope it doesn't suck.</p>\n");
|
||||
printf("</body></html>\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -27,10 +27,20 @@
|
|||
<body>
|
||||
<h1>Tank Designer</h1>
|
||||
<div id="preview"><canvas id="design"></canvas><p id="debug"></p></div>
|
||||
<form>
|
||||
|
||||
<p>
|
||||
Before you can get going with a tank, you need a token. If you
|
||||
need a token, just ask one of the dirtbags.
|
||||
</p>
|
||||
|
||||
<form action="designer.cgi" method="post">
|
||||
<fieldset id="metadata">
|
||||
<legend>Information</legend>
|
||||
<table>
|
||||
<tr>
|
||||
<td>Token:</td>
|
||||
<td><input name="token"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Tank name:</td>
|
||||
<td><input name="name"></td>
|
||||
|
|
|
@ -18,7 +18,7 @@ function update() {
|
|||
var color = document.getElementsByName('color')[0].value;
|
||||
var sensors = new Array();
|
||||
|
||||
for (i = 0; i < 4; i += 1) {
|
||||
for (i = 0; i < 10; i += 1) {
|
||||
var range = document.getElementsByName('s'+i+'r')[0].value;
|
||||
var angle = document.getElementsByName('s'+i+'a')[0].value;
|
||||
var width = document.getElementsByName('s'+i+'w')[0].value;
|
||||
|
|
11
dirtbags.css
11
dirtbags.css
|
@ -17,8 +17,6 @@ body {
|
|||
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;
|
||||
|
@ -117,15 +115,6 @@ pre {
|
|||
}
|
||||
|
||||
|
||||
th {
|
||||
vertical-align: top;
|
||||
text-align: center;
|
||||
}
|
||||
td {
|
||||
vertical-align: top;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
p {
|
||||
line-height: 1.4em;
|
||||
margin-bottom: 20px;
|
||||
|
|
14
round.sh
14
round.sh
|
@ -1,5 +1,13 @@
|
|||
#! /bin/sh
|
||||
|
||||
if [ "$#" -gt 0 ]; then
|
||||
tanks="$@"
|
||||
else
|
||||
echo "Usage: $0 tank1 tank2 [...]"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
|
||||
if [ -f next-round ]; then
|
||||
next=$(cat next-round)
|
||||
else
|
||||
|
@ -18,13 +26,13 @@ cat <<EOF >$fn
|
|||
<head>
|
||||
<title>Tanks Round $next</title>
|
||||
<script type="application/javascript" src="tanks.js"></script>
|
||||
<link rel="stylesheet" href="tanks.css" type="text/css">
|
||||
<link rel="stylesheet" href="dirtbags.css" type="text/css">
|
||||
<script type="application/javascript">
|
||||
function go() {
|
||||
start("battlefield",
|
||||
// Start JSON data
|
||||
EOF
|
||||
./run-tanks players/* >>$fn 3>$rfn
|
||||
./run-tanks $tanks >>$fn 3>$rfn
|
||||
cat <<EOF >>$fn
|
||||
// end JSON data
|
||||
);
|
||||
|
@ -43,7 +51,7 @@ cat <<EOF >>$fn
|
|||
</html>
|
||||
EOF
|
||||
|
||||
./summary.awk > summary.html
|
||||
./summary.awk $tanks > summary.html
|
||||
|
||||
echo "done."
|
||||
|
||||
|
|
|
@ -12,7 +12,7 @@ BEGIN {
|
|||
print "<html>";
|
||||
print " <head>";
|
||||
print " <title>Dirtbags Tanks</title>";
|
||||
print " <link rel=\"stylesheet\" href=\"tanks.css\" type=\"text/css\">";
|
||||
print " <link rel=\"stylesheet\" href=\"dirtbags.css\" type=\"text/css\">";
|
||||
print " </head>";
|
||||
print " <body>";
|
||||
print " <h1>Dirtbags Tanks</h1>";
|
||||
|
@ -27,7 +27,9 @@ BEGIN {
|
|||
|
||||
print " <h2>Rankings</h2>";
|
||||
print " <ol>";
|
||||
while ("ls -d players/*" | getline id) {
|
||||
for (i = 1; i < ARGC; i += 1) {
|
||||
id = ARGV[i];
|
||||
|
||||
if (1 == getline < (id "/name")) {
|
||||
names[id] = esc($0);
|
||||
} else {
|
||||
|
|
|
@ -0,0 +1,142 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
width="315"
|
||||
height="180"
|
||||
id="svg2"
|
||||
sodipodi:version="0.32"
|
||||
inkscape:version="0.46"
|
||||
version="1.0"
|
||||
sodipodi:docname="token.svg"
|
||||
inkscape:output_extension="org.inkscape.output.svg.inkscape">
|
||||
<defs
|
||||
id="defs4">
|
||||
<inkscape:perspective
|
||||
sodipodi:type="inkscape:persp3d"
|
||||
inkscape:vp_x="0 : 526.18109 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_z="744.09448 : 526.18109 : 1"
|
||||
inkscape:persp3d-origin="372.04724 : 350.78739 : 1"
|
||||
id="perspective10" />
|
||||
</defs>
|
||||
<sodipodi:namedview
|
||||
id="base"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
gridtolerance="10000"
|
||||
guidetolerance="10"
|
||||
objecttolerance="10"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:zoom="1"
|
||||
inkscape:cx="269.04724"
|
||||
inkscape:cy="12"
|
||||
inkscape:document-units="px"
|
||||
inkscape:current-layer="layer1"
|
||||
showgrid="false"
|
||||
units="in"
|
||||
inkscape:window-width="1020"
|
||||
inkscape:window-height="687"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="17" />
|
||||
<metadata
|
||||
id="metadata7">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
inkscape:label="Layer 1"
|
||||
inkscape:groupmode="layer"
|
||||
id="layer1">
|
||||
<g
|
||||
id="g3161"
|
||||
transform="matrix(1.0829475,0,0,1.0829475,-3.8658087,40.040188)">
|
||||
<rect
|
||||
y="29.306273"
|
||||
x="39.023125"
|
||||
height="58.804661"
|
||||
width="46.712982"
|
||||
id="rect2383"
|
||||
style="fill:#4f4f4f;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.96922117px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
|
||||
<rect
|
||||
y="11.121428"
|
||||
x="85.736092"
|
||||
height="89.043518"
|
||||
width="28.585094"
|
||||
id="rect2385"
|
||||
style="fill:#777777;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.96357071px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
|
||||
<rect
|
||||
style="fill:#777777;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.96357071px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
id="rect2387"
|
||||
width="28.585094"
|
||||
height="89.043518"
|
||||
x="10.438034"
|
||||
y="11.121428" />
|
||||
<rect
|
||||
inkscape:transform-center-y="-20.587678"
|
||||
inkscape:transform-center-x="-11.779977"
|
||||
transform="matrix(0.8668119,0.4986353,-0.4986353,0.8668119,0,0)"
|
||||
y="-37.782883"
|
||||
x="75.485535"
|
||||
height="60.45842"
|
||||
width="12.091684"
|
||||
id="rect3159"
|
||||
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
|
||||
</g>
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-size:36.12366104px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Sans;-inkscape-font-specification:Sans Bold"
|
||||
x="52.018929"
|
||||
y="36.05489"
|
||||
id="text3167"
|
||||
sodipodi:linespacing="125%"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan3169"
|
||||
x="52.018929"
|
||||
y="36.05489">Play Tanks</tspan></text>
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-size:24px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Sans;-inkscape-font-specification:Sans"
|
||||
x="128"
|
||||
y="69"
|
||||
id="text3171"
|
||||
sodipodi:linespacing="125%"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan3173"
|
||||
x="128"
|
||||
y="69">essid: Tanks</tspan><tspan
|
||||
sodipodi:role="line"
|
||||
x="128"
|
||||
y="99"
|
||||
id="tspan3175">http://10.0.0.1/</tspan><tspan
|
||||
sodipodi:role="line"
|
||||
x="128"
|
||||
y="129"
|
||||
id="tspan3179">Token:</tspan></text>
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:100%;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Sans;-inkscape-font-specification:Sans"
|
||||
x="8"
|
||||
y="168"
|
||||
id="text3183"
|
||||
sodipodi:linespacing="100%"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan3185"
|
||||
x="8"
|
||||
y="168">a dirtbags production</tspan></text>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 5.3 KiB |
Loading…
Reference in New Issue