Dec 232017
 
Generates TP4 screen code.
File MINIGEN.ZIP from The Programmer’s Corner in
Category Pascal Source Code
Generates TP4 screen code.
File Name File Size Zip Size Zip Type
CURDATE.INC 521 295 deflated
CURSOR.INC 464 216 deflated
CURTIME.INC 754 337 deflated
EXIST.INC 172 137 deflated
MGEDIT.COM 49090 22258 deflated
MGPROG.PAS 30361 7172 deflated
MGPROG.TPU 18144 8040 deflated
MGSKEL.PAS 603 338 deflated
MINIGEN.DOC 37784 10434 deflated
MINIGEN.EXE 56144 20324 deflated
WIDGIT.DAT 3690 635 deflated
WIDGIT.INC 2855 820 deflated
WIDGIT.PAS 5848 2171 deflated
WNDODEMO.PAS 1231 593 deflated

Download File MINIGEN.ZIP Here

Contents of the MINIGEN.DOC file


WxP3$
January 16, 1988

To : Minigen Users
Fm : Eric H. Snyder
MiniGen Products
1417 Evergreen
Homewood, IL 60430
Re : Minigen V1.3 Pascal screen code generator.


Belief is nearly the whole of the Universe,
whether based on truth or not.
- Kurt Vonnegut -



Minigen is a Turbo Pascal(tm) V4.0 code generator designed to work
on an IBM PC or compatible with a MonoChrome or Color Graphics Adapter
installed. With it you can paint data entry screens (constants areas
and data fields), open and close windows with borders and cursor
memory, perform controlled data entry with type and range checking, and
create pull down menus. There are also a number of utility procedures
and functions which support common DOS calls and disk functions. How
you use MiniGen is up to you, but its strong points are data entry and
screen handling.

I have chosen to Copyright this version of MiniGen, but to place
it to the public domain for free distribution. Like many products of
this nature, MiniGen is user supported, and carries a modest
registration fee of $10.00. If you use MiniGen at home, at school, or
in business, and find that it meets your needs, you are asked to send
in your registration fee. You will be posted on upcoming versions of
the product and where to get them. But whether you register or not, let
me know your reaction to the product pro or con, and how it could be
made more useful to you.

MiniGen is entirely written in Turbo Pascal (tm) using the same
source code routines you have received on disk. Now, here's what you
can do with it.

1) Screen paint text areas (put words on the screen), fields
(colored backgrounds of a certain length), and vertical and horizontal
lines. Thus you lay out the physical appearance of a screen. Your
default boundaries are 1,1,80,25.

2) Perform controlled data entry using single line keyboard
commands as well as the cursor key pad. You can specify what data type
is being entered as well as the maximum and minimum range values of
numerics. Exit codes allow you to determine how the user terminated the
procedure.

3) Open and close windows with one of eight boxes drawn around
them. Cursor memory is retained so that when you close the window, it
will be returned to the same position it had before the window was
opened.

4) Create pull down menus with reversible backgrounds controlled
by the up and down arrow keys. You'll get the idea while working with
MiniGen in edit mode.






WxPWxPWxPWxP
WxPWxPWxP
WxPWxP KWxPKWxPKWxPKWxPKWxPKWxPKWxP MiniGen KWxPKWxPKWxPKWxPKWxPKWxPKWxP Page 2WxP
WxPWxPWxP
WxP
Eventually, the package will generate data entry programs which
will automate the process of gathering data from the screen. Additional
utility functions will be added as the need arises, or the spirit moves
me. Any more ideas? Suggestions and constructive criticism are
encouraged and welcome.


{************} Screen Painting {************}

All screen painting is done with MINIGEN.EXE. The options on the
main menu are pretty much self explanatory, but I'll go into them here
anyway.

1) Load a screen data file. You don't have to do all your work in
one sitting. You can resume working on a screen at a later time with no
loss of data. ESCape lets you exit the function.

2) Save the current screen definition file for future
modifications and abandon it to work on another screen file (or quit
the program). This feature is convenient when developing an application
that has similar screen elements, like a series of data entry programs
which share a common page header and trailer structure. By creating a
single file containing these elements you can pull it in for every
screen, and write it out under a different name. If you with to save
periodically as you go along, use the 'B' for backup command. You can
then continue editing the screen with option '6'. ESCape lets you exit
the function.

