Commit 2c6955fa authored by Dan Pascu's avatar Dan Pascu

Refactored session info panel

parent 99163a70
...@@ -7,7 +7,7 @@ import os ...@@ -7,7 +7,7 @@ import os
from PyQt4 import uic from PyQt4 import uic
from PyQt4.QtCore import Qt, QEasingCurve, QEvent, QPointF, QPropertyAnimation, QRect, QSettings, QTimer, pyqtSignal from PyQt4.QtCore import Qt, QEasingCurve, QEvent, QPointF, QPropertyAnimation, QRect, QSettings, QTimer, pyqtSignal
from PyQt4.QtGui import QAction, QBrush, QColor, QIcon, QLabel, QLinearGradient, QListView, QMenu, QPainter, QPalette, QPen, QPolygonF, QTextCursor, QTextDocument, QTextEdit from PyQt4.QtGui import QAction, QBrush, QColor, QIcon, QLabel, QLinearGradient, QListView, QMenu, QPainter, QPalette, QPen, QPixmap, QPolygonF, QTextCursor, QTextDocument, QTextEdit
from PyQt4.QtGui import QApplication, QDesktopServices from PyQt4.QtGui import QApplication, QDesktopServices
from PyQt4.QtWebKit import QWebPage, QWebSettings, QWebView from PyQt4.QtWebKit import QWebPage, QWebSettings, QWebView
...@@ -714,6 +714,10 @@ class ChatWindow(base_class, ui_class, ColorHelperMixin): ...@@ -714,6 +714,10 @@ class ChatWindow(base_class, ui_class, ColorHelperMixin):
self.lock_grey_icon = QIcon(Resources.get('icons/lock-grey-12.svg')) self.lock_grey_icon = QIcon(Resources.get('icons/lock-grey-12.svg'))
self.lock_green_icon = QIcon(Resources.get('icons/lock-green-12.svg')) self.lock_green_icon = QIcon(Resources.get('icons/lock-green-12.svg'))
self.direct_connection_pixmap = QPixmap(Resources.get('icons/connection-direct.svg'))
self.relay_connection_pixmap = QPixmap(Resources.get('icons/connection-relay.svg'))
self.unknown_connection_pixmap = QPixmap(Resources.get('icons/connection-unknown.svg'))
# fix the SVG icons as the generated code loads them as pixmaps, losing their ability to scale -Dan # fix the SVG icons as the generated code loads them as pixmaps, losing their ability to scale -Dan
def svg_icon(filename_off, filename_on): def svg_icon(filename_off, filename_on):
icon = QIcon() icon = QIcon()
...@@ -877,22 +881,16 @@ class ChatWindow(base_class, ui_class, ColorHelperMixin): ...@@ -877,22 +881,16 @@ class ChatWindow(base_class, ui_class, ColorHelperMixin):
def _update_session_info_panel(self, elements={}, update_visibility=False): def _update_session_info_panel(self, elements={}, update_visibility=False):
blink_session = self.selected_session.blink_session blink_session = self.selected_session.blink_session
have_session = blink_session.state in ('connecting/*', 'connected/*', 'ending') have_session = blink_session.state in ('connecting/*', 'connected/*', 'ending')
have_audio = 'audio' in blink_session.streams
have_chat = 'chat' in blink_session.streams
have_screen = 'screen-sharing' in blink_session.streams
if update_visibility: if update_visibility:
self.status_value_label.setEnabled(have_session) self.status_value_label.setEnabled(have_session)
self.duration_value_label.setEnabled(have_session) self.duration_value_label.setEnabled(have_session)
self.account_value_label.setEnabled(have_session) self.account_value_label.setEnabled(have_session)
self.remote_agent_value_label.setEnabled(have_session) self.remote_agent_value_label.setEnabled(have_session)
self.sip_addresses_value_label.setEnabled(have_session) self.sip_address_value_label.setEnabled(have_session)
self.audio_value_widget.setEnabled(have_audio) self.audio_value_widget.setEnabled('audio' in blink_session.streams)
self.audio_addresses_value_label.setEnabled(have_audio) self.chat_value_widget.setEnabled('chat' in blink_session.streams)
self.audio_ice_status_value_label.setEnabled(have_audio) self.screen_value_widget.setEnabled('screen-sharing' in blink_session.streams)
self.chat_value_widget.setEnabled(have_chat)
self.chat_addresses_value_label.setEnabled(have_chat)
self.screen_value_widget.setEnabled(have_screen)
session_info = blink_session.info session_info = blink_session.info
audio_info = blink_session.info.streams.audio audio_info = blink_session.info.streams.audio
...@@ -924,52 +922,47 @@ class ChatWindow(base_class, ui_class, ColorHelperMixin): ...@@ -924,52 +922,47 @@ class ChatWindow(base_class, ui_class, ColorHelperMixin):
if 'session' in elements: if 'session' in elements:
self.account_value_label.setText(blink_session.account.id) self.account_value_label.setText(blink_session.account.id)
self.remote_agent_value_label.setText(session_info.remote_user_agent or u'N/A') self.remote_agent_value_label.setText(session_info.remote_user_agent or u'N/A')
if session_info.local_address and session_info.remote_address: if session_info.remote_address:
self.sip_addresses_value_label.setText(u'%s \u21c4 %s:%s' % (session_info.local_address, session_info.transport, session_info.remote_address)) self.sip_address_value_label.setText(u'%s:%s' % (session_info.transport, session_info.remote_address))
elif session_info.local_address:
self.sip_addresses_value_label.setText(u'%s \u21c4 N/A' % session_info.local_address)
else: else:
self.sip_addresses_value_label.setText(u'N/A') self.sip_address_value_label.setText(u'N/A')
if 'media' in elements: if 'media' in elements:
self.audio_value_label.setText(audio_info.codec or 'N/A') self.audio_value_label.setText(audio_info.codec or 'N/A')
self.audio_encryption_label.setVisible(audio_info.encryption is not None)
if audio_info.local_address and audio_info.remote_address:
self.audio_addresses_value_label.setText(u'%s \u21c4 %s' % (audio_info.local_address, audio_info.remote_address))
else:
self.audio_addresses_value_label.setText(u'N/A')
if audio_info.ice_status == None: if audio_info.ice_status == 'succeeded':
self.audio_ice_status_value_label.setText(u'N/A')
elif audio_info.ice_status == 'disabled':
self.audio_ice_status_value_label.setText(u'Disabled')
elif audio_info.ice_status == 'gathering':
self.audio_ice_status_value_label.setText(u'Gathering candidates')
elif audio_info.ice_status == 'gathering_complete':
self.audio_ice_status_value_label.setText(u'Gathered candidates')
elif audio_info.ice_status == 'negotiating':
self.audio_ice_status_value_label.setText(u'Negotiating')
elif audio_info.ice_status == 'succeeded':
if 'relay' in {candidate.type.lower() for candidate in (audio_info.local_rtp_candidate, audio_info.remote_rtp_candidate)}: if 'relay' in {candidate.type.lower() for candidate in (audio_info.local_rtp_candidate, audio_info.remote_rtp_candidate)}:
self.audio_ice_status_value_label.setText(u'Using relay') self.audio_connection_label.setPixmap(self.relay_connection_pixmap)
self.audio_connection_label.setToolTip(u'Using relay')
else: else:
self.audio_ice_status_value_label.setText(u'Peer to peer') self.audio_connection_label.setPixmap(self.direct_connection_pixmap)
self.audio_connection_label.setToolTip(u'Peer to peer')
elif audio_info.ice_status == 'failed': elif audio_info.ice_status == 'failed':
self.audio_ice_status_value_label.setText(u"Couldn't negotiate ICE") self.audio_connection_label.setPixmap(self.unknown_connection_pixmap)
self.audio_connection_label.setToolTip(u"Couldn't negotiate ICE")
elif audio_info.ice_status == 'disabled':
self.audio_connection_label.setPixmap(self.unknown_connection_pixmap)
self.audio_connection_label.setToolTip(u'ICE is disabled')
else:
self.audio_connection_label.setPixmap(self.unknown_connection_pixmap)
self.audio_connection_label.setToolTip(u'Negotiating ICE')
self.audio_connection_label.setVisible(audio_info.remote_address is not None)
self.audio_encryption_label.setVisible(audio_info.encryption is not None)
if any(len(path) > 1 for path in (chat_info.full_local_path, chat_info.full_remote_path)): if any(len(path) > 1 for path in (chat_info.full_local_path, chat_info.full_remote_path)):
self.chat_value_label.setText(u'Using relay') self.chat_value_label.setText(u'Using relay')
self.chat_connection_label.setPixmap(self.relay_connection_pixmap)
self.chat_connection_label.setToolTip(u'Using relay')
elif chat_info.full_local_path and chat_info.full_remote_path: elif chat_info.full_local_path and chat_info.full_remote_path:
self.chat_value_label.setText(u'Peer to peer') self.chat_value_label.setText(u'Peer to peer')
self.chat_connection_label.setPixmap(self.direct_connection_pixmap)
self.chat_connection_label.setToolTip(u'Peer to peer')
else: else:
self.chat_value_label.setText(u'N/A') self.chat_value_label.setText(u'N/A')
self.chat_encryption_label.setVisible(chat_info.remote_address is not None and chat_info.transport=='tls')
if chat_info.local_address and chat_info.remote_address: self.chat_connection_label.setVisible(chat_info.remote_address is not None)
self.chat_addresses_value_label.setText(u'%s \u21c4 %s:%s' % (chat_info.local_address, chat_info.transport, chat_info.remote_address)) self.chat_encryption_label.setVisible(chat_info.remote_address is not None and chat_info.transport=='tls')
else:
self.chat_addresses_value_label.setText(u'N/A')
if screen_info.remote_address is not None and screen_info.mode == 'active': if screen_info.remote_address is not None and screen_info.mode == 'active':
self.screen_value_label.setText(u'Viewing remote') self.screen_value_label.setText(u'Viewing remote')
...@@ -977,6 +970,15 @@ class ChatWindow(base_class, ui_class, ColorHelperMixin): ...@@ -977,6 +970,15 @@ class ChatWindow(base_class, ui_class, ColorHelperMixin):
self.screen_value_label.setText(u'Sharing local') self.screen_value_label.setText(u'Sharing local')
else: else:
self.screen_value_label.setText(u'N/A') self.screen_value_label.setText(u'N/A')
if any(len(path) > 1 for path in (screen_info.full_local_path, screen_info.full_remote_path)):
self.screen_connection_label.setPixmap(self.relay_connection_pixmap)
self.screen_connection_label.setToolTip(u'Using relay')
elif screen_info.full_local_path and screen_info.full_remote_path:
self.screen_connection_label.setPixmap(self.direct_connection_pixmap)
self.screen_connection_label.setToolTip(u'Peer to peer')
self.screen_connection_label.setVisible(screen_info.remote_address is not None)
self.screen_encryption_label.setVisible(screen_info.remote_address is not None and screen_info.transport=='tls') self.screen_encryption_label.setVisible(screen_info.remote_address is not None and screen_info.transport=='tls')
if 'statistics' in elements: if 'statistics' in elements:
......
This diff is collapsed.
<?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="12"
height="12"
id="svg2"
version="1.1"
inkscape:version="0.48.4 r9939"
sodipodi:docname="connection-direct.svg">
<defs
id="defs4" />
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="77.083333"
inkscape:cx="6"
inkscape:cy="6"
inkscape:document-units="px"
inkscape:current-layer="g3904"
showgrid="true"
showguides="true"
inkscape:guide-bbox="true"
inkscape:window-width="1706"
inkscape:window-height="1135"
inkscape:window-x="60"
inkscape:window-y="0"
inkscape:window-maximized="0">
<inkscape:grid
type="xygrid"
id="grid2985"
empspacing="10"
visible="true"
enabled="true"
snapvisiblegridlinesonly="true"
spacingx="0.25px"
spacingy="0.25px" />
</sodipodi:namedview>
<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" />
<dc:title />
</cc:Work>
</rdf:RDF>
</metadata>
<g
style="display:inline"
inkscape:label="Direct connection"
inkscape:groupmode="layer"
id="g3904"
transform="translate(0,-1040.3622)">
<path
style="fill:none;stroke:#272727;stroke-width:1.20000005;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
d="M 2,10 10,2"
id="path3906"
inkscape:connector-curvature="0"
transform="translate(0,1040.3622)" />
<path
sodipodi:type="arc"
style="fill:#272727;fill-opacity:1;stroke:#272727;stroke-width:0.80000001;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:1.6;display:inline"
id="path3908"
sodipodi:cx="4.5"
sodipodi:cy="4.5"
sodipodi:rx="0.5"
sodipodi:ry="0.5"
d="M 5,4.5 C 5,4.7761424 4.7761424,5 4.5,5 4.2238576,5 4,4.7761424 4,4.5 4,4.2238576 4.2238576,4 4.5,4 4.7761424,4 5,4.2238576 5,4.5 z"
transform="matrix(1.6666666,0,0,1.6666666,2.0000002,1035.3622)" />
<path
sodipodi:type="arc"
style="fill:#272727;fill-opacity:1;stroke:#272727;stroke-width:0.80000001;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:1.6;display:inline"
id="path3910"
sodipodi:cx="4.5"
sodipodi:cy="4.5"
sodipodi:rx="0.5"
sodipodi:ry="0.5"
d="M 5,4.5 C 5,4.7761424 4.7761424,5 4.5,5 4.2238576,5 4,4.7761424 4,4.5 4,4.2238576 4.2238576,4 4.5,4 4.7761424,4 5,4.2238576 5,4.5 z"
transform="matrix(1.6666666,0,0,1.6666666,-4.9999998,1042.3622)" />
</g>
</svg>
<?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="12"
height="12"
id="svg2"
version="1.1"
inkscape:version="0.48.4 r9939"
sodipodi:docname="connection-relay.svg">
<defs
id="defs4" />
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="77.083333"
inkscape:cx="6"
inkscape:cy="6"
inkscape:document-units="px"
inkscape:current-layer="g4897"
showgrid="true"
showguides="true"
inkscape:guide-bbox="true"
inkscape:window-width="1706"
inkscape:window-height="1135"
inkscape:window-x="60"
inkscape:window-y="0"
inkscape:window-maximized="0">
<inkscape:grid
type="xygrid"
id="grid2985"
empspacing="10"
visible="true"
enabled="true"
snapvisiblegridlinesonly="true"
spacingx="0.25px"
spacingy="0.25px" />
</sodipodi:namedview>
<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" />
<dc:title />
</cc:Work>
</rdf:RDF>
</metadata>
<g
transform="translate(0,-1040.3622)"
id="g4897"
inkscape:groupmode="layer"
inkscape:label="Relay connection"
style="display:inline">
<path
transform="matrix(1.6666666,0,0,1.6666666,-4.9999998,1042.3622)"
d="M 5,4.5 C 5,4.7761424 4.7761424,5 4.5,5 4.2238576,5 4,4.7761424 4,4.5 4,4.2238576 4.2238576,4 4.5,4 4.7761424,4 5,4.2238576 5,4.5 z"
sodipodi:ry="0.5"
sodipodi:rx="0.5"
sodipodi:cy="4.5"
sodipodi:cx="4.5"
id="path4903"
style="fill:#272727;fill-opacity:1;stroke:#272727;stroke-width:0.80000001;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:1.6;display:inline"
sodipodi:type="arc" />
<path
style="fill:none;stroke:#272727;stroke-width:1.20000005;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;display:inline"
d="m 3,1049.8622 6,0"
id="path5064-9"
inkscape:connector-curvature="0" />
<path
style="fill:none;stroke:#272727;stroke-width:1.20000005;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
d="m 9.4999999,1043.3622 0,6"
id="path5064"
inkscape:connector-curvature="0" />
<path
transform="matrix(1.6666666,0,0,1.6666666,2.0000002,1035.3622)"
d="M 5,4.5 C 5,4.7761424 4.7761424,5 4.5,5 4.2238576,5 4,4.7761424 4,4.5 4,4.2238576 4.2238576,4 4.5,4 4.7761424,4 5,4.2238576 5,4.5 z"
sodipodi:ry="0.5"
sodipodi:rx="0.5"
sodipodi:cy="4.5"
sodipodi:cx="4.5"
id="path4901"
style="fill:#272727;fill-opacity:1;stroke:#272727;stroke-width:0.80000001;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:1.6;display:inline"
sodipodi:type="arc" />
<path
transform="matrix(1.6666666,0,0,1.6666666,2.0000002,1042.3622)"
d="M 5,4.5 C 5,4.7761424 4.7761424,5 4.5,5 4.2238576,5 4,4.7761424 4,4.5 4,4.2238576 4.2238576,4 4.5,4 4.7761424,4 5,4.2238576 5,4.5 z"
sodipodi:ry="0.5"
sodipodi:rx="0.5"
sodipodi:cy="4.5"
sodipodi:cx="4.5"
id="path4901-1"
style="fill:#272727;fill-opacity:1;stroke:#272727;stroke-width:0.80000001;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:1.6;display:inline"
sodipodi:type="arc" />
</g>
</svg>
<?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="12"
height="12"
id="svg2"
version="1.1"
inkscape:version="0.48.4 r9939"
sodipodi:docname="connection-unknown.svg">
<defs
id="defs4" />
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="77.083333"
inkscape:cx="6"
inkscape:cy="6"
inkscape:document-units="px"
inkscape:current-layer="g2992"
showgrid="true"
showguides="true"
inkscape:guide-bbox="true"
inkscape:window-width="1706"
inkscape:window-height="1135"
inkscape:window-x="60"
inkscape:window-y="0"
inkscape:window-maximized="0">
<inkscape:grid
type="xygrid"
id="grid2985"
empspacing="10"
visible="true"
enabled="true"
snapvisiblegridlinesonly="true"
spacingx="0.25px"
spacingy="0.25px" />
</sodipodi:namedview>
<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" />
<dc:title />
</cc:Work>
</rdf:RDF>
</metadata>
<g
style="display:inline"
inkscape:label="Unknown connection"
inkscape:groupmode="layer"
id="g2992"
transform="translate(0,-1040.3622)">
<path
sodipodi:type="arc"
style="fill:#272727;fill-opacity:1;stroke:#272727;stroke-width:0.80000001;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:1.6;display:inline"
id="path2994"
sodipodi:cx="4.5"
sodipodi:cy="4.5"
sodipodi:rx="0.5"
sodipodi:ry="0.5"
d="M 5,4.5 C 5,4.7761424 4.7761424,5 4.5,5 4.2238576,5 4,4.7761424 4,4.5 4,4.2238576 4.2238576,4 4.5,4 4.7761424,4 5,4.2238576 5,4.5 z"
transform="matrix(1.6666666,0,0,1.6666666,-4.9999998,1042.3622)" />
<path
sodipodi:type="arc"
style="fill:#272727;fill-opacity:1;stroke:#272727;stroke-width:0.80000001;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:1.6;display:inline"
id="path3000"
sodipodi:cx="4.5"
sodipodi:cy="4.5"
sodipodi:rx="0.5"
sodipodi:ry="0.5"
d="M 5,4.5 C 5,4.7761424 4.7761424,5 4.5,5 4.2238576,5 4,4.7761424 4,4.5 4,4.2238576 4.2238576,4 4.5,4 4.7761424,4 5,4.2238576 5,4.5 z"
transform="matrix(1.6666666,0,0,1.6666666,2.0000002,1035.3622)" />
<path
sodipodi:type="arc"
style="fill:#272727;fill-opacity:1;stroke:#272727;stroke-width:0.80000001;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:1.6;display:inline"
id="path3002"
sodipodi:cx="4.5"
sodipodi:cy="4.5"
sodipodi:rx="0.5"
sodipodi:ry="0.5"
d="M 5,4.5 C 5,4.7761424 4.7761424,5 4.5,5 4.2238576,5 4,4.7761424 4,4.5 4,4.2238576 4.2238576,4 4.5,4 4.7761424,4 5,4.2238576 5,4.5 z"
transform="matrix(1.6666666,0,0,1.6666666,2.0000002,1042.3622)" />
</g>
</svg>
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment