Commit e83b0fd6 authored by Jody Goldberg's avatar Jody Goldberg Committed by Jody Goldberg

The format table nows stores pointers to StyleFormats rather than their


2000-08-21  Jody Goldberg <jgoldberg@home.com>

	* ms-excel-write.c (formats_init) : The format table nows stores
	  pointers to StyleFormats rather than their strings.
	(formats_get_format) : Ditto.
	(formats_free) : Ditto.
	(formats_get_index) : Ditto.
	(put_format) : Ditto.
	(write_format) : Ditto.

	* ms-excel-read.c (biff_format_data_lookup) : Number formats are
	  stored in XLS using the 'C' locale. eg a french user who sees
	  '# ##0,00' will actually save '#,##0.00'.
	(ms_excel_get_style_from_xf) : Kludge.  We need to actually set
	  non-borders so that things get over ridden.  The core model needs
	  improving before this can happen correctly.
	(ms_excel_get_style_from_xf) : Ditto.

	* ms-escher.c (ms_escher_read_Blip) : Remove gnorba.

	* ms-chart.c (ai) : Changes to the interface for StyleFormats.
	(ifmt) : Ditto.
	(ms_excel_chart) : Init the sheet.  Ignore BIFF_DIMENSION records for
	  now.  I have no idea what they represenent.

2000-08-20  Jody Goldberg <jgoldberg@home.com>

	* ms-excel-read.c (ms_excel_get_style_from_xf) : No need to use
	  set_text.  Set the StyleFormat directly.

