예제 #1
0
    def make_additional_questions():
        """Make additional questions, such as prompts for dialectical bootstrapping

        :return: additional questions
        :rtype: list of hemlock.Question
        """
        if not current_user.meta['Bootstrap']:
            return [
                Label('''
                Please make second estimates which are different from your first estimates.
                ''')
            ]
        return [
            Textarea('''
                Imagine your first estimates were off the mark. Write at least one reason why that could be. Which assumptions or considerations could have been wrong?
                ''',
                     var='Assumptions',
                     required=True,
                     validate=V.min_words(7),
                     debug=[
                         D.send_keys('here are 7 words without a meaning'),
                         D.send_keys(p_exec=.2)
                     ]),
            Check('''
                What does this reason imply? Were your first estimates too high or too low?
                ''', [('Too high', 'high'), ('Too low', 'low'),
                      ('Some were too high, others too low', 'both')],
                  var='Direction',
                  validate=V.require()),
            Label('''
                Based on this new perspective, make second estimates which are different from your first estimates.
                ''')
        ]
예제 #2
0
def live_with_parents(require=False):
    live_with_parents = binary('Do you live with one or both of your parents?',
                               var='LiveWithParents',
                               validate=V.require() if require else None)
    live_with_inlaws = binary(
        'Do you live with one or both your parents in law?',
        ['Yes', 'No (or, I do not have parents in law)'],
        var='LiveWithInlaws',
        validate=V.require() if require else None)
    return [
        _debug_choices(q, require)
        for q in (live_with_parents, live_with_inlaws)
    ]
예제 #3
0
def age_bins(require=False):
    return Select('How old are you?', [
        '', 'Younger than 18', '18-24', '25-29', '30-34', '35-39', '40-44',
        '45-49', '50-54', '55-59', '60-64', '65 or older'
    ],
                  var='AgeBins',
                  validate=V.require() if require else None)
예제 #4
0
def occupation(require=False):
    occupation_q = Select('''
        To which occupational group do you belong?
        
        If you have multiple jobs, select the option for your main job. If you are not employed, select the option for your most recent job.
        ''', [
        '',
        ('Professional and technical (for example: doctor, teacher, engineer, artist, accountant, nurse)',
         'professional'),
        ('Higher administrative (for example: banker, executive in big business, high government official, union official)',
         'admin'),
        ('Clerical (for example: secretary, clerk, office manager, civil servant, bookkeeper)',
         'clerical'),
        ('''
                Sales (for example: sales manager, shop owner, shop assistant, 
                insurance agent, buyer)
                ''', 'sales'),
        ('Service (for example: restaurant owner, police officer, waitress, barber, caretaker)',
         'service'),
        ('Skilled worker (for example: foreman, motor mechanic, printer, seamstress, tool and die maker, electrician)',
         'skilled'),
        ('Semi-skilled worker (for example: bricklayer, bus driver, cannery worker, carpenter, sheet metal worker, baker)',
         'semi-skilled'),
        ('Unskilled worker (for example: laborer, porter, unskilled factory worker, cleaner)',
         'unskilled'), ('Farm worker', 'farm worker'),
        ('Farm proprietor or manager', 'farm manager'),
        ('Never had a job', 'none')
    ],
                          var='Occupation',
                          validate=V.require() if require else None)
    return _debug_choices(occupation_q, require)
예제 #5
0
def marital_status(require=False):
    status_q = Select('What is your marital status?', [
        '', 'Married', 'Living together as married', 'Divorced', 'Separated',
        'Widowed', 'Single'
    ],
                      var='MaritalStatus',
                      validate=V.require() if require else None)
    return _debug_choices(status_q, require)
예제 #6
0
def household_residents(require=False):
    return Input(
        'How many people regularly live in your household, including yourself and children?',
        var='NHouseholdResidents',
        type='number',
        min=1,
        validate=V.require() if require else None,
        debug=D.send_keys(str(randint(1, 10)), p_exec=1 if require else .8))
