2015-06-05 03:59:28 -04:00
var FFZ = window . FrankerFaceZ ,
utils = require ( '../utils' ) ,
constants = require ( '../constants' ) ,
format _unread = function ( count ) {
if ( count < 1 )
return "" ;
else if ( count >= 99 )
return "99+" ;
return "" + count ;
} ;
// --------------------
// Settings
// --------------------
2015-07-04 17:06:36 -04:00
2015-07-06 00:09:21 -04:00
FFZ . settings _info . swap _sidebars = {
2015-07-04 17:06:36 -04:00
type : "boolean" ,
value : false ,
2015-07-06 00:09:21 -04:00
category : "Miscellaneous" ,
no _bttv : true ,
name : "Swap Sidebar Positions" ,
help : "Swap the positions of the left and right sidebars, placing chat on the left." ,
on _update : function ( val ) {
if ( ! this . has _bttv )
document . body . classList . toggle ( "ffz-sidebar-swap" , val ) ;
}
} ;
FFZ . settings _info . minimal _chat = {
type : "boolean" ,
value : false ,
2015-07-04 17:06:36 -04:00
category : "Chat" ,
name : "Minimalistic Chat" ,
help : "Hide all of the chat user interface, only showing messages and an input box." ,
on _update : function ( val ) {
document . body . classList . toggle ( "ffz-minimal-chat" , val ) ;
if ( this . settings . group _tabs && this . _chatv && this . _chatv . _ffz _tabs ) {
var f = this ;
setTimeout ( function ( ) {
f . _chatv && f . _chatv . $ ( '.chat-room' ) . css ( 'top' , f . _chatv . _ffz _tabs . offsetHeight + "px" ) ;
2015-07-06 00:09:21 -04:00
f . _roomv && f . _roomv . get ( 'stuckToBottom' ) && f . _roomv . _scrollToBottom ( ) ;
2015-07-04 17:06:36 -04:00
} , 0 ) ;
}
}
} ;
2015-06-10 18:46:04 -04:00
FFZ . settings _info . prevent _clear = {
type : "boolean" ,
value : false ,
no _bttv : true ,
2015-07-04 17:06:36 -04:00
category : "Chat Moderation" ,
2015-06-10 18:46:04 -04:00
name : "Show Deleted Messages" ,
help : "Fade deleted messages instead of replacing them, and prevent chat from being cleared." ,
on _update : function ( val ) {
if ( this . has _bttv || ! this . rooms )
return ;
for ( var room _id in this . rooms ) {
var ffz _room = this . rooms [ room _id ] ,
room = ffz _room && ffz _room . room ;
if ( ! room )
continue ;
room . get ( "messages" ) . forEach ( function ( s , n ) {
if ( val && ! s . ffz _deleted && s . deleted )
room . set ( "messages." + n + ".deleted" , false ) ;
else if ( s . ffz _deleted && ! val && ! s . deleted )
room . set ( "messages." + n + ".deleted" , true ) ;
} ) ;
}
}
} ;
FFZ . settings _info . chat _history = {
type : "boolean" ,
value : true ,
visible : false ,
category : "Chat" ,
name : "Chat History <span>Alpha</span>" ,
help : "Load previous chat messages when loading a chat room so you can see what people have been talking about. <b>This currently only works in a handful of channels due to server capacity.</b>" ,
} ;
2015-06-05 03:59:28 -04:00
FFZ . settings _info . group _tabs = {
type : "boolean" ,
value : false ,
no _bttv : true ,
category : "Chat" ,
name : "Chat Room Tabs <span>Beta</span>" ,
help : "Enhanced UI for switching the current chat room and noticing new messages." ,
on _update : function ( val ) {
var enabled = ! this . has _bttv && val ;
if ( ! this . _chatv || enabled === this . _group _tabs _state )
return ;
if ( enabled )
this . _chatv . ffzEnableTabs ( ) ;
else
this . _chatv . ffzDisableTabs ( ) ;
}
} ;
FFZ . settings _info . pinned _rooms = {
type : "button" ,
value : [ ] ,
category : "Chat" ,
visible : false ,
name : "Pinned Chat Rooms" ,
help : "Set a list of channels that should always be available in chat."
} ;
2015-01-20 01:53:18 -05:00
// --------------------
// Initialization
// --------------------
FFZ . prototype . setup _chatview = function ( ) {
2015-07-04 17:06:36 -04:00
document . body . classList . toggle ( "ffz-minimal-chat" , this . settings . minimal _chat ) ;
2015-07-06 00:09:21 -04:00
if ( ! this . has _bttv )
document . body . classList . toggle ( "ffz-sidebar-swap" , this . settings . swap _sidebars ) ;
2015-07-04 17:06:36 -04:00
2015-06-05 03:59:28 -04:00
this . log ( "Hooking the Ember Chat controller." ) ;
var Chat = App . _ _container _ _ . lookup ( 'controller:chat' ) ,
f = this ;
if ( Chat ) {
Chat . reopen ( {
ffzUpdateChannels : function ( ) {
if ( f . settings . group _tabs && f . _chatv )
f . _chatv . ffzRebuildTabs ( ) ;
2015-07-04 17:06:36 -04:00
} . observes ( "currentChannelRoom" , "connectedPrivateGroupRooms" ) ,
removeCurrentChannelRoom : function ( ) {
if ( ! f . settings . group _tabs || f . has _bttv )
return this . _super ( ) ;
var room = this . get ( "currentChannelRoom" ) ,
room _id = room && room . get ( 'id' ) ;
if ( ! f . settings . pinned _rooms || f . settings . pinned _rooms . indexOf ( room _id ) === - 1 ) {
// We can actually destroy it.
if ( room === this . get ( "currentRoom" ) )
this . blurRoom ( ) ;
if ( room )
room . destroy ( ) ;
}
this . set ( "currentChannelRoom" , void 0 ) ;
}
2015-06-05 03:59:28 -04:00
} ) ;
}
2015-01-20 01:53:18 -05:00
this . log ( "Hooking the Ember Chat view." ) ;
var Chat = App . _ _container _ _ . resolve ( 'view:chat' ) ;
this . _modify _cview ( Chat ) ;
// For some reason, this doesn't work unless we create an instance of the
// chat view and then destroy it immediately.
2015-02-24 00:33:29 -05:00
try {
Chat . create ( ) . destroy ( ) ;
} catch ( err ) { }
2015-01-20 01:53:18 -05:00
// Modify all existing Chat views.
for ( var key in Ember . View . views ) {
if ( ! Ember . View . views . hasOwnProperty ( key ) )
continue ;
var view = Ember . View . views [ key ] ;
if ( ! ( view instanceof Chat ) )
continue ;
2015-06-05 03:59:28 -04:00
this . log ( "Manually updating existing Chat view." , view ) ;
2015-02-10 01:34:23 -05:00
try {
2015-06-05 03:59:28 -04:00
view . ffzInit ( ) ;
2015-02-10 01:34:23 -05:00
} catch ( err ) {
this . error ( "setup: build_ui_link: " + err ) ;
}
2015-01-20 01:53:18 -05:00
}
2015-06-05 03:59:28 -04:00
this . log ( "Hooking the Ember Layout controller." ) ;
var Layout = App . _ _container _ _ . lookup ( 'controller:layout' ) ;
if ( ! Layout )
return ;
Layout . reopen ( {
ffzFixTabs : function ( ) {
if ( f . settings . group _tabs && f . _chatv && f . _chatv . _ffz _tabs ) {
setTimeout ( function ( ) {
f . _chatv && f . _chatv . $ ( '.chat-room' ) . css ( 'top' , f . _chatv . _ffz _tabs . offsetHeight + "px" ) ;
} , 0 ) ;
}
} . observes ( "isRightColumnClosed" )
} ) ;
this . log ( "Hooking the Ember 'Right Column' controller. Seriously..." ) ;
var Column = App . _ _container _ _ . lookup ( 'controller:right-column' ) ;
if ( ! Column )
return ;
Column . reopen ( {
ffzFixTabs : function ( ) {
if ( f . settings . group _tabs && f . _chatv && f . _chatv . _ffz _tabs ) {
setTimeout ( function ( ) {
f . _chatv && f . _chatv . $ ( '.chat-room' ) . css ( 'top' , f . _chatv . _ffz _tabs . offsetHeight + "px" ) ;
} , 0 ) ;
}
} . observes ( "firstTabSelected" )
} ) ;
2015-01-20 01:53:18 -05:00
}
// --------------------
// Modify Chat View
// --------------------
FFZ . prototype . _modify _cview = function ( view ) {
var f = this ;
view . reopen ( {
didInsertElement : function ( ) {
this . _super ( ) ;
2015-06-05 03:59:28 -04:00
2015-02-10 01:34:23 -05:00
try {
2015-06-05 03:59:28 -04:00
this . ffzInit ( ) ;
2015-02-10 01:34:23 -05:00
} catch ( err ) {
2015-06-05 03:59:28 -04:00
f . error ( "ChatView didInsertElement: " + err ) ;
2015-02-10 01:34:23 -05:00
}
2015-01-20 01:53:18 -05:00
} ,
willClearRender : function ( ) {
2015-02-10 01:34:23 -05:00
try {
2015-06-05 03:59:28 -04:00
this . ffzTeardown ( ) ;
2015-02-10 01:34:23 -05:00
} catch ( err ) {
2015-06-05 03:59:28 -04:00
f . error ( "ChatView willClearRender: " + err ) ;
2015-02-10 01:34:23 -05:00
}
2015-06-05 03:59:28 -04:00
this . _super ( ) ;
2015-01-20 01:53:18 -05:00
} ,
2015-06-05 03:59:28 -04:00
ffzInit : function ( ) {
f . _chatv = this ;
this . $ ( '.textarea-contain' ) . append ( f . build _ui _link ( this ) ) ;
if ( ! f . has _bttv && f . settings . group _tabs )
this . ffzEnableTabs ( ) ;
setTimeout ( function ( ) {
if ( f . settings . group _tabs && f . _chatv . _ffz _tabs )
f . _chatv . $ ( '.chat-room' ) . css ( 'top' , f . _chatv . _ffz _tabs . offsetHeight + "px" ) ;
var controller = f . _chatv . get ( 'controller' ) ;
controller && controller . set ( 'showList' , false ) ;
} , 1000 ) ;
} ,
ffzTeardown : function ( ) {
if ( f . _chatv === this )
f . _chatv = null ;
this . $ ( '.textarea-contain .ffz-ui-toggle' ) . remove ( ) ;
if ( f . settings . group _tabs )
this . ffzDisableTabs ( ) ;
} ,
ffzChangeRoom : Ember . observer ( 'controller.currentRoom' , function ( ) {
2015-02-10 01:34:23 -05:00
try {
f . update _ui _link ( ) ;
2015-06-05 03:59:28 -04:00
if ( ! f . has _bttv && f . settings . group _tabs && this . _ffz _tabs ) {
var room = this . get ( 'controller.currentRoom' ) ;
room && room . resetUnreadCount ( ) ;
var tabs = jQuery ( this . _ffz _tabs ) ;
tabs . children ( '.ffz-chat-tab' ) . removeClass ( 'active' ) ;
if ( room )
tabs . children ( '.ffz-chat-tab[data-room="' + room . get ( 'id' ) + '"]' ) . removeClass ( 'tab-mentioned' ) . addClass ( 'active' ) . children ( 'span' ) . text ( '' ) ;
// Invite Link
var can _invite = room && room . get ( 'canInvite' ) ;
this . _ffz _invite && this . _ffz _invite . classList . toggle ( 'hidden' , ! can _invite ) ;
this . set ( 'controller.showInviteUser' , can _invite && this . get ( 'controller.showInviteUser' ) )
// Now, adjust the chat-room.
this . $ ( '.chat-room' ) . css ( 'top' , this . _ffz _tabs . offsetHeight + "px" ) ;
}
2015-02-10 01:34:23 -05:00
} catch ( err ) {
2015-06-05 03:59:28 -04:00
f . error ( "ChatView ffzUpdateLink: " + err ) ;
}
} ) ,
// Group Tabs~!
ffzEnableTabs : function ( ) {
if ( f . has _bttv || ! f . settings . group _tabs )
return ;
// Hide the existing chat UI.
this . $ ( ".chat-header" ) . addClass ( "hidden" ) ;
// Create our own UI.
var tabs = this . _ffz _tabs = document . createElement ( "div" ) ;
tabs . id = "ffz-group-tabs" ;
this . $ ( ".chat-header" ) . after ( tabs ) ;
// List the Rooms
this . ffzRebuildTabs ( ) ;
} ,
ffzRebuildTabs : function ( ) {
if ( f . has _bttv || ! f . settings . group _tabs )
return ;
var tabs = this . _ffz _tabs || this . get ( 'element' ) . querySelector ( '#ffz-group-tabs' ) ;
if ( ! tabs )
return ;
tabs . innerHTML = "" ;
var link = document . createElement ( 'a' ) ,
view = this ;
link . className = 'button glyph-only tooltip' ;
link . title = "Chat Room Management" ;
link . innerHTML = constants . ROOMS ;
link . addEventListener ( 'click' , function ( ) {
var controller = view . get ( 'controller' ) ;
controller && controller . set ( 'showList' , ! controller . get ( 'showList' ) ) ;
} ) ;
tabs . appendChild ( link ) ;
link = document . createElement ( 'a' ) ,
link . className = 'button glyph-only tooltip invite' ;
link . title = "Invite a User" ;
link . innerHTML = constants . INVITE ;
link . addEventListener ( 'click' , function ( ) {
var controller = view . get ( 'controller' ) ;
controller && controller . set ( 'showInviteUser' , controller . get ( 'currentRoom.canInvite' ) && ! controller . get ( 'showInviteUser' ) ) ;
} ) ;
link . classList . toggle ( 'hidden' , ! this . get ( "controller.currentRoom.canInvite" ) ) ;
view . _ffz _invite = link ;
tabs . appendChild ( link ) ;
var room = this . get ( 'controller.currentChannelRoom' ) , tab ;
if ( room ) {
tab = this . ffzBuildTab ( view , room , true ) ;
tab && tabs . appendChild ( tab ) ;
2015-02-10 01:34:23 -05:00
}
2015-06-05 03:59:28 -04:00
// Check Host Target
var Channel = App . _ _container _ _ . lookup ( 'controller:channel' ) ,
Room = App . _ _container _ _ . resolve ( 'model:room' ) ;
target = Channel && Channel . get ( 'hostModeTarget' ) ;
if ( target && Room ) {
var target _id = target . get ( 'id' ) ;
if ( this . _ffz _host !== target _id ) {
2015-07-04 17:06:36 -04:00
if ( f . settings . pinned _rooms . indexOf ( this . _ffz _host ) === - 1 && this . _ffz _host _room ) {
2015-06-05 03:59:28 -04:00
if ( this . get ( 'controller.currentRoom' ) === this . _ffz _host _room )
this . get ( 'controller' ) . blurRoom ( ) ;
this . _ffz _host _room . destroy ( ) ;
}
this . _ffz _host = target _id ;
this . _ffz _host _room = Room . findOne ( target _id ) ;
}
} else if ( this . _ffz _host ) {
2015-07-04 17:06:36 -04:00
if ( f . settings . pinned _rooms . indexOf ( this . _ffz _host ) === - 1 && this . _ffz _host _room ) {
2015-06-05 03:59:28 -04:00
if ( this . get ( 'controller.currentRoom' ) === this . _ffz _host _room )
this . get ( 'controller' ) . blurRoom ( ) ;
this . _ffz _host _room . destroy ( ) ;
}
delete this . _ffz _host ;
delete this . _ffz _host _room ;
}
if ( this . _ffz _host _room ) {
tab = view . ffzBuildTab ( view , this . _ffz _host _room , false , true ) ;
tab && tabs . appendChild ( tab ) ;
}
// Pinned Rooms
for ( var i = 0 ; i < f . settings . pinned _rooms . length ; i ++ ) {
var room _id = f . settings . pinned _rooms [ i ] ;
if ( room && room . get ( 'id' ) !== room _id && this . _ffz _host !== room _id && f . rooms [ room _id ] && f . rooms [ room _id ] . room ) {
var tab = view . ffzBuildTab ( view , f . rooms [ room _id ] . room , false , false ) ;
tab && tabs . appendChild ( tab ) ;
}
}
_ . each ( this . get ( 'controller.connectedPrivateGroupRooms' ) , function ( room ) {
var tab = view . ffzBuildTab ( view , room ) ;
tab && tabs . appendChild ( tab ) ;
} ) ;
// Now, adjust the chat-room.
this . $ ( '.chat-room' ) . css ( 'top' , tabs . offsetHeight + "px" ) ;
} ,
ffzTabUnread : function ( room _id ) {
if ( f . has _bttv || ! f . settings . group _tabs )
return ;
var tabs = this . _ffz _tabs || this . get ( 'element' ) . querySelector ( '#ffz-group-tabs' ) ,
current _id = this . get ( 'controller.currentRoom.id' ) ;
if ( ! tabs )
return ;
if ( room _id ) {
var tab = tabs . querySelector ( '.ffz-chat-tab[data-room="' + room _id + '"]' ) ,
room = f . rooms && f . rooms [ room _id ] ;
if ( tab && room ) {
var unread = format _unread ( room _id === current _id ? 0 : room . room . get ( 'unreadCount' ) ) ;
tab . querySelector ( 'span' ) . innerHTML = unread ;
}
// Now, adjust the chat-room.
return this . $ ( '.chat-room' ) . css ( 'top' , tabs . offsetHeight + "px" ) ;
}
var children = tabs . querySelectorAll ( '.ffz-chat-tab' ) ;
for ( var i = 0 ; i < children . length ; i ++ ) {
var tab = children [ i ] ,
room _id = tab . getAttribute ( 'data-room' ) ,
room = f . rooms && f . rooms [ room _id ] ;
if ( ! room )
continue ;
var unread = format _unread ( room _id === current _id ? 0 : room . room . get ( 'unreadCount' ) ) ;
tab . querySelector ( 'span' ) . innerHTML = unread ;
}
// Now, adjust the chat-room.
this . $ ( '.chat-room' ) . css ( 'top' , tabs . offsetHeight + "px" ) ;
} ,
ffzBuildTab : function ( view , room , current _channel , host _channel ) {
2015-07-04 17:06:36 -04:00
var tab = document . createElement ( 'span' ) , name , unread , icon = '' ,
2015-06-05 03:59:28 -04:00
group = room . get ( 'isGroupRoom' ) ,
current = room === view . get ( 'controller.currentRoom' ) ;
tab . setAttribute ( 'data-room' , room . id ) ;
tab . className = 'ffz-chat-tab tooltip' ;
tab . classList . toggle ( 'current-channel' , current _channel ) ;
tab . classList . toggle ( 'host-channel' , host _channel ) ;
tab . classList . toggle ( 'group-chat' , group ) ;
tab . classList . toggle ( 'active' , current ) ;
unread = format _unread ( current ? 0 : room . get ( 'unreadCount' ) ) ;
2015-07-04 17:06:36 -04:00
name = room . get ( 'tmiRoom.displayName' ) || ( group ? room . get ( 'tmiRoom.name' ) : FFZ . get _capitalization ( room . get ( 'id' ) , function ( name ) {
unread = format _unread ( current ? 0 : room . get ( 'unreadCount' ) ) ;
tab . innerHTML = icon + utils . sanitize ( name ) + '<span>' + unread + '</span>' ;
} ) ) ;
2015-06-05 03:59:28 -04:00
if ( current _channel ) {
2015-07-04 17:06:36 -04:00
icon = constants . CAMERA ;
2015-06-05 03:59:28 -04:00
tab . title = "Current Channel" ;
} else if ( host _channel ) {
2015-07-04 17:06:36 -04:00
icon = constants . EYE ;
2015-06-05 03:59:28 -04:00
tab . title = "Hosted Channel" ;
} else if ( group )
tab . title = "Group Chat" ;
else
tab . title = "Pinned Channel" ;
2015-07-04 17:06:36 -04:00
tab . innerHTML = icon + utils . sanitize ( name ) + '<span>' + unread + '</span>' ;
2015-06-05 03:59:28 -04:00
tab . addEventListener ( 'click' , function ( ) {
view . get ( 'controller' ) . focusRoom ( room ) ;
} ) ;
return tab ;
} ,
ffzDisableTabs : function ( ) {
if ( this . _ffz _tabs ) {
this . _ffz _tabs . parentElement . removeChild ( this . _ffz _tabs ) ;
delete this . _ffz _tabs ;
delete this . _ffz _invite ;
}
if ( this . _ffz _host ) {
2015-07-04 17:06:36 -04:00
if ( f . settings . pinned _rooms . indexOf ( this . _ffz _host ) === - 1 && this . _ffz _host _room ) {
2015-06-05 03:59:28 -04:00
if ( this . get ( 'controller.currentRoom' ) === this . _ffz _host _room )
this . get ( 'controller' ) . blurRoom ( ) ;
this . _ffz _host _room . destroy ( ) ;
}
delete this . _ffz _host ;
delete this . _ffz _host _room ;
}
// Show the old chat UI.
this . $ ( '.chat-room' ) . css ( 'top' , '' ) ;
this . $ ( ".chat-header" ) . removeClass ( "hidden" ) ;
} ,
2015-01-20 01:53:18 -05:00
} ) ;
2015-06-05 03:59:28 -04:00
}
// ----------------------
// Chat Room Connections
// ----------------------
FFZ . prototype . connect _extra _chat = function ( ) {
if ( this . has _bttv )
return ;
for ( var i = 0 ; i < this . settings . pinned _rooms . length ; i ++ )
this . _join _room ( this . settings . pinned _rooms [ i ] , true ) ;
if ( ! this . has _bttv && this . _chatv && this . settings . group _tabs )
this . _chatv . ffzRebuildTabs ( ) ;
}
FFZ . prototype . _join _room = function ( room _id , no _rebuild ) {
var did _join = false ;
if ( this . settings . pinned _rooms . indexOf ( room _id ) === - 1 ) {
this . settings . pinned _rooms . push ( room _id ) ;
this . settings . set ( "pinned_rooms" , this . settings . pinned _rooms ) ;
did _join = true ;
}
// Make sure we're not already there.
if ( this . rooms [ room _id ] && this . rooms [ room _id ] . room )
return did _join ;
// Okay, fine. Get it.
var Room = App . _ _container _ _ . resolve ( 'model:room' ) ,
r = Room && Room . findOne ( room _id ) ;
// Finally, rebuild the chat UI.
if ( ! no _rebuild && ! this . has _bttv && this . _chatv && this . settings . group _tabs )
this . _chatv . ffzRebuildTabs ( ) ;
return did _join ;
}
FFZ . prototype . _leave _room = function ( room _id , no _rebuild ) {
var did _leave = false ;
if ( this . settings . pinned _rooms . indexOf ( room _id ) !== - 1 ) {
this . settings . pinned _rooms . removeObject ( room _id ) ;
this . settings . set ( "pinned_rooms" , this . settings . pinned _rooms ) ;
did _leave = true ;
}
if ( ! this . rooms [ room _id ] || ! this . rooms [ room _id ] . room )
return did _leave ;
var Chat = App . _ _container _ _ . lookup ( 'controller:chat' ) ,
r = this . rooms [ room _id ] . room ;
if ( ! Chat || Chat . get ( 'currentChannelRoom.id' ) === room _id || ( this . _chatv && this . _chatv . _ffz _host === room _id ) )
return did _leave ;
if ( Chat . get ( 'currentRoom.id' ) === room _id )
Chat . blurRoom ( ) ;
r . destroy ( ) ;
if ( ! no _rebuild && ! this . has _bttv && this . _chatv && this . settings . group _tabs )
this . _chatv . ffzRebuildTabs ( ) ;
return did _leave ;
}
// ----------------------
// Commands
// ----------------------
FFZ . chat _commands . join = function ( room , args ) {
if ( ! args || ! args . length || args . length > 1 )
return "Join Usage: /join <channel>" ;
var room _id = args [ 0 ] . toLowerCase ( ) ;
if ( room _id . charAt ( 0 ) === "#" )
room _id = room _id . substr ( 1 ) ;
if ( this . _join _room ( room _id ) )
return "Joining " + room _id + ". You will always connect to this channel's chat unless you later /part from it." ;
else
return "You have already joined " + room _id + ". Please use \"/part " + room _id + "\" to leave it." ;
}
FFZ . chat _commands . part = function ( room , args ) {
if ( ! args || ! args . length || args . length > 1 )
return "Part Usage: /part <channel>" ;
var room _id = args [ 0 ] . toLowerCase ( ) ;
if ( room _id . charAt ( 0 ) === "#" )
room _id = room _id . substr ( 1 ) ;
if ( this . _leave _room ( room _id ) )
return "Leaving " + room _id + "." ;
else if ( this . rooms [ room _id ] )
return "You do not have " + room _id + " pinned and you cannot leave the current channel or hosted channels via /part." ;
else
return "You are not in " + room _id + "." ;
2015-01-12 17:58:07 -05:00
}