apps: - bots: 'yield Welcome yield Consent yield InstructionsIntro' constants: - datatype: int js_value: 2 name: PLAYERS_PER_GROUP - datatype: int js_value: 1 name: NUM_ROUNDS custom_export: "# Header\nyield [\n 'session_code',\n 'participant_id_in_session',\n \ 'participant_code',\n 'id_in_group',\n 'group_number'\n]\n\n# Rows\nfor p in players:\n pp = p.participant\n pg = p.group\n ps = p.session\n \ \n yield [\n ps.code,\n pp.id_in_session,\n pp.code,\n \ p.id_in_group,\n pg.id_in_subsession\n ]" doc: Intro to experiment. Provides players brief introduction and gets informed consent. Then plays video instructions for first phase of experiment. includable_templates: - content: "\n{% load otree %}\n\n\n\n" name: uw_teton_bg models: Group: fields: [] methods: [] Player: fields: - datatype: StringField kwargs: blank: null choices: null initial: null label: constant: null expr_type: plain js_value: Please enter your couple code widget: null name: couple_code - datatype: IntegerField kwargs: blank: null choices: constant: null expr_type: plain js_value: [] initial: null label: null max: null min: null widget: null name: my_field methods: [] Subsession: fields: [] methods: - code: "# Build a dict: code → list of player IDs\nbuckets = {}\nfor p in subsession.get_players():\n \ buckets.setdefault(p.couple_code.strip().lower(), []).append(p.id_in_subsession)\n# Now turn that into a list-of-lists matrix\nmatrix = [ids for ids in buckets.values() if len(ids) == 2]\n# (You can handle odd or mistyped codes however you like here.)\nsubsession.set_group_matrix(matrix)\nsubsession.session.vars['couple_matrix'] = matrix" is_method: false name: after_all_players_arrive name: Intro pages: - app_after_this_page: null before_next_page: '# copy into participant.vars so it’s visible at grouping time player.participant.vars[''couple_code''] = player.couple_code' error_message: null form_fields: - couple_code form_model: player get_form_fields: null get_timeout_seconds: null is_displayed: null is_waitpage: false js_vars: null live_method: null name: Assignment template: content: ' {{ include_sibling ''uw_teton_bg.html'' }} {{ formfields }} {{ next_button }}' javascript: null title: Couple Assignment timeout_seconds: null timer_text: null vars_for_template: null - after_all_players_arrive: after_all_players_arrive body_text: null group_by_arrival_time: null is_displayed: null is_waitpage: true name: AssignmentWaitPage template: null title_text: null wait_for_all_groups: true - app_after_this_page: null before_next_page: null error_message: null form_fields: null form_model: player get_form_fields: null get_timeout_seconds: null is_displayed: null is_waitpage: false js_vars: null live_method: null name: Welcome template: content: "\n{{ include_sibling 'uw_teton_bg.html' }}\n\n

\n You are about to participate in an economic decision-making study. You have the opportunity to make money in this study. How much money you make depends on your decisions. Whatever money you make will be paid to you in cash at the end of the study.\n

\n \ \n

\n During the study, verbal or nonverbal communication with other participants, cell phone use, and so on, is strictly prohibited. Communication between participants will lead to your exclusion from the study and forfeiting all monetary earnings. Please raise your hand if you have any questions; a member of the research team will come to you and answer your questions privately.\n

\n\n{{ next_button }}" javascript: null title: Welcome timeout_seconds: null timer_text: null vars_for_template: null - app_after_this_page: null before_next_page: null error_message: null form_fields: null form_model: player get_form_fields: null get_timeout_seconds: null is_displayed: null is_waitpage: false js_vars: null live_method: null name: Consent template: content: "\n{{ include_sibling 'uw_teton_bg.html' }}\n\n\n\n

\n Thank you for signing up to participate in a decision-making study. The study should last about {{session.config.exp_time}}, and you will be paid in cash at the end of the study.\n

\n\n

\n Participation is voluntary. Your decisions will remain confidential, and your name will not be recorded anywhere in the data. All information collected in this study is confidential and will be used for statistical purposes only. The data will be securely stored. The risks associated with this study are minimal. Risks are similar to everyday computer use, though some participants may feel some stress in playing a game. Although this study will not benefit you personally, the results will help our understanding of strategic behavior.\n

\n\n

\n The University of Wyoming, the principal investigator, and the research team are not liable for any injury participants might sustain while participating in this study and are not able to offer financial compensation or absorb the costs of medical treatment should the participant sustain such an injury. By agreeing to participate, you do not waive any of your legal rights; however, no funds have been set aside to compensate you in the event of injury.\n

\n\n

\n For additional information related to this study, contact Dr. Linda Thunström, Department of Economics, University of Wyoming, at lthunstr@uwyo.edu, or Collin DePaemelere, Department of Economics, University of Wyoming, at cdepaeme@uwyo.edu. University of Wyoming's Institutional Review Board (IRB) has determined this study to be exempt from review by the IRB administration. You can contact UW IRB if you have questions about your rights as participants (irb@uwyo.edu; 307-766-5322).\n

\n\n

\n \ By continuing in the session, you are indicating that you are at least 18 years old, have read and understood this consent form, and agree to participate. Thank you.\n

\n\n{% next_button %}" javascript: null title: Consent timeout_seconds: null timer_text: null vars_for_template: "return dict(\n my_label=player.participant.label,\n my_group=player.group.id_in_subsession,\n)" - after_all_players_arrive: null body_text: null group_by_arrival_time: null is_displayed: null is_waitpage: true name: IntroEndPage template: null title_text: null wait_for_all_groups: true - bots: '' constants: - datatype: int js_value: 2 name: PLAYERS_PER_GROUP - datatype: int js_value: 1 name: NUM_ROUNDS - datatype: list_str js_value: - A - B - C - D - E - F - G - H - I - J name: CHOICES custom_export: "# Header\nyield [\n 'session_code',\n 'participant_id_in_session',\n \ 'participant_code',\n 'id_in_group',\n 'group_number',\n 'ranking',\n \ 'partner_ranking',\n 'correct_belief',\n 'spender_item'\n]\n\n# Rows\nfor p in players:\n pp = p.participant\n pg = p.group\n ps = p.session\n \ \n # Pull participant fields (needed as these are only saved in 'all apps wide' normally)\n correct_belief = p.participant.vars.get('correct_belief', '')\n \n yield [\n ps.code,\n pp.id_in_session,\n pp.code,\n \ p.id_in_group,\n pg.id_in_subsession,\n p.ranking,\n p.partner_ranking,\n \ correct_belief,\n pg.spender_item\n ]" doc: 'Preference rating of potential items for BDM auction. Involves participants ranking their preferences for the selection of items, and then predicting their partner''s preferences. ' includable_templates: - content: '{% load otree %}' name: instructions - content: "\n{% load otree %}\n\n\n\n" name: uw_teton_bg - content: "" name: data_id models: Group: fields: - datatype: StringField kwargs: blank: null choices: null initial: null label: null widget: null name: spender_item methods: - code: "import json\n\n# Retrieve all players in the group\nplayers = group.get_players()\n\n# Map actual preferences for easy reference\nactual_prefs = {p.id_in_group: p.ranking.split(',') for p in players}\n\nfor p in players:\n # Only proceed if there are valid rankings\n if p.ranking and p.partner_ranking:\n \ \n # Split the comma-separated strings of rankings into lists of item IDs\n own_pref = p.ranking.split(',')\n predicted_partner_pref = p.partner_ranking.split(',')\n\n # Find the group partner\n partner = p.get_others_in_group()[0]\n partner_actual_pref = actual_prefs[partner.id_in_group]\n \ \n # Calculate differences between own preference and partner's actual preference\n differences = {}\n for item in own_pref:\n \ index1 = own_pref.index(item)\n index2 = predicted_partner_pref.index(item)\n \ differences[item] = index1 - index2\n\n diffs = json.dumps([differences])\n \ min_difference = min(differences.values(), key=lambda x: (x, own_pref.index(item)))\n \ selected_item = [key for key, value in differences.items() if value == min_difference][0]\n\n # Store selected item and differences\n \ p.participant.selected_item = selected_item\n p.diffs = diffs\n \ \n # Only proceed if there are valid partner rankings\n if partner_actual_pref != ['']:\n\n # Count matching positions between predicted and actual preferences\n match_count = sum([\n predicted_partner_pref[i] == partner_actual_pref[i]\n for i in range(len(predicted_partner_pref))\n \ ])\n\n # Store the number of matches\n p.participant.belief_match_count = match_count\n\n # Reward if at least 5 match\n p.participant.correct_belief = 1 if match_count >= session.config['match_requirement'] else 0\n \n \ # If any partner ranking is left blank\n else:\n p.participant.belief_match_count = 0\n p.participant.correct_belief = 0\n \n # If any personal ranking is left blank\n else:\n p.diffs = json.dumps([{\"\": 0}])\n \ p.participant.selected_item = \"\"\n p.participant.belief_match_count = 0\n p.participant.correct_belief = 0" is_method: false name: set_pref_diff - code: "import random\n\n# Randomly choosing one of the group members to be the earner in round 1\nr = random.randint(1,2)\n\n# Gather players \nplayers = group.get_players()\n\n# Assign roles based on random draw\nfor p in players:\n \ if p.id_in_group == r: # If your player id in your group matches the draw, you are the spender (permanent throughout experiment)\n p.participant.spender = 1\n group.spender_item = p.participant.selected_item \n else: # If not, then you will sit out of the spending tasks\n p.participant.spender = 0\n \n # set the exit\n p.participant.exit_1 = 0" is_method: false name: assign_spender - code: "# Gather players \nplayers = group.get_players()\n\n# Assign roles based on random draw\nfor p in players:\n# set spender_selected_item so both players see same item later\n p.participant.spender_selected_item = group.spender_item" is_method: false name: assign_spender_item Player: fields: - datatype: StringField kwargs: blank: null choices: null initial: null label: null widget: null name: ranking - datatype: StringField kwargs: blank: null choices: null initial: null label: null widget: null name: partner_ranking - datatype: LongStringField kwargs: blank: null choices: null initial: null label: null widget: null name: diffs methods: [] Subsession: fields: [] methods: - code: "# pull the matrix you stored in the code‐entry app\nmatrix = subsession.session.vars.get('couple_matrix')\nif not matrix:\n # safety check in case someone forgot to run grouping first\n \ raise RuntimeError(\"No couple_matrix in session.vars\")\n# re‐apply it in this app's subsession\nsubsession.set_group_matrix(matrix)" is_method: false name: after_all_players_arrive name: PrefRating pages: - after_all_players_arrive: after_all_players_arrive body_text: null group_by_arrival_time: null is_displayed: null is_waitpage: true name: GroupingWaitPage template: null title_text: null wait_for_all_groups: true - app_after_this_page: null before_next_page: null error_message: null form_fields: - ranking form_model: player get_form_fields: null get_timeout_seconds: null is_displayed: null is_waitpage: false js_vars: null live_method: null name: PrefRanking template: content: "\n{{ include_sibling 'uw_teton_bg.html' }}\n\n\n

\n Please arrange the items in the list by dragging them into your own preferred order. Start with the item you like the most, placing it at the top of the list (ranked as 1), and proceed to rank each item in descending order of your own preference until the item you like the least, which should be placed at the bottom (ranked as 10). All items are of equal market value and are priced at approximately $30.\n

\n\n\n
\n \n \n
\n\n\n\n\n\n\n\n\n\n{{ formfield_errors 'ranking' }}\n\n\n{{ next_button }}" javascript: '' title: Personal Product Ranking timeout_seconds: null timer_text: null vars_for_template: "# Define the list of items with unique identifiers, their associated image URLs, and a description\nimgur_urls = [\n {'id': 'A', 'url': 'https://i.imgur.com/OfsrPbR.jpeg', 'description': \"Coloring book with pencils\"}, # Image and description for item A\n {'id': 'B', 'url': 'https://i.imgur.com/tmBYFwX.jpeg', 'description': \"Headphones\"}, # Image and description for item B\n {'id': 'C', 'url': 'https://i.imgur.com/oBfC4Mz.jpeg', 'description': \"Moisturizer\"}, # Image and description for item C\n {'id': 'D', 'url': 'https://i.imgur.com/q7bBuv6.jpeg', 'description': \"Spa kit\"}, # Image and description for item D\n {'id': 'E', 'url': 'https://i.imgur.com/Zc7vR6m.jpeg', 'description': \"Grilling accessories\"}, # Image and description for item E\n {'id': 'F', 'url': 'https://i.imgur.com/YLEoKGI.jpeg', 'description': \"Tactical flashlight\"}, # Image and description for item F\n \ {'id': 'G', 'url': 'https://i.imgur.com/lmMFuFL.jpeg', 'description': \"Lip Balm\"}, # Image and description for item G\n {'id': 'H', 'url': 'https://i.imgur.com/5KfUIfj.jpeg', 'description': \"Water bottle\"}, # Image and description for item H\n {'id': 'I', 'url': 'https://i.imgur.com/AS1feBP.jpeg', 'description': \"Car detailing kit\"}, # Image and description for item I\n {'id': 'J', 'url': 'https://i.imgur.com/SfJ7GmF.jpeg', 'description': \"Multi-tool\"} # Image and description for item J\n]\n\n# Passing Python variables to the HTML template of the page\nreturn dict(\n image_paths=imgur_urls # Key 'image_paths' will be accessible in the HTML template\n )" - app_after_this_page: null before_next_page: null error_message: null form_fields: - partner_ranking form_model: player get_form_fields: null get_timeout_seconds: null is_displayed: null is_waitpage: false js_vars: null live_method: null name: PartnerPrefRanking template: content: "\n{{ include_sibling 'uw_teton_bg.html' }}\n\n\n

\n Please arrange the items in the list by dragging them into your partner's preferred order, based on your understanding of their tastes. Start with the item you believe your partner likes the most, placing it at the top of the list (ranked as 1), and proceed to rank each item in descending order of preference until the item you believe they like the least, which should be placed at the bottom (ranked as 10). All items are of equal market value and are priced at approximately $30.\n

\n\n

\n You can earn money from this task. Your partner will also rank these items for themselves. If you can correctly guess your partner's rankings, you earn ${{ session.config.belief_payout }}. Specifically, we will compare your guess of your partner's preferences to your partner's actual ranking. If you have accurately guessed the numerical ranking of least {{ session.config.match_requirement }} of these items, you will earn ${{ session.config.belief_payout }}.\n

\n\n\n
\n \n \n
\n\n\n\n\n\n\n\n\n\n{{ formfield_errors 'partner_ranking' }}\n\n\n{{ next_button }}" javascript: null title: Partner Product Ranking timeout_seconds: null timer_text: null vars_for_template: "# Define the list of items with unique identifiers, their associated image URLs, and a description\nimgur_urls = [\n {'id': 'A', 'url': 'https://i.imgur.com/OfsrPbR.jpeg', 'description': \"Coloring book with pencils\"}, # Image and description for item A\n {'id': 'B', 'url': 'https://i.imgur.com/tmBYFwX.jpeg', 'description': \"Headphones\"}, # Image and description for item B\n {'id': 'C', 'url': 'https://i.imgur.com/oBfC4Mz.jpeg', 'description': \"Moisturizer\"}, # Image and description for item C\n {'id': 'D', 'url': 'https://i.imgur.com/q7bBuv6.jpeg', 'description': \"Spa kit\"}, # Image and description for item D\n {'id': 'E', 'url': 'https://i.imgur.com/Zc7vR6m.jpeg', 'description': \"Grilling accessories\"}, # Image and description for item E\n {'id': 'F', 'url': 'https://i.imgur.com/YLEoKGI.jpeg', 'description': \"Tactical flashlight\"}, # Image and description for item F\n \ {'id': 'G', 'url': 'https://i.imgur.com/lmMFuFL.jpeg', 'description': \"Lip Balm\"}, # Image and description for item G\n {'id': 'H', 'url': 'https://i.imgur.com/5KfUIfj.jpeg', 'description': \"Water bottle\"}, # Image and description for item H\n {'id': 'I', 'url': 'https://i.imgur.com/AS1feBP.jpeg', 'description': \"Car detailing kit\"}, # Image and description for item I\n {'id': 'J', 'url': 'https://i.imgur.com/SfJ7GmF.jpeg', 'description': \"Multi-tool\"} # Image and description for item J\n]\n\n# Passing Python variables to the HTML template of the page\nreturn dict(\n image_paths=imgur_urls # Key 'image_paths' will be accessible in the HTML template\n )" - after_all_players_arrive: set_pref_diff body_text: null group_by_arrival_time: null is_displayed: null is_waitpage: true name: PrefDiffWaitPage template: null title_text: null wait_for_all_groups: null - after_all_players_arrive: assign_spender body_text: null group_by_arrival_time: null is_displayed: null is_waitpage: true name: AssignSpenderWaitPage template: null title_text: null wait_for_all_groups: null - after_all_players_arrive: assign_spender_item body_text: null group_by_arrival_time: null is_displayed: null is_waitpage: true name: AssignSpenderItemWaitPage template: null title_text: null wait_for_all_groups: null - after_all_players_arrive: null body_text: null group_by_arrival_time: null is_displayed: null is_waitpage: true name: PrefRatingEndPage template: null title_text: null wait_for_all_groups: true - bots: '' constants: - datatype: int js_value: 2 name: PLAYERS_PER_GROUP - datatype: int js_value: 1 name: NUM_ROUNDS - datatype: str js_value: 'CQ1: The answer is TRUE. They will be presented with a series of matrices and will need to count the number of 1s.' name: Q1_ANSWER - datatype: str js_value: 'CQ2: The answer is FALSE. They will be rewarded per matrix they complete.' name: Q2_ANSWER - datatype: str js_value: 'CQ3: The answer is FALSE. One of you will be picked at random to complete the earnings task, while the other waits.' name: Q3_ANSWER custom_export: "# Header\nyield [\n 'session_code',\n 'participant_id_in_session',\n \ 'participant_code',\n 'id_in_group',\n 'group_number',\n 'RET_cq_1',\n \ 'RET_cq_2',\n 'RET_cq_3'\n]\n\n# Rows\nfor p in players:\n pp = p.participant\n \ pg = p.group\n ps = p.session\n \n yield [\n ps.code,\n pp.id_in_session,\n \ pp.code,\n p.id_in_group,\n pg.id_in_subsession,\n p.cq_1,\n \ p.cq_2,\n p.cq_3\n ]" doc: Provides video instructions for the earning task, with comprehension questions for additional understanding. includable_templates: - content: "\n{% load otree %}\n\n\n\n" name: uw_teton_bg models: Group: fields: [] methods: - code: '' is_method: false name: my_function Player: fields: - datatype: BooleanField kwargs: blank: null choices: constant: null expr_type: plain js_value: - - true - 'True' - - false - 'False' initial: null label: constant: null expr_type: plain js_value: The person assigned to earning money will earn money by counting the number of 1s in a matrix. widget: null name: cq_1 - datatype: BooleanField kwargs: blank: null choices: constant: null expr_type: plain js_value: - - true - 'True' - - false - 'False' initial: null label: constant: null expr_type: plain js_value: The person earning money will only be rewarded if they get every matrix correct. widget: null name: cq_2 - datatype: BooleanField kwargs: blank: null choices: constant: null expr_type: plain js_value: - - true - 'True' - - false - 'False' initial: null label: constant: null expr_type: plain js_value: You and your partner will both get the opportunity to do the earnings task. widget: null name: cq_3 methods: [] Subsession: fields: [] methods: - code: "# pull the matrix you stored in the code‐entry app\nmatrix = subsession.session.vars.get('couple_matrix')\nif not matrix:\n # safety check in case someone forgot to run grouping first\n \ raise RuntimeError(\"No couple_matrix in session.vars\")\n# re‐apply it in this app's subsession\nsubsession.set_group_matrix(matrix)" is_method: false name: after_all_players_arrive name: RET_instructions pages: - after_all_players_arrive: after_all_players_arrive body_text: null group_by_arrival_time: null is_displayed: null is_waitpage: true name: GroupingWaitPage template: null title_text: null wait_for_all_groups: true - app_after_this_page: null before_next_page: null error_message: null form_fields: null form_model: player get_form_fields: null get_timeout_seconds: null is_displayed: null is_waitpage: false js_vars: null live_method: null name: ExpIntro template: content: "\n{{ include_sibling 'uw_teton_bg.html' }}\n\n