예제 #7
0
def children(require=False):
    return Input('How many children do you have?',
                 var='NChildren',
                 type='number',
                 min=0,
                 validate=V.require() if require else None,
                 debug=D.send_keys(str(randint(0, 10)),
                                   p_exec=1 if require else .8))
예제 #8
0
def save_money(require=False):
    save_q = Select('In the last year, did your family:', [
        '', ('Save money', 'save'), ('Just get by', 'get by'),
        ('Spent some savings', 'spent'),
        ('Spent savings and borrowed money', 'borrowed')
    ],
                    var='Savings',
                    validate=V.require() if require else None)
    return _debug_choices(save_q, require)
예제 #9
0
def age(require=False):
    return Input(
        'How old are you?',
        var='Age',
        type='number',
        min=0,
        max=100,
        validate=V.require() if require else None,
    )
예제 #10
0
def income_group(require=False):
    return RangeInput('''
        On a scale from 0 (lowest) to 10 (highest), which income group does your household belong to?

        Please consider all wages, salaries, pensions, investments, and other income.
        ''',
                      var='IncomeGroup',
                      min=0,
                      max=10,
                      validate=V.require() if require else None)
예제 #11
0
def social_class(require=False):
    social_q = Select(
        'Which social class would you describe yourself as belonging to?', [
            '', ('Upper class', 'upper'),
            ('Upper middle class', 'upper middle'),
            ('Lower middle class', 'lower middle'),
            ('Working class', 'working'), ('Lower class', 'lower')
        ],
        var='SocialClass',
        validate=V.require() if require else None)
    return _debug_choices(social_q, require)
예제 #12
0
def gender(require=False):
    gender = Check('What is your gender?', ['Male', 'Female', 'Other'],
                   var='Gender',
                   validate=V.require() if require else None,
                   submit=_record_male)
    _debug_choices(gender, require)
    specify = Input('Please specify your gender.',
                    var='GenderSpecify',
                    data_rows=-1)
    show_on_event(specify, gender, 'Other')
    return gender, specify
예제 #13
0
def sector(require=False):
    sector_q = Select('''
        Are you working for the government or public institution, for private business or industry, or for a private nonprofit organization? 
        
        If you are not employed, select the option for your most recent job.
        ''', [
        '', ('Government or public instution', 'public'),
        ('Private business or industry', 'private'),
        ('Private non-profit organization', 'non-profit'),
        ('Never had a job', 'none')
    ],
                      var='Sector',
                      validate=V.require() if require else None)
    return _debug_choices(sector_q, require)
예제 #14
0
def employment(require=False):
    employment_q = Select('''
        What is your employment status?
        
        If you have multiple jobs, select the option for your main job.
        ''', [
        '', ('Full time employment (30 or more hours/week)', 'full'),
        ('Part time employment (fewer than 30 hours/week)', 'part'),
        ('Self employed', 'self'), ('Retired/pensioned', 'retired'),
        ('Stay at home spouse not otherwise employed', 'home'),
        ('Student', 'student'), ('Unemployed', 'unemployed')
    ],
                          var='Employment',
                          validate=V.require() if require else None)
    return _debug_choices(employment_q, require)
예제 #15
0
def education(require=False):
    educ_q = Select(
        'What is the highest educational level you have completed? (Values in parentheses are for the U.S. school system.)',
        [
            '', ('Early childhood education or no education', 0),
            ('Primary education (elementary school)', 1),
            ('Lower secondary education (middle school)', 2),
            ('Upper secondary education (high school/GED)', 3),
            ('Post-secondary non-tertiary education (vocational training)', 4),
            ('Short-cycle tertiary education (2-year college)', 5),
            ('Bachelor or equivalent', 6), ('Master or equivalent', 7),
            ('Doctoral or equivalent', 8)
        ],
        var='Education',
        validate=V.require() if require else None)
    return _debug_choices(educ_q, require)