3) Define a screen. You will be prompted for the four corners of
the screen and its background color. You can hop back and forth between
the corner data fields by using the ^J and ^K, and at he Up arrow and
Down arrow keys. When selecting the background color, the Up and Down
arrow keys will move the reverse video block to the selection you want.
Just press RETURN to make your selection. Hitting escape from any field
returns you to the home position to make another selection.

4) Make a procedure. This option will create a Turbo Pascal(tm)
source code procedure from the loaded screen file, which will display
your data entry screen. You will be prompted to supply the name of the
include file into which you wish the procedure to be placed. If the
file already exists, you will be asked if you wish to overlay it with
the new file. You will then be prompted for the name of the procedure
itself. Supply a valid Pascal procedure name.
At this point, you will be asked whether you wish to create an
overlay procedure. This is a very important question. For one thing,
overlays are not supported in version 4.0. However, there are packages
which let you create them and Borland says that they will build them
back in to future versions. So I decided to leave this capability in
MiniGen.
If you choose not to use an overlay, a standard procedure is
generated and the calling procedure is as follows;

OpenWindow(1);
MainMenuScreen; {Or whatever name you pick.}







WxPWxPWxPWxP
WxPWxPWxP
WxPWxP KWxPKWxPKWxPKWxPKWxPKWxPKWxP MiniGen KWxPKWxPKWxPKWxPKWxPKWxPKWxP Page 3WxP
WxPWxPWxP
WxP Just be sure that the window you open is the one designed for that
procedure, and the fields you have defined will appear within it. The
window will be opened, and the screen displayed within it.
However, if you choose to create an overlay, your program must be
structured differently. The Overlay procedure will load all your fields
into a linked list and set a Boolean flag telling MiniGen that it has
done so. Just issue

MainMenuScreen(1);

at the start of your program after defining your screens. Notice that
the procedure now needs a parameter. This tells MiniGen which window
will own these fields. Now when you issue

OpenWindow(1);

in your program, the linked list will be searched for the window number
(in this case 1), and the fields will be written automatically. This
gives you several advantages. You will save code and data space by
storing these procedures outside your program. Hence your MiniGen
programs can now be bigger. Also, your programming life is simplified.
All you have to do is to open the window. As before, be sure that the
window you associate with the procedure is the one designed for that
it. As before, the ESCape sets you free.

5) Clear the screen. No, not the Pascal procedure! This selection
will erase the file currently in memory and let you start out fresh.

6) Resume editing. If you have exited edit mode for any reason
and wish to resume editing the same window, you may do so. Remember,
saving a file clears it out of memory (abandons it). To perform a
periodic save, Press ['B','b'] for backup then resume editing with 6.

7) Execute Turbo. Executes Turbo Pascal(tm) if it can be found in
the current directory. Here is a convenienc way to develop your MiniGen
rograms step by step. Escape to DOS from MiniGen. Copy MGSkel.Pas to a
file bearing your program name. Exit. Define your screens in MiniGen,
saving them to data files along the way. Create their procedures, then
execute Turbo. Modify the skeleton program with screen definitions,
includes for generated screen procedures, calls to window and screen
procedures, and compile a test program to see what the screens look
like, or how several appear together. Change what you don't like and go
at it again. Be sure to save your screen data files along the way so
they can be called back in for future modification. Once you have all
the fields where they should be it is a simple matter to add in the
code which writes gathered data to a file, performs a function, etc. I
generated the WIDGIT example program this way!

8) Escape to DOS. Lets you get out of MiniGen and go do something
else for a while. When you tire of that, you can return to MiniGen by
typing EXIT at the DOS prompt. (Be sure to get yourself back into the
proper directory first.)

Q) Exit. You got it.

B) When you save a screen with option '2', you also abandon it.






WxPWxPWxPWxP
WxPWxPWxP
WxPWxP KWxPKWxPKWxPKWxPKWxPKWxPKWxP MiniGen KWxPKWxPKWxPKWxPKWxPKWxPKWxP Page 4WxP
WxPWxPWxP
WxP This is inconvenient if you want to store part of your work as you go
along so it will not be lost accidentally. 'B' or 'b' will save the
file you are working on and allow you return to edit mode with option
'6'.