\n This study will consist of 2 rounds. Within each round, your performance will directly impact your final earnings. At the end of the study, we will randomly draw one round to determine your final payoff.\n

\n\n{{ next_button }}" javascript: null title: Instructions timeout_seconds: null timer_text: null vars_for_template: null - app_after_this_page: null before_next_page: null error_message: null form_fields: - cq_1 form_model: player get_form_fields: null get_timeout_seconds: null is_displayed: null is_waitpage: false js_vars: null live_method: null name: EarnerInstructions template: content: "\n{{ include_sibling 'uw_teton_bg.html' }}\n\n\n\n\n\n\n\n

\n \ In one part of the study, you or your partner will be randomly chosen to get the opportunity to earn money. The person selected will earn their money by completing a task that involves counting the number of 1s in matrices made up of 1s and 0s. \n

\n\n

\n If you are chosen to do the matrix task to earn money, your task is to count the number of 1s in each matrix. Your pay from this task will be determined by how many matrices you correctly answer. If you answer a matrix incorrectly, you will move on to a new matrix. You will have {{session.config.time_limit}} minutes to earn up to ${{max_budget}} by completing up to {{session.config.num_correct}} matrices.\n

\n

\n \ You will each get an opportunity to practice the matrix task. Below is an example of a {{session.config.m_size}} by {{session.config.m_size}} matrix identical to what you would see during the task. In this example, there are {{matrix_sum}} total 1s that you would need to count.\n

\n\n\n {% for row in matrix %} \n {% for cell in row %} \n {% endfor %} \n {% endfor %} \n
{{ cell }}

\n\n{{ formfields }}\n\n{{ next_button }}" javascript: null title: Earning Money timeout_seconds: null timer_text: null vars_for_template: "import random\n\n# Generate C.M_SIZExC.M_SIZE matrix with random 0s and 1s\nmatrix = [[random.randint(0, 1) for _ in range(session.config['m_size'])] for _ in range(session.config['m_size'])]\n\n# Calculate the sum of all 1s in the matrix\nmatrix_sum = sum(sum(row) for row in matrix)\n\n# Calculate max earnings from the task\nmax_budget = session.config['x_rate'] * session.config['num_correct']\n\n# Passing Python variables to the HTML template of the page\nreturn dict(\n matrix=matrix,\n \ matrix_sum=matrix_sum,\n max_budget = max_budget\n)" - app_after_this_page: null before_next_page: null error_message: null form_fields: - cq_2 form_model: player get_form_fields: null get_timeout_seconds: null is_displayed: null is_waitpage: false js_vars: null live_method: null name: CQ_2 template: content: "\n{{ include_sibling 'uw_teton_bg.html' }}\n\n\n\n\n\n\n\n

\n \ In one part of the study, you or your partner will be randomly chosen to get the opportunity to earn money. The person selected will earn their money by completing a task that involves counting the number of 1s in matrices made up of 1s and 0s. \n

\n\n

\n If you are chosen to do the matrix task to earn money, your task is to count the number of 1s in each matrix. Your pay from this task will be determined by how many matrices you correctly answer. If you answer a matrix incorrectly, you will move on to a new matrix. You will have {{session.config.time_limit}} minutes to earn up to ${{max_budget}} by completing up to {{session.config.num_correct}} matrices.\n

\n

\n \ You will each get an opportunity to practice the matrix task. Below is an example of a {{session.config.m_size}} by {{session.config.m_size}} matrix identical to what you would see during the task. In this example, there are {{matrix_sum}} total 1s that you would need to count.\n

\n\n\n {% for row in matrix %} \n {% for cell in row %} \n {% endfor %} \n {% endfor %} \n
{{ cell }}

\n\n

\n {{ C.Q1_ANSWER }}\n

\n
\n\n{{ formfields }}\n\n{{ next_button }}" javascript: null title: Comprehension Questions timeout_seconds: null timer_text: null vars_for_template: "import random\n\n# Generate C.M_SIZExC.M_SIZE matrix with random 0s and 1s\nmatrix = [[random.randint(0, 1) for _ in range(session.config['m_size'])] for _ in range(session.config['m_size'])]\n\n# Calculate the sum of all 1s in the matrix\nmatrix_sum = sum(sum(row) for row in matrix)\n\n# Calculate max earnings from the task\nmax_budget = session.config['x_rate'] * session.config['num_correct']\n\n# Passing Python variables to the HTML template of the page\nreturn dict(\n matrix=matrix,\n \ matrix_sum=matrix_sum,\n max_budget = max_budget\n)" - app_after_this_page: null before_next_page: null error_message: null form_fields: - cq_3 form_model: player get_form_fields: null get_timeout_seconds: null is_displayed: null is_waitpage: false js_vars: null live_method: null name: CQ_3 template: content: "\n{{ include_sibling 'uw_teton_bg.html' }}\n\n\n\n\n\n\n\n

\n \ In one part of the study, you or your partner will be randomly chosen to get the opportunity to earn money. The person selected will earn their money by completing a task that involves counting the number of 1s in matrices made up of 1s and 0s. \n

\n\n

\n If you are chosen to do the matrix task to earn money, your task is to count the number of 1s in each matrix. Your pay from this task will be determined by how many matrices you correctly answer. If you answer a matrix incorrectly, you will move on to a new matrix. You will have {{session.config.time_limit}} minutes to earn up to ${{max_budget}} by completing up to {{session.config.num_correct}} matrices.\n

\n

\n \ You will each get an opportunity to practice the matrix task. Below is an example of a {{session.config.m_size}} by {{session.config.m_size}} matrix identical to what you would see during the task. In this example, there are {{matrix_sum}} total 1s that you would need to count.\n

\n\n\n {% for row in matrix %} \n {% for cell in row %} \n {% endfor %} \n {% endfor %} \n
{{ cell }}

\n\n

\n {{ C.Q1_ANSWER }}\n

\n
\n

\n {{ C.Q2_ANSWER }}\n

\n
\n\n{{ formfields }}\n\n{{ next_button }}" javascript: null title: Comprehension Questions timeout_seconds: null timer_text: null vars_for_template: "import random\n\n# Generate C.M_SIZExC.M_SIZE matrix with random 0s and 1s\nmatrix = [[random.randint(0, 1) for _ in range(session.config['m_size'])] for _ in range(session.config['m_size'])]\n\n# Calculate the sum of all 1s in the matrix\nmatrix_sum = sum(sum(row) for row in matrix)\n\n# Calculate max earnings from the task\nmax_budget = session.config['x_rate'] * session.config['num_correct']\n\n# Passing Python variables to the HTML template of the page\nreturn dict(\n matrix=matrix,\n \ matrix_sum=matrix_sum,\n max_budget = max_budget\n)" - app_after_this_page: null before_next_page: null error_message: null form_fields: null form_model: player get_form_fields: null get_timeout_seconds: null is_displayed: null is_waitpage: false js_vars: null live_method: null name: CQ_Answers template: content: "\n{{ include_sibling 'uw_teton_bg.html' }}\n\n\n\n\n\n\n\n

\n \ In one part of the study, you or your partner will be randomly chosen to get the opportunity to earn money. The person selected will earn their money by completing a task that involves counting the number of 1s in matrices made up of 1s and 0s. \n

\n\n

\n If you are chosen to do the matrix task to earn money, your task is to count the number of 1s in each matrix. Your pay from this task will be determined by how many matrices you correctly answer. If you answer a matrix incorrectly, you will move on to a new matrix. You will have {{session.config.time_limit}} minutes to earn up to ${{max_budget}} by completing up to {{session.config.num_correct}} matrices.\n

\n

\n \ You will each get an opportunity to practice the matrix task. Below is an example of a {{session.config.m_size}} by {{session.config.m_size}} matrix identical to what you would see during the task. In this example, there are {{matrix_sum}} total 1s that you would need to count.\n

\n\n\n {% for row in matrix %} \n {% for cell in row %} \n {% endfor %} \n {% endfor %} \n
{{ cell }}

\n\n

\n {{ C.Q1_ANSWER }}\n

\n
\n

\n {{ C.Q2_ANSWER }}\n

\n
\n

\n {{ C.Q3_ANSWER }}\n

\n
\n\n{{ formfields }}\n\n{{ next_button }}" javascript: null title: Comprehension Questions timeout_seconds: null timer_text: null vars_for_template: "import random\n\n# Generate C.M_SIZExC.M_SIZE matrix with random 0s and 1s\nmatrix = [[random.randint(0, 1) for _ in range(session.config['m_size'])] for _ in range(session.config['m_size'])]\n\n# Calculate the sum of all 1s in the matrix\nmatrix_sum = sum(sum(row) for row in matrix)\n\n# Calculate max earnings from the task\nmax_budget = session.config['x_rate'] * session.config['num_correct']\n\n# Passing Python variables to the HTML template of the page\nreturn dict(\n matrix=matrix,\n \ matrix_sum=matrix_sum,\n max_budget = max_budget\n)" - after_all_players_arrive: null body_text: null group_by_arrival_time: null is_displayed: null is_waitpage: true name: RET_instructionsEndPage template: null title_text: null wait_for_all_groups: true - bots: '' constants: - datatype: int js_value: 2 name: PLAYERS_PER_GROUP - datatype: int js_value: 3 name: NUM_ROUNDS - datatype: int js_value: 3 name: NUM_CORRECT custom_export: "# Header\nyield [\n 'session_code',\n 'participant_id_in_session',\n \ 'participant_code',\n 'id_in_group',\n 'group_number'\n]\n\n# Rows\nfor p in players:\n pp = p.participant\n pg = p.group\n ps = p.session\n \ \n yield [\n ps.code,\n pp.id_in_session,\n pp.code,\n \ p.id_in_group,\n pg.id_in_subsession\n ]" doc: Real-effort task (RET) portion of the experiment. RET is counting the number of 1s in a matrix of 1s and 0s. includable_templates: - content: "\n{% load otree %}\n\n\n\n" name: uw_teton_bg models: Group: fields: - datatype: IntegerField kwargs: blank: null choices: null initial: null label: null max: null min: null widget: null name: budget - datatype: IntegerField kwargs: blank: null choices: null initial: constant: null expr_type: plain js_value: 0 label: null max: null min: null widget: null name: correct - datatype: FloatField kwargs: blank: null choices: null initial: null label: null max: null min: null widget: null name: earner_id methods: - code: "# Access all players in the current group\nplayers = group.get_players()\n\n# Exit check for conditions that don't require individual updates\nif group.round_number > 1 and group.correct == C.NUM_CORRECT:\n # Directly carry over the correct count from the previous round\n group.correct = group.in_round(group.round_number - 1).correct\n return\n\n# Initialize or update correct counts for players\nfor p in players:\n # Ensure that player_sum is not None, treat None as an incorrect guess\n if p.player_sum is None:\n p.last_guess_correct = False\n current_guess_correct = 0 # This will treat None as an incorrect guess\n else:\n # Compare player_sum with matrix_sum and update correct and feedback accordingly\n current_guess_correct = int(p.player_sum == p.matrix_sum)\n p.last_guess_correct = (p.player_sum == p.matrix_sum)\n\n # Update the correct count based on the current guess\n if group.round_number == 1:\n p.correct = current_guess_correct\n \ else:\n previous_correct = p.in_round(group.round_number - 1).correct\n \ p.correct = previous_correct + current_guess_correct" is_method: false name: check_func Player: fields: - datatype: IntegerField kwargs: blank: null choices: null initial: constant: null expr_type: plain js_value: 1 label: null max: null min: null widget: null name: matrix_sum - datatype: IntegerField kwargs: blank: null choices: null initial: constant: null expr_type: plain js_value: 0 label: constant: null expr_type: plain js_value: How many 1s are in the above matrix? max: null min: constant: null expr_type: plain js_value: 0 widget: null name: player_sum - datatype: IntegerField kwargs: blank: null choices: null initial: constant: null expr_type: plain js_value: 0 label: null max: null min: constant: null expr_type: plain js_value: 0 widget: null name: correct - datatype: BooleanField kwargs: blank: null choices: null initial: null label: null widget: null name: last_guess_correct - datatype: FloatField kwargs: blank: null choices: null initial: constant: null expr_type: plain js_value: 0 label: null max: null min: null widget: null name: exit_1 methods: - code: return session.config['m_size'] * session.config['m_size'] is_method: false name: player_sum_max Subsession: fields: [] methods: - code: "# pull the matrix you stored in the code‐entry app\nmatrix = subsession.session.vars.get('couple_matrix')\nif not matrix:\n # safety check in case someone forgot to run grouping first\n \ raise RuntimeError(\"No couple_matrix in session.vars\")\n# re‐apply it in this app's subsession\nsubsession.set_group_matrix(matrix)" is_method: false name: after_all_players_arrive name: RET_practice pages: - after_all_players_arrive: after_all_players_arrive body_text: null group_by_arrival_time: null is_displayed: null is_waitpage: true name: GroupingWaitPage template: null title_text: null wait_for_all_groups: true - app_after_this_page: null before_next_page: '' error_message: null form_fields: null form_model: player get_form_fields: null get_timeout_seconds: null is_displayed: "if group.round_number == 1: \n return True" is_waitpage: false js_vars: null live_method: null name: Intro template: content: "{{ include_sibling 'uw_teton_bg.html' }}\n\n

\n Again, you or your partner will be given the chance to earn money by solving matrices. You will now be given a chance to practice the matrix task. In this practice round, both you and your partner will be given the opportunity to solve {{ C.NUM_ROUNDS }} matrices.\n

\n\n{{ next_button }}" javascript: null title: Practice Round timeout_seconds: null timer_text: null vars_for_template: null - app_after_this_page: null before_next_page: "if timeout_happened:\n # Default value for any form fields if timeout occurs, because otherwise they may be left null\n player.player_sum = 0" error_message: null form_fields: - player_sum form_model: player get_form_fields: null get_timeout_seconds: null is_displayed: "# Display if it's round 1\nif group.round_number == 1:\n return True\n\n# Display if it's after round 1 AND is not done with the task\nelif group.in_round(group.round_number - 1).correct != C.NUM_CORRECT:\n return True" is_waitpage: false js_vars: null live_method: null name: Task template: content: "\n{{ include_sibling 'uw_teton_bg.html' }}\n\n\n\n\n\n\n\n\n {% for row in matrix %} \n {% for cell in row %} \n {% endfor %} \n {% endfor %} \n
{{ cell }}
\n\n\n\n\n
\n\n{{ formfields }}\n\n{{ next_button }}" javascript: null title: Practice Task timeout_seconds: 60 timer_text: null vars_for_template: "import random\n\n# Generate C.M_SIZExC.M_SIZE matrix with random 0s and 1s\nmatrix = [[random.randint(0, 1) for _ in range(session.config['m_size'])] for _ in range(session.config['m_size'])]\n\n# Calculate the sum of all 1s in the matrix\nmatrix_sum = sum(sum(row) for row in matrix)\n\n# Store the sum in the player variable\nplayer.matrix_sum = matrix_sum\n\n# Passing Python variables to the HTML template of the page\nreturn dict(\n matrix=matrix,\n matrix_sum=matrix_sum,\n)" - after_all_players_arrive: check_func body_text: null group_by_arrival_time: null is_displayed: null is_waitpage: true name: EarningWaitPage template: null title_text: null wait_for_all_groups: null - app_after_this_page: null before_next_page: null error_message: null form_fields: null form_model: player get_form_fields: null get_timeout_seconds: null is_displayed: "# Display if participant is the earner AND it's round 1\nif group.round_number == 1:\n return True\n\n# Display if participant is the earner AND it's after round 1 AND is not done with the task\nelif group.in_round(group.round_number - 1).correct != C.NUM_CORRECT:\n return True\n\n# Don't display if final round\nif group.round_number == C.NUM_CORRECT:\n return False" is_waitpage: false js_vars: null live_method: null name: Feedback template: content: "\n{{ include_sibling 'uw_teton_bg.html' }}\n\n\n
\n \ {% if player.last_guess_correct %}\n

\n \ Correct! You guessed the right number of 1s.\n

\n {% else %}\n

\n Incorrect guess. You will have another chance with a new matrix.\n

\n {% endif %}\n \ \n \n

\n Number of correct guesses: {{ player.correct }}.\n

\n
\n\n\n{{ next_button }}" javascript: null title: Feedback timeout_seconds: null timer_text: null vars_for_template: null - app_after_this_page: '# Used to skip directly to the next app return "RET_1"' before_next_page: null error_message: null form_fields: null form_model: player get_form_fields: null get_timeout_seconds: null is_displayed: "# Display if they are done or we hit the round limit\nif group.round_number == C.NUM_ROUNDS:\n return True\nelse:\n return False" is_waitpage: false js_vars: null live_method: null name: Results template: content: "\n{{ include_sibling 'uw_teton_bg.html' }}\n\n

\n You have finished the practice round. You correctly guessed {{ player.correct }} of the {{C.NUM_ROUNDS}} matrices. We will now move on to the real task.\n

