Hide keyboard shortcuts

Hot-keys on this page

r m x p   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

1#!/usr/bin/env python 

2 

3""" 

4camcops_server/tasks/ceca.py 

5 

6=============================================================================== 

7 

8 Copyright (C) 2012-2020 Rudolf Cardinal (rudolf@pobox.com). 

9 

10 This file is part of CamCOPS. 

11 

12 CamCOPS is free software: you can redistribute it and/or modify 

13 it under the terms of the GNU General Public License as published by 

14 the Free Software Foundation, either version 3 of the License, or 

15 (at your option) any later version. 

16 

17 CamCOPS is distributed in the hope that it will be useful, 

18 but WITHOUT ANY WARRANTY; without even the implied warranty of 

19 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 

20 GNU General Public License for more details. 

21 

22 You should have received a copy of the GNU General Public License 

23 along with CamCOPS. If not, see <https://www.gnu.org/licenses/>. 

24 

25=============================================================================== 

26 

27""" 

28 

29from typing import Any, Dict, List, Optional 

30 

31import cardinal_pythonlib.rnc_web as ws 

32from sqlalchemy.sql.schema import Column 

33from sqlalchemy.sql.sqltypes import Boolean, Float, Integer, UnicodeText 

34 

35from camcops_server.cc_modules.cc_constants import CssClass 

36from camcops_server.cc_modules.cc_html import ( 

37 answer, 

38 get_yes_no, 

39 get_yes_no_none, 

40 subheading_spanning_two_columns, 

41 tr, 

42 tr_qa, 

43) 

44from camcops_server.cc_modules.cc_request import CamcopsRequest 

45from camcops_server.cc_modules.cc_sqla_coltypes import ( 

46 BIT_CHECKER, 

47 CamcopsColumn, 

48 MIN_ZERO_CHECKER, 

49 ONE_TO_FOUR_CHECKER, 

50 ONE_TO_FIVE_CHECKER, 

51 PermittedValueChecker, 

52 ZERO_TO_TWO_CHECKER, 

53 ZERO_TO_THREE_CHECKER, 

54 ZERO_TO_FOUR_CHECKER, 

55 ZERO_TO_FIVE_CHECKER 

56) 

57from camcops_server.cc_modules.cc_summaryelement import SummaryElement 

58from camcops_server.cc_modules.cc_task import ( 

59 get_from_dict, 

60 Task, 

61 TaskHasPatientMixin, 

62) 

63 

64 

65# ============================================================================= 

66# CECA-Q3 

67# ============================================================================= 

68 

69FREQUENCY_COMMENT = "Frequency (0 never - 3 often)" 

70 

71 

72class CecaQ3(TaskHasPatientMixin, Task): 

73 """ 

74 Server implementation of the CECA-Q3 task. 

75 """ 

76 __tablename__ = "cecaq3" 

77 shortname = "CECA-Q3" 

78 

79 # ------------------------------------------------------------------------- 

80 # Section 1(A) 

81 # ------------------------------------------------------------------------- 

82 s1a_motherfigure_birthmother = CamcopsColumn( 

83 "s1a_motherfigure_birthmother", Boolean, 

84 permitted_value_checker=BIT_CHECKER, 

85 comment="Raised by, maternal, birth mother?" 

86 ) 

87 s1a_motherfigure_stepmother = CamcopsColumn( 

88 "s1a_motherfigure_stepmother", Boolean, 

89 permitted_value_checker=BIT_CHECKER, 

90 comment="Raised by, maternal, stepmother?" 

91 ) 

92 s1a_motherfigure_femalerelative = CamcopsColumn( 

93 "s1a_motherfigure_femalerelative", Boolean, 

94 permitted_value_checker=BIT_CHECKER, 

95 comment="Raised by, maternal, female relative?" 

96 ) 

97 s1a_motherfigure_femalerelative_detail = Column( 

98 "s1a_motherfigure_femalerelative_detail", UnicodeText, 

99 comment="Raised by, maternal, female relative, detail" 

100 ) 

101 s1a_motherfigure_familyfriend = CamcopsColumn( 

102 "s1a_motherfigure_familyfriend", Boolean, 

103 permitted_value_checker=BIT_CHECKER, 

104 comment="Raised by, maternal, family friend?" 

105 ) 

106 s1a_motherfigure_fostermother = CamcopsColumn( 

107 "s1a_motherfigure_fostermother", Boolean, 

108 permitted_value_checker=BIT_CHECKER, 

109 comment="Raised by, maternal, foster mother?" 

110 ) 

111 s1a_motherfigure_adoptivemother = CamcopsColumn( 

112 "s1a_motherfigure_adoptivemother", Boolean, 

113 permitted_value_checker=BIT_CHECKER, 

114 comment="Raised by, maternal, adoptive mother?" 

115 ) 

116 s1a_motherfigure_other = CamcopsColumn( 

117 "s1a_motherfigure_other", Boolean, 

118 permitted_value_checker=BIT_CHECKER, 

119 comment="Raised by, maternal, other?" 

120 ) 

121 s1a_motherfigure_other_detail = Column( 

122 "s1a_motherfigure_other_detail", UnicodeText, 

123 comment="Raised by, maternal, other, detail" 

124 ) 

125 s1a_fatherfigure_birthfather = CamcopsColumn( 

126 "s1a_fatherfigure_birthfather", Boolean, 

127 permitted_value_checker=BIT_CHECKER, 

128 comment="Raised by, paternal, birth father?" 

129 ) 

130 s1a_fatherfigure_stepfather = CamcopsColumn( 

131 "s1a_fatherfigure_stepfather", Boolean, 

132 permitted_value_checker=BIT_CHECKER, 

133 comment="Raised by, paternal, stepfather?" 

134 ) 

135 s1a_fatherfigure_malerelative = CamcopsColumn( 

136 "s1a_fatherfigure_malerelative", Boolean, 

137 permitted_value_checker=BIT_CHECKER, 

138 comment="Raised by, paternal, male relative?" 

139 ) 

140 s1a_fatherfigure_malerelative_detail = Column( 

141 "s1a_fatherfigure_malerelative_detail", UnicodeText, 

142 comment="Raised by, paternal, male relative, detail" 

143 ) 

144 s1a_fatherfigure_familyfriend = CamcopsColumn( 

145 "s1a_fatherfigure_familyfriend", Boolean, 

146 permitted_value_checker=BIT_CHECKER, 

147 comment="Raised by, paternal, family friend?" 

148 ) 

149 s1a_fatherfigure_fosterfather = CamcopsColumn( 

150 "s1a_fatherfigure_fosterfather", Boolean, 

151 permitted_value_checker=BIT_CHECKER, 

152 comment="Raised by, paternal, foster father?" 

153 ) 

154 s1a_fatherfigure_adoptivefather = CamcopsColumn( 

155 "s1a_fatherfigure_adoptivefather", Boolean, 

156 permitted_value_checker=BIT_CHECKER, 

157 comment="Raised by, paternal, adoptive father?" 

158 ) 

159 s1a_fatherfigure_other = CamcopsColumn( 

160 "s1a_fatherfigure_other", Boolean, 

161 permitted_value_checker=BIT_CHECKER, 

162 comment="Raised by, paternal, other?" 

163 ) 

164 s1a_fatherfigure_other_detail = Column( 

165 "s1a_fatherfigure_other_detail", UnicodeText, 

166 comment="Raised by, paternal, other, detail" 

167 ) 

168 

169 # ------------------------------------------------------------------------- 

170 # Section 1(B) 

171 # ------------------------------------------------------------------------- 

172 s1b_institution = CamcopsColumn( 

173 "s1b_institution", Boolean, 

174 permitted_value_checker=BIT_CHECKER, 

175 comment="In institution before 17?" 

176 ) 

177 s1b_institution_time_years = CamcopsColumn( 

178 "s1b_institution_time_years", Float, 

179 permitted_value_checker=MIN_ZERO_CHECKER, 

180 comment="In institution, time (years)" 

181 ) 

182 

183 # ------------------------------------------------------------------------- 

184 # Section 1(C) 

185 # ------------------------------------------------------------------------- 

186 s1c_mother_died = CamcopsColumn( 

187 "s1c_mother_died", Boolean, 

188 permitted_value_checker=BIT_CHECKER, 

189 comment="Mother died before 17?" 

190 ) 

191 s1c_father_died = CamcopsColumn( 

192 "s1c_father_died", Boolean, 

193 permitted_value_checker=BIT_CHECKER, 

194 comment="Father died before 17?" 

195 ) 

196 s1c_mother_died_subject_aged = CamcopsColumn( 

197 "s1c_mother_died_subject_aged", Float, 

198 permitted_value_checker=MIN_ZERO_CHECKER, 

199 comment="Age when mother died (years)" 

200 ) 

201 s1c_father_died_subject_aged = CamcopsColumn( 

202 "s1c_father_died_subject_aged", Float, 

203 permitted_value_checker=MIN_ZERO_CHECKER, 

204 comment="Age when father died (years)" 

205 ) 

206 s1c_separated_from_mother = CamcopsColumn( 

207 "s1c_separated_from_mother", Boolean, 

208 permitted_value_checker=BIT_CHECKER, 

209 comment="Separated from mother for >=1y before 17?" 

210 ) 

211 s1c_separated_from_father = CamcopsColumn( 

212 "s1c_separated_from_father", Boolean, 

213 permitted_value_checker=BIT_CHECKER, 

214 comment="Separated from father for >=1y before 17?" 

215 ) 

216 s1c_first_separated_from_mother_aged = CamcopsColumn( 

217 "s1c_first_separated_from_mother_aged", Float, 

218 permitted_value_checker=MIN_ZERO_CHECKER, 

219 comment="Maternal separation, age (years)" 

220 ) 

221 s1c_first_separated_from_father_aged = CamcopsColumn( 

222 "s1c_first_separated_from_father_aged", Float, 

223 permitted_value_checker=MIN_ZERO_CHECKER, 

224 comment="Paternal separation, age (years)" 

225 ) 

226 s1c_mother_how_long_first_separation_years = CamcopsColumn( 

227 "s1c_mother_how_long_first_separation_years", Float, 

228 permitted_value_checker=MIN_ZERO_CHECKER, 

229 comment="Maternal separation, how long first separation (y)" 

230 ) 

231 s1c_father_how_long_first_separation_years = CamcopsColumn( 

232 "s1c_father_how_long_first_separation_years", Float, 

233 permitted_value_checker=MIN_ZERO_CHECKER, 

234 comment="Paternal separation, how long first separation (y)" 

235 ) 

236 s1c_mother_separation_reason = CamcopsColumn( 

237 "s1c_mother_separation_reason", Integer, 

238 permitted_value_checker=PermittedValueChecker(minimum=1, maximum=6), 

239 comment="Maternal separation, reason " 

240 "(1 illness, 2 work, 3 divorce/separation, 4 never knew, " 

241 "5 abandoned, 6 other)" 

242 ) 

243 s1c_father_separation_reason = CamcopsColumn( 

244 "s1c_father_separation_reason", Integer, 

245 permitted_value_checker=PermittedValueChecker(minimum=1, maximum=6), 

246 comment="Paternal separation, reason " 

247 "(1 illness, 2 work, 3 divorce/separation, 4 never knew, " 

248 "5 abandoned, 6 other)" 

249 ) 

250 s1c_describe_experience = Column( 

251 "s1c_describe_experience", UnicodeText, 

252 comment="Loss of/separation from parent, description" 

253 ) 

254 

255 # ------------------------------------------------------------------------- 

256 # Section 2(A) 

257 # ------------------------------------------------------------------------- 

258 s2a_which_mother_figure = CamcopsColumn( 

259 "s2a_which_mother_figure", Integer, 

260 permitted_value_checker=PermittedValueChecker(minimum=0, maximum=5), 

261 comment="Mother figure, which one (0 none/skip, 1 birth mother, " 

262 "2 stepmother, 3 other relative, 4 other non-relative, " 

263 "5 other)" 

264 ) 

265 s2a_which_mother_figure_other_detail = Column( 

266 "s2a_which_mother_figure_other_detail", UnicodeText, 

267 comment="Mother figure, other, detail" 

268 ) 

269 s2a_q1 = CamcopsColumn( 

270 "s2a_q1", Integer, 

271 permitted_value_checker=ONE_TO_FIVE_CHECKER, 

272 comment="Mother figure, difficult to please (1 no - 5 yes)" 

273 ) 

274 s2a_q2 = CamcopsColumn( 

275 "s2a_q2", Integer, 

276 permitted_value_checker=ONE_TO_FIVE_CHECKER, 

277 comment="Mother figure, concerned re my worries (1 no - 5 yes)" 

278 ) 

279 s2a_q3 = CamcopsColumn( 

280 "s2a_q3", Integer, 

281 permitted_value_checker=ONE_TO_FIVE_CHECKER, 

282 comment="Mother figure, interested re school (1 no - 5 yes)" 

283 ) 

284 s2a_q4 = CamcopsColumn( 

285 "s2a_q4", Integer, 

286 permitted_value_checker=ONE_TO_FIVE_CHECKER, 

287 comment="Mother figure, made me feel unwanted (1 no - 5 yes)" 

288 ) 

289 s2a_q5 = CamcopsColumn( 

290 "s2a_q5", Integer, 

291 permitted_value_checker=ONE_TO_FIVE_CHECKER, 

292 comment="Mother figure, better when upset (1 no - 5 yes)" 

293 ) 

294 s2a_q6 = CamcopsColumn( 

295 "s2a_q6", Integer, 

296 permitted_value_checker=ONE_TO_FIVE_CHECKER, 

297 comment="Mother figure, critical (1 no - 5 yes)" 

298 ) 