E) MGEdit. This is a very straight forward text editor which can
be executed from within MiniGen in the same way that you execute Turbo.
It obeys a good number of the Turbo editor commands. It is not terribly
elaborate, but is more than adequate for the tasks for which it is
intended, namely, your convenience in getting off to a running start
with your programs. Any serious editing will of course be done with
Turbo or a formal programmer's editor. If you select the 'E' function
right after creating a procedure (option 4), the editor will pull in
that procedure automatically.


{************} EDIT MODE {************}

Once you have defined a screen (option 3), or loaded a screen
(option 1), or resume editing (option 6), the program hops into edit
mode. This is where the real work gets done. From edit mode you can;

1) Move the cursor within defined screen boundaries.
Up - ^E, up arrow,
Down - ^X, down arrow,
Right - ^D, right arrow and
Left - ^S, left arrow.

2) F1 - Define a screen object. This will take you into object
definition. You can specify the type of object (text, field, horizontal
or vertical), its foreground and background colors, length and contents
of text objects. Here are some points to keep in mind.
a) If you try to define an object on top of another, you will
be prompted to respond (Y)es, (N)o, (O)verlay or
(R)eplace.
b) The color block on the right hand side of the top window
lets you know what the field looks like so far.
c) The right and left arrow keys will let you move back and
forth between the pull down menus.
d) Likewise, ^J and ^K, or the up and down arrow keys, let
you get into and out of length and contents description.
e) ESCape gets you out of object definition.
f) When defining a horizontal or vertical line, you will have
to hold down the ALT key and type in the ASCII value of
the box drawing character you wish to enter. These are
found from characters 179 to 218 of any complete ASCII
character code chart.

3) F2 - See a display of all possible background and foreground
combinations (except the ones that blink, which give me the jitters
anyway and whose use should be restricted to temporary error messages,
if then).

4) F10 - Return to main menu. (Also ^Z.)

Now, I will discuss the various procedures which you have in the






WxPWxPWxPWxP
WxPWxPWxP
WxPWxP KWxPKWxPKWxPKWxPKWxPKWxPKWxP MiniGen KWxPKWxPKWxPKWxPKWxPKWxPKWxP Page 5WxP
WxPWxPWxP
WxP MiniGen environment and how to use them.


{************} Windowing {************}

Opens and closes windows with boxes and colored backgrounds which
you specify. Several procedures and one constants are involved as
follows. In order of use, they are;

Const
ScreenCount = N;

ScreenCount declares the number of screens you can define (N),
but not the number of screens you can open at one time.

DefineScreen(Ind,X1,Y1,X2,Y2,BGColor,FrameType,FrameColor);
Where: Ind = Which window this is - 1,2,3,4, etc.
X1,Y1,X2,Y2 = Window coordinates, just like the Turbo
window procedure.
BGColor = Background color (1-8), of the opened widow.
FrameType =
1 - Single bar. - 5
2 - Double bar. - 6
3 - Horiz double, vert single. - 7
4 - Vert double, horiz double. - 8
FrameColor : Any valid attribute byte.
(See 'A Note on Attributes', below.)

DefineScreen(); describes a window to be opened, and associates it
with the index number used in OpenWindow. Types 5 thru 8 on the left
have top corner characters which join nicely to the bottom of their
corresponding boxes on the left. These are the ones I used when writing
the field definition section (F1) of the Edit mode.

OpenWindow(N);

OpenWindow(); opens the specified window (the one specified in Ind
above). OpenWindow received quite a face lift for V1.2. It no longer
stores all 4000 bytes of screen data. Instead, only that portion of
video memory within the boundaries of the opened window is saved. This
reduces the memory requirements of each window down to only what is
needed. If you are interested in how it is done, take a look at the
function SaveWindowContents which is internal to procedure OpenWindow.
I have not seen quite this algorithm used elsewhere. It is based on the
concept of buffering strings to save space and does its business by
advancing a pointer in preparation for a move statement.

CloseWindow;

CloseWindow; closes the current window and restores the screen to
its original condition.

TerminateScreens;

TerminateScreens; Cleans up behind the Initialize routine. This
procedure is called once from the main routine on the way out of your






WxPWxPWxPWxP
WxPWxPWxP
WxPWxP KWxPKWxPKWxPKWxPKWxPKWxPKWxP MiniGen KWxPKWxPKWxPKWxPKWxPKWxPKWxP Page 6WxP
WxPWxPWxP
WxP program.