\n\n{{ next_button }}" javascript: null title: Results timeout_seconds: null timer_text: null vars_for_template: null - after_all_players_arrive: null body_text: null group_by_arrival_time: null is_displayed: "# Display if they are done or we hit the round limit\nif group.round_number == C.NUM_ROUNDS:\n return True\nelse:\n return False" is_waitpage: true name: RET_practiceEndPage template: null title_text: null wait_for_all_groups: true - bots: '' constants: - datatype: int js_value: 2 name: PLAYERS_PER_GROUP - datatype: int js_value: 20 name: NUM_ROUNDS - datatype: str js_value: 'Time left to complete the matrix task:' name: TIMER_TEXT custom_export: "# Header\nyield [\n 'session_code',\n 'participant_id_in_session',\n \ 'participant_code',\n 'id_in_group',\n 'group_number',\n 'earner_round_1',\n \ 'budget_1'\n]\n\n# Rows\nfor p in players:\n pp = p.participant\n pg = p.group\n ps = p.session\n \n # Pull participant fields\n earner_round_1 = p.participant.vars.get('earner_round_1', '')\n budget_1 = p.participant.vars.get('budget_1', '')\n \n yield [\n ps.code,\n pp.id_in_session,\n pp.code,\n \ p.id_in_group,\n pg.id_in_subsession,\n earner_round_1,\n \ budget_1\n ]" doc: Real-effort task (RET) portion of the experiment. RET is counting the number of 1s in a matrix of 1s and 0s. includable_templates: - content: "\n{% load otree %}\n\n\n\n" name: uw_teton_bg models: Group: fields: - datatype: IntegerField kwargs: blank: null choices: null initial: null label: null max: null min: null widget: null name: budget - datatype: IntegerField kwargs: blank: null choices: null initial: constant: null expr_type: plain js_value: 0 label: null max: null min: null widget: null name: correct - datatype: FloatField kwargs: blank: null choices: null initial: null label: null max: null min: null widget: null name: earner_id methods: - code: "# Access all players in the current group\nplayers = group.get_players()\n\n# Exit check for conditions that don't require individual updates\nif group.round_number > 1 and group.correct == session.config['num_correct']:\n # Directly carry over the correct count from the previous round\n group.correct = group.in_round(group.round_number - 1).correct\n return\n\n# Identify the player who did the task in the first round\nptask = group.get_player_by_id(group.in_round(1).earner_id)\n\n# Initialize or update correct counts for players\nfor p in players:\n # Ensure that player_sum is not None, treat None as an incorrect guess\n if p.player_sum is None:\n p.last_guess_correct = False\n current_guess_correct = 0 # This will treat None as an incorrect guess\n else:\n # Compare player_sum with matrix_sum and update correct and feedback accordingly\n \ current_guess_correct = int(p.player_sum == p.matrix_sum)\n p.last_guess_correct = (p.player_sum == p.matrix_sum)\n\n # Update the correct count based on the current guess\n if group.round_number == 1:\n p.correct = current_guess_correct\n else:\n previous_correct = p.in_round(group.round_number - 1).correct\n p.correct = previous_correct + current_guess_correct\n\n \ # Update the group.correct counter if this is the player who did the task\n if p == ptask:\n group.correct = p.correct" is_method: false name: check_func - code: "# Defining player that did the task\nptask = group.get_player_by_id(group.in_round(1).earner_id)\n\n# Setting the budget based on how many were correct and the pay per correct answer\ngroup.budget = ptask.correct * session.config['x_rate']\n\n# Defining the players\nplayers = group.get_players()\n\n# Store budget at the participant level for the next app\nfor p in players:\n p.participant.budget_1 = group.budget" is_method: false name: RET_payoff - code: "import random\n\n# Randomly choosing one of the group members to be the earner in round 1\nr = random.randint(1,2)\n\n# Gather players \nplayers = group.get_players()\n\n# Initialize earner_id at the group level\ngroup.earner_id = None\n\n# Assign roles based on random draw\nfor p in players:\n if p.id_in_group == r:\n p.participant.earner_round_1 = 1\n group.earner_id = p.id_in_group # Store the earner's id_in_group at the group level\n else:\n \ p.participant.earner_round_1 = 0\n \n p.exit_1 = 0" is_method: false name: assign_earner_1 - code: "# Defining players\nplayers = group.get_players()\n\n# Setting the exit condition to avoid duplicating the results page\nfor p in players:\n \ p.exit_1 = 1" is_method: false name: exit Player: fields: - datatype: IntegerField kwargs: blank: null choices: null initial: constant: null expr_type: plain js_value: 1 label: null max: null min: null widget: null name: matrix_sum - datatype: IntegerField kwargs: blank: null choices: null initial: constant: null expr_type: plain js_value: 0 label: constant: null expr_type: plain js_value: How many 1s are in the above matrix? max: null min: constant: null expr_type: plain js_value: 0 widget: null name: player_sum - datatype: IntegerField kwargs: blank: null choices: null initial: constant: null expr_type: plain js_value: 0 label: null max: null min: constant: null expr_type: plain js_value: 0 widget: null name: correct - datatype: BooleanField kwargs: blank: null choices: null initial: null label: null widget: null name: last_guess_correct - datatype: FloatField kwargs: blank: null choices: null initial: constant: null expr_type: plain js_value: 0 label: null max: null min: null widget: null name: exit_1 - datatype: IntegerField kwargs: blank: null choices: constant: null expr_type: plain js_value: - - 1 - The money goes to the participant who earned it through the matrix task - - 2 - The money is split evenly between both partners - - 3 - The participant chosen to spend money keeps all remaining funds initial: null label: constant: null expr_type: plain js_value: What happens to the money in the joint account at the end of the study? max: null min: null widget: constant: null expr_type: plain js_value: RadioSelect name: cq - datatype: IntegerField kwargs: blank: null choices: constant: null expr_type: plain js_value: - - 1 - The money goes to the participant who earned it through the matrix task - - 2 - The money is split evenly between both partners - - 3 - The participant chosen to spend money keeps all remaining funds initial: null label: constant: null expr_type: plain js_value: What happens to the money in the joint account at the end of the study? max: null min: null widget: constant: null expr_type: plain js_value: RadioSelect name: cq_try2 methods: - code: return session.config['m_size'] * session.config['m_size'] is_method: false name: player_sum_max Subsession: fields: [] methods: - code: "# pull the matrix you stored in the code‐entry app\nmatrix = subsession.session.vars.get('couple_matrix')\nif not matrix:\n # safety check in case someone forgot to run grouping first\n \ raise RuntimeError(\"No couple_matrix in session.vars\")\n# re‐apply it in this app's subsession\nsubsession.set_group_matrix(matrix)" is_method: false name: after_all_players_arrive name: RET_1 pages: - after_all_players_arrive: after_all_players_arrive body_text: null group_by_arrival_time: null is_displayed: null is_waitpage: true name: GroupingWaitPage template: null title_text: null wait_for_all_groups: true - after_all_players_arrive: assign_earner_1 body_text: null group_by_arrival_time: null is_displayed: "if group.round_number == 1: \n return True" is_waitpage: true name: RoleAssignmentWaitPage template: null title_text: null wait_for_all_groups: null - app_after_this_page: null before_next_page: '# Set a global ''task_min'' minute timer for all the task pages participant = player.participant import time # Defining the global timer amount using the session.config participant.expiry = time.time() + session.config[''task_min'']*60' error_message: null form_fields: null form_model: player get_form_fields: null get_timeout_seconds: null is_displayed: "if group.round_number == 1: \n return True" is_waitpage: false js_vars: null live_method: null name: RoleAssignment template: content: "\n{{ include_sibling 'uw_teton_bg.html' }}\n\n\n{{ if player.participant.earner_round_1 == 1 }}\n

\n You were randomly selected to earn money by completing the earnings task. You will have {{ session.config.time_limit }} minutes to earn up to ${{max_budget}} by completing {{ session.config.num_correct }} matrices.\n

\n\n\n{{ else }}\n

\n You were not selected to earn money by completing the earnings task. Please wait for further instructions.\n

\n\n{{ endif}}\n\n{{ next_button }}" javascript: null title: Role Assignment timeout_seconds: null timer_text: null vars_for_template: '# Calculate the maximum possible earnings from the task max_budget = session.config[''x_rate''] * session.config[''num_correct''] # Passing Python variables to the HTML template of the page return dict(max_budget = max_budget)' - app_after_this_page: null before_next_page: "if timeout_happened:\n # Default value for any form fields if timeout occurs, because otherwise they may be left null\n player.player_sum = 0" error_message: null form_fields: - player_sum form_model: player get_form_fields: null get_timeout_seconds: '# Using the global timer set at RoleAssignment participant = player.participant import time # Passing the global timer to the HTML template of the page return participant.expiry - time.time()' is_displayed: "import time\n\n# Display if participant is the earner AND it's round 1 AND global timer isn't 0\nif player.participant.earner_round_1 == 1 and group.round_number == 1 and max(participant.expiry - time.time(), 0) > 3:\n \ return True\n\n# Display if participant is the earner AND it's after round 1 AND is not done with the task AND global timer isn't 0\nelif player.participant.earner_round_1 == 1 and group.in_round(group.round_number - 1).correct != session.config['num_correct'] and max(participant.expiry - time.time(), 0) > 3:\n return True" is_waitpage: false js_vars: null live_method: null name: Task template: content: "\n{{ include_sibling 'uw_teton_bg.html' }}\n\n\n\n\n\n\n\n\n {% for row in matrix %} \n {% for cell in row %} \n {% endfor %} \n {% endfor %} \n
{{ cell }}
\n\n\n\n\n
\n\n{{ formfields }}\n\n{{ next_button }}" javascript: null title: Matrix Task timeout_seconds: null timer_text: 'Time left to complete the matrix task:' vars_for_template: "import random\n\n# Generate session.config.m_size x session.config.m_size matrix with random 0s and 1s\nmatrix = [[random.randint(0, 1) for _ in range(session.config['m_size'])] for _ in range(session.config['m_size'])]\n\n# Calculate the sum of all 1s in the matrix\nmatrix_sum = sum(sum(row) for row in matrix)\n\n# Store the sum in the player variable\nplayer.matrix_sum = matrix_sum\n\n# Passing Python variables to the HTML template of the page\nreturn dict(\n matrix=matrix,\n matrix_sum=matrix_sum,\n)" - after_all_players_arrive: check_func body_text: null group_by_arrival_time: null is_displayed: "# Display if earner\nif participant.earner_round_1 == 1:\n return True" is_waitpage: true name: EarningWaitPage template: null title_text: null wait_for_all_groups: null - app_after_this_page: null before_next_page: null error_message: null form_fields: null form_model: player get_form_fields: null get_timeout_seconds: '# Using the global timer set at RoleAssignment participant = player.participant import time # Passing the global timer to the HTML template of the page return participant.expiry - time.time()' is_displayed: "import time\n\n# Display if participant is the earner AND it's round 1 AND global timer isn't 0\nif participant.earner_round_1 == 1 and group.round_number == 1 and max(participant.expiry - time.time(), 0) > 3:\n return True\n\n# Display if participant is the earner AND it's after round 1 AND is not done with the task AND global timer isn't 0\nelif participant.earner_round_1 == 1 and group.in_round(group.round_number - 1).correct != session.config['num_correct'] and max(participant.expiry - time.time(), 0) > 3:\n return True" is_waitpage: false js_vars: null live_method: null name: Feedback template: content: "\n{{ include_sibling 'uw_teton_bg.html' }}\n\n\n\n\n\n
\n {% if player.last_guess_correct %}\n

\n Correct! You guessed the right number of 1s.\n

\n {% else %}\n

\n \ Incorrect guess. You will have another chance with a new matrix.\n \

\n {% endif %}\n \n \n

\n Number of correct guesses: {{ player.correct }}.\n

\n
\n\n\n{{ next_button }}" javascript: null title: Feedback timeout_seconds: null timer_text: 'Time left to complete the matrix task:' vars_for_template: null - app_after_this_page: null before_next_page: '# Used to manually reach the exit condition to get to the results screen if timed out group.round_number = session.config[''num_rounds'']' error_message: null form_fields: null form_model: player get_form_fields: null get_timeout_seconds: null is_displayed: 'import time # Only display this page if the participant ran out of time on the matrix task return (player.participant.expiry - time.time()) <= 3' is_waitpage: false js_vars: null live_method: null name: TimeExpired template: content: "{{ include_sibling 'uw_teton_bg.html' }}\n\n

\n The time allotted for this task has ended. Please proceed to the next part of the experiment.\n

\n\n{{ next_button }}" javascript: null title: Time Limit Reached timeout_seconds: null timer_text: null vars_for_template: null - after_all_players_arrive: null body_text: null group_by_arrival_time: null is_displayed: "# If the participant is not the earner, have them sit on this wait page\nif participant.earner_round_1 != 1:\n return True" is_waitpage: true name: NotEarningWaitPage template: null title_text: Please wait for further instructions. wait_for_all_groups: null - after_all_players_arrive: RET_payoff body_text: null group_by_arrival_time: null is_displayed: "# Only reach this page if the group has gotten enough matrices correct OR they hit the max number of rounds\nif group.correct == session.config['num_correct'] or group.round_number == session.config['num_rounds']:\n return True" is_waitpage: true name: PayoffWaitPage template: null title_text: null wait_for_all_groups: null - after_all_players_arrive: null body_text: null group_by_arrival_time: null is_displayed: "# Display if they are done or we hit the round limit\nif group.correct == session.config['num_correct'] or group.round_number == session.config['num_rounds']:\n \ return True\nelse:\n return False" is_waitpage: true name: ExitWaitPage template: null title_text: null wait_for_all_groups: true - app_after_this_page: null before_next_page: null error_message: null form_fields: null form_model: player get_form_fields: null get_timeout_seconds: null is_displayed: "# Display if they are done or we hit the round limit\nif group.correct == session.config['num_correct'] or group.round_number == session.config['num_rounds']:\n \ return True\nelse:\n return False\n\n# Only show the page if we haven't already shown it\nif player.participant.vars.get('my_page_shown', False):\n \ return False\nelse:\n player.participant.vars['my_page_shown'] = True\n \ return True" is_waitpage: false js_vars: null live_method: null name: Results template: content: "\n{{ include_sibling 'uw_teton_bg.html' }}\n\n{{ if player.participant.earner_round_1 == 1 }}

\n You got {{ player.correct }} of the matrices correct. For every correct matrix, you receive ${{ session.config.x_rate }}. You earned ${{ group.budget }}.\n

\n\n{{ else }}

\n Your partner has completed the earnings task. They earned ${{ group.budget }}.\n

\n\n{{ endif }}\n\n{{ next_button }}" javascript: null title: Results timeout_seconds: null timer_text: null vars_for_template: null - app_after_this_page: null before_next_page: null error_message: null form_fields: - cq form_model: player get_form_fields: null get_timeout_seconds: null is_displayed: "# Display if they are done or we hit the round limit\nif group.correct == session.config['num_correct'] or group.round_number == session.config['num_rounds']:\n \ return True\nelse:\n return False" is_waitpage: false js_vars: null live_method: null name: JointAccount template: content: "\n{{ include_sibling 'uw_teton_bg.html' }}\n\n\n\n\n\n\n\n

\n \ The money {{ if player.participant.earner_round_1 == 1 }}you{{ else }}your partner{{ endif }} earned from the matrix task has been placed in a joint account you share with your partner. At the end of the study, the money remaining in this joint account will be split evenly between you and your partner. For example, if there were $20 remaining in the joint account at the end of the study, you would each be given $10.\n

\n\n

\n There is ${{ group.budget }} in the joint account. In this part of the study, you or your partner will be randomly chosen to receive the opportunity to spend the money {{ if player.participant.earner_round_1 == 1 }}you{{ else }}your partner{{ endif }} earned. The participant who is not given the opportunity to spend money will wait for further instructions.\n

\n\n
\n\n{{ formfields }}\n\n{{ next_button }}" javascript: null title: Joint Account timeout_seconds: null timer_text: null vars_for_template: null - app_after_this_page: null before_next_page: null error_message: null form_fields: - cq_try2 form_model: player get_form_fields: null get_timeout_seconds: null is_displayed: "# Display if they are done or we hit the round limit and If participant got comprehension question wrong, show them this page\nif group.correct == session.config['num_correct'] and player.cq != 2 or group.round_number == session.config['num_rounds'] and player.cq != 2:\n return True\nelse:\n return False" is_waitpage: false js_vars: null live_method: null name: CQ template: content: "\n{{ include_sibling 'uw_teton_bg.html' }}\n\n\n\n\n\n\n\n\nIncorrect. At the end of the study, all funds in the joint account are split evenly between you and your partner.

\n\n{{ formfields }}\n\n{{ next_button }}" javascript: null title: Joint Account timeout_seconds: null timer_text: null vars_for_template: null - app_after_this_page: '# Used to skip directly to the next app return "Auction_instructions"' before_next_page: null error_message: null form_fields: null form_model: player get_form_fields: null get_timeout_seconds: null is_displayed: "# Display if they are done or we hit the round limit\nif group.correct == session.config['num_correct'] or group.round_number == session.config['num_rounds']:\n \ return True\nelse:\n return False" is_waitpage: false js_vars: null live_method: null name: JointAccountEnd template: content: "\n{{ include_sibling 'uw_teton_bg.html' }}\n\n\n\n\n\n\n\n\n{{ if player.cq == 2 or player.cq_try2 == 2 }}Correct!{{ else }}Incorrect.{{ endif }} At the end of the study, all funds in the joint account are split evenly between you and your partner.

\n\n{{ formfields }}\n\n{{ next_button }}" javascript: null title: Joint Account timeout_seconds: null timer_text: null vars_for_template: null - bots: '' constants: - datatype: int js_value: 2 name: PLAYERS_PER_GROUP - datatype: int js_value: 1 name: NUM_ROUNDS custom_export: "# Header\nyield [\n 'session_code',\n 'participant_id_in_session',\n \ 'participant_code',\n 'id_in_group', \n 'group_number',\n 'cq_1', 'cq_1_try2',\n 'cq_2', 'cq_2_try2',\n 'cq_3', 'cq_3_try2',\n 'cq_4', 'cq_4_try2',\n]\n\n# Rows\nfor p in players:\n pp = p.participant\n pg = p.group\n ps = p.session\n \n yield [\n ps.code,\n pp.id_in_session,\n \ pp.code,\n p.id_in_group,\n pg.id_in_subsession,\n p.cq_1, p.cq_1_try2, \n p.cq_2, p.cq_2_try2, \n p.cq_3, p.cq_3_try2, \n \ p.cq_4, p.cq_4_try2\n ]" doc: Provides instructions for the spending task, with comprehension questions for additional understanding. includable_templates: - content: "\n{% load otree %}\n\n\n\n" name: uw_teton_bg models: Group: fields: - datatype: IntegerField kwargs: blank: null choices: null initial: null label: null max: null min: null widget: null name: budget methods: - code: "# Gather players\nplayers = group.get_players()\n\n# Define the group budget from RET1\ngroup.budget = players[0].participant.budget_1\n\n# Set default for comprehension questions\nfor p in players:\n p.cq_1 = \"NA\"\n \ p.cq_1_try2 = \"NA\"\n p.cq_2 = \"NA\"\n p.cq_2_try2 = \"NA\"\n \ p.cq_3 = \"NA\"\n p.cq_3_try2 = \"NA\"\n p.cq_4 = \"NA\"\n p.cq_4_try2 = \"NA\"\n\n# Set default for winner_X checks\nfor p in players:\n p.participant.winner_1 = 0\n p.participant.winner_2 = 0" is_method: false name: set_budget Player: fields: - datatype: StringField kwargs: blank: null choices: constant: null expr_type: plain js_value: - - '1' - You pay the amount the computer bid - - '2' - You pay the amount you bid - - '3' - You pay the average of your bid and the computer's bid initial: null label: constant: null expr_type: plain js_value: In this auction, if you win, how much do you pay? widget: constant: null expr_type: plain js_value: RadioSelect name: cq_1 - datatype: StringField kwargs: blank: null choices: constant: null expr_type: plain js_value: - - '1' - You pay the amount the computer bid - - '2' - You pay the amount you bid - - '3' - You pay the average of your bid and the computer's bid initial: null label: constant: null expr_type: plain js_value: In this auction, if you win, how much do you pay? widget: constant: null expr_type: plain js_value: RadioSelect name: cq_1_try2 - datatype: StringField kwargs: blank: null choices: constant: null expr_type: plain js_value: - - '1' - You should bid more than $50 - - '2' - You should bid exactly $50 - - '3' - You should bid less than $50 initial: null label: constant: null expr_type: plain js_value: If you think an item is worth $50 to you, what amount should you bid in this auction? widget: constant: null expr_type: plain js_value: RadioSelect name: cq_2 - datatype: StringField kwargs: blank: null choices: constant: null expr_type: plain js_value: - - '1' - You should bid more than $50 - - '2' - You should bid exactly $50 - - '3' - You should bid less than $50 initial: null label: constant: null expr_type: plain js_value: If you think an item is worth $50 to you, what amount should you bid in this auction? widget: constant: null expr_type: plain js_value: RadioSelect name: cq_2_try2 - datatype: StringField kwargs: blank: null choices: constant: null expr_type: plain js_value: - - '1' - You lose the auction and pay nothing - - '2' - You win the auction and pay $75 - - '3' - You win the auction and pay $60 initial: null label: constant: null expr_type: plain js_value: If you bid $75 and the computer randomly selects $60, what happens? widget: constant: null expr_type: plain js_value: RadioSelect name: cq_3 - datatype: StringField kwargs: blank: null choices: constant: null expr_type: plain js_value: - - '1' - You lose the auction and pay nothing - - '2' - You win the auction and pay $75 - - '3' - You win the auction and pay $60 initial: null label: constant: null expr_type: plain js_value: If you bid $75 and the computer randomly selects $60, what happens? widget: constant: null expr_type: plain js_value: RadioSelect name: cq_3_try2 - datatype: StringField kwargs: blank: null choices: constant: null expr_type: plain js_value: - - '1' - You win the auction, get red chair, and you get $800 at the end of the study - - '2' - You win the auction, get red chair, and you get $400 and your partner gets $400 at the end of the study - - '3' - You lost the auction and you get $800 at the end of the study initial: null label: constant: null expr_type: plain js_value: Now that you know how this auction works, let’s put this in the context of the study. You will be asked to bid on an item using money from the joint account with your partner. Imagine that you and your partner had $1,000 in the joint account. Remember, at the end of the study, anything that is not spent will be equally split between the two of you. Imagine that you bid $200 on the red chair, and the computer chooses $200. What is the outcome of the auction and your final payment for the study? widget: constant: null expr_type: plain js_value: RadioSelect name: cq_4 - datatype: StringField kwargs: blank: null choices: constant: null expr_type: plain js_value: - - '1' - You win the auction, get red chair, and you get $800 at the end of the study - - '2' - You win the auction, get red chair, and you get $400 and your partner gets $400 at the end of the study - - '3' - You lose the auction and you get $800 at the end of the study initial: null label: constant: null expr_type: plain js_value: You will be asked to bid on an item using money from the joint account with your partner. Imagine that you and your partner had $1,000 in the joint account. Remember, at the end of the study, anything that is not spent will be equally split between the two of you. Imagine that you bid $200 on the red chair, and the computer chooses $200. What is the outcome of the auction and your final payment for the study? widget: constant: null expr_type: plain js_value: RadioSelect name: cq_4_try2 methods: [] Subsession: fields: [] methods: - code: "# pull the matrix you stored in the code‐entry app\nmatrix = subsession.session.vars.get('couple_matrix')\nif not matrix:\n # safety check in case someone forgot to run grouping first\n \ raise RuntimeError(\"No couple_matrix in session.vars\")\n# re‐apply it in this app's subsession\nsubsession.set_group_matrix(matrix)" is_method: false name: after_all_players_arrive name: Auction_instructions pages: - after_all_players_arrive: after_all_players_arrive body_text: null group_by_arrival_time: null is_displayed: null is_waitpage: true name: GroupingWaitPage template: null title_text: null wait_for_all_groups: true - after_all_players_arrive: null body_text: null group_by_arrival_time: null is_displayed: null is_waitpage: true name: AuctionInstructionsStartPage template: null title_text: null wait_for_all_groups: true - after_all_players_arrive: set_budget body_text: null group_by_arrival_time: null is_displayed: null is_waitpage: true name: SetBudgetWaitPage template: null title_text: null wait_for_all_groups: null - app_after_this_page: null before_next_page: null error_message: null form_fields: - cq_1 form_model: player get_form_fields: null get_timeout_seconds: null is_displayed: '# If participant is the spender, show them this page return participant.spender == 1' is_waitpage: false js_vars: null live_method: null name: SpenderInstructions1 template: content: "\n{{ include_sibling 'uw_teton_bg.html' }}\n\n\n\n\n\n\n\n

