<commit_before>= Form support

Showoff extends Markdown to render a limited subset of form elements. This is
mostly useful for polls, quizzes, surveys, etc. These extensions are only
rendered on slide that have been marked as forms.

Form responses are saved to a JSON file on disk, <tt>stats/forms.json</tt>, and
cached in memory for quick access. Responses are keyed by form ID and IP
address. Each IP has only one response saved, and subsequent submissions will
overwrite.  Showoff saves and reloads data from disk, so you can run the
presentation multiple times without data loss. Just like
<tt>stats/viewstats.json</tt>, you should remove the file prior to starting the
presentation if you'd like to start from a clean slate.

Responses can optionally be displayed live in the presenter view.

== Marking a slide

Each slide containing a form must be marked as such by including that form's ID
in the slide signature.  For example, to create a slide that posts to the id of
`experience`, the slide signature that you might use could look like:

    <!SLIDE form=experience>

== Markdown extensions

Form slides are rendered via Markdown extension with the general form of:

    question = answer(s)

Both sides, the question and the answer(s) are tokenized so that they may be
represented as either a single continuous string, or a key and a string. This
would look like:

    key -> A human readable representation of the element

If the `=` sign has an asterisk prepended, then the field is marked as required.

    question *= answer(s)

=== Form element syntax

The right hand side (answer) can be rendered in the following ways:

[text field]
  Three or more consecutive underscores, followed by an optional length.

    name = ___

    name = ___[50]

    name -> What is your name? = ___[50]

[text area]
  Whitespace surrounded by square brackets, including an optional number of rows.

    comments = [   ]

    comments = [   5]

[radio buttons]
  Delineate a list of options on the right hand side with parentheses, optionally
  marking one as default using an `x`. This accepts the tokenized form for a key
  and a full human readable string. If options are placed on multiple lines
  indented by 3+ spaces, then the output will be rendered as a bullet list.

    smartphone = () iPhone () Android () other -> Any other phone not listed

    awake -> Are you paying attention? = (x) No () Yes

    continent =
        () Africa
        () Americas
        () Asia
        () Australia
        () Europe

[checkboxes]
  Works exactly like radio boxes, only using square brackets as delineators.

    smartphone = [] iPhone [] Android [x] other -> Any other phone not listed

[combo select]
  Surround options on the right hand side with curly brackets and a combo select
  box will be rendered. If you place the options on multiple lines, you can use
  the long tokenized form. The shorthand single line syntax supports keys only.
  The default option may be specified by surrounding an option with parentheses.

    smartphone = {iPhone, Android, Other }

    smartphone = {iPhone, Android, (Other) }

    smartphone = {iPhone, Android, (other -> Any other phone not listed) }

    cuisine -> What is your favorite cuisine? = { American, Italian, French }

    cuisine -> What is your favorite cuisine? = {
          US -> American,
          IT -> Italian,
          FR -> French
        }

== Viewing results

A continuously updating block displaying the live results from a given form ID
can be embedded into the presenter notes using the syntax below. The ID should
match the ID of a form created by marking a slide with a form tag.

    ~~~FORM:id~~~

This will display all data that can be rendered in aggregate form as a horizontal
bar chart that updates every three seconds. Free entry elements are not displayed.

The presenter view also includes a <em>Display Results</em> button instead of the
<em>Save</em> button that audience members see. Pressing this button will render
a single snapshot of the current results over the slave window. This will commonly
be displayed on the projector. Pressing the button again will update the results.<commit_msg>Added a complete example slide<commit_after>= Form support

Showoff extends Markdown to render a limited subset of form elements. This is
mostly useful for polls, quizzes, surveys, etc. These extensions are only
rendered on slide that have been marked as forms.

Form responses are saved to a JSON file on disk, <tt>stats/forms.json</tt>, and
cached in memory for quick access. Responses are keyed by form ID and IP
address. Each IP has only one response saved, and subsequent submissions will
overwrite.  Showoff saves and reloads data from disk, so you can run the
presentation multiple times without data loss. Just like
<tt>stats/viewstats.json</tt>, you should remove the file prior to starting the
presentation if you'd like to start from a clean slate.

