Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
emulab-devel
Project overview
Project overview
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
112
Issues
112
List
Boards
Labels
Milestones
Merge Requests
4
Merge Requests
4
Wiki
Wiki
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Commits
Issue Boards
Open sidebar
emulab
emulab-devel
Commits
36290a89
Commit
36290a89
authored
May 28, 2015
by
Leigh Stoller
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
More multisite changes; stats and history.
parent
9316dea7
Changes
7
Hide whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
225 additions
and
75 deletions
+225
-75
apt/APT_Instance.pm.in
apt/APT_Instance.pm.in
+44
-3
www/aptui/instance_defs.php
www/aptui/instance_defs.php
+8
-0
www/aptui/js/quickvm_sup.js
www/aptui/js/quickvm_sup.js
+31
-4
www/aptui/js/status.js
www/aptui/js/status.js
+48
-11
www/aptui/myexperiments.php
www/aptui/myexperiments.php
+44
-5
www/aptui/status.ajax
www/aptui/status.ajax
+38
-50
www/aptui/template/status.html
www/aptui/template/status.html
+12
-2
No files found.
apt/APT_Instance.pm.in
View file @
36290a89
...
...
@@ -453,6 +453,10 @@ sub RecordHistory($)
my
($
self
)
=
@
_
;
my
$
uuid
=
$
self
->
uuid
();
DBQueryWarn
(
"replace into apt_instance_aggregate_history "
.
"select * from apt_instance_aggregates where uuid='$uuid'"
)
or
return
-
1
;
DBQueryWarn
(
"replace into apt_instance_history "
.
"select uuid,name,profile_id,profile_version,slice_uuid, "
.
" creator,creator_idx,creator_uuid,pid,pid_idx, "
.
...
...
@@ -553,6 +557,9 @@ sub ComputeNodeCounts($)
print
STDERR
"Could not parse manifest for $sliver
\n
"
;
return
-
1
;
}
my
$
pcount
=
0
;
my
$
vcount
=
0
;
foreach
my
$
ref
(
GeniXML
::
FindNodes
(
"n:node"
,
$
manifest
)->
get_nodelist
())
{
my
$
virtualization_type
=
GeniXML
::
GetVirtualizationSubtype
($
ref
);
...
...
@@ -565,11 +572,17 @@ sub ComputeNodeCounts($)
if
(
defined
($
virtualization_type
)
&&
$
virtualization_type
eq
"emulab-xen"
)
{
$
v
irtnode_
count
++;
$
vcount
++;
next
;
}
$
p
hysnode_
count
++;
$
pcount
++;
}
$
sliver
->
Update
({
"physnode_count"
=>
$
pcount
,
"virtnode_count"
=>
$
vcount
})
==
0
or
return
-
1
;
$
physnode_count
+=
$
pcount
;
$
virtnode_count
+=
$
vcount
;
}
$
self
->
Update
({
"physnode_count"
=>
$
physnode_count
,
"virtnode_count"
=>
$
virtnode_count
})
...
...
@@ -731,7 +744,10 @@ sub instance($) { return $_[0]->{'INSTANCE'}; }
sub
GenTemp
($$)
{
my
($
class
,
$
instance
)
=
@
_
;
my
$
webtask
=
WebTask
->
Create
($
instance
->
uuid
());
my
$
webtask
=
WebTask
->
LookupByObject
($
instance
->
uuid
());
if
(
!defined($webtask)) {
$
webtask
=
WebTask
->
Create
($
instance
->
uuid
());
}
$
webtask
->
AutoStore
(
1
);
my
$
self
=
{};
...
...
@@ -870,6 +886,31 @@ sub Refresh($)
return
0
;
}
#
#
Perform
some
updates
...
#
sub
Update
($$)
{
my
($
self
,
$
argref
)
=
@
_
;
#
Must
be
a
real
reference
.
return
-
1
if
(
! ref($self));
my
$
uuid
=
$
self
->
uuid
();
my
$
urn
=
$
self
->
aggregate_urn
();
my
$
query
=
"update apt_instance_aggregates set "
.
join
(
","
,
map
(
"$_="
.
DBQuoteSpecial
($
argref
->{$
_
}),
keys
(%{$
argref
})));
$
query
.=
" where uuid='$uuid' and aggregate_urn='$urn'"
;
return
-
1
if
(
! DBQueryWarn($query));
return
Refresh
($
self
);
}
sub
SetStatus
($$)
{
my
($
self
,$
status
)
=
@
_
;
...
...
www/aptui/instance_defs.php
View file @
36290a89
...
...
@@ -109,6 +109,10 @@ class Instance
function
IsCloud
()
{
return
preg_match
(
'/cloudlab/'
,
$this
->
servername
());
}
function
aggregate_name
()
{
global
$urn_mapping
;
return
$urn_mapping
[
$this
->
aggregate_urn
()];
}
# Hmm, how does one cause an error in a php constructor?
function
IsValid
()
{
...
...
@@ -469,6 +473,10 @@ class InstanceSliver
function
public_url
()
{
return
$this
->
field
(
'public_url'
);
}
function
webtask_id
()
{
return
$this
->
field
(
'webtask_id'
);
}
function
manifest
()
{
return
$this
->
field
(
'manifest'
);
}
function
aggregate_name
()
{
global
$urn_mapping
;
return
$urn_mapping
[
$this
->
aggregate_urn
()];
}
# Hmm, how does one cause an error in a php constructor?
function
IsValid
()
{
...
...
www/aptui/js/quickvm_sup.js
View file @
36290a89
...
...
@@ -15,10 +15,10 @@ function HideModal(which)
function
CallServerMethod
(
url
,
route
,
method
,
args
)
{
if
(
url
==
null
)
{
url
=
'
https://
'
+
window
.
location
.
host
+
'
/apt/server-ajax.php
'
;
url
=
'
server-ajax.php
'
;
}
// ignore url now.
url
=
'
https://
'
+
window
.
location
.
host
+
'
/apt/server-ajax.php
'
;
url
=
'
server-ajax.php
'
;
if
(
args
==
null
)
{
args
=
{
"
noargs
"
:
"
noargs
"
};
}
...
...
@@ -47,6 +47,33 @@ var jacksOutput;
function
maketopmap
(
divname
,
xml
,
showinfo
,
withoutMultiSite
)
{
var
xmlDoc
=
$
.
parseXML
(
xml
);
var
xmlXML
=
$
(
xmlDoc
);
/*
* See how many sites. Do not use multiSite if no sites or
* only one site. Overrides the withoutMultiSite argument if set.
*/
var
sites
=
{};
$
(
xmlXML
).
find
(
"
node
"
).
each
(
function
()
{
var
JACKS_NS
=
"
http://www.protogeni.net/resources/rspec/ext/jacks/1
"
;
var
node_id
=
$
(
this
).
attr
(
"
client_id
"
);
var
site
=
this
.
getElementsByTagNameNS
(
JACKS_NS
,
'
site
'
);
if
(
!
site
.
length
)
{
return
;
}
var
siteid
=
$
(
site
).
attr
(
"
id
"
);
if
(
siteid
===
undefined
)
{
console
.
log
(
"
No site ID in
"
+
site
);
return
;
}
sites
[
siteid
]
=
siteid
;
});
if
(
Object
.
keys
(
sites
)
<=
1
)
{
withoutMultiSite
=
true
;
}
if
(
!
jacksInstance
)
{
jacksInstance
=
new
window
.
Jacks
({
...
...
www/aptui/js/status.js
View file @
36290a89
...
...
@@ -27,6 +27,7 @@ function (_, sup, moment, marked, UriTemplate, ShowImagingModal,
var
profile_uuid
=
null
;
var
extend
=
null
;
var
jacksIDs
=
{};
var
publicURLs
=
null
;
var
status_collapsed
=
false
;
var
status_message
=
""
;
var
statusTemplate
=
_
.
template
(
statusString
);
...
...
@@ -169,11 +170,6 @@ function (_, sup, moment, marked, UriTemplate, ShowImagingModal,
'
&snapuuid=
'
+
uuid
);
});
// If we got a publicURL, set the href and show the button.
if
(
window
.
APT_OPTIONS
.
publicURL
)
{
ShowSliverInfo
(
window
.
APT_OPTIONS
.
publicURL
);
}
//
// Attach a hover popover to explain what Clone means. We need
// the hover action delayed by our own code, since we want to
...
...
@@ -362,8 +358,8 @@ function (_, sup, moment, marked, UriTemplate, ShowImagingModal,
StatusWatchCallBack
.
active
=
1
;
}
// Ditto the publicURL.
if
(
_
.
has
(
json
.
value
,
"
publicURL
"
))
{
ShowSliverInfo
(
json
.
value
.
publicURL
);
if
(
_
.
has
(
json
.
value
,
"
sliverurls
"
))
{
ShowSliverInfo
(
json
.
value
.
sliverurls
);
}
if
(
status
==
'
provisioned
'
)
{
...
...
@@ -1181,7 +1177,7 @@ function (_, sup, moment, marked, UriTemplate, ShowImagingModal,
// Bind a function to start up ssh for one node topologies.
if
(
nodecount
==
1
&&
!
oneonly
&&
dossh
)
{
startOneSSH
=
function
()
{
var
nodename
=
hostportList
.
keys
(
)[
0
];
var
nodename
=
Object
.
keys
(
hostportList
)[
0
];
var
hostport
=
hostportList
[
nodename
];
NewSSHTab
(
hostport
,
nodename
);
};
...
...
@@ -1542,10 +1538,51 @@ function (_, sup, moment, marked, UriTemplate, ShowImagingModal,
}
}
function
ShowSliverInfo
(
url
)
function
ShowSliverInfo
(
url
s
)
{
$
(
"
#sliverinfo_button
"
).
attr
(
"
href
"
,
url
);
$
(
"
#sliverinfo_button
"
).
removeClass
(
"
hidden
"
);
if
(
!
publicURLs
)
{
$
(
'
#sliverinfo_dropdown
'
).
change
(
function
(
event
)
{
var
selected
=
$
(
'
#sliverinfo_dropdown select option:selected
'
).
val
();
console
.
info
(
selected
);
// Find the URL
_
.
each
(
publicURLs
,
function
(
obj
)
{
var
url
=
obj
.
url
;
var
name
=
obj
.
name
;
if
(
name
==
selected
)
{
$
(
"
#sliverinfo_dropdown a
"
).
attr
(
"
href
"
,
url
);
}
});
});
}
publicURLs
=
urls
;
if
(
urls
.
length
==
0
)
{
return
;
}
if
(
urls
.
length
==
1
)
{
$
(
"
#sliverinfo_button
"
).
attr
(
"
href
"
,
urls
[
0
].
url
);
$
(
"
#sliverinfo_button
"
).
removeClass
(
"
hidden
"
);
$
(
"
#sliverinfo_dropdown
"
).
addClass
(
"
hidden
"
);
return
;
}
// Selection list.
_
.
each
(
urls
,
function
(
obj
)
{
var
url
=
obj
.
url
;
var
name
=
obj
.
name
;
// Add only once of course
var
option
=
$
(
'
#sliverinfo_dropdown select option[value="
'
+
name
+
'
"]
'
);
if
(
!
option
.
length
)
{
$
(
"
#sliverinfo_dropdown select
"
).
append
(
"
<option value='
"
+
name
+
"
'>
"
+
name
+
"
</option>
"
);
}
});
$
(
"
#sliverinfo_button
"
).
addClass
(
"
hidden
"
);
$
(
"
#sliverinfo_dropdown
"
).
removeClass
(
"
hidden
"
);
}
$
(
document
).
ready
(
initialize
);
...
...
www/aptui/myexperiments.php
View file @
36290a89
...
...
@@ -73,8 +73,16 @@ if ($all && ISADMIN()) {
" UNIX_TIMESTAMP(s.expires)) as expired, "
.
" truncate(a.physnode_count * "
.
" ((UNIX_TIMESTAMP(now()) - "
.
" UNIX_TIMESTAMP(a.created)) / 3600.0),2) as phours "
.
" UNIX_TIMESTAMP(a.created)) / 3600.0),2) as phours, "
.
" IFNULL(aggs.count,0) as aggrows, "
.
" agg.aggregate_urn as aggrow_urn"
.
" from apt_instances as a "
.
"left join ("
.
" select uuid, COUNT(*) AS count "
.
" from apt_instance_aggregates group by uuid) AS aggs "
.
" on aggs.uuid=a.uuid "
.
"left join apt_instance_aggregates as agg "
.
" on agg.uuid=a.uuid "
.
"left join geni.geni_slices as s on "
.
" s.uuid=a.slice_uuid "
.
"left join geni.geni_users as u on u.uuid=a.creator_uuid "
.
...
...
@@ -87,8 +95,16 @@ else {
" UNIX_TIMESTAMP(s.expires)) as expired, "
.
" truncate(a.physnode_count * "
.
" ((UNIX_TIMESTAMP(now()) - "
.
" UNIX_TIMESTAMP(a.created)) / 3600.0),2) as phours "
.
" UNIX_TIMESTAMP(a.created)) / 3600.0),2) as phours, "
.
" IFNULL(aggs.count,0) as aggrows, "
.
" agg.aggregate_urn as aggrow_urn"
.
" from apt_instances as a "
.
"left join ("
.
" select uuid, COUNT(*) AS count "
.
" from apt_instance_aggregates group by uuid) AS aggs "
.
" on aggs.uuid=a.uuid "
.
"left join apt_instance_aggregates as agg "
.
" on agg.uuid=a.uuid "
.
"left join geni.geni_slices as s on "
.
" s.uuid=a.slice_uuid "
.
"left join geni.geni_users as u on u.uuid=a.creator_uuid "
.
...
...
@@ -100,8 +116,16 @@ else {
" UNIX_TIMESTAMP(s.expires)) as expired, "
.
" truncate(a.physnode_count * "
.
" ((UNIX_TIMESTAMP(now()) - "
.
" UNIX_TIMESTAMP(a.created)) / 3600.0),2) as phours "
.
" UNIX_TIMESTAMP(a.created)) / 3600.0),2) as phours, "
.
" IFNULL(aggs.count,0) as aggrows, "
.
" agg.aggregate_urn as aggrow_urn"
.
" from apt_instances as a "
.
"left join ("
.
" select uuid, COUNT(*) AS count "
.
" from apt_instance_aggregates group by uuid) AS aggs "
.
" on aggs.uuid=a.uuid "
.
"left join apt_instance_aggregates as agg "
.
" on agg.uuid=a.uuid "
.
"left join geni.geni_slices as s on "
.
" s.uuid=a.slice_uuid "
.
"left join geni.geni_users as u on u.uuid=a.creator_uuid "
.
...
...
@@ -152,8 +176,6 @@ function SPITROWS($all, $name, $result)
$profile_name
=
"
$profile_id
:
$version
"
;
$creator_uid
=
$row
[
"creator"
];
$pid
=
$row
[
"pid"
];
$urn
=
$row
[
"aggregate_urn"
];
$cluster
=
$urn_mapping
[
$urn
];
$pcount
=
$row
[
"physnode_count"
];
$vcount
=
$row
[
"virtnode_count"
];
$lockdown
=
$row
[
"admin_lockdown"
]
||
$row
[
"user_lockdown"
]
?
1
:
0
;
...
...
@@ -182,6 +204,23 @@ function SPITROWS($all, $name, $result)
if
(
!
isset
(
$name
))
{
$name
=
$hrn
;
}
#
# If arows non-zero, then we use that for aggregate_urn,
# and if its more then 1, we need to consume the extras rows
# to get the rest of the aggregate urns.
#
if
(
$row
[
"aggrows"
]
>
0
)
{
$cluster
=
$urn_mapping
[
$row
[
"aggrow_urn"
]];
for
(
$i
=
1
;
$i
<
$row
[
"aggrows"
];
$i
++
)
{
$row
=
mysql_fetch_array
(
$result
);
$cluster
.=
","
.
$urn_mapping
[
$row
[
"aggrow_urn"
]];
}
}
else
{
$cluster
=
$urn_mapping
[
$row
[
"aggregate_urn"
]];
}
echo
" <tr>
\n
"
;
echo
"<td><a href='status.php?uuid=
$uuid
'>
$name
</a></td>"
;
if
(
$profile
)
{
...
...
www/aptui/status.ajax
View file @
36290a89
...
...
@@ -118,8 +118,8 @@ function Do_GetInstanceStatus()
}
}
if
(
$sliver
->
public_url
())
{
$blob
[
"sliverurls"
][
$sliver
->
aggregate_urn
()]
=
$sliver
->
public_url
(
);
$blob
[
"sliverurls"
][
]
=
array
(
"name"
=>
$sliver
->
aggregate_name
(),
"url"
=>
$sliver
->
public_url
()
);
}
}
$blob
[
"havemanifests"
]
=
$havemanifests
;
...
...
@@ -509,15 +509,18 @@ function Do_ConsoleURL()
global
$instance
,
$creator
;
global
$ajax_args
;
if
(
StatusSetupAjax
(
1
))
{
return
;
}
if
(
!
isset
(
$this_user
))
{
SPITAJAX_ERROR
(
1
,
"Only registered users can reboot/reload nodes"
);
return
;
}
if
(
!
isset
(
$ajax_args
[
"node"
]))
{
SPITAJAX_ERROR
(
1
,
"Missing node argument"
);
return
1
;
}
$node
=
$ajax_args
[
"node"
];
if
(
StatusSetupAjax
(
1
))
{
return
;
}
$uuid
=
$instance
->
uuid
();
$slice
=
GeniSlice
::
Lookup
(
"sa"
,
$instance
->
slice_uuid
());
if
(
!
slice
)
{
...
...
@@ -556,21 +559,19 @@ function Do_ConsoleURL()
#
function
Do_Snapshot
()
{
global
$this_user
;
global
$this_user
,
$instance
;
global
$ajax_args
;
$this_idx
=
$this_user
->
uid_idx
();
if
(
!
isset
(
$ajax_args
[
"uuid"
]))
{
SPITAJAX_ERROR
(
1
,
"Missing profile uuid"
);
if
(
StatusSetupAjax
(
1
))
{
return
;
}
$uuid
=
$ajax_args
[
"uuid"
];
$instance
=
Instance
::
Lookup
(
$uuid
);
if
(
!
$instance
)
{
SPITAJAX_ERROR
(
1
,
"Unknown instance uuid"
);
if
(
!
isset
(
$this_user
))
{
SPITAJAX_ERROR
(
1
,
"Only registered users can snapshot nodes"
);
return
;
}
$this_idx
=
$this_user
->
uid_idx
();
$uuid
=
$ajax_args
[
"uuid"
];
if
(
$this_idx
!=
$instance
->
creator_idx
()
&&
!
ISADMIN
())
{
SPITAJAX_ERROR
(
1
,
"Not enough permission. Maybe Clone instead?"
);
return
;
...
...
@@ -650,20 +651,18 @@ function Do_Snapshot()
#
function
Do_SnapshotStatus
()
{
global
$this_user
;
global
$this_user
,
$instance
;
global
$ajax_args
;
$this_idx
=
$this_user
->
uid_idx
();
if
(
!
isset
(
$ajax_args
[
"uuid"
]))
{
SPITAJAX_ERROR
(
1
,
"Missing profile uuid"
);
if
(
StatusSetupAjax
(
1
))
{
return
;
}
$instance
=
Instance
::
Lookup
(
$ajax_args
[
"uuid"
]);
if
(
!
$instance
)
{
SPITAJAX_ERROR
(
1
,
"Unknown instance uuid"
);
if
(
!
isset
(
$this_user
))
{
SPITAJAX_ERROR
(
1
,
"Only registered users can snapshot nodes"
);
return
;
}
$this_idx
=
$this_user
->
uid_idx
();
if
(
$this_idx
!=
$instance
->
creator_idx
()
&&
!
ISADMIN
())
{
SPITAJAX_ERROR
(
1
,
"Not enough permission"
);
return
;
...
...
@@ -704,21 +703,17 @@ function Do_SnapshotStatus()
#
function
Do_Refresh
()
{
global
$this_user
;
global
$this_user
,
$instance
;
global
$ajax_args
;
$this_idx
=
$this_user
->
uid_idx
();
if
(
!
isset
(
$ajax_args
[
"uuid"
]))
{
SPITAJAX_ERROR
(
1
,
"Missing profile uuid"
);
#
# Guest users can do this.
#
if
(
StatusSetupAjax
(
1
))
{
return
;
}
$this_idx
=
$this_user
->
uid_idx
();
$uuid
=
$ajax_args
[
"uuid"
];
$instance
=
Instance
::
Lookup
(
$uuid
);
if
(
!
$instance
)
{
SPITAJAX_ERROR
(
1
,
"Unknown instance uuid"
);
return
;
}
if
(
$this_idx
!=
$instance
->
creator_idx
()
&&
!
ISADMIN
())
{
SPITAJAX_ERROR
(
1
,
"Not enough permission. Maybe Clone instead?"
);
return
;
...
...
@@ -727,7 +722,7 @@ function Do_Refresh()
# Call out to the backend.
#
$webtask_id
=
WebTask
::
GenerateID
();
$retval
=
SUEXEC
(
$this_user
->
uid
()
,
"nobody"
,
$retval
=
SUEXEC
(
"nobody"
,
"nobody"
,
"webmanage_instance -t
$webtask_id
-- refresh
$uuid
"
,
SUEXEC_ACTION_IGNORE
);
$webtask
=
WebTask
::
Lookup
(
$webtask_id
);
...
...
@@ -757,14 +752,18 @@ function Do_Refresh()
#
function
Do_RebootOrReload
(
$which
)
{
global
$this_user
;
global
$this_user
,
$instance
;
global
$ajax_args
;
if
(
StatusSetupAjax
(
1
))
{
return
;
}
if
(
!
isset
(
$this_user
))
{
SPITAJAX_ERROR
(
1
,
"Only registered users can reboot/reload nodes"
);
return
;
}
$this_idx
=
$this_user
->
uid_idx
();
$uuid
=
$ajax_args
[
"uuid"
];
if
(
!
isset
(
$ajax_args
[
"node_id"
]))
{
SPITAJAX_ERROR
(
1
,
"Missing node_id"
);
...
...
@@ -774,17 +773,6 @@ function Do_RebootOrReload($which)
if
(
!
preg_match
(
"/^[-\w]+$/"
,
$node_id
))
{
SPITAJAX_ERROR
(
1
,
"Illegal characters in node_id"
);
}
if
(
!
isset
(
$ajax_args
[
"uuid"
]))
{
SPITAJAX_ERROR
(
1
,
"Missing profile uuid"
);
return
;
}
$uuid
=
$ajax_args
[
"uuid"
];
$instance
=
Instance
::
Lookup
(
$uuid
);
if
(
!
$instance
)
{
SPITAJAX_ERROR
(
1
,
"Unknown instance uuid"
);
return
;
}
if
(
$this_idx
!=
$instance
->
creator_idx
()
&&
!
ISADMIN
())
{
SPITAJAX_ERROR
(
1
,
"Not enough permission. Maybe Clone instead?"
);
return
;
...
...
@@ -843,6 +831,10 @@ function Do_Lockout()
global
$this_user
;
global
$ajax_args
;
if
(
!
isset
(
$this_user
)
||
!
ISADMIN
())
{
SPITAJAX_ERROR
(
1
,
"Not enough permission."
);
return
;
}
$this_idx
=
$this_user
->
uid_idx
();
if
(
!
isset
(
$ajax_args
[
"uuid"
]))
{
...
...
@@ -859,10 +851,6 @@ function Do_Lockout()
SPITAJAX_ERROR
(
1
,
"Unknown instance uuid"
);
return
;
}
if
(
!
ISADMIN
())
{
SPITAJAX_ERROR
(
1
,
"Not enough permission."
);
return
;
}
$lockout
=
(
$ajax_args
[
"lockout"
]
?
1
:
0
);
if
(
!
DBQueryWarn
(
"update apt_instances set extension_adminonly='
$lockout
' "
.
"where uuid='
$uuid
'"
))
{
...
...
www/aptui/template/status.html
View file @
36290a89
...
...
@@ -74,8 +74,18 @@
style=
'margin-right: 10px;'
id=
'sliverinfo_button'
href=
'#'
type=
'button'
>
Sliver
</a>
target=
'_blank'
type=
'button'
>
Sliver
</a>
<div
id=
'sliverinfo_dropdown'
class=
'hidden'
>
<select
style=
'margin-right: 0px;'
>
<option
value=
'selectme'
>
Slivers
</option>
</select>
<a
class=
'btn btn-info btn-tiny'
style=
'margin-right: 10px;'
href=
'#'
target=
'_blank'
type=
'button'
>
Go
</a>
</div>
</div>
<
%
if
(
isadmin
)
{
%
>
<div
class=
'pull-left'
...
...
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