예제 #16
0
def religion(require=False):
    religion_q = Select(
        'Which religion or religious denomination do you belong to, if any?', [
            '', 'None', 'Roman Catholic', 'Protestant',
            ('Orthodox (Russian, Greek, etc.)', 'Orthodox'), 'Jewish',
            'Muslim', 'Hindu', 'Buddhist', 'Other'
        ],
        var='Religion',
        validate=V.require() if require else None)
    _debug_choices(religion_q, require)
    specify = Input(
        'Please specify your religion or religious denomination.',
        var='RelgionSpecify',
    )
    show_on_event(specify, religion_q, 'Other')
    return religion_q, specify
예제 #17
0
def crt(*items, page=False, require=False, shuffle=False):
    """
    Parameters
    ----------
    \*items : str
        The names of CRT items. If no items are given, the standard 3-item CRT
        is used. [See the full list of available items.](items.md).

    page : bool, default=False
        Indicates that items should be in separate pages.

    require : bool, default=False
        Indicates that responses are required.

    shuffle : bool, default=False
        Indicates that items should be shuffled.

    Returns
    -------
    CRT items : list
        List of `hemlock.Question` if not `page`, otherwise list of 
        `hemlock.Page`.
    """
    if 'CRT_Total' not in current_user.g:
        current_user.g.update({
            'CRT_Total': 0,
            'CRT_Correct': 0,
            'CRT_Intuitive': 0
        })
    items = items if items else ['bat_ball', 'widgets', 'lily_pads']
    items = [crt_items[item]() for item in items]
    if require:
        for item in items:
            item.validate.append(V.require())
    if page:
        items = [
            Page(item,
                 name=item.var,
                 timer=(item.var + 'Time', -1),
                 debug=[D.debug_questions(), D.forward()]) for item in items
        ]
    if shuffle:
        random.shuffle(items)
    return items
예제 #18
0
def start():
    return Branch(
        Page(
            Label(texts.consent_label),
            Check(
                choices=[('I consent to participate', 'consent')],
                validate=V.correct_choices(
                    'consent', 
                    error_msg='<p>Please consent to participate.</p>'
                )
            )
        ),
        demographics(
            'age_bins', 'gender', 'race', 'education', 
            page=True, require=True
        ),
        *crt(page=True, require=True),
        berlin(require=True),
        navigate=N.comprehension()
    )
예제 #19
0
def race(require=False):
    race_q = Check('''
        Which race or ethnicity do you belong to?

        Check as many as apply.
        ''', [
        'White', 'Black',
        ('South Asian (Indian, Pakistani, etc.)', 'South Asian'),
        ('East Asian (Chinese, Japanese, etc.)', 'East Asian'),
        'Arabic or Central Asian', 'Other'
    ],
                   var='Race',
                   multiple=True,
                   validate=V.min_len(1) if require else None)
    _debug_choices(race_q, require)
    specify = Input('Please specify your race or ethnicity.',
                    var='RaceSpecify',
                    data_rows=-1)
    show_on_event(specify, race_q, 'Other')
    return race_q, specify
예제 #20
0
def start():
    return Branch(
        *comprehension_check(
            instructions=Page(
                Label('Here are some instructions')
            ),
            checks=Page(
                Check(
                    '<p>Select the correct choice.</p>',
                    ['Correct', 'Incorrect', 'Also incorrect'],
                    compile=[C.clear_response(), C.shuffle()],
                    validate=V.require(),
                    submit=S.correct_choices('Correct')
                )
            ),
            attempts=3
        ),
        Page(
            Label('You passed the comprehension check!'),
            terminal=True
        )
    )
예제 #21
0
def birth_year(require=False):
    years = list(range(1900, datetime.now().year))
    years.sort(reverse=True)
    return Select('What year were you born in?', [''] + years,
                  validate=V.require() if require else None)