\n \ You have been selected to spend the money {{ if player.participant.earner_round_1 == 1 }}you{{ else }} your partner{{ endif }} earned that is in the joint account. You will spend the money by participating in a special type of auction. This auction works differently from regular auctions you might be familiar with.\n

\n\n
    \n \
  1. In this auction, you're not competing with other people. Instead, your bid will be compared with a random bid generated by the computer.
  2. \n \
  3. If your bid is greater than or equal to the computer's random bid, you win the auction. If your bid is lower than the computer's bid, you lose the auction.
  4. \n
  5. If you win, you don't pay your own bid amount. Instead, you pay the computer's (lower) bid amount.
  6. \n
\n\n

\n For example, suppose that you were asked to state your bid to purchase a red chair. Also, suppose we paid you a larger amount of $1,000 to participate in this study. Your payment from participating in this study will be this amount minus anything you spend on the chair.\n

\n\n

\n Let's say you decide to bid $100 to purchase the red chair. Now we'll consider two example prices:\n


\n\n
\n Scenario 1: The computer randomly draws a bid of $82.\n
\n\n

\n Since your bid ($100) is higher than the computer's bid ($82), you WIN the auction! You get to purchase the red chair, and you pay $82 (the computer's bid), not your bid of $100. So your final payment are $1,000 - $82 = $918.\n


\n\n
\n Scenario 2: The computer randomly draws a bid of $110.\n
\n\n

\n Since your bid ($100) is lower than the computer's bid ($82), you LOSE the auction! You don't get the red chair and don't pay anything. So, your final earnings are $1,000.\n


\n\n{{ formfields }}\n\n{{ next_button }}" javascript: "// This script is included to ensure that if tags are included in form fields they are observed\n$(document).ready(function (e) {\n labels = document.getElementsByTagName(\"label\");\n\n for (var i = 0; i < labels.length; i++) {\n labels[i].innerHTML = labels[i].innerHTML.replaceAll(\"<\", \"<\").\n replaceAll(\">\", \">\");\n }\n});" title: Instructions timeout_seconds: null timer_text: null vars_for_template: null - app_after_this_page: null before_next_page: null error_message: null form_fields: - cq_1_try2 form_model: player get_form_fields: null get_timeout_seconds: null is_displayed: '# If participant is the spender and got comprehension question wrong, show them this page return participant.spender == 1 and player.cq_1 != "1"' is_waitpage: false js_vars: null live_method: null name: CQ_1 template: content: "\n{{ include_sibling 'uw_teton_bg.html' }}\n\n\n\n\n\n\n\n\nIncorrect. If you win the auction, you pay the amount the computer bid.

\n\n{{ formfields }}\n\n{{ next_button }}" javascript: "// This script is included to ensure that if tags are included in form fields they are observed\n$(document).ready(function (e) {\n labels = document.getElementsByTagName(\"label\");\n\n for (var i = 0; i < labels.length; i++) {\n labels[i].innerHTML = labels[i].innerHTML.replaceAll(\"<\", \"<\").\n replaceAll(\">\", \">\");\n }\n});" title: Comprehension Question timeout_seconds: null timer_text: null vars_for_template: null - app_after_this_page: null before_next_page: null error_message: null form_fields: - cq_2 form_model: player get_form_fields: null get_timeout_seconds: null is_displayed: '# If participant is the spender, show them this page return participant.spender == 1' is_waitpage: false js_vars: null live_method: null name: SpenderInstructions2 template: content: "\n{{ include_sibling 'uw_teton_bg.html' }}\n\n\n\n\n\n\n\n\n{{ if player.cq_1 == \"1\" or player.cq_1_try2 == \"1\" }}Correct!{{ else }}Incorrect.{{ endif }} If you win the auction, you pay the amount the computer bid.

\n\n

\n \ Tips for How to Bid\n

\n\n

\n The best bidding strategy in this type of auction is to bid exactly how much the item is worth to you. Here's why:\n

\n\n

\n Let's say you decide the red chair is worth $200 to you. This means you'd be equally happy keeping your money or spending $200 to buy the red chair. Is your best strategy bidding more than $200, less than $200, or exactly $200? The answer is exactly $200.\n

\n\n

\n \ If you were to bid less than $200 (say $100), then the auction might be won by the computer (if its random bid was $150, say). You would not be able to buy the red chair even though you were truly willing to pay more than $150. You miss out on a good deal. Therefore, bidding less than your true value is not a good strategy.\n

\n\n

\n If you bid more than $200 (say $300), you might win the auction but have to pay a higher price than your value of the red chair. If the computer bids $250, you win the auction but have to pay $250, which is more than the $200 the chair is worth to you. You end up with a bad deal. Therefore, bidding more than your true value is not a good strategy.\n

\n\n

\n Let's say you choose to bid exactly $200. If the computer bids less than $200, you win and pay less than what the chair is worth to you. If the computer bids more than $200, you lose, but that's okay because the price would have been too high anyway. You do not risk paying more for the good than you want to, and you will never pay more than the computer’s bid anyway.\n

\n\n{{ formfields }}\n\n{{ next_button }}" javascript: "// This script is included to ensure that if tags are included in form fields they are observed\n$(document).ready(function (e) {\n labels = document.getElementsByTagName(\"label\");\n\n for (var i = 0; i < labels.length; i++) {\n labels[i].innerHTML = labels[i].innerHTML.replaceAll(\"<\", \"<\").\n replaceAll(\">\", \">\");\n }\n});" title: Instructions timeout_seconds: null timer_text: null vars_for_template: null - app_after_this_page: null before_next_page: null error_message: null form_fields: - cq_2_try2 form_model: player get_form_fields: null get_timeout_seconds: null is_displayed: '# If participant is the spender and got comprehension question wrong, show them this page return participant.spender == 1 and player.cq_2 != "2"' is_waitpage: false js_vars: null live_method: null name: CQ_2 template: content: "\n{{ include_sibling 'uw_teton_bg.html' }}\n\n\n\n\n\n\n\n\nIncorrect. In this auction you should bid exactly how much you value the item.

\n\n{{ formfields }}\n\n{{ next_button }}" javascript: "// This script is included to ensure that if tags are included in form fields they are observed\n$(document).ready(function (e) {\n labels = document.getElementsByTagName(\"label\");\n\n for (var i = 0; i < labels.length; i++) {\n labels[i].innerHTML = labels[i].innerHTML.replaceAll(\"<\", \"<\").\n replaceAll(\">\", \">\");\n }\n});" title: Comprehension Question timeout_seconds: null timer_text: null vars_for_template: null - app_after_this_page: null before_next_page: null error_message: null form_fields: - cq_3 form_model: player get_form_fields: null get_timeout_seconds: null is_displayed: '# If participant is the spender, show them this page return participant.spender == 1' is_waitpage: false js_vars: null live_method: null name: SpenderInstructions3 template: content: "\n{{ include_sibling 'uw_teton_bg.html' }}\n\n\n\n\n\n\n\n\n{{ if player.cq_2 == \"2\" or player.cq_2_try2 == \"2\" }}Correct!{{ else }}Incorrect.{{ endif }} In this auction you should bid exactly how much you value the item, which in this example is $50.

\n\n

\n Final Notes\n

\n\n\n\n{{ formfields }}\n\n{{ next_button }}" javascript: "// This script is included to ensure that if tags are included in form fields they are observed\n$(document).ready(function (e) {\n labels = document.getElementsByTagName(\"label\");\n\n for (var i = 0; i < labels.length; i++) {\n labels[i].innerHTML = labels[i].innerHTML.replaceAll(\"<\", \"<\").\n replaceAll(\">\", \">\");\n }\n});" title: Instructions timeout_seconds: null timer_text: null vars_for_template: null - app_after_this_page: null before_next_page: null error_message: null form_fields: - cq_3_try2 form_model: player get_form_fields: null get_timeout_seconds: null is_displayed: '# If participant is the spender and got comprehension question wrong, show them this page return participant.spender == 1 and player.cq_3 != "3"' is_waitpage: false js_vars: null live_method: null name: CQ_3 template: content: "\n{{ include_sibling 'uw_teton_bg.html' }}\n\n\n\n\n\n\n\n\nIncorrect. If your bid is higher than the computer's, you will win the auction and pay the computer's bid.

\n\n{{ formfields }}\n\n{{ next_button }}" javascript: "// This script is included to ensure that if tags are included in form fields they are observed\n$(document).ready(function (e) {\n labels = document.getElementsByTagName(\"label\");\n\n for (var i = 0; i < labels.length; i++) {\n labels[i].innerHTML = labels[i].innerHTML.replaceAll(\"<\", \"<\").\n replaceAll(\">\", \">\");\n }\n});" title: Comprehension Questions timeout_seconds: null timer_text: null vars_for_template: null - app_after_this_page: null before_next_page: null error_message: null form_fields: - cq_4 form_model: player get_form_fields: null get_timeout_seconds: null is_displayed: '# If participant is the spender, show them this page return participant.spender == 1' is_waitpage: false js_vars: null live_method: null name: SpenderInstructions4 template: content: "\n{{ include_sibling 'uw_teton_bg.html' }}\n\n\n\n\n\n\n\n\nIncorrect. If you bid $200 on the chair and the computer chooses $200, you win the auction, paying $200 and getting the red chair. This means the money remaining in the joint account is $1,000 - $200 = $800. At the end of the study, whatever is left in the joint account is split equally between you and your partner. So, you will get the red chair, receive $400, and your partner will receive $400.

\n\n{{ formfields }}\n\n{{ next_button }}" javascript: "// This script is included to ensure that if tags are included in form fields they are observed\n$(document).ready(function (e) {\n labels = document.getElementsByTagName(\"label\");\n\n for (var i = 0; i < labels.length; i++) {\n labels[i].innerHTML = labels[i].innerHTML.replaceAll(\"<\", \"<\").\n replaceAll(\">\", \">\");\n }\n});" title: Instructions timeout_seconds: null timer_text: null vars_for_template: null - app_after_this_page: null before_next_page: null error_message: null form_fields: - cq_4_try2 form_model: player get_form_fields: null get_timeout_seconds: null is_displayed: '# If participant is the spender and got comprehension question wrong, show them this page return participant.spender == 1 and player.cq_4 != "2"' is_waitpage: false js_vars: null live_method: null name: CQ_4 template: content: "\n{{ include_sibling 'uw_teton_bg.html' }}\n\n\n\n\n\n\n\n\nIncorrect. If you bid $200 on the chair and the computer chooses $200, you win the auction, paying $200 and getting the red chair. This means the money remaining in the joint account is $1,000 - $200 = $800. At the end of the study, whatever is left in the joint account is split equally between you and your partner. So, you will get the red chair, receive $400, and your partner will receive $400.

\n\n{{ formfields }}\n\n{{ next_button }}" javascript: "// This script is included to ensure that if tags are included in form fields they are observed\n$(document).ready(function (e) {\n labels = document.getElementsByTagName(\"label\");\n\n for (var i = 0; i < labels.length; i++) {\n labels[i].innerHTML = labels[i].innerHTML.replaceAll(\"<\", \"<\").\n replaceAll(\">\", \">\");\n }\n});" title: Comprehension Questions timeout_seconds: null timer_text: null vars_for_template: null - app_after_this_page: null before_next_page: null error_message: null form_fields: null form_model: player get_form_fields: null get_timeout_seconds: null is_displayed: '# If participant is the spender, show them this page return participant.spender == 1' is_waitpage: false js_vars: null live_method: null name: SpenderInstructionsEnd template: content: "\n{{ include_sibling 'uw_teton_bg.html' }}\n\n\n\n\n\n\n\n\n{{ if player.cq_4 == \"2\" or player.cq_4_try2 == \"2\" }}Correct!{{ else }}Incorrect.{{ endif }} If you bid $200 on the chair and the computer chooses $200, you win the auction, paying $200 and getting the red chair. This means the money remaining in the joint account is $1,000 - $200 = $800. At the end of the study, whatever is left in the joint account is split equally between you and your partner. So, you will get the red chair, receive $400, and your partner will receive $400.

\n\n{{ next_button }}" javascript: "// This script is included to ensure that if tags are included in form fields they are observed\n$(document).ready(function (e) {\n labels = document.getElementsByTagName(\"label\");\n\n for (var i = 0; i < labels.length; i++) {\n labels[i].innerHTML = labels[i].innerHTML.replaceAll(\"<\", \"<\").\n replaceAll(\">\", \">\");\n }\n});" title: Instructions timeout_seconds: null timer_text: null vars_for_template: null - after_all_players_arrive: null body_text: null group_by_arrival_time: null is_displayed: null is_waitpage: true name: AuctionInstructionsEndPage template: null title_text: Your partner is being given instructions for their next task. Please wait for your partner. wait_for_all_groups: true - bots: '' constants: - datatype: int js_value: 2 name: PLAYERS_PER_GROUP - datatype: int js_value: 1 name: NUM_ROUNDS - datatype: int js_value: 40 name: NUM_POP_QS - datatype: list_int js_value: - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 - 11 - 12 - 13 - 14 - 15 - 16 - 17 - 18 - 19 - 20 name: PRICE_STEPS - datatype: list_int js_value: - 1 - 2 - 3 - 4 - 5 - 6 - 7 name: SMILEY_LIKERT_OPTS custom_export: "# Header\nyield [\n 'session_code',\n 'participant_id_in_session',\n \ 'participant_code',\n 'id_in_group',\n 'group_member',\n 'spender',\n \ 'earner_round_1',\n 'WTP_1',\n 'computer_price_1',\n 'won_auction_1'\n]\n\n# Rows\nfor p in players:\n pp = p.participant\n pg = p.group\n ps = p.session\n \ \n # Pull participant fields (needed as these are only saved in 'all apps wide' normally)\n spender = p.participant.vars.get('spender', '')\n earner_round_1 = p.participant.vars.get('earner_round_1', '')\n computer_price_1 = p.participant.vars.get('computer_price_1', '')\n \n yield [\n ps.code,\n pp.id_in_session,\n pp.code,\n \ p.id_in_group,\n pg.id_in_subsession,\n spender,\n earner_round_1,\n \ p.WTP,\n computer_price_1,\n pg.win\n ]" doc: BDM auction to elicit WTP/ pain of paying of the spender. One person (spender) participates in auction while other (waiter) waits until next phase. If spender is successful in auction, fills out information for either lab pick-up or shipping. includable_templates: - content: "
\n
\n

\n \ Auction Instructions\n

\n

\n Here are the rules of the auction:\n

\n \n
\n
" name: auction_instructions - content: "\n{% load otree %}\n\n\n\n" name: uw_teton_bg - content: "{% load otree %}\n\n\n" name: uw_teton_survey - content: "{% load otree %}\n\n" name: two_column_flex_container models: Group: fields: - datatype: IntegerField kwargs: blank: null choices: null initial: null label: null max: null min: null widget: null name: budget - datatype: IntegerField kwargs: blank: null choices: null initial: null label: null max: null min: null widget: null name: price - datatype: BooleanField kwargs: blank: null choices: null initial: null label: null widget: null name: win - datatype: FloatField kwargs: blank: null choices: null initial: null label: null max: null min: null widget: null name: WTP_spender - datatype: IntegerField kwargs: blank: null choices: null initial: null label: null max: null min: null widget: null name: budget_initial methods: - code: "# import random\nimport random\n\n# Gather players\nplayers = group.get_players()\n\n# Define the group budget from RET1\ngroup.budget = players[0].participant.budget_1\ngroup.budget_initial = players[0].participant.budget_1\n\n# Draw a single random number to use as the price\ngroup.price = int((random.uniform((group.budget*0.85), group.budget)) + 0.5) # UNIFORM DIST VERSION\n\n# Sanity check for price bounds\nif group.price <= 1:\n group.price = 1\nelif group.price >= group.budget:\n group.price = group.budget" is_method: false name: set_price - code: "# Gather players\nplayers = group.get_players()\n\n# Identify the player with the spending role\nspender_player = None\nfor p in players:\n p.participant.WTP_1 = 0 # set default value of WTP to participant field if not used\n if p.participant.spender == 1:\n spender_player = p\n p.participant.WTP_1 = spender_player.WTP # set WTP for spender to participant field\n\n# Compare the WTP to price\nif spender_player.WTP >= group.price:\n group.win = True\n group.budget = group.budget - group.price # Money taken from joint account\nelse:\n group.win = False\n group.budget = group.budget # Nothing spent from joint account\n \n# If winner, save to participant field\nfor p in players:\n if p.participant.spender == 1 and group.win == True:\n p.participant.winner_1 = 1\n\n# Save final earnings to a global variable\nfor p in players:\n p.participant.earnings_1 = group.budget /2\n p.participant.computer_price_1 = group.price" is_method: false name: auction_check Player: fields: - datatype: BooleanField kwargs: blank: null choices: null initial: constant: null expr_type: plain js_value: false label: null widget: null name: won_auction - datatype: FloatField kwargs: blank: null choices: null initial: null label: constant: null expr_type: plain js_value: How much would you be willing to spend on the item shown above in dollars? (Enter your bid as a dollar value using at maximum 2 decimals) max: null min: constant: null expr_type: plain js_value: 0 widget: null name: WTP methods: - code: return group.budget is_method: false name: WTP_max Subsession: fields: [] methods: - code: "# pull the matrix you stored in the code‐entry app\nmatrix = subsession.session.vars.get('couple_matrix')\nif not matrix:\n # safety check in case someone forgot to run grouping first\n \ raise RuntimeError(\"No couple_matrix in session.vars\")\n# re‐apply it in this app's subsession\nsubsession.set_group_matrix(matrix)" is_method: false name: after_all_players_arrive name: Auction_1 pages: - after_all_players_arrive: after_all_players_arrive body_text: null group_by_arrival_time: null is_displayed: null is_waitpage: true name: GroupingWaitPage template: null title_text: null wait_for_all_groups: true - after_all_players_arrive: set_price body_text: null group_by_arrival_time: null is_displayed: null is_waitpage: true name: SetBudgetWaitPage template: null title_text: null wait_for_all_groups: null - app_after_this_page: null before_next_page: null error_message: null form_fields: null form_model: player get_form_fields: null get_timeout_seconds: null is_displayed: null is_waitpage: false js_vars: null live_method: null name: RoleReveal template: content: "\n{{ include_sibling 'uw_teton_bg.html' }}\n\n\n{{ if player.participant.spender == 1 }}

\n You have been selected and are receiving the opportunity to spend the money {{ if player.participant.earner_round_1 == 1 }} you{{ else }} your partner{{ endif }} earned from the matrix task. In other words, ${{ group.budget }} in the joint account. Remember, whatever balance is remaining in the joint account at the end of the study will be split equally between you and your partner.\n

