Fl_Html_View - a new HTML widget and framework for FLTK
The purpose of this widget is a replacement of limited and rather buggy Fl_Help_View widget
and to add new HTML capabilities for FLTK.
The code does not depend on any external library and although the classes and functions have
Fl_* prefix, most of the code is fltk-independent and can be used with other drawing systems.
The purpose is not to write a web-browser but to have a viewer with much improved rendering
and navigation capabilities than original Fl_Help_View
. It is also extensible so that
new features and tags can be easily added keeping binary compatibility (that is without
the need of recompilation of the library - any existing Fl_Html_Wiew
source files).
The library also adds support for HTML Fl_Labeltype so that (const char *) strings can be
interpreted and rendered as HTML for all widgets labels. The original Fl_Help_View
cannot be
used for that purpose because of its hard-codded implementation and hacky nature.
HTML Features:
- Drop-in replacement for Fl_Help_View widget
The Fl_Html_View widget is source-compatible with Fl_Help_View (the API/functions is its superset).
It also supports all tags, attributes of Fl_Help_View - and much more.
- Additional tags and attributes
Additional useful tags like <sub> <sup> (Osubscript Osuperscript) and more...
see currently supported HTML tags and attributes
- Comprehensive document framework
The framework consists of several classes which most of them
are FLTK-independent (Fl_Html_Tokenizer, Fl_Xml_Parser, Fl_Html_Parser, Fl_Html_Formatter, Fl_Html_Object
and all its subclasses and abstract base class Fl_Html_Drawing_Device_). The only fltk-specific is
the Fl_Html_Drawing_Device class with concrete implementation of drawing and measurement functions,
and the Fl_Html_View
widget itself.
- Exensibility
The user can define its own document properties by subclassing Fl_Html_Object and overriding bunch of
virtual functions such as init_format(), format() draw(). Such a class definition can be then "plugged in"
to the parser-creation table by adding a pair of tag-name and object-creation-function to this table. Such addition
either adds new functionality or "shadows" previous definition adding room for future improvements -
all with binary compatibility
The Parser can be extended too. For instance Fl_Html_Parser is a subclass of Fl_Xml_Parser changing
its properties to remove case-sensitivity, add a possibility of creation of "unclosed" tags with their proper
automatic closing (p, li, dt, dd, tr, td, th...), possibility to parse unquoted attribute values and other usual
HTML sloppiness.
Similarly the "Special character" table (&xxx;) can be extended (or modified) by adding new
"translation" pairs although the standard table already comprises nearly complete set with more than
110 characters. Apart from that numeric (both decadic and hexadecimal) codepoint specification can be used.
- Proper text formatting of the text and inlined objects (images or even inlined-tables)
A single word can consist of different fonts and still be consistent (that is no breaking
at the end of the line). The paragraphs can be left/right/justify aligned. Proper line spacing is
always calculated to avoid collision even if the font changes or the text contains differently sized alien
objects (images or inlined-tables) .
Different fonts normally have "baseline" vertical align, alien objects can be top, middle or bottom aligned.
- Partial CSS support within tags's
style
attributes
For the moment CSS lists of properties/values are supported only within tag's style
attribute
which allow to add many useful properties otherwise unavailable as any other attribute
(keeping full compatibility with standard HTML and CSS syntax). At later stage simplified "global" styles
(both external and internal within the document) will be supported, referring to tag name,
class or id and with possibility to specify all "stylable" attributes and properties.
- Proper table formatting and comprehensive set of features for the
<table>
,
<tr>
, <td>
and <th>
tags
Great focuss was taken for proper formatting and rendering of the tables as tables are main formatting
elements in "Classic HTML" documents. The features include:
- Each cell is a properly formatted "nested" document with possibility to use all tags.
- The tables can be nested too (this is a direct result of proper document nesting).
- Support for both
colspan
and rowspan
attributes
- Support for proper dynamic resizing + proper support for
width
and height
attributes.
The width and height can have either absolute (in pixels) or percentage specification.
For cells the percentage value is related to the table, for the table it is relative to the "outer object"
(the encapsulating cell if it is nested table or the document if it is top-level table). Such percentual
specification influences the object itself or containing parent (usually if the object can't be shrinked
enough to accommodate its content). If the width is missing the objects could be resized to the maximum with
of properly unwrapped content. The tables can have complicates specification of different cells with mixed static,
percentual or pure dynamic (none) specifications on very complex tables with complicated "colspan" and "rowspan"
cell placements. It properly renders even tables where big browsers like Firefox or IE have problems ;)
- Support for various properties like cellspacing, cellpadding, rules, borders, margins etc
- Tables can be inlined in the text flow if "display:inline" or "display:inline-table" is within style
attribute (use proper "inline-table" version, if you need compatibility with older IE use both).
- Zoomed rendering
The view can be zoomed by any factor. For Fl_Help_View widgets
use "FL_COMMAND + scrollwheel"
to change zooming. Note that there might be initial lag caused not by the speed of Fl_Html_View
itself
but by fltk loading new fonts with new sizes. Once fonts are loaded, zooming changes are fast.
- The document can be displayed with different drawing device that it was formatted with.
This gives possibility for instance to generate "Print Prewiew" where all elements are placed exactly like on the other device (a page).
- Support for Image "Data URI" scheme when images are inlined directly and base64 encoded in the
href
attribute
At the moment only JPEG and PNG are supported as data-uri images, GIF will be added when a constructor from in-memory data will be added to
the class Fl_GIF_Image in fltk (as they are mow for Fl_PNG_Image and Fl_JPEG_Image classes).
- Speed
The document is parsed only once when it is loaded. After that only generated binary tree-like structure of the objects is kept around.
More: upon load (within init_format() phase) a lot of expensive calculation is performed only once and do not need to performed again unless
user wants to change base font or base font size.
During rendering each element keeps the dimension of the "bounding box" of its children so that fast recursive rendering can be performed
upon only to those parts (groups, elements) which has crossection with the viewing port. In the future "artificial" subgrouping (and ungrouping) will be added to
further speed up rendering in rare cases when document contains hundred of thousands elements at the same level (like words) as "direct siblings".
- Lightweight
The whole codebase (including all headers) is still way below 10 000 lines
- Selection, Copy & Paste
When dragging the mouse during selection outside the viewing area, the Fl_Html_View automatically scrolls so that also text outside area can be selected.
Currently only "whole words can be selected, similar as for Fl_Help_View, also only "plain text" is/can be copied to clipboard 0 and 1.
- Implementation of
Fl_Labeltype
drawing and measurement functions
Those functions be used to register new labeltype using Fl::set_label() function, user can also use FL_HTML_LABEL_SRC
and
FL_HTML_LABEL_CACHE
macros which upon first use register these functions automatically (as l5 and 16).
There are two labeltypes due to speed concerns:
Normally the html-formatted string would need to be parsed and formatted each time the label is drawn - and this is what FL_HTML_LABEL_SRC
does.
To speed-up redraw process there is additional labeltype FL_HTML_LABEL_CACHE
, in such a case the string is parsed and formatted
only once until something changes (like label font or size, formatting width, FL_ALIGN_WRAP or the string itself). However in this case not
(const char *) string is assigned as a widget label but pointer to a Fl_Html_Label_Cache
instance and drawing/measurement
functions treat this pointer accordingly. There is a helper function fl_html_label(Fl_Widget *, Fl_Html_Label_Cache *) which helps with
type-casting and assignment, however it would be useful if in the future FLTK would support label caching natively: there is shown possible implementation
in the header Fl_Html_View.H
which would even not require any additional storage pointer - destructor of Fl_Widget and label() functions
would need to be reimplemented so that label returns proper string, and new string asignment destructor properly cleans the cache. In this implementation
current "copied label" is just a special case of label cache with internally copied string.
- Currently supported HTML tags and attributes
Unsupported tags are quietly ignored but the children are rendered as normal. Such a tag is present in the object-tree as an instance
of an "unknown" tag class and its name can be inspected.
The pixels
specification are logical pixels sublect to zooming.
Various colors can be specified either as hexadecimal #RRGGBB
value or as red, white, cyan, silver, blue, gray, grey, darkblue, black,
lightblue, orange, purple, brown, yellow, maroon, lime, green, magenta or olive.
- <p> (can be open, automatically closed by next block-level tag)
- align = left/right/center/justify
- <ul>
- type = dics/square/circle
- style = "padding-left:pixels"
- <ol>
- type = 1/A/a
- start = "number" or an ASCII character
- style = "padding-left:pixels" (unlike other browsers if the space is insufficient the padding is calculated as such that it accommodates
the widest bullet without any collision (for all <li> the same) - that means
it is safe to put "0" and let the formatter to calculate sufficient padding with proper alignment)
- <li> (can be open, automatically closed by next <li>,
</ul> or </ol>
)
- value = "number" or an ASCII character (valid only for <li> within <ol> tags)
- <dl>
- <dt> (can be open, automatically closed by next <dt>,
<dd> or </dl>
)
- <dd> (can be open, automatically closed by next <dt>,
<dd> or </dl>
)
- style = "margin-left:pixels"
- <body> (does not need to be present)
- bgcolor = color
- link = color
- text = color
- <pre>
- <span> At the moment it does not do anything but might be useful for grouping
- <div> Similar as above but causes new lines
- <meta> (unclosed and ignored)
- <head> (does not need to be present, everything inside except title is ignored)
- <title>
- <h1>, <h2>, <h3>, <h4>, <h5>, <h6>
- align = left/right/center/justify
- <br> (always self-closing, equivalent to <br/>)
- style = "clear:left/right/both; page-break-after:always" (use "clear:both" and "page-break-after:always" if you want clean page break when printing)
- <hr> (always self-closing, equivalent to <hr/>)
- size = pixels
- width = pixels
- align = left/center/right
- noshade
- <u>
- <b>
- <i>
- <em>
- <kbd>
- <tt>
- <var>
- <font>
- face = helvetica/courier/times/symbol/arial/sans/serif
- size = absolute or relative (+/-1...7)
- color = color
- <sub> Subscript(O2)
- <sup> Superscript(E = m c2)
- <center>
- <a> (can be open)
- href = [url][#anchor]
- name = anchor
- style = "text-decoration:none"
- <img> (self-closing)
- src = url or data:image/TYPE;base64,BaSE64enCOdED ImaGEdAta...
- align = left/right/top/middle/bottom
- alt = name
- width = pixels or percents%
- height = pixels
- hspace = pixels
- vspace = pixels
- border = pixels
- <table>
- style = "margin:pixels; display:inline/inline-table; vertical-align:top/middle/bottom/baseline"
- align = left/right/center
- width = pixels or percents%
- height = pixels or percents%
- border [= pixels]
- cellpadding = pixels
- cellspacing = pixels
- bgcolor = color
- bordercolor = color
- rules = all/columns/rows
- <tr> (can be open)
- <td>, <th> (
th
has content bold and center-aligned by default, both can be open)
- bgcolor = color
- width = pixels or percents%
- height = pixels or percents%
- align = left/center/right/justify
- valign = top/middle/bottom/baseline
- colspan = number
- rowspan = number
- nowrap
Compilation & Usage
Just compile all .cxx files from html/src
directory and include the header html/FL/Fl_Html_View.H
wherever uou want to use the widget or FL_HTML_LABEL* labeltype.
You can start with html/test/main.cxx
as an example code which renders this page.
Todo & future work
- Implementation of page-oriented formatting, print preview and print support
Page-oriented formatting would avoid splitting of the rows, images, and some composite elements (like table rows or even the whole tables -
as long as they fit within a single page). The print-preview would then format the document using particular printing device but display the
result on the screen.
- "Hardening" of the code so that no matter how badly is the document written it would not cause the crash.
Theoretically a badly-written document should never crash the application.
Although the parsing errors are caught as soon as possible during tokenizing and parsing, there still might be cases when a badly written or malicious document
could cause a crash. Apart from that there could be memory related crashes:
- Too large documents which do not fit in the (heap) memory
If a document is loaded from a disk, for parsing simplicity and speed the file is first loaded into the memory as a whole and then it is parsed.
There could be some "(f)stat" done before loading, however the document can load additional images which would need to be checked too.
Additionally during parsing a tree of binary elements is created so there must be a space for it - overall not sure
if it is worth the effort (apart from file-size checking).
- Stack-memory crash
For speed and simplicity the drawing and formatting is recursively based: for instance <font> tag first stores current font within function,
changes the font, draws the children and then resets font
to its original value. Although for normal documents this is not a problem (even most complicated documents have usually only several levels of tag-nesting),
malicious documents written "for that purpose" which include tens of thousand ofnested tags could cause a crash. This could be easily checked
during parsing so in the future I will limit the maximum levels to user-configurable value (default 640 - this certainly should be enough for everybody)
Anyway Fl_Html_View
at the moment opens only local or local-network files (other links in default browser using fl_open_uri()) so this should
not be a problem.
- Improvement of the CSS styling support
This will probably be only a subset of the ""Cascading Style Sheets" features with CSS resolving depending on tag's name, "class" or "id" but not combination (due concerns for parsing speed and precedence resolution,
to be honest W3C did quite some messy job with CSS) but with full syntax compatibility so that any document using Fl_Help_View-only features will be rendered similarly
in any other browser
- Special "Fltk-Widget" tags
Such tags would function as containers to which any FLTK widget or group could be assigned - with full event delivery to those widgets. In such a case HTML page could function as
a description for powerful widget layout engine (especially thanks to tables with all colspans/rowspans and their powerful layout and resizing capabilities).
There are several possible approaches how it could work, eg either:
- During parsing the widget would be created according to some widget-creation able; or
- A page would be applied and operate on a list or array of existig widgets, functioning as sort-of presentational "style sheet". In such a case it would be overriding
resizing of the widgets (from top to bottom) and maybe some other widget "layout" properties and render rest of the page content in-between of those widgets.
Some testing:
TABLE align=left style=margin:5 cellspacing=0
|
Lorem ipsum | Quam nullam et
|
TABLE align=right style=margin:5 cellspacing=0
|
Lorem ipsum | Quam nullam et
|
Testing text-flow with various floats: this is a "justify-aligned" paragraph which at the beginning includes one left and one right-aligned table. After English text there is included right-aligned image
(for King Crimson fans: "Discipline" cover, graphics created by Steve Ball and reusable under CC 3.0 SA) with 10% width specification and another left-aligned table.
Further down a greyed-out "Lorem Ipsum" text is included with an inlined table and an inlined image.
Another left-table
|
Lorem ipsum | Quam nullam et
|
Lorem ipsum dolor sit amet, sed vel lobortis, integer ab veniam, mi nec pharetra nec at eligendi volutpat.
Dolor a erat sed, lectus dolor, ridiculus eu orci
vulputate eros lacinia.
Quis dictum neque nisl non nonummy nonummy, etiam faucibus nunc, dolor vestibulum eu nibh augue amet, qui leo quam.
Sed nec consectetur velit. Proin vel est sit amet lorem ultrices rhoncus. Maecenas risus velit, dapibus sed eleifend condimentum, sagittis nec augue. Nunc aliquam venenatis nisi nec cursus.
At the end of the paragrapg there is a <br style="clear:both"/>
tag so that following content continues after all left and right-aligned floats.
A nested table properties: | border align = right
| width = 50% | style = "margin: 5"
|
This table is "pure" dynamic with no width or height specifications of the cells
with exeption of the nested table to the right in this cell: The table has the width specified as 50% so it occupies half-width of the cell
Cell: colspan=2 align=justify
| Pro ex alia constituto | Ne eam quot fabulas | Vis illud fabulas | Ius, nobis fabulas |
Cell: align=center
| A cell with rowspan 2 This is second line in the cell | At mei illum iisque |
This is another nested table | Amet oratio erroribus nec et | In sea errem dolor soleat. |
Ei autem scriptorem | Fabulas singulis |
This text is right and bottom aligned | Eos ea quem offendit interpretaris. |
Pri habemus repudiare | Image to the left occupies 40% of the cell width |
Fierent constituto ex sed, | Constituto ex sed | Pro no inermis
|
|
Align right | Meis libris numquam | Qui ut augue
|
This is title
This is heading 1
This is heading 2
This is heading 3
This is heading 4
This is heading 5
This is heading 6
Some underlinedned text and an image.
- This is a tex after <dt> tag (within <dl>)
- This is <dd> text
Second line after <br>...
- Another <dt> text followed by two <dd> lines.
- Scelerisque id orci, quam nulla sit felis in leo, inceptos vitae diam congue nullam pharetra.
- Habitant libero sit tortor, ultrices nonummy amet cubilia orci ac.
Some nested lists...
- A bullet list
- In lorem iaculis erat et ut, dolor consectetuer ac suscipit et mattis viverra, et nascetur sit.
- Tempus pellentesque officia placerat odio, turpis augue euismod suspendisse rhoncus.
- Nested bullet list (notice automatic change of bullet type relative to parent - if not otherwise specified)
- Magna non dui nec nibh luctus, magna amet ante fusce.
- Ut nulla a posuere ornare, mauris aliquet congue tempor massa donec ultricies.
- Vivamus accumsan luctus a, eget arcu nec rutrum vitae eos, fringilla netus luctus in, velit donec sociis ultricies, justo nonummy nibh in ut nec.
- Et amet eu consequat sit, proin massa quam, cras nulla nulla ligula nulla, erat id nam sem accumsan totam.
-
- Another third-level bullet list, this time all content inside of <li> tags (notice bullet right in front of this line)
- Eget montes quis reprehenderit ullamcorper. Ac nec libero eu id nibh suspendisse, semper et risus amet tortor leo vivamus, rhoncus sem hymenaeos, fringilla sed.
- Urna est nulla commodo vehicula, orci tortor conubia vestibulum, vitae non rutrum wisi, curabitur pede urna pede urna dolor pharetra, leo eget lectus ante per.
- Pellentesque a euismod quisquam scelerisque arcu, at maecenas augue, ultrices
- Sed lectus, consequat velit ultrices sit, porta at lorem ac arcu. Donec inceptos integer.
- Suspendisse purus vehicula elit eget primis, pellentesque est eros orci nullam mauris placerat, quis convallis, volutpat sociosqu, ac nec neque risus.
- Viverra condimentum nec eu donec, lorem quidem vitae suspendisse, vestibulum et ac lorem tincidunt, blandit lectus vel nulla.
- Dictum porta odio lorem nam eros, suspendisse morbi.
- Nibh qui orci aenean, nulla pede dolor dictumst imperdiet aptent, lobortis nisl.
- Sed inceptos pellentesque, amet imperdiet, wisi pretium felis placerat, eros eu posuere vel integer imperdiet, donec congue potenti faucibus morbi massa non.
- Per arcu auctor bibendum viverra nisl, amet nulla, malesuada sem metus lorem elit a ac.
Some enumerated lists...
- Tempor et suspendisse sit nonummy ac proin, sed quam neque pede donec justo, nam aliquet nascetur cras laboriosam.
- Consequat nibh morbi urna mauris euismod at, morbi fermentum hendrerit lorem phasellus, vulputate lobortis lobortis sagittis et bibendum nonummy, interdum metus
- Sed vel, ac pede diam ipsa nec quam erat, ac urna viverra eleifend et aliquam sed, pellentesque suspendisse lobortis condimentum sed.
- Nested, letter-enumerated list
- Scelerisque amet at fringilla, justo ac lacus lobortis in deserunt commodo.
- Pretium lacus molestie. Erat dolor ipsum est praesent lobortis lorem, gravida amet malesuada sit sagittis, malesuada nullam metus risus pharetra fringilla tincidunt.
- Quis vel accumsan mollis ut. Elit metus ut sem at mi turpis, aliquam class turpis, fames morbi sit sollicitudin, ligula libero.
- Third level list, this time capital letter enumerated
- Scelerisque amet at fringilla, justo ac lacus lobortis in deserunt commodo.
- Pretium lacus molestie. Erat dolor ipsum est praesent lobortis lorem, gravida amet malesuada sit sagittis, malesuada nullam metus risus pharetra fringilla tincidunt.
- Quis vel accumsan mollis ut. Elit metus ut sem at mi turpis, aliquam class turpis, fames morbi sit sollicitudin, ligula libero.
- Pretium lacus molestie. Erat dolor ipsum est praesent lobortis lorem, gravida amet malesuada sit sagittis, malesuada nullam metus risus pharetra fringilla tincidunt.
- Quis vel accumsan mollis ut. Elit metus ut sem at mi turpis, aliquam class turpis, fames morbi sit sollicitudin, ligula libero.
- Tempor et suspendisse sit nonummy ac proin, sed quam neque pede donec justo, nam aliquet nascetur cras laboriosam.
- Consequat nibh morbi urna mauris euismod at, morbi fermentum hendrerit lorem phasellus, vulputate lobortis lobortis sagittis et bibendum nonummy, interdum metus
- Sed vel, ac pede diam ipsa nec quam erat, ac urna viverra eleifend et aliquam sed, pellentesque suspendisse lobortis condimentum sed.
Similar lists as above but with small padding (style="padding-left:5")
Other browsers might cause collisions if padding is smaller than bullet sizes... Impossibility of element collisions in Fl_Help_View can be called either feature or bug but its not gonna change
just to match rendering exactly as in the other browsers.
- A bullet list
- In lorem iaculis erat et ut, dolor consectetuer ac suscipit et mattis viverra, et nascetur sit.
- Tempus pellentesque officia placerat odio, turpis augue euismod suspendisse rhoncus.
- Nested bullet list (notice automatic change of bullet type relative to parent - if not otherwise specified)
- Magna non dui nec nibh luctus, magna amet ante fusce.
- Ut nulla a posuere ornare, mauris aliquet congue tempor massa donec ultricies.
- Vivamus accumsan luctus a, eget arcu nec rutrum vitae eos, fringilla netus luctus in, velit donec sociis ultricies, justo nonummy nibh in ut nec.
- Et amet eu consequat sit, proin massa quam, cras nulla nulla ligula nulla, erat id nam sem accumsan totam.
-
- Another third-level bullet list, this time all content inside of <li> tags (notice bullet right in front of this line)
- Eget montes quis reprehenderit ullamcorper. Ac nec libero eu id nibh suspendisse, semper et risus amet tortor leo vivamus, rhoncus sem hymenaeos, fringilla sed.
- Urna est nulla commodo vehicula, orci tortor conubia vestibulum, vitae non rutrum wisi, curabitur pede urna pede urna dolor pharetra, leo eget lectus ante per.
- Pellentesque a euismod quisquam scelerisque arcu, at maecenas augue, ultrices
- Sed lectus, consequat velit ultrices sit, porta at lorem ac arcu. Donec inceptos integer.
- Suspendisse purus vehicula elit eget primis, pellentesque est eros orci nullam mauris placerat, quis convallis, volutpat sociosqu, ac nec neque risus.
- Viverra condimentum nec eu donec, lorem quidem vitae suspendisse, vestibulum et ac lorem tincidunt, blandit lectus vel nulla.
- Dictum porta odio lorem nam eros, suspendisse morbi.
- Nibh qui orci aenean, nulla pede dolor dictumst imperdiet aptent, lobortis nisl.
- Sed inceptos pellentesque, amet imperdiet, wisi pretium felis placerat, eros eu posuere vel integer imperdiet, donec congue potenti faucibus morbi massa non.
- Per arcu auctor bibendum viverra nisl, amet nulla, malesuada sem metus lorem elit a ac.
- Tempor et suspendisse sit nonummy ac proin, sed quam neque pede donec justo, nam aliquet nascetur cras laboriosam.
- Consequat nibh morbi urna mauris euismod at, morbi fermentum hendrerit lorem phasellus, vulputate lobortis lobortis sagittis et bibendum nonummy, interdum metus
- Sed vel, ac pede diam ipsa nec quam erat, ac urna viverra eleifend et aliquam sed, pellentesque suspendisse lobortis condimentum sed.
- Nested, letter-enumerated list
- Scelerisque amet at fringilla, justo ac lacus lobortis in deserunt commodo.
- Pretium lacus molestie. Erat dolor ipsum est praesent lobortis lorem, gravida amet malesuada sit sagittis, malesuada nullam metus risus pharetra fringilla tincidunt.
- Quis vel accumsan mollis ut. Elit metus ut sem at mi turpis, aliquam class turpis, fames morbi sit sollicitudin, ligula libero.
- Third level list, this time capital letter enumerated
- Scelerisque amet at fringilla, justo ac lacus lobortis in deserunt commodo.
- Pretium lacus molestie. Erat dolor ipsum est praesent lobortis lorem, gravida amet malesuada sit sagittis, malesuada nullam metus risus pharetra fringilla tincidunt.
- Quis vel accumsan mollis ut. Elit metus ut sem at mi turpis, aliquam class turpis, fames morbi sit sollicitudin, ligula libero.
- Pretium lacus molestie. Erat dolor ipsum est praesent lobortis lorem, gravida amet malesuada sit sagittis, malesuada nullam metus risus pharetra fringilla tincidunt.
- Quis vel accumsan mollis ut. Elit metus ut sem at mi turpis, aliquam class turpis, fames morbi sit sollicitudin, ligula libero.
- Tempor et suspendisse sit nonummy ac proin, sed quam neque pede donec justo, nam aliquet nascetur cras laboriosam.
- Consequat nibh morbi urna mauris euismod at, morbi fermentum hendrerit lorem phasellus, vulputate lobortis lobortis sagittis et bibendum nonummy, interdum metus
- Sed vel, ac pede diam ipsa nec quam erat, ac urna viverra eleifend et aliquam sed, pellentesque suspendisse lobortis condimentum sed.