예제 #22
0
def primary_wage_earner(require=False):
    wage_q = binary('Are you the primary wage earner in your household?',
                    var='PrimaryWageEarner',
                    validate=V.require() if require else None)
    return _debug_choices(wage_q, require)
예제 #23
0
def second_estimates_branch(first_estimate_branch, first_estimate_questions):
    """Create branch for second estimates

    :param first_estimate_branch: branch for first estimates
    :type first_estimate_branch: hemlock.Branch
    :param first_estimate_questions: questions containing participant's first estimates
    :type first_estimate_questions: list of (time-series key, question) tuples
    :return: second estimates branch
    :rtype: hemlock.Branch
    """
    def make_instructions_labels():
        """
        :return: instructions labels for second estimates
        :rtype: list of hemlock.Label
        """
        labels = [Label(open('texts/second_estimate.md', 'r').read())]
        if current_user.meta['Context'] == 'second-only':
            labels.append(Label(open('texts/second_estimate_addcontext.md')))
        return labels

    def make_second_estimate_page(i, key, questions):
        """
        :param i: estimate number
        :type i: int
        :param key: name of time-series
        :type key: str
        :param questions: corresponding first estimate questions
        :type questions: list of hemlock.Blank
        :return: page asking for second estimates
        :rtype: hemlock.Page
        """
        labels = make_fcast_question_labels(key, context)
        return Page(
            Label(progress(i / N_FCASTS, f'Estimate {i+1} of {N_FCASTS}')),
            Dashboard(src='/dashapp/',
                      g={
                          'fcast_key': key,
                          'context': context
                      }),
            Label(f'''
                Your first estimates were:

                {make_list(
                    [
                        label[0]+q.response+label[1]
                        for label, q in zip(labels, questions)
                    ]
                )}
                '''),
            # additional questions (i.e., for dialectical bootstrapping)
            *make_additional_questions(),
            # estimation questions
            *make_fcast_questions(key, context, first_estimate=False),
            timer='SecondEstimateTime')

    def make_additional_questions():
        """Make additional questions, such as prompts for dialectical bootstrapping

        :return: additional questions
        :rtype: list of hemlock.Question
        """
        if not current_user.meta['Bootstrap']:
            return [
                Label('''
                Please make second estimates which are different from your first estimates.
                ''')
            ]
        return [
            Textarea('''
                Imagine your first estimates were off the mark. Write at least one reason why that could be. Which assumptions or considerations could have been wrong?
                ''',
                     var='Assumptions',
                     required=True,
                     validate=V.min_words(7),
                     debug=[
                         D.send_keys('here are 7 words without a meaning'),
                         D.send_keys(p_exec=.2)
                     ]),
            Check('''
                What does this reason imply? Were your first estimates too high or too low?
                ''', [('Too high', 'high'), ('Too low', 'low'),
                      ('Some were too high, others too low', 'both')],
                  var='Direction',
                  validate=V.require()),
            Label('''
                Based on this new perspective, make second estimates which are different from your first estimates.
                ''')
        ]

    context = use_context(first_estimate=False)
    return Branch(
        Page(Label(INSTRUCTIONS['second'][current_user.meta['Context']])), *[
            make_second_estimate_page(i, key, questions)
            for i, (key, questions) in enumerate(first_estimate_questions)
        ],
        Page(*[
            likert(
                f'Compared to the average person, how much do you know about {forecast_questions[key]["know_about"]}?',
                [
                    'Much less than average', 'Less than average',
                    'About average', 'More than average',
                    'Much more than average'
                ],
                var='ContextKnowledge') for key, _ in first_estimate_questions
        ]),
        Page(
            binary('''
                Did you look up the answers to any of the questions we asked?

                It's important that you answer honestly for research purposes. Your answer won't affect your bonus.
                ''',
                   var='LookUp',
                   data_rows=-1,
                   validate=V.require()),
            Textarea(
                'Do you have any suggestions for how to improve our study? Feedback is greatly appreciated!',
                var='AdditionalComments',
                data_rows=-1)), completion_page())