299 s2a_q7 = CamcopsColumn( 

300 "s2a_q7", Integer, 

301 permitted_value_checker=ONE_TO_FIVE_CHECKER, 

302 comment="Mother figure, unsupervised <10y (1 no - 5 yes)" 

303 ) 

304 s2a_q8 = CamcopsColumn( 

305 "s2a_q8", Integer, 

306 permitted_value_checker=ONE_TO_FIVE_CHECKER, 

307 comment="Mother figure, time to talk (1 no - 5 yes)" 

308 ) 

309 s2a_q9 = CamcopsColumn( 

310 "s2a_q9", Integer, 

311 permitted_value_checker=ONE_TO_FIVE_CHECKER, 

312 comment="Mother figure, nuisance (1 no - 5 yes)" 

313 ) 

314 s2a_q10 = CamcopsColumn( 

315 "s2a_q10", Integer, 

316 permitted_value_checker=ONE_TO_FIVE_CHECKER, 

317 comment="Mother figure, picked on unfairly (1 no - 5 yes)" 

318 ) 

319 s2a_q11 = CamcopsColumn( 

320 "s2a_q11", Integer, 

321 permitted_value_checker=ONE_TO_FIVE_CHECKER, 

322 comment="Mother figure, there if needed (1 no - 5 yes)" 

323 ) 

324 s2a_q12 = CamcopsColumn( 

325 "s2a_q12", Integer, 

326 permitted_value_checker=ONE_TO_FIVE_CHECKER, 

327 comment="Mother figure, interested in friends (1 no - 5 yes)" 

328 ) 

329 s2a_q13 = CamcopsColumn( 

330 "s2a_q13", Integer, 

331 permitted_value_checker=ONE_TO_FIVE_CHECKER, 

332 comment="Mother figure, concerned re whereabouts (1 no - 5 yes)" 

333 ) 

334 s2a_q14 = CamcopsColumn( 

335 "s2a_q14", Integer, 

336 permitted_value_checker=ONE_TO_FIVE_CHECKER, 

337 comment="Mother figure, cared when ill (1 no - 5 yes)" 

338 ) 

339 s2a_q15 = CamcopsColumn( 

340 "s2a_q15", Integer, 

341 permitted_value_checker=ONE_TO_FIVE_CHECKER, 

342 comment="Mother figure, neglected basic needs (1 no - 5 yes)" 

343 ) 

344 s2a_q16 = CamcopsColumn( 

345 "s2a_q16", Integer, 

346 permitted_value_checker=ONE_TO_FIVE_CHECKER, 

347 comment="Mother figure, preferred siblings (1 no - 5 yes)" 

348 ) 

349 s2a_extra = Column( 

350 "s2a_extra", UnicodeText, 

351 comment="Mother figure, extra detail" 

352 ) 

353 

354 # ------------------------------------------------------------------------- 

355 # Section 2(B) 

356 # ------------------------------------------------------------------------- 

357 s2b_q1 = CamcopsColumn( 

358 "s2b_q1", Integer, 

359 permitted_value_checker=ZERO_TO_TWO_CHECKER, 

360 comment="Mother figure, tease me (0 no - 2 yes)" 

361 ) 

362 s2b_q2 = CamcopsColumn( 

363 "s2b_q2", Integer, 

364 permitted_value_checker=ZERO_TO_TWO_CHECKER, 

365 comment="Mother figure, made me keep secrets (0 no - 2 yes)" 

366 ) 

367 s2b_q3 = CamcopsColumn( 

368 "s2b_q3", Integer, 

369 permitted_value_checker=ZERO_TO_TWO_CHECKER, 

370 comment="Mother figure, undermined confidence (0 no - 2 yes)" 

371 ) 

372 s2b_q4 = CamcopsColumn( 

373 "s2b_q4", Integer, 

374 permitted_value_checker=ZERO_TO_TWO_CHECKER, 

375 comment="Mother figure, contradictory (0 no - 2 yes)" 

376 ) 

377 s2b_q5 = CamcopsColumn( 

378 "s2b_q5", Integer, 

379 permitted_value_checker=ZERO_TO_TWO_CHECKER, 

380 comment="Mother figure, played on fears (0 no - 2 yes)" 

381 ) 

382 s2b_q6 = CamcopsColumn( 

383 "s2b_q6", Integer, 

384 permitted_value_checker=ZERO_TO_TWO_CHECKER, 

385 comment="Mother figure, liked to see me suffer (0 no - 2 yes)" 

386 ) 

387 s2b_q7 = CamcopsColumn( 

388 "s2b_q7", Integer, 

389 permitted_value_checker=ZERO_TO_TWO_CHECKER, 

390 comment="Mother figure, humiliated me (0 no - 2 yes)" 

391 ) 

392 s2b_q8 = CamcopsColumn( 

393 "s2b_q8", Integer, 

394 permitted_value_checker=ZERO_TO_TWO_CHECKER, 

395 comment="Mother figure, shamed me before others (0 no - 2 yes)" 

396 ) 

397 s2b_q9 = CamcopsColumn( 

398 "s2b_q9", Integer, 

399 permitted_value_checker=ZERO_TO_TWO_CHECKER, 

400 comment="Mother figure, rejecting (0 no - 2 yes)" 

401 ) 

402 s2b_q10 = CamcopsColumn( 

403 "s2b_q10", Integer, 

404 permitted_value_checker=ZERO_TO_TWO_CHECKER, 

405 comment="Mother figure, took things I cherished (0 no - 2 yes)" 

406 ) 

407 s2b_q11 = CamcopsColumn( 

408 "s2b_q11", Integer, 

409 permitted_value_checker=ZERO_TO_TWO_CHECKER, 

410 comment="Mother figure, eat disliked until sick (0 no - 2 yes)" 

411 ) 

412 s2b_q12 = CamcopsColumn( 

413 "s2b_q12", Integer, 

414 permitted_value_checker=ZERO_TO_TWO_CHECKER, 

415 comment="Mother figure, deprived light/food/company (0 no - 2 yes)" 

416 ) 

417 s2b_q13 = CamcopsColumn( 

418 "s2b_q13", Integer, 

419 permitted_value_checker=ZERO_TO_TWO_CHECKER, 

420 comment="Mother figure, wouldn't let me mix (0 no - 2 yes)" 

421 ) 

422 s2b_q14 = CamcopsColumn( 

423 "s2b_q14", Integer, 

424 permitted_value_checker=ZERO_TO_TWO_CHECKER, 

425 comment="Mother figure, obedience through guilt (0 no - 2 yes)" 

426 ) 

427 s2b_q15 = CamcopsColumn( 

428 "s2b_q15", Integer, 

429 permitted_value_checker=ZERO_TO_TWO_CHECKER, 

430 comment="Mother figure, threatened to hurt people dear to me " 

431 "(0 no - 2 yes)" 

432 ) 

433 s2b_q16 = CamcopsColumn( 

434 "s2b_q16", Integer, 

435 permitted_value_checker=ZERO_TO_TWO_CHECKER, 

436 comment="Mother figure, forced to break law (0 no - 2 yes)" 

437 ) 

438 s2b_q17 = CamcopsColumn( 

439 "s2b_q17", Integer, 

440 permitted_value_checker=ZERO_TO_TWO_CHECKER, 

441 comment="Mother figure, said wanted me dead (0 no - 2 yes)" 

442 ) 

443 s2b_q1_frequency = CamcopsColumn( 

444 "s2b_q1_frequency", Integer, 

445 permitted_value_checker=ZERO_TO_THREE_CHECKER, 

446 comment=FREQUENCY_COMMENT 

447 ) 

448 s2b_q2_frequency = CamcopsColumn( 

449 "s2b_q2_frequency", Integer, 

450 permitted_value_checker=ZERO_TO_THREE_CHECKER, 

451 comment=FREQUENCY_COMMENT 

452 ) 

453 s2b_q3_frequency = CamcopsColumn( 

454 "s2b_q3_frequency", Integer, 

455 permitted_value_checker=ZERO_TO_THREE_CHECKER, 

456 comment=FREQUENCY_COMMENT 

457 ) 

458 s2b_q4_frequency = CamcopsColumn( 

459 "s2b_q4_frequency", Integer, 

460 permitted_value_checker=ZERO_TO_THREE_CHECKER, 

461 comment=FREQUENCY_COMMENT 

462 ) 

463 s2b_q5_frequency = CamcopsColumn( 

464 "s2b_q5_frequency", Integer, 

465 permitted_value_checker=ZERO_TO_THREE_CHECKER, 

466 comment=FREQUENCY_COMMENT 

467 ) 

468 s2b_q6_frequency = CamcopsColumn( 

469 "s2b_q6_frequency", Integer, 

470 permitted_value_checker=ZERO_TO_THREE_CHECKER, 

471 comment=FREQUENCY_COMMENT 

472 ) 

473 s2b_q7_frequency = CamcopsColumn( 

474 "s2b_q7_frequency", Integer, 

475 permitted_value_checker=ZERO_TO_THREE_CHECKER, 

476 comment=FREQUENCY_COMMENT 

477 ) 

478 s2b_q8_frequency = CamcopsColumn( 

479 "s2b_q8_frequency", Integer, 

480 permitted_value_checker=ZERO_TO_THREE_CHECKER, 

481 comment=FREQUENCY_COMMENT 

482 ) 

483 s2b_q9_frequency = CamcopsColumn( 

484 "s2b_q9_frequency", Integer, 

485 permitted_value_checker=ZERO_TO_THREE_CHECKER, 

486 comment=FREQUENCY_COMMENT 

487 ) 

488 s2b_q10_frequency = CamcopsColumn( 

489 "s2b_q10_frequency", Integer, 

490 permitted_value_checker=ZERO_TO_THREE_CHECKER, 

491 comment=FREQUENCY_COMMENT 

492 ) 

493 s2b_q11_frequency = CamcopsColumn( 

494 "s2b_q11_frequency", Integer, 

495 permitted_value_checker=ZERO_TO_THREE_CHECKER, 

496 comment=FREQUENCY_COMMENT 

497 ) 

498 s2b_q12_frequency = CamcopsColumn( 

499 "s2b_q12_frequency", Integer, 

500 permitted_value_checker=ZERO_TO_THREE_CHECKER, 

501 comment=FREQUENCY_COMMENT 

502 ) 

503 s2b_q13_frequency = CamcopsColumn( 

504 "s2b_q13_frequency", Integer, 

505 permitted_value_checker=ZERO_TO_THREE_CHECKER, 

506 comment=FREQUENCY_COMMENT 

507 ) 

508 s2b_q14_frequency = CamcopsColumn( 

509 "s2b_q14_frequency", Integer, 

510 permitted_value_checker=ZERO_TO_THREE_CHECKER, 

511 comment=FREQUENCY_COMMENT 

512 ) 

513 s2b_q15_frequency = CamcopsColumn( 

514 "s2b_q15_frequency", Integer, 

515 permitted_value_checker=ZERO_TO_THREE_CHECKER, 

516 comment=FREQUENCY_COMMENT 

517 ) 

518 s2b_q16_frequency = CamcopsColumn( 

519 "s2b_q16_frequency", Integer, 

520 permitted_value_checker=ZERO_TO_THREE_CHECKER, 

521 comment=FREQUENCY_COMMENT 

522 ) 

523 s2b_q17_frequency = CamcopsColumn( 

524 "s2b_q17_frequency", Integer, 

525 permitted_value_checker=ZERO_TO_THREE_CHECKER, 

526 comment=FREQUENCY_COMMENT 

527 ) 

528 s2b_age_began = CamcopsColumn( 

529 "s2b_age_began", Float, 

530 permitted_value_checker=MIN_ZERO_CHECKER, 

531 comment="Age these experienced began (years)" 

532 ) 

533 s2b_extra = Column( 

534 "s2b_extra", UnicodeText, 

535 comment="Extra detail" 

536 ) 

537 

538 # ------------------------------------------------------------------------- 

539 # Section 3(A) 

540 # ------------------------------------------------------------------------- 

541 s3a_which_father_figure = CamcopsColumn( 

542 "s3a_which_father_figure", Integer, 

543 permitted_value_checker=ZERO_TO_FIVE_CHECKER, 

544 comment="Father figure, which one (0 none/skip, 1 birth father, " 

545 "2 stepfather, 3 other relative, 4 other non-relative, " 

546 "5 other)" 

547 ) 

548 s3a_which_father_figure_other_detail = Column( 

549 "s3a_which_father_figure_other_detail", UnicodeText, 

550 comment="Father figure, other, detail" 

551 ) 

552 s3a_q1 = CamcopsColumn( 

553 "s3a_q1", Integer, 

554 permitted_value_checker=ONE_TO_FIVE_CHECKER, 

555 comment="Father figure, difficult to please (1 no - 5 yes)" 

556 ) 

557 s3a_q2 = CamcopsColumn( 

558 "s3a_q2", Integer, 

559 permitted_value_checker=ONE_TO_FIVE_CHECKER, 

560 comment="Father figure, concerned re my worries (1 no - 5 yes)" 

561 ) 

562 s3a_q3 = CamcopsColumn( 

563 "s3a_q3", Integer, 

564 permitted_value_checker=ONE_TO_FIVE_CHECKER, 

565 comment="Father figure, interested re school (1 no - 5 yes)" 

566 ) 

567 s3a_q4 = CamcopsColumn( 

568 "s3a_q4", Integer, 

569 permitted_value_checker=ONE_TO_FIVE_CHECKER, 

570 comment="Father figure, made me feel unwanted (1 no - 5 yes)" 

571 ) 