\n\n

\n \ It is important to our study that the item you purchase is for your own use and that, after the study, you do not compensate your partner for having bought the item.\n

\n\n

\n The budget for you to spend is ${{ group.budget }}.\n

\n\n\n{{ else }}

\n You were not selected to complete the spending task. Please wait for further instructions.\n

\n\n{{ endif}}\n\n{{ next_button }}" javascript: null title: Spending Task timeout_seconds: null timer_text: null vars_for_template: null - after_all_players_arrive: null body_text: null group_by_arrival_time: null is_displayed: "# If the participant is not the spender, sit on this wait page\nif participant.spender != 1:\n return True" is_waitpage: true name: NotSpendingWaitPage template: null title_text: You were not selected for the spending task. Please wait for further instructions. wait_for_all_groups: null - app_after_this_page: null before_next_page: "group.WTP_spender = player.WTP\nif timeout_happened:\n # Default value for any form fields if timeout occurs, because otherwise they may be left null\n player.WTP = 0\n participant.WTP_1_timeout = 1" error_message: null form_fields: - WTP form_model: player get_form_fields: null get_timeout_seconds: null is_displayed: '# If participant is the spender, show them this page return participant.spender == 1' is_waitpage: false js_vars: null live_method: null name: Spending template: content: "\n{{ include_sibling 'uw_teton_bg.html' }}\n\n\n\n\n\n\n\n

\n You are being offered this item, whose market value is approximately $30:\n

\n\n\n\"Selected\n\n\n

\n {{ description }}\n

\n\n\n

\n You will get the opportunity to buy this item by participating in an auction that works the same way as the practice auction you just learned about. If you win the auction, the item will be delivered to the lab and we will contact you so you can pick it up from us at a time that is convenient to you. The total amount you can spend on this task is the ${{group.budget}}, the money that {{if player.participant.earner_round_1 == 1}}you{{else}}your partner{{endif}} earned from the matrix task; in other words you can spend up to ${{group.budget}} from the joint account. Remember, all money remaining in the joint account at the end of the study will be split evenly between you and your partner.\n

\n

\n \ Here's a reminder of the rules of the auction:\n

\n\n\n

\n The money you can spend on this item is the ${{ group.budget }} in the joint account.\n

\n\n
\n\n\n{{ formfields }}\n\n{{ next_button }}" javascript: "// This script is included to ensure that if tags are included in form fields they are observed\n$(document).ready(function (e) {\n labels = document.getElementsByTagName(\"label\");\n\n for (var i = 0; i < labels.length; i++) {\n labels[i].innerHTML = labels[i].innerHTML.replaceAll(\"<\", \"<\").\n replaceAll(\">\", \">\");\n }\n});" title: The Auction timeout_seconds: 180 timer_text: null vars_for_template: "# Define the list of items with unique identifiers, their associated image URLs, and a description\nimgur_urls = [\n {'id': 'A', 'url': 'https://i.imgur.com/OfsrPbR.jpeg', 'description': \"Coloring book with pencils\"},\n \ {'id': 'B', 'url': 'https://i.imgur.com/tmBYFwX.jpeg', 'description': \"Headphones\"},\n \ {'id': 'C', 'url': 'https://i.imgur.com/oBfC4Mz.jpeg', 'description': \"Moisturizer\"},\n \ {'id': 'D', 'url': 'https://i.imgur.com/q7bBuv6.jpeg', 'description': \"Spa kit\"},\n {'id': 'E', 'url': 'https://i.imgur.com/Zc7vR6m.jpeg', 'description': \"Grilling accessories\"},\n {'id': 'F', 'url': 'https://i.imgur.com/YLEoKGI.jpeg', 'description': \"Tactical flashlight\"},\n {'id': 'G', 'url': 'https://i.imgur.com/lmMFuFL.jpeg', 'description': \"Lip Balm\"},\n {'id': 'H', 'url': 'https://i.imgur.com/5KfUIfj.jpeg', 'description': \"Water bottle\"},\n {'id': 'I', 'url': 'https://i.imgur.com/AS1feBP.jpeg', 'description': \"Car detailing kit\"},\n {'id': 'J', 'url': 'https://i.imgur.com/SfJ7GmF.jpeg', 'description': \"Multi-tool\"}\n]\n\n# Default fallback if selected_item is missing or invalid\ndefault_image = 'https://miro.medium.com/v2/resize:fit:1100/format:webp/1*MXyMqcEJ6Se0SCWcYCKZTQ.jpeg'\ndefault_desc = 'No description available.'\n\n# Retrieve the selected item from participant data\nselected_item = participant.selected_item # Expect one of 'A' through 'J'\n\n# Find the dictionary for the selected item\nselected = next((item for item in imgur_urls if item['id'] == selected_item),\n {'url': default_image, 'description': default_desc})\n\n# Pass both the full list and the selected item's data to the template\nreturn dict(\n image_paths=imgur_urls,\n \ image_path=selected['url'],\n description=selected['description'],\n)" - after_all_players_arrive: auction_check body_text: null group_by_arrival_time: null is_displayed: null is_waitpage: true name: ResultsWaitPage template: null title_text: null wait_for_all_groups: null - app_after_this_page: null before_next_page: null error_message: null form_fields: null form_model: player get_form_fields: null get_timeout_seconds: null is_displayed: null is_waitpage: false js_vars: null live_method: null name: Results template: content: "\n{{ include_sibling 'uw_teton_bg.html' }}\n\n

\n You have finished Round 1 of the study, and we will now proceed to Round 2.{{if participant.spender == 1}} We will repeat the earning and spending games.{{endif}} At the end of the study, we will randomly choose one of the rounds to determine your final payoff{{ if participant.spender == 1 }}, including the result of the auction.{{else}}.{{endif}}\n

\n\n{{ next_button }}" javascript: '' title: Auction Results timeout_seconds: null timer_text: null vars_for_template: null - after_all_players_arrive: null body_text: null group_by_arrival_time: null is_displayed: null is_waitpage: true name: Auction_1EndPage template: null title_text: Please wait for further instructions. wait_for_all_groups: true - bots: '' constants: - datatype: int js_value: 2 name: PLAYERS_PER_GROUP - datatype: int js_value: 20 name: NUM_ROUNDS - datatype: str js_value: 'Time left to complete the matrix task:' name: TIMER_TEXT custom_export: "# Header\nyield [\n 'session_code',\n 'participant_id_in_session',\n \ 'participant_code',\n 'id_in_group',\n 'earner_round_2',\n 'budget_2'\n]\n\n# Rows\nfor p in players:\n pp = p.participant\n pg = p.group\n ps = p.session\n \ # Pull participant fields\n earner_round_2 = p.participant.vars.get('earner_round_2', '')\n budget_2 = p.participant.vars.get('budget_2', '')\n yield [\n ps.code,\n \ pp.id_in_session,\n pp.code,\n p.id_in_group,\n earner_round_2,\n \ budget_2\n ]" doc: Real-effort task (RET) portion of the experiment. RET is counting the number of 1s in a matrix of 1s and 0s. includable_templates: - content: "\n{% load otree %}\n\n\n\n" name: uw_teton_bg models: Group: fields: - datatype: IntegerField kwargs: blank: null choices: null initial: null label: null max: null min: null widget: null name: budget - datatype: IntegerField kwargs: blank: null choices: null initial: constant: null expr_type: plain js_value: 0 label: null max: null min: null widget: null name: correct - datatype: FloatField kwargs: blank: null choices: null initial: null label: null max: null min: null widget: null name: earner_id methods: - code: "# Access all players in the current group\nplayers = group.get_players()\n\n# Exit check for conditions that don't require individual updates\nif group.round_number > 1 and group.correct == session.config['num_correct']:\n # Directly carry over the correct count from the previous round\n group.correct = group.in_round(group.round_number - 1).correct\n return\n\n# Identify the player who did the task in the first round\nptask = group.get_player_by_id(group.in_round(1).earner_id)\n\n# Initialize or update correct counts for players\nfor p in players:\n # Ensure that player_sum is not None, treat None as an incorrect guess\n if p.player_sum is None:\n p.last_guess_correct = False\n current_guess_correct = 0 # This will treat None as an incorrect guess\n else:\n # Compare player_sum with matrix_sum and update correct and feedback accordingly\n \ current_guess_correct = int(p.player_sum == p.matrix_sum)\n p.last_guess_correct = (p.player_sum == p.matrix_sum)\n\n # Update the correct count based on the current guess\n if group.round_number == 1:\n p.correct = current_guess_correct\n else:\n previous_correct = p.in_round(group.round_number - 1).correct\n p.correct = previous_correct + current_guess_correct\n\n \ # Update the group.correct counter if this is the player who did the task\n if p == ptask:\n group.correct = p.correct" is_method: false name: check_func - code: "# Defining player that did the task\nptask = group.get_player_by_id(group.in_round(1).earner_id)\n\n# Setting the budget based on how many were correct and the pay per correct answer\ngroup.budget = ptask.correct * session.config['x_rate']\n\n# Defining the players\nplayers = group.get_players()\n\n# Store budget at the participant level for the next app\nfor p in players:\n p.participant.budget_2 = group.budget" is_method: false name: RET_payoff - code: "# Gather players \nplayers = group.get_players()\n\n# Initialize earner_id at the group level\ngroup.earner_id = None\n\n# Assign roles based on random draw\nfor p in players:\n if p.participant.earner_round_1 == 0: # if they were not the earner in round 1\n p.participant.earner_round_2 = 1\n group.earner_id = p.id_in_group # Store the earner's id_in_group at the group level\n else:\n p.participant.earner_round_2 = 0\n \ \n p.exit_2 = 0" is_method: false name: assign_earner_2 - code: "# Defining players\nplayers = group.get_players()\n\n# Setting the exit condition to avoid duplicating the results page\nfor p in players:\n \ p.exit_2 = 1" is_method: false name: exit Player: fields: - datatype: IntegerField kwargs: blank: null choices: null initial: constant: null expr_type: plain js_value: 1 label: null max: null min: null widget: null name: matrix_sum - datatype: IntegerField kwargs: blank: null choices: null initial: constant: null expr_type: plain js_value: 0 label: constant: null expr_type: plain js_value: How many 1s are in the above matrix? max: null min: constant: null expr_type: plain js_value: 0 widget: null name: player_sum - datatype: IntegerField kwargs: blank: null choices: null initial: constant: null expr_type: plain js_value: 0 label: null max: null min: constant: null expr_type: plain js_value: 0 widget: null name: correct - datatype: BooleanField kwargs: blank: null choices: null initial: null label: null widget: null name: last_guess_correct - datatype: FloatField kwargs: blank: null choices: null initial: constant: null expr_type: plain js_value: 0 label: null max: null min: null widget: null name: exit_2 methods: - code: return session.config['m_size'] * session.config['m_size'] is_method: false name: player_sum_max Subsession: fields: [] methods: - code: "# pull the matrix you stored in the code‐entry app\nmatrix = subsession.session.vars.get('couple_matrix')\nif not matrix:\n # safety check in case someone forgot to run grouping first\n \ raise RuntimeError(\"No couple_matrix in session.vars\")\n# re‐apply it in this app's subsession\nsubsession.set_group_matrix(matrix)" is_method: false name: after_all_players_arrive name: RET_2 pages: - after_all_players_arrive: after_all_players_arrive body_text: null group_by_arrival_time: null is_displayed: null is_waitpage: true name: GroupingWaitPage template: null title_text: null wait_for_all_groups: true - after_all_players_arrive: assign_earner_2 body_text: null group_by_arrival_time: null is_displayed: "if group.round_number == 1: \n return True" is_waitpage: true name: RoleAssignmentWaitPage template: null title_text: null wait_for_all_groups: null - app_after_this_page: null before_next_page: '# Set a global 5 minute timer for all the task pages participant = player.participant import time participant.expiry = time.time() + session.config[''task_min'']*60' error_message: null form_fields: null form_model: player get_form_fields: null get_timeout_seconds: null is_displayed: "if group.round_number == 1: \n return True" is_waitpage: false js_vars: null live_method: null name: RoleAssignment template: content: "\n{{ include_sibling 'uw_teton_bg.html' }}\n\n\n{{ if player.participant.earner_round_2 == 1 }}\n

\n You were randomly selected to earn money by completing the earnings task. You will have {{ session.config.time_limit }} minutes to earn up to ${{max_budget}} by completing {{ session.config.num_correct }} matrices.\n

\n\n\n{{ else }}\n

\n You were not selected to earn money by completing the earnings task. Please wait for further instructions.\n

\n\n{{ endif}}\n\n{{ next_button }}" javascript: null title: Role Assignment timeout_seconds: null timer_text: null vars_for_template: 'max_budget = session.config[''x_rate''] * session.config[''num_correct''] return dict(max_budget = max_budget)' - app_after_this_page: null before_next_page: "if timeout_happened:\n # Default value for any form fields if timeout occurs, because otherwise they may be left null\n player.player_sum = 0" error_message: null form_fields: - player_sum form_model: player get_form_fields: null get_timeout_seconds: '# Using the global timer set at RoleAssignment participant = player.participant import time # Passing the global timer to the HTML template of the page return participant.expiry - time.time()' is_displayed: "import time\n\n# Display if participant is the earner AND it's round 1 AND global timer isn't 0\nif player.participant.earner_round_2 == 1 and group.round_number == 1 and max(participant.expiry - time.time(), 0) > 3:\n \ return True\n\n# Display if participant is the earner AND it's after round 1 AND is not done with the task AND global timer isn't 0\nelif player.participant.earner_round_2 == 1 and group.in_round(group.round_number - 1).correct != session.config['num_correct'] and max(participant.expiry - time.time(), 0) > 3:\n return True" is_waitpage: false js_vars: null live_method: null name: Task template: content: "\n{{ include_sibling 'uw_teton_bg.html' }}\n\n\n\n\n\n\n\n\n {% for row in matrix %} \n {% for cell in row %} \n {% endfor %} \n {% endfor %} \n
{{ cell }}
\n\n\n\n\n
\n\n{{ formfields }}\n\n{{ next_button }}" javascript: null title: Matrix Task timeout_seconds: null timer_text: 'Time left to complete the matrix task:' vars_for_template: "import random\n\n# Generate session.config.m_size x session.config.m_size matrix with random 0s and 1s\nmatrix = [[random.randint(0, 1) for _ in range(session.config['m_size'])] for _ in range(session.config['m_size'])]\n\n# Calculate the sum of all 1s in the matrix\nmatrix_sum = sum(sum(row) for row in matrix)\n\n# Store the sum in the player variable\nplayer.matrix_sum = matrix_sum\n\n# Passing Python variables to the HTML template of the page\nreturn dict(\n matrix=matrix,\n matrix_sum=matrix_sum,\n)" - after_all_players_arrive: check_func body_text: null group_by_arrival_time: null is_displayed: "# Display if earner\nif participant.earner_round_2 == 1:\n return True" is_waitpage: true name: EarningWaitPage template: null title_text: null wait_for_all_groups: null - app_after_this_page: null before_next_page: null error_message: null form_fields: null form_model: player get_form_fields: null get_timeout_seconds: '# Using the global timer set at RoleAssignment participant = player.participant import time # Passing the global timer to the HTML template of the page return participant.expiry - time.time()' is_displayed: "import time\n\n# Display if participant is the earner AND it's round 1 AND global timer isn't 0\nif participant.earner_round_2 == 1 and group.round_number == 1 and max(participant.expiry - time.time(), 0) > 3:\n return True\n\n# Display if participant is the earner AND it's after round 1 AND is not done with the task AND global timer isn't 0\nelif participant.earner_round_2 == 1 and group.in_round(group.round_number - 1).correct != session.config['num_correct'] and max(participant.expiry - time.time(), 0) > 3:\n return True" is_waitpage: false js_vars: null live_method: null name: Feedback template: content: "\n{{ include_sibling 'uw_teton_bg.html' }}\n\n\n\n\n\n
\n {% if player.last_guess_correct %}\n

\n Correct! You guessed the right number of 1s.\n

\n {% else %}\n

\n \ Incorrect guess. You will have another chance with a new matrix.\n \

\n {% endif %}\n \n \n

\n Number of correct guesses: {{ player.correct }}.\n

\n
\n\n\n{{ next_button }}" javascript: null title: Feedback timeout_seconds: null timer_text: 'Time left to complete the matrix task:' vars_for_template: null - app_after_this_page: null before_next_page: '# Used to manually reach the exit condition to get to the results screen group.round_number = session.config[''num_rounds'']' error_message: null form_fields: null form_model: player get_form_fields: null get_timeout_seconds: null is_displayed: 'import time # Only display this page if the participant ran out of time on the matrix task return (player.participant.expiry - time.time()) <= 3' is_waitpage: false js_vars: null live_method: null name: TimeExpired template: content: "{{ include_sibling 'uw_teton_bg.html' }}\n\n

\n The time allotted for this task has ended. Please proceed to the next part of the experiment.\n

\n\n{{ next_button }}" javascript: null title: Time Limit Reached timeout_seconds: null timer_text: null vars_for_template: null - after_all_players_arrive: null body_text: null group_by_arrival_time: null is_displayed: "# If the participant is not the earner, have them sit on this wait page\nif participant.earner_round_2 != 1:\n return True" is_waitpage: true name: NotEarningWaitPage template: null title_text: Please wait for further instructions. wait_for_all_groups: null - after_all_players_arrive: RET_payoff body_text: null group_by_arrival_time: null is_displayed: "if group.correct == session.config['num_correct'] or group.round_number == session.config['num_rounds']:\n return True" is_waitpage: true name: PayoffWaitPage template: null title_text: null wait_for_all_groups: null - after_all_players_arrive: null body_text: null group_by_arrival_time: null is_displayed: "# Display if they are done or we hit the round limit\nif group.correct == session.config['num_correct'] or group.round_number == session.config['num_rounds']:\n \ return True\nelse:\n return False" is_waitpage: true name: ExitWaitPage template: null title_text: null wait_for_all_groups: true - app_after_this_page: null before_next_page: null error_message: null form_fields: null form_model: player get_form_fields: null get_timeout_seconds: null is_displayed: "# Display if they are done or we hit the round limit\nif group.correct == session.config['num_correct'] or group.round_number == session.config['num_rounds']:\n \ return True\nelse:\n return False\n\n# Only show the page if we haven't already shown it\nif player.participant.vars.get('my_page_shown', False):\n \ return False\nelse:\n player.participant.vars['my_page_shown'] = True\n \ return True" is_waitpage: false js_vars: null live_method: null name: Results template: content: "\n{{ include_sibling 'uw_teton_bg.html' }}\n\n{{ if player.participant.earner_round_2 == 1 }}

\n You got {{ player.correct }} of the matrices correct. For every correct matrix, you receive ${{ session.config.x_rate }}. You earned ${{ group.budget }}.\n

\n\n{{ else }}

\n Your partner has completed the earnings task. They earned ${{ group.budget }}.\n

\n\n{{ endif }}\n\n{{ next_button }}" javascript: null title: Results timeout_seconds: null timer_text: null vars_for_template: null - app_after_this_page: '# Used to skip directly to the next app return "Auction_2"' before_next_page: null error_message: null form_fields: null form_model: player get_form_fields: null get_timeout_seconds: null is_displayed: "# Display if they are done or we hit the round limit\nif group.correct == session.config['num_correct'] or group.round_number == session.config['num_rounds']:\n \ return True\nelse:\n return False" is_waitpage: false js_vars: null live_method: null name: JointAccount template: content: "\n{{ include_sibling 'uw_teton_bg.html' }}\n\n

\n The money {{ if player.participant.earner_round_2 == 1 }}you{{ else }}your partner{{ endif }} earned from the matrix task has been placed in a joint account you share with your partner. At the end of the study, the money remaining in this joint account will be split evenly between you and your partner. For example, if there were $20 remaining in the joint account at the end of the study, you would each be given $10.\n

\n\n

\n There is ${{ group.budget }} in the joint account. In this part of the study, you or your partner will be randomly chosen to receive the opportunity to spend the money {{ if player.participant.earner_round_2 == 1 }}you{{ else }}your partner{{ endif }} earned. The participant who is not given the opportunity to spend money will wait for further instructions.\n

\n\n{{ next_button }}" javascript: null title: Joint Account timeout_seconds: null timer_text: null vars_for_template: null - bots: '' constants: - datatype: int js_value: 2 name: PLAYERS_PER_GROUP - datatype: int js_value: 1 name: NUM_ROUNDS - datatype: int js_value: 40 name: NUM_POP_QS - datatype: list_int js_value: - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 - 11 - 12 - 13 - 14 - 15 - 16 - 17 - 18 - 19 - 20 name: PRICE_STEPS - datatype: list_int js_value: - 1 - 2 - 3 - 4 - 5 - 6 - 7 name: SMILEY_LIKERT_OPTS custom_export: "# Header\nyield [\n 'session_code',\n 'participant_id_in_session',\n \ 'participant_code',\n 'id_in_group',\n 'group_member',\n 'spender',\n \ 'earner_round_2',\n 'WTP_2',\n 'computer_price_2',\n 'won_auction_2'\n]\n\n# Rows\nfor p in players:\n pp = p.participant\n pg = p.group\n ps = p.session\n \ \n # Pull participant fields\n spender = p.participant.vars.get('spender', '')\n earner_round_2 = p.participant.vars.get('earner_round_2', '')\n computer_price_2 = p.participant.vars.get('computer_price_2', '')\n \n yield [\n ps.code,\n \ pp.id_in_session,\n pp.code,\n p.id_in_group,\n pg.id_in_subsession,\n \ spender,\n earner_round_2,\n p.WTP,\n computer_price_2,\n \ pg.win\n ]" doc: BDM auction to elicit WTP/ pain of paying of the spender. One person (spender) participates in auction while other (waiter) waits until next phase. If spender is successful in auction, fills out information for either lab pick-up or shipping. includable_templates: - content: "
\n
\n

\n \ Auction Instructions\n

\n

\n Here are the rules of the auction:\n

\n \n
\n
" name: auction_instructions - content: "\n{% load otree %}\n\n\n\n" name: uw_teton_bg - content: "{% load otree %}\n\n\n" name: uw_teton_survey - content: "{% load otree %}\n\n" name: two_column_flex_container models: Group: fields: - datatype: IntegerField kwargs: blank: null choices: null initial: null label: null max: null min: null widget: null name: budget - datatype: IntegerField kwargs: blank: null choices: null initial: null label: null max: null min: null widget: null name: price - datatype: BooleanField kwargs: blank: null choices: null initial: null label: null widget: null name: win - datatype: FloatField kwargs: blank: null choices: null initial: null label: null max: null min: null widget: null name: WTP_spender - datatype: IntegerField kwargs: blank: null choices: null initial: null label: null max: null min: null widget: null name: budget_initial methods: - code: "# import random\nimport random\n\n# Gather players\nplayers = group.get_players()\n\n# Define the group budget from RET1\ngroup.budget = players[0].participant.budget_2\ngroup.budget_initial = players[0].participant.budget_2\n\n# Draw a single random number to use as the price\ngroup.price = int((random.uniform((group.budget*0.85), group.budget)) + 0.5) # UNIFORM DIST VERSION\n\n# Sanity check for price bounds and bounding the distribution if normal\nif group.price <= 1:\n group.price = 1\nelif group.price >= group.budget:\n group.price = group.budget" is_method: false name: set_price - code: "# Gather players\nplayers = group.get_players()\n\n# Identify the player with the spending role\nspender_player = None\nfor p in players:\n p.participant.WTP_2 = 0 # set default value of WTP to participant field if not used\n if p.participant.spender == 1:\n spender_player = p\n p.participant.WTP_2 = spender_player.WTP # set WTP for spender to participant field\n\n# Compare the WTP to price\nif spender_player.WTP >= group.price:\n group.win = True\n group.budget = group.budget - group.price # Money taken from joint account\nelse:\n group.win = False\n group.budget = group.budget # Nothing spent from joint account\n \n# If winner, save to participant field\nfor p in players:\n if p.participant.spender == 1 and group.win == True:\n p.participant.winner_2 = 1\n\n# Save final earnings to a global variable\nfor p in players:\n p.participant.earnings_2 = group.budget /2\n p.participant.computer_price_2 = group.price" is_method: false name: auction_check Player: fields: - datatype: BooleanField kwargs: blank: null choices: null initial: constant: null expr_type: plain js_value: false label: null widget: null name: won_auction - datatype: FloatField kwargs: blank: null choices: null initial: null label: constant: null expr_type: plain js_value: How much would you be willing to spend on the item shown above in dollars? (Enter your bid as a dollar value using at maximum 2 decimals) max: null min: constant: null expr_type: plain js_value: 0 widget: null name: WTP methods: - code: return group.budget is_method: false name: WTP_max Subsession: fields: [] methods: - code: "# pull the matrix you stored in the code‐entry app\nmatrix = subsession.session.vars.get('couple_matrix')\nif not matrix:\n # safety check in case someone forgot to run grouping first\n \ raise RuntimeError(\"No couple_matrix in session.vars\")\n# re‐apply it in this app's subsession\nsubsession.set_group_matrix(matrix)" is_method: false name: after_all_players_arrive name: Auction_2 pages: - after_all_players_arrive: after_all_players_arrive body_text: null group_by_arrival_time: null is_displayed: null is_waitpage: true name: GroupingWaitPage template: null title_text: null wait_for_all_groups: true - after_all_players_arrive: null body_text: null group_by_arrival_time: null is_displayed: null is_waitpage: true name: Auction_2StartPage template: null title_text: null wait_for_all_groups: true - after_all_players_arrive: set_price body_text: null group_by_arrival_time: null is_displayed: null is_waitpage: true name: SetBudgetWaitPage template: null title_text: null wait_for_all_groups: null - app_after_this_page: null before_next_page: null error_message: null form_fields: null form_model: player get_form_fields: null get_timeout_seconds: null is_displayed: null is_waitpage: false js_vars: null live_method: null name: RoleReveal template: content: "\n{{ include_sibling 'uw_teton_bg.html' }}\n\n\n{{ if player.participant.spender == 1 }}

\n You have been selected and are receiving the opportunity to spend the money {{ if player.participant.earner_round_2 == 1 }} you{{ else }} your partner{{ endif }} earned from the matrix task. In other words, ${{ group.budget }} in the joint account. Remember, whatever balance is remaining in the joint account at the end of the experiment will be split equally between you and your partner.\n

\n\n

\n \ It is important to our study that the item you purchase is for your own use and that, after the experiment, you do not compensate your partner for having bought the item.\n

\n\n

\n The budget for you to spend is ${{ group.budget }}.\n

\n\n\n{{ else }}

\n You were not selected to complete the spending task. Please wait for further instructions.\n

\n\n{{ endif}}\n\n{{ next_button }}" javascript: null title: Spending Task timeout_seconds: null timer_text: null vars_for_template: null - after_all_players_arrive: null body_text: null group_by_arrival_time: null is_displayed: "# If the participant is not the spender, sit on this wait page\nif participant.spender != 1:\n return True" is_waitpage: true name: NotSpendingWaitPage template: null title_text: You were not selected for the spending task. Please wait for further instructions. wait_for_all_groups: null - app_after_this_page: null before_next_page: "group.WTP_spender = player.WTP\nif timeout_happened:\n # Default value for any form fields if timeout occurs, because otherwise they may be left null\n player.player_sum = 0\n participant.WTP_2_timeout = 1" error_message: null form_fields: - WTP form_model: player get_form_fields: null get_timeout_seconds: null is_displayed: '# If participant is the spender, show them this page return participant.spender == 1' is_waitpage: false js_vars: null live_method: null name: Spending template: content: "\n{{ include_sibling 'uw_teton_bg.html' }}\n\n\n\n\n\n

\n You are being offered this item, whose market value is approximately $30:\n

\n\n\n\"Selected\n\n\n

\n {{ description }}\n

\n\n\n

\n You will participate in an auction to determine if you will purchase this item. The total amount you can spend on this task is the ${{group.budget}}, the money that {{if player.participant.earner_round_2 == 1}}you{{else}}your partner{{endif}} earned from the matrix task; in other words you can spend up to ${{group.budget}} from the joint account. Remember, all money remaining in the joint account at the end of the study will be split evenly between you and your partner.\n

\n

\n \ Remember, the results of the first and second joint account and auction are completely separate, and only one will be chosen randomly for your final payment.\n

\n

\n Here's a reminder of the rules of the auction:\n

\n\n\n
\n\n\n{{ formfields }}\n\n{{ next_button }}" javascript: "// This script is included to ensure that if tags are included in form fields they are observed\n$(document).ready(function (e) {\n labels = document.getElementsByTagName(\"label\");\n\n for (var i = 0; i < labels.length; i++) {\n labels[i].innerHTML = labels[i].innerHTML.replaceAll(\"<\", \"<\").\n replaceAll(\">\", \">\");\n }\n});" title: The Auction timeout_seconds: 180 timer_text: null vars_for_template: "# Define the list of items with unique identifiers, their associated image URLs, and a description\nimgur_urls = [\n {'id': 'A', 'url': 'https://i.imgur.com/OfsrPbR.jpeg', 'description': \"Coloring book with pencils\"},\n \ {'id': 'B', 'url': 'https://i.imgur.com/tmBYFwX.jpeg', 'description': \"Headphones\"},\n \ {'id': 'C', 'url': 'https://i.imgur.com/oBfC4Mz.jpeg', 'description': \"Moisturizer\"},\n \ {'id': 'D', 'url': 'https://i.imgur.com/q7bBuv6.jpeg', 'description': \"Spa kit\"},\n {'id': 'E', 'url': 'https://i.imgur.com/Zc7vR6m.jpeg', 'description': \"Grilling accessories\"},\n {'id': 'F', 'url': 'https://i.imgur.com/YLEoKGI.jpeg', 'description': \"Tactical flashlight\"},\n {'id': 'G', 'url': 'https://i.imgur.com/lmMFuFL.jpeg', 'description': \"Lip Balm\"},\n {'id': 'H', 'url': 'https://i.imgur.com/5KfUIfj.jpeg', 'description': \"Water bottle\"},\n {'id': 'I', 'url': 'https://i.imgur.com/AS1feBP.jpeg', 'description': \"Car detailing kit\"},\n {'id': 'J', 'url': 'https://i.imgur.com/SfJ7GmF.jpeg', 'description': \"Multi-tool\"}\n]\n\n# Default fallback if selected_item is missing or invalid\ndefault_image = 'https://miro.medium.com/v2/resize:fit:1100/format:webp/1*MXyMqcEJ6Se0SCWcYCKZTQ.jpeg'\ndefault_desc = 'No description available.'\n\n# Retrieve the selected item from participant data\nselected_item = participant.selected_item # Expect one of 'A' through 'J'\n\n# Find the dictionary for the selected item\nselected = next((item for item in imgur_urls if item['id'] == selected_item),\n {'url': default_image, 'description': default_desc})\n\n# Pass both the full list and the selected item's data to the template\nreturn dict(\n image_paths=imgur_urls,\n \ image_path=selected['url'],\n description=selected['description'],\n)" - after_all_players_arrive: auction_check body_text: null group_by_arrival_time: null is_displayed: null is_waitpage: true name: ResultsWaitPage template: null title_text: null wait_for_all_groups: null - after_all_players_arrive: null body_text: null group_by_arrival_time: null is_displayed: null is_waitpage: true name: Auction_1EndPage template: null title_text: Please wait for further instructions. wait_for_all_groups: true - bots: '' constants: - datatype: int js_value: 2 name: PLAYERS_PER_GROUP - datatype: int js_value: 1 name: NUM_ROUNDS - datatype: int js_value: 22 name: NUM_POP_QS - datatype: list_int js_value: - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 - 11 - 12 - 13 - 14 - 15 - 16 - 17 - 18 - 19 - 20 name: PRICE_STEPS - datatype: list_int js_value: - 1 - 2 - 3 - 4 - 5 - 6 - 7 name: SMILEY_LIKERT_OPTS custom_export: "# Header\nyield [\n 'session_code',\n 'participant_id_in_session',\n \ 'participant_code',\n 'id_in_group',\n 'group_number',\n 'spender',\n \ 'pop_self_00', 'pop_self_02', 'pop_self_04', 'pop_self_06', 'pop_self_08', 'pop_self_10', 'pop_self_12', 'pop_self_16', 'pop_self_20',\n 'pop_partner_00', 'pop_partner_02', 'pop_partner_04', 'pop_partner_06', 'pop_partner_08', 'pop_partner_10', 'pop_partner_12', 'pop_partner_16', 'pop_partner_20', \n]\n\n# Rows\nfor p in players:\n pp = p.participant\n pg = p.group\n ps = p.session\n # Pull participant fields\n spender = p.participant.vars.get('spender', '')\n \ yield [\n ps.code,\n pp.id_in_session,\n pp.code,\n p.id_in_group,\n \ pg.id_in_subsession,\n spender,\n p.pop_self_00, p.pop_self_02, p.pop_self_04, p.pop_self_06, p.pop_self_08, p.pop_self_10, p.pop_self_12, p.pop_self_16, p.pop_self_20, \n p.pop_partner_00, p.pop_partner_02, p.pop_partner_04, p.pop_partner_06, p.pop_partner_08, p.pop_partner_10, p.pop_partner_12, p.pop_partner_16, p.pop_partner_20\n ]" doc: '' includable_templates: - content: "
\n
\n

\n \ Auction Instructions\n

\n

\n Here are the rules of the auction:\n

\n \n
\n
" name: auction_instructions - content: "\n{% load otree %}\n\n\n\n" name: uw_teton_bg - content: "{% load otree %}\n\n\n" name: uw_teton_survey - content: "{% load otree %}\n\n" name: two_column_flex_container models: Group: fields: [] methods: [] Player: fields: - datatype: IntegerField kwargs: blank: null choices: constant: SMILEY_LIKERT_OPTS expr_type: constant js_value: null initial: null label: constant: null expr_type: plain js_value: $0 (Free) max: null min: null widget: constant: null expr_type: plain js_value: RadioSelectHorizontal name: pop_self_00 - datatype: IntegerField kwargs: blank: null choices: constant: SMILEY_LIKERT_OPTS expr_type: constant js_value: null initial: null label: constant: null expr_type: plain js_value: $2 max: null min: null widget: constant: null expr_type: plain js_value: RadioSelectHorizontal name: pop_self_02 - datatype: IntegerField kwargs: blank: null choices: constant: SMILEY_LIKERT_OPTS expr_type: constant js_value: null initial: null label: constant: null expr_type: plain js_value: $4 max: null min: null widget: constant: null expr_type: plain js_value: RadioSelectHorizontal name: pop_self_04 - datatype: IntegerField kwargs: blank: null choices: constant: SMILEY_LIKERT_OPTS expr_type: constant js_value: null initial: null label: constant: null expr_type: plain js_value: $6 max: null min: null widget: constant: null expr_type: plain js_value: RadioSelectHorizontal name: pop_self_06 - datatype: IntegerField kwargs: blank: null choices: constant: SMILEY_LIKERT_OPTS expr_type: constant js_value: null initial: null label: constant: null expr_type: plain js_value: $8 max: null min: null widget: constant: null expr_type: plain js_value: RadioSelectHorizontal name: pop_self_08 - datatype: IntegerField kwargs: blank: null choices: constant: SMILEY_LIKERT_OPTS expr_type: constant js_value: null initial: null label: constant: null expr_type: plain js_value: $10 max: null min: null widget: constant: null expr_type: plain js_value: RadioSelectHorizontal name: pop_self_10 - datatype: IntegerField kwargs: blank: null choices: constant: SMILEY_LIKERT_OPTS expr_type: constant js_value: null initial: null label: constant: null expr_type: plain js_value: $12 max: null min: null widget: constant: null expr_type: plain js_value: RadioSelectHorizontal name: pop_self_12 - datatype: IntegerField kwargs: blank: null choices: constant: SMILEY_LIKERT_OPTS expr_type: constant js_value: null initial: null label: constant: null expr_type: plain js_value: $16 max: null min: null widget: constant: null expr_type: plain js_value: RadioSelectHorizontal name: pop_self_16 - datatype: IntegerField kwargs: blank: null choices: constant: SMILEY_LIKERT_OPTS expr_type: constant js_value: null initial: null label: constant: null expr_type: plain js_value: $20 max: null min: null widget: constant: null expr_type: plain js_value: RadioSelectHorizontal name: pop_self_20 - datatype: IntegerField kwargs: blank: null choices: constant: SMILEY_LIKERT_OPTS expr_type: constant js_value: null initial: null label: constant: null expr_type: plain js_value: $0 (Free) max: null min: null widget: constant: null expr_type: plain js_value: RadioSelectHorizontal name: pop_partner_00 - datatype: IntegerField kwargs: blank: null choices: constant: SMILEY_LIKERT_OPTS expr_type: constant js_value: null initial: null label: constant: null expr_type: plain js_value: $2 max: null min: null widget: constant: null expr_type: plain js_value: RadioSelectHorizontal name: pop_partner_02 - datatype: IntegerField kwargs: blank: null choices: constant: SMILEY_LIKERT_OPTS expr_type: constant js_value: null initial: null label: constant: null expr_type: plain js_value: $4 max: null min: null widget: constant: null expr_type: plain js_value: RadioSelectHorizontal name: pop_partner_04 - datatype: IntegerField kwargs: blank: null choices: constant: SMILEY_LIKERT_OPTS expr_type: constant js_value: null initial: null label: constant: null expr_type: plain js_value: $6 max: null min: null widget: constant: null expr_type: plain js_value: RadioSelectHorizontal name: pop_partner_06 - datatype: IntegerField kwargs: blank: null choices: constant: SMILEY_LIKERT_OPTS expr_type: constant js_value: null initial: null label: constant: null expr_type: plain js_value: $8 max: null min: null widget: constant: null expr_type: plain js_value: RadioSelectHorizontal name: pop_partner_08 - datatype: IntegerField kwargs: blank: null choices: constant: SMILEY_LIKERT_OPTS expr_type: constant js_value: null initial: null label: constant: null expr_type: plain js_value: $10 max: null min: null widget: constant: null expr_type: plain js_value: RadioSelectHorizontal name: pop_partner_10 - datatype: IntegerField kwargs: blank: null choices: constant: SMILEY_LIKERT_OPTS expr_type: constant js_value: null initial: null label: constant: null expr_type: plain js_value: $12 max: null min: null widget: constant: null expr_type: plain js_value: RadioSelectHorizontal name: pop_partner_12 - datatype: IntegerField kwargs: blank: null choices: constant: SMILEY_LIKERT_OPTS expr_type: constant js_value: null initial: null label: constant: null expr_type: plain js_value: $16 max: null min: null widget: constant: null expr_type: plain js_value: RadioSelectHorizontal name: pop_partner_16 - datatype: IntegerField kwargs: blank: null choices: constant: SMILEY_LIKERT_OPTS expr_type: constant js_value: null initial: null label: constant: null expr_type: plain js_value: $20 max: null min: null widget: constant: null expr_type: plain js_value: RadioSelectHorizontal name: pop_partner_20 methods: [] Subsession: fields: [] methods: - code: "# pull the matrix you stored in the code‐entry app\nmatrix = subsession.session.vars.get('couple_matrix')\nif not matrix:\n # safety check in case someone forgot to run grouping first\n \ raise RuntimeError(\"No couple_matrix in session.vars\")\n# re‐apply it in this app's subsession\nsubsession.set_group_matrix(matrix)" is_method: false name: after_all_players_arrive name: PainofPaying pages: - after_all_players_arrive: after_all_players_arrive body_text: null group_by_arrival_time: null is_displayed: null is_waitpage: true name: GroupingWaitPage template: null title_text: null wait_for_all_groups: true - app_after_this_page: null before_next_page: null error_message: null form_fields: - pop_self_00 - pop_self_02 - pop_self_04 - pop_self_06 - pop_partner_00 - pop_partner_02 - pop_partner_04 - pop_partner_06 - pop_partner_08 - pop_partner_10 - pop_partner_12 - pop_partner_16 - pop_partner_20 - pop_self_08 - pop_self_10 - pop_self_12 - pop_self_16 - pop_self_20 form_model: player get_form_fields: null get_timeout_seconds: null is_displayed: null is_waitpage: false js_vars: null live_method: null name: PainOfPaying template: content: "\n{{ include_sibling 'uw_teton_survey.html' }}\n\n\n\n\n

