2008-08-27 15:48:50 +00:00
|
|
|
//#include "gc_console.hpp"
|
2008-08-30 21:09:13 +00:00
|
|
|
#include <math.h>
|
|
|
|
|
2008-08-27 15:48:50 +00:00
|
|
|
#include <game/generated/gc_data.hpp>
|
2008-01-16 22:14:06 +00:00
|
|
|
|
2008-08-14 17:19:13 +00:00
|
|
|
#include <base/system.h>
|
|
|
|
|
2008-08-27 19:50:33 +00:00
|
|
|
#include <engine/e_client_interface.h>
|
|
|
|
|
2008-01-16 22:14:06 +00:00
|
|
|
extern "C" {
|
2008-02-04 00:13:34 +00:00
|
|
|
#include <engine/e_ringbuffer.h>
|
2008-01-16 22:14:06 +00:00
|
|
|
#include <engine/client/ec_font.h>
|
|
|
|
}
|
|
|
|
|
|
|
|
#include <cstring>
|
|
|
|
#include <cstdio>
|
|
|
|
|
2008-08-30 21:31:01 +00:00
|
|
|
#include <game/client/ui.hpp>
|
2008-01-16 22:14:06 +00:00
|
|
|
|
2008-08-27 15:48:50 +00:00
|
|
|
#include <game/version.hpp>
|
|
|
|
|
|
|
|
#include <game/client/lineinput.hpp>
|
|
|
|
|
|
|
|
#include "console.hpp"
|
2008-01-30 13:15:58 +00:00
|
|
|
|
|
|
|
enum
|
|
|
|
{
|
|
|
|
CONSOLE_CLOSED,
|
|
|
|
CONSOLE_OPENING,
|
|
|
|
CONSOLE_OPEN,
|
|
|
|
CONSOLE_CLOSING,
|
|
|
|
};
|
|
|
|
|
2008-08-27 15:48:50 +00:00
|
|
|
CONSOLE::INSTANCE::INSTANCE(int t)
|
2008-03-01 14:36:36 +00:00
|
|
|
{
|
2008-08-27 15:48:50 +00:00
|
|
|
// init ringbuffers
|
2008-10-02 12:29:19 +00:00
|
|
|
history = ringbuf_init(history_data, sizeof(history_data), RINGBUF_FLAG_RECYCLE);
|
|
|
|
backlog = ringbuf_init(backlog_data, sizeof(backlog_data), RINGBUF_FLAG_RECYCLE);
|
2008-03-01 14:36:36 +00:00
|
|
|
|
2008-08-27 15:48:50 +00:00
|
|
|
history_entry = 0x0;
|
2008-03-01 14:36:36 +00:00
|
|
|
|
2008-08-27 15:48:50 +00:00
|
|
|
type = t;
|
|
|
|
}
|
|
|
|
|
|
|
|
void CONSOLE::INSTANCE::execute_line(const char *line)
|
|
|
|
{
|
|
|
|
if(type == 0)
|
|
|
|
console_execute_line(line);
|
|
|
|
else
|
2008-03-01 14:36:36 +00:00
|
|
|
{
|
2008-08-27 15:48:50 +00:00
|
|
|
if(client_rcon_authed())
|
|
|
|
client_rcon(line);
|
2008-03-01 14:36:36 +00:00
|
|
|
else
|
2008-08-27 15:48:50 +00:00
|
|
|
client_rcon_auth("", line);
|
2008-03-01 14:36:36 +00:00
|
|
|
}
|
2008-08-27 15:48:50 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void CONSOLE::INSTANCE::on_input(INPUT_EVENT e)
|
|
|
|
{
|
|
|
|
bool handled = false;
|
2008-03-01 14:36:36 +00:00
|
|
|
|
2008-08-27 15:48:50 +00:00
|
|
|
if(e.flags&INPFLAG_PRESS)
|
2008-03-01 14:36:36 +00:00
|
|
|
{
|
2008-10-23 16:18:33 +00:00
|
|
|
if(e.key == KEY_RETURN || e.key == KEY_KP_ENTER)
|
2008-03-01 14:36:36 +00:00
|
|
|
{
|
2008-08-27 15:48:50 +00:00
|
|
|
if(input.get_string()[0])
|
2008-03-01 14:36:36 +00:00
|
|
|
{
|
2008-08-27 15:48:50 +00:00
|
|
|
char *entry = (char *)ringbuf_allocate(history, input.get_length()+1);
|
|
|
|
mem_copy(entry, input.get_string(), input.get_length()+1);
|
2008-03-21 16:45:26 +00:00
|
|
|
|
2008-08-27 15:48:50 +00:00
|
|
|
execute_line(input.get_string());
|
|
|
|
input.clear();
|
|
|
|
history_entry = 0x0;
|
2008-03-01 14:36:36 +00:00
|
|
|
}
|
2008-08-27 15:48:50 +00:00
|
|
|
|
|
|
|
handled = true;
|
|
|
|
}
|
|
|
|
else if (e.key == KEY_UP)
|
|
|
|
{
|
|
|
|
if (history_entry)
|
2008-03-01 14:36:36 +00:00
|
|
|
{
|
2008-08-27 15:48:50 +00:00
|
|
|
char *test = (char *)ringbuf_prev(history, history_entry);
|
2008-03-01 14:36:36 +00:00
|
|
|
|
2008-08-27 15:48:50 +00:00
|
|
|
if (test)
|
|
|
|
history_entry = test;
|
2008-03-01 20:03:04 +00:00
|
|
|
}
|
2008-08-27 15:48:50 +00:00
|
|
|
else
|
|
|
|
history_entry = (char *)ringbuf_last(history);
|
|
|
|
|
|
|
|
if (history_entry)
|
2008-03-01 14:36:36 +00:00
|
|
|
{
|
2008-08-27 15:48:50 +00:00
|
|
|
unsigned int len = strlen(history_entry);
|
|
|
|
if (len < sizeof(input) - 1)
|
|
|
|
input.set(history_entry);
|
2008-03-01 14:36:36 +00:00
|
|
|
}
|
2008-08-27 15:48:50 +00:00
|
|
|
handled = true;
|
|
|
|
}
|
|
|
|
else if (e.key == KEY_DOWN)
|
|
|
|
{
|
|
|
|
if (history_entry)
|
|
|
|
history_entry = (char *)ringbuf_next(history, history_entry);
|
|
|
|
|
|
|
|
if (history_entry)
|
|
|
|
{
|
|
|
|
unsigned int len = strlen(history_entry);
|
|
|
|
if (len < sizeof(input) - 1)
|
|
|
|
input.set(history_entry);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
input.clear();
|
|
|
|
handled = true;
|
2008-03-01 20:03:04 +00:00
|
|
|
}
|
2008-03-01 14:36:36 +00:00
|
|
|
}
|
|
|
|
|
2008-08-27 15:48:50 +00:00
|
|
|
if(!handled)
|
|
|
|
input.process_input(e);
|
|
|
|
}
|
2008-03-01 14:36:36 +00:00
|
|
|
|
2008-08-27 15:48:50 +00:00
|
|
|
void CONSOLE::INSTANCE::print_line(const char *line)
|
|
|
|
{
|
|
|
|
int len = strlen(line);
|
2008-03-01 14:36:36 +00:00
|
|
|
|
2008-08-27 15:48:50 +00:00
|
|
|
if (len > 255)
|
|
|
|
len = 255;
|
2008-03-01 14:36:36 +00:00
|
|
|
|
2008-08-27 15:48:50 +00:00
|
|
|
char *entry = (char *)ringbuf_allocate(backlog, len+1);
|
|
|
|
mem_copy(entry, line, len+1);
|
|
|
|
}
|
2008-03-01 14:36:36 +00:00
|
|
|
|
2008-08-27 15:48:50 +00:00
|
|
|
CONSOLE::CONSOLE()
|
|
|
|
: local_console(0), remote_console(1)
|
|
|
|
{
|
|
|
|
console_type = 0;
|
|
|
|
console_state = CONSOLE_CLOSED;
|
|
|
|
state_change_end = 0.0f;
|
|
|
|
state_change_duration = 0.1f;
|
|
|
|
}
|
2008-01-16 22:14:06 +00:00
|
|
|
|
2008-08-27 15:48:50 +00:00
|
|
|
float CONSOLE::time_now()
|
2008-01-30 13:15:58 +00:00
|
|
|
{
|
|
|
|
static long long time_start = time_get();
|
|
|
|
return float(time_get()-time_start)/float(time_freq());
|
|
|
|
}
|
|
|
|
|
2008-08-27 15:48:50 +00:00
|
|
|
CONSOLE::INSTANCE *CONSOLE::current_console()
|
2008-01-16 22:14:06 +00:00
|
|
|
{
|
2008-03-01 14:36:36 +00:00
|
|
|
if(console_type != 0)
|
|
|
|
return &remote_console;
|
|
|
|
return &local_console;
|
|
|
|
}
|
2008-01-16 22:14:06 +00:00
|
|
|
|
2008-08-27 15:48:50 +00:00
|
|
|
void CONSOLE::on_reset()
|
2008-03-01 14:36:36 +00:00
|
|
|
{
|
2008-01-16 22:14:06 +00:00
|
|
|
}
|
|
|
|
|
2008-08-27 15:48:50 +00:00
|
|
|
// only defined for 0<=t<=1
|
|
|
|
static float console_scale_func(float t)
|
2008-03-01 14:36:36 +00:00
|
|
|
{
|
2008-08-27 15:48:50 +00:00
|
|
|
//return t;
|
|
|
|
return sinf(acosf(1.0f-t));
|
2008-03-01 14:36:36 +00:00
|
|
|
}
|
2008-01-18 15:55:03 +00:00
|
|
|
|
2008-08-27 15:48:50 +00:00
|
|
|
void CONSOLE::on_render()
|
2008-01-29 21:39:41 +00:00
|
|
|
{
|
2008-08-27 15:48:50 +00:00
|
|
|
RECT screen = *ui_screen();
|
|
|
|
float console_max_height = screen.h*3/5.0f;
|
|
|
|
float console_height;
|
2008-02-04 00:13:34 +00:00
|
|
|
|
2008-08-27 15:48:50 +00:00
|
|
|
float progress = (time_now()-(state_change_end-state_change_duration))/float(state_change_duration);
|
2008-02-04 00:13:34 +00:00
|
|
|
|
2008-08-27 15:48:50 +00:00
|
|
|
if (progress >= 1.0f)
|
|
|
|
{
|
|
|
|
if (console_state == CONSOLE_CLOSING)
|
|
|
|
console_state = CONSOLE_CLOSED;
|
|
|
|
else if (console_state == CONSOLE_OPENING)
|
|
|
|
console_state = CONSOLE_OPEN;
|
2008-03-18 02:14:35 +00:00
|
|
|
|
2008-08-27 15:48:50 +00:00
|
|
|
progress = 1.0f;
|
|
|
|
}
|
|
|
|
|
2008-11-01 16:49:05 +00:00
|
|
|
if (console_state == CONSOLE_CLOSED || config.cl_editor)
|
2008-08-27 15:48:50 +00:00
|
|
|
return;
|
2008-11-01 16:49:05 +00:00
|
|
|
|
|
|
|
if (console_state == CONSOLE_OPEN)
|
|
|
|
inp_mouse_mode_absolute();
|
2008-03-18 02:14:35 +00:00
|
|
|
|
2008-08-27 15:48:50 +00:00
|
|
|
float console_height_scale;
|
2008-03-18 02:14:35 +00:00
|
|
|
|
2008-08-27 15:48:50 +00:00
|
|
|
if (console_state == CONSOLE_OPENING)
|
|
|
|
console_height_scale = console_scale_func(progress);
|
|
|
|
else if (console_state == CONSOLE_CLOSING)
|
|
|
|
console_height_scale = console_scale_func(1.0f-progress);
|
|
|
|
else //if (console_state == CONSOLE_OPEN)
|
|
|
|
console_height_scale = console_scale_func(1.0f);
|
2008-03-18 02:14:35 +00:00
|
|
|
|
2008-08-27 15:48:50 +00:00
|
|
|
console_height = console_height_scale*console_max_height;
|
2008-02-04 00:13:34 +00:00
|
|
|
|
2008-08-27 15:48:50 +00:00
|
|
|
gfx_mapscreen(screen.x, screen.y, screen.w, screen.h);
|
2008-02-04 00:13:34 +00:00
|
|
|
|
2008-08-27 15:48:50 +00:00
|
|
|
// do console shadow
|
|
|
|
gfx_texture_set(-1);
|
|
|
|
gfx_quads_begin();
|
|
|
|
gfx_setcolorvertex(0, 0,0,0, 0.5f);
|
|
|
|
gfx_setcolorvertex(1, 0,0,0, 0.5f);
|
|
|
|
gfx_setcolorvertex(2, 0,0,0, 0.0f);
|
|
|
|
gfx_setcolorvertex(3, 0,0,0, 0.0f);
|
|
|
|
gfx_quads_drawTL(0,console_height,screen.w,10.0f);
|
|
|
|
gfx_quads_end();
|
2008-03-01 20:03:04 +00:00
|
|
|
|
2008-08-27 15:48:50 +00:00
|
|
|
// do background
|
|
|
|
gfx_texture_set(data->images[IMAGE_CONSOLE_BG].id);
|
|
|
|
gfx_quads_begin();
|
|
|
|
gfx_setcolor(0.2f, 0.2f, 0.2f,0.9f);
|
|
|
|
if(console_type != 0)
|
|
|
|
gfx_setcolor(0.4f, 0.2f, 0.2f,0.9f);
|
|
|
|
gfx_quads_setsubset(0,-console_height*0.075f,screen.w*0.075f*0.5f,0);
|
|
|
|
gfx_quads_drawTL(0,0,screen.w,console_height);
|
|
|
|
gfx_quads_end();
|
2008-03-01 20:03:04 +00:00
|
|
|
|
2008-08-27 15:48:50 +00:00
|
|
|
// do small bar shadow
|
|
|
|
gfx_texture_set(-1);
|
|
|
|
gfx_quads_begin();
|
|
|
|
gfx_setcolorvertex(0, 0,0,0, 0.0f);
|
|
|
|
gfx_setcolorvertex(1, 0,0,0, 0.0f);
|
|
|
|
gfx_setcolorvertex(2, 0,0,0, 0.25f);
|
|
|
|
gfx_setcolorvertex(3, 0,0,0, 0.25f);
|
|
|
|
gfx_quads_drawTL(0,console_height-20,screen.w,10);
|
|
|
|
gfx_quads_end();
|
2008-03-01 20:03:04 +00:00
|
|
|
|
2008-08-27 15:48:50 +00:00
|
|
|
// do the lower bar
|
|
|
|
gfx_texture_set(data->images[IMAGE_CONSOLE_BAR].id);
|
|
|
|
gfx_quads_begin();
|
|
|
|
gfx_setcolor(1.0f, 1.0f, 1.0f, 0.9f);
|
|
|
|
gfx_quads_setsubset(0,0.1f,screen.w*0.015f,1-0.1f);
|
|
|
|
gfx_quads_drawTL(0,console_height-10.0f,screen.w,10.0f);
|
|
|
|
gfx_quads_end();
|
|
|
|
|
|
|
|
console_height -= 10.0f;
|
|
|
|
|
|
|
|
INSTANCE *console = current_console();
|
2008-03-29 15:00:04 +00:00
|
|
|
|
2008-08-27 15:48:50 +00:00
|
|
|
{
|
|
|
|
float font_size = 10.0f;
|
|
|
|
float row_height = font_size*1.25f;
|
|
|
|
float x = 3;
|
|
|
|
float y = console_height - row_height - 2;
|
2008-03-23 09:22:15 +00:00
|
|
|
|
2008-08-27 15:48:50 +00:00
|
|
|
// render prompt
|
|
|
|
TEXT_CURSOR cursor;
|
|
|
|
gfx_text_set_cursor(&cursor, x, y, font_size, TEXTFLAG_RENDER);
|
|
|
|
|
|
|
|
const char *prompt = "> ";
|
|
|
|
if(console_type)
|
|
|
|
{
|
|
|
|
if(client_state() == CLIENTSTATE_ONLINE)
|
|
|
|
{
|
|
|
|
if(client_rcon_authed())
|
|
|
|
prompt = "rcon> ";
|
|
|
|
else
|
|
|
|
prompt = "ENTER PASSWORD> ";
|
|
|
|
}
|
|
|
|
else
|
|
|
|
prompt = "NOT CONNECTED> ";
|
|
|
|
}
|
|
|
|
|
|
|
|
gfx_text_ex(&cursor, prompt, -1);
|
|
|
|
|
|
|
|
// render console input
|
|
|
|
gfx_text_ex(&cursor, console->input.get_string(), console->input.cursor_offset());
|
|
|
|
TEXT_CURSOR marker = cursor;
|
|
|
|
gfx_text_ex(&marker, "|", -1);
|
|
|
|
gfx_text_ex(&cursor, console->input.get_string()+console->input.cursor_offset(), -1);
|
|
|
|
|
|
|
|
// render version
|
|
|
|
char buf[128];
|
|
|
|
str_format(buf, sizeof(buf), "v%s", GAME_VERSION);
|
|
|
|
float version_width = gfx_text_width(0, font_size, buf, -1);
|
|
|
|
gfx_text(0, screen.w-version_width-5, y, font_size, buf, -1);
|
|
|
|
|
|
|
|
// render log
|
|
|
|
y -= row_height;
|
|
|
|
char *entry = (char *)ringbuf_last(console->backlog);
|
|
|
|
while (y > 0.0f && entry)
|
|
|
|
{
|
|
|
|
gfx_text(0, x, y, font_size, entry, -1);
|
|
|
|
y -= row_height;
|
|
|
|
|
|
|
|
entry = (char *)ringbuf_prev(console->backlog, entry);
|
|
|
|
}
|
|
|
|
}
|
2008-03-23 09:22:15 +00:00
|
|
|
}
|
|
|
|
|
2008-08-27 15:48:50 +00:00
|
|
|
void CONSOLE::on_message(int msgtype, void *rawmsg)
|
2008-03-01 20:03:04 +00:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2008-08-27 15:48:50 +00:00
|
|
|
bool CONSOLE::on_input(INPUT_EVENT e)
|
2008-03-01 20:03:04 +00:00
|
|
|
{
|
2008-08-27 16:23:15 +00:00
|
|
|
if(console_state == CONSOLE_CLOSED)
|
|
|
|
return false;
|
2008-10-20 17:47:42 +00:00
|
|
|
if(e.key >= KEY_F1 && e.key <= KEY_F15)
|
2008-08-27 16:23:15 +00:00
|
|
|
return false;
|
|
|
|
|
2008-10-23 16:18:33 +00:00
|
|
|
if(e.key == KEY_ESCAPE && (e.flags&INPFLAG_PRESS))
|
2008-08-27 16:23:15 +00:00
|
|
|
toggle(console_type);
|
|
|
|
else
|
|
|
|
current_console()->on_input(e);
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
void CONSOLE::toggle(int type)
|
|
|
|
{
|
|
|
|
if(console_type != type && (console_state == CONSOLE_OPEN || console_state == CONSOLE_OPENING))
|
|
|
|
{
|
|
|
|
// don't toggle console, just switch what console to use
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (console_state == CONSOLE_CLOSED || console_state == CONSOLE_OPEN)
|
|
|
|
{
|
|
|
|
state_change_end = time_now()+state_change_duration;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
float progress = state_change_end-time_now();
|
|
|
|
float reversed_progress = state_change_duration-progress;
|
|
|
|
|
|
|
|
state_change_end = time_now()+reversed_progress;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (console_state == CONSOLE_CLOSED || console_state == CONSOLE_CLOSING)
|
2008-10-20 18:12:15 +00:00
|
|
|
{
|
|
|
|
inp_mouse_mode_absolute();
|
2008-08-27 16:23:15 +00:00
|
|
|
console_state = CONSOLE_OPENING;
|
2008-10-20 18:12:15 +00:00
|
|
|
}
|
2008-08-27 16:23:15 +00:00
|
|
|
else
|
2008-10-20 18:12:15 +00:00
|
|
|
{
|
|
|
|
inp_mouse_mode_relative();
|
2008-08-27 16:23:15 +00:00
|
|
|
console_state = CONSOLE_CLOSING;
|
2008-10-20 18:12:15 +00:00
|
|
|
}
|
2008-08-27 16:23:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
console_type = type;
|
|
|
|
}
|
|
|
|
|
|
|
|
void CONSOLE::con_toggle_local_console(void *result, void *user_data)
|
|
|
|
{
|
|
|
|
((CONSOLE *)user_data)->toggle(0);
|
|
|
|
}
|
|
|
|
|
|
|
|
void CONSOLE::con_toggle_remote_console(void *result, void *user_data)
|
|
|
|
{
|
|
|
|
((CONSOLE *)user_data)->toggle(1);
|
|
|
|
}
|
|
|
|
|
|
|
|
void CONSOLE::client_console_print_callback(const char *str, void *user_data)
|
|
|
|
{
|
|
|
|
((CONSOLE *)user_data)->local_console.print_line(str);
|
|
|
|
}
|
|
|
|
|
2008-08-30 08:01:29 +00:00
|
|
|
void CONSOLE::print_line(int type, const char *line)
|
|
|
|
{
|
|
|
|
if(type == 0)
|
|
|
|
local_console.print_line(line);
|
|
|
|
else if(type == 1)
|
|
|
|
remote_console.print_line(line);
|
|
|
|
}
|
|
|
|
|
2008-09-04 21:36:44 +00:00
|
|
|
void CONSOLE::on_console_init()
|
2008-08-27 16:23:15 +00:00
|
|
|
{
|
|
|
|
//
|
|
|
|
console_register_print_callback(client_console_print_callback, this);
|
|
|
|
|
|
|
|
MACRO_REGISTER_COMMAND("toggle_local_console", "", con_toggle_local_console, this);
|
|
|
|
MACRO_REGISTER_COMMAND("toggle_remote_console", "", con_toggle_remote_console, this);
|
2008-03-01 20:03:04 +00:00
|
|
|
}
|
|
|
|
|
2008-08-27 15:48:50 +00:00
|
|
|
/*
|
|
|
|
static void con_team(void *result, void *user_data)
|
2008-03-29 15:00:04 +00:00
|
|
|
{
|
2008-08-27 15:48:50 +00:00
|
|
|
send_switch_team(console_arg_int(result, 0));
|
2008-03-29 15:00:04 +00:00
|
|
|
}
|
|
|
|
|
2008-08-27 15:48:50 +00:00
|
|
|
static void con_kill(void *result, void *user_data)
|
2008-03-01 20:03:04 +00:00
|
|
|
{
|
2008-08-27 15:48:50 +00:00
|
|
|
send_kill(-1);
|
2008-03-01 20:03:04 +00:00
|
|
|
}
|
|
|
|
|
2008-08-30 08:01:29 +00:00
|
|
|
void send_kill(int client_id);
|
|
|
|
|
2008-03-01 20:03:04 +00:00
|
|
|
static void con_emote(void *result, void *user_data)
|
|
|
|
{
|
2008-03-14 23:39:52 +00:00
|
|
|
send_emoticon(console_arg_int(result, 0));
|
2008-03-01 20:03:04 +00:00
|
|
|
}
|
|
|
|
|
2008-08-27 15:48:50 +00:00
|
|
|
extern void con_chat(void *result, void *user_data);
|
|
|
|
|
2008-01-16 22:14:06 +00:00
|
|
|
void client_console_init()
|
|
|
|
{
|
2008-03-01 20:03:04 +00:00
|
|
|
//
|
2008-01-29 21:39:41 +00:00
|
|
|
MACRO_REGISTER_COMMAND("team", "i", con_team, 0x0);
|
2008-03-01 14:36:36 +00:00
|
|
|
MACRO_REGISTER_COMMAND("kill", "", con_kill, 0x0);
|
2008-03-01 20:03:04 +00:00
|
|
|
|
|
|
|
// chatting
|
|
|
|
MACRO_REGISTER_COMMAND("emote", "i", con_emote, 0);
|
2008-03-14 23:39:52 +00:00
|
|
|
MACRO_REGISTER_COMMAND("+emote", "", con_key_input_state, &emoticon_selector_active);
|
2008-01-16 22:14:06 +00:00
|
|
|
}
|
2008-08-27 15:48:50 +00:00
|
|
|
*/
|