572 s3a_q5 = CamcopsColumn( 

573 "s3a_q5", Integer, 

574 permitted_value_checker=ONE_TO_FIVE_CHECKER, 

575 comment="Father figure, better when upset (1 no - 5 yes)" 

576 ) 

577 s3a_q6 = CamcopsColumn( 

578 "s3a_q6", Integer, 

579 permitted_value_checker=ONE_TO_FIVE_CHECKER, 

580 comment="Father figure, critical (1 no - 5 yes)" 

581 ) 

582 s3a_q7 = CamcopsColumn( 

583 "s3a_q7", Integer, 

584 permitted_value_checker=ONE_TO_FIVE_CHECKER, 

585 comment="Father figure, unsupervised <10y (1 no - 5 yes)" 

586 ) 

587 s3a_q8 = CamcopsColumn( 

588 "s3a_q8", Integer, 

589 permitted_value_checker=ONE_TO_FIVE_CHECKER, 

590 comment="Father figure, time to talk (1 no - 5 yes)" 

591 ) 

592 s3a_q9 = CamcopsColumn( 

593 "s3a_q9", Integer, 

594 permitted_value_checker=ONE_TO_FIVE_CHECKER, 

595 comment="Father figure, nuisance (1 no - 5 yes)" 

596 ) 

597 s3a_q10 = CamcopsColumn( 

598 "s3a_q10", Integer, 

599 permitted_value_checker=ONE_TO_FIVE_CHECKER, 

600 comment="Father figure, picked on unfairly (1 no - 5 yes)" 

601 ) 

602 s3a_q11 = CamcopsColumn( 

603 "s3a_q11", Integer, 

604 permitted_value_checker=ONE_TO_FIVE_CHECKER, 

605 comment="Father figure, there if needed (1 no - 5 yes)" 

606 ) 

607 s3a_q12 = CamcopsColumn( 

608 "s3a_q12", Integer, 

609 permitted_value_checker=ONE_TO_FIVE_CHECKER, 

610 comment="Father figure, interested in friends (1 no - 5 yes)" 

611 ) 

612 s3a_q13 = CamcopsColumn( 

613 "s3a_q13", Integer, 

614 permitted_value_checker=ONE_TO_FIVE_CHECKER, 

615 comment="Father figure, concerned re whereabouts (1 no - 5 yes)" 

616 ) 

617 s3a_q14 = CamcopsColumn( 

618 "s3a_q14", Integer, 

619 permitted_value_checker=ONE_TO_FIVE_CHECKER, 

620 comment="Father figure, cared when ill (1 no - 5 yes)" 

621 ) 

622 s3a_q15 = CamcopsColumn( 

623 "s3a_q15", Integer, 

624 permitted_value_checker=ONE_TO_FIVE_CHECKER, 

625 comment="Father figure, neglected basic needs (1 no - 5 yes)" 

626 ) 

627 s3a_q16 = CamcopsColumn( 

628 "s3a_q16", Integer, 

629 permitted_value_checker=ONE_TO_FIVE_CHECKER, 

630 comment="Father figure, preferred siblings (1 no - 5 yes)" 

631 ) 

632 s3a_extra = Column( 

633 "s3a_extra", UnicodeText, 

634 comment="Father figure, extra detail" 

635 ) 

636 

637 # ------------------------------------------------------------------------- 

638 # Section 3(B) 

639 # ------------------------------------------------------------------------- 

640 s3b_q1 = CamcopsColumn( 

641 "s3b_q1", Integer, 

642 permitted_value_checker=ZERO_TO_TWO_CHECKER, 

643 comment="Father figure, tease me (0 no - 2 yes)" 

644 ) 

645 s3b_q2 = CamcopsColumn( 

646 "s3b_q2", Integer, 

647 permitted_value_checker=ZERO_TO_TWO_CHECKER, 

648 comment="Father figure, made me keep secrets (0 no - 2 yes)" 

649 ) 

650 s3b_q3 = CamcopsColumn( 

651 "s3b_q3", Integer, 

652 permitted_value_checker=ZERO_TO_TWO_CHECKER, 

653 comment="Father figure, undermined confidence (0 no - 2 yes)" 

654 ) 

655 s3b_q4 = CamcopsColumn( 

656 "s3b_q4", Integer, 

657 permitted_value_checker=ZERO_TO_TWO_CHECKER, 

658 comment="Father figure, contradictory (0 no - 2 yes)" 

659 ) 

660 s3b_q5 = CamcopsColumn( 

661 "s3b_q5", Integer, 

662 permitted_value_checker=ZERO_TO_TWO_CHECKER, 

663 comment="Father figure, played on fears (0 no - 2 yes)" 

664 ) 

665 s3b_q6 = CamcopsColumn( 

666 "s3b_q6", Integer, 

667 permitted_value_checker=ZERO_TO_TWO_CHECKER, 

668 comment="Father figure, liked to see me suffer (0 no - 2 yes)" 

669 ) 

670 s3b_q7 = CamcopsColumn( 

671 "s3b_q7", Integer, 

672 permitted_value_checker=ZERO_TO_TWO_CHECKER, 

673 comment="Father figure, humiliated me (0 no - 2 yes)" 

674 ) 

675 s3b_q8 = CamcopsColumn( 

676 "s3b_q8", Integer, 

677 permitted_value_checker=ZERO_TO_TWO_CHECKER, 

678 comment="Father figure, shamed me before others (0 no - 2 yes)" 

679 ) 

680 s3b_q9 = CamcopsColumn( 

681 "s3b_q9", Integer, 

682 permitted_value_checker=ZERO_TO_TWO_CHECKER, 

683 comment="Father figure, rejecting (0 no - 2 yes)" 

684 ) 

685 s3b_q10 = CamcopsColumn( 

686 "s3b_q10", Integer, 

687 permitted_value_checker=ZERO_TO_TWO_CHECKER, 

688 comment="Father figure, took things I cherished (0 no - 2 yes)" 

689 ) 

690 s3b_q11 = CamcopsColumn( 

691 "s3b_q11", Integer, 

692 permitted_value_checker=ZERO_TO_TWO_CHECKER, 

693 comment="Father figure, eat disliked until sick (0 no - 2 yes)" 

694 ) 

695 s3b_q12 = CamcopsColumn( 

696 "s3b_q12", Integer, 

697 permitted_value_checker=ZERO_TO_TWO_CHECKER, 

698 comment="Father figure, deprived light/food/company (0 no - 2 yes)" 

699 ) 

700 s3b_q13 = CamcopsColumn( 

701 "s3b_q13", Integer, 

702 permitted_value_checker=ZERO_TO_TWO_CHECKER, 

703 comment="Father figure, wouldn't let me mix (0 no - 2 yes)" 

704 ) 

705 s3b_q14 = CamcopsColumn( 

706 "s3b_q14", Integer, 

707 permitted_value_checker=ZERO_TO_TWO_CHECKER, 

708 comment="Father figure, obedience through guilt (0 no - 2 yes)" 

709 ) 

710 s3b_q15 = CamcopsColumn( 

711 "s3b_q15", Integer, 

712 permitted_value_checker=ZERO_TO_TWO_CHECKER, 

713 comment="Father figure, threatened to hurt people dear to me " 

714 "(0 no - 2 yes)" 

715 ) 

716 s3b_q16 = CamcopsColumn( 

717 "s3b_q16", Integer, 

718 permitted_value_checker=ZERO_TO_TWO_CHECKER, 

719 comment="Father figure, forced to break law (0 no - 2 yes)" 

720 ) 

721 s3b_q17 = CamcopsColumn( 

722 "s3b_q17", Integer, 

723 permitted_value_checker=ZERO_TO_TWO_CHECKER, 

724 comment="Father figure, said wanted me dead (0 no - 2 yes)" 

725 ) 

726 s3b_q1_frequency = CamcopsColumn( 

727 "s3b_q1_frequency", Integer, 

728 permitted_value_checker=ZERO_TO_THREE_CHECKER, 

729 comment=FREQUENCY_COMMENT 

730 ) 

731 s3b_q2_frequency = CamcopsColumn( 

732 "s3b_q2_frequency", Integer, 

733 permitted_value_checker=ZERO_TO_THREE_CHECKER, 

734 comment=FREQUENCY_COMMENT 

735 ) 

736 s3b_q3_frequency = CamcopsColumn( 

737 "s3b_q3_frequency", Integer, 

738 permitted_value_checker=ZERO_TO_THREE_CHECKER, 

739 comment=FREQUENCY_COMMENT 

740 ) 

741 s3b_q4_frequency = CamcopsColumn( 

742 "s3b_q4_frequency", Integer, 

743 permitted_value_checker=ZERO_TO_THREE_CHECKER, 

744 comment=FREQUENCY_COMMENT 

745 ) 

746 s3b_q5_frequency = CamcopsColumn( 

747 "s3b_q5_frequency", Integer, 

748 permitted_value_checker=ZERO_TO_THREE_CHECKER, 

749 comment=FREQUENCY_COMMENT 

750 ) 

751 s3b_q6_frequency = CamcopsColumn( 

752 "s3b_q6_frequency", Integer, 

753 permitted_value_checker=ZERO_TO_THREE_CHECKER, 

754 comment=FREQUENCY_COMMENT 

755 ) 

756 s3b_q7_frequency = CamcopsColumn( 

757 "s3b_q7_frequency", Integer, 

758 permitted_value_checker=ZERO_TO_THREE_CHECKER, 

759 comment=FREQUENCY_COMMENT 

760 ) 

761 s3b_q8_frequency = CamcopsColumn( 

762 "s3b_q8_frequency", Integer, 

763 permitted_value_checker=ZERO_TO_THREE_CHECKER, 

764 comment=FREQUENCY_COMMENT 

765 ) 

766 s3b_q9_frequency = CamcopsColumn( 

767 "s3b_q9_frequency", Integer, 

768 permitted_value_checker=ZERO_TO_THREE_CHECKER, 

769 comment=FREQUENCY_COMMENT 

770 ) 

771 s3b_q10_frequency = CamcopsColumn( 

772 "s3b_q10_frequency", Integer, 

773 permitted_value_checker=ZERO_TO_THREE_CHECKER, 

774 comment=FREQUENCY_COMMENT 

775 ) 

776 s3b_q11_frequency = CamcopsColumn( 

777 "s3b_q11_frequency", Integer, 

778 permitted_value_checker=ZERO_TO_THREE_CHECKER, 

779 comment=FREQUENCY_COMMENT 

780 ) 

781 s3b_q12_frequency = CamcopsColumn( 

782 "s3b_q12_frequency", Integer, 

783 permitted_value_checker=ZERO_TO_THREE_CHECKER, 

784 comment=FREQUENCY_COMMENT 

785 ) 

786 s3b_q13_frequency = CamcopsColumn( 

787 "s3b_q13_frequency", Integer, 

788 permitted_value_checker=ZERO_TO_THREE_CHECKER, 

789 comment=FREQUENCY_COMMENT 

790 ) 

791 s3b_q14_frequency = CamcopsColumn( 

792 "s3b_q14_frequency", Integer, 

793 permitted_value_checker=ZERO_TO_THREE_CHECKER, 

794 comment=FREQUENCY_COMMENT 

795 ) 

796 s3b_q15_frequency = CamcopsColumn( 

797 "s3b_q15_frequency", Integer, 

798 permitted_value_checker=ZERO_TO_THREE_CHECKER, 

799 comment=FREQUENCY_COMMENT 

800 ) 

801 s3b_q16_frequency = CamcopsColumn( 

802 "s3b_q16_frequency", Integer, 

803 permitted_value_checker=ZERO_TO_THREE_CHECKER, 

804 comment=FREQUENCY_COMMENT 

805 ) 

806 s3b_q17_frequency = CamcopsColumn( 

807 "s3b_q17_frequency", Integer, 

808 permitted_value_checker=ZERO_TO_THREE_CHECKER, 

809 comment=FREQUENCY_COMMENT 

810 ) 

811 s3b_age_began = CamcopsColumn( 

812 "s3b_age_began", Float, 

813 permitted_value_checker=MIN_ZERO_CHECKER, 

814 comment="Age these experienced began (years)" 

815 ) 

816 s3b_extra = Column( 

817 "s3b_extra", UnicodeText, 

818 comment="Extra detail" 

819 ) 

820 

821 # ------------------------------------------------------------------------- 

822 # Section 3(C) 

823 # ------------------------------------------------------------------------- 

824 s3c_q1 = CamcopsColumn( 

825 "s3c_q1", Integer, 

826 permitted_value_checker=ONE_TO_FIVE_CHECKER, 

827 comment="Responsibility (1 no - 5 yes)" 

828 ) 

829 s3c_q2 = CamcopsColumn( 

830 "s3c_q2", Integer, 

831 permitted_value_checker=ONE_TO_FIVE_CHECKER, 

832 comment="Housework (1 no - 5 yes)" 

833 ) 

834 s3c_q3 = CamcopsColumn( 

835 "s3c_q3", Integer, 

836 permitted_value_checker=ONE_TO_FIVE_CHECKER, 

837 comment="Look after young siblings (1 no - 5 yes)" 

838 ) 

839 s3c_q4 = CamcopsColumn( 

840 "s3c_q4", Integer, 

841 permitted_value_checker=ONE_TO_FIVE_CHECKER, 

842 comment="Cooking/cleaning (1 no - 5 yes)" 

843 ) 

844 s3c_q5 = CamcopsColumn( 

845 "s3c_q5", Integer, 

846 permitted_value_checker=ONE_TO_FIVE_CHECKER, 

847 comment="Miss school for domestic responsibilities (1 no - 5 yes)" 

848 ) 

849 s3c_q6 = CamcopsColumn( 

850 "s3c_q6", Integer, 

851 permitted_value_checker=ONE_TO_FIVE_CHECKER, 

852 comment="Miss seeing friends for domestic responsibilities " 

853 "(1 no - 5 yes)" 

854 ) 

855 s3c_q7 = CamcopsColumn( 

856 "s3c_q7", Integer, 

857 permitted_value_checker=ONE_TO_FIVE_CHECKER, 

858 comment="Parents said they couldn't cope (1 no - 5 yes)" 

859 ) 

860 s3c_q8 = CamcopsColumn( 

861 "s3c_q8", Integer, 

862 permitted_value_checker=ONE_TO_FIVE_CHECKER, 

863 comment="Parents looked to you for help (1 no - 5 yes)" 

864 ) 

865 s3c_q9 = CamcopsColumn( 

866 "s3c_q9", Integer, 

867 permitted_value_checker=ONE_TO_FIVE_CHECKER, 

868 comment="Parents coped if you were hurt/ill (1 no - 5 yes)" 

869 ) 

870 s3c_q10 = CamcopsColumn( 

871 "s3c_q10", Integer, 

872 permitted_value_checker=ONE_TO_FIVE_CHECKER, 

873 comment="Parents confided their problems (1 no - 5 yes)" 

874 ) 

875 s3c_q11 = CamcopsColumn( 

876 "s3c_q11", Integer, 

877 permitted_value_checker=ONE_TO_FIVE_CHECKER, 

878 comment="Parents relied on you for emotional support (1 no - 5 yes)" 

879 ) 

880 s3c_q12 = CamcopsColumn( 

881 "s3c_q12", Integer, 

882 permitted_value_checker=ONE_TO_FIVE_CHECKER, 

883 comment="Parents cried in front of you (1 no - 5 yes)" 

884 ) 

885 s3c_q13 = CamcopsColumn( 

886 "s3c_q13", Integer, 

887 permitted_value_checker=ONE_TO_FIVE_CHECKER, 

888 comment="Concerned/worried re parent (1 no - 5 yes)" 

889 ) 

890 s3c_q14 = CamcopsColumn( 

891 "s3c_q14", Integer, 

892 permitted_value_checker=ONE_TO_FIVE_CHECKER, 

893 comment="Tried to support/care for parent (1 no - 5 yes)" 

894 ) 

895 s3c_q15 = CamcopsColumn( 

896 "s3c_q15", Integer, 

897 permitted_value_checker=ONE_TO_FIVE_CHECKER, 

898 comment="Try to make parent smile when upset (1 no - 5 yes)" 

899 ) 

900 s3c_q16 = CamcopsColumn( 

901 "s3c_q16", Integer, 

902 permitted_value_checker=ONE_TO_FIVE_CHECKER, 

903 comment="Parents made you feel guilty for their sacrifices " 

904 "(1 no - 5 yes)" 

905 ) 

906 s3c_q17 = CamcopsColumn( 

907 "s3c_q17", Integer, 

908 permitted_value_checker=ONE_TO_FIVE_CHECKER, 

909 comment="Had to keep secrets for parent (1 no - 5 yes)" 

910 ) 

911 s3c_which_parent_cared_for = CamcopsColumn( 

912 "s3c_which_parent_cared_for", Integer, 

913 permitted_value_checker=ZERO_TO_FOUR_CHECKER, 

914 comment="Which parent did you have to provide care for (0 none, " 

915 "1 mother, 2 father, 3 both, 4 other)" 

916 ) 

917 s3c_parent_mental_problem = CamcopsColumn( 

918 "s3c_parent_mental_problem", Integer, 

919 permitted_value_checker=ZERO_TO_TWO_CHECKER, 

920 comment="Parent/s had emotional/mental health problems (0 no - 2 yes)" 

921 ) 

922 s3c_parent_physical_problem = CamcopsColumn( 

923 "s3c_parent_physical_problem", Integer, 

924 permitted_value_checker=ZERO_TO_TWO_CHECKER, 

925 comment="Parent/s had disability/physical illness (0 no - 2 yes)" 

926 ) 

927 

928 # ------------------------------------------------------------------------- 

929 # Section 4(A) 

930 # ------------------------------------------------------------------------- 

931 s4a_adultconfidant = CamcopsColumn( 

932 "s4a_adultconfidant", Boolean, 

933 permitted_value_checker=BIT_CHECKER, 

934 comment="Adult confidant?" 

935 ) 

936 s4a_adultconfidant_mother = CamcopsColumn( 

937 "s4a_adultconfidant_mother", Boolean, 

938 permitted_value_checker=BIT_CHECKER, 

939 comment="Adult confidant, mother?" 

940 ) 

941 s4a_adultconfidant_father = CamcopsColumn( 

942 "s4a_adultconfidant_father", Boolean, 

943 permitted_value_checker=BIT_CHECKER, 

944 comment="Adult confidant, father?" 

945 ) 

946 s4a_adultconfidant_otherrelative = CamcopsColumn( 

947 "s4a_adultconfidant_otherrelative", Boolean, 

948 permitted_value_checker=BIT_CHECKER, 

949 comment="Adult confidant, other relative?" 

950 ) 

951 s4a_adultconfidant_familyfriend = CamcopsColumn( 

952 "s4a_adultconfidant_familyfriend", Boolean, 

953 permitted_value_checker=BIT_CHECKER, 

954 comment="Adult confidant, family friend?" 

955 ) 

956 s4a_adultconfidant_responsibleadult = CamcopsColumn( 

957 "s4a_adultconfidant_responsibleadult", Boolean, 

958 permitted_value_checker=BIT_CHECKER, 

959 comment="Adult confidant, teacher/vicar/etc.?" 

960 ) 

961 s4a_adultconfidant_other = CamcopsColumn( 

962 "s4a_adultconfidant_other", Boolean, 

963 permitted_value_checker=BIT_CHECKER, 

964 comment="Adult confidant, other?" 

965 ) 

966 s4a_adultconfidant_other_detail = Column( 

967 "s4a_adultconfidant_other_detail", UnicodeText, 

968 comment="Adult confidant, other, detail" 

969 ) 

970 s4a_adultconfidant_additional = Column( 

971 "s4a_adultconfidant_additional", UnicodeText, 

972 comment="Adult confidant, additional notes" 

973 ) 

974 

975 # ------------------------------------------------------------------------- 

976 # Section 4(B) 

977 # ------------------------------------------------------------------------- 

978 s4b_childconfidant = CamcopsColumn( 

979 "s4b_childconfidant", Boolean, 

980 permitted_value_checker=BIT_CHECKER, 

981 comment="Child confidant?" 

982 ) 

983 s4b_childconfidant_sister = CamcopsColumn( 

984 "s4b_childconfidant_sister", Boolean, 

985 permitted_value_checker=BIT_CHECKER, 

986 comment="Child confidant, sister?" 

987 ) 

988 s4b_childconfidant_brother = CamcopsColumn( 

989 "s4b_childconfidant_brother", Boolean, 

990 permitted_value_checker=BIT_CHECKER, 

991 comment="Child confidant, brother?" 

992 ) 

993 s4b_childconfidant_otherrelative = CamcopsColumn( 

994 "s4b_childconfidant_otherrelative", Boolean, 

995 permitted_value_checker=BIT_CHECKER, 

996 comment="Child confidant, other relative?" 

997 ) 

998 s4b_childconfidant_closefriend = CamcopsColumn( 

999 "s4b_childconfidant_closefriend", Boolean, 

1000 permitted_value_checker=BIT_CHECKER, 

1001 comment="Child confidant, close friend?" 

1002 ) 

1003 s4b_childconfidant_otherfriend = CamcopsColumn( 

1004 "s4b_childconfidant_otherfriend", Boolean, 

1005 permitted_value_checker=BIT_CHECKER, 

1006 comment="Child confidant, other less close friend(s)?" 

1007 ) 

1008 s4b_childconfidant_other = CamcopsColumn( 

1009 "s4b_childconfidant_other", Boolean, 

1010 permitted_value_checker=BIT_CHECKER, 

1011 comment="Child confidant, other person?" 

1012 ) 

1013 s4b_childconfidant_other_detail = Column( 

1014 "s4b_childconfidant_other_detail", UnicodeText, 

1015 comment="Child confidant, other person, detail" 

1016 ) 

1017 s4b_childconfidant_additional = Column( 

1018 "s4b_childconfidant_additional", UnicodeText, 

1019 comment="Child confidant, additional notes" 

1020 ) 

1021 

1022 # ------------------------------------------------------------------------- 

1023 # Section 4(C) 

1024 # ------------------------------------------------------------------------- 

1025 s4c_closest_mother = CamcopsColumn( 

1026 "s4c_closest_mother", Boolean, 

1027 permitted_value_checker=BIT_CHECKER, 

1028 comment="Two closest people include: mother?" 

1029 ) 

1030 s4c_closest_father = CamcopsColumn( 

1031 "s4c_closest_father", Boolean, 

1032 permitted_value_checker=BIT_CHECKER, 

1033 comment="Two closest people include: father?" 

1034 ) 

1035 s4c_closest_sibling = CamcopsColumn( 

1036 "s4c_closest_sibling", Boolean, 

1037 permitted_value_checker=BIT_CHECKER, 

1038 comment="Two closest people include: sibling?" 

1039 ) 

1040 s4c_closest_otherrelative = CamcopsColumn( 

1041 "s4c_closest_otherrelative", Boolean, 

1042 permitted_value_checker=BIT_CHECKER, 

1043 comment="Two closest people include: other relative?" 

1044 ) 

1045 s4c_closest_adultfriend = CamcopsColumn( 

1046 "s4c_closest_adultfriend", Boolean, 

1047 permitted_value_checker=BIT_CHECKER, 

1048 comment="Two closest people include: adult family friend?" 

1049 ) 

1050 s4c_closest_childfriend = CamcopsColumn( 

1051 "s4c_closest_childfriend", Boolean, 

1052 permitted_value_checker=BIT_CHECKER, 

1053 comment="Two closest people include: friend your age?" 

1054 ) 

1055 s4c_closest_other = CamcopsColumn( 

1056 "s4c_closest_other", Boolean, 

1057 permitted_value_checker=BIT_CHECKER, 

1058 comment="Two closest people include: other?" 

1059 ) 

1060 s4c_closest_other_detail = Column( 

1061 "s4c_closest_other_detail", UnicodeText, 

1062 comment="Two closest people include: other, detail" 

1063 ) 

1064 s4c_closest_additional = Column( 

1065 "s4c_closest_additional", UnicodeText, 

1066 comment="Two closest people include: additional notes" 

1067 ) 

1068 

1069 # ------------------------------------------------------------------------- 

1070 # Section 5(C) 

1071 # ------------------------------------------------------------------------- 

1072 s5c_physicalabuse = CamcopsColumn( 

1073 "s5c_physicalabuse", Boolean, 

1074 permitted_value_checker=BIT_CHECKER, 

1075 comment="Physical abuse?" 

1076 ) 

1077 s5c_abused_by_mother = CamcopsColumn( 

1078 "s5c_abused_by_mother", Boolean, 

1079 permitted_value_checker=BIT_CHECKER, 

1080 comment="Physical abuse, by mother?" 

1081 ) 

1082 s5c_abused_by_father = CamcopsColumn( 

1083 "s5c_abused_by_father", Boolean, 

1084 permitted_value_checker=BIT_CHECKER, 

1085 comment="Physical abuse, by father?" 

1086 ) 

1087 s5c_mother_abuse_age_began = CamcopsColumn( 

1088 "s5c_mother_abuse_age_began", Float, 

1089 comment="Physical abuse, by mother, age began (y)" 

1090 ) 

1091 s5c_father_abuse_age_began = CamcopsColumn( 

1092 "s5c_father_abuse_age_began", Float, 

1093 comment="Physical abuse, by father, age began (y)" 

1094 ) 

1095 s5c_mother_hit_more_than_once = CamcopsColumn( 

1096 "s5c_mother_hit_more_than_once", Boolean, 

1097 permitted_value_checker=BIT_CHECKER, 

1098 comment="Physical abuse, by mother, hit on >1 occasion" 

1099 ) 

1100 s5c_father_hit_more_than_once = CamcopsColumn( 

1101 "s5c_father_hit_more_than_once", Boolean, 

1102 permitted_value_checker=BIT_CHECKER, 

1103 comment="Physical abuse, by father, hit on >1 occasion" 

1104 ) 

1105 s5c_mother_hit_how = CamcopsColumn( 

1106 "s5c_mother_hit_how", Integer, 

1107 permitted_value_checker=ONE_TO_FOUR_CHECKER, 

1108 comment="Physical abuse, by mother, hit how (1 belt/stick, " 

1109 "2 punched/kicked, 3 hit with hand, 4 other)" 

1110 ) 

1111 s5c_father_hit_how = CamcopsColumn( 

1112 "s5c_father_hit_how", Integer, 

1113 permitted_value_checker=ONE_TO_FOUR_CHECKER, 

1114 comment="Physical abuse, by father, hit how (1 belt/stick, " 

1115 "2 punched/kicked, 3 hit with hand, 4 other)" 

1116 ) 

1117 s5c_mother_injured = CamcopsColumn( 

1118 "s5c_mother_injured", Boolean, 

1119 permitted_value_checker=BIT_CHECKER, 

1120 comment="Physical abuse, by mother, injured?" 

1121 ) 

1122 s5c_father_injured = CamcopsColumn( 

1123 "s5c_father_injured", Boolean, 

1124 permitted_value_checker=BIT_CHECKER, 

1125 comment="Physical abuse, by father, injured?" 

1126 ) 

1127 s5c_mother_out_of_control = CamcopsColumn( 

1128 "s5c_mother_out_of_control", Boolean, 

1129 permitted_value_checker=BIT_CHECKER, 

1130 comment="Physical abuse, by mother, out of control?" 

1131 ) 

1132 s5c_father_out_of_control = CamcopsColumn( 

1133 "s5c_father_out_of_control", Boolean, 

1134 permitted_value_checker=BIT_CHECKER, 

1135 comment="Physical abuse, by father, out of control?" 

1136 ) 

1137 s5c_parental_abuse_description = Column( 

1138 "s5c_parental_abuse_description", UnicodeText, 

1139 comment="Physical abuse, description" 

1140 ) 

1141 s5c_abuse_by_nonparent = CamcopsColumn( 

1142 "s5c_abuse_by_nonparent", Boolean, 

1143 permitted_value_checker=BIT_CHECKER, 

1144 comment="Physical abuse, by anyone else in household?" 

1145 ) 

1146 s5c_nonparent_abuse_description = Column( 

1147 "s5c_nonparent_abuse_description", UnicodeText, 

1148 comment="Physical abuse, nonparent, description" 

1149 ) 

1150 

1151 # ------------------------------------------------------------------------- 

1152 # Section 6 

1153 # ------------------------------------------------------------------------- 

1154 s6_any_unwanted_sexual_experience = CamcopsColumn( 

1155 # Prior to 2.1.0: was cctype="BOOL" on the server, but this gave 

1156 # TINYINT(1), which can store -128 to 128. Corrected to Integer. 

1157 "s6_any_unwanted_sexual_experience", Integer, 

1158 permitted_value_checker=ZERO_TO_TWO_CHECKER, 

1159 comment="Any unwanted sexual experiences (0 no - 2 yes)" 

1160 ) 

1161 s6_unwanted_intercourse = CamcopsColumn( 

1162 # Prior to 2.1.0: was cctype="BOOL" on the server, but this gave 

1163 # TINYINT(1), which can store -128 to 128. Corrected to Integer. 

1164 "s6_unwanted_intercourse", Integer, 

1165 permitted_value_checker=ZERO_TO_TWO_CHECKER, 

1166 comment="Unwanted intercourse before 17yo (0 no - 2 yes)" 

1167 ) 

1168 s6_upsetting_sexual_adult_authority = CamcopsColumn( 

1169 # Prior to 2.1.0: was cctype="BOOL" on the server, but this gave 

1170 # TINYINT(1), which can store -128 to 128. Corrected to Integer. 

1171 "s6_upsetting_sexual_adult_authority", Integer, 

1172 permitted_value_checker=ZERO_TO_TWO_CHECKER, 

1173 comment="Upsetting sexual experiences under 17yo with " 

1174 "related adult or someone in authority (0 no - 2 yes)" 

1175 ) 

1176 s6_first_age = CamcopsColumn( 

1177 "s6_first_age", Float, 

1178 permitted_value_checker=MIN_ZERO_CHECKER, 

1179 comment="Sexual abuse, first experience, age it began" 

1180 ) 

1181 s6_other_age = CamcopsColumn( 

1182 "s6_other_age", Float, 

1183 permitted_value_checker=MIN_ZERO_CHECKER, 

1184 comment="Sexual abuse, other experience, age it began" 

1185 ) 

1186 s6_first_person_known = CamcopsColumn( 

1187 "s6_first_person_known", Boolean, 

1188 permitted_value_checker=BIT_CHECKER, 

1189 comment="Sexual abuse, first experience, knew the person?" 

1190 ) 

1191 s6_other_person_known = CamcopsColumn( 

1192 "s6_other_person_known", Boolean, 

1193 permitted_value_checker=BIT_CHECKER, 

1194 comment="Sexual abuse, other experience, knew the person?" 

1195 ) 

1196 s6_first_relative = CamcopsColumn( 

1197 "s6_first_relative", Boolean, 

1198 permitted_value_checker=BIT_CHECKER, 

1199 comment="Sexual abuse, first experience, person was a relative?" 

1200 ) 

1201 s6_other_relative = CamcopsColumn( 

1202 "s6_other_relative", Boolean, 

1203 permitted_value_checker=BIT_CHECKER, 

1204 comment="Sexual abuse, other experience, person was a relative?" 

1205 ) 

1206 s6_first_in_household = CamcopsColumn( 

1207 "s6_first_in_household", Boolean, 

1208 permitted_value_checker=BIT_CHECKER, 

1209 comment="Sexual abuse, first experience, person lived in household?" 

1210 ) 

1211 s6_other_in_household = CamcopsColumn( 

1212 "s6_other_in_household", Boolean, 

1213 permitted_value_checker=BIT_CHECKER, 

1214 comment="Sexual abuse, other experience, person lived in household?" 

1215 ) 

1216 s6_first_more_than_once = CamcopsColumn( 

1217 "s6_first_more_than_once", Boolean, 

1218 permitted_value_checker=BIT_CHECKER, 

1219 comment="Sexual abuse, first experience, happened more than once?" 

1220 ) 

1221 s6_other_more_than_once = CamcopsColumn( 

1222 "s6_other_more_than_once", Boolean, 

1223 permitted_value_checker=BIT_CHECKER, 

1224 comment="Sexual abuse, other experience, happened more than once?" 

1225 ) 

1226 s6_first_touch_privates_subject = CamcopsColumn( 

1227 "s6_first_touch_privates_subject", Boolean, 

1228 permitted_value_checker=BIT_CHECKER, 

1229 comment="Sexual abuse, first experience, touched your private parts?" 

1230 ) 

1231 s6_other_touch_privates_subject = CamcopsColumn( 

1232 "s6_other_touch_privates_subject", Boolean, 

1233 permitted_value_checker=BIT_CHECKER, 

1234 comment="Sexual abuse, other experience, touched your private parts?" 

1235 ) 

1236 s6_first_touch_privates_other = CamcopsColumn( 

1237 "s6_first_touch_privates_other", Boolean, 

1238 permitted_value_checker=BIT_CHECKER, 

1239 comment="Sexual abuse, first experience, touched their private parts?" 

1240 ) 

1241 s6_other_touch_privates_other = CamcopsColumn( 

1242 "s6_other_touch_privates_other", Boolean, 

1243 permitted_value_checker=BIT_CHECKER, 

1244 comment="Sexual abuse, other experience, touched their private parts?" 

1245 ) 

1246 s6_first_intercourse = CamcopsColumn( 

1247 "s6_first_intercourse", Boolean, 

1248 permitted_value_checker=BIT_CHECKER, 

1249 comment="Sexual abuse, first experience, sexual intercourse?" 

1250 ) 

1251 s6_other_intercourse = CamcopsColumn( 

1252 "s6_other_intercourse", Boolean, 

1253 permitted_value_checker=BIT_CHECKER, 

1254 comment="Sexual abuse, other experience, sexual intercourse?" 

1255 ) 

1256 s6_unwanted_sexual_description = Column( 

1257 "s6_unwanted_sexual_description", UnicodeText, 

1258 comment="Sexual abuse, description" 

1259 ) 

1260 

1261 # ------------------------------------------------------------------------- 

1262 # Final 

1263 # ------------------------------------------------------------------------- 

1264 any_other_comments = CamcopsColumn( 

1265 "any_other_comments", UnicodeText, 

1266 comment="Any other comments" 

1267 ) 

1268 

1269 @staticmethod 

1270 def longname(req: "CamcopsRequest") -> str: 

1271 _ = req.gettext 

1272 return _("Childhood Experience of Care and Abuse Questionnaire") 

1273 

1274 def get_summaries(self, req: CamcopsRequest) -> List[SummaryElement]: 

1275 return self.standard_task_summary_fields() + [ 

1276 SummaryElement( 

1277 name="parental_loss_risk", 

1278 coltype=Boolean(), 

1279 value=self.parental_loss_risk(), 

1280 comment="Parental loss risk factor?"), 

1281 SummaryElement( 

1282 name="parental_loss_high_risk", 

1283 coltype=Boolean(), 

1284 value=self.parental_loss_high_risk(), 

1285 comment="Parental loss higher risk factor?"), 

1286 SummaryElement( 

1287 name="mother_antipathy", 

1288 coltype=Integer(), 

1289 value=self.mother_antipathy(), 

1290 comment="Maternal antipathy score (8-40)"), 

1291 SummaryElement( 

1292 name="mother_neglect", 

1293 coltype=Integer(), 

1294 value=self.mother_neglect(), 

1295 comment="Maternal neglect score (8-40)"), 

1296 SummaryElement( 

1297 name="mother_psychological_abuse", 

1298 coltype=Integer(), 

1299 value=self.mother_psychological_abuse(), 

1300 comment="Maternal psychological abuse score (0-85)"), 

1301 SummaryElement( 

1302 name="father_antipathy", 

1303 coltype=Integer(), 

1304 value=self.father_antipathy(), 

1305 comment="Paternal antipathy score (8-40)"), 

1306 SummaryElement( 

1307 name="father_neglect", 

1308 coltype=Integer(), 

1309 value=self.father_neglect(), 

1310 comment="Paternal neglect score (8-40)"), 

1311 SummaryElement( 

1312 name="father_psychological_abuse", 

1313 coltype=Integer(), 

1314 value=self.father_psychological_abuse(), 

1315 comment="Paternal psychological abuse score (0-85)"), 

1316 SummaryElement( 

1317 name="role_reversal", 

1318 coltype=Integer(), 

1319 value=self.role_reversal(), 

1320 comment="Role reversal score (17-85)"), 

1321 SummaryElement( 

1322 name="physical_abuse_screen", 

1323 coltype=Integer(), 

1324 value=self.physical_abuse_screen(), 

1325 comment="Physical abuse screen (0-1)"), 

1326 SummaryElement( 

1327 name="physical_abuse_severity_mother", 

1328 coltype=Integer(), 

1329 value=self.physical_abuse_severity_mother(), 

1330 comment="Maternal physical abuse severity score (0-4)"), 

1331 SummaryElement( 

1332 name="physical_abuse_severity_father", 

1333 coltype=Integer(), 

1334 value=self.physical_abuse_severity_father(), 

1335 comment="Paternal physical abuse severity score (0-4)"), 

1336 SummaryElement( 

1337 name="sexual_abuse_screen", 

1338 coltype=Integer(), 

1339 value=self.sexual_abuse_screen(), 

1340 comment="Sexual abuse screen (0-3)"), 

1341 SummaryElement( 

1342 name="sexual_abuse_score_first", 

1343 coltype=Integer(), 

1344 value=self.sexual_abuse_score_first(), 

1345 comment="First sexual abuse severity score (0-7)"), 

1346 SummaryElement( 

1347 name="sexual_abuse_score_other", 

1348 coltype=Integer(), 

1349 value=self.sexual_abuse_score_other(), 

1350 comment="Other sexual abuse severity score (0-7)"), 

1351 ] 

1352 

1353 # ------------------------------------------------------------------------- 

1354 # Complete? 

1355 # ------------------------------------------------------------------------- 

1356 

1357 def is_complete(self) -> bool: 

1358 return ( 

1359 self.complete_1a() and 

1360 self.complete_1b() and 

1361 self.complete_1c() and 

1362 self.complete_2a() and 

1363 self.complete_2b() and 

1364 self.complete_3a() and 

1365 self.complete_3b() and 

1366 self.complete_3c() and 

1367 self.complete_4a() and 

1368 self.complete_4b() and 

1369 self.complete_4c() and 

1370 self.complete_5() and 

1371 self.complete_6() and 

1372 self.field_contents_valid() 

1373 ) 

1374 

1375 def is_at_least_one_field_true(self, fields: List[str]) -> bool: 

1376 for f in fields: 

1377 if getattr(self, f): 

1378 return True 

1379 return True 

1380 

1381 def complete_1a(self) -> bool: 

1382 if not self.is_at_least_one_field_true([ 

1383 "s1a_motherfigure_birthmother", 

1384 "s1a_motherfigure_stepmother", 

1385 "s1a_motherfigure_femalerelative", 

1386 "s1a_motherfigure_familyfriend", 

1387 "s1a_motherfigure_fostermother", 

1388 "s1a_motherfigure_adoptivemother", 

1389 "s1a_motherfigure_other", 

1390 "s1a_fatherfigure_birthfather", 

1391 "s1a_fatherfigure_stepfather", 

1392 "s1a_fatherfigure_malerelative", 

1393 "s1a_fatherfigure_familyfriend", 

1394 "s1a_fatherfigure_fosterfather", 

1395 "s1a_fatherfigure_adoptivefather", 

1396 "s1a_fatherfigure_other", 

1397 ]): 

1398 return False 

1399 if (self.s1a_motherfigure_other and 

1400 not self.s1a_motherfigure_other_detail): 

1401 return False 

1402 if (self.s1a_motherfigure_femalerelative and 

1403 not self.s1a_motherfigure_femalerelative_detail): 

1404 return False 

1405 if (self.s1a_fatherfigure_other and 

1406 not self.s1a_fatherfigure_other_detail): 

1407 return False 

1408 if (self.s1a_fatherfigure_malerelative and 

1409 not self.s1a_fatherfigure_malerelative_detail): 

1410 return False 

1411 return True 

1412 

1413 def complete_1b(self) -> bool: 

1414 if self.s1b_institution is None: 

1415 return False 

1416 if self.s1b_institution and self.s1b_institution_time_years is None: 

1417 return False 

1418 return True 

1419 

1420 def complete_1c(self) -> bool: 

1421 if self.s1c_mother_died is None or self.s1c_father_died is None: 

1422 return False 

1423 if self.s1c_mother_died and self.s1c_mother_died_subject_aged is None: 

1424 return False 

1425 if self.s1c_father_died and self.s1c_father_died_subject_aged is None: 

1426 return False 

1427 if (self.s1c_separated_from_mother is None or 

1428 self.s1c_separated_from_father is None): 

1429 return False 

1430 if self.s1c_separated_from_mother: 

1431 if self.any_fields_none(["s1c_first_separated_from_mother_aged", 

1432 "s1c_mother_how_long_first_separation_years", # noqa 

1433 "s1c_mother_separation_reason"]): 

1434 return False 

1435 if self.s1c_separated_from_father: 

1436 if self.any_fields_none(["s1c_first_separated_from_father_aged", 

1437 "s1c_father_how_long_first_separation_years", # noqa 

1438 "s1c_father_separation_reason"]): 

1439 return False 

1440 return True 

1441 

1442 def complete_2a(self) -> bool: 

1443 if self.s2a_which_mother_figure is None: 

1444 return False 

1445 if self.s2a_which_mother_figure == 0: 

1446 return True 

1447 if (self.s2a_which_mother_figure == 5 and 

1448 self.s2a_which_mother_figure_other_detail is None): 

1449 return False 

1450 for i in range(1, 16): # not q16 (siblings) 

1451 if getattr(self, "s2a_q" + str(i)) is None: 

1452 return False 

1453 return True 

1454 

1455 def complete_2b(self) -> bool: 

1456 abuse = False 

1457 if self.s2a_which_mother_figure == 0: 

1458 return True 

1459 for i in range(1, 18): 

1460 if getattr(self, "s2b_q" + str(i)) is None: 

1461 return False 

1462 if getattr(self, "s2b_q" + str(i)) != 0: 

1463 abuse = True 

1464 if getattr(self, "s2b_q" + str(i) + "_frequency") is None: 

1465 return False 

1466 if abuse and self.s2b_age_began is None: 

1467 return False 

1468 return True 

1469 

1470 def complete_3a(self): 

1471 if self.s3a_which_father_figure is None: 

1472 return False 

1473 if self.s3a_which_father_figure == 0: 

1474 return True 

1475 if (self.s3a_which_father_figure == 5 and 

1476 self.s3a_which_father_figure_other_detail is None): 

1477 return False 

1478 for i in range(1, 16): # not q16 (siblings) 

1479 if getattr(self, "s3a_q" + str(i)) is None: 

1480 return False 

1481 return True 

1482 

1483 def complete_3b(self) -> bool: 

1484 abuse = False 

1485 if self.s3a_which_father_figure == 0: 

1486 return True 

1487 for i in range(1, 18): 

1488 if getattr(self, "s3b_q" + str(i)) is None: 

1489 return False 

1490 if getattr(self, "s3b_q" + str(i)) != 0: 

1491 abuse = True 

1492 if getattr(self, "s3b_q" + str(i) + "_frequency") is None: 

1493 return False 

1494 if abuse and self.s3b_age_began is None: 

1495 return False 

1496 return True 

1497 

1498 def complete_3c(self) -> bool: 

1499 return self.all_fields_not_none([ 

1500 "s3c_q1", 

1501 "s3c_q2", 

1502 "s3c_q3", 

1503 "s3c_q4", 

1504 "s3c_q5", 

1505 "s3c_q6", 

1506 "s3c_q7", 

1507 "s3c_q8", 

1508 "s3c_q9", 

1509 "s3c_q10", 

1510 "s3c_q11", 

1511 "s3c_q12", 

1512 "s3c_q13", 

1513 "s3c_q14", 

1514 "s3c_q15", 

1515 "s3c_q16", 

1516 "s3c_q17", 

1517 "s3c_which_parent_cared_for", 

1518 "s3c_parent_mental_problem", 

1519 "s3c_parent_physical_problem" 

1520 ]) 

1521 

1522 def complete_4a(self) -> bool: 

1523 if self.s4a_adultconfidant is None: 

1524 return False 

1525 if not self.s4a_adultconfidant: 

1526 return True 

1527 if not self.is_at_least_one_field_true([ 

1528 "s4a_adultconfidant_mother", 

1529 "s4a_adultconfidant_father", 

1530 "s4a_adultconfidant_otherrelative", 

1531 "s4a_adultconfidant_familyfriend", 

1532 "s4a_adultconfidant_responsibleadult", 

1533 "s4a_adultconfidant_other" 

1534 ]): 

1535 return False 

1536 if self.s4a_adultconfidant_other \ 

1537 and not self.s4a_adultconfidant_other_detail: 

1538 return False 

1539 return True 

1540 

1541 def complete_4b(self) -> bool: 

1542 if self.s4b_childconfidant is None: 

1543 return False 

1544 if not self.s4b_childconfidant: 

1545 return True 

1546 if not self.is_at_least_one_field_true([ 

1547 "s4b_childconfidant_sister", 

1548 "s4b_childconfidant_brother", 

1549 "s4b_childconfidant_otherrelative", 

1550 "s4b_childconfidant_closefriend", 

1551 "s4b_childconfidant_otherfriend", 

1552 "s4b_childconfidant_other" 

1553 ]): 

1554 return False 

1555 if self.s4b_childconfidant_other \ 

1556 and not self.s4b_childconfidant_other_detail: 

1557 return False 

1558 return True 

1559 

1560 def complete_4c(self) -> bool: 

1561 n = 0 

1562 if self.s4c_closest_mother: 

1563 n += 1 

1564 if self.s4c_closest_father: 

1565 n += 1 

1566 if self.s4c_closest_sibling: 

1567 n += 1 

1568 if self.s4c_closest_otherrelative: 

1569 n += 1 

1570 if self.s4c_closest_adultfriend: 

1571 n += 1 

1572 if self.s4c_closest_childfriend: 

1573 n += 1 

1574 if self.s4c_closest_other: 

1575 n += 1 

1576 if n < 2: 

1577 return False 

1578 if self.s4c_closest_other and not self.s4c_closest_other_detail: 

1579 return False 

1580 return True 

1581 

1582 def complete_5(self) -> bool: 

1583 if self.s5c_physicalabuse is None: 

1584 return False 

1585 if self.s5c_physicalabuse == 0: 

1586 return True 

1587 if (self.s5c_abused_by_mother is None or 

1588 self.s5c_abused_by_father is None or 

1589 self.s5c_abuse_by_nonparent is None): 

1590 return False 

1591 if self.s5c_abused_by_mother: 

1592 if self.any_fields_none(["s5c_mother_abuse_age_began", 

1593 "s5c_mother_hit_more_than_once", 

1594 "s5c_mother_hit_how", 

1595 "s5c_mother_injured", 

1596 "s5c_mother_out_of_control"]): 

1597 return False 

1598 if self.s5c_abused_by_father: 

1599 if self.any_fields_none(["s5c_father_abuse_age_began", 

1600 "s5c_father_hit_more_than_once", 

1601 "s5c_father_hit_how", 

1602 "s5c_father_injured", 

1603 "s5c_father_out_of_control"]): 

1604 return False 

1605 if (self.s5c_abuse_by_nonparent and 

1606 not self.s5c_nonparent_abuse_description): 

1607 return False 

1608 return True 

1609 

1610 def complete_6(self) -> bool: 

1611 if (self.s6_any_unwanted_sexual_experience is None or 

1612 self.s6_unwanted_intercourse is None or 

1613 self.s6_upsetting_sexual_adult_authority is None): 

1614 return False 

1615 if (self.s6_any_unwanted_sexual_experience == 0 and 

1616 self.s6_unwanted_intercourse == 0 and 

1617 self.s6_upsetting_sexual_adult_authority == 0): 

1618 return True 

1619 if self.any_fields_none(["s6_first_age", 

1620 "s6_first_person_known", 

1621 "s6_first_relative", 

1622 "s6_first_in_household", 

1623 "s6_first_more_than_once", 

1624 "s6_first_touch_privates_subject", 

1625 "s6_first_touch_privates_other", 

1626 "s6_first_intercourse"]): 

1627 return False 

1628 # no checks for "other experience" 

1629 return True 

1630 

1631 # ------------------------------------------------------------------------- 

1632 # Scoring 

1633 # ------------------------------------------------------------------------- 

1634 

1635 def total_sum_abort_if_none(self, fields: List[str]) -> Optional[int]: 

1636 total = 0 

1637 for field in fields: 

1638 value = getattr(self, field) 

1639 if value is None: 

1640 return None 

1641 total += value 

1642 return total 

1643 

1644 def total_nonzero_scores_1_abort_if_none(self, fields: List[str]) \ 

1645 -> Optional[int]: 

1646 total = 0 

1647 for field in fields: 

1648 value = getattr(self, field) 

1649 if value is None: 

1650 return None 

1651 if value: 

1652 total += 1 

1653 return total 

1654 

1655 def parental_loss_risk(self) -> bool: 

1656 return bool( 

1657 self.s1c_mother_died or 

1658 self.s1c_father_died or 

1659 self.s1c_separated_from_mother or 

1660 self.s1c_separated_from_father 

1661 ) 

1662 

1663 def parental_loss_high_risk(self) -> bool: 

1664 return bool( 

1665 self.s1c_separated_from_mother and ( 

1666 self.s1c_mother_separation_reason == 5 or 

1667 self.s1c_mother_separation_reason == 6 

1668 ) or 

1669 self.s1c_separated_from_father and ( 

1670 self.s1c_father_separation_reason == 5 or 

1671 self.s1c_father_separation_reason == 6 

1672 ) 

1673 ) 

1674 

1675 def mother_antipathy(self) -> Optional[int]: 

1676 if self.s2a_which_mother_figure == 0: 

1677 return None 

1678 total = 0 

1679 for i in [1, 4, 6, 8, 9, 10, 11, 16]: 

1680 score = getattr(self, "s2a_q" + str(i)) 

1681 if i == 16 and score is None: 

1682 # Q16 is allowed to be blank (if no siblings) 

1683 score = 0 

1684 if score is None: 

1685 return None 

1686 if i in [8, 11]: 

1687 score = 6 - score # reverse 

1688 total += score 

1689 return total 

1690 

1691 def father_antipathy(self) -> Optional[int]: 

1692 if self.s3a_which_father_figure == 0: 

1693 return None 

1694 total = 0 

1695 for i in [1, 4, 6, 8, 9, 10, 11, 16]: 

1696 score = getattr(self, "s3a_q" + str(i)) 

1697 if i == 16 and score is None: 

1698 # Q16 is allowed to be blank (if no siblings) 

1699 score = 0 

1700 if score is None: 

1701 return None 

1702 if i in [8, 11]: 

1703 score = 6 - score # reverse 

1704 total += score 

1705 return total 

1706 

1707 def mother_neglect(self) -> Optional[int]: 

1708 if self.s2a_which_mother_figure == 0: 

1709 return None 

1710 total = 0 

1711 for i in [2, 3, 5, 7, 12, 13, 14, 15]: 

1712 score = getattr(self, "s2a_q" + str(i)) 

1713 if score is None: 

1714 return None 

1715 if i in [2, 3, 5, 12, 13, 14]: 

1716 score = 6 - score # reverse 

1717 total += score 

1718 return total 

1719 

1720 def father_neglect(self) -> Optional[int]: 

1721 if self.s3a_which_father_figure == 0: 

1722 return None 

1723 total = 0 

1724 for i in [2, 3, 5, 7, 12, 13, 14, 15]: 

1725 score = getattr(self, "s3a_q" + str(i)) 

1726 if score is None: 

1727 return None 

1728 if i in [2, 3, 5, 12, 13, 14]: 

1729 score = 6 - score # reverse 

1730 total += score 

1731 return total 

1732 

1733 def mother_psychological_abuse(self) -> Optional[int]: 

1734 if self.s2a_which_mother_figure == 0: 

1735 return None 

1736 total = 0 

1737 for i in range(1, 18): 

1738 score = getattr(self, "s2b_q" + str(i)) 

1739 if score is None: 

1740 return None 

1741 total += score 

1742 freqscore = getattr(self, "s2b_q" + str(i) + "_frequency") 

1743 if score != 0 and freqscore is None: 

1744 return None 

1745 if freqscore is not None: 

1746 total += freqscore 

1747 return total 

1748 

1749 def father_psychological_abuse(self) -> Optional[int]: 

1750 if self.s3a_which_father_figure == 0: 

1751 return None 

1752 total = 0 

1753 for i in range(1, 18): 

1754 score = getattr(self, "s3b_q" + str(i)) 

1755 if score is None: 

1756 return None 

1757 total += score 

1758 freqscore = getattr(self, "s3b_q" + str(i) + "_frequency") 

1759 if score != 0 and freqscore is None: 

1760 return None 

1761 if freqscore is not None: 

1762 total += freqscore 

1763 return total 

1764 

1765 def role_reversal(self) -> Optional[int]: 

1766 total = 0 

1767 for i in range(1, 18): 

1768 score = getattr(self, "s3c_q" + str(i)) 

1769 if score is None: 

1770 return None 

1771 total += score 

1772 return total 

1773 

1774 def physical_abuse_screen(self) -> Optional[int]: 

1775 fields = [ 

1776 "s5c_physicalabuse" 

1777 ] 

1778 return self.total_nonzero_scores_1_abort_if_none(fields) 

1779 

1780 def physical_abuse_severity_mother(self) -> Optional[int]: 

1781 if self.physical_abuse_screen() == 0: 

1782 return 0 

1783 if self.s5c_abused_by_mother == 0: 

1784 return 0 

1785 mainfields = [ 

1786 "s5c_mother_hit_more_than_once", 

1787 "s5c_mother_injured", 

1788 "s5c_mother_out_of_control" 

1789 ] 

1790 total = self.total_nonzero_scores_1_abort_if_none(mainfields) 

1791 if total is None: 

1792 return None 

1793 if self.s5c_mother_hit_how is None: 

1794 return None 

1795 if self.s5c_mother_hit_how == 1 or self.s5c_mother_hit_how == 2: 

1796 total += 1 

1797 return total 

1798 

1799 def physical_abuse_severity_father(self) -> Optional[int]: 

1800 if self.physical_abuse_screen() == 0: 

1801 return 0 

1802 if self.s5c_abused_by_father == 0: 

1803 return 0 

1804 mainfields = [ 

1805 "s5c_father_hit_more_than_once", 

1806 "s5c_father_injured", 

1807 "s5c_father_out_of_control" 

1808 ] 

1809 total = self.total_nonzero_scores_1_abort_if_none(mainfields) 

1810 if total is None: 

1811 return None 

1812 if self.s5c_father_hit_how is None: 

1813 return None 

1814 if self.s5c_father_hit_how == 1 or self.s5c_father_hit_how == 2: 

1815 total += 1 

1816 return total 

1817 

1818 def sexual_abuse_screen(self) -> Optional[int]: 

1819 fields = [ 

1820 "s6_any_unwanted_sexual_experience", 

1821 "s6_unwanted_intercourse", 

1822 "s6_upsetting_sexual_adult_authority" 

1823 ] 

1824 return self.total_nonzero_scores_1_abort_if_none(fields) 

1825 

1826 def sexual_abuse_score_first(self) -> Optional[int]: 

1827 if self.sexual_abuse_screen() == 0: 

1828 return 0 

1829 fields = [ 

1830 "s6_first_person_known", 

1831 "s6_first_relative", 

1832 "s6_first_in_household", 

1833 "s6_first_more_than_once", 

1834 "s6_first_touch_privates_subject", 

1835 "s6_first_touch_privates_other", 

1836 "s6_first_intercourse" 

1837 ] 

1838 return self.total_nonzero_scores_1_abort_if_none(fields) 

1839 

1840 def sexual_abuse_score_other(self) -> Optional[int]: 

1841 if self.sexual_abuse_screen() == 0: 

1842 return 0 

1843 fields = [ 

1844 "s6_other_person_known", 

1845 "s6_other_relative", 

1846 "s6_other_in_household", 

1847 "s6_other_more_than_once", 

1848 "s6_other_touch_privates_subject", 

1849 "s6_other_touch_privates_other", 

1850 "s6_other_intercourse" 

1851 ] 

1852 return self.total_nonzero_scores_1_abort_if_none(fields) 

1853 

1854 # ------------------------------------------------------------------------- 

1855 # HTML 

1856 # ------------------------------------------------------------------------- 

1857 

1858 def get_task_html(self, req: CamcopsRequest) -> str: 

1859 

1860 def wxstring(wstringname: str) -> str: 

1861 return self.wxstring(req, wstringname) 

1862 

1863 def subheading_from_wstring(wstringname: str) -> str: 

1864 return subheading_from_string(self.wxstring(req, wstringname)) 

1865 

1866 def subsubheading_from_wstring(wstringname: str) -> str: 

1867 return subsubheading_from_string(self.wxstring(req, wstringname)) 

1868 

1869 def wstring_boolean(wstring: str, value: Any) -> str: 

1870 return string_boolean_(req, self.wxstring(req, wstring), value) 

1871 

1872 def wstring_numeric(wstring: str, value: Any) -> str: 

1873 return string_numeric(self.wxstring(req, wstring), value) 

1874 

1875 def wstring_string(wstring: str, value: str) -> str: 

1876 return string_string(self.wxstring(req, wstring), value) 

1877 

1878 def wstring_dict(wstring: str, value: Any, d: Dict) -> str: 

1879 return string_dict(self.wxstring(req, wstring), value, d) 

1880 

1881 def string_boolean(string: str, value: Any) -> str: 

1882 return string_boolean_(req, string, value) 

1883 

1884 separation_map = { 

1885 None: None, 

1886 1: "1 — " + wxstring("1c_separation_reason1"), 

1887 2: "2 — " + wxstring("1c_separation_reason2"), 

1888 3: "3 — " + wxstring("1c_separation_reason3"), 

1889 4: "4 — " + wxstring("1c_separation_reason4"), 

1890 5: "5 — " + wxstring("1c_separation_reason5"), 

1891 6: "6 — " + wxstring("1c_separation_reason6"), 

1892 } 

1893 motherfigure_map = { 

1894 None: None, 

1895 0: "0 — " + wxstring("2a_which_option0"), 

1896 1: "1 — " + wxstring("2a_which_option1"), 

1897 2: "2 — " + wxstring("2a_which_option2"), 

1898 3: "3 — " + wxstring("2a_which_option3"), 

1899 4: "4 — " + wxstring("2a_which_option4"), 

1900 5: "5 — " + wxstring("2a_which_option5"), 

1901 } 

1902 fatherfigure_map = { 

1903 None: None, 

1904 0: "0 — " + wxstring("3a_which_option0"), 

1905 1: "1 — " + wxstring("3a_which_option1"), 

1906 2: "2 — " + wxstring("3a_which_option2"), 

1907 3: "3 — " + wxstring("3a_which_option3"), 

1908 4: "4 — " + wxstring("3a_which_option4"), 

1909 5: "5 — " + wxstring("3a_which_option5"), 

1910 } 

1911 no_yes_5way_map = { 

1912 None: None, 

1913 1: "1 — " + wxstring("options5way_notoyes_1"), 

1914 2: "2 — (between not-at-all and unsure)", 

1915 3: "3 — " + wxstring("options5way_notoyes_3"), 

1916 4: "4 — (between unsure and yes-definitely)", 

1917 5: "5 — " + wxstring("options5way_notoyes_5"), 

1918 } 

1919 no_yes_3way_map = { 

1920 None: None, 

1921 0: "0 — " + wxstring("options3way_noto_yes_0"), 

1922 1: "1 — " + wxstring("options3way_noto_yes_1"), 

1923 2: "2 — " + wxstring("options3way_noto_yes_2"), 

1924 } 

1925 frequency_map = { 

1926 None: None, 

1927 0: "0 — " + wxstring("optionsfrequency0"), 

1928 1: "1 — " + wxstring("optionsfrequency1"), 

1929 2: "2 — " + wxstring("optionsfrequency2"), 

1930 3: "3 — " + wxstring("optionsfrequency3"), 

1931 } 

1932 parent_cared_for_map = { 

1933 None: None, 

1934 0: "0 — " + wxstring("3c_whichparentcaredfor_option0"), 

1935 1: "1 — " + wxstring("3c_whichparentcaredfor_option1"), 

1936 2: "2 — " + wxstring("3c_whichparentcaredfor_option2"), 

1937 3: "3 — " + wxstring("3c_whichparentcaredfor_option3"), 

1938 4: "4 — " + wxstring("3c_whichparentcaredfor_option4"), 

1939 } 

1940 hitting_map = { 

1941 None: None, 

1942 1: "1 — " + wxstring("5_hit_option_1"), 

1943 2: "2 — " + wxstring("5_hit_option_2"), 

1944 3: "3 — " + wxstring("5_hit_option_3"), 

1945 4: "4 — " + wxstring("5_hit_option_4"), 

1946 } 

1947 html = ( 

1948 f""" 

1949 <div class="{CssClass.SUMMARY}"> 

1950 <table class="{CssClass.SUMMARY}"> 

1951 """ + 

1952 self.get_is_complete_tr(req) + 

1953 tr_qa("Parental loss risk factor? <sup>[1]</sup>", 

1954 get_yes_no(req, self.parental_loss_risk())) + 

1955 tr_qa("Parental loss higher risk factor? <sup>[2]</sup>", 

1956 get_yes_no(req, self.parental_loss_high_risk())) + 

1957 tr_qa("Maternal antipathy score (8–40) <sup>[3]</sup>", 

1958 self.mother_antipathy()) + 

1959 tr_qa("Maternal neglect score (8–40) <sup>[3]</sup>", 

1960 self.mother_neglect()) + 

1961 tr_qa("Maternal psychological abuse score (0–85) <sup>[4]</sup>", 

1962 self.mother_psychological_abuse()) + 

1963 tr_qa("Paternal antipathy score (8–40) <sup>[3]</sup>", 

1964 self.father_antipathy()) + 

1965 tr_qa("Paternal neglect score (8–40) <sup>[3]</sup>", 

1966 self.father_neglect()) + 

1967 tr_qa("Paternal psychological abuse score (0–85) <sup>[4]</sup>", 

1968 self.father_psychological_abuse()) + 

1969 tr_qa("Role reversal score (17–85) <sup>[5]</sup>", 

1970 self.role_reversal()) + 

1971 tr_qa("Physical abuse screen (0–1) <sup>[6]</sup>", 

1972 self.physical_abuse_screen()) + 

1973 tr_qa("Maternal physical abuse severity score (0–4) " 

1974 "<sup>[6]</sup>", 

1975 self.physical_abuse_severity_mother()) + 

1976 tr_qa("Paternal physical abuse severity score (0–4) " 

1977 "<sup>[6]</sup>", 

1978 self.physical_abuse_severity_father()) + 

1979 tr_qa("Sexual abuse screen (0–3) <sup>[7]</sup>", 

1980 self.sexual_abuse_screen()) + 

1981 tr_qa("First sexual abuse severity score (0–7) <sup>[7]</sup>", 

1982 self.sexual_abuse_score_first()) + 

1983 tr_qa("Other sexual abuse severity score (0–7) <sup>[7]</sup>", 

1984 self.sexual_abuse_score_other()) + 

1985 f""" 

1986 </table> 

1987 </div> 

1988 <table class="{CssClass.TASKDETAIL}"> 

1989 """ + 

1990 

1991 subheading_spanning_two_columns("1A: " + 

1992 wxstring("1a_q")) + 

1993 subsubheading_from_wstring("1a_motherfigures") + 

1994 wstring_boolean("1a_mf_birthmother", 

1995 self.s1a_motherfigure_birthmother) + 

1996 wstring_boolean("1a_mf_stepmother", 

1997 self.s1a_motherfigure_stepmother) + 

1998 wstring_boolean("1a_mf_femalerelative", 

1999 self.s1a_motherfigure_femalerelative) + 

2000 string_string("(Female relative details)", 

2001 self.s1a_motherfigure_femalerelative_detail) + 

2002 wstring_boolean("1a_mf_familyfriend", 

2003 self.s1a_motherfigure_familyfriend) + 

2004 wstring_boolean("1a_mf_fostermother", 

2005 self.s1a_motherfigure_fostermother) + 

2006 wstring_boolean("1a_mf_adoptivemother", 

2007 self.s1a_motherfigure_adoptivemother) + 

2008 wstring_boolean("other", self.s1a_motherfigure_other) + 

2009 string_string("(Other, details)", 

2010 self.s1a_motherfigure_other_detail) + 

2011 

2012 subsubheading_from_wstring("1a_fatherfigures") + 

2013 wstring_boolean("1a_ff_birthfather", 

2014 self.s1a_fatherfigure_birthfather) + 

2015 wstring_boolean("1a_ff_stepfather", 

2016 self.s1a_fatherfigure_stepfather) + 

2017 wstring_boolean("1a_ff_malerelative", 

2018 self.s1a_fatherfigure_malerelative) + 

2019 string_string("(Male relative details)", 

2020 self.s1a_fatherfigure_malerelative_detail) + 

2021 wstring_boolean("1a_ff_familyfriend", 

2022 self.s1a_fatherfigure_familyfriend) + 

2023 wstring_boolean("1a_ff_fosterfather", 

2024 self.s1a_fatherfigure_fosterfather) + 

2025 wstring_boolean("1a_ff_adoptivefather", 

2026 self.s1a_fatherfigure_adoptivefather) + 

2027 wstring_boolean("other", self.s1a_fatherfigure_other) + 

2028 string_string("(Other, details)", 

2029 self.s1a_fatherfigure_other_detail) + 

2030 

2031 subheading_from_string("1B: " + wxstring("1b_q")) + 

2032 wstring_boolean("1b_q", self.s1b_institution) + 

2033 wstring_numeric("1b_q_how_long", self.s1b_institution_time_years) + 

2034 

2035 subheading_from_string("1C: " + wxstring("1c_heading")) + 

2036 subsubheading_from_wstring("mother") + 

2037 

2038 string_boolean("Mother died before age 17", 

2039 self.s1c_mother_died) + 

2040 wstring_numeric("1c_parentdiedage", 

2041 self.s1c_mother_died_subject_aged) + 

2042 string_boolean("Separated from mother for >1y", 

2043 self.s1c_separated_from_mother) + 

2044 wstring_numeric("1c_age_first_separated", 

2045 self.s1c_first_separated_from_mother_aged) + 

2046 wstring_numeric( 

2047 "1c_how_long_separation", 

2048 self.s1c_mother_how_long_first_separation_years) + 

2049 wstring_dict("1c_separation_reason", 

2050 self.s1c_mother_separation_reason, 

2051 separation_map) + 

2052 

2053 subsubheading_from_wstring("father") + 

2054 string_boolean("Father died before age 17", self.s1c_father_died) + 

2055 wstring_numeric("1c_parentdiedage", 

2056 self.s1c_father_died_subject_aged) + 

2057 string_boolean("Separated from father for >1y", 

2058 self.s1c_separated_from_father) + 

2059 wstring_numeric("1c_age_first_separated", 

2060 self.s1c_first_separated_from_father_aged) + 

2061 wstring_numeric( 

2062 "1c_how_long_separation", 

2063 self.s1c_father_how_long_first_separation_years) + 

2064 wstring_dict("1c_separation_reason", 

2065 self.s1c_father_separation_reason, 

2066 separation_map) + 

2067 wstring_string("please_describe_experience", 

2068 self.s1c_describe_experience) + 

2069 

2070 subheading_from_string("2A: " + wxstring("2a_heading")) + 

2071 wstring_dict("2a_which", 

2072 self.s2a_which_mother_figure, motherfigure_map) + 

2073 wstring_string("rnc_if_other_describe", 

2074 self.s2a_which_mother_figure_other_detail) 

2075 ) 

2076 for i in range(1, 17): 

2077 html += string_dict(str(i) + ". " + wxstring("2a_q" + str(i)), 

2078 getattr(self, "s2a_q" + str(i)), 

2079 no_yes_5way_map) 

2080 html += ( 

2081 wstring_string("2a_add_anything", self.s2a_extra) + 

2082 subheading_from_string("2B: " + wxstring("2b_heading")) 

2083 ) 

2084 for i in range(1, 18): 

2085 html += tr( 

2086 str(i) + ". " + wxstring("2b_q" + str(i)), 

2087 answer(get_from_dict(no_yes_3way_map, 

2088 getattr(self, "s2b_q" + str(i)))) + 

2089 " (" + 

2090 answer(get_from_dict( 

2091 frequency_map, 

2092 getattr(self, "s2b_q" + str(i) + "_frequency"))) + 

2093 ")" 

2094 ) 

2095 html += ( 

2096 wstring_boolean("if_any_what_age", self.s2b_age_began) + 

2097 wstring_string("is_there_more_you_want_to_say", self.s2b_extra) + 

2098 

2099 subheading_from_string("3A: " + wxstring("3a_heading")) + 

2100 wstring_dict("2a_which", 

2101 self.s3a_which_father_figure, fatherfigure_map) + 

2102 wstring_string("rnc_if_other_describe", 

2103 self.s3a_which_father_figure_other_detail) 

2104 ) 

2105 for i in range(1, 17): 

2106 html += string_dict( 

2107 str(i) + ". " + wxstring("3a_q" + str(i)), 

2108 getattr(self, "s3a_q" + str(i)), no_yes_5way_map) 

2109 html += ( 

2110 wstring_string("3a_add_anything", self.s3a_extra) + 

2111 subheading_from_string("3B: " + wxstring("3b_heading")) 

2112 ) 

2113 for i in range(1, 18): 

2114 html += tr( 

2115 str(i) + ". " + wxstring("3b_q" + str(i)), 

2116 answer(get_from_dict(no_yes_3way_map, 

2117 getattr(self, "s3b_q" + str(i)))) + 

2118 " (" + 

2119 answer(get_from_dict( 

2120 frequency_map, 

2121 getattr(self, "s3b_q" + str(i) + "_frequency"))) + 

2122 ")" 

2123 ) 

2124 html += ( 

2125 wstring_boolean("if_any_what_age", self.s3b_age_began) + 

2126 wstring_string("is_there_more_you_want_to_say", self.s3b_extra) + 

2127 subheading_from_string("3C: " + wxstring("3c_heading")) 

2128 ) 

2129 for i in range(1, 18): 

2130 html += string_dict( 

2131 str(i) + ". " + wxstring("3c_q" + str(i)), 

2132 getattr(self, "s3c_q" + str(i)), no_yes_5way_map) 

2133 html += ( 

2134 wstring_dict("3c_which_parent_cared_for", 

2135 self.s3c_which_parent_cared_for, 

2136 parent_cared_for_map) + 

2137 wstring_boolean("3c_parent_mental_problem", 

2138 self.s3c_parent_mental_problem) + 

2139 wstring_boolean("3c_parent_physical_problem", 

2140 self.s3c_parent_physical_problem) + 

2141 

2142 subheading_from_string("4: " + wxstring("4_heading")) + 

2143 subsubheading_from_string("(Adult confidant)") + 

2144 wstring_boolean("4a_q", self.s4a_adultconfidant) + 

2145 subsubheading_from_wstring("4_if_so_who") + 

2146 wstring_boolean("4a_option_mother", 

2147 self.s4a_adultconfidant_mother) + 

2148 wstring_boolean("4a_option_father", 

2149 self.s4a_adultconfidant_father) + 

2150 wstring_boolean("4a_option_relative", 

2151 self.s4a_adultconfidant_otherrelative) + 

2152 wstring_boolean("4a_option_friend", 

2153 self.s4a_adultconfidant_familyfriend) + 

2154 wstring_boolean("4a_option_responsibleadult", 

2155 self.s4a_adultconfidant_responsibleadult) + 

2156 wstring_boolean("4a_option_other", 

2157 self.s4a_adultconfidant_other) + 

2158 string_string("(Other, details)", 

2159 self.s4a_adultconfidant_other_detail) + 

2160 wstring_string("4_note_anything", 

2161 self.s4a_adultconfidant_additional) + 

2162 subsubheading_from_string("(Child confidant)") + 

2163 wstring_boolean("4b_q", self.s4b_childconfidant) + 

2164 subsubheading_from_wstring("4_if_so_who") + 

2165 wstring_boolean("4b_option_sister", 

2166 self.s4b_childconfidant_sister) + 

2167 wstring_boolean("4b_option_brother", 

2168 self.s4b_childconfidant_brother) + 

2169 wstring_boolean("4b_option_relative", 

2170 self.s4b_childconfidant_otherrelative) + 

2171 wstring_boolean("4b_option_closefriend", 

2172 self.s4b_childconfidant_closefriend) + 

2173 wstring_boolean("4b_option_otherfriend", 

2174 self.s4b_childconfidant_otherfriend) + 

2175 wstring_boolean("4b_option_other", 

2176 self.s4b_childconfidant_other) + 

2177 string_string("(Other, details)", 

2178 self.s4b_childconfidant_other_detail) + 

2179 wstring_string("4_note_anything", 

2180 self.s4b_childconfidant_additional) + 

2181 subsubheading_from_wstring("4c_q") + 

2182 wstring_boolean("4c_option_mother", 

2183 self.s4c_closest_mother) + 

2184 wstring_boolean("4c_option_father", 

2185 self.s4c_closest_father) + 

2186 string_boolean("4c_option_sibling", 

2187 self.s4c_closest_sibling) + 

2188 wstring_boolean("4c_option_relative", 

2189 self.s4c_closest_otherrelative) + 

2190 wstring_boolean("4c_option_adultfriend", 

2191 self.s4c_closest_adultfriend) + 

2192 wstring_boolean("4c_option_youngfriend", 

2193 self.s4c_closest_childfriend) + 

2194 wstring_boolean("4c_option_other", self.s4c_closest_other) + 

2195 string_string("(Other, details)", self.s4c_closest_other_detail) + 

2196 wstring_string("4_note_anything", self.s4c_closest_additional) + 

2197 

2198 subheading_from_string("4: " + wxstring("5_heading")) + 

2199 wstring_boolean("5_mainq", self.s5c_physicalabuse) + 

2200 subsubheading_from_wstring("5_motherfigure") + 

2201 wstring_boolean("5_did_this_person_hurt_you", 

2202 self.s5c_abused_by_mother) + 

2203 wstring_numeric("5_how_old", 

2204 self.s5c_mother_abuse_age_began) + 

2205 wstring_boolean("5_hit_more_than_once", 

2206 self.s5c_mother_hit_more_than_once) + 

2207 wstring_dict("5_how_hit", self.s5c_mother_hit_how, hitting_map) + 

2208 wstring_boolean("5_injured", self.s5c_mother_injured) + 

2209 wstring_boolean("5_outofcontrol", self.s5c_mother_out_of_control) + 

2210 subsubheading_from_wstring("5_fatherfigure") + 

2211 wstring_boolean("5_did_this_person_hurt_you", 

2212 self.s5c_abused_by_father) + 

2213 wstring_numeric("5_how_old", self.s5c_father_abuse_age_began) + 

2214 wstring_boolean("5_hit_more_than_once", 

2215 self.s5c_father_hit_more_than_once) + 

2216 wstring_dict("5_how_hit", self.s5c_father_hit_how, hitting_map) + 

2217 wstring_boolean("5_injured", self.s5c_father_injured) + 

2218 wstring_boolean("5_outofcontrol", self.s5c_father_out_of_control) + 

2219 wstring_string("5_can_you_describe_1", 

2220 self.s5c_parental_abuse_description) + 

2221 subsubheading_from_string("(Other in household)") + 

2222 wstring_boolean("5_anyone_else", self.s5c_abuse_by_nonparent) + 

2223 wstring_string("5_can_you_describe_2", 

2224 self.s5c_nonparent_abuse_description) + 

2225 

2226 subheading_from_string("6: " + wxstring("6_heading")) + 

2227 wstring_dict("6_any_unwanted", 

2228 self.s6_any_unwanted_sexual_experience, 

2229 no_yes_3way_map) + 

2230 wstring_dict("6_intercourse", 

2231 self.s6_unwanted_intercourse, no_yes_3way_map) + 

2232 wstring_dict("6_upset_adult_authority", 

2233 self.s6_upsetting_sexual_adult_authority, 

2234 no_yes_3way_map) + 

2235 

2236 subsubheading_from_wstring("6_first_experience") + 

2237 wstring_numeric("6_q1", self.s6_first_age) + 

2238 wstring_boolean("6_q2", self.s6_first_person_known) + 

2239 wstring_boolean("6_q3", self.s6_first_relative) + 

2240 wstring_boolean("6_q4", self.s6_first_in_household) + 

2241 wstring_boolean("6_q5", self.s6_first_more_than_once) + 

2242 wstring_boolean("6_q6", self.s6_first_touch_privates_subject) + 

2243 wstring_boolean("6_q7", self.s6_first_touch_privates_other) + 

2244 wstring_boolean("6_q8", self.s6_first_intercourse) + 

2245 

2246 subsubheading_from_wstring("6_other_experience") + 

2247 wstring_numeric("6_q1", self.s6_other_age) + 

2248 wstring_boolean("6_q2", self.s6_other_person_known) + 

2249 wstring_boolean("6_q3", self.s6_other_relative) + 

2250 wstring_boolean("6_q4", self.s6_other_in_household) + 

2251 wstring_boolean("6_q5", self.s6_other_more_than_once) + 

2252 wstring_boolean("6_q6", self.s6_other_touch_privates_subject) + 

2253 wstring_boolean("6_q7", self.s6_other_touch_privates_other) + 

2254 wstring_boolean("6_q8", self.s6_other_intercourse) + 

2255 wstring_string("5_can_you_describe_1", 

2256 self.s6_unwanted_sexual_description) + 

2257 

2258 subheading_from_wstring("any_other_comments") + 

2259 wstring_string("any_other_comments", self.any_other_comments) + 

2260 

2261 f""" 

2262 </table> 

2263 <div class="{CssClass.FOOTNOTES}"> 

2264 [1] Death of mother/father before age 17 or continuous 

2265 separation of ≥1 year. 

2266 [2] Reason for loss ‘abandonment’ or ‘other’. 

2267 [3] Section 2A and 3A contain antipathy and neglect scales. 

2268 Antipathy scales: reverse items 8, 11; 

2269 then sum 1, 4, 6, 8–11, 16. 

2270 Neglect scales: reverse items 2, 3, 5, 12–14; 

2271 then sum 2, 3, 5, 7, 12–15. 

2272 [4] Psychological abuse scores (sections 2B, 3B): 

2273 sum of items 1–17 (yes=2, unsure=1, no=0) with 

2274 frequencies (never=0, once=1, rarely=2, often=3). 

2275 Any score &gt;1 is a risk indicator. 

2276 [5] Role reversal: sum of scores from section 3C. 

2277 [6] Physical abuse (section 4): first question (screen 

2278 item) is scored 0/1. For each parent, score 1 for 

2279 {{&gt;1 occasion, {{belt/stick/punch/kick}}, injured, 

2280 out-of-control}}. 

2281 [7] Sexual abuse (section 6): no=0, unsure=1, yes=1. 

2282 First three questions are the screen. 

2283 </div> 

2284 """ 

2285 ) 

2286 return html 

2287 

2288 

2289# ============================================================================= 

2290# More helper functions 

2291# ============================================================================= 

2292 

2293def subheading_from_string(s: str) -> str: 

2294 return subheading_spanning_two_columns(s) 

2295 

2296 

2297def subsubheading_from_string(s: str) -> str: 

2298 return f'<tr><td></td><td class="{CssClass.SUBHEADING}">{s}</td></tr>' 

2299 

2300 

2301def row(label: str, value: Any, default: str = "") -> str: 

2302 return tr_qa(label, value, default=default) 

2303 

2304 

2305def string_boolean_(req: CamcopsRequest, string: str, value: Any) -> str: 

2306 return row(string, get_yes_no_none(req, value)) 

2307 

2308 

2309def string_numeric(string: str, value: Any) -> str: 

2310 return row(string, value) 

2311 

2312 

2313def string_string(string: str, value: str) -> str: 

2314 return row(string, ws.webify(value)) 

2315 

2316 

2317def string_dict(string: str, value: Any, d: Dict) -> str: 

2318 return row(string, get_from_dict(d, value))