{{ if player.participant.spender == 1 }}\n You just attempted to purchase the following item using money from the joint account.\n

\n\n\n

{{ else }}\n Your partner attempted to purchase the following item using money from the joint account.\n

\n \n{{ endif }}\n\n\n\"Selected\n\n\n

\n {{ description }}\n

\n\n
\n

\n We will ask you how you would feel purchasing the item at amounts ranging from $0 to $20. For instance, how would you feel if {{ if player.participant.spender == 1 }}you{{ else }}your partner{{ endif }} were able to purchase the item for $8 with money earned by you? How would you feel if {{ if player.participant.spender == 1 }}you{{ else }}your partner{{ endif }} were able to purchase the item for $8 with money earned by your partner? How would your feelings change if {{ if player.participant.spender == 1 }}you{{ else }}your partner{{ endif }} were instead paying $12 for the item? Please indicate your feelings using the smiley face scale above — ranging from very positive (Face A) to very negative (Face G).\n

\n \n \n \"Smiley\n \n

\n Please indicate how you would feel about the purchase at the different prices, stating a letter (A-G) that best corresponds to your feelings.\n

\n\n \n
\n\n \ \n
\n \

\n Money YOU earned, from the joint account\n \

\n \n \n \ \n \n \ \n \n \ \n \n \ \n \n \ \n
PriceABCDEFG

\n
\n\n \n
\n

\n \ Money YOUR PARTNER earned, the from joint account\n

\n \ \n \n \n \ \n \n \ \n \n \ \n \n \ \n \n
PriceABCDEFG

\n
\n\n
\n \n
\n\n\n
\n \n \n \
\n \n {% for field in form %}\n {% if field.name.startswith('pop_self') %}\n \n \ \n {% for choice in field %}\n \n \ {% endfor %}\n \n {% endif %}\n {% endfor %}\n
{{ field.label }}{{ choice }}

\n
\n\n \ \n
\n \n {% for field in form %}\n {% if field.name.startswith('pop_partner') %}\n \n \n {% for choice in field %}\n \n {% endfor %}\n \n \ {% endif %}\n {% endfor %}\n
{{ field.label }}{{ choice }}

\n \
\n \n
\n\n{{ next_button }}" javascript: null title: Feelings on Purchase timeout_seconds: null timer_text: null vars_for_template: "# Define the list of items with unique identifiers, their associated image URLs, and a description\nimgur_urls = [\n {'id': 'A', 'url': 'https://i.imgur.com/OfsrPbR.jpeg', 'description': \"Coloring book with pencils\"}, # Image and description for item A\n {'id': 'B', 'url': 'https://i.imgur.com/tmBYFwX.jpeg', 'description': \"Headphones\"}, # Image and description for item B\n {'id': 'C', 'url': 'https://i.imgur.com/oBfC4Mz.jpeg', 'description': \"Moisturizer\"}, # Image and description for item C\n {'id': 'D', 'url': 'https://i.imgur.com/q7bBuv6.jpeg', 'description': \"Spa kit\"}, # Image and description for item D\n {'id': 'E', 'url': 'https://i.imgur.com/Zc7vR6m.jpeg', 'description': \"Grilling accessories\"}, # Image and description for item E\n {'id': 'F', 'url': 'https://i.imgur.com/YLEoKGI.jpeg', 'description': \"Tactical flashlight\"}, # Image and description for item F\n \ {'id': 'G', 'url': 'https://i.imgur.com/lmMFuFL.jpeg', 'description': \"Lip Balm\"}, # Image and description for item G\n {'id': 'H', 'url': 'https://i.imgur.com/5KfUIfj.jpeg', 'description': \"Water bottle\"}, # Image and description for item H\n {'id': 'I', 'url': 'https://i.imgur.com/AS1feBP.jpeg', 'description': \"Car detailing kit\"}, # Image and description for item I\n {'id': 'J', 'url': 'https://i.imgur.com/SfJ7GmF.jpeg', 'description': \"Multi-tool\"} # Image and description for item J\n]\n\n# Fallback defaults for missing items\ndefault_image = 'https://miro.medium.com/v2/resize:fit:1100/format:webp/1*MXyMqcEJ6Se0SCWcYCKZTQ.jpeg'\ndefault_desc = 'No description available.'\n\n# Get the selected item code from participant\nselected_item = participant.spender_selected_item\n# Look up the selected entry or fall back to defaults\nselected = next(\n (item for item in imgur_urls if item['id'] == selected_item),\n {'url': default_image, 'description': default_desc}\n)\n\n# Pass data to template\nreturn dict(\n price_steps=C.PRICE_STEPS,\n img_url='https://imgur.com/N7q1Rts.png',\n \ image_paths=imgur_urls,\n image_path=selected['url'],\n description=selected['description'],\n)" - after_all_players_arrive: null body_text: null group_by_arrival_time: null is_displayed: null is_waitpage: true name: POPEndPage template: null title_text: Please wait for further instructions. wait_for_all_groups: true - bots: '' constants: - datatype: int js_value: 2 name: PLAYERS_PER_GROUP - datatype: int js_value: 1 name: NUM_ROUNDS - datatype: list_int js_value: - 1 - 2 - 3 - 4 - 5 name: LIKERT_OPTS - datatype: list_int js_value: - 1 - 2 - 3 - 4 - 5 - 6 - 7 name: SMILEY_LIKERT_OPTS custom_export: "# Header\nyield [\n 'session_code',\n 'participant_id_in_session',\n \ 'participant_code',\n 'id_in_group',\n 'group_number',\n 'spender',\n \ 'earner_1', # noticed error (not correct variable), keeping for consistency in custom exports\n 'earner_2', # noticed error (not correct variable), keeping for consistency in custom exports\n # Relationship Qs\n 'r_entiltedMe', 'r_entiltedPartner', 'r_upsetPartner', 'r_guilty', # Spender likert Qs\n 'r_entitledPartnerToSpendTheirs', 'r_entitledPartnerToSpendMine', 'r_upsetWithPartner', 'r_expectPartnerGuilt', # Nonspender likert Qs\n 'r_importance', 'r_uncomfortable', 'r_liveTogether', 'r_maritalStatus', 'r_relationshipLength', 'r_relationshipLast', 'r_householdAdults', 'r_householdChildren', 'r_happy',\n # TWST Qs\n 'TWST_1', 'TWST_2a', 'TWST_2b', 'TWST_3',\n # General Demographis Qs\n 'gender',\n 'age',\n 'student',\n \ 'education',\n 'householdIncome'\n]\n\n# Rows\nfor p in players:\n pp = p.participant\n pg = p.group\n ps = p.session\n # Pull participant fields\n spender = p.participant.vars.get('spender', '')\n earner_round_1 = p.participant.vars.get('earner_round_1', '')\n earner_round_2 = p.participant.vars.get('earner_round_2', '')\n yield [\n ps.code,\n pp.id_in_session,\n pp.code,\n \ p.id_in_group,\n pg.id_in_subsession,\n spender,\n earner_1, # noticed error (not correct variable), keeping for consistency in custom exports\n \ earner2, # noticed error (not correct variable), keeping for consistency in custom exports\n p.r_entiltedMe, p.r_entiltedPartner, p.r_upsetPartner, p.r_guilty,\n p.r_entitledPartnerToSpendTheirs, p.r_entitledPartnerToSpendMine, p.r_upsetWithPartner, p.r_expectPartnerGuilt,\n p.r_importance, p.r_uncomfortable, p.r_liveTogether, p.r_maritalStatus, p.r_relationshipLength, p.r_relationshipLast, p.r_householdAdults, p.r_householdChildren, p.r_happy,\n p.TWST_1, p.TWST_2a, p.TWST_2b, p.TWST_3,\n p.gender,\n p.age,\n p.student,\n \ p.education,\n p.f_householdIncome\n ]" doc: 'Post experiment questions. Includes survey questions, Tightwad-spendthrift scale by Rick Scott, Cynthia Cryder, and George Loewenstein (2008), and demographic questions. ' includable_templates: - content: "\n{% load otree %}\n\n\n\n" name: uw_teton_bg - content: "{% load otree %}\n" name: uw_teton_survey - content: "{% load otree %}\n\n" name: checkbox_list models: Group: fields: [] methods: [] Player: fields: - datatype: IntegerField kwargs: blank: null choices: constant: LIKERT_OPTS expr_type: constant js_value: null initial: null label: constant: null expr_type: plain js_value: I felt entitled to spend the money earned by me in the joint account. max: null min: null widget: constant: null expr_type: plain js_value: RadioSelectHorizontal name: r_entiltedMe - datatype: IntegerField kwargs: blank: null choices: constant: LIKERT_OPTS expr_type: constant js_value: null initial: null label: constant: null expr_type: plain js_value: I felt entitled to spend the money earned by my partner in the joint account. max: null min: null widget: constant: null expr_type: plain js_value: RadioSelectHorizontal name: r_entiltedPartner - datatype: IntegerField kwargs: blank: null choices: constant: LIKERT_OPTS expr_type: constant js_value: null initial: null label: constant: null expr_type: plain js_value: My partner would be upset with me if I spent a large portion of the money from the joint account in this study on an item only I would use. max: null min: null widget: constant: null expr_type: plain js_value: RadioSelectHorizontal name: r_upsetPartner - datatype: IntegerField kwargs: blank: null choices: constant: LIKERT_OPTS expr_type: constant js_value: null initial: null label: constant: null expr_type: plain js_value: I would feel guilty if I spent a large portion of the money from the joint account in this study on an item only I would use. max: null min: null widget: constant: null expr_type: plain js_value: RadioSelectHorizontal name: r_guilty - datatype: IntegerField kwargs: blank: null choices: constant: LIKERT_OPTS expr_type: constant js_value: null initial: null label: constant: null expr_type: plain js_value: I felt my partner was entitled to spend the money earned by themselves in the joint account. max: null min: null widget: constant: null expr_type: plain js_value: RadioSelectHorizontal name: r_entitledPartnerToSpendTheirs - datatype: IntegerField kwargs: blank: null choices: constant: LIKERT_OPTS expr_type: constant js_value: null initial: null label: constant: null expr_type: plain js_value: I felt my partner was entitled to spend the money earned by me in the joint account. max: null min: null widget: constant: null expr_type: plain js_value: RadioSelectHorizontal name: r_entitledPartnerToSpendMine - datatype: IntegerField kwargs: blank: null choices: constant: LIKERT_OPTS expr_type: constant js_value: null initial: null label: constant: null expr_type: plain js_value: I would be upset with my partner if they spent a large portion of the money from the joint account in this study on an item only they would use. max: null min: null widget: constant: null expr_type: plain js_value: RadioSelectHorizontal name: r_upsetWithPartner - datatype: IntegerField kwargs: blank: null choices: constant: LIKERT_OPTS expr_type: constant js_value: null initial: null label: constant: null expr_type: plain js_value: I would expect my partner to feel guilty if they spent a large portion of the money from the joint account in this study on an item only they would use. max: null min: null widget: constant: null expr_type: plain js_value: RadioSelectHorizontal name: r_expectPartnerGuilt - datatype: IntegerField kwargs: blank: null choices: constant: LIKERT_OPTS expr_type: constant js_value: null initial: null label: constant: null expr_type: plain js_value: My relationship with my partner is very important to me. max: null min: null widget: constant: null expr_type: plain js_value: RadioSelectHorizontal name: r_importance - datatype: IntegerField kwargs: blank: null choices: constant: LIKERT_OPTS expr_type: constant js_value: null initial: null label: constant: null expr_type: plain js_value: I feel very uncomfortable when my partner is upset with me. max: null min: null widget: constant: null expr_type: plain js_value: RadioSelectHorizontal name: r_uncomfortable - datatype: BooleanField kwargs: blank: null choices: constant: null expr_type: plain js_value: - - true - Yes - - false - No initial: null label: constant: null expr_type: plain js_value: Do you live with your partner? widget: constant: null expr_type: plain js_value: RadioSelect name: r_liveTogether - datatype: StringField kwargs: blank: null choices: constant: null expr_type: plain js_value: - - '0' - Relationship with Partner - - '1' - Married initial: null label: constant: null expr_type: plain js_value: What is your current relationship status? widget: constant: null expr_type: plain js_value: RadioSelect name: r_maritalStatus - datatype: StringField kwargs: blank: null choices: constant: null expr_type: plain js_value: - - '1' - Less than 6 months - - '2' - 6 months to 1 year - - '3' - 1 to 2 years - - '4' - 3 to 5 years - - '5' - 6 to 10 years - - '6' - 11 to 20 years - - '7' - More than 20 years initial: null label: constant: null expr_type: plain js_value: How long have you been in a relationship with your partner? (Please round to the nearest full year. For example, 2.3 years = "1 to 2 years") widget: constant: null expr_type: plain js_value: RadioSelect name: r_relationshipLength - datatype: StringField kwargs: blank: null choices: constant: null expr_type: plain js_value: - - '1' - A few months at most - - '2' - Around a year - - '3' - Several years - - '4' - A lifetime initial: null label: constant: null expr_type: plain js_value: How long do you believe your relationship with your partner will last? widget: constant: null expr_type: plain js_value: RadioSelect name: r_relationshipLast - datatype: IntegerField kwargs: blank: null choices: null initial: null label: constant: null expr_type: plain js_value: How many adults (age 18 or older) are in your household (including you)? max: null min: constant: null expr_type: plain js_value: 0 widget: null name: r_householdAdults - datatype: IntegerField kwargs: blank: null choices: null initial: null label: constant: null expr_type: plain js_value: How many children (under age 18) are in your household? max: null min: constant: null expr_type: plain js_value: 0 widget: null name: r_householdChildren - datatype: StringField kwargs: blank: null choices: constant: null expr_type: plain js_value: - - '1' - '' - - '2' - '' - - '3' - '' - - '4' - '' - - '5' - '' - - '6' - '' - - '7' - '' initial: null label: constant: null expr_type: plain js_value: How happy are you in your relationship? widget: constant: null expr_type: plain js_value: RadioSelectHorizontal name: r_happy - datatype: StringField kwargs: blank: null choices: constant: null expr_type: plain js_value: - - '1' - '1' - - '2' - '2' - - '3' - '3' - - '4' - '4' - - '5' - '5' - - '6' - '6' - - '7' - '7' - - '8' - '8' - - '9' - '9' - - '10' - '10' - - '11' - '11' initial: null label: constant: null expr_type: plain js_value: Which of the following descriptions fits you better? widget: constant: null expr_type: plain js_value: RadioSelectHorizontal name: TWST_1 - datatype: StringField kwargs: blank: null choices: constant: null expr_type: plain js_value: - - '1' - Never - - '2' - Rarely - - '3' - Sometimes - - '4' - Often - - '5' - Always initial: null label: constant: null expr_type: plain js_value: How well does the the first description fit you? That is, do you have trouble limiting your spending? widget: constant: null expr_type: plain js_value: RadioSelectHorizontal name: TWST_2a - datatype: StringField kwargs: blank: null choices: constant: null expr_type: plain js_value: - - '1' - Never - - '2' - Rarely - - '3' - Sometimes - - '4' - Often - - '5' - Always initial: null label: constant: null expr_type: plain js_value: How well does the the second description fit you? That is, do you have trouble spending money? widget: constant: null expr_type: plain js_value: RadioSelectHorizontal name: TWST_2b - datatype: StringField kwargs: blank: null choices: constant: null expr_type: plain js_value: - - '1' - '1' - - '2' - '2' - - '3' - '3' - - '4' - '4' - - '5' - '5' initial: null label: constant: null expr_type: plain js_value: In terms of your own behavior, who are you more similar to, Mr. A or Mr. B? widget: constant: null expr_type: plain js_value: RadioSelectHorizontal name: TWST_3 - datatype: StringField kwargs: blank: null choices: constant: null expr_type: plain js_value: - - '1' - Under $25,000 - - '2' - Between $25,001 and $50,000 - - '3' - Between $50,001 and $75,000 - - '4' - Between $75,001 and $100,000 - - '5' - Between $100,001 and $125,000 - - '6' - Between $125,001 and $150,000 - - '7' - Between $150,001 and $175,000 - - '8' - Between $175,001 and $200,000 - - '9' - More than $200,001 initial: null label: constant: null expr_type: plain js_value: What is your household's combined, pre-tax, annual income (including bonuses and commissions) last year in U.S. dollars? widget: constant: null expr_type: plain js_value: RadioSelect name: f_householdIncome - datatype: StringField kwargs: blank: null choices: constant: null expr_type: plain js_value: - - '0' - Male - - '1' - Female - - '2' - Other initial: null label: constant: null expr_type: plain js_value: What is your gender? widget: constant: null expr_type: plain js_value: RadioSelect name: gender - datatype: StringField kwargs: blank: null choices: null initial: null label: constant: null expr_type: plain js_value: '"You selected ''Other'' as your gender. Please describe your gender identity:"' widget: null name: gender_other - datatype: IntegerField kwargs: blank: null choices: null initial: null label: constant: null expr_type: plain js_value: What is your age? Please enter your answer as a number max: constant: null expr_type: plain js_value: 99 min: constant: null expr_type: plain js_value: 18 widget: null name: age - datatype: StringField kwargs: blank: null choices: constant: null expr_type: plain js_value: - - '1' - Yes - - '0' - No initial: null label: constant: null expr_type: plain js_value: Are you a college student? widget: constant: null expr_type: plain js_value: RadioSelect name: student - datatype: StringField kwargs: blank: null choices: constant: null expr_type: plain js_value: - - '1' - Some high school or less - - '2' - High school diploma or GED - - '3' - Some college, but no degree - - '4' - Associates or technical degree - - '5' - Bachelor's degree - - '6' - Graduate or professional degree (MA, MS, MBA, PhD, JD, MD, DDS etc.) initial: null label: constant: null expr_type: plain js_value: What is the highest level of education you have completed? widget: constant: null expr_type: plain js_value: RadioSelect name: education methods: [] Subsession: fields: [] methods: - code: "# pull the matrix you stored in the code‐entry app\nmatrix = subsession.session.vars.get('couple_matrix')\nif not matrix:\n # safety check in case someone forgot to run grouping first\n \ raise RuntimeError(\"No couple_matrix in session.vars\")\n# re‐apply it in this app's subsession\nsubsession.set_group_matrix(matrix)" is_method: false name: after_all_players_arrive name: Survey pages: - after_all_players_arrive: after_all_players_arrive body_text: null group_by_arrival_time: null is_displayed: null is_waitpage: true name: GroupingWaitPage template: null title_text: null wait_for_all_groups: true - app_after_this_page: null before_next_page: null error_message: null form_fields: - r_entiltedMe - r_entiltedPartner - r_upsetPartner - r_guilty - r_importance - r_uncomfortable - r_liveTogether - r_maritalStatus - r_relationshipLength - r_relationshipLast - r_householdAdults - r_householdChildren - r_happy form_model: player get_form_fields: null get_timeout_seconds: null is_displayed: "# Display if participant is the spender\nif player.participant.spender == 1:\n return True" is_waitpage: false js_vars: null live_method: null name: Relationship_Qs_Spender template: content: "\n{{ include_sibling 'uw_teton_survey.html' }} \n\n\n\n
\n
\n \

\n In this final part of the study, we will ask you to answer a series of questions about yourself and your partner. These questions will help us gather additional information for our research. All details are confidential and cannot be used to track your personal identity.\n \

\n
\n
\n\n\n

\n Please rate how much you agree with the following statements:\n

\n\n \n \n \n \n \ \n \n \ \n \n {% for field in form %}\n {% if field.name in likert_fields_spender %}\n \n \ \n {% for choice in field %}\n \n {% endfor %}\n \n {% endif %}\n {% endfor %}\n
QuestionStrongly DisagreeSomewhat DisagreeNeutralSomewhat AgreeStrongly Agree
{{ field.label }}{{ choice }}

\n\n\n
\n \ {% for field in form %}\n {% if not field.name in likert_fields_spender and not field.name in happiness_fields %}\n
\n \ \n {{ field }}\n