{************} Data Entry {************}

The EnterData function controls data entry by giving you
keyboard commands and letting you specify data type and what key(s)
exit the routine. Numeric data is entered with range checking and
commas displayed upon exiting if field size allows. If you do not want
range checking, call MaxLimits; (described below), at the start of the
program. Otherwiswe, simply set the Upper??? and Lower??? variables for
the type you are entering before calling the EnterData function. A
status code is returned telling you whether the function was terminated
as the result of an exit key, a carriage return, ^M, or (for 'S'
strings), by typing past the end of the field. When called initially,
EnterData displays the value it finds in the field you pass. If an exit
code is returned, the value of the subject variable is unchanged unless
you specify otherwise for that exit code in UserExitSet, described
below.
One nice feature of this procedure (and pull down menus), is that
it will blank the screen for you if a certain amount of time goes by
without receiving any input from the keyboard. A typed constant in
MGPROG.PAS named MG_TimeOut is initially set to 300, giving you 5
minutes of inactivity before the ScreenSaver() procedure blanks the
screen. Once this happens, just hit any key and the screen will come
back unchanged. I have seen lots of terminals ruined by constantly
active displays. So protect those phosphors for future generations and
save yourself or your company a buck in the process! If you do not wish
this feature to activate, set MG_TimeOut to a very high duration which
is not likely to expire such as 18,000 for a five hour fuse.

Var
UpperByte,LowerByte : Byte; {Range checking limits}
UpperInt,LowerInt : Integer;
UpperReal,LowerReal : Real;

Procedure MaxLimits; {Sets Range check values to maximum}

Upper??? and Lower??? variables are used to set the limits for
numeric data entry. Always assign values to the proper set of limit
variables calling EnterData(); (U/L byte for VarTyp = 'B', etc.),
because they will be used for range checking regardless.
Use Maxlimits if numeric ranges are not important to you for any
particular EnterData(); call. It will set all six limit variables to
their extreme values.

Type
Exits = Set of Byte;

EnterDAta(Variable,VarTyp,XLoc,YLoc,Len,Decs,FieldAttr,CursorAttr,Exits);
Where: Variable = The variable to be entered, of course!
VarTyp = 'B'(Byte),'I'(Integer),'R'(Real),
'N'(Numeric only string data) 'S'(String, data:
all letters, numbers and special characters)
'A'(Alphabetics),U(Upper case),L(Lower case)
'M'Here is were you specify which characters






