Le repo des sources pour le site web des JM2L
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

530 lines
24 KiB

  1. # -*- coding: utf8 -*-
  2. from wtforms import Form, BooleanField, TextField, TextAreaField, SelectField
  3. from wtforms import SubmitField, validators, FieldList, PasswordField
  4. #import .ExtWforms
  5. from .ExtWtforms import MySelectField
  6. from wtforms import HiddenField, DecimalField, DateTimeField, FormField, FileField, DateField
  7. from wtforms.validators import ValidationError
  8. from datetime import datetime
  9. strip_filter = lambda x: x.strip() if x else None
  10. from wtforms.csrf.session import SessionCSRF
  11. from datetime import timedelta
  12. class MyBaseForm(Form):
  13. class Meta:
  14. csrf = True
  15. csrf_class = SessionCSRF
  16. csrf_secret = b'lJDQtOAMC2qe89doIn8u3Mch_DgeLSKO'
  17. csrf_time_limit = timedelta(minutes=20)
  18. class BlogCreateForm(MyBaseForm):
  19. title = TextField('Entry title', [validators.Length(min=1, max=255)],
  20. filters=[strip_filter])
  21. body = TextAreaField('Entry body', [validators.Length(min=1)],
  22. filters=[strip_filter])
  23. class BlogUpdateForm(BlogCreateForm):
  24. id = HiddenField()
  25. PLACE_TYPE = [('Aeroport', u'Aéroport'), ('Gare','Gare'), ('JM2L','JM2L'),
  26. ('Hotel',u'Hôtel'), ('Habitant','Habitant'),
  27. ('Restaurant','Restaurant'), ('Autres','Autres')]
  28. TIERS_ROLE = [('Exposant','Exposant'), ('Sponsor','Sponsor'),
  29. ('Donateur','Donateur')]
  30. EVENT_TYPE = ['Stand', 'Table ronde', 'Atelier', 'Concert', 'Conference', 'Repas']
  31. CONF_DURATION = [ (15,u'Lighting talk ( 5 min)'),
  32. (30,u'Conférence (20 min)'),
  33. (60,u'Conférence (50 min)'),
  34. (90,u'Conférence (75 min)'),]
  35. ATELIER_DURATION = [ (15,u'Lighting talk ( 5 min)'),
  36. (30,u'Conférence (20 min)'),
  37. (60,u'Conférence (50 min)'),
  38. (90,u'Conférence (75 min)'),]
  39. class StaffArea(MyBaseForm):
  40. name = TextField(u'Pôle')
  41. description = TextAreaField('Description', [validators.optional(), validators.Length(max=1000000)],
  42. filters=[strip_filter]
  43. )
  44. class EditStaffArea(StaffArea):
  45. uid = HiddenField()
  46. class StaffTasks(MyBaseForm):
  47. name = TextField(u'Nom de la tâche', [validators.Required()])
  48. area_uid = SelectField(u'Pôle concerné', coerce=int )
  49. closed_by = SelectField(u'Assigné à', coerce=int )
  50. due_date = DateField(u'Date prévue', format='%d/%m/%Y')
  51. description = TextAreaField('Description', [validators.optional(), validators.Length(max=1000000)],
  52. filters=[strip_filter])
  53. class EditStaffTasks(StaffTasks):
  54. uid = HiddenField()
  55. class DossPresse(MyBaseForm):
  56. year_uid = HiddenField()
  57. doss_presse = TextAreaField('Dossier de Presse', [validators.optional(), validators.Length(max=1000000)],
  58. filters=[strip_filter])
  59. class TiersMember(MyBaseForm):
  60. class Meta:
  61. csrf = False
  62. year_uid = SelectField(u'Année', coerce=int, choices=zip(range(2006,2016),range(2006,2016)))
  63. user_uid = TextField(u'user')
  64. role = TextField(u'Role')
  65. class TiersRole(MyBaseForm):
  66. class Meta:
  67. csrf = False
  68. year_uid = SelectField(u'Année', coerce=int, choices=zip(range(2006,2016),range(2006,2016)))
  69. tiers_role = SelectField(u'Role', choices=TIERS_ROLE)
  70. class TiersChoice(MyBaseForm):
  71. class Meta:
  72. csrf = False
  73. year_uid = HiddenField()
  74. user_uid = HiddenField()
  75. tiers_uid = TextField(u'Entité')
  76. role = TextField(u'Role')
  77. class AddIntervenant(MyBaseForm):
  78. class Meta:
  79. csrf = False
  80. event_uid = HiddenField()
  81. intervenant = SelectField(u'Intervenant', coerce=int )
  82. class AddTiers(MyBaseForm):
  83. class Meta:
  84. csrf = False
  85. event_uid = HiddenField()
  86. tiers = SelectField(u'Entité', coerce=int )
  87. class ConfCreateForm(MyBaseForm):
  88. event_type = HiddenField()
  89. for_year = HiddenField()
  90. start_time = HiddenField()
  91. end_time = HiddenField()
  92. start_sel = SelectField(u'Début', coerce=int,
  93. description=u"C'est une heure indicative correspondant au mieux à vos préférences "+
  94. u"personnelles. Vous pouvez prendre un créneau horaire déjà réservé si vous avez des contraintes "
  95. u"particulières. L'équipe des JM2L mettra à disposition plus de salle si nécessaire. En cas de conflit,"+
  96. u"l'organisation se réserve le droit de changer la salle et l'heure avec votre accord."
  97. )
  98. duration = SelectField(u'Durée', coerce=int,
  99. description=u"Précisez ici la durée de votre intervention"
  100. )
  101. salle_uid = SelectField(u'Salle', coerce=int,
  102. description=u"Choisissez ici la salle en fonction "
  103. u"du nombres de personnes potentiellement intéressé par votre intervention "+
  104. u"l'organisation se réserve le droit de changer la salle (avec votre accord)."
  105. )
  106. name = TextField(u'Le nom de votre ',
  107. [validators.DataRequired(u'Vous devez spécifier un nom pour votre intérvention'),
  108. validators.Length(min=1, max=80, message='entre 1 et 80 car')],
  109. filters=[strip_filter])
  110. description = TextAreaField(u'Décrivez ici quelques détails à propos de votre intervention ',
  111. [validators.Optional(), validators.Length(max=1000000)],
  112. filters=[strip_filter]
  113. )
  114. class ConfUpdateForm(ConfCreateForm):
  115. uid = HiddenField()
  116. class SalleForm(MyBaseForm):
  117. year_uid = SelectField(u'Année', coerce=int)
  118. phy_salle_id = SelectField('Salle Physique', coerce=int)
  119. place_type = SelectField('Type', choices=[('Conference','Conference'),
  120. ('Stand','Stand'), ('Ateliers','Ateliers'), ('Autres','Autres') ])
  121. name = TextField('Nom de la salle', [validators.Length(min=1, max=40)],
  122. filters=[strip_filter])
  123. description = TextAreaField('Description',
  124. filters=[strip_filter])
  125. class EditSalleForm(SalleForm):
  126. salle_id = HiddenField()
  127. class SallePhyForm(MyBaseForm):
  128. name = TextField('Nom de la salle', [validators.Length(min=1, max=40)],
  129. filters=[strip_filter])
  130. nb_places = TextField('Nombre de places', [validators.Length(max=4)])
  131. description = TextAreaField('Description',
  132. filters=[strip_filter])
  133. class EditSallePhyForm(SallePhyForm):
  134. uid = HiddenField()
  135. class PlaceCreateForm(MyBaseForm):
  136. place_type = SelectField('Type', choices=PLACE_TYPE)
  137. display_name = TextField(u'Nom affiché', [validators.Length(min=1, max=20)],
  138. filters=[strip_filter])
  139. name = TextField('Nom Complet', [validators.Length(min=1, max=80)],
  140. filters=[strip_filter])
  141. gps_coord = TextField(u'Coordonnées GPS', [validators.Length(max=30)],
  142. filters=[strip_filter])
  143. adresse = TextAreaField('Adresse', [validators.Length(max=100)],
  144. filters=[strip_filter])
  145. codePostal = TextField('Code Postal', [validators.Length(max=5)],
  146. filters=[strip_filter])
  147. ville = TextField('Ville', [validators.Length(max=40)],
  148. filters=[strip_filter])
  149. website = TextField('Site Web', [validators.Length(max=100)],
  150. filters=[strip_filter])
  151. description = TextAreaField('Description',
  152. filters=[strip_filter])
  153. created_by = HiddenField()
  154. class PlaceUpdateForm(PlaceCreateForm):
  155. place_id = HiddenField()
  156. def captcha_check(form, field):
  157. if form.meta.csrf_context.get('Captcha')!=field.data:
  158. raise ValidationError(u"la vérification captcha est invalide.")
  159. class UserPasswordForm(MyBaseForm):
  160. uid = HiddenField()
  161. password = PasswordField("Mot de passe",[
  162. validators.Length(max=128, message=u"128 car. maximum"),
  163. validators.required(message=u"Ce champ est obligatoire"),
  164. validators.EqualTo('confirm', message=u'Les password ne sont pas équivalents') ],
  165. filters=[strip_filter]
  166. )
  167. confirm = PasswordField('Confirmez')
  168. class UserRegisterForm(MyBaseForm):
  169. nom = TextField(u'Nom', [
  170. validators.Length(max=80, message=u"80 car. maximum"),
  171. validators.required(message=u"Ce champ est obligatoire") ],
  172. filters=[strip_filter]
  173. )
  174. prenom = TextField(u'Prénom', [
  175. validators.Length(max=80, message=u"80 car. maximum"),
  176. validators.required(message=u"Ce champ est obligatoire"),
  177. validators.Length(max=80)], filters=[strip_filter]
  178. )
  179. mail = TextField(u'Adresse électronique', [
  180. validators.required(message=u"Ce champ est obligatoire"),
  181. validators.Email(message=u"Essayez aussi avec une adresse e-mail valide"),
  182. validators.Length(max=100)],
  183. filters=[strip_filter],
  184. description = u"Une adresse e-mail valide." +
  185. u"Cette adresse ne sera pas rendue publique, "+
  186. u"et ne sera pas divulgué à des tiers."
  187. )
  188. captcha = TextField(u'Captcha', [validators.Length(max=8), captcha_check],
  189. filters=[strip_filter]
  190. )
  191. class ProfilForm(MyBaseForm):
  192. id = HiddenField()
  193. user_id = HiddenField()
  194. nom = TextField(u'Nom', [validators.Length(max=80)],
  195. filters=[strip_filter],
  196. description = u"Les espaces sont autorisés, la ponctuation n'est " +
  197. u"pas autorisée à l'exception des points, traits d'union, " +
  198. u"apostrophes et tirets bas."
  199. )
  200. prenom = TextField(u'Prénom', [validators.Length(max=80)],
  201. filters=[strip_filter],
  202. description = u"Les espaces sont autorisés, la ponctuation n'est " +
  203. u"pas autorisée à l'exception des points, traits d'union, " +
  204. u"apostrophes et tirets bas."
  205. )
  206. pseudo = TextField(u'Pseudo', [validators.Length(max=80)],
  207. filters=[strip_filter],
  208. description = "Votre pseudo d'usage sur la toile."
  209. )
  210. mail = TextField(u'Adresse électronique', [validators.optional(), validators.Email(), validators.Length(max=100)],
  211. filters=[strip_filter],
  212. description = u"Une adresse e-mail valide. Tous les messages de ce système" +
  213. u"seront envoyés à cette adresse. Cette adresse ne sera pas rendue publique,"+
  214. u"et ne sera utilisée que si vous désirez obtenir un nouveau mot de passe ou" +
  215. u"recevoir personnellement certaines nouvelles ou avertissements."
  216. )
  217. phone = TextField(u'Mobile', [validators.optional(), validators.Length(max=10),
  218. validators.Regexp("\d+", message=u"Le numéro de téléphone mobile ne doit contenir que des chiffres")],
  219. filters=[strip_filter],
  220. description = u"Un numéro de mobile valide. Afin de pouvoir rester en" +
  221. u"contact avec les personne de l'organisation, et pour vos échanges. " +
  222. u"Ce numéro ne sera pas publié, et ne sera utilisé que si " +
  223. u"vous désirez recevoir personnellement certaines nouvelles ou alertes."
  224. )
  225. website = TextField(u'Site web', [validators.optional(), validators.URL(), validators.Length(max=100)],
  226. filters=[strip_filter],
  227. description = "Renseignez ici votre site Web."
  228. )
  229. gpg_key = TextAreaField(u'Ma clé GPG',
  230. [validators.optional(), validators.Length(max=9000)],
  231. filters=[strip_filter],
  232. description = u"Vous pouvez insérer votre clé GPG publique pour " +
  233. u"échanger des données sécurisées."
  234. )
  235. soc_link = TextAreaField('Mes autres identifiants',
  236. [validators.optional(), validators.Length(max=1000000)],
  237. filters=[strip_filter],
  238. description = u"Vous pouvez insérer ici d'autres identifiants " +
  239. u"permettant aux autres de vous retrouver sur la toile (IRC, jabber, réseaux sociaux etc)."
  240. )
  241. bio = TextAreaField('Biographie', [validators.optional(), validators.Length(max=1000000)],
  242. filters=[strip_filter]
  243. )
  244. tiersship = FieldList(FormField(TiersChoice))
  245. class DateStartConfidenceForm(MyBaseForm):
  246. ConfidenceLevel = [
  247. ("0",u"exactement à"),
  248. ("1",u"approximativement à"),
  249. ("2",u"à peu près (5 à 15 min) vers"),
  250. ("3",u"à une vache près (1h) vers")
  251. ]
  252. DayChoice = [("4","Jeudi"), ("5","Vendredi"), ("6","Samedi"), ("0","Dimanche"), ("1","Lundi")]
  253. Day = SelectField(u'Jour', choices=DayChoice )
  254. Confidence = SelectField(u'Confiance', choices=ConfidenceLevel)
  255. Hour = TextField(u'Heure', [validators.Length(max=5,
  256. message=u"doit faire au maximum 5 caractères"),
  257. validators.Regexp("\d+:\d+",
  258. message=u"doit être sous la forme HH:MM")],
  259. filters=[strip_filter])
  260. start_time = HiddenField()
  261. class ItineraireForm(Form):
  262. start_place = SelectField(u'En partant de', coerce=int)
  263. arrival_place = SelectField(u'et à destination de', coerce=int)
  264. itin_id = HiddenField()
  265. class AddItineraireForm(Form):
  266. itin = FormField(ItineraireForm)
  267. distance = DecimalField(u'Distance', [validators.Length(min=1, max=4)],
  268. filters=[strip_filter])
  269. duration = DateTimeField(u'Durée', [validators.Length(min=4, max=5)],
  270. filters=[strip_filter])
  271. price = DecimalField(u'Prix approx.', [validators.Length(min=1, max=5)],
  272. filters=[strip_filter])
  273. tr_pied = BooleanField(u'à pied')
  274. tr_velo = BooleanField(u'à vélo')
  275. tr_moto = BooleanField(u'à moto')
  276. tr_voiture = BooleanField(u'en voiture')
  277. tr_taxi = BooleanField(u'en taxi')
  278. tr_bus = BooleanField(u'en bus')
  279. tr_avion = BooleanField(u'en avion')
  280. description = TextAreaField(u'Description de l\'itinéraire')
  281. class AddMember(MyBaseForm):
  282. tiers_uid = HiddenField()
  283. nom = TextField(u'Nom', [validators.Length(max=80)],
  284. filters=[strip_filter],
  285. description = u"Les espaces sont autorisés, la ponctuation n'est " +
  286. u"pas autorisée à l'exception des points, traits d'union, " +
  287. u"apostrophes et tirets bas."
  288. )
  289. prenom = TextField(u'Prénom', [validators.Length(max=80)],
  290. filters=[strip_filter],
  291. description = u"Les espaces sont autorisés, la ponctuation n'est " +
  292. u"pas autorisée à l'exception des points, traits d'union, " +
  293. u"apostrophes et tirets bas."
  294. )
  295. email = TextField(u'Email', [validators.required(),
  296. validators.length(max=10),
  297. validators.Email(message='Ceci ne ressemble pas à une adresse valide')],
  298. description=u"Afin d'éviter la duplication d'information et les doublons inutile, "+
  299. u"pensez d'abord à lui demander de confirmer le mail qu'il a utilisé lors de "+
  300. u"son inscription sur le site.")
  301. add = SubmitField('Ajouter des membres')
  302. class TiersForm(MyBaseForm):
  303. name = TextField(u'Nom', [validators.Length(max=100)],
  304. filters=[strip_filter],
  305. description = u"Les espaces sont autorisés, la ponctuation n'est " +
  306. u"pas autorisée à l'exception des points, traits d'union, " +
  307. u"apostrophes et tirets bas."
  308. )
  309. tiers_type = MySelectField('Nature', coerce=int)
  310. website = TextField(u'Site web', [validators.optional(), validators.URL(), validators.Length(max=100)],
  311. filters=[strip_filter],
  312. description = "Renseignez ici le site Web."
  313. )
  314. description = TextAreaField('Descriptif',
  315. [validators.optional(), validators.Length(max=1000000)],
  316. filters=[strip_filter],
  317. description = u"Vous pouvez insérer les détails"
  318. )
  319. membership = FieldList(FormField(TiersMember))
  320. roles = FieldList(FormField(TiersRole))
  321. class UpdateTiersForm(TiersForm):
  322. uid = HiddenField()
  323. tiers_id = HiddenField()
  324. class ExchCateg(MyBaseForm):
  325. exch_type = HiddenField()
  326. exch_subtype = TextField(u'Catégorie', [validators.Length(max=80)],
  327. filters=[strip_filter],
  328. description = "Le nom de la categorie"
  329. )
  330. description = TextAreaField('Description',
  331. filters=[strip_filter])
  332. class UpdateExchangeForm(MyBaseForm):
  333. exch_id = HiddenField()
  334. class AskCForm(ItineraireForm):
  335. ConfidenceLevel = [
  336. ("0",u"exactement à"),
  337. ("1",u"approximativement à"),
  338. ("2",u"à peu près (5 à 15 min) vers"),
  339. ("3",u"à une vache près (1h) vers")
  340. ]
  341. DayChoice = [("4","Jeudi"), ("5","Vendredi"), ("6","Samedi"), ("0","Dimanche"), ("1","Lundi")]
  342. Day_start = SelectField(u'Jour', choices=DayChoice )
  343. Confidence = SelectField(u'Confiance', choices=ConfidenceLevel)
  344. Hour_start = TextField(u'Heure', [validators.Length(max=5,
  345. message=u"doit faire au maximum 5 caractères"),
  346. validators.Regexp("\d+:\d+",
  347. message=u"doit être sous la forme HH:MM")],
  348. filters=[strip_filter])
  349. start_time = HiddenField()
  350. start_place = SelectField(u'En partant de', coerce=int)
  351. arrival_place = SelectField(u'et à destination de', coerce=int)
  352. itin_id = HiddenField()
  353. class AskHForm(MyBaseForm):
  354. DayChoice = [("4",u"Jeudi à Vendredi"), ("5",u"Vendredi à Samedi"), ("6",u"Samedi à Dimanche"), ("0",u"Dimanche à Lundi")]
  355. Day_start = SelectField(u'Pour la nuit de', choices=DayChoice )
  356. start_time = HiddenField()
  357. description = TextAreaField(u'Description de vos contraintes éventuelles', filters=[strip_filter],
  358. description = u"Décrivez ici vos souhaits et éventuellement "
  359. + u"les contraintes à prendre en compte. N'hésitez pas à donner des détails."
  360. )
  361. class AskMForm(MyBaseForm):
  362. DayChoice = [("4","Jeudi"), ("5","Vendredi"), ("6","Samedi"), ("0","Dimanche"), ("1","Lundi")]
  363. Day_start = SelectField(u"à partir de", choices=DayChoice )
  364. Hour_start = TextField(u'vers', [validators.Length(max=5,
  365. message=u"doit faire au maximum 5 caractères"),
  366. validators.Regexp("\d+:\d+",
  367. message=u"doit être sous la forme HH:MM")],
  368. filters=[strip_filter])
  369. start_time = HiddenField()
  370. Day_end = SelectField(u"Jusqu'à", choices=DayChoice )
  371. Hour_end = TextField(u'vers', [validators.Length(max=5,
  372. message=u"doit faire au maximum 5 caractères"),
  373. validators.Regexp("\d+:\d+",
  374. message=u"doit être sous la forme HH:MM")],
  375. filters=[strip_filter])
  376. end_time = HiddenField()
  377. exch_categ = SelectField(u'Catégorie de matériel', coerce=int,
  378. description = u"Choisissez une catégorie de bien"
  379. )
  380. description = TextAreaField(u'Description du bien', filters=[strip_filter],
  381. description = u"Décrivez ici les biens que vous souhaitez"
  382. + u"échanger. N'hésitez pas à donner des détails."
  383. )
  384. class PropCForm(ItineraireForm):
  385. ConfidenceLevel = [
  386. ("0",u"exactement à"),
  387. ("1",u"approximativement à"),
  388. ("2",u"à peu près (5 à 15 min) vers"),
  389. ("3",u"à une vache près (1h) vers")
  390. ]
  391. DayChoice = [("4","Jeudi"), ("5","Vendredi"), ("6","Samedi"), ("0","Dimanche"), ("1","Lundi")]
  392. Day_start = SelectField(u'Jour', choices=DayChoice )
  393. Confidence = SelectField(u'Confiance', choices=ConfidenceLevel)
  394. Hour_start = TextField(u'Heure', [validators.Length(max=5,
  395. message=u"doit faire au maximum 5 caractères"),
  396. validators.Regexp("\d+:\d+",
  397. message=u"doit être sous la forme HH:MM")],
  398. filters=[strip_filter])
  399. start_time = HiddenField()
  400. start_place = SelectField(u'En partant de', coerce=int)
  401. arrival_place = SelectField(u'et à destination de', coerce=int)
  402. itin_id = HiddenField()
  403. class PropHForm(MyBaseForm):
  404. DayChoice = [("4",u"Jeudi à Vendredi"), ("5",u"Vendredi à Samedi"), ("6",u"Samedi à Dimanche"), ("0",u"Dimanche à Lundi")]
  405. Day_start = SelectField(u'Pour la nuit de', choices=DayChoice )
  406. start_time = HiddenField()
  407. exch_categ = SelectField(u'Type de couchage', coerce=int,
  408. description = u"Indiquez ici le type de couchage proposé")
  409. description = TextAreaField(u'Quelques mots autour du logement que vous proposez', filters=[strip_filter],
  410. description = u"Décrivez ici quelques détails sur le logement que vous souhaitez "
  411. + u"proposer, les contraintes à prendre en compte. N'hésitez pas à donner des détails."
  412. )
  413. place_id = SelectField(u'Emplacement', coerce=int,
  414. description = u"Indiquez ici une des adresses que vous avez proposé")
  415. class PropMForm(MyBaseForm):
  416. DayChoice = [("4","Jeudi"), ("5","Vendredi"), ("6","Samedi"), ("0","Dimanche"), ("1","Lundi")]
  417. Day_start = SelectField(u"à partir de", choices=DayChoice )
  418. Hour_start = TextField(u'vers', [validators.Length(max=5,
  419. message=u"doit faire au maximum 5 caractères"),
  420. validators.Regexp("\d+:\d+",
  421. message=u"doit être sous la forme HH:MM")],
  422. filters=[strip_filter])
  423. start_time = HiddenField()
  424. Day_end = SelectField(u"Jusqu'a ", choices=DayChoice )
  425. Hour_end = TextField(u'vers', [validators.Length(max=5,
  426. message=u"doit faire au maximum 5 caractères"),
  427. validators.Regexp("\d+:\d+",
  428. message=u"doit être sous la forme HH:MM")],
  429. filters=[strip_filter])
  430. end_time = HiddenField()
  431. exch_categ = SelectField(u'Catégorie de matériel', coerce=int,
  432. description = u"Choisissez une catégorie de bien matériel"
  433. )
  434. description = TextAreaField(u'Ajoutez quelques mots autour du matériel que vous proposez', filters=[strip_filter],
  435. description = u"Décrivez ici quelques détails sur le matériel que vous souhaitez "
  436. + u"proposer. N'hésitez pas à donner des détails."
  437. )
  438. class UpdateAskCForm(AskCForm, UpdateExchangeForm):
  439. pass
  440. class UpdateAskHForm(AskHForm, UpdateExchangeForm):
  441. pass
  442. class UpdateAskMForm(AskMForm, UpdateExchangeForm):
  443. pass
  444. class UpdatePropCForm(PropCForm, UpdateExchangeForm):
  445. pass
  446. class UpdatePropHForm(PropHForm, UpdateExchangeForm):
  447. pass
  448. class UpdatePropMForm(PropMForm, UpdateExchangeForm):
  449. pass