2000-08-16  Jody Goldberg <jgoldberg@home.com>

	* ms-excel-util.c (init_xl_font_widths) : Tweak Times New Roman
	  to match observations.  It seems as if the size is non-linear :-(
	  We'll need another round of measurements to account for this.

2000-08-15  Jody Goldberg <jgoldberg@home.com>

	* ms-chart.c (ms_excel_chart) : conditionalize debug info.
parent 6c6a93c7
2000-08-21 Jody Goldberg <jgoldberg@home.com>
* ms-excel-write.c (formats_init) : The format table nows stores
pointers to StyleFormats rather than their strings.
(formats_get_format) : Ditto.
(formats_free) : Ditto.
(formats_get_index) : Ditto.
(put_format) : Ditto.
(write_format) : Ditto.
* ms-excel-read.c (biff_format_data_lookup) : Number formats are
stored in XLS using the 'C' locale. eg a french user who sees
'# ##0,00' will actually save '#,##0.00'.
(ms_excel_get_style_from_xf) : Kludge. We need to actually set
non-borders so that things get over ridden. The core model needs
improving before this can happen correctly.
(ms_excel_get_style_from_xf) : Ditto.
* ms-escher.c (ms_escher_read_Blip) : Remove gnorba.
* ms-chart.c (ai) : Changes to the interface for StyleFormats.
(ifmt) : Ditto.
(ms_excel_chart) : Init the sheet. Ignore BIFF_DIMENSION records for
now. I have no idea what they represenent.
2000-08-20 Jody Goldberg <jgoldberg@home.com>
* ms-excel-read.c (ms_excel_get_style_from_xf) : No need to use
set_text. Set the StyleFormat directly.
2000-08-16 Jody Goldberg <jgoldberg@home.com>
* ms-excel-util.c (init_xl_font_widths) : Tweak Times New Roman
to match observations. It seems as if the size is non-linear :-(
We'll need another round of measurements to account for this.
2000-08-15 Jody Goldberg <jgoldberg@home.com>
* ms-chart.c (ms_excel_chart) : conditionalize debug info.
2000-08-14 Jody Goldberg <jgoldberg@home.com>
* ms-excel-read.c (ms_excel_set_xf) : Improve debug info.
(ms_excel_set_xf_segment) : Ditto.
(biff_xf_data_new) : Ditto.
(ms_excel_get_style_from_xf) : Always apply the
borders. We need to apply even in the case of no border in order to
over ride previously applied defaults.
(ms_excel_read_row) : Apply default style to the entire row.
2000-08-09 Jody Goldberg <jgoldberg@home.com>
* ms-excel-read.c (ms_excel_biff_dimensions) : Move back from
......
......@@ -17,6 +17,7 @@
#include "ms-escher.h"
#include "parse-util.h"
#include "style.h"
#include "format.h"
#include "expr.h"
#include "gnumeric-chart.h"
......@@ -161,9 +162,11 @@ BC_R(ai)(ExcelChartHandler const *handle,
guint16 const fmt_index = MS_OLE_GET_GUINT16 (q->data + 4);
StyleFormat * fmt = biff_format_data_lookup (chart->wb, fmt_index);
puts ("Has Custom number format");
if (fmt != NULL)
printf ("Format = '%s';\n", fmt->format);
if (fmt != NULL) {
char * desc = style_format_as_XL (fmt, FALSE);
printf ("Format = '%s';\n", desc);
g_free (desc);
}
} else
puts ("Uses number format from data source");
......@@ -924,8 +927,12 @@ BC_R(ifmt)(ExcelChartHandler const *handle,
guint16 const fmt_index = MS_OLE_GET_GUINT16 (q->data);
StyleFormat * fmt = biff_format_data_lookup (s->wb, fmt_index);
if (fmt != NULL)
printf ("Format = '%s';\n", fmt->format);
if (fmt != NULL) {
char * desc = style_format_as_XL (fmt, FALSE);
printf ("Format = '%s';\n", desc);
g_free (desc);
}
return FALSE;
}
......@@ -2030,6 +2037,7 @@ ms_excel_chart (BiffQuery *q, MSContainer *container, MsBiffBofData *bof)
state.container.ver = bof->version;
state.depth = 0;
state.sheet = NULL;
state.prev_opcode = 0xdead; /* Invalid */
state.parent = container;
state.chart = gnumeric_chart_new ();
......@@ -2087,16 +2095,10 @@ ms_excel_chart (BiffQuery *q, MSContainer *container, MsBiffBofData *bof)
}
break;
/* The ordering seems constant at the start
* of a chart
*/
case BIFF_DIMENSIONS :
/* ms_excel_biff_dimensions (q, wb); */
break;
case BIFF_NUMBER: /* Should figure out what these are associated with */
{
printf ("%f\n", BIFF_GETDOUBLE (q->data + 6));
if (ms_excel_chart_debug > 0)
printf ("%f\n", BIFF_GETDOUBLE (q->data + 6));
break;
}
......@@ -2106,10 +2108,11 @@ ms_excel_chart (BiffQuery *q, MSContainer *container, MsBiffBofData *bof)
guint16 xf = MS_OLE_GET_GUINT16 (q->data + 4);
guint16 len = MS_OLE_GET_GUINT16 (q->data + 6);
char *label = biff_get_text (q->data + 8, len, NULL);
puts (label);
printf ("hmm, what are these values for a chart ???\n"
"row = %d, col = %d, xf = %d\n", row, col, xf);
if (ms_excel_chart_debug > 0) {
puts (label);
printf ("hmm, what are these values for a chart ???\n"
"row = %d, col = %d, xf = %d\n", row, col, xf);
}
g_free (label);
break;
}
......@@ -2118,6 +2121,7 @@ ms_excel_chart (BiffQuery *q, MSContainer *container, MsBiffBofData *bof)
ms_escher_parse (q, &state.container);
break;
case BIFF_DIMENSIONS : /* Skip for Now */
case BIFF_HEADER : /* Skip for Now */
case BIFF_FOOTER : /* Skip for Now */
case BIFF_HCENTER : /* Skip for Now */
......
......@@ -399,11 +399,7 @@ ms_escher_read_Blip (MSEscherState * state, MSEscherHeader * h)
ms_escher_get_data (state, h->offset, h->len,
header, &needs_free);
#if USING_OAF
repoid = "OAFIID:eog_image-generic:0d77ee99-ce0d-4463-94ec-99969f567f33";
#else
repoid = "embeddable:image-generic";
#endif
ms_escher_blip_new (data, h->len - header, repoid, state->container);
#ifndef NO_DEBUG_EXCEL
......
......@@ -23,6 +23,7 @@
#include "ranges.h"
#include "expr-name.h"
#include "style.h"
#include "format.h"
#include "eval.h"
#include "cell-comment.h"
#include "application.h"
......@@ -755,7 +756,7 @@ biff_format_data_lookup (ExcelWorkbook *wb, guint16 idx)
printf ("Unknown format: 0x%x\n", idx);
if (ans)
return style_format_new (ans);
return style_format_new_XL (ans, FALSE);
else
return NULL;
}
......@@ -1230,10 +1231,8 @@ ms_excel_get_style_from_xf (ExcelSheet *sheet, guint16 xfidx)
/* If we've already done the conversion use the cached style */
if (xf->mstyle[0] != NULL) {
mstyle_ref (xf->mstyle[0]);
if (xf->mstyle[1] != NULL)
mstyle_ref (xf->mstyle[1]);
if (xf->mstyle[2] != NULL)
mstyle_ref (xf->mstyle[2]);
mstyle_ref (xf->mstyle[1]);
mstyle_ref (xf->mstyle[2]);
return xf->mstyle;
}
......@@ -1242,7 +1241,7 @@ ms_excel_get_style_from_xf (ExcelSheet *sheet, guint16 xfidx)
/* Format */
if (xf->style_format)
mstyle_set_format_text (mstyle, xf->style_format->format);
mstyle_set_format (mstyle, xf->style_format);
/* Alignment */
mstyle_set_align_v (mstyle, xf->valign);
......@@ -1403,6 +1402,8 @@ ms_excel_get_style_from_xf (ExcelSheet *sheet, guint16 xfidx)
/* Borders */
for (i = 0; i < STYLE_ORIENT_MAX; i++) {
MStyle *tmp = mstyle;
MStyleElementType t;
int const color_index = xf->border_color[i];
/* Handle auto colours */
StyleColor *color = (color_index == 64 || color_index == 65 || color_index == 127)
......@@ -1413,23 +1414,19 @@ ms_excel_get_style_from_xf (ExcelSheet *sheet, guint16 xfidx)
? style_color_black ()
: ms_excel_palette_get (sheet->wb->palette,
color_index);
if (xf->border_type [i] != STYLE_BORDER_NONE) {
MStyle *tmp = mstyle;
MStyleElementType t;
if (i == STYLE_BOTTOM) {
t = MSTYLE_BORDER_TOP;
mstyle_ref (((BiffXFData *)xf)->mstyle[1] = tmp = mstyle_new());
} else if (i == STYLE_RIGHT) {
t = MSTYLE_BORDER_LEFT;
mstyle_ref (((BiffXFData *)xf)->mstyle[2] = tmp = mstyle_new());
} else
t = MSTYLE_BORDER_TOP + i;
mstyle_set_border (tmp, t,
style_border_fetch (xf->border_type [i],
color, t));
}
if (i == STYLE_BOTTOM) {
t = MSTYLE_BORDER_TOP;
mstyle_ref (((BiffXFData *)xf)->mstyle[1] = tmp = mstyle_new());
} else if (i == STYLE_RIGHT) {
t = MSTYLE_BORDER_LEFT;
mstyle_ref (((BiffXFData *)xf)->mstyle[2] = tmp = mstyle_new());
} else
t = MSTYLE_BORDER_TOP + i;
mstyle_set_border (tmp, t,
style_border_fetch (xf->border_type [i],
color, t));
}
/* Set the cache (const_cast) */
......@@ -1457,6 +1454,10 @@ ms_excel_set_xf (ExcelSheet *sheet, int col, int row, guint16 xfidx)
printf ("%s!%s%d\n", sheet->gnum_sheet->name_unquoted,
col_name(col), row+1);
}
if (ms_excel_read_debug > 2) {
printf ("%s!%s%d = xf(%d)\n", sheet->gnum_sheet->name_unquoted,
col_name(col), row+1, xfidx);
}
#endif
range.start.col = col;
......@@ -1526,6 +1527,12 @@ ms_excel_set_xf_segment (ExcelSheet *sheet, int start_col, int end_col, int row,
range.end.row = row;
sheet_style_attach (sheet->gnum_sheet, range, mstyle[0]);
#ifndef NO_DEBUG_EXCEL
if (ms_excel_read_debug > 2) {
range_dump (&range);
fprintf (stderr, " = xf(%d)\n", xfidx);
}
#endif
if (mstyle[1] != NULL) {
range.start.col = start_col;
range.start.row = row+1;
......@@ -1867,9 +1874,13 @@ biff_xf_data_new (ExcelWorkbook *wb, BiffQuery *q, MsBiffVersion ver)
g_ptr_array_add (wb->XF_cell_records, xf);
#ifndef NO_DEBUG_EXCEL
if (ms_excel_read_debug > 2) {
printf ("XF : Font %d, Format %d, Fore %d, Back %d\n",
xf->font_idx, xf->format_idx,
xf->pat_foregnd_col, xf->pat_backgnd_col);
printf ("XF(%d) : Font %d, Format %d, Fore %d, Back %d, Pattern = %d\n",
wb->XF_cell_records->len,
xf->font_idx,
xf->format_idx,
xf->pat_foregnd_col,
xf->pat_backgnd_col,
xf->fill_pattern_idx);
}
#endif
}
......@@ -2546,6 +2557,7 @@ ms_excel_workbook_new (MsBiffVersion ver)
ans->container.ver = ver;
ans->extern_sheets = NULL;
ans->num_extern_sheets = 0;
ans->gnum_wb = NULL;
/* Boundsheet data hashed twice */
ans->boundsheet_data_by_stream = g_hash_table_new ((GHashFunc)biff_guint32_hash,
......@@ -2940,8 +2952,13 @@ static void
ms_excel_read_row (BiffQuery *q, ExcelSheet *sheet)
{
const guint16 row = MS_OLE_GET_GUINT16(q->data);
#if 0
/* Unnecessary info for now.
* FIXME : do we want to preallocate baed on this info ?
*/
const guint16 start_col = MS_OLE_GET_GUINT16(q->data+2);
const guint16 end_col = MS_OLE_GET_GUINT16(q->data+4) - 1;
#endif
const guint16 height = MS_OLE_GET_GUINT16(q->data+6);
const guint16 flags = MS_OLE_GET_GUINT16(q->data+12);
const guint16 flags2 = MS_OLE_GET_GUINT16(q->data+14);
......@@ -2976,19 +2993,17 @@ ms_excel_read_row (BiffQuery *q, ExcelSheet *sheet)
sheet_row_set_size_pts (sheet->gnum_sheet, row, hu, TRUE);
}
/* FIXME : We should associate a style region with the row segment */
/* FIXME : I am not clear on the difference between collapsed, and dyn 0
* Use both for now */
if (flags & 0x30)
col_row_set_visibility (sheet->gnum_sheet, FALSE, FALSE, row, row);
if (flags & 0x80) {
ms_excel_set_xf_segment (sheet, 0, SHEET_MAX_COLS, row, xf);
#ifndef NO_DEBUG_EXCEL
if (ms_excel_read_debug > 1) {
printf ("row %d has flags 0x%x a default style %hd from col %s - ",
row+1, flags, xf, col_name(start_col));
printf ("%s;\n", col_name(end_col));
printf ("row %d has flags 0x%x a default style %hd;\n",
row+1, flags, xf);
}
#endif
}
......
......@@ -242,7 +242,11 @@ init_xl_font_widths ()
{ 93, 100, "Tahoma" },
{ 50, 54, "Terminal" },
{ 86, 92, "Times" },
{ 86, 92, "Times New Roman" },
/* TODO : actual measurement was 86, but that was too big when
* columns with 10pt fonts. Figure out why ? (test case aksjefon.xls)
*/
{ 83, 92, "Times New Roman" },
{ 91, 97, "Times New Roman MT Extra Bold" },
{ 90, 96, "Trebuchet MS" },
{ 109, 117, "Verdana" },
......
......@@ -37,11 +37,13 @@
#include "cell.h"
#include "sheet-object.h"
#include "style.h"
#include "format.h"
#include "main.h"
#include "parse-util.h"
#include "print-info.h"
#include "command-context.h"
#include "workbook.h"
#include "expr.h"
#include <libole2/ms-ole.h>
#include "ms-biff.h"
......@@ -764,7 +766,7 @@ excel_font_to_string (const ExcelFont *f)
int nused;
nused = snprintf (buf, sizeof buf, "%s, %g", sf->font_name, sf->size);
if (nused < sizeof buf && sf->is_bold)
nused += snprintf (buf + nused, sizeof buf - nused, ", %s",
"bold");
......@@ -812,7 +814,7 @@ excel_font_new (MStyle *st)
f->color = style_color_to_int (c);
f->underline = mstyle_get_font_uline (st);
f->strikethrough = mstyle_get_font_strike (st);
return f;
}
......@@ -1129,7 +1131,7 @@ formats_init (ExcelWorkbook *wb)
wb->formats = g_new (Formats, 1);
wb->formats->two_way_table
= two_way_table_new (g_str_hash, g_str_equal, 0);
= two_way_table_new (g_direct_hash, g_direct_equal, 0);
formats_put_magic (wb);
}
......@@ -1138,12 +1140,12 @@ formats_init (ExcelWorkbook *wb)
/**
* Get a format, given index
**/
static char *
static StyleFormat const *
formats_get_format (ExcelWorkbook *wb, gint idx)
{
TwoWayTable *twt = wb->formats->two_way_table;
return (char *) two_way_table_idx_to_key (twt, idx);
return two_way_table_idx_to_key (twt, idx);
}
/**
......@@ -1153,19 +1155,12 @@ static void
formats_free (ExcelWorkbook *wb)
{
TwoWayTable *twt;
int i;
char *format;
if (wb && wb->formats) {
twt = wb->formats->two_way_table;
if (twt) {
for (i = 0; i < twt->idx_to_key->len; i++) {
format = formats_get_format (wb,
i + twt->base);
g_free (format);
}
if (twt)
two_way_table_free (twt);
}
g_free (wb->formats);
wb->formats = NULL;
}
......@@ -1175,7 +1170,7 @@ formats_free (ExcelWorkbook *wb)
* Get index of a format
**/
static gint
formats_get_index (ExcelWorkbook *wb, const char *format)
formats_get_index (ExcelWorkbook *wb, StyleFormat const *format)
{
TwoWayTable *twt = wb->formats->two_way_table;
return two_way_table_key_to_idx (twt, format);
......@@ -1189,10 +1184,9 @@ formats_get_index (ExcelWorkbook *wb, const char *format)
static void
put_format (MStyle *mstyle, gconstpointer dummy, ExcelWorkbook *wb)
{
StyleFormat *sf = mstyle_get_format (mstyle);
StyleFormat const *fmt = mstyle_get_format (mstyle);
two_way_table_put (wb->formats->two_way_table,
g_strdup (sf->format), TRUE,
(gpointer)fmt, TRUE,
(AfterPutFunc) after_put_format,
"Found unique format %d - %s\n");
}
......@@ -1224,7 +1218,9 @@ static void
write_format (BiffPut *bp, ExcelWorkbook *wb, int fidx)
{
guint8 data[64];
char *format = formats_get_format(wb, fidx);
StyleFormat const *sf = formats_get_format(wb, fidx);
char *format = style_format_as_XL (sf, FALSE);
#ifndef NO_DEBUG_EXCEL
if (ms_excel_write_debug > 1) {
......@@ -1242,6 +1238,7 @@ write_format (BiffPut *bp, ExcelWorkbook *wb, int fidx)
biff_put_text (bp, format, MS_BIFF_V7, TRUE, AS_PER_VER);
ms_biff_put_commit (bp);
g_free (format);
}
/**
......@@ -1435,8 +1432,8 @@ pre_cell (gconstpointer dummy, Cell *cell, ExcelSheet *sheet)
g_return_if_fail (cell != NULL);
g_return_if_fail (sheet != NULL);
col = cell->col_info->pos;
row = cell->row_info->pos;
col = cell->pos.col;
row = cell->pos.row;
#ifndef NO_DEBUG_EXCEL
if (ms_excel_write_debug > 3) {
......@@ -1813,9 +1810,14 @@ log_xf_data (ExcelWorkbook *wb, BiffXFData *xfd, int idx)
int i;
ExcelFont *f = fonts_get_font (wb, xfd->font_idx);
/* Formats are saved using the 'C' locale number format */
char * desc = style_format_as_XL (xfd->style_format, FALSE);
printf ("Writing xf 0x%x : font 0x%x (%s), format 0x%x (%s)\n",
idx, xfd->font_idx, excel_font_to_string (f),
xfd->format_idx, xfd->style_format->format);
xfd->format_idx, desc);
g_free (desc);
printf (" hor align 0x%x, ver align 0x%x, wrap %s\n",
xfd->halign, xfd->valign, xfd->wrap ? "on" : "off");
printf (" fill fg color idx 0x%x, fill bg color idx 0x%x"
......@@ -1875,7 +1877,7 @@ build_xf_data (ExcelWorkbook *wb, BiffXFData *xfd, MStyle *st)
xfd->font_idx = fonts_get_index (wb, f);
excel_font_free (f);
xfd->style_format = mstyle_get_format (st);
xfd->format_idx = formats_get_index (wb, xfd->style_format->format);
xfd->format_idx = formats_get_index (wb, xfd->style_format);
/* Hidden and locked - we don't have those yet */
xfd->hidden = MS_BIFF_H_VISIBLE;
......@@ -2365,8 +2367,8 @@ write_formula (BiffPut *bp, ExcelSheet *sheet, const Cell *cell, gint16 xf)
g_return_if_fail (cell_has_expr (cell));
g_return_if_fail (cell->value);
col = cell->col_info->pos;
row = cell->row_info->pos;
col = cell->pos.col;
row = cell->pos.row;
v = cell->value;
/* See: S59D8F.HTM */
......@@ -2451,8 +2453,8 @@ write_cell (BiffPut *bp, ExcelSheet *sheet, const ExcelCell *cell)
g_return_if_fail (sheet);
gnum_cell = cell->gnum_cell;
col = gnum_cell->col_info->pos;
row = gnum_cell->row_info->pos;
col = gnum_cell->pos.col;
row = gnum_cell->pos.row;
#ifndef NO_DEBUG_EXCEL
if (ms_excel_write_debug > 2) {
......@@ -2461,7 +2463,7 @@ write_cell (BiffPut *bp, ExcelSheet *sheet, const ExcelCell *cell)
cell_name (gnum_cell),
(cell_has_expr (gnum_cell) ?
expr_tree_as_string (gnum_cell->u.expression,
parse_pos_init_cell (&tmp, gnum_cell)) :
parse_pos_init_cell (&tmp, gnum_cell)) :
"none"),
(gnum_cell->value ?
value_get_as_string (gnum_cell->value) : "empty"),
......@@ -2624,7 +2626,7 @@ init_base_char_width_for_write (ExcelSheet *sheet)
excel_font_free (f);
}
}
#ifndef NO_DEBUG_EXCEL
if (ms_excel_write_debug > 1)
printf ("Font for column sizing: %s %.1f\n", name, size);
......@@ -3257,7 +3259,7 @@ new_sheet (ExcelWorkbook *wb, Sheet *value)
ms_formula_cache_init (sheet);
sheet->cell_used_map = cell_used_map_new (sheet);
sheet->cells = g_new (ExcelCell *, sheet->maxy);
for (p = sheet->cells, pmax = p + sheet->maxy; p < pmax; p++)
*p = g_new0 (ExcelCell, sheet->maxx);
......@@ -3295,7 +3297,7 @@ static int
pre_pass (CommandContext *context, ExcelWorkbook *wb)
{
int ret = 0;
/* The default style first */
put_mstyle (wb, wb->xf->default_style);
/* Its font and format */
......@@ -3321,7 +3323,7 @@ static void
free_workbook (ExcelWorkbook *wb)
{
int lp;
fonts_free (wb);
formats_free (wb);
palette_free (wb);
......@@ -3431,7 +3433,7 @@ ms_excel_check_write (CommandContext *context, void **state, Workbook *gwb,
g_return_val_if_fail (ver >= MS_BIFF_V7, -1);
*state = wb;
wb->ver = ver;
wb->gnum_wb = gwb;
wb->sheets = g_ptr_array_new ();
......
......@@ -254,6 +254,11 @@ ms_obj_read_biff8_obj (BiffQuery *q, MSContainer *container, MSObj *obj)
break;
case GR_SCROLLBAR_FORMULA :
/* A touch of spelunking suggests that
* 0x06 uint16 == first visible element (0 based)
* 0x12 uint16 == number of elements
* 0x14 uint16 == current element (1 based)
*/
ms_obj_dump (data, len, "ScrollbarFmla");
break;
......@@ -274,8 +279,10 @@ ms_obj_read_biff8_obj (BiffQuery *q, MSContainer *container, MSObj *obj)
break;
case GR_LISTBOX_DATA :
{
ms_obj_dump (data, len, "ListBoxData");
break;
}
case GR_CHECKBOX_FORMULA :
{
......
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