WxPWxPWxPWxP
WxPWxPWxP
WxPWxP KWxPKWxPKWxPKWxPKWxPKWxPKWxP MiniGen KWxPKWxPKWxPKWxPKWxPKWxPKWxP Page 7WxP
WxPWxPWxP
WxP are to be considered valid. Before you call
EnterData with a VarTyp of M, assign a set
of characters to a MiniGen reserved variable
called UserEditSet, which is a Set of Char.
This set of characters will be used by
MiniGen while the variable is entered.
'X'(Anything from #32 to #254)
XLoc,YLoc = X and Y coordinates.
Len = length of field.
Decs = Number off decimal points (used with reals).
FieldAttr = background/foreground attribute.
CursorAttr = same as FieldAttr, but for the cursor only.
Exits = a set of integer values representing the decimal
value of the keystrokes you wish to use to
exit the routine.
13 - Carriage return. Returns your variable.
<< Always exits. Do not code as an exit!! >>
0 - Typing off the field of a string item.
Returns your variable.
<< Always exits. Do not code as an exit!! >>
10 - Line feed.
27 - ESCape.
59..68,84..93,94..103,104..113
- All function keys (NoShft,Shft,Ctrl,Alt)
119 - Ctrl Home
117 - Ctrl End
73,132 - PgUp : Unshft, Ctrl
81,118 - PgDn : Unshft, Ctrl
72,80 - Up arrow, down arrow : Unshft
3,114 - ^2, ^*
120-131 - Alt's 1..9,0,-,=
30,48,46,32,18,33,34,35,23,36,37,38,50,
49,24,25,16,19,31,20,22,47,17,45,21,44
- Alt'd alphabetics
4,9,11,14,15,16,17,18,20,23,25,26
- ^C,^I,^K,^N,^O,^P,^Q,^R,^T,^W,^Y,^Z
-13 - ^M produces a negative thirteen to
distinguish it from the enter key.
Just as 13 (and 0 for 'S'), always exit and
return data, -13 always exits without
returning your data. Thus, even if you code
EnterData(); with Exits = [], the user can
always leave the routine without changing
anything.
<< Always exits. Do not code as an exit!! >>
-1 - Negative 1 indicates a parameter error.
Included for your convenience during program
development.
<< Always exits. Do not code as an exit!! >>

EnterData obeys the following commands;

^D, RArr - Cursor right
^S, LArr - Cursor left
^F, ^RArr - Jump right a word
^A, ^LArr - Jump left a word






WxPWxPWxPWxP
WxPWxPWxP
WxPWxP KWxPKWxPKWxPKWxPKWxPKWxPKWxP MiniGen KWxPKWxPKWxPKWxPKWxPKWxPKWxP Page 8WxP
WxPWxPWxP
WxP Tab - Right justify string fields
Shft Tab - Left justify string fields
^G, Del - Delete a character
^V, Ins - Toggle insert function
^H, Bksp - Destructive backspace
^B - Toggle key click noise
^U - Convert an 'S' string to all upper case
^L - Convert an 'S'string to all lower case
Home - Go to first position
End - Go to last position
^E - Erase from current position forward
^X - Erase entire field

As stated, the data entered will be returned to your Variable when
EnterData(); terminates with an exit code of 0 or 13. That is to say,
Exits leave the contents of your Variable unchanged. This is exactly
what you will want in most cases.
However, you can override this behavior. MiniGen contains a
reserved variable called UserExitSet, which is a set of Byte. By
assigning UserExitSet, you can specify which of your EnterData(); Exits
will return data upon termination. For example, the sample code below
{1} initializes UserExitSet to the up and down arrow keys, {2} calls
EnterData(); with ESC, UpArr and DnArr as exits, {3} returns
UserExitSet to its initialized value, the null set, and {4} takes some
action based on the returned Exit. The UpArr (72) and the DnArr (80)
now return changed data which (for purposes of illustration alone),
receive special treatment.
As a general rule when programming for return codes, it is best to
code for the exception conditions first : the exits. You always have
two valid return codes in 13 and -13, and 0 for 'S'. These distinct
codes are there for your use if you need them. But by programming for
the exceptions, you can lump the remaining three together as valid and
not be bothered by having to treat them individually.

{1} UserExitSet := [72,80];
{2} ReturnCode := EnterData(AnyVariable,...,[27,72,80]);
{3} UserExitSet := [];
{4} Case ReturnCode of
27 : Exit; {** Variable remains unchanged. **}
72,80 : Begin {** Changed data returns to your program **}
...
End;
Else
... {** Changed data returns to your program **}
End;

{************} Character Entry {************}

Entering a single character can be performed with the EnterChar
function. You specify the variable to be accepted from the keyboard,
provide a set of acceptable characters for which the routine will wait,
and a set of byte values to serve as exits from the routine. Exits do
not have to generate extended scan codes to be acceptable. You may
specify the ord(#?) of any character to be an exit. Screen blanking is
turned on here as well.







WxPWxPWxPWxP
WxPWxPWxP
WxPWxP KWxPKWxPKWxPKWxPKWxPKWxPKWxP MiniGen KWxPKWxPKWxPKWxPKWxPKWxPKWxP Page 9WxP
WxPWxPWxP
WxP EnterChar(CharVariable,GoodCharSet,ExitSet);
Where;
CharVariable = The Char you want to read
GoodCharSet = A set of Char limiting what the routine will
accept
ExitSet = A set of byte listing the exits.



{************} Pull Down Menus {************}

Pull down menus can be created with the Menu function. These
menus are controllable by the up and down keys. Hitting the return
key terminates the function and tells you the number of the selection
made. You are informed of exits in the same way, so it is a good idea
to make the Ord(#?) of the lowest exit higher than number of
selections you are providing to the user. The escape key causes the
function to return with a value of zero. Screen blanking is astive in
Menu. The function takes the following arguments;

Type
Str255 : String[255];

Function Menu(Window : Byte;
S : Str255;
Selections,NormAttr,ReverseAttr
: Byte;
Exits : ExitsTyp) : Byte;

Where: Window = the number of the window to be opened,
S = a string variable containing a number of equal
length sub-strings, each terminated by a back-
slash character ('\'). These sub-strings will be
written inside the menu window box. It is your
responsibility to make sure that each one is the
exact width of the box. For example, the
following string is used in ScrnGen to display
the possible background colors.
' Black \ Blue \ Green \ Cyan \ ', etc, etc.
Selections = the number of sub-strings found in S.
Norm Attr = the background attribute of the window as
specified in DefineScreen;
ReverseAttr = the background attribute (colors 1 thru 8), to
be displayed when a selection is being
indicated.
Exits = the decimal value of the keystroke(s) which will
exit the routine without making a selection.
These are the exits which allow you to move left
and right while selecting the attributes of a
field in Edit mode (F1). An escape key always
returns the value zero (0).


{************} Shift Status Detection {************}

Upon exiting the EnterData, EnterChar and Menu routines, you can






WxPWxPWxPWxP
WxPWxPWxP
WxPWxP KWxPKWxPKWxPKWxPKWxPKWxP MiniGen KWxPKWxPKWxPKWxPKWxPKWxP Page 10WxP
WxPWxPWxP
WxP query four reserved Boolean variables to determine the shift status of
the keyboard. Such information can be used for even greater keyboard
and program control. The variables are as follows;

RightShift LeftShift
CtrlKey AltKey

{************} Skeleton Program {************}

To give your programs a quick start, copy MGSkel.Pas over to your
new program name and use it to include all the minigen source files,
MGProg.Inc (windowing and data entry), MFMenu.Inc (pull down menus),
Cursor.Inc (play with the cursor), your MiniGen generated window
procedures, your other include routines, etc.
















































WxPWxPWxPWxP
WxPWxPWxP
WxPWxP KWxPKWxPKWxPKWxPKWxPKWxP MiniGen KWxPKWxPKWxPKWxPKWxPKWxP Page 11WxP
WxPWxPWxP
WxP



{************} A Note on Attributes {************}

Screen color attributes are the one bytes values which determing
the foreground and background characteristics of the displayed
character. You should derive color attributes from the following table.
They are best understood in hexidecimal notation, and are constructed
as follows;


Bit : 7 6 5 4 | 3 2 1 0 Background - First 8 colors only
BL R G B | I R G B Foreground - All 16 colors
Background | Foreground

Black 0 0 0 0 1 0 0 0 Dark Gray BL = Blinking
Blue 0 0 0 1 1 0 0 1 Light Blue I = High Intensity
Green 0 0 1 0 1 0 1 0 Light Green
Cyan 0 0 1 1 0 0 1 1 Light Cyan R = Red
Red 0 1 0 0 1 1 0 0 Light Red G = Green
Magenta 0 1 0 1 1 1 0 1 Light Magenta B = Blue
Brown 0 1 1 0 1 1 1 0 Yellow
Lt. Gray 0 1 1 1 1 1 1 1 White

Source : Assembler for the IBM PC and PC-XT by Peter Abel.



































WxPWxPWxPWxP
WxPWxPWxP
WxPWxP KWxPKWxPKWxPKWxPKWxPKWxP MiniGen KWxPKWxPKWxPKWxPKWxPKWxP Page 12WxP
WxPWxPWxP
WxP

{************} Warranty {************}

Here's where I cover my, uh, ... bases.

I make no warranty of any kind, express or implied, including
without limitation, any warranties of merchantability and/or fitness for
a particular purpose. I shall not be liable for any damages, whether
direct, indirect, special or consequential arising from a failure of
this program to operate in the manner desired by the user. I shall not
be liable for any damages to data or property which may be caused
directly or indirectly by the use of this program.

IN NO EVENT WILL I BE LIABLE TO YOU FOR ANY DAMAGES, INCLUDING ANY
LOST PROFITS, LOST SAVINGS OR OTHER INCIDENTAL OR CONSEQUENTIAL DAMAGES
ARISING OUT OF YOUR USE OR INABILITY TO USE THE PROGRAM, OR FOR ANY
CLAIM BY ANY OTHER PARTY.












































WxP3$


 December 23, 2017  Add comments

 Leave a Reply

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

(required)

(required)