Scheduled service maintenance on November 22


On Friday, November 22, 2024, between 06:00 CET and 18:00 CET, GIN services will undergo planned maintenance. Extended service interruptions should be expected. We will try to keep downtimes to a minimum, but recommend that users avoid critical tasks, large data uploads, or DOI requests during this time.

We apologize for any inconvenience.

settings_eyetracking_test.m 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437
  1. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  2. %% Checking keyboard, screens
  3. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  4. % Response keys (optional; for no subject response use empty list)
  5. responseKeys = {'UpArrow','RightArrow','LeftArrow','space'};
  6. % Background color: cho ose a number from 0 (black) to 255 (white)
  7. % Text color: choose a number from 0 (black) to 255 (white)
  8. textColor = 200;
  9. % % Screen setup
  10. % clear screen
  11. %
  12. % if SkipSyncTests
  13. % Screen('Preference', 'SkipSyncTests', 1) %%% IMPORTANT!! REMOVE THIS LINE WHEN RUNNING THE TASK
  14. % end
  15. %
  16. % whichScreen = max(Screen('Screens'));
  17. %
  18. % [window1, rect] = Screen('Openwindow',whichScreen,backgroundColor,[],[],2);
  19. %
  20. % slack = Screen('GetFlipInterval', window1)/2;
  21. %
  22. % W=rect(RectRight); % screen width
  23. % H=rect(RectBottom); % screen height
  24. %
  25. % % Get the centre coordinate of the window
  26. % [xCenter, yCenter] = RectCenter(rect);
  27. %
  28. % Screen(window1,'FillRect',backgroundColor);
  29. % HideCursor(window1);
  30. % Screen('Flip', window1);
  31. % Keyboard setup
  32. KbName('UnifyKeyNames');
  33. if lab
  34. KbCheckList = [KbName('space'),KbName('ESCAPE'),KbName('Q'),KbName('Control')];
  35. keytoaccepabs='Control';
  36. else
  37. KbCheckList = [KbName('space'),KbName('ESCAPE'),KbName('Q'),KbName('RightShift')];
  38. keytoaccepabs='RightShift';
  39. end
  40. for i = 1:length(responseKeys)
  41. KbCheckList = [KbName(responseKeys{i}),KbCheckList];
  42. end
  43. RestrictKeysForKbCheck(KbCheckList);
  44. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  45. %% Set up TIMING
  46. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  47. % Fix cross + JITTER (0 to 500ms)
  48. fixationDuration = 1; %PLUS JITTER!! (0 to 500ms)
  49. % Object 1 presented
  50. objectTimeout = 2; %timeout of the object
  51. postobjectTimeout1 =0.5; %gap between object1 time out and next fix cross
  52. % Fix cross
  53. fixationDuration = 1;
  54. % Object 2 presented
  55. objectTimeout = 2; %timeout of the object
  56. postobjectTimeout2 =0.5; %gap between object2 time out and next event (retro cue)
  57. % Fix cross
  58. % Audio item cue (350ms)
  59. % Not in Memoreye % audiogap=0.2% gap between audio cues (seconds) - Not in Memoreye
  60. %Pins and timing
  61. npings=3; % total number of pings
  62. nodd=1; % number of odd pings
  63. delth=3500; % delay period length (ms)
  64. pilth=100; % ping duration (ms)
  65. minipi=600; % minimum inter-ping-interval
  66. maxsend=1000; %max pause (ms) before first/last ping
  67. minstart = 300 %minimum start time
  68. % Memory tasks 1 (here only concrete task)
  69. % (i) Abtract task
  70. abstractTimeout = 10;%Timeout to respond in the abstract task (in seconds)
  71. fbrespabs = 0.2; %Abstract task. How long we show the rotation selected before show feedback (in seconds) -avoiding trigger of response and fb too close
  72. fbtimeoutabs = 0.5; %Abstract task. How long we show the feedback screen (in seconds)
  73. % (ii) Concrete task
  74. concreteTimeout = 2.5;%Timeout to respond in the concrete task (in seconds)
  75. fbrespcon = 0.2; %Concrete task. How long we show the rotation selected (visual feedback to key pressed) (in seconds)
  76. fbtimeoutcon = 0.3; %Concrete task. How long we show the feedback screen (in seconds)
  77. fbaudiogap = 0.5; %After receiving FB leaving a gab before the next audio message
  78. % Fix cross
  79. % Audio item cue (300ms) / Or thank you sound ( 300ms if the uncued item is not
  80. % tested)
  81. % If the uncued item is also tested
  82. % 2nd Delay period
  83. npings_2=2; % total number of pings
  84. nodd_2=1; % number of odd pings
  85. delth_2=2500; % delay period length (ms) - Keeping in mind the fb-audio gap and the audio
  86. pilth_2=100; % ping duration (ms)
  87. minipi_2=600; % minimum inter-ping-interval
  88. maxsend_2=1000; %max pause (ms) before first/last ping
  89. minstart_2 = 300 %minimum start time
  90. % Same timing as in (ii) Concrete task
  91. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  92. %% Creating a sequence of trials for the task
  93. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  94. % "sequence" is a matrix where each row is a trial and each column:
  95. % Column 1 = Object 1
  96. % Column 2 = Object 2
  97. % Column 3 = Rotation Object 1
  98. % Column 4 = Rotarion Object 2
  99. % Column 5 = Target: 1 or 2
  100. % Column 6 = Target Object (id)
  101. % Column 7 = Type of task (1= concrete/perceptual; 2=continuous/abstract)
  102. % Column 8 = Object memory test
  103. % Column 9 = Rotation Object memory test
  104. % Column 10 = Block number
  105. % Column 11 = Rotation target
  106. % Column 12 = Testing uncued (True / False)
  107. % Column 13 = Object memory test 2
  108. % Column 14 = Rotation Object memory test 2
  109. % Column 15 = Rotation UNCUED
  110. % Inputs
  111. nc=3% Number of cue objects
  112. % nat=9% Number of objects for the abstract task
  113. npr=16% Number of positions/possible rotations
  114. contestdif=3.5; % Difficulty of perceptual task. The memory test object will be presented +-(distrot/contestdif) from original position
  115. nblocks = 16;
  116. if new_participant == 1
  117. [sequence_real distrot]=create_sequence_210311_BSJL(nc, npr, contestdif,nblocks);
  118. nblocks; %number of blocks
  119. name_sti = strcat('sequences/m_sequence_',subID,'.mat');
  120. name_val = strcat('sequences/other_info_',subID,'.mat');
  121. save(name_sti,'sequence_real');
  122. save(name_val,'distrot','nblocks','setofobjects');
  123. [sequence_pract distrot]=create_sequence_210311_BSJL(nc, npr, contestdif,nblocks);
  124. poi1=sequence_pract(:,12)==0&sequence_pract(:,10)==1; %Preparing a sequence for practice (only cue)
  125. sequencepract1=sequence_pract(poi1,:);
  126. sequencepract1=sequencepract1(1:8,:);% only 8 trials
  127. poi2=sequence_pract(:,12)==1&sequence_pract(:,10)==1; %Preparing a sequence for practice (only trials where we also ask for the uncued)
  128. sequencepract2=sequence_pract(poi2,:);
  129. sequencepract2=sequencepract2(1:8,:);% only 8 trials
  130. poi3=sequence_pract(:,10)==2; %Preparing a sequence for practice (mixed)
  131. sequencepract3=sequence_pract(poi3,:);
  132. sequencepract3=sequencepract3(1:8,:);% only 8 trials
  133. elseif new_participant == 0
  134. name_sti_load = strcat('sequences/m_sequence_',subID,'.mat');
  135. name_val_load = strcat('sequences/other_info_',subID,'.mat');
  136. load(name_sti_load);
  137. load(name_val_load);
  138. end
  139. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  140. %% Set up stimuli lists
  141. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  142. % First, selecting one of 4 different subsets
  143. % in setst, 1= object used for as cue; 0= object used only in abstract
  144. % test
  145. %IMPORTANT TO CHANGES THIS FOR 3 TARGETS
  146. setst = [0 0 0 1 0 0 0 0 0 0 1 1 ;...
  147. 1 0 0 0 0 1 0 1 0 0 0 0 ;...
  148. 0 0 1 0 1 0 0 0 1 0 0 0 ];
  149. subset= setofobjects;
  150. subsetfff= setst(subset,:);
  151. delete stimuli/all_pics/.DS_Store
  152. delete stimuli/target/*.*
  153. delete stimuli/abstract_test/*.*
  154. list_a=dir('stimuli/all_pics/*.jpg');
  155. list_a=struct2cell(list_a);
  156. orifolder='stimuli/all_pics'
  157. for f= 1:length(subsetfff);
  158. objname=list_a{1,f};
  159. ffolder=strcat(orifolder,'/',objname);
  160. if subsetfff(f)==1
  161. copyfile(ffolder, 'stimuli/target');
  162. else
  163. copyfile(ffolder, 'stimuli/abstract_test');
  164. end
  165. end
  166. % Get the image files for the experiment:
  167. imageFolder = 'stimuli/target';
  168. imgList = dir(fullfile(imageFolder,['*.' 'jpg']));
  169. imgList = {imgList(:).name};
  170. % Get the image files for the experiment (test in the abstract condition):
  171. imageFolder_test = 'stimuli/abstract_test';
  172. imgList_test = dir(fullfile(imageFolder_test,['*.' 'jpg']));
  173. imgList_test = {imgList_test(:).name};
  174. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  175. %% Audio files and Audio Setting
  176. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  177. [audcue1(:,1),Fs] = audioread('sound_demo/Cue_one_JH.wav');
  178. [audcue1(:,2),Fs] = audioread('sound_demo/Cue_one_JH.wav');
  179. [audcue2(:,1),Fs] = audioread('sound_demo/Cue_two_JH.wav');
  180. [audcue2(:,2),Fs] = audioread('sound_demo/Cue_two_JH.wav');
  181. %
  182. % audcue1=audcue1(1:size(audcue1,1)/2,:); %Cutting these long audio files
  183. % audcue2=audcue2(1:size(audcue2,1)/2,:);
  184. audcue{1}=audcue1;
  185. audcue{2}=audcue2;
  186. [aud1,Fs] = audioread('sound_demo/camera300.wav');
  187. [aud2,Fs] = audioread('sound_demo/magic300.wav');
  188. audtaskcue{1}=aud1;
  189. audtaskcue{2}=aud2;
  190. [audtest,Fs] = audioread('sound_demo/test.wav');
  191. [aud1th(:,1),Fs] = audioread('sound_demo/Cue_thanks_JH.wav');
  192. [aud1th(:,2),Fs] = audioread('sound_demo/Cue_thanks_JH.wav'); %fake stereo
  193. audthanks{1}=aud1th;
  194. % Audio
  195. InitializePsychSound;
  196. devices = PsychPortAudio('GetDevices',[]);
  197. if lab
  198. DEVICE_NUMBER=[14]; % when running in the lap
  199. else
  200. DEVICE_NUMBER=[];% when running on laptop
  201. end
  202. % Options
  203. repetitions = 1;
  204. startCue = 0;
  205. pahandle = PsychPortAudio('Open', DEVICE_NUMBER, 1, 1, Fs, 2);
  206. %
  207. % 'reqlatencyclass' Allows to select how aggressive PsychPortAudio should be about
  208. % minimizing sound latency and getting good deterministic timing, i.e. how to
  209. % trade off latency vs. system load and playing nicely with other sound
  210. % applications on the system. Level 0 means: Don't care about latency or timing
  211. % precision. This mode works always and with all settings, plays nicely with other
  212. % sound applications. Level 1 (the default) means: Try to get the lowest latency
  213. % that is possible under the constraint of reliable playback, freedom of choice
  214. % for all parameters and interoperability with other applications. Level 2 means:
  215. % Take full control over the audio device, even if this causes other sound
  216. % applications to fail or shutdown. Level 3 means: As level 2, but request the
  217. % most aggressive settings for the given device. Level 4: Same as 3, but fail if
  218. % device can't meet the strictest requirements.
  219. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  220. %% Set up other keyboard inputs parameter
  221. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  222. %Abstract task
  223. if lab
  224. rotSensi=0.03%360/(npr*4);% Sensibility to rotate the images with the keyboard (abstract)
  225. keypul=0.05 % Minimum delay between key pulse (seconds) to start accelerating the speed of rotation
  226. keyacce=0.2 % Acceleration increase
  227. else
  228. rotSensi=0.03%360/(npr*4);% Sensibility to rotate the images with the keyboard (abstract)
  229. keypul=0.05 % Minimum delay between key pulse (seconds) to start accelerating the speed of rotation
  230. keyacce=1.6 % Acceleration increase
  231. end
  232. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  233. %% Set up PINGS
  234. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  235. % Make a base Rect
  236. redup = 0.42;% to reduce the diameter of pings
  237. baseRect1 = [0 0 W/2 W/2].*redup;
  238. baseRect2 = [0 0 W/2.5 W/2.5].*redup;
  239. baseRect3 = [0 0 W/3.5 W/3.5].*redup;
  240. baseRect4 = [0 0 W/6 W/6].*redup;
  241. baseRect5 = [0 0 W/15 W/15].*redup;
  242. % For Ovals we set a miximum diameter up to which it is perfect for
  243. maxDiameter1 = (max(baseRect1) * 1.01);
  244. maxDiameter2 = (max(baseRect2) * 1.01);
  245. maxDiameter3 = (max(baseRect3) * 1.01);
  246. maxDiameter4 = (max(baseRect4) * 1.01);
  247. maxDiameter5 = (max(baseRect5) * 1.01);
  248. % Center the rectangle on the centre of the screen
  249. centeredRect1 = CenterRectOnPointd(baseRect1, xCenter, yCenter);
  250. centeredRect2 = CenterRectOnPointd(baseRect2, xCenter, yCenter);
  251. centeredRect3 = CenterRectOnPointd(baseRect3, xCenter, yCenter);
  252. centeredRect4 = CenterRectOnPointd(baseRect4, xCenter, yCenter);
  253. centeredRect5 = CenterRectOnPointd(baseRect5, xCenter, yCenter);
  254. if pingcolorset==1
  255. AcP = [250 0 0]; %Red Odd
  256. BcP = [245 245 245]; %White Odd
  257. CcP = [90 90 90];%Grey Normal
  258. DcP = [255 255 255];%White Normal
  259. elseif pingcolorset==2
  260. AcP = [90 90 90];%Grey Odd
  261. BcP = [255 255 255];%White Odd
  262. CcP = [250 0 0]; %Red Normal
  263. DcP = [255 255 255]; %White Normal
  264. elseif pingcolorset==3
  265. AcP = [0 250 0]; %Green Odd
  266. BcP = [255 255 255]; %White Odd
  267. CcP = [90 90 90];%Grey Normal
  268. DcP = [255 255 255];%White Normal
  269. elseif pingcolorset==4
  270. AcP = [90 90 90];%Grey Odd
  271. BcP = [255 255 255];%White Odd
  272. CcP = [0 250 0]; %Green Normal
  273. DcP = [255 255 255]; %White Normal
  274. elseif pingcolorset==5
  275. AcP = [200 200 0]; %Yellow Odd
  276. BcP = [255 255 255]; %White Odd
  277. CcP = [90 90 90];%Grey Normal
  278. DcP = [255 255 255];%White Normal
  279. elseif pingcolorset==6
  280. AcP = [90 90 90];%Grey Odd
  281. BcP = [255 255 255];%White Odd
  282. CcP = [200 200 0]; %Yellow Normal
  283. DcP = [255 255 255]; %White Normal
  284. end
  285. % Set the color for obbball pings
  286. rectColor_odd{1} = AcP;
  287. rectColor_odd{2} = BcP;
  288. rectColor_odd{3} = AcP;
  289. rectColor_odd{4} = BcP;
  290. rectColor_odd{5} = AcP;
  291. % Set the color for pings
  292. rectColor{1} = CcP;
  293. rectColor{2} = DcP;
  294. rectColor{3} = CcP;
  295. rectColor{4} = DcP;
  296. rectColor{5} = CcP;
  297. %% Setting the pixel deviation from the center to show fixation cross in different position
  298. % Important info regarding our setup (data recorded during spring 2021)
  299. % The size of our screen in mm is 600x340. The distance between the screen and participants' eyes is around 620mm. So, using a 2K resolution (2560x1440px), a pixel is equal to 0.0217 visual degrees.
  300. vdperpixel=0.0217;
  301. pp=visdegdis/vdperpixel;
  302. % these are the 8 different values that we can add to the center to show the fix cross (both
  303. % w and h dimensions); third column is just a value to send a trigger
  304. fixcrosdev=[0 -pp 1;...
  305. 0 pp 2;...
  306. pp -pp 3;...
  307. pp 0 4;...
  308. pp pp 5;...
  309. -pp -pp 6;
  310. -pp 0 7;...
  311. -pp pp 8;
  312. 0 0 9];
  313. %%
  314. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  315. %% Set up results file
  316. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  317. % Set up the output file (this output is for info related with the
  318. % presention of room-object association and word tasks)
  319. %
  320. % subID='1';
  321. % gender='xxx';
  322. % age=99;
  323. if pingsareon %if we are using ping we will have a more detailed output file
  324. resultsFolder = 'outputfiles';
  325. outputfile = fopen([resultsFolder '/resultfile_' num2str(subID) '.txt'],'a');
  326. fprintf(outputfile, 'task_version\t date\t subID\t sub_gender\t sub_age\t block_number\t trial\t object_1_name\t object_1_id\t object_1_rot\t object_2_name\t object_2_id\t object_2_rot\t retro_cue\t object_cued_id\t object_cued_rot\t retro_cue_uncued\t object_uncued_id\t object_uncue_rot\t type_of_task\t total_of_pings_1\t position_odd_pings_1\t total_of_pings_2\t position_odd_pings_2\t pings_on_off\t object_test_name_cued\t object_test_id_cued\t object_test_rot_cued\t object_test_name_uncued\t object_test_id_uncued\t object_test_rot_uncued\t rt_resp_concrete_cued\t acc_trial_concrete_cued\t final_rot_concrete_cued\t rt_resp_concrete_uncued\t acc_trial_concrete_uncued\t final_rot_concrete_uncued\t testing_uncued\t onset_object_1\t onset_object_2\t onset_retrocue\t onset_taskcue\t onset_test_cued\t onset_response_cued\t onset_feedback_cued\t onset_retrocue_2_or_thanks\t onset_test_uncued\t onset_response_uncued\t onset_feedback_uncued\t onset_thanks_uncued\t onset_ping_1_delay_1\t onset_ping_2_delay_1\t onset_ping_3_delay_1\t onset_ping_4_delay_1\t onset_ping_5_delay_1\t onset_ping_1_delay_2\t onset_ping_2_delay_2\t onset_ping_3_delay_2\t onset_ping_4_delay_2\t onset_ping_5_delay_2\t trigger_object_1\t trigger_object_2\t trigger_retrocue_1\t trigger_taskcue\t trigger_object_concrete\t trigger_object_abstract\t colorset_pins\t practice\t righthanded\t ping_null_1\t ping_null_2\t ping_null_3\t ping_null_4\t ping_null_2_1\t ping_null_2_2\t ping_null_2_3\t ping_null_2_4\t object_null_1\t object_null_2\t block_repe_null\t threshold_fix\n');
  327. else
  328. resultsFolder = 'outputfiles';
  329. outputfile = fopen([resultsFolder '/resultfile_eyetest_' num2str(subID) '.txt'],'a');
  330. fprintf(outputfile, 'task_version\t date\t subID\t sub_gender\t sub_age\t block_number\t trial\t object_1_name\t object_1_id\t object_1_rot\t object_2_name\t object_2_id\t object_2_rot\t retro_cue\t object_cued_id\t object_cued_rot\t retro_cue_uncued\t object_uncued_id\t object_uncue_rot\t type_of_task\t pings_on_off\t object_test_name_cued\t object_test_id_cued\t object_test_rot_cued\t object_test_name_uncued\t object_test_id_uncued\t object_test_rot_uncued\t rt_resp_concrete_cued\t acc_trial_concrete_cued\t final_rot_concrete_cued\t rt_resp_concrete_uncued\t acc_trial_concrete_uncued\t final_rot_concrete_uncued\t testing_uncued\t onset_object_1\t onset_object_2\t onset_retrocue\t onset_taskcue\t onset_test_cued\t onset_response_cued\t onset_feedback_cued\t onset_retrocue_2_or_thanks\t onset_test_uncued\t onset_response_uncued\t onset_feedback_uncued\t onset_thanks_uncued\t trigger_object_1\t trigger_object_2\t trigger_retrocue_1\t trigger_taskcue\t trigger_object_concrete\t trigger_object_abstract\t practice\t righthanded\t delay_1_null\t delay_2_null\t object_null_1\t object_null_2\t block_repe_null\t cue_fix_dev_1\t cue_fix_dev_2\t cue_fix_dev_3\t cue_fix_dev_4\t cue_fix_dev_5\t cue_fix_dev_6\t cue_fix_dev_7\t cue_fix_dev_8\t cue_fix_dev_9\t fix_dev_vd_distance threshold_fix\n');
  331. end