Skip to content
GitLab
Menu
Projects
Groups
Snippets
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Menu
Open sidebar
emulab
emulab-devel
Commits
c6395734
Commit
c6395734
authored
Mar 22, 2014
by
Leigh B Stoller
Browse files
Mostly a big clean up, moving code out of the old sup file,
and into the js files associated with the code.
parent
81642ef0
Changes
13
Hide whitespace changes
Inline
Side-by-side
www/aptui/instantiate.php
View file @
c6395734
...
...
@@ -56,6 +56,14 @@ $optargs = OptionalPageArguments("create", PAGEARG_STRING,
#
if
(
isset
(
$ajax_request
))
{
if
(
$ajax_method
==
"getprofile"
)
{
#
# We require the UUID on this path, until proper permission
# checks are done; too easy to guess an index.
#
if
(
!
IsValidUUID
(
$ajax_argument
))
{
SPITAJAX_ERROR
(
1
,
"Not a valid UUID:
$ajax_argument
"
);
exit
();
}
$obj
=
Profile
::
Lookup
(
$ajax_argument
);
if
(
!
$obj
)
{
SPITAJAX_ERROR
(
1
,
"No such profile
$ajax_argument
"
);
...
...
@@ -80,25 +88,42 @@ $profile_array = array();
# add to the array now since it might not be public or belong to the user.
#
if
(
isset
(
$profile
))
{
if
(
preg_match
(
"/^\w+\-\w+\-\w+\-\w+\-\w+$/"
,
$profile
))
{
$obj
=
Profile
::
Lookup
(
$profile
);
if
(
!
$obj
)
{
SPITHEADER
(
1
);
SPITUSERERROR
(
"No such profile:
$profile
"
);
echo
"<script src='js/lib/require.js' data-main='js/null'>
</script>
\n
"
;
SPITFOOTER
();
}
#
# Guest users must use the uuid, but logged in users may use the
# internal index.
#
if
(
!
(
$this_user
||
IsValidUUID
(
$profile
)))
{
SPITUSERERROR
(
"Illegal profile for guest user:
$profile
"
);
exit
();
}
$obj
=
Profile
::
Lookup
(
$profile
);
if
(
!
$obj
)
{
SPITUSERERROR
(
"No such profile:
$profile
"
);
exit
();
}
if
(
IsValidUUID
(
$profile
))
{
$profile_array
[
$profile
]
=
$obj
->
name
();
$profilename
=
$obj
->
name
();
}
else
{
$profilename
=
$profile
;
#
# Must be public or belong to user.
#
if
(
!
(
$obj
->
ispublic
()
||
$obj
->
creator_idx
==
$this_user
->
uid_idx
()))
{
SPITUSERERROR
(
"No permission to use profile:
$profile
"
);
exit
();
}
$profile
=
$obj
->
uuid
();
$profile_array
[
$profile
]
=
$obj
->
name
();
$profilename
=
$obj
->
name
();
}
}
#
# Still do this cause of non-secret URLs. This needs more work.
# Find all the public and user profiles. We use the UUID instead of
# indicies cause we do not want to leak internal DB state to guest
# users.
#
$query_result
=
DBQueryFatal
(
"select * from apt_profiles "
.
...
...
www/aptui/js/instantiate.js
View file @
c6395734
...
...
@@ -10,14 +10,14 @@ function ($, sup)
function
initialize
()
{
window
.
APT_OPTIONS
.
initialize
(
sup
);
sup
.
UpdateProfileSelection
(
$
(
'
#profile_name li[value =
'
+
window
.
PROFILE
+
'
]
'
));
$
(
'
#quickvm_topomodal
'
).
on
(
'
hidden.bs.modal
'
,
function
()
{
sup
.
ShowProfileList
(
$
(
'
.current
'
))
ShowProfileList
(
$
(
'
.current
'
))
});
$
(
'
button#reset-form
'
).
click
(
function
(
event
)
{
event
.
preventDefault
();
sup
.
resetForm
(
$
(
'
#quickvm_form
'
));
resetForm
(
$
(
'
#quickvm_form
'
));
});
$
(
'
button#profile
'
).
click
(
function
(
event
)
{
event
.
preventDefault
();
...
...
@@ -25,13 +25,92 @@ function ($, sup)
});
$
(
'
li.profile-item
'
).
click
(
function
(
event
)
{
event
.
preventDefault
();
sup
.
ShowProfileList
(
event
.
target
);
ShowProfileList
(
event
.
target
);
});
$
(
'
button#showtopo_select
'
).
click
(
function
(
event
)
{
event
.
preventDefault
();
sup
.
UpdateProfileSelection
(
$
(
'
.selected
'
));
UpdateProfileSelection
(
$
(
'
.selected
'
));
sup
.
HideModal
(
'
#quickvm_topomodal
'
);
});
UpdateProfileSelection
(
$
(
'
#profile_name li[value =
'
+
window
.
PROFILE
+
'
]
'
));
}
function
resetForm
(
$form
)
{
$form
.
find
(
'
input:text, input:password, select, textarea
'
).
val
(
''
);
}
function
UpdateProfileSelection
(
selectedElement
)
{
var
profile_name
=
$
(
selectedElement
).
text
();
var
profile_value
=
$
(
selectedElement
).
attr
(
'
value
'
);
$
(
'
#selected_profile
'
).
attr
(
'
value
'
,
profile_value
);
$
(
'
#selected_profile_text
'
).
html
(
""
+
profile_name
);
if
(
!
$
(
selectedElement
).
hasClass
(
'
current
'
))
{
$
(
'
#profile_name li
'
).
each
(
function
()
{
$
(
this
).
removeClass
(
'
current
'
);
});
$
(
selectedElement
).
addClass
(
'
current
'
);
}
ShowProfileList
(
selectedElement
);
}
function
ShowProfileList
(
selectedElement
)
{
var
profile
=
$
(
selectedElement
).
attr
(
'
value
'
);
if
(
!
$
(
selectedElement
).
hasClass
(
'
selected
'
))
{
$
(
'
#profile_name li
'
).
each
(
function
()
{
$
(
this
).
removeClass
(
'
selected
'
);
});
$
(
selectedElement
).
addClass
(
'
selected
'
);
}
var
callback
=
function
(
json
)
{
console
.
info
(
json
.
value
);
if
(
json
.
code
)
{
alert
(
"
Could not get profile:
"
+
json
.
value
);
return
;
}
var
xmlDoc
=
$
.
parseXML
(
json
.
value
.
rspec
);
var
xml
=
$
(
xmlDoc
);
var
topo
=
sup
.
ConvertManifestToJSON
(
profile
,
xml
);
$
(
'
#showtopo_title
'
).
html
(
"
<h3>
"
+
json
.
value
.
name
+
"
</h3>
"
);
/*
* We now use the desciption from inside the rspec, unless there
* is none, in which case look to see if the we got one in the
* rpc reply, which we will until all profiles converted over to
* new format rspecs.
*/
var
description
=
null
;
$
(
xml
).
find
(
"
rspec_tour
"
).
each
(
function
()
{
$
(
this
).
find
(
"
description
"
).
each
(
function
()
{
description
=
$
(
this
).
text
();
});
});
if
(
!
description
)
{
if
(
json
.
value
.
description
!=
""
)
{
description
=
json
.
value
.
description
;
}
else
{
description
=
"
Hmm, no description for this profile
"
;
}
}
$
(
'
#showtopo_description
'
).
html
(
description
);
$
(
'
#selected_profile_description
'
).
html
(
description
);
sup
.
maketopmap
(
"
#showtopo_div
"
,
(
$
(
"
#showtopo_div
"
).
outerWidth
()),
300
,
topo
,
null
);
}
var
$xmlthing
=
sup
.
CallMethod
(
"
getprofile
"
,
null
,
0
,
profile
);
$xmlthing
.
done
(
callback
);
}
$
(
document
).
ready
(
initialize
);
...
...
www/aptui/js/manage_profile.js
View file @
c6395734
...
...
@@ -39,7 +39,6 @@ function ($, sup)
$
(
'
#profile_rspec_textarea
'
).
val
(
content
);
ExtractFromRspec
(
xml
);
//ShowRspecTopo(xml);
};
reader
.
readAsText
(
this
.
files
[
0
]);
});
...
...
@@ -205,9 +204,10 @@ function ($, sup)
removeLast
:
true
},
columns
:
[
{
name
:
'
Type
'
,
display
:
'
Type
'
,
type
:
'
tex
t
'
,
{
name
:
'
Type
'
,
display
:
'
Type
'
,
type
:
'
selec
t
'
,
ctrlAttr
:
{
maxlength
:
100
},
ctrlCss
:
{
width
:
'
80px
'
}
ctrlCss
:
{
width
:
'
80px
'
},
ctrlOptions
:
[
"
node
"
,
"
link
"
],
},
{
name
:
'
ID
'
,
display
:
'
ID
'
,
type
:
'
text
'
,
ctrlAttr
:
{
maxlength
:
100
,
...
...
@@ -221,6 +221,9 @@ function ($, sup)
initData
:
steps
});
});
// Show the steps area.
$
(
'
#profile_steps_div
'
).
removeClass
(
"
hidden
"
);
}
//
...
...
@@ -376,7 +379,7 @@ function ($, sup)
// Subtract -2 cause of the border.
sup
.
maketopmap
(
"
#showtopo_nopicker
"
,
(
$
(
"
#showtopo_nopicker
"
).
outerWidth
()
-
2
),
300
,
topo
);
300
,
topo
,
null
);
}
$
(
document
).
ready
(
initialize
);
...
...
www/aptui/js/myprofiles.js
View file @
c6395734
...
...
@@ -63,7 +63,7 @@ function ($, sup)
// Subtract -2 cause of the border.
sup
.
maketopmap
(
"
#showtopo_nopicker
"
,
(
$
(
"
#showtopo_nopicker
"
).
outerWidth
()
-
2
),
300
,
topo
);
300
,
topo
,
null
);
};
var
$xmlthing
=
sup
.
CallMethod
(
"
getprofile
"
,
null
,
0
,
profile
);
$xmlthing
.
done
(
callback
);
...
...
www/aptui/js/quickvm_sup.js
View file @
c6395734
define
([
'
jquery
'
,
'
d3
'
,
'
dateformat
'
,
'
marked
'
],
function
(
$
,
d3
)
{
var
myuuid
=
null
;
function
ShowModal
(
which
)
{
// console.log('Showing modal ' + which);
...
...
@@ -37,606 +35,13 @@ function CallMethod(method, callback, uuid, arg)
});
}
function
GetStatus
(
uuid
)
{
var
callback
=
function
(
json
)
{
StatusWatchCallBack
(
uuid
,
json
);
}
var
$xmlthing
=
CallMethod
(
"
status
"
,
null
,
uuid
,
null
);
$xmlthing
.
done
(
callback
);
}
// Set up a timer to watch the status.
function
StartStatusWatch
(
uuid
)
{
setTimeout
(
function
f
()
{
GetStatus
(
uuid
)
},
5000
);
}
// Call back for above.
function
StatusWatchCallBack
(
uuid
,
json
)
{
// Check to see if the static variable has been initialized
if
(
typeof
StatusWatchCallBack
.
laststatus
==
'
undefined
'
)
{
// It has not... perform the initilization
StatusWatchCallBack
.
laststatus
=
""
;
}
var
status
=
json
.
value
;
if
(
json
.
code
)
{
status
=
"
terminated
"
;
}
if
(
status
!=
StatusWatchCallBack
.
laststatus
)
{
status_html
=
status
;
var
bgtype
=
""
;
var
statustext
=
"
Please wait while we get your experiment ready
"
;
if
(
status
==
'
provisioned
'
)
{
$
(
"
#quickvm_progress_bar
"
).
width
(
"
66%
"
);
}
else
if
(
status
==
'
ready
'
)
{
bgtype
=
"
bg-success
"
;
statustext
=
"
Your experiment is ready!
"
;
status_html
=
"
<font color=green>ready</font>
"
;
if
(
$
(
"
#quickvm_progress
"
).
length
)
{
$
(
"
#quickvm_progress
"
).
removeClass
(
"
progress-striped
"
);
$
(
"
#quickvm_progress
"
).
removeClass
(
"
active
"
);
$
(
"
#quickvm_progress
"
).
addClass
(
"
progress-bar-success
"
);
$
(
"
#quickvm_progress_bar
"
).
width
(
"
100%
"
);
}
$
(
"
#terminate_button
"
).
prop
(
"
disabled
"
,
false
);
$
(
"
#extend_button
"
).
prop
(
"
disabled
"
,
false
);
ShowTopo
(
uuid
);
}
else
if
(
status
==
'
failed
'
)
{
bgtype
=
"
bg-danger
"
;
statustext
=
"
Something went wrong, sorry! We've been notified.
"
;
status_html
=
"
<font color=red>failed</font>
"
;
if
(
$
(
"
#quickvm_progress
"
).
length
)
{
$
(
"
#quickvm_progress
"
).
removeClass
(
"
progress-striped
"
);
$
(
"
#quickvm_progress
"
).
removeClass
(
"
active
"
);
$
(
"
#quickvm_progress
"
).
addClass
(
"
progress-bar-danger
"
);
$
(
"
#quickvm_progress_bar
"
).
width
(
"
100%
"
);
}
$
(
"
#terminate_button
"
).
prop
(
"
disabled
"
,
false
);
}
else
if
(
status
==
'
terminating
'
||
status
==
'
terminated
'
)
{
status_html
=
"
<font color=red>
"
+
status
+
"
</font>
"
;
$
(
"
#terminate_button
"
).
prop
(
"
disabled
"
,
true
);
$
(
"
#extend_button
"
).
prop
(
"
disabled
"
,
true
);
StartCountdownClock
.
stop
=
0
;
}
$
(
"
#statusmessage
"
).
html
(
statustext
);
$
(
"
#statusmessage-container
"
)
.
removeClass
(
'
bg-success bg-danger
'
)
.
addClass
(
bgtype
);
$
(
"
#quickvm_status
"
).
html
(
status_html
);
}
StatusWatchCallBack
.
laststatus
=
status
;
if
(
!
(
status
==
'
terminating
'
||
status
==
'
terminated
'
))
{
setTimeout
(
function
f
()
{
GetStatus
(
uuid
)
},
5000
);
}
}
function
Terminate
(
uuid
,
url
)
{
var
callback
=
function
(
json
)
{
window
.
location
.
replace
(
url
);
}
$
(
"
#terminate_button
"
).
prop
(
"
disabled
"
,
true
);
$
(
"
#extend_button
"
).
prop
(
"
disabled
"
,
true
);
HideModal
(
'
#terminate_modal
'
);
var
$xmlthing
=
CallMethod
(
"
terminate
"
,
null
,
uuid
,
null
);
$xmlthing
.
done
(
callback
);
}
function
ShowTopo
(
uuid
)
{
var
callback
=
function
(
json
)
{
console
.
info
(
json
.
value
);
var
xmlDoc
=
$
.
parseXML
(
json
.
value
);
var
xml
=
$
(
xmlDoc
);
var
topo
=
ConvertManifestToJSON
(
null
,
xml
);
console
.
info
(
json
.
value
);
// Suck the instructions out of the tour and put them into
// the Usage area.
$
(
xml
).
find
(
"
rspec_tour
"
).
each
(
function
()
{
$
(
this
).
find
(
"
instructions
"
).
each
(
function
()
{
var
marked
=
require
(
'
marked
'
);
marked
.
setOptions
({
"
sanitize
"
:
true
});
var
text
=
$
(
this
).
text
();
// Stick the text in
$
(
'
#instructions_text
'
).
html
(
marked
(
text
));
// Make the div visible.
$
(
'
#instructions_panel
'
).
removeClass
(
"
invisible
"
);
});
});
// Find all of the nodes, and put them into the list tab.
// Clear current table.
$
(
'
#listview_table > tbody
'
).
html
(
""
);
$
(
xml
).
find
(
"
node
"
).
each
(
function
()
{
var
node
=
$
(
this
).
attr
(
"
client_id
"
);
var
login
=
$
(
this
).
find
(
"
login
"
);
var
href
=
"
n/a
"
;
var
ssh
=
"
n/a
"
;
if
(
login
.
length
)
{
var
user
=
login
.
attr
(
"
username
"
);
var
host
=
login
.
attr
(
"
hostname
"
);
var
port
=
login
.
attr
(
"
port
"
);
var
url
=
"
ssh://
"
+
user
+
"
@
"
+
host
+
"
:
"
+
port
+
"
/
"
;
href
=
"
<a href='
"
+
url
+
"
'>
"
+
url
+
"
</a>
"
;
console
.
info
(
url
);
var
hostport
=
host
+
"
:
"
+
port
;
ssh
=
"
<button class='btn btn-primary btn-xs'
"
+
"
id='
"
+
"
sshbutton_
"
+
node
+
"
'
"
+
"
type='button'>
"
+
"
<span class='glyphicon glyphicon-log-in'><span>
"
+
"
</button>
"
;
console
.
info
(
ssh
);
// Use this to attach handlers to things that do not exist.
$
(
'
#listview_table
'
).
off
(
'
click
'
,
'
#sshbutton_
'
+
node
);
$
(
'
#listview_table
'
).
on
(
'
click
'
,
'
#sshbutton_
'
+
node
,
function
()
{
NewSSHTab
(
hostport
,
node
);
});
}
$
(
'
#listview_table > tbody:last
'
).
append
(
'
<tr><td>
'
+
node
+
'
</td><td>
'
+
ssh
+
'
</td><td>
'
+
href
+
'
</td></tr>
'
);
});
$
(
"
#showtopo_container
"
).
removeClass
(
"
invisible
"
);
// Subtract -2 cause of the border.
maketopmap
(
"
#showtopo_statuspage
"
,
$
(
"
#showtopo_statuspage
"
).
outerWidth
()
-
2
,
300
,
topo
);
}
console
.
info
(
uuid
);
var
$xmlthing
=
CallMethod
(
"
manifest
"
,
null
,
uuid
,
null
);
$xmlthing
.
done
(
callback
);
}
function
UpdateProfileSelection
(
selectedElement
)
{
var
profile_name
=
$
(
selectedElement
).
text
();
var
profile_value
=
$
(
selectedElement
).
attr
(
'
value
'
);
$
(
'
#selected_profile
'
).
attr
(
'
value
'
,
profile_value
);
$
(
'
#selected_profile_text
'
).
html
(
""
+
profile_name
);
if
(
!
$
(
selectedElement
).
hasClass
(
'
current
'
))
{
$
(
'
#profile_name li
'
).
each
(
function
()
{
$
(
this
).
removeClass
(
'
current
'
);
});
$
(
selectedElement
).
addClass
(
'
current
'
);
}
ShowProfileList
(
selectedElement
);
}
function
ShowProfileList
(
selectedElement
)
{
var
profile
=
$
(
selectedElement
).
attr
(
'
value
'
);
if
(
!
$
(
selectedElement
).
hasClass
(
'
selected
'
))
{
$
(
'
#profile_name li
'
).
each
(
function
()
{
$
(
this
).
removeClass
(
'
selected
'
);
});
$
(
selectedElement
).
addClass
(
'
selected
'
);
}
var
callback
=
function
(
json
)
{
console
.
info
(
json
.
value
);
if
(
json
.
code
)
{
alert
(
"
Could not get profile:
"
+
json
.
value
);
return
;
}
var
xmlDoc
=
$
.
parseXML
(
json
.
value
.
rspec
);
var
xml
=
$
(
xmlDoc
);
var
topo
=
ConvertManifestToJSON
(
profile
,
xml
);
$
(
'
#showtopo_title
'
).
html
(
"
<h3>
"
+
json
.
value
.
name
+
"
</h3>
"
);
/*
* We now use the desciption from inside the rspec, unless there
* is none, in which case look to see if the we got one in the
* rpc reply, which we will until all profiles converted over to
* new format rspecs.
*/
var
description
=
null
;
$
(
xml
).
find
(
"
rspec_tour
"
).
each
(
function
()
{
$
(
this
).
find
(
"
description
"
).
each
(
function
()
{
description
=
$
(
this
).
text
();
});
});
if
(
!
description
)
{
if
(
json
.
value
.
description
!=
""
)
{
description
=
json
.
value
.
description
;
}
else
{
description
=
"
Hmm, no description for this profile
"
;
}
}
$
(
'
#showtopo_description
'
).
html
(
description
);
$
(
'
#selected_profile_description
'
).
html
(
description
);
maketopmap
(
"
#showtopo_div
"
,
(
$
(
"
#showtopo_div
"
).
outerWidth
()),
300
,
topo
);
}
var
$xmlthing
=
CallMethod
(
"
getprofile
"
,
null
,
0
,
profile
);
$xmlthing
.
done
(
callback
);
}
function
Setsshurl
(
uuid
)
{
var
callback
=
function
(
json
)
{
var
xmlDoc
=
$
.
parseXML
(
json
.
value
);
var
xml
=
$
(
xmlDoc
);
var
login
=
$
(
xml
).
find
(
"
login
"
);
var
user
=
login
.
attr
(
"
username
"
);
var
host
=
login
.
attr
(
"
hostname
"
);
var
port
=
login
.
attr
(
"
port
"
);
var
url
=
"
ssh://
"
+
user
+
"
@
"
+
host
+
"
:
"
+
port
+
"
/
"
;
var
href
=
"
<a href='
"
+
url
+
"
'>
"
+
url
+
"
</a>
"
;
console
.
info
(
url
);
$
(
"
#quickvm_sshurl
"
).
html
(
href
);
}
var
$xmlthing
=
CallMethod
(
"
manifest
"
,
null
,
uuid
,
null
);
$xmlthing
.
done
(
callback
);
}
//
// Request experiment extension.
//
function
RequestExtension
(
uuid
)
{
var
reason
=
$
(
"
#why_extend
"
).
val
();
console
.
info
(
reason
);
if
(
reason
.
length
<
30
)
{
alert
(
"
Your reason is too short! Say more please.
"
);
return
;
}
var
callback
=
function
(
json
)
{
console
.
info
(
json
.
value
);
if
(
json
.
code
)
{
if
(
json
.
code
<
0
)
{
alert
(
"
Could not extend experiment. Please try again later
"
);
}
else
{
alert
(
"
Could not extend experiment:
"
+
json
.
value
);
}
return
;
}
$
(
"
#quickvm_expires
"
).
html
(
json
.
value
);
// Reset the countdown clock.
StartCountdownClock
.
reset
=
json
.
value
;
}
var
$xmlthing
=
CallMethod
(
"
request_extension
"
,
null
,
uuid
,
reason
);
HideModal
(
'
#extend_modal
'
);
$xmlthing
.
done
(
callback
);
}
function
Extend
(
uuid
)
{
var
code
=
$
(
"
#extend_code
"
).
val
();
console
.
info
(
code
);
if
(
code
==
""
)
{
return
;
}
var
callback
=
function
(
json
)
{
console
.
info
(
json
.
value
);
}
var
$xmlthing
=
CallMethod
(
"
extend
"
,
null
,
uuid
,
code
);
HideModal
(
'
#extend_modal
'
);
$xmlthing
.
done
(
callback
);
}
//
// Open up a window to the account registration page.
//
function
RegisterAccount
(
uid
,
email
)
{
HideModal
(
'
#register_modal
'
);
var
url
=
"
signup.php?uid=
"
+
uid
+
"
&email=
"
+
email
+
""
;
var
win
=
window
.
open
(
url
,
'
_blank
'
);
win
.
focus
();
}
function
InitQuickVM
(
uuid
,
slice_expires
)
{
// Use an unload event to terminate any shells.
$
(
window
).
bind
(
"
unload
"
,
function
()
{
console
.
info
(
"
Unload function called
"
);
$
(
'
#quicktabs_content div
'
).
each
(
function
()
{
var
$this
=
$
(
this
);
// Skip the main profile tab
if
(
$this
.
attr
(
"
id
"
)
==
"
profile
"
)
{
return
;
}
var
tabname
=
$this
.
attr
(
"
id
"
);
// Trigger the custom event.
$
(
"
#
"
+
tabname
).
trigger
(
"
killssh
"
);
});
});
$
(
window
).
bind
(
"
beforeunload
"
,
function
()
{
console
.
info
(
"
BeforeUnload function called
"
);
});
$
(
window
).
bind
(
"
pagehide
"
,
function
()
{
console
.
info
(
"
Pagehide function called
"
);
});
StartCountdownClock
(
slice_expires
);
GetStatus
(
uuid
);
myuuid
=
uuid
;
}
function
resetForm
(
$form
)
{
$form
.
find
(
'
input:text, input:password, select, textarea
'
).
val
(
''
);
}
function
StartSSH
(
id
,
authobject
)
{
var
jsonauth
=
$
.
parseJSON
(
authobject
);
var
callback
=
function
(
stuff
)
{
var
split
=
stuff
.
split
(
'
:
'
);