\n {% endif %}\n {% endfor %}\n
\n\n\n

\n Please rate how much you agree with the following statements according to the smiley face scale below:\n

\n\n \"Smiley\n\n\n \n \n \n \ \n \n \ \n \n \ \n \n \ \n {% for field in form %}\n {% if field.name in happiness_fields %}\n \n \n {% for choice in field %}\n \n {% endfor %}\n \n {% endif %}\n {% endfor %}\n
ABCDEFG
{{ field.label }}{{ choice }}

\n\n{{ next_button }}" javascript: "// This script is included to ensure that if tags are included in form fields they are observed\n$(document).ready(function (e) {\n labels = document.getElementsByTagName(\"label\");\n\n for (var i = 0; i < labels.length; i++) {\n labels[i].innerHTML = labels[i].innerHTML.replaceAll(\"<\", \"<\").\n replaceAll(\">\", \">\");\n }\n});" title: Questionnaire timeout_seconds: null timer_text: null vars_for_template: "# List of fields to include in the Likert scale table\nlikert_fields_spender = ['r_entiltedMe','r_entiltedPartner', 'r_upsetPartner','r_guilty','r_importance','r_uncomfortable']\n\n# List of fields for the happiness Likert scale\nhappiness_fields = ['r_happy']\n\n# Passing Python variables to the HTML template of the page\nreturn {\n 'img_url': 'https://imgur.com/N7q1Rts.png',\n 'likert_fields_spender': likert_fields_spender,\n \ 'happiness_fields': happiness_fields\n}" - app_after_this_page: null before_next_page: null error_message: null form_fields: - r_entitledPartnerToSpendTheirs - r_entitledPartnerToSpendMine - r_upsetWithPartner - r_expectPartnerGuilt - r_importance - r_uncomfortable - r_liveTogether - r_maritalStatus - r_relationshipLength - r_relationshipLast - r_householdAdults - r_householdChildren - r_happy form_model: player get_form_fields: null get_timeout_seconds: null is_displayed: "# Display if participant is the spender\nif player.participant.spender != 1:\n return True" is_waitpage: false js_vars: null live_method: null name: Relationship_Qs_Nonspender template: content: "\n{{ include_sibling 'uw_teton_survey.html' }} \n\n\n\n
\n
\n \

\n In this final part of the study, we will ask you to answer a series of questions about yourself and your partner. These questions will help us gather additional information for our research. All details are confidential and cannot be used to track your personal identity.\n \

\n
\n
\n\n\n

\n Please rate how much you agree with the following statements:\n

\n\n \n \n \n \n \ \n \n \ \n \n {% for field in form %}\n {% if field.name in likert_fields_nonspender %}\n \n \ \n {% for choice in field %}\n \n {% endfor %}\n \n {% endif %}\n {% endfor %}\n
QuestionStrongly DisagreeSomewhat DisagreeNeutralSomewhat AgreeStrongly Agree
{{ field.label }}{{ choice }}

\n\n\n
\n \ {% for field in form %}\n {% if not field.name in likert_fields_nonspender and not field.name in happiness_fields %}\n
\n \ \n {{ field }}\n

\n {% endif %}\n {% endfor %}\n
\n\n\n

\n Please rate how much you agree with the following statements according to the smiley face scale below:\n

\n\n \"Smiley\n\n\n \n \n \n \ \n \n \ \n \n \ \n \n \ \n {% for field in form %}\n {% if field.name in happiness_fields %}\n \n \n {% for choice in field %}\n \n {% endfor %}\n \n {% endif %}\n {% endfor %}\n
ABCDEFG
{{ field.label }}{{ choice }}

\n\n{{ next_button }}" javascript: "// This script is included to ensure that if tags are included in form fields they are observed\n$(document).ready(function (e) {\n labels = document.getElementsByTagName(\"label\");\n\n for (var i = 0; i < labels.length; i++) {\n labels[i].innerHTML = labels[i].innerHTML.replaceAll(\"<\", \"<\").\n replaceAll(\">\", \">\");\n }\n});" title: Questionnaire timeout_seconds: null timer_text: null vars_for_template: "# List of fields to include in the Likert scale table\nlikert_fields_nonspender = ['r_entitledPartnerToSpendMine','r_entitledPartnerToSpendTheirs', 'r_upsetWithPartner','r_expectPartnerGuilt','r_importance','r_uncomfortable']\n\n# List of fields for the happiness Likert scale\nhappiness_fields = ['r_happy']\n\n# Passing Python variables to the HTML template of the page\nreturn {\n 'img_url': 'https://imgur.com/N7q1Rts.png',\n 'likert_fields_nonspender': likert_fields_nonspender,\n \ 'happiness_fields': happiness_fields\n}" - app_after_this_page: null before_next_page: null error_message: null form_fields: - TWST_1 - TWST_2a - TWST_2b - TWST_3 form_model: player get_form_fields: null get_timeout_seconds: null is_displayed: null is_waitpage: false js_vars: null live_method: null name: TWST_Questions template: content: "\n{{ include_sibling 'uw_teton_survey.html' }} \n\n\n
\n

\n Consider which of the following descriptions fits you better:\n

\n \

\n \"I find it difficult to spend money\"
OR
\"I have difficulty controlling my spending\"\n

\n

\n Below, select a number from 1 to 11 below to indicate where you fall on this dimension. 1 indicates \"I find it difficult to spend money.\" 11 indicates \"I have difficulty controlling my spending.\"\n

\n \n \ \n \n \n \ \n \n \ \n \n \ \n \n \ \n \n \ \n \n \n {% for choice in form.TWST_1 %}\n \n {% endfor %}\n \n \n \n \n \n \ \n \n \ \n \n \ \n \n \ \n \n \n
1234567891011
{{ choice }}
Tightwad
(difficulty spending money)
About the the same or neitherSpendthrift
(difficulty controlling spending)
\n

\n\n\n
\n

\n Some people have trouble limiting their spending: they often spend money—for example on clothes, meals, vacations, phone calls—when they would do better not to.\n

\n \

\n Other people have trouble spending money. Perhaps because spending money makes them anxious, they often don't spend money on things they should spend it on.\n

\n \n \ \n \n {% for choice in form.TWST_2a %}\n \n {% endfor %}\n \n \n \n \ \n \n \ \n \n \ \n
{{ choice }}
NeverRarelySometimesOftenAlways
\n
\n\n\n\n
\n \n \n \n {% for choice in form.TWST_2b %}\n \n {% endfor %}\n \n \ \n \n \n \ \n \n \ \n \n
{{ choice }}
NeverRarelySometimesOftenAlways
\n

\n\n\n
\n

\n The following is a scenario describing the behavior of two shoppers. After reading about each shopper, please answer the question that follows.\n

\n

\n \ Mr. A is accompanying a good friend who is on a shopping spree at a local mall. When they enter a large department store, Mr. A sees that the store has a \"one-day-only-sale\" where everything is priced 10-60% off. He realizes he doesn't need anything, yet can't resist and ends up spending almost $100 on stuff.\n

\n

\n Mr. B is accompanying a good friend who is on a shopping spree at a local mall. When they enter a large department store, Mr. B sees that the store has a \"one-day-only-sale\" where everything is priced 10-60% off. He figures he can get great deals on many items that he needs, yet the thought of spending the money keeps him from buying the stuff.\n

\n \n \n \ \n \n \n \ \n \n \ \n \n \n {% for choice in form.TWST_3 %}\n \n {% endfor %}\n \n \n \n \ \n \n \n \n \n
12345
{{ choice }}
Mr. AAbout the same or neitherMr. B
\n
\n\n{{ next_button }}\n" javascript: "// This script is included to ensure that if tags are included in form fields they are observed\n$(document).ready(function (e) {\n labels = document.getElementsByTagName(\"label\");\n\n for (var i = 0; i < labels.length; i++) {\n labels[i].innerHTML = labels[i].innerHTML.replaceAll(\"<\", \"<\").\n replaceAll(\">\", \">\");\n }\n});" title: Questionnaire timeout_seconds: null timer_text: null vars_for_template: null - app_after_this_page: null before_next_page: null error_message: null form_fields: - gender - age - student - education - f_householdIncome form_model: player get_form_fields: null get_timeout_seconds: null is_displayed: null is_waitpage: false js_vars: null live_method: null name: Demo_Questions template: content: "\n{{ include_sibling 'uw_teton_survey.html' }} \n{{ include_sibling 'checkbox_list.html' }}\n\n
\n \ {% for field in form %}\n
\n \n {{ field }}\n

\n {% endfor %}\n
\n\n{{ next_button }}" javascript: "// This script is included to ensure that if tags are included in form fields they are observed\n$(document).ready(function (e) {\n labels = document.getElementsByTagName(\"label\");\n\n for (var i = 0; i < labels.length; i++) {\n labels[i].innerHTML = labels[i].innerHTML.replaceAll(\"<\", \"<\").\n replaceAll(\">\", \">\");\n }\n});" title: Questionnaire timeout_seconds: null timer_text: null vars_for_template: null - after_all_players_arrive: null body_text: null group_by_arrival_time: null is_displayed: null is_waitpage: true name: SurveyEndPage template: null title_text: null wait_for_all_groups: true - bots: '' constants: - datatype: int js_value: 2 name: PLAYERS_PER_GROUP - datatype: int js_value: 1 name: NUM_ROUNDS - datatype: int js_value: 5 name: BASE_PAY custom_export: "# Header\nyield [\n 'session_code',\n 'participant_id_in_session',\n \ 'participant_code',\n 'id_in_group',\n 'group_number',\n 'spender',\n \ 'payoff',\n 'show_up_fee',\n 'earnings',\n 'selected_round',\n 'winner_round_1',\n \ 'winner_round_2',\n 'group_winner',\n 'selected_item',\n 'auction_win_code'\n]\n\n# Rows\nfor p in players:\n pp = p.participant\n pg = p.group\n ps = p.session\n \ \n # Calculating the earnings\n payoff = p.participant.payoff\n fee = p.session.config['fee']\n # if fee is stored as a plain number, wrap it in Currency:\n fee_currency = c(fee) \n earnings = payoff + fee_currency\n \ \n # Pull participant fields\n spender = p.participant.vars.get('spender', '')\n selected_round = p.participant.vars.get('selected_round', '')\n winner_1 = p.participant.vars.get('winner_1', '')\n winner_2 = p.participant.vars.get('winner_2', '')\n spender_selected_item = p.participant.vars.get('spender_selected_item', '')\n random_code = p.participant.vars.get('random_code', '')\n \n yield [\n ps.code,\n pp.id_in_session,\n pp.code,\n p.id_in_group,\n \ pg.id_in_subsession,\n spender,\n payoff,\n fee_currency,\n \ earnings,\n selected_round,\n winner_1,\n winner_2,\n \ pg.winner,\n spender_selected_item,\n random_code\n ]" doc: Participants are told their earnings (cumulative for entire experiment) and debriefed. Shown amount to be paid and then dismissed. includable_templates: - content: "\n{% load otree %}\n\n\n\n" name: uw_teton_bg models: Group: fields: - datatype: IntegerField kwargs: blank: null choices: null initial: null label: null max: null min: null widget: null name: selected_round_price - datatype: IntegerField kwargs: blank: null choices: null initial: null label: null max: null min: null widget: null name: spender_WTP - datatype: IntegerField kwargs: blank: null choices: null initial: null label: null max: null min: null widget: null name: winner methods: - code: "import random\n\nplayers = group.get_players()\n\nfor p in players:\n \ payoff_round = p.participant.selected_round\n p.participant.random_code = random.randint(10000, 99999) # code used for verifying item payout\n\n# Assign payoff depending on selected round and add correct belief bonus\nif payoff_round == 1:\n for p in players:\n p.participant.final_earnings_without_fee = p.participant.earnings_1\n if p.participant.correct_belief == 1:\n \ p.participant.final_earnings_without_fee += session.config['belief_payout']\n \ p.payoff = p.participant.final_earnings_without_fee\nelse:\n for p in players:\n p.participant.final_earnings_without_fee = p.participant.earnings_2\n \ if p.participant.correct_belief == 1:\n p.participant.final_earnings_without_fee += session.config['belief_payout']\n p.payoff = p.participant.final_earnings_without_fee\n\n# Add in the participation fee, adjusted for rounding\nfor p in players:\n \ p.participant.final_earnings_with_fee = int(p.participant.final_earnings_without_fee + session.config[\"fee\"] + 0.5) # the \"int(x + 0.5)\" is used to round. Basically, there's some weird behavior with the round function due to \"banker's rounding\": if using round(), if the leading number is even, the number will round up, and if leading number is odd, the number will round down. This way will work no matter what, as int() always rounds down (so 2.3 -> 2.3 + 0.5 = 2.8, int(2.8) = 2, and 2.7 -> 2.7 + 0.5 = 3.2, int(3.3) = 3)" is_method: false name: payoff_calc_func - code: "import random\n\n# Select the round for payoff for the group\npayoff_round = random.randint(1,2)\n\nplayers = group.get_players()\n\nfor p in players:\n \ # Save the selected round to the participant field\n p.participant.selected_round = payoff_round\n # Conditional depending on which round was selected for payoff\n if payoff_round == 1:\n # Save the spender's WTP for the selected round in a group variable\n if p.participant.spender == 1:\n group.spender_WTP = int(p.participant.WTP_1)\n # Save the computer's price for the selected round in a group variable\n group.selected_round_price = p.participant.computer_price_1\n # If the participant is the spender AND won in the selected round\n if p.participant.spender == 1 and p.participant.winner_1 == 1:\n group.winner = 1\n else:\n \ group.winner = 0\n else: # i.e. if the selected round is round 2\n # Save the spender's WTP for the selected round in a group variable\n if p.participant.spender == 1:\n group.spender_WTP = int(p.participant.WTP_2)\n # Save the computer's price and spender's WTP for the selected round in a group variable\n group.selected_round_price = p.participant.computer_price_2\n # If the participant is the spender AND won in the selected round\n if p.participant.spender == 1 and p.participant.winner_2 == 1:\n group.winner = 1\n else:\n \ group.winner = 0" is_method: false name: select_payoff_round Player: fields: - datatype: FloatField kwargs: blank: null choices: null initial: null label: null max: null min: null widget: null name: exp_payment methods: [] Subsession: fields: [] methods: - code: "# pull the matrix you stored in the code‐entry app\nmatrix = subsession.session.vars.get('couple_matrix')\nif not matrix:\n # safety check in case someone forgot to run grouping first\n \ raise RuntimeError(\"No couple_matrix in session.vars\")\n# re‐apply it in this app's subsession\nsubsession.set_group_matrix(matrix)" is_method: false name: after_all_players_arrive name: Outro pages: - after_all_players_arrive: after_all_players_arrive body_text: null group_by_arrival_time: null is_displayed: null is_waitpage: true name: GroupingWaitPage template: null title_text: null wait_for_all_groups: true - after_all_players_arrive: select_payoff_round body_text: null group_by_arrival_time: null is_displayed: null is_waitpage: true name: SelectRoundWaitPage template: null title_text: null wait_for_all_groups: null - after_all_players_arrive: payoff_calc_func body_text: null group_by_arrival_time: null is_displayed: null is_waitpage: true name: PayoffCalcWaitPage template: null title_text: null wait_for_all_groups: null - app_after_this_page: null before_next_page: null error_message: null form_fields: null form_model: player get_form_fields: null get_timeout_seconds: null is_displayed: null is_waitpage: false js_vars: null live_method: null name: Dismissal template: content: "\n{{ include_sibling 'uw_teton_bg.html' }}\n\n\n

\n The randomly selected round that determined your earnings was: Round {{selected_round}}. \n

\n\n\n{{ if participant.spender == 1 }}\n

\n In Round {{selected_round}}, the computer's random price was ${{computer_price}}, and your bid was ${{spender_WTP}}.\n

\n \n {{ if selected_round == 1 and winner_1 == 1 or selected_round == 2 and winner_2 == 1}}\n

\n \ Since your bid was higher than the computer's price, you won the auction. You paid the computer's price of ${{computer_price}} for your item.\n \

\n \n {{ else }}\n

\n Since your bid was lower than the computer's price, you lost the auction. You did not purchase an item, and no funds were removed from the joint account.\n

\n {{ endif }}\n{{ endif }}\n\n\n\n

\n Your total earnings in the study {{ if participant.spender == 1 and group.winner == 1 }}(after removing your purchase){{ endif }} are ${{payoff}}. \n

\n\n{{ if participant.spender == 1 and selected_round == 1 and winner_1 == 1 or participant.spender == 1 and selected_round == 2 and winner_2 == 1 }} \n

\n Please write down the following code on your receipt so we can ask you for more information about shipping: {{participant.random_code}} \n

\n{{ endif }}\n\n

\n \ Thank you for participating!\n

" javascript: null title: Session Ended timeout_seconds: null timer_text: null vars_for_template: "# Define final variables for dismissal\nwinner_1 = int(participant.winner_1)\nwinner_2 = int(participant.winner_2)\nselected_round = int(participant.selected_round)\npayoff = int(participant.final_earnings_with_fee)\ncomputer_price = int(group.selected_round_price)\nspender_WTP = group.spender_WTP\n\n# Passing Python variables to the HTML template of the page\nreturn dict(selected_round = selected_round,\n payoff = payoff,\n \ computer_price = computer_price,\n spender_WTP = spender_WTP,\n \ winner_1 = winner_1,\n winner_2 = winner_2)" css: "body {\n overflow: scroll; /* Always show the scrollbars */\n}" mturk_settings: null other_settings: DEMO_PAGE_INTRO_HTML: '' LANGUAGE_CODE: en PARTICIPANT_FIELDS: - pref_str - partner_pref_str - selected_item - earner_round_1 - earner_round_2 - exit_1 - exit_2 - budget_1 - budget_2 - spender - earnings_1 - earnings_2 - selected_round - final_earnings_without_fee - final_earnings_with_fee - correct_belief - spender_selected_item - winner_1 - winner_2 - WTP_1 - WTP_2 - belief_match_count - expiry - computer_price_1 - computer_price_2 - selected_round_price - random_code - WTP_1_timeout - WTP_2_timeout - couple_code REAL_WORLD_CURRENCY_CODE: USD SESSION_FIELDS: [] USE_POINTS: false rooms: - display_name: BU26 name: BU26 participant_labels: - A1 - A2 - A3 - A4 - A5 - A6 - A7 - A8 - B1 - B2 - B3 - B4 - B5 - B6 - B7 - B8 - C1 - C2 - C3 - C4 - C5 - C6 - C7 - C8 - D1 - D2 - D3 - D4 - D5 - D6 - D7 - D8 - E1 - E2 - E3 - E4 - E5 - E6 - E7 - E8 use_secure_urls: false session_config_defaults: participation_fee: 15 real_world_currency_per_point: 1 session_configs: - app_sequence: - Intro - PrefRating - RET_instructions - RET_practice - RET_1 - Auction_instructions - Auction_1 - RET_2 - Auction_2 - PainofPaying - Survey - Outro custom_entries: - datatype: int js_value: 15 name: fee - datatype: int js_value: 1 name: belief_payout - datatype: str js_value: 30 minutes name: exp_time - datatype: int js_value: 5 name: match_requirement - datatype: int js_value: 5 name: time_limit - datatype: int js_value: 5 name: task_min - datatype: int js_value: 5 name: num_correct - datatype: int js_value: 20 name: num_rounds - datatype: int js_value: 4 name: x_rate - datatype: int js_value: 5 name: m_size - datatype: bool js_value: false name: group_by_arrival_time name: SMEBSE_partners num_demo_participants: null - app_sequence: - RET_practice custom_entries: - datatype: int js_value: 15 name: fee - datatype: int js_value: 1 name: belief_payout - datatype: str js_value: 30 minutes name: exp_time - datatype: int js_value: 5 name: match_requirement - datatype: int js_value: 5 name: time_limit - datatype: int js_value: 5 name: task_min - datatype: int js_value: 5 name: num_correct - datatype: int js_value: 20 name: num_rounds - datatype: int js_value: 4 name: x_rate - datatype: int js_value: 5 name: m_size - datatype: bool js_value: false name: group_by_arrival_time name: testing num_demo_participants: null shared_out: ''