Responses can optionally be displayed live in the presenter view.

== Marking a slide

Each slide containing a form must be marked as such by including that form's ID
in the slide signature.  For example, to create a slide that posts to the id of
`experience`, the slide signature that you might use could look like:

    <!SLIDE form=experience>

== Markdown extensions

Form slides are rendered via Markdown extension with the general form of:

    question = answer(s)

Both sides, the question and the answer(s) are tokenized so that they may be
represented as either a single continuous string, or a key and a string. This
would look like:

    key -> A human readable representation of the element

If the `=` sign has an asterisk prepended, then the field is marked as required.

    question *= answer(s)

=== Form element syntax

The right hand side (answer) can be rendered in the following ways:

[text field]
  Three or more consecutive underscores, followed by an optional length.

    name = ___

    name = ___[50]

    name -> What is your name? = ___[50]

[text area]
  Whitespace surrounded by square brackets, including an optional number of rows.

    comments = [   ]

    comments = [   5]

[radio buttons]
  Delineate a list of options on the right hand side with parentheses, optionally
  marking one as default using an `x`. This accepts the tokenized form for a key
  and a full human readable string. If options are placed on multiple lines
  indented by 3+ spaces, then the output will be rendered as a bullet list.

    smartphone = () iPhone () Android () other -> Any other phone not listed

    awake -> Are you paying attention? = (x) No () Yes

    continent =
        () Africa
        () Americas
        () Asia
        () Australia
        () Europe

[checkboxes]
  Works exactly like radio boxes, only using square brackets as delineators.

    smartphone = [] iPhone [] Android [x] other -> Any other phone not listed

[combo select]
  Surround options on the right hand side with curly brackets and a combo select
  box will be rendered. If you place the options on multiple lines, you can use
  the long tokenized form. The shorthand single line syntax supports keys only.
  The default option may be specified by surrounding an option with parentheses.

    smartphone = {iPhone, Android, Other }

    smartphone = {iPhone, Android, (Other) }

    smartphone = {iPhone, Android, (other -> Any other phone not listed) }

    cuisine -> What is your favorite cuisine? = { American, Italian, French }

    cuisine -> What is your favorite cuisine? = {
          US -> American
          IT -> Italian
          FR -> French
        }

== Viewing results

A continuously updating block displaying the live results from a given form ID
can be embedded into the presenter notes using the syntax below. The ID should
match the ID of a form created by marking a slide with a form tag.

    ~~~FORM:id~~~

This will display all data that can be rendered in aggregate form as a horizontal
bar chart that updates every three seconds. Free entry elements are not displayed.

The presenter view also includes a <em>Display Results</em> button instead of the
<em>Save</em> button that audience members see. Pressing this button will render
a single snapshot of the current results over the slave window. This will commonly
be displayed on the projector. Pressing the button again will update the results.

== Example slide

    <!SLIDE form=classinfo>
    # Making Acquaintances
    ## Let's get to know each other

    Tell me a little bit about yourself to help me better tailor the classroom
    experience towards your needs.

    howlong -> How long have have you been using Puppet? = {
       under -> Less than six months
       6mo -> Around six months
       1yr -> About a year
       2yr -> Two years or so
       more -> Since before Puppet Enterprise was a sparkle in Luke's eye, get offa my lawn.
    }

    job -> What is your work role? =
        [] support -> Technical Support
        [] Sysadmin
        [] dbadmin -> DB Admin
        [] Developer
        [] Management


    usedpe -> Have you used Puppet Enterprise? = () Yes () No

    prepared -> Do you feel prepared for this class? = () Yes () No

    ~~~SECTION:notes~~~

    Tell the class a little bit about yourself and your own background.

    ~~~FORM:classinfo~~~

    ~~~ENDSECTION~~~
{'fraction_non_alphanumeric': 0.058161953727506426, 'fraction_numerical': 0.0016066838046272494, 'mean_word_length': 3.277141548327989, 'pattern_counts': {'":': 0, '<': 22, '<?xml version=': 0, '>': 55, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 1, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7523526', 'n_tokens_mistral': 2434, 'n_tokens_neox': 2272, 'n_words': 1349}