This commit is contained in:
2026-05-27 15:27:38 +02:00
parent 23aa4b7fe7
commit 93de82256a
50 changed files with 17314 additions and 18 deletions
+9
View File
@@ -0,0 +1,9 @@
{
"mcpServers": {
"janssen-mongo": {
"command": "python",
"args": ["U:\\PythonProject\\Janssen\\mcp_mongo.py"],
"cwd": "U:\\PythonProject\\Janssen"
}
}
}
@@ -0,0 +1,38 @@
"Protocol","Study Population","Country","Site","Principal Investigator","Participant ID","Baseline Stool Frequency","Visit","Visit Date","Endoscopy Completed?","Endoscopy Date","Bowel Preparation Start Date 1","Bowel Preparation End Date 1","Bowel Preparation Start Date 2","Bowel Preparation End Date 2","Central Endoscopy Score","Local Endoscopy Score","PGA Score","Eligible Day (-1)","Day (-1) Excluded Reason(s)","Eligible Day (-2)","Day (-2) Excluded Reason(s)","Eligible Day (-3)","Day (-3) Excluded Reason(s)","Eligible Day (-4)","Day (-4) Excluded Reason(s)","Eligible Day (-5)","Day (-5) Excluded Reason(s)","Eligible Day (-6)","Day (-6) Excluded Reason(s)","Eligible Day (-7)","Day (-7) Excluded Reason(s)","Eligible Day (-8)","Day (-8) Excluded Reason(s)","Eligible Day (-9)","Day (-9) Excluded Reason(s)","Eligible Day (-10)","Day (-10) Excluded Reason(s)","Eligible Day (-1) Stool Count","Eligible Day (-2) Stool Count","Eligible Day (-3) Stool Count","Eligible Day (-4) Stool Count","Eligible Day (-5) Stool Count","Eligible Day (-6) Stool Count","Eligible Day (-7) Stool Count","Eligible Day (-8) Stool Count","Eligible Day (-9) Stool Count","Eligible Day (-10) Stool Count","Stool Frequency Sub-score","Eligible Day (-1) Rectal Bleeding Score","Eligible Day (-2) Rectal Bleeding Score","Eligible Day (-3) Rectal Bleeding Score","Eligible Day (-4) Rectal Bleeding Score","Eligible Day (-5) Rectal Bleeding Score","Eligible Day (-6) Rectal Bleeding Score","Eligible Day (-7) Rectal Bleeding Score","Eligible Day (-8) Rectal Bleeding Score","Eligible Day (-9) Rectal Bleeding Score","Eligible Day (-10) Rectal Bleeding Score","Rectal Bleeding Sub-score","Partial Mayo Score","Modified Mayo Score","Full Mayo Score","Site Action","Last Mayo Score Submission","Week I-12 Clinical Responder","Week I-12 Clinical Remission","Clinical Flare","Loss of Response","Partial Mayo Response Post Loss of Response","Partial Mayo Response for Clinical Non-Responders"
"77242113UCO3001","Adult","Czech Republic","DD5-CZ10001","Matej Falc","CZ100012001","1","I-0","19 Feb 2026","Yes","05 Feb 2026","04 Feb 2026","04 Feb 2026","-","-","2","-","3","18 Feb 2026","-","17 Feb 2026","-","16 Feb 2026","-","15 Feb 2026","-","14 Feb 2026","-","13 Feb 2026","-","12 Feb 2026","-","11 Feb 2026","Day Not Applicable for Calculation","10 Feb 2026","Day Not Applicable for Calculation","09 Feb 2026","Day Not Applicable for Calculation","10","8","7","5","7","8","8","-","-","-","3","1","1","1","0","1","1","1","-","-","-","1","7","6","9","-","08 Apr 2026 07:11:25","N/A","N/A","N/A","N/A","N/A","N/A"
"77242113UCO3001","Adult","Czech Republic","DD5-CZ10001","Matej Falc","CZ100012001","1","I-2","04 Mar 2026","-","-","-","-","-","-","-","-","3","03 Mar 2026","-","02 Mar 2026","-","01 Mar 2026","-","28 Feb 2026","-","27 Feb 2026","-","26 Feb 2026","-","25 Feb 2026","-","24 Feb 2026","Day Not Applicable for Calculation","23 Feb 2026","Day Not Applicable for Calculation","22 Feb 2026","Day Not Applicable for Calculation","5","4","5","4","5","6","6","-","-","-","2","1","0","1","0","1","0","1","-","-","-","1","6","","","-","-","N/A","N/A","N/A","N/A","N/A","N/A"
"77242113UCO3001","Adult","Czech Republic","DD5-CZ10001","Matej Falc","CZ100012001","1","I-4","18 Mar 2026","-","-","-","-","-","-","-","-","2","17 Mar 2026","-","16 Mar 2026","-","15 Mar 2026","-","14 Mar 2026","-","13 Mar 2026","-","12 Mar 2026","-","11 Mar 2026","-","10 Mar 2026","Day Not Applicable for Calculation","09 Mar 2026","Day Not Applicable for Calculation","08 Mar 2026","Day Not Applicable for Calculation","5","5","5","4","5","4","5","-","-","-","2","1","0","0","1","1","1","0","-","-","-","1","5","","","-","08 Apr 2026 07:11:43","N/A","N/A","N/A","N/A","N/A","N/A"
"77242113UCO3001","Adult","Czech Republic","DD5-CZ10001","Matej Falc","CZ100012001","1","I-8","05 May 2026","-","-","-","-","-","-","-","-","1","04 May 2026","-","03 May 2026","-","02 May 2026","-","01 May 2026","-","30 Apr 2026","-","29 Apr 2026","-","28 Apr 2026","-","27 Apr 2026","Day Not Applicable for Calculation","26 Apr 2026","Day Not Applicable for Calculation","25 Apr 2026","Day Not Applicable for Calculation","3","3","4","4","5","4","4","-","-","-","2","1","1","1","1","1","1","1","-","-","-","1","4","","","-","-","N/A","N/A","N/A","N/A","N/A","N/A"
"77242113UCO3001","Adult","Czech Republic","DD5-CZ10001","Matej Falc","CZ100012001","1","I-12","13 May 2026","Yes","06 May 2026","05 May 2026","05 May 2026","-","-","1","-","1","12 May 2026","-","11 May 2026","-","10 May 2026","-","09 May 2026","-","08 May 2026","-","07 May 2026","-","06 May 2026","Endoscopy","05 May 2026","Bowel Preparation for Procedure;Day Not Applicable for Calculation","04 May 2026","-","03 May 2026","Day Not Applicable for Calculation","5","4","6","5","5","5","-","-","3","-","2","1","0","1","1","1","1","-","-","1","-","1","4","4","5","-","-","Clinical Responder","No","N/A","N/A","N/A","N/A"
"77242113UCO3001","Adult","Czech Republic","DD5-CZ10001","Matej Falc","CZ100012002","1","I-0","08 Apr 2026","Yes","18 Mar 2026","17 Mar 2026","18 Mar 2026","-","-","2","-","2","07 Apr 2026","-","06 Apr 2026","-","05 Apr 2026","-","04 Apr 2026","Missing Diary","03 Apr 2026","-","02 Apr 2026","-","01 Apr 2026","-","31 Mar 2026","Day Not Applicable for Calculation","30 Mar 2026","Day Not Applicable for Calculation","29 Mar 2026","Day Not Applicable for Calculation","3","3","4","-","3","3","4","-","-","-","1","0","0","0","-","0","0","1","-","-","-","0","3","3","5","-","-","N/A","N/A","N/A","N/A","N/A","N/A"
"77242113UCO3001","Adult","Czech Republic","DD5-CZ10001","Matej Falc","CZ100012002","1","I-2","23 Apr 2026","-","-","-","-","-","-","-","-","2","22 Apr 2026","Missing Diary","21 Apr 2026","-","20 Apr 2026","-","19 Apr 2026","-","18 Apr 2026","-","17 Apr 2026","-","16 Apr 2026","-","15 Apr 2026","Day Not Applicable for Calculation","14 Apr 2026","Day Not Applicable for Calculation","13 Apr 2026","Day Not Applicable for Calculation","-","3","3","6","5","5","4","-","-","-","2","-","0","0","1","1","1","1","-","-","-","1","5","","","-","-","N/A","N/A","N/A","N/A","N/A","N/A"
"77242113UCO3001","Adult","Czech Republic","DD5-CZ10001","Matej Falc","CZ100012002","1","I-4","06 May 2026","-","-","-","-","-","-","-","-","1","05 May 2026","-","04 May 2026","-","03 May 2026","-","02 May 2026","-","01 May 2026","-","30 Apr 2026","-","29 Apr 2026","-","28 Apr 2026","Day Not Applicable for Calculation","27 Apr 2026","Day Not Applicable for Calculation","26 Apr 2026","Day Not Applicable for Calculation","6","3","2","3","3","3","3","-","-","-","1","1","0","0","0","1","1","0","-","-","-","0","2","","","-","-","N/A","N/A","N/A","N/A","N/A","N/A"
"77242113UCO3001","Adult","Czech Republic","DD5-CZ10001","Matej Falc","CZ100012003","1","I-0","27 May 2026","Yes","13 May 2026","12 May 2026","12 May 2026","-","-","3","-","2","26 May 2026","-","25 May 2026","-","24 May 2026","-","23 May 2026","-","22 May 2026","-","21 May 2026","-","20 May 2026","-","19 May 2026","Day Not Applicable for Calculation","18 May 2026","Day Not Applicable for Calculation","17 May 2026","Day Not Applicable for Calculation","6","9","7","8","9","7","8","-","-","-","3","2","2","2","2","1","1","1","-","-","-","2","7","8","10","-","27 May 2026 07:24:39","N/A","N/A","N/A","N/A","N/A","N/A"
"77242113UCO3001","Adult","Czech Republic","DD5-CZ10006","Michal Konecny","CZ100062001","1","I-0","20 Mar 2026","Yes","19 Feb 2026","-","-","-","-","3","-","3","19 Mar 2026","-","18 Mar 2026","-","17 Mar 2026","-","16 Mar 2026","-","15 Mar 2026","-","14 Mar 2026","-","13 Mar 2026","-","12 Mar 2026","Day Not Applicable for Calculation","11 Mar 2026","Day Not Applicable for Calculation","10 Mar 2026","Day Not Applicable for Calculation","7","7","8","8","7","8","5","-","-","-","3","2","1","1","1","1","1","0","-","-","-","1","7","7","10","-","20 Mar 2026 07:02:44","N/A","N/A","N/A","N/A","N/A","N/A"
"77242113UCO3001","Adult","Czech Republic","DD5-CZ10006","Michal Konecny","CZ100062001","1","I-2","08 Apr 2026","-","-","-","-","-","-","-","-","2","07 Apr 2026","Medication For Diarrhea","06 Apr 2026","Medication For Diarrhea","05 Apr 2026","Medication For Diarrhea","04 Apr 2026","Medication For Diarrhea","03 Apr 2026","Medication For Diarrhea","02 Apr 2026","Medication For Diarrhea","01 Apr 2026","Medication For Diarrhea","31 Mar 2026","Medication For Diarrhea;Day Not Applicable for Calculation","30 Mar 2026","Medication For Diarrhea;Day Not Applicable for Calculation","29 Mar 2026","Day Not Applicable for Calculation","-","-","-","-","-","-","-","-","-","-","Non-Evaluable","-","-","-","-","-","-","-","-","-","-","Non-Evaluable","Non-Evaluable","Non-Evaluable","Non-Evaluable","-","-","N/A","N/A","N/A","N/A","N/A","N/A"
"77242113UCO3001","Adult","Czech Republic","DD5-CZ10006","Michal Konecny","CZ100062001","1","I-4","15 Apr 2026","-","-","-","-","-","-","-","-","3","14 Apr 2026","-","13 Apr 2026","-","12 Apr 2026","-","11 Apr 2026","-","10 Apr 2026","-","09 Apr 2026","-","08 Apr 2026","-","07 Apr 2026","Medication For Diarrhea;Day Not Applicable for Calculation","06 Apr 2026","Medication For Diarrhea;Day Not Applicable for Calculation","05 Apr 2026","Medication For Diarrhea;Day Not Applicable for Calculation","9","22","20","19","17","18","18","-","-","-","3","1","3","2","2","2","2","2","-","-","-","2","8","","","-","04 May 2026 22:06:47","N/A","N/A","N/A","N/A","N/A","N/A"
"77242113UCO3001","Adult","Czech Republic","DD5-CZ10006","Michal Konecny","CZ100062001","1","I-8","18 May 2026","-","-","-","-","-","-","-","-","2","17 May 2026","-","16 May 2026","-","15 May 2026","-","14 May 2026","-","13 May 2026","-","12 May 2026","-","11 May 2026","-","10 May 2026","Day Not Applicable for Calculation","09 May 2026","Day Not Applicable for Calculation","08 May 2026","Day Not Applicable for Calculation","7","5","9","7","7","8","8","-","-","-","3","1","1","1","1","1","1","1","-","-","-","1","6","","","-","-","N/A","N/A","N/A","N/A","N/A","N/A"
"77242113UCO3001","Adult","Czech Republic","DD5-CZ10006","Michal Konecny","CZ100062002","1","I-0","26 May 2026","Yes","14 May 2026","13 May 2026","13 May 2026","-","-","2","-","2","25 May 2026","-","24 May 2026","-","23 May 2026","-","22 May 2026","-","21 May 2026","-","20 May 2026","-","19 May 2026","-","18 May 2026","Day Not Applicable for Calculation","17 May 2026","Day Not Applicable for Calculation","16 May 2026","Day Not Applicable for Calculation","8","8","6","7","7","6","7","-","-","-","3","2","2","2","2","2","2","2","-","-","-","2","7","7","9","-","-","N/A","N/A","N/A","N/A","N/A","N/A"
"77242113UCO3001","Adult","Czech Republic","DD5-CZ10009","Jiri Pumprla","CZ100092001","1","I-0","05 May 2026","Yes","24 Apr 2026","23 Apr 2026","23 Apr 2026","-","-","2","-","2","04 May 2026","-","03 May 2026","-","02 May 2026","-","01 May 2026","-","30 Apr 2026","-","29 Apr 2026","-","28 Apr 2026","-","27 Apr 2026","Day Not Applicable for Calculation","26 Apr 2026","Day Not Applicable for Calculation","25 Apr 2026","Day Not Applicable for Calculation","5","5","5","5","5","5","5","-","-","-","2","1","1","1","1","1","1","1","-","-","-","1","5","5","7","-","05 May 2026 11:19:40","N/A","N/A","N/A","N/A","N/A","N/A"
"77242113UCO3001","Adult","Czech Republic","DD5-CZ10009","Jiri Pumprla","CZ100092001","1","I-2","19 May 2026","-","-","-","-","-","-","-","-","1","18 May 2026","-","17 May 2026","-","16 May 2026","-","15 May 2026","-","14 May 2026","-","13 May 2026","-","12 May 2026","-","11 May 2026","Day Not Applicable for Calculation","10 May 2026","Day Not Applicable for Calculation","09 May 2026","Day Not Applicable for Calculation","5","4","5","5","5","4","6","-","-","-","2","1","1","1","1","1","1","1","-","-","-","1","4","","","-","19 May 2026 10:38:25","N/A","N/A","N/A","N/A","N/A","N/A"
"77242113UCO3001","Adult","Czech Republic","DD5-CZ10012","Stefan Konecny","CZ100122001","5","I-0","07 Apr 2026","Yes","24 Mar 2026","22 Mar 2026","22 Mar 2026","-","-","2","-","2","06 Apr 2026","-","05 Apr 2026","-","04 Apr 2026","-","03 Apr 2026","-","02 Apr 2026","-","01 Apr 2026","-","31 Mar 2026","-","30 Mar 2026","Day Not Applicable for Calculation","29 Mar 2026","Day Not Applicable for Calculation","28 Mar 2026","Day Not Applicable for Calculation","8","11","5","9","11","10","13","-","-","-","3","1","2","2","2","2","2","2","-","-","-","2","7","7","9","-","04 May 2026 08:44:52","N/A","N/A","N/A","N/A","N/A","N/A"
"77242113UCO3001","Adult","Czech Republic","DD5-CZ10012","Stefan Konecny","CZ100122001","5","I-2","22 Apr 2026","-","-","-","-","-","-","-","-","2","21 Apr 2026","-","20 Apr 2026","-","19 Apr 2026","-","18 Apr 2026","-","17 Apr 2026","-","16 Apr 2026","-","15 Apr 2026","-","14 Apr 2026","Day Not Applicable for Calculation","13 Apr 2026","Day Not Applicable for Calculation","12 Apr 2026","Day Not Applicable for Calculation","7","5","6","6","7","8","2","-","-","-","1","1","0","1","1","1","2","0","-","-","-","1","4","","","-","04 May 2026 08:45:07","N/A","N/A","N/A","N/A","N/A","N/A"
"77242113UCO3001","Adult","Czech Republic","DD5-CZ10012","Stefan Konecny","CZ100122001","5","I-4","07 May 2026","-","-","-","-","-","-","-","-","1","06 May 2026","-","05 May 2026","-","04 May 2026","-","03 May 2026","-","02 May 2026","-","01 May 2026","-","30 Apr 2026","-","29 Apr 2026","Day Not Applicable for Calculation","28 Apr 2026","Day Not Applicable for Calculation","27 Apr 2026","Day Not Applicable for Calculation","8","7","7","8","4","11","7","-","-","-","1","2","1","1","1","0","1","1","-","-","-","1","3","","","-","-","N/A","N/A","N/A","N/A","N/A","N/A"
"77242113UCO3001","Adult","Czech Republic","DD5-CZ10013","David Stepek","CZ100132001","1","I-0","24 Mar 2026","Yes","12 Mar 2026","11 Mar 2026","11 Mar 2026","-","-","2","-","2","23 Mar 2026","-","22 Mar 2026","-","21 Mar 2026","-","20 Mar 2026","-","19 Mar 2026","-","18 Mar 2026","-","17 Mar 2026","-","16 Mar 2026","Day Not Applicable for Calculation","15 Mar 2026","Day Not Applicable for Calculation","14 Mar 2026","Day Not Applicable for Calculation","8","6","5","7","6","7","6","-","-","-","3","1","1","1","0","1","1","1","-","-","-","1","6","6","8","-","05 Apr 2026 22:41:27","N/A","N/A","N/A","N/A","N/A","N/A"
"77242113UCO3001","Adult","Czech Republic","DD5-CZ10013","David Stepek","CZ100132001","1","I-2","08 Apr 2026","-","-","-","-","-","-","-","-","2","07 Apr 2026","-","06 Apr 2026","-","05 Apr 2026","-","04 Apr 2026","-","03 Apr 2026","-","02 Apr 2026","-","01 Apr 2026","-","31 Mar 2026","Day Not Applicable for Calculation","30 Mar 2026","Day Not Applicable for Calculation","29 Mar 2026","Day Not Applicable for Calculation","5","2","3","6","5","5","5","-","-","-","2","0","0","0","0","1","1","0","-","-","-","0","4","","","-","27 May 2026 12:53:52","N/A","N/A","N/A","N/A","N/A","N/A"
"77242113UCO3001","Adult","Czech Republic","DD5-CZ10013","David Stepek","CZ100132001","1","I-4","21 Apr 2026","-","-","-","-","-","-","-","-","0","20 Apr 2026","-","19 Apr 2026","-","18 Apr 2026","-","17 Apr 2026","-","16 Apr 2026","-","15 Apr 2026","-","14 Apr 2026","-","13 Apr 2026","Day Not Applicable for Calculation","12 Apr 2026","Day Not Applicable for Calculation","11 Apr 2026","Day Not Applicable for Calculation","4","3","4","3","3","4","4","-","-","-","2","0","0","0","0","0","0","0","-","-","-","0","2","","","-","27 May 2026 12:54:41","N/A","N/A","N/A","N/A","N/A","N/A"
"77242113UCO3001","Adult","Czech Republic","DD5-CZ10013","David Stepek","CZ100132002","1","I-0","12 May 2026","Yes","21 Apr 2026","20 Apr 2026","21 Apr 2026","-","-","2","-","2","11 May 2026","-","10 May 2026","-","09 May 2026","-","08 May 2026","-","07 May 2026","-","06 May 2026","-","05 May 2026","Missing Diary","04 May 2026","Day Not Applicable for Calculation","03 May 2026","Day Not Applicable for Calculation","02 May 2026","Day Not Applicable for Calculation","2","1","1","1","1","2","-","-","-","-","0","0","0","0","0","0","0","-","-","-","-","0","2","2","4","-","-","N/A","N/A","N/A","N/A","N/A","N/A"
"77242113UCO3001","Adult","Czech Republic","DD5-CZ10013","David Stepek","CZ100132002","1","I-2","26 May 2026","-","-","-","-","-","-","-","-","1","25 May 2026","-","24 May 2026","Missing Diary","23 May 2026","-","22 May 2026","-","21 May 2026","-","20 May 2026","-","19 May 2026","-","18 May 2026","Missing Diary;Day Not Applicable for Calculation","17 May 2026","Day Not Applicable for Calculation","16 May 2026","Day Not Applicable for Calculation","1","-","1","2","1","2","2","-","-","-","1","0","-","0","0","0","0","0","-","-","-","0","2","","","-","-","N/A","N/A","N/A","N/A","N/A","N/A"
"77242113UCO3001","Adolescent","Czech Republic","DD5-CZ10020","Lucie Gonsorcikova","CZ100201001","1","Unscheduled 1","04 May 2026","Yes","20 Apr 2026","12 Apr 2026","15 Apr 2026","-","-","2","-","3","03 May 2026","-","02 May 2026","-","01 May 2026","-","30 Apr 2026","-","29 Apr 2026","-","28 Apr 2026","-","27 Apr 2026","-","26 Apr 2026","Day Not Applicable for Calculation","25 Apr 2026","Day Not Applicable for Calculation","24 Apr 2026","Day Not Applicable for Calculation","5","6","6","7","6","3","3","-","-","-","2","0","0","0","0","0","0","0","-","-","-","0","5","4","7","-","-","N/A","N/A","N/A","N/A","N/A","N/A"
"77242113UCO3001","Adolescent","Czech Republic","DD5-CZ10020","Lucie Gonsorcikova","CZ100201001","1","I-0","18 May 2026","Yes","01 May 2026","01 May 2026","01 May 2026","-","-","2","-","3","17 May 2026","-","16 May 2026","-","15 May 2026","-","14 May 2026","-","13 May 2026","-","12 May 2026","-","11 May 2026","-","10 May 2026","Day Not Applicable for Calculation","09 May 2026","Day Not Applicable for Calculation","08 May 2026","Day Not Applicable for Calculation","6","6","6","6","6","6","6","-","-","-","3","0","0","0","0","0","0","0","-","-","-","0","6","5","8","-","04 May 2026 09:51:14","N/A","N/A","N/A","N/A","N/A","N/A"
"77242113UCO3001","Adult","Czech Republic","DD5-CZ10021","Martin Bortlik","CZ100212001","1","I-0","07 Apr 2026","Yes","16 Mar 2026","15 Mar 2026","16 Mar 2026","-","-","3","-","3","06 Apr 2026","-","05 Apr 2026","-","04 Apr 2026","-","03 Apr 2026","-","02 Apr 2026","-","01 Apr 2026","-","31 Mar 2026","-","30 Mar 2026","Day Not Applicable for Calculation","29 Mar 2026","Day Not Applicable for Calculation","28 Mar 2026","Day Not Applicable for Calculation","11","11","10","11","11","10","9","-","-","-","3","2","2","2","2","2","2","2","-","-","-","2","8","8","11","-","20 Apr 2026 09:27:58","N/A","N/A","N/A","N/A","N/A","N/A"
"77242113UCO3001","Adult","Czech Republic","DD5-CZ10021","Martin Bortlik","CZ100212001","1","I-2","20 Apr 2026","-","-","-","-","-","-","-","-","3","19 Apr 2026","-","18 Apr 2026","-","17 Apr 2026","-","16 Apr 2026","-","15 Apr 2026","-","14 Apr 2026","-","13 Apr 2026","-","12 Apr 2026","Day Not Applicable for Calculation","11 Apr 2026","Day Not Applicable for Calculation","10 Apr 2026","Day Not Applicable for Calculation","8","7","9","8","8","7","8","-","-","-","3","2","2","1","1","1","2","1","-","-","-","1","7","","","-","20 Apr 2026 09:29:01","N/A","N/A","N/A","N/A","N/A","N/A"
"77242113UCO3001","Adult","Czech Republic","DD5-CZ10021","Martin Bortlik","CZ100212001","1","I-4","05 May 2026","-","-","-","-","-","-","-","-","1","04 May 2026","-","03 May 2026","-","02 May 2026","-","01 May 2026","-","30 Apr 2026","-","29 Apr 2026","-","28 Apr 2026","-","27 Apr 2026","Day Not Applicable for Calculation","26 Apr 2026","Day Not Applicable for Calculation","25 Apr 2026","Day Not Applicable for Calculation","6","6","6","6","7","7","6","-","-","-","3","0","0","1","1","1","1","1","-","-","-","1","5","","","-","-","N/A","N/A","N/A","N/A","N/A","N/A"
"77242113UCO3001","Adult","Czech Republic","DD5-CZ10022","Petr Hrabak","CZ100222002","1","I-0","19 Feb 2026","Yes","11 Feb 2026","10 Feb 2026","11 Feb 2026","-","-","2","-","2","18 Feb 2026","-","17 Feb 2026","-","16 Feb 2026","-","15 Feb 2026","-","14 Feb 2026","-","13 Feb 2026","-","12 Feb 2026","-","11 Feb 2026","Endoscopy;Bowel Preparation for Procedure;Day Not Applicable for Calculation","10 Feb 2026","Bowel Preparation for Procedure;Day Not Applicable for Calculation","09 Feb 2026","Day Not Applicable for Calculation","3","2","2","3","4","3","2","-","-","-","1","1","1","0","0","0","2","2","-","-","-","1","4","4","6","-","19 Feb 2026 15:41:35","N/A","N/A","N/A","N/A","N/A","N/A"
"77242113UCO3001","Adult","Czech Republic","DD5-CZ10022","Petr Hrabak","CZ100222003","1","I-0","09 Mar 2026","Yes","11 Feb 2026","10 Feb 2026","11 Feb 2026","-","-","2","-","2","08 Mar 2026","-","07 Mar 2026","-","06 Mar 2026","-","05 Mar 2026","-","04 Mar 2026","-","03 Mar 2026","Missing Diary","02 Mar 2026","Missing Diary","01 Mar 2026","Missing Diary;Day Not Applicable for Calculation","28 Feb 2026","Missing Diary;Day Not Applicable for Calculation","27 Feb 2026","Missing Diary;Day Not Applicable for Calculation","7","7","6","6","7","-","-","-","-","-","3","2","2","2","2","2","-","-","-","-","-","2","7","7","9","-","22 Mar 2026 18:34:58","N/A","N/A","N/A","N/A","N/A","N/A"
"77242113UCO3001","Adult","Czech Republic","DD5-CZ10022","Petr Hrabak","CZ100222003","1","I-2","27 Mar 2026","-","-","-","-","-","-","-","-","2","26 Mar 2026","-","25 Mar 2026","-","24 Mar 2026","-","23 Mar 2026","-","22 Mar 2026","-","21 Mar 2026","-","20 Mar 2026","-","19 Mar 2026","Day Not Applicable for Calculation","18 Mar 2026","Day Not Applicable for Calculation","17 Mar 2026","Day Not Applicable for Calculation","7","3","3","3","5","5","5","-","-","-","2","0","0","1","1","1","1","2","-","-","-","1","5","","","-","27 Mar 2026 07:22:31","N/A","N/A","N/A","N/A","N/A","N/A"
"77242113UCO3001","Adult","Czech Republic","DD5-CZ10022","Petr Hrabak","CZ100222003","1","I-4","08 Apr 2026","-","-","-","-","-","-","-","-","2","07 Apr 2026","-","06 Apr 2026","-","05 Apr 2026","-","04 Apr 2026","-","03 Apr 2026","-","02 Apr 2026","-","01 Apr 2026","-","31 Mar 2026","Day Not Applicable for Calculation","30 Mar 2026","Day Not Applicable for Calculation","29 Mar 2026","Day Not Applicable for Calculation","3","3","4","4","5","4","3","-","-","-","2","1","0","0","2","1","1","2","-","-","-","1","5","","","-","08 Apr 2026 07:59:35","N/A","N/A","N/A","N/A","N/A","N/A"
"77242113UCO3001","Adult","Czech Republic","DD5-CZ10022","Petr Hrabak","CZ100222003","1","I-8","04 May 2026","-","-","-","-","-","-","-","-","2","03 May 2026","-","02 May 2026","-","01 May 2026","-","30 Apr 2026","-","29 Apr 2026","-","28 Apr 2026","-","27 Apr 2026","-","26 Apr 2026","Day Not Applicable for Calculation","25 Apr 2026","Day Not Applicable for Calculation","24 Apr 2026","Missing Diary;Day Not Applicable for Calculation","3","5","3","3","3","2","3","-","-","-","1","0","0","0","0","0","0","0","-","-","-","0","3","","","-","04 May 2026 07:52:47","N/A","N/A","N/A","N/A","N/A","N/A"
"77242113UCO3001","Adult","Czech Republic","DD5-CZ10022","Petr Hrabak","CZ100222005","1","I-0","09 Apr 2026","Yes","08 Apr 2026","31 Mar 2026","01 Apr 2026","-","-","2","-","2","08 Apr 2026","Endoscopy","07 Apr 2026","-","06 Apr 2026","-","05 Apr 2026","-","04 Apr 2026","-","03 Apr 2026","-","02 Apr 2026","-","01 Apr 2026","Bowel Preparation for Procedure;Day Not Applicable for Calculation","31 Mar 2026","Bowel Preparation for Procedure;Day Not Applicable for Calculation","30 Mar 2026","-","-","3","3","4","3","4","3","-","-","3","1","-","2","2","2","2","2","2","-","-","2","2","5","5","7","-","-","N/A","N/A","N/A","N/A","N/A","N/A"
"77242113UCO3001","Adult","Czech Republic","DD5-CZ10022","Petr Hrabak","CZ100222005","1","I-2","22 Apr 2026","-","-","-","-","-","-","-","-","2","21 Apr 2026","-","20 Apr 2026","-","19 Apr 2026","-","18 Apr 2026","-","17 Apr 2026","-","16 Apr 2026","-","15 Apr 2026","-","14 Apr 2026","Day Not Applicable for Calculation","13 Apr 2026","Day Not Applicable for Calculation","12 Apr 2026","Day Not Applicable for Calculation","3","3","5","3","2","3","2","-","-","-","1","1","2","2","1","1","1","2","-","-","-","1","4","","","-","22 Apr 2026 14:03:33","N/A","N/A","N/A","N/A","N/A","N/A"
"77242113UCO3001","Adult","Czech Republic","DD5-CZ10022","Petr Hrabak","CZ100222005","1","I-4","05 May 2026","-","-","-","-","-","-","-","-","2","04 May 2026","-","03 May 2026","-","02 May 2026","-","01 May 2026","-","30 Apr 2026","-","29 Apr 2026","-","28 Apr 2026","-","27 Apr 2026","Day Not Applicable for Calculation","26 Apr 2026","Day Not Applicable for Calculation","25 Apr 2026","Day Not Applicable for Calculation","4","2","2","2","2","2","2","-","-","-","1","1","1","1","1","2","1","1","-","-","-","1","4","","","-","05 May 2026 07:30:02","N/A","N/A","N/A","N/A","N/A","N/A"
1 Protocol Study Population Country Site Principal Investigator Participant ID Baseline Stool Frequency Visit Visit Date Endoscopy Completed? Endoscopy Date Bowel Preparation Start Date 1 Bowel Preparation End Date 1 Bowel Preparation Start Date 2 Bowel Preparation End Date 2 Central Endoscopy Score Local Endoscopy Score PGA Score Eligible Day (-1) Day (-1) Excluded Reason(s) Eligible Day (-2) Day (-2) Excluded Reason(s) Eligible Day (-3) Day (-3) Excluded Reason(s) Eligible Day (-4) Day (-4) Excluded Reason(s) Eligible Day (-5) Day (-5) Excluded Reason(s) Eligible Day (-6) Day (-6) Excluded Reason(s) Eligible Day (-7) Day (-7) Excluded Reason(s) Eligible Day (-8) Day (-8) Excluded Reason(s) Eligible Day (-9) Day (-9) Excluded Reason(s) Eligible Day (-10) Day (-10) Excluded Reason(s) Eligible Day (-1) Stool Count Eligible Day (-2) Stool Count Eligible Day (-3) Stool Count Eligible Day (-4) Stool Count Eligible Day (-5) Stool Count Eligible Day (-6) Stool Count Eligible Day (-7) Stool Count Eligible Day (-8) Stool Count Eligible Day (-9) Stool Count Eligible Day (-10) Stool Count Stool Frequency Sub-score Eligible Day (-1) Rectal Bleeding Score Eligible Day (-2) Rectal Bleeding Score Eligible Day (-3) Rectal Bleeding Score Eligible Day (-4) Rectal Bleeding Score Eligible Day (-5) Rectal Bleeding Score Eligible Day (-6) Rectal Bleeding Score Eligible Day (-7) Rectal Bleeding Score Eligible Day (-8) Rectal Bleeding Score Eligible Day (-9) Rectal Bleeding Score Eligible Day (-10) Rectal Bleeding Score Rectal Bleeding Sub-score Partial Mayo Score Modified Mayo Score Full Mayo Score Site Action Last Mayo Score Submission Week I-12 Clinical Responder Week I-12 Clinical Remission Clinical Flare Loss of Response Partial Mayo Response Post Loss of Response Partial Mayo Response for Clinical Non-Responders
2 77242113UCO3001 Adult Czech Republic DD5-CZ10001 Matej Falc CZ100012001 1 I-0 19 Feb 2026 Yes 05 Feb 2026 04 Feb 2026 04 Feb 2026 - - 2 - 3 18 Feb 2026 - 17 Feb 2026 - 16 Feb 2026 - 15 Feb 2026 - 14 Feb 2026 - 13 Feb 2026 - 12 Feb 2026 - 11 Feb 2026 Day Not Applicable for Calculation 10 Feb 2026 Day Not Applicable for Calculation 09 Feb 2026 Day Not Applicable for Calculation 10 8 7 5 7 8 8 - - - 3 1 1 1 0 1 1 1 - - - 1 7 6 9 - 08 Apr 2026 07:11:25 N/A N/A N/A N/A N/A N/A
3 77242113UCO3001 Adult Czech Republic DD5-CZ10001 Matej Falc CZ100012001 1 I-2 04 Mar 2026 - - - - - - - - 3 03 Mar 2026 - 02 Mar 2026 - 01 Mar 2026 - 28 Feb 2026 - 27 Feb 2026 - 26 Feb 2026 - 25 Feb 2026 - 24 Feb 2026 Day Not Applicable for Calculation 23 Feb 2026 Day Not Applicable for Calculation 22 Feb 2026 Day Not Applicable for Calculation 5 4 5 4 5 6 6 - - - 2 1 0 1 0 1 0 1 - - - 1 6 - - N/A N/A N/A N/A N/A N/A
4 77242113UCO3001 Adult Czech Republic DD5-CZ10001 Matej Falc CZ100012001 1 I-4 18 Mar 2026 - - - - - - - - 2 17 Mar 2026 - 16 Mar 2026 - 15 Mar 2026 - 14 Mar 2026 - 13 Mar 2026 - 12 Mar 2026 - 11 Mar 2026 - 10 Mar 2026 Day Not Applicable for Calculation 09 Mar 2026 Day Not Applicable for Calculation 08 Mar 2026 Day Not Applicable for Calculation 5 5 5 4 5 4 5 - - - 2 1 0 0 1 1 1 0 - - - 1 5 - 08 Apr 2026 07:11:43 N/A N/A N/A N/A N/A N/A
5 77242113UCO3001 Adult Czech Republic DD5-CZ10001 Matej Falc CZ100012001 1 I-8 05 May 2026 - - - - - - - - 1 04 May 2026 - 03 May 2026 - 02 May 2026 - 01 May 2026 - 30 Apr 2026 - 29 Apr 2026 - 28 Apr 2026 - 27 Apr 2026 Day Not Applicable for Calculation 26 Apr 2026 Day Not Applicable for Calculation 25 Apr 2026 Day Not Applicable for Calculation 3 3 4 4 5 4 4 - - - 2 1 1 1 1 1 1 1 - - - 1 4 - - N/A N/A N/A N/A N/A N/A
6 77242113UCO3001 Adult Czech Republic DD5-CZ10001 Matej Falc CZ100012001 1 I-12 13 May 2026 Yes 06 May 2026 05 May 2026 05 May 2026 - - 1 - 1 12 May 2026 - 11 May 2026 - 10 May 2026 - 09 May 2026 - 08 May 2026 - 07 May 2026 - 06 May 2026 Endoscopy 05 May 2026 Bowel Preparation for Procedure;Day Not Applicable for Calculation 04 May 2026 - 03 May 2026 Day Not Applicable for Calculation 5 4 6 5 5 5 - - 3 - 2 1 0 1 1 1 1 - - 1 - 1 4 4 5 - - Clinical Responder No N/A N/A N/A N/A
7 77242113UCO3001 Adult Czech Republic DD5-CZ10001 Matej Falc CZ100012002 1 I-0 08 Apr 2026 Yes 18 Mar 2026 17 Mar 2026 18 Mar 2026 - - 2 - 2 07 Apr 2026 - 06 Apr 2026 - 05 Apr 2026 - 04 Apr 2026 Missing Diary 03 Apr 2026 - 02 Apr 2026 - 01 Apr 2026 - 31 Mar 2026 Day Not Applicable for Calculation 30 Mar 2026 Day Not Applicable for Calculation 29 Mar 2026 Day Not Applicable for Calculation 3 3 4 - 3 3 4 - - - 1 0 0 0 - 0 0 1 - - - 0 3 3 5 - - N/A N/A N/A N/A N/A N/A
8 77242113UCO3001 Adult Czech Republic DD5-CZ10001 Matej Falc CZ100012002 1 I-2 23 Apr 2026 - - - - - - - - 2 22 Apr 2026 Missing Diary 21 Apr 2026 - 20 Apr 2026 - 19 Apr 2026 - 18 Apr 2026 - 17 Apr 2026 - 16 Apr 2026 - 15 Apr 2026 Day Not Applicable for Calculation 14 Apr 2026 Day Not Applicable for Calculation 13 Apr 2026 Day Not Applicable for Calculation - 3 3 6 5 5 4 - - - 2 - 0 0 1 1 1 1 - - - 1 5 - - N/A N/A N/A N/A N/A N/A
9 77242113UCO3001 Adult Czech Republic DD5-CZ10001 Matej Falc CZ100012002 1 I-4 06 May 2026 - - - - - - - - 1 05 May 2026 - 04 May 2026 - 03 May 2026 - 02 May 2026 - 01 May 2026 - 30 Apr 2026 - 29 Apr 2026 - 28 Apr 2026 Day Not Applicable for Calculation 27 Apr 2026 Day Not Applicable for Calculation 26 Apr 2026 Day Not Applicable for Calculation 6 3 2 3 3 3 3 - - - 1 1 0 0 0 1 1 0 - - - 0 2 - - N/A N/A N/A N/A N/A N/A
10 77242113UCO3001 Adult Czech Republic DD5-CZ10001 Matej Falc CZ100012003 1 I-0 27 May 2026 Yes 13 May 2026 12 May 2026 12 May 2026 - - 3 - 2 26 May 2026 - 25 May 2026 - 24 May 2026 - 23 May 2026 - 22 May 2026 - 21 May 2026 - 20 May 2026 - 19 May 2026 Day Not Applicable for Calculation 18 May 2026 Day Not Applicable for Calculation 17 May 2026 Day Not Applicable for Calculation 6 9 7 8 9 7 8 - - - 3 2 2 2 2 1 1 1 - - - 2 7 8 10 - 27 May 2026 07:24:39 N/A N/A N/A N/A N/A N/A
11 77242113UCO3001 Adult Czech Republic DD5-CZ10006 Michal Konecny CZ100062001 1 I-0 20 Mar 2026 Yes 19 Feb 2026 - - - - 3 - 3 19 Mar 2026 - 18 Mar 2026 - 17 Mar 2026 - 16 Mar 2026 - 15 Mar 2026 - 14 Mar 2026 - 13 Mar 2026 - 12 Mar 2026 Day Not Applicable for Calculation 11 Mar 2026 Day Not Applicable for Calculation 10 Mar 2026 Day Not Applicable for Calculation 7 7 8 8 7 8 5 - - - 3 2 1 1 1 1 1 0 - - - 1 7 7 10 - 20 Mar 2026 07:02:44 N/A N/A N/A N/A N/A N/A
12 77242113UCO3001 Adult Czech Republic DD5-CZ10006 Michal Konecny CZ100062001 1 I-2 08 Apr 2026 - - - - - - - - 2 07 Apr 2026 Medication For Diarrhea 06 Apr 2026 Medication For Diarrhea 05 Apr 2026 Medication For Diarrhea 04 Apr 2026 Medication For Diarrhea 03 Apr 2026 Medication For Diarrhea 02 Apr 2026 Medication For Diarrhea 01 Apr 2026 Medication For Diarrhea 31 Mar 2026 Medication For Diarrhea;Day Not Applicable for Calculation 30 Mar 2026 Medication For Diarrhea;Day Not Applicable for Calculation 29 Mar 2026 Day Not Applicable for Calculation - - - - - - - - - - Non-Evaluable - - - - - - - - - - Non-Evaluable Non-Evaluable Non-Evaluable Non-Evaluable - - N/A N/A N/A N/A N/A N/A
13 77242113UCO3001 Adult Czech Republic DD5-CZ10006 Michal Konecny CZ100062001 1 I-4 15 Apr 2026 - - - - - - - - 3 14 Apr 2026 - 13 Apr 2026 - 12 Apr 2026 - 11 Apr 2026 - 10 Apr 2026 - 09 Apr 2026 - 08 Apr 2026 - 07 Apr 2026 Medication For Diarrhea;Day Not Applicable for Calculation 06 Apr 2026 Medication For Diarrhea;Day Not Applicable for Calculation 05 Apr 2026 Medication For Diarrhea;Day Not Applicable for Calculation 9 22 20 19 17 18 18 - - - 3 1 3 2 2 2 2 2 - - - 2 8 - 04 May 2026 22:06:47 N/A N/A N/A N/A N/A N/A
14 77242113UCO3001 Adult Czech Republic DD5-CZ10006 Michal Konecny CZ100062001 1 I-8 18 May 2026 - - - - - - - - 2 17 May 2026 - 16 May 2026 - 15 May 2026 - 14 May 2026 - 13 May 2026 - 12 May 2026 - 11 May 2026 - 10 May 2026 Day Not Applicable for Calculation 09 May 2026 Day Not Applicable for Calculation 08 May 2026 Day Not Applicable for Calculation 7 5 9 7 7 8 8 - - - 3 1 1 1 1 1 1 1 - - - 1 6 - - N/A N/A N/A N/A N/A N/A
15 77242113UCO3001 Adult Czech Republic DD5-CZ10006 Michal Konecny CZ100062002 1 I-0 26 May 2026 Yes 14 May 2026 13 May 2026 13 May 2026 - - 2 - 2 25 May 2026 - 24 May 2026 - 23 May 2026 - 22 May 2026 - 21 May 2026 - 20 May 2026 - 19 May 2026 - 18 May 2026 Day Not Applicable for Calculation 17 May 2026 Day Not Applicable for Calculation 16 May 2026 Day Not Applicable for Calculation 8 8 6 7 7 6 7 - - - 3 2 2 2 2 2 2 2 - - - 2 7 7 9 - - N/A N/A N/A N/A N/A N/A
16 77242113UCO3001 Adult Czech Republic DD5-CZ10009 Jiri Pumprla CZ100092001 1 I-0 05 May 2026 Yes 24 Apr 2026 23 Apr 2026 23 Apr 2026 - - 2 - 2 04 May 2026 - 03 May 2026 - 02 May 2026 - 01 May 2026 - 30 Apr 2026 - 29 Apr 2026 - 28 Apr 2026 - 27 Apr 2026 Day Not Applicable for Calculation 26 Apr 2026 Day Not Applicable for Calculation 25 Apr 2026 Day Not Applicable for Calculation 5 5 5 5 5 5 5 - - - 2 1 1 1 1 1 1 1 - - - 1 5 5 7 - 05 May 2026 11:19:40 N/A N/A N/A N/A N/A N/A
17 77242113UCO3001 Adult Czech Republic DD5-CZ10009 Jiri Pumprla CZ100092001 1 I-2 19 May 2026 - - - - - - - - 1 18 May 2026 - 17 May 2026 - 16 May 2026 - 15 May 2026 - 14 May 2026 - 13 May 2026 - 12 May 2026 - 11 May 2026 Day Not Applicable for Calculation 10 May 2026 Day Not Applicable for Calculation 09 May 2026 Day Not Applicable for Calculation 5 4 5 5 5 4 6 - - - 2 1 1 1 1 1 1 1 - - - 1 4 - 19 May 2026 10:38:25 N/A N/A N/A N/A N/A N/A
18 77242113UCO3001 Adult Czech Republic DD5-CZ10012 Stefan Konecny CZ100122001 5 I-0 07 Apr 2026 Yes 24 Mar 2026 22 Mar 2026 22 Mar 2026 - - 2 - 2 06 Apr 2026 - 05 Apr 2026 - 04 Apr 2026 - 03 Apr 2026 - 02 Apr 2026 - 01 Apr 2026 - 31 Mar 2026 - 30 Mar 2026 Day Not Applicable for Calculation 29 Mar 2026 Day Not Applicable for Calculation 28 Mar 2026 Day Not Applicable for Calculation 8 11 5 9 11 10 13 - - - 3 1 2 2 2 2 2 2 - - - 2 7 7 9 - 04 May 2026 08:44:52 N/A N/A N/A N/A N/A N/A
19 77242113UCO3001 Adult Czech Republic DD5-CZ10012 Stefan Konecny CZ100122001 5 I-2 22 Apr 2026 - - - - - - - - 2 21 Apr 2026 - 20 Apr 2026 - 19 Apr 2026 - 18 Apr 2026 - 17 Apr 2026 - 16 Apr 2026 - 15 Apr 2026 - 14 Apr 2026 Day Not Applicable for Calculation 13 Apr 2026 Day Not Applicable for Calculation 12 Apr 2026 Day Not Applicable for Calculation 7 5 6 6 7 8 2 - - - 1 1 0 1 1 1 2 0 - - - 1 4 - 04 May 2026 08:45:07 N/A N/A N/A N/A N/A N/A
20 77242113UCO3001 Adult Czech Republic DD5-CZ10012 Stefan Konecny CZ100122001 5 I-4 07 May 2026 - - - - - - - - 1 06 May 2026 - 05 May 2026 - 04 May 2026 - 03 May 2026 - 02 May 2026 - 01 May 2026 - 30 Apr 2026 - 29 Apr 2026 Day Not Applicable for Calculation 28 Apr 2026 Day Not Applicable for Calculation 27 Apr 2026 Day Not Applicable for Calculation 8 7 7 8 4 11 7 - - - 1 2 1 1 1 0 1 1 - - - 1 3 - - N/A N/A N/A N/A N/A N/A
21 77242113UCO3001 Adult Czech Republic DD5-CZ10013 David Stepek CZ100132001 1 I-0 24 Mar 2026 Yes 12 Mar 2026 11 Mar 2026 11 Mar 2026 - - 2 - 2 23 Mar 2026 - 22 Mar 2026 - 21 Mar 2026 - 20 Mar 2026 - 19 Mar 2026 - 18 Mar 2026 - 17 Mar 2026 - 16 Mar 2026 Day Not Applicable for Calculation 15 Mar 2026 Day Not Applicable for Calculation 14 Mar 2026 Day Not Applicable for Calculation 8 6 5 7 6 7 6 - - - 3 1 1 1 0 1 1 1 - - - 1 6 6 8 - 05 Apr 2026 22:41:27 N/A N/A N/A N/A N/A N/A
22 77242113UCO3001 Adult Czech Republic DD5-CZ10013 David Stepek CZ100132001 1 I-2 08 Apr 2026 - - - - - - - - 2 07 Apr 2026 - 06 Apr 2026 - 05 Apr 2026 - 04 Apr 2026 - 03 Apr 2026 - 02 Apr 2026 - 01 Apr 2026 - 31 Mar 2026 Day Not Applicable for Calculation 30 Mar 2026 Day Not Applicable for Calculation 29 Mar 2026 Day Not Applicable for Calculation 5 2 3 6 5 5 5 - - - 2 0 0 0 0 1 1 0 - - - 0 4 - 27 May 2026 12:53:52 N/A N/A N/A N/A N/A N/A
23 77242113UCO3001 Adult Czech Republic DD5-CZ10013 David Stepek CZ100132001 1 I-4 21 Apr 2026 - - - - - - - - 0 20 Apr 2026 - 19 Apr 2026 - 18 Apr 2026 - 17 Apr 2026 - 16 Apr 2026 - 15 Apr 2026 - 14 Apr 2026 - 13 Apr 2026 Day Not Applicable for Calculation 12 Apr 2026 Day Not Applicable for Calculation 11 Apr 2026 Day Not Applicable for Calculation 4 3 4 3 3 4 4 - - - 2 0 0 0 0 0 0 0 - - - 0 2 - 27 May 2026 12:54:41 N/A N/A N/A N/A N/A N/A
24 77242113UCO3001 Adult Czech Republic DD5-CZ10013 David Stepek CZ100132002 1 I-0 12 May 2026 Yes 21 Apr 2026 20 Apr 2026 21 Apr 2026 - - 2 - 2 11 May 2026 - 10 May 2026 - 09 May 2026 - 08 May 2026 - 07 May 2026 - 06 May 2026 - 05 May 2026 Missing Diary 04 May 2026 Day Not Applicable for Calculation 03 May 2026 Day Not Applicable for Calculation 02 May 2026 Day Not Applicable for Calculation 2 1 1 1 1 2 - - - - 0 0 0 0 0 0 0 - - - - 0 2 2 4 - - N/A N/A N/A N/A N/A N/A
25 77242113UCO3001 Adult Czech Republic DD5-CZ10013 David Stepek CZ100132002 1 I-2 26 May 2026 - - - - - - - - 1 25 May 2026 - 24 May 2026 Missing Diary 23 May 2026 - 22 May 2026 - 21 May 2026 - 20 May 2026 - 19 May 2026 - 18 May 2026 Missing Diary;Day Not Applicable for Calculation 17 May 2026 Day Not Applicable for Calculation 16 May 2026 Day Not Applicable for Calculation 1 - 1 2 1 2 2 - - - 1 0 - 0 0 0 0 0 - - - 0 2 - - N/A N/A N/A N/A N/A N/A
26 77242113UCO3001 Adolescent Czech Republic DD5-CZ10020 Lucie Gonsorcikova CZ100201001 1 Unscheduled 1 04 May 2026 Yes 20 Apr 2026 12 Apr 2026 15 Apr 2026 - - 2 - 3 03 May 2026 - 02 May 2026 - 01 May 2026 - 30 Apr 2026 - 29 Apr 2026 - 28 Apr 2026 - 27 Apr 2026 - 26 Apr 2026 Day Not Applicable for Calculation 25 Apr 2026 Day Not Applicable for Calculation 24 Apr 2026 Day Not Applicable for Calculation 5 6 6 7 6 3 3 - - - 2 0 0 0 0 0 0 0 - - - 0 5 4 7 - - N/A N/A N/A N/A N/A N/A
27 77242113UCO3001 Adolescent Czech Republic DD5-CZ10020 Lucie Gonsorcikova CZ100201001 1 I-0 18 May 2026 Yes 01 May 2026 01 May 2026 01 May 2026 - - 2 - 3 17 May 2026 - 16 May 2026 - 15 May 2026 - 14 May 2026 - 13 May 2026 - 12 May 2026 - 11 May 2026 - 10 May 2026 Day Not Applicable for Calculation 09 May 2026 Day Not Applicable for Calculation 08 May 2026 Day Not Applicable for Calculation 6 6 6 6 6 6 6 - - - 3 0 0 0 0 0 0 0 - - - 0 6 5 8 - 04 May 2026 09:51:14 N/A N/A N/A N/A N/A N/A
28 77242113UCO3001 Adult Czech Republic DD5-CZ10021 Martin Bortlik CZ100212001 1 I-0 07 Apr 2026 Yes 16 Mar 2026 15 Mar 2026 16 Mar 2026 - - 3 - 3 06 Apr 2026 - 05 Apr 2026 - 04 Apr 2026 - 03 Apr 2026 - 02 Apr 2026 - 01 Apr 2026 - 31 Mar 2026 - 30 Mar 2026 Day Not Applicable for Calculation 29 Mar 2026 Day Not Applicable for Calculation 28 Mar 2026 Day Not Applicable for Calculation 11 11 10 11 11 10 9 - - - 3 2 2 2 2 2 2 2 - - - 2 8 8 11 - 20 Apr 2026 09:27:58 N/A N/A N/A N/A N/A N/A
29 77242113UCO3001 Adult Czech Republic DD5-CZ10021 Martin Bortlik CZ100212001 1 I-2 20 Apr 2026 - - - - - - - - 3 19 Apr 2026 - 18 Apr 2026 - 17 Apr 2026 - 16 Apr 2026 - 15 Apr 2026 - 14 Apr 2026 - 13 Apr 2026 - 12 Apr 2026 Day Not Applicable for Calculation 11 Apr 2026 Day Not Applicable for Calculation 10 Apr 2026 Day Not Applicable for Calculation 8 7 9 8 8 7 8 - - - 3 2 2 1 1 1 2 1 - - - 1 7 - 20 Apr 2026 09:29:01 N/A N/A N/A N/A N/A N/A
30 77242113UCO3001 Adult Czech Republic DD5-CZ10021 Martin Bortlik CZ100212001 1 I-4 05 May 2026 - - - - - - - - 1 04 May 2026 - 03 May 2026 - 02 May 2026 - 01 May 2026 - 30 Apr 2026 - 29 Apr 2026 - 28 Apr 2026 - 27 Apr 2026 Day Not Applicable for Calculation 26 Apr 2026 Day Not Applicable for Calculation 25 Apr 2026 Day Not Applicable for Calculation 6 6 6 6 7 7 6 - - - 3 0 0 1 1 1 1 1 - - - 1 5 - - N/A N/A N/A N/A N/A N/A
31 77242113UCO3001 Adult Czech Republic DD5-CZ10022 Petr Hrabak CZ100222002 1 I-0 19 Feb 2026 Yes 11 Feb 2026 10 Feb 2026 11 Feb 2026 - - 2 - 2 18 Feb 2026 - 17 Feb 2026 - 16 Feb 2026 - 15 Feb 2026 - 14 Feb 2026 - 13 Feb 2026 - 12 Feb 2026 - 11 Feb 2026 Endoscopy;Bowel Preparation for Procedure;Day Not Applicable for Calculation 10 Feb 2026 Bowel Preparation for Procedure;Day Not Applicable for Calculation 09 Feb 2026 Day Not Applicable for Calculation 3 2 2 3 4 3 2 - - - 1 1 1 0 0 0 2 2 - - - 1 4 4 6 - 19 Feb 2026 15:41:35 N/A N/A N/A N/A N/A N/A
32 77242113UCO3001 Adult Czech Republic DD5-CZ10022 Petr Hrabak CZ100222003 1 I-0 09 Mar 2026 Yes 11 Feb 2026 10 Feb 2026 11 Feb 2026 - - 2 - 2 08 Mar 2026 - 07 Mar 2026 - 06 Mar 2026 - 05 Mar 2026 - 04 Mar 2026 - 03 Mar 2026 Missing Diary 02 Mar 2026 Missing Diary 01 Mar 2026 Missing Diary;Day Not Applicable for Calculation 28 Feb 2026 Missing Diary;Day Not Applicable for Calculation 27 Feb 2026 Missing Diary;Day Not Applicable for Calculation 7 7 6 6 7 - - - - - 3 2 2 2 2 2 - - - - - 2 7 7 9 - 22 Mar 2026 18:34:58 N/A N/A N/A N/A N/A N/A
33 77242113UCO3001 Adult Czech Republic DD5-CZ10022 Petr Hrabak CZ100222003 1 I-2 27 Mar 2026 - - - - - - - - 2 26 Mar 2026 - 25 Mar 2026 - 24 Mar 2026 - 23 Mar 2026 - 22 Mar 2026 - 21 Mar 2026 - 20 Mar 2026 - 19 Mar 2026 Day Not Applicable for Calculation 18 Mar 2026 Day Not Applicable for Calculation 17 Mar 2026 Day Not Applicable for Calculation 7 3 3 3 5 5 5 - - - 2 0 0 1 1 1 1 2 - - - 1 5 - 27 Mar 2026 07:22:31 N/A N/A N/A N/A N/A N/A
34 77242113UCO3001 Adult Czech Republic DD5-CZ10022 Petr Hrabak CZ100222003 1 I-4 08 Apr 2026 - - - - - - - - 2 07 Apr 2026 - 06 Apr 2026 - 05 Apr 2026 - 04 Apr 2026 - 03 Apr 2026 - 02 Apr 2026 - 01 Apr 2026 - 31 Mar 2026 Day Not Applicable for Calculation 30 Mar 2026 Day Not Applicable for Calculation 29 Mar 2026 Day Not Applicable for Calculation 3 3 4 4 5 4 3 - - - 2 1 0 0 2 1 1 2 - - - 1 5 - 08 Apr 2026 07:59:35 N/A N/A N/A N/A N/A N/A
35 77242113UCO3001 Adult Czech Republic DD5-CZ10022 Petr Hrabak CZ100222003 1 I-8 04 May 2026 - - - - - - - - 2 03 May 2026 - 02 May 2026 - 01 May 2026 - 30 Apr 2026 - 29 Apr 2026 - 28 Apr 2026 - 27 Apr 2026 - 26 Apr 2026 Day Not Applicable for Calculation 25 Apr 2026 Day Not Applicable for Calculation 24 Apr 2026 Missing Diary;Day Not Applicable for Calculation 3 5 3 3 3 2 3 - - - 1 0 0 0 0 0 0 0 - - - 0 3 - 04 May 2026 07:52:47 N/A N/A N/A N/A N/A N/A
36 77242113UCO3001 Adult Czech Republic DD5-CZ10022 Petr Hrabak CZ100222005 1 I-0 09 Apr 2026 Yes 08 Apr 2026 31 Mar 2026 01 Apr 2026 - - 2 - 2 08 Apr 2026 Endoscopy 07 Apr 2026 - 06 Apr 2026 - 05 Apr 2026 - 04 Apr 2026 - 03 Apr 2026 - 02 Apr 2026 - 01 Apr 2026 Bowel Preparation for Procedure;Day Not Applicable for Calculation 31 Mar 2026 Bowel Preparation for Procedure;Day Not Applicable for Calculation 30 Mar 2026 - - 3 3 4 3 4 3 - - 3 1 - 2 2 2 2 2 2 - - 2 2 5 5 7 - - N/A N/A N/A N/A N/A N/A
37 77242113UCO3001 Adult Czech Republic DD5-CZ10022 Petr Hrabak CZ100222005 1 I-2 22 Apr 2026 - - - - - - - - 2 21 Apr 2026 - 20 Apr 2026 - 19 Apr 2026 - 18 Apr 2026 - 17 Apr 2026 - 16 Apr 2026 - 15 Apr 2026 - 14 Apr 2026 Day Not Applicable for Calculation 13 Apr 2026 Day Not Applicable for Calculation 12 Apr 2026 Day Not Applicable for Calculation 3 3 5 3 2 3 2 - - - 1 1 2 2 1 1 1 2 - - - 1 4 - 22 Apr 2026 14:03:33 N/A N/A N/A N/A N/A N/A
38 77242113UCO3001 Adult Czech Republic DD5-CZ10022 Petr Hrabak CZ100222005 1 I-4 05 May 2026 - - - - - - - - 2 04 May 2026 - 03 May 2026 - 02 May 2026 - 01 May 2026 - 30 Apr 2026 - 29 Apr 2026 - 28 Apr 2026 - 27 Apr 2026 Day Not Applicable for Calculation 26 Apr 2026 Day Not Applicable for Calculation 25 Apr 2026 Day Not Applicable for Calculation 4 2 2 2 2 2 2 - - - 1 1 1 1 1 2 1 1 - - - 1 4 - 05 May 2026 07:30:02 N/A N/A N/A N/A N/A N/A
@@ -0,0 +1,38 @@
Protocol,Study Population,Country,Site,Principal Investigator,Participant ID,Baseline Stool Frequency,Visit,Visit Date,Endoscopy Completed?,Endoscopy Date,Bowel Preparation Start Date 1,Bowel Preparation End Date 1,Bowel Preparation Start Date 2,Bowel Preparation End Date 2,Central Endoscopy Score,Local Endoscopy Score,PGA Score,Eligible Day (-1),Day (-1) Excluded Reason(s),Eligible Day (-2),Day (-2) Excluded Reason(s),Eligible Day (-3),Day (-3) Excluded Reason(s),Eligible Day (-4),Day (-4) Excluded Reason(s),Eligible Day (-5),Day (-5) Excluded Reason(s),Eligible Day (-6),Day (-6) Excluded Reason(s),Eligible Day (-7),Day (-7) Excluded Reason(s),Eligible Day (-8),Day (-8) Excluded Reason(s),Eligible Day (-9),Day (-9) Excluded Reason(s),Eligible Day (-10),Day (-10) Excluded Reason(s),Eligible Day (-1) Stool Count,Eligible Day (-2) Stool Count,Eligible Day (-3) Stool Count,Eligible Day (-4) Stool Count,Eligible Day (-5) Stool Count,Eligible Day (-6) Stool Count,Eligible Day (-7) Stool Count,Eligible Day (-8) Stool Count,Eligible Day (-9) Stool Count,Eligible Day (-10) Stool Count,Stool Frequency Sub-score,Eligible Day (-1) Rectal Bleeding Score,Eligible Day (-2) Rectal Bleeding Score,Eligible Day (-3) Rectal Bleeding Score,Eligible Day (-4) Rectal Bleeding Score,Eligible Day (-5) Rectal Bleeding Score,Eligible Day (-6) Rectal Bleeding Score,Eligible Day (-7) Rectal Bleeding Score,Eligible Day (-8) Rectal Bleeding Score,Eligible Day (-9) Rectal Bleeding Score,Eligible Day (-10) Rectal Bleeding Score,Rectal Bleeding Sub-score,Partial Mayo Score,Modified Mayo Score,Full Mayo Score,Site Action,Last Mayo Score Submission,Week I-12 Clinical Responder,Week I-12 Clinical Remission,Clinical Flare,Loss of Response,Partial Mayo Response Post Loss of Response,Partial Mayo Response for Clinical Non-Responders
77242113UCO3001,Adult,Czech Republic,DD5-CZ10001,Matej Falc,CZ100012001,1,I-0,19 Feb 2026,Yes,05 Feb 2026,04 Feb 2026,04 Feb 2026,-,-,2,-,3,18 Feb 2026,-,17 Feb 2026,-,16 Feb 2026,-,15 Feb 2026,-,14 Feb 2026,-,13 Feb 2026,-,12 Feb 2026,-,11 Feb 2026,Day Not Applicable for Calculation,10 Feb 2026,Day Not Applicable for Calculation,09 Feb 2026,Day Not Applicable for Calculation,10,8,7,5,7,8,8,-,-,-,3,1,1,1,0,1,1,1,-,-,-,1,7,6,10,-,08 Apr 2026 07:11:25,N/A,N/A,N/A,N/A,N/A,N/A
77242113UCO3001,Adult,Czech Republic,DD5-CZ10001,Matej Falc,CZ100012001,1,I-2,04 Mar 2026,-,-,-,-,-,-,-,-,3,03 Mar 2026,-,02 Mar 2026,-,01 Mar 2026,-,28 Feb 2026,-,27 Feb 2026,-,26 Feb 2026,-,25 Feb 2026,-,24 Feb 2026,Day Not Applicable for Calculation,23 Feb 2026,Day Not Applicable for Calculation,22 Feb 2026,Day Not Applicable for Calculation,5,4,5,4,5,6,6,-,-,-,2,1,0,1,0,1,0,1,-,-,-,1,6,,,-,-,N/A,N/A,N/A,N/A,N/A,N/A
77242113UCO3001,Adult,Czech Republic,DD5-CZ10001,Matej Falc,CZ100012001,1,I-4,18 Mar 2026,-,-,-,-,-,-,-,-,2,17 Mar 2026,-,16 Mar 2026,-,15 Mar 2026,-,14 Mar 2026,-,13 Mar 2026,-,12 Mar 2026,-,11 Mar 2026,-,10 Mar 2026,Day Not Applicable for Calculation,09 Mar 2026,Day Not Applicable for Calculation,08 Mar 2026,Day Not Applicable for Calculation,5,5,5,4,5,4,5,-,-,-,2,1,0,0,1,1,1,0,-,-,-,1,5,,,-,08 Apr 2026 07:11:43,N/A,N/A,N/A,N/A,N/A,N/A
77242113UCO3001,Adult,Czech Republic,DD5-CZ10001,Matej Falc,CZ100012001,1,I-8,05 May 2026,-,-,-,-,-,-,-,-,1,04 May 2026,-,03 May 2026,-,02 May 2026,-,01 May 2026,-,30 Apr 2026,-,29 Apr 2026,-,28 Apr 2026,-,27 Apr 2026,Day Not Applicable for Calculation,26 Apr 2026,Day Not Applicable for Calculation,25 Apr 2026,Day Not Applicable for Calculation,3,3,4,4,5,4,4,-,-,-,2,1,1,1,1,1,1,1,-,-,-,1,4,,,-,-,N/A,N/A,N/A,N/A,N/A,N/A
77242113UCO3001,Adult,Czech Republic,DD5-CZ10001,Matej Falc,CZ100012001,1,I-12,13 May 2026,Yes,06 May 2026,05 May 2026,05 May 2026,-,-,1,-,1,12 May 2026,-,11 May 2026,-,10 May 2026,-,09 May 2026,-,08 May 2026,-,07 May 2026,-,06 May 2026,Endoscopy,05 May 2026,Bowel Preparation for Procedure;Day Not Applicable for Calculation,04 May 2026,-,03 May 2026,Day Not Applicable for Calculation,5,4,6,5,5,5,-,-,3,-,2,1,0,1,1,1,1,-,-,1,-,1,4,4,5,-,-,Clinical Responder,No,N/A,N/A,N/A,N/A
77242113UCO3001,Adult,Czech Republic,DD5-CZ10001,Matej Falc,CZ100012002,1,I-0,08 Apr 2026,Yes,18 Mar 2026,17 Mar 2026,18 Mar 2026,-,-,2,-,2,07 Apr 2026,-,06 Apr 2026,-,05 Apr 2026,-,04 Apr 2026,Missing Diary,03 Apr 2026,-,02 Apr 2026,-,01 Apr 2026,-,31 Mar 2026,Day Not Applicable for Calculation,30 Mar 2026,Day Not Applicable for Calculation,29 Mar 2026,Day Not Applicable for Calculation,3,3,4,-,3,3,4,-,-,-,1,0,0,0,-,0,0,1,-,-,-,0,3,3,5,-,-,N/A,N/A,N/A,N/A,N/A,N/A
77242113UCO3001,Adult,Czech Republic,DD5-CZ10001,Matej Falc,CZ100012002,1,I-2,23 Apr 2026,-,-,-,-,-,-,-,-,2,22 Apr 2026,Missing Diary,21 Apr 2026,-,20 Apr 2026,-,19 Apr 2026,-,18 Apr 2026,-,17 Apr 2026,-,16 Apr 2026,-,15 Apr 2026,Day Not Applicable for Calculation,14 Apr 2026,Day Not Applicable for Calculation,13 Apr 2026,Day Not Applicable for Calculation,-,3,3,6,5,5,4,-,-,-,2,-,0,0,1,1,1,1,-,-,-,1,5,,,-,-,N/A,N/A,N/A,N/A,N/A,N/A
77242113UCO3001,Adult,Czech Republic,DD5-CZ10001,Matej Falc,CZ100012002,1,I-4,06 May 2026,-,-,-,-,-,-,-,-,1,05 May 2026,-,04 May 2026,-,03 May 2026,-,02 May 2026,-,01 May 2026,-,30 Apr 2026,-,29 Apr 2026,-,28 Apr 2026,Day Not Applicable for Calculation,27 Apr 2026,Day Not Applicable for Calculation,26 Apr 2026,Day Not Applicable for Calculation,6,3,2,3,3,3,3,-,-,-,1,1,0,0,0,1,1,0,-,-,-,0,2,,,-,-,N/A,N/A,N/A,N/A,N/A,N/A
77242113UCO3001,Adult,Czech Republic,DD5-CZ10001,Matej Falc,CZ100012003,1,I-0,27 May 2026,Yes,13 May 2026,12 May 2026,12 May 2026,-,-,3,-,2,26 May 2026,-,25 May 2026,-,24 May 2026,-,23 May 2026,-,22 May 2026,-,21 May 2026,-,20 May 2026,-,19 May 2026,Day Not Applicable for Calculation,18 May 2026,Day Not Applicable for Calculation,17 May 2026,Day Not Applicable for Calculation,6,9,7,8,9,7,8,-,-,-,3,2,2,2,2,1,1,1,-,-,-,2,7,8,10,-,27 May 2026 07:24:39,N/A,N/A,N/A,N/A,N/A,N/A
77242113UCO3001,Adult,Czech Republic,DD5-CZ10006,Michal Konecny,CZ100062001,1,I-0,20 Mar 2026,Yes,19 Feb 2026,-,-,-,-,3,-,3,19 Mar 2026,-,18 Mar 2026,-,17 Mar 2026,-,16 Mar 2026,-,15 Mar 2026,-,14 Mar 2026,-,13 Mar 2026,-,12 Mar 2026,Day Not Applicable for Calculation,11 Mar 2026,Day Not Applicable for Calculation,10 Mar 2026,Day Not Applicable for Calculation,7,7,8,8,7,8,5,-,-,-,3,2,1,1,1,1,1,0,-,-,-,1,7,7,10,-,20 Mar 2026 07:02:44,N/A,N/A,N/A,N/A,N/A,N/A
77242113UCO3001,Adult,Czech Republic,DD5-CZ10006,Michal Konecny,CZ100062001,1,I-2,08 Apr 2026,-,-,-,-,-,-,-,-,2,07 Apr 2026,Medication For Diarrhea,06 Apr 2026,Medication For Diarrhea,05 Apr 2026,Medication For Diarrhea,04 Apr 2026,Medication For Diarrhea,03 Apr 2026,Medication For Diarrhea,02 Apr 2026,Medication For Diarrhea,01 Apr 2026,Medication For Diarrhea,31 Mar 2026,Medication For Diarrhea;Day Not Applicable for Calculation,30 Mar 2026,Medication For Diarrhea;Day Not Applicable for Calculation,29 Mar 2026,Day Not Applicable for Calculation,-,-,-,-,-,-,-,-,-,-,Non-Evaluable,-,-,-,-,-,-,-,-,-,-,Non-Evaluable,Non-Evaluable,Non-Evaluable,Non-Evaluable,-,-,N/A,N/A,N/A,N/A,N/A,N/A
77242113UCO3001,Adult,Czech Republic,DD5-CZ10006,Michal Konecny,CZ100062001,1,I-4,15 Apr 2026,-,-,-,-,-,-,-,-,3,14 Apr 2026,-,13 Apr 2026,-,12 Apr 2026,-,11 Apr 2026,-,10 Apr 2026,-,09 Apr 2026,-,08 Apr 2026,-,07 Apr 2026,Medication For Diarrhea;Day Not Applicable for Calculation,06 Apr 2026,Medication For Diarrhea;Day Not Applicable for Calculation,05 Apr 2026,Medication For Diarrhea;Day Not Applicable for Calculation,9,22,20,19,17,18,18,-,-,-,3,1,3,2,2,2,2,2,-,-,-,2,8,,,-,04 May 2026 22:06:47,N/A,N/A,N/A,N/A,N/A,N/A
77242113UCO3001,Adult,Czech Republic,DD5-CZ10006,Michal Konecny,CZ100062001,1,I-8,18 May 2026,-,-,-,-,-,-,-,-,2,17 May 2026,-,16 May 2026,-,15 May 2026,-,14 May 2026,-,13 May 2026,-,12 May 2026,-,11 May 2026,-,10 May 2026,Day Not Applicable for Calculation,09 May 2026,Day Not Applicable for Calculation,08 May 2026,Day Not Applicable for Calculation,7,5,9,7,7,8,8,-,-,-,3,1,1,1,1,1,1,1,-,-,-,1,6,,,-,-,N/A,N/A,N/A,N/A,N/A,N/A
77242113UCO3001,Adult,Czech Republic,DD5-CZ10006,Michal Konecny,CZ100062002,1,I-0,26 May 2026,Yes,14 May 2026,13 May 2026,13 May 2026,-,-,2,-,2,25 May 2026,-,24 May 2026,-,23 May 2026,-,22 May 2026,-,21 May 2026,-,20 May 2026,-,19 May 2026,-,18 May 2026,Day Not Applicable for Calculation,17 May 2026,Day Not Applicable for Calculation,16 May 2026,Day Not Applicable for Calculation,8,8,6,7,7,6,7,-,-,-,3,2,2,2,2,2,2,2,-,-,-,2,7,7,9,-,-,N/A,N/A,N/A,N/A,N/A,N/A
77242113UCO3001,Adult,Czech Republic,DD5-CZ10009,Jiri Pumprla,CZ100092001,1,I-0,05 May 2026,Yes,24 Apr 2026,23 Apr 2026,23 Apr 2026,-,-,2,-,2,04 May 2026,-,03 May 2026,-,02 May 2026,-,01 May 2026,-,30 Apr 2026,-,29 Apr 2026,-,28 Apr 2026,-,27 Apr 2026,Day Not Applicable for Calculation,26 Apr 2026,Day Not Applicable for Calculation,25 Apr 2026,Day Not Applicable for Calculation,5,5,5,5,5,5,5,-,-,-,2,1,1,1,1,1,1,1,-,-,-,1,5,5,7,-,05 May 2026 11:19:40,N/A,N/A,N/A,N/A,N/A,N/A
77242113UCO3001,Adult,Czech Republic,DD5-CZ10009,Jiri Pumprla,CZ100092001,1,I-2,19 May 2026,-,-,-,-,-,-,-,-,1,18 May 2026,-,17 May 2026,-,16 May 2026,-,15 May 2026,-,14 May 2026,-,13 May 2026,-,12 May 2026,-,11 May 2026,Day Not Applicable for Calculation,10 May 2026,Day Not Applicable for Calculation,09 May 2026,Day Not Applicable for Calculation,5,4,5,5,5,4,6,-,-,-,2,1,1,1,1,1,1,1,-,-,-,1,4,,,-,19 May 2026 10:38:25,N/A,N/A,N/A,N/A,N/A,N/A
77242113UCO3001,Adult,Czech Republic,DD5-CZ10012,Stefan Konecny,CZ100122001,5,I-0,07 Apr 2026,Yes,24 Mar 2026,22 Mar 2026,22 Mar 2026,-,-,2,-,2,06 Apr 2026,-,05 Apr 2026,-,04 Apr 2026,-,03 Apr 2026,-,02 Apr 2026,-,01 Apr 2026,-,31 Mar 2026,-,30 Mar 2026,Day Not Applicable for Calculation,29 Mar 2026,Day Not Applicable for Calculation,28 Mar 2026,Day Not Applicable for Calculation,8,11,5,9,11,10,13,-,-,-,3,1,2,2,2,2,2,2,-,-,-,2,7,7,9,-,04 May 2026 08:44:52,N/A,N/A,N/A,N/A,N/A,N/A
77242113UCO3001,Adult,Czech Republic,DD5-CZ10012,Stefan Konecny,CZ100122001,5,I-2,22 Apr 2026,-,-,-,-,-,-,-,-,2,21 Apr 2026,-,20 Apr 2026,-,19 Apr 2026,-,18 Apr 2026,-,17 Apr 2026,-,16 Apr 2026,-,15 Apr 2026,-,14 Apr 2026,Day Not Applicable for Calculation,13 Apr 2026,Day Not Applicable for Calculation,12 Apr 2026,Day Not Applicable for Calculation,7,5,6,6,7,8,2,-,-,-,1,1,0,1,1,1,2,0,-,-,-,1,4,,,-,04 May 2026 08:45:07,N/A,N/A,N/A,N/A,N/A,N/A
77242113UCO3001,Adult,Czech Republic,DD5-CZ10012,Stefan Konecny,CZ100122001,5,I-4,07 May 2026,-,-,-,-,-,-,-,-,1,06 May 2026,-,05 May 2026,-,04 May 2026,-,03 May 2026,-,02 May 2026,-,01 May 2026,-,30 Apr 2026,-,29 Apr 2026,Day Not Applicable for Calculation,28 Apr 2026,Day Not Applicable for Calculation,27 Apr 2026,Day Not Applicable for Calculation,8,7,7,8,4,11,7,-,-,-,1,2,1,1,1,0,1,1,-,-,-,1,3,,,-,-,N/A,N/A,N/A,N/A,N/A,N/A
77242113UCO3001,Adult,Czech Republic,DD5-CZ10013,David Stepek,CZ100132001,1,I-0,24 Mar 2026,Yes,12 Mar 2026,11 Mar 2026,11 Mar 2026,-,-,2,-,2,23 Mar 2026,-,22 Mar 2026,-,21 Mar 2026,-,20 Mar 2026,-,19 Mar 2026,-,18 Mar 2026,-,17 Mar 2026,-,16 Mar 2026,Day Not Applicable for Calculation,15 Mar 2026,Day Not Applicable for Calculation,14 Mar 2026,Day Not Applicable for Calculation,8,6,5,7,6,7,6,-,-,-,3,1,1,1,0,1,1,1,-,-,-,1,6,6,8,-,05 Apr 2026 22:41:27,N/A,N/A,N/A,N/A,N/A,N/A
77242113UCO3001,Adult,Czech Republic,DD5-CZ10013,David Stepek,CZ100132001,1,I-2,08 Apr 2026,-,-,-,-,-,-,-,-,2,07 Apr 2026,-,06 Apr 2026,-,05 Apr 2026,-,04 Apr 2026,-,03 Apr 2026,-,02 Apr 2026,-,01 Apr 2026,-,31 Mar 2026,Day Not Applicable for Calculation,30 Mar 2026,Day Not Applicable for Calculation,29 Mar 2026,Day Not Applicable for Calculation,5,2,3,6,5,5,5,-,-,-,2,0,0,0,0,1,1,0,-,-,-,0,4,,,-,27 May 2026 12:53:52,N/A,N/A,N/A,N/A,N/A,N/A
77242113UCO3001,Adult,Czech Republic,DD5-CZ10013,David Stepek,CZ100132001,1,I-4,21 Apr 2026,-,-,-,-,-,-,-,-,0,20 Apr 2026,-,19 Apr 2026,-,18 Apr 2026,-,17 Apr 2026,-,16 Apr 2026,-,15 Apr 2026,-,14 Apr 2026,-,13 Apr 2026,Day Not Applicable for Calculation,12 Apr 2026,Day Not Applicable for Calculation,11 Apr 2026,Day Not Applicable for Calculation,4,3,4,3,3,4,4,-,-,-,2,0,0,0,0,0,0,0,-,-,-,0,2,,,-,27 May 2026 12:54:41,N/A,N/A,N/A,N/A,N/A,N/A
77242113UCO3001,Adult,Czech Republic,DD5-CZ10013,David Stepek,CZ100132002,1,I-0,12 May 2026,Yes,21 Apr 2026,20 Apr 2026,21 Apr 2026,-,-,2,-,2,11 May 2026,-,10 May 2026,-,09 May 2026,-,08 May 2026,-,07 May 2026,-,06 May 2026,-,05 May 2026,Missing Diary,04 May 2026,Day Not Applicable for Calculation,03 May 2026,Day Not Applicable for Calculation,02 May 2026,Day Not Applicable for Calculation,2,1,1,1,1,2,-,-,-,-,0,0,0,0,0,0,0,-,-,-,-,0,2,2,4,-,-,N/A,N/A,N/A,N/A,N/A,N/A
77242113UCO3001,Adult,Czech Republic,DD5-CZ10013,David Stepek,CZ100132002,1,I-2,26 May 2026,-,-,-,-,-,-,-,-,1,25 May 2026,-,24 May 2026,Missing Diary,23 May 2026,-,22 May 2026,-,21 May 2026,-,20 May 2026,-,19 May 2026,-,18 May 2026,Missing Diary;Day Not Applicable for Calculation,17 May 2026,Day Not Applicable for Calculation,16 May 2026,Day Not Applicable for Calculation,1,-,1,2,1,2,2,-,-,-,1,0,-,0,0,0,0,0,-,-,-,0,2,,,-,-,N/A,N/A,N/A,N/A,N/A,N/A
77242113UCO3001,Adolescent,Czech Republic,DD5-CZ10020,Lucie Gonsorcikova,CZ100201001,1,Unscheduled 1,04 May 2026,Yes,20 Apr 2026,12 Apr 2026,15 Apr 2026,-,-,2,-,3,03 May 2026,-,02 May 2026,-,01 May 2026,-,30 Apr 2026,-,29 Apr 2026,-,28 Apr 2026,-,27 Apr 2026,-,26 Apr 2026,Day Not Applicable for Calculation,25 Apr 2026,Day Not Applicable for Calculation,24 Apr 2026,Day Not Applicable for Calculation,5,6,6,7,6,3,3,-,-,-,2,0,0,0,0,0,0,0,-,-,-,0,5,4,7,-,-,N/A,N/A,N/A,N/A,N/A,N/A
77242113UCO3001,Adolescent,Czech Republic,DD5-CZ10020,Lucie Gonsorcikova,CZ100201001,1,I-0,18 May 2026,Yes,01 May 2026,01 May 2026,01 May 2026,-,-,2,-,3,17 May 2026,-,16 May 2026,-,15 May 2026,-,14 May 2026,-,13 May 2026,-,12 May 2026,-,11 May 2026,-,10 May 2026,Day Not Applicable for Calculation,09 May 2026,Day Not Applicable for Calculation,08 May 2026,Day Not Applicable for Calculation,6,6,6,6,6,6,6,-,-,-,3,0,0,0,0,0,0,0,-,-,-,0,6,5,8,-,04 May 2026 09:51:14,N/A,N/A,N/A,N/A,N/A,N/A
77242113UCO3001,Adult,Czech Republic,DD5-CZ10021,Martin Bortlik,CZ100212001,1,I-0,07 Apr 2026,Yes,16 Mar 2026,15 Mar 2026,16 Mar 2026,-,-,3,-,3,06 Apr 2026,-,05 Apr 2026,-,04 Apr 2026,-,03 Apr 2026,-,02 Apr 2026,-,01 Apr 2026,-,31 Mar 2026,-,30 Mar 2026,Day Not Applicable for Calculation,29 Mar 2026,Day Not Applicable for Calculation,28 Mar 2026,Day Not Applicable for Calculation,11,11,10,11,11,10,9,-,-,-,3,2,2,2,2,2,2,2,-,-,-,2,8,8,11,-,20 Apr 2026 09:27:58,N/A,N/A,N/A,N/A,N/A,N/A
77242113UCO3001,Adult,Czech Republic,DD5-CZ10021,Martin Bortlik,CZ100212001,1,I-2,20 Apr 2026,-,-,-,-,-,-,-,-,3,19 Apr 2026,-,18 Apr 2026,-,17 Apr 2026,-,16 Apr 2026,-,15 Apr 2026,-,14 Apr 2026,-,13 Apr 2026,-,12 Apr 2026,Day Not Applicable for Calculation,11 Apr 2026,Day Not Applicable for Calculation,10 Apr 2026,Day Not Applicable for Calculation,8,7,9,8,8,7,8,-,-,-,3,2,2,1,1,1,2,1,-,-,-,1,7,,,-,20 Apr 2026 09:29:01,N/A,N/A,N/A,N/A,N/A,N/A
77242113UCO3001,Adult,Czech Republic,DD5-CZ10021,Martin Bortlik,CZ100212001,1,I-4,05 May 2026,-,-,-,-,-,-,-,-,1,04 May 2026,-,03 May 2026,-,02 May 2026,-,01 May 2026,-,30 Apr 2026,-,29 Apr 2026,-,28 Apr 2026,-,27 Apr 2026,Day Not Applicable for Calculation,26 Apr 2026,Day Not Applicable for Calculation,25 Apr 2026,Day Not Applicable for Calculation,6,6,6,6,7,7,6,-,-,-,3,0,0,1,1,1,1,1,-,-,-,1,5,,,-,-,N/A,N/A,N/A,N/A,N/A,N/A
77242113UCO3001,Adult,Czech Republic,DD5-CZ10022,Petr Hrabak,CZ100222002,1,I-0,19 Feb 2026,Yes,11 Feb 2026,10 Feb 2026,11 Feb 2026,-,-,2,-,2,18 Feb 2026,-,17 Feb 2026,-,16 Feb 2026,-,15 Feb 2026,-,14 Feb 2026,-,13 Feb 2026,-,12 Feb 2026,-,11 Feb 2026,Endoscopy;Bowel Preparation for Procedure;Day Not Applicable for Calculation,10 Feb 2026,Bowel Preparation for Procedure;Day Not Applicable for Calculation,09 Feb 2026,Day Not Applicable for Calculation,3,2,2,3,4,3,2,-,-,-,1,1,1,0,0,0,2,2,-,-,-,1,4,4,6,-,19 Feb 2026 15:41:35,N/A,N/A,N/A,N/A,N/A,N/A
77242113UCO3001,Adult,Czech Republic,DD5-CZ10022,Petr Hrabak,CZ100222003,1,I-0,09 Mar 2026,Yes,11 Feb 2026,10 Feb 2026,11 Feb 2026,-,-,2,-,2,08 Mar 2026,-,07 Mar 2026,-,06 Mar 2026,-,05 Mar 2026,-,04 Mar 2026,-,03 Mar 2026,Missing Diary,02 Mar 2026,Missing Diary,01 Mar 2026,Missing Diary;Day Not Applicable for Calculation,28 Feb 2026,Missing Diary;Day Not Applicable for Calculation,27 Feb 2026,Missing Diary;Day Not Applicable for Calculation,7,7,6,6,7,-,-,-,-,-,3,2,2,2,2,2,-,-,-,-,-,2,7,7,9,-,22 Mar 2026 18:34:58,N/A,N/A,N/A,N/A,N/A,N/A
77242113UCO3001,Adult,Czech Republic,DD5-CZ10022,Petr Hrabak,CZ100222003,1,I-2,27 Mar 2026,-,-,-,-,-,-,-,-,2,26 Mar 2026,-,25 Mar 2026,-,24 Mar 2026,-,23 Mar 2026,-,22 Mar 2026,-,21 Mar 2026,-,20 Mar 2026,-,19 Mar 2026,Day Not Applicable for Calculation,18 Mar 2026,Day Not Applicable for Calculation,17 Mar 2026,Day Not Applicable for Calculation,7,3,3,3,5,5,5,-,-,-,2,0,0,1,1,1,1,2,-,-,-,1,5,,,-,27 Mar 2026 07:22:31,N/A,N/A,N/A,N/A,N/A,N/A
77242113UCO3001,Adult,Czech Republic,DD5-CZ10022,Petr Hrabak,CZ100222003,1,I-4,08 Apr 2026,-,-,-,-,-,-,-,-,2,07 Apr 2026,-,06 Apr 2026,-,05 Apr 2026,-,04 Apr 2026,-,03 Apr 2026,-,02 Apr 2026,-,01 Apr 2026,-,31 Mar 2026,Day Not Applicable for Calculation,30 Mar 2026,Day Not Applicable for Calculation,29 Mar 2026,Day Not Applicable for Calculation,3,3,4,4,5,4,3,-,-,-,2,1,0,0,2,1,1,2,-,-,-,1,5,,,-,08 Apr 2026 07:59:35,N/A,N/A,N/A,N/A,N/A,N/A
77242113UCO3001,Adult,Czech Republic,DD5-CZ10022,Petr Hrabak,CZ100222003,1,I-8,04 May 2026,-,-,-,-,-,-,-,-,2,03 May 2026,-,02 May 2026,-,01 May 2026,-,30 Apr 2026,-,29 Apr 2026,-,28 Apr 2026,-,27 Apr 2026,-,26 Apr 2026,Day Not Applicable for Calculation,25 Apr 2026,Day Not Applicable for Calculation,24 Apr 2026,Missing Diary;Day Not Applicable for Calculation,3,5,3,3,3,2,3,-,-,-,1,0,0,0,0,0,0,0,-,-,-,0,3,,,-,04 May 2026 07:52:47,N/A,N/A,N/A,N/A,N/A,N/A
77242113UCO3001,Adult,Czech Republic,DD5-CZ10022,Petr Hrabak,CZ100222005,1,I-0,09 Apr 2026,Yes,08 Apr 2026,31 Mar 2026,01 Apr 2026,-,-,2,-,2,08 Apr 2026,Endoscopy,07 Apr 2026,-,06 Apr 2026,-,05 Apr 2026,-,04 Apr 2026,-,03 Apr 2026,-,02 Apr 2026,-,01 Apr 2026,Bowel Preparation for Procedure;Day Not Applicable for Calculation,31 Mar 2026,Bowel Preparation for Procedure;Day Not Applicable for Calculation,30 Mar 2026,-,-,3,3,4,3,4,3,-,-,3,1,-,2,2,2,2,2,2,-,-,2,2,5,5,7,-,-,N/A,N/A,N/A,N/A,N/A,N/A
77242113UCO3001,Adult,Czech Republic,DD5-CZ10022,Petr Hrabak,CZ100222005,1,I-2,22 Apr 2026,-,-,-,-,-,-,-,-,2,21 Apr 2026,-,20 Apr 2026,-,19 Apr 2026,-,18 Apr 2026,-,17 Apr 2026,-,16 Apr 2026,-,15 Apr 2026,-,14 Apr 2026,Day Not Applicable for Calculation,13 Apr 2026,Day Not Applicable for Calculation,12 Apr 2026,Day Not Applicable for Calculation,3,3,5,3,2,3,2,-,-,-,1,1,2,2,1,1,1,2,-,-,-,1,4,,,-,22 Apr 2026 14:03:33,N/A,N/A,N/A,N/A,N/A,N/A
77242113UCO3001,Adult,Czech Republic,DD5-CZ10022,Petr Hrabak,CZ100222005,1,I-4,05 May 2026,-,-,-,-,-,-,-,-,2,04 May 2026,-,03 May 2026,-,02 May 2026,-,01 May 2026,-,30 Apr 2026,-,29 Apr 2026,-,28 Apr 2026,-,27 Apr 2026,Day Not Applicable for Calculation,26 Apr 2026,Day Not Applicable for Calculation,25 Apr 2026,Day Not Applicable for Calculation,4,2,2,2,2,2,2,-,-,-,1,1,1,1,1,2,1,1,-,-,-,1,4,,,-,05 May 2026 07:30:02,N/A,N/A,N/A,N/A,N/A,N/A
1 Protocol Study Population Country Site Principal Investigator Participant ID Baseline Stool Frequency Visit Visit Date Endoscopy Completed? Endoscopy Date Bowel Preparation Start Date 1 Bowel Preparation End Date 1 Bowel Preparation Start Date 2 Bowel Preparation End Date 2 Central Endoscopy Score Local Endoscopy Score PGA Score Eligible Day (-1) Day (-1) Excluded Reason(s) Eligible Day (-2) Day (-2) Excluded Reason(s) Eligible Day (-3) Day (-3) Excluded Reason(s) Eligible Day (-4) Day (-4) Excluded Reason(s) Eligible Day (-5) Day (-5) Excluded Reason(s) Eligible Day (-6) Day (-6) Excluded Reason(s) Eligible Day (-7) Day (-7) Excluded Reason(s) Eligible Day (-8) Day (-8) Excluded Reason(s) Eligible Day (-9) Day (-9) Excluded Reason(s) Eligible Day (-10) Day (-10) Excluded Reason(s) Eligible Day (-1) Stool Count Eligible Day (-2) Stool Count Eligible Day (-3) Stool Count Eligible Day (-4) Stool Count Eligible Day (-5) Stool Count Eligible Day (-6) Stool Count Eligible Day (-7) Stool Count Eligible Day (-8) Stool Count Eligible Day (-9) Stool Count Eligible Day (-10) Stool Count Stool Frequency Sub-score Eligible Day (-1) Rectal Bleeding Score Eligible Day (-2) Rectal Bleeding Score Eligible Day (-3) Rectal Bleeding Score Eligible Day (-4) Rectal Bleeding Score Eligible Day (-5) Rectal Bleeding Score Eligible Day (-6) Rectal Bleeding Score Eligible Day (-7) Rectal Bleeding Score Eligible Day (-8) Rectal Bleeding Score Eligible Day (-9) Rectal Bleeding Score Eligible Day (-10) Rectal Bleeding Score Rectal Bleeding Sub-score Partial Mayo Score Modified Mayo Score Full Mayo Score Site Action Last Mayo Score Submission Week I-12 Clinical Responder Week I-12 Clinical Remission Clinical Flare Loss of Response Partial Mayo Response Post Loss of Response Partial Mayo Response for Clinical Non-Responders
2 77242113UCO3001 Adult Czech Republic DD5-CZ10001 Matej Falc CZ100012001 1 I-0 19 Feb 2026 Yes 05 Feb 2026 04 Feb 2026 04 Feb 2026 - - 2 - 3 18 Feb 2026 - 17 Feb 2026 - 16 Feb 2026 - 15 Feb 2026 - 14 Feb 2026 - 13 Feb 2026 - 12 Feb 2026 - 11 Feb 2026 Day Not Applicable for Calculation 10 Feb 2026 Day Not Applicable for Calculation 09 Feb 2026 Day Not Applicable for Calculation 10 8 7 5 7 8 8 - - - 3 1 1 1 0 1 1 1 - - - 1 7 6 10 - 08 Apr 2026 07:11:25 N/A N/A N/A N/A N/A N/A
3 77242113UCO3001 Adult Czech Republic DD5-CZ10001 Matej Falc CZ100012001 1 I-2 04 Mar 2026 - - - - - - - - 3 03 Mar 2026 - 02 Mar 2026 - 01 Mar 2026 - 28 Feb 2026 - 27 Feb 2026 - 26 Feb 2026 - 25 Feb 2026 - 24 Feb 2026 Day Not Applicable for Calculation 23 Feb 2026 Day Not Applicable for Calculation 22 Feb 2026 Day Not Applicable for Calculation 5 4 5 4 5 6 6 - - - 2 1 0 1 0 1 0 1 - - - 1 6 - - N/A N/A N/A N/A N/A N/A
4 77242113UCO3001 Adult Czech Republic DD5-CZ10001 Matej Falc CZ100012001 1 I-4 18 Mar 2026 - - - - - - - - 2 17 Mar 2026 - 16 Mar 2026 - 15 Mar 2026 - 14 Mar 2026 - 13 Mar 2026 - 12 Mar 2026 - 11 Mar 2026 - 10 Mar 2026 Day Not Applicable for Calculation 09 Mar 2026 Day Not Applicable for Calculation 08 Mar 2026 Day Not Applicable for Calculation 5 5 5 4 5 4 5 - - - 2 1 0 0 1 1 1 0 - - - 1 5 - 08 Apr 2026 07:11:43 N/A N/A N/A N/A N/A N/A
5 77242113UCO3001 Adult Czech Republic DD5-CZ10001 Matej Falc CZ100012001 1 I-8 05 May 2026 - - - - - - - - 1 04 May 2026 - 03 May 2026 - 02 May 2026 - 01 May 2026 - 30 Apr 2026 - 29 Apr 2026 - 28 Apr 2026 - 27 Apr 2026 Day Not Applicable for Calculation 26 Apr 2026 Day Not Applicable for Calculation 25 Apr 2026 Day Not Applicable for Calculation 3 3 4 4 5 4 4 - - - 2 1 1 1 1 1 1 1 - - - 1 4 - - N/A N/A N/A N/A N/A N/A
6 77242113UCO3001 Adult Czech Republic DD5-CZ10001 Matej Falc CZ100012001 1 I-12 13 May 2026 Yes 06 May 2026 05 May 2026 05 May 2026 - - 1 - 1 12 May 2026 - 11 May 2026 - 10 May 2026 - 09 May 2026 - 08 May 2026 - 07 May 2026 - 06 May 2026 Endoscopy 05 May 2026 Bowel Preparation for Procedure;Day Not Applicable for Calculation 04 May 2026 - 03 May 2026 Day Not Applicable for Calculation 5 4 6 5 5 5 - - 3 - 2 1 0 1 1 1 1 - - 1 - 1 4 4 5 - - Clinical Responder No N/A N/A N/A N/A
7 77242113UCO3001 Adult Czech Republic DD5-CZ10001 Matej Falc CZ100012002 1 I-0 08 Apr 2026 Yes 18 Mar 2026 17 Mar 2026 18 Mar 2026 - - 2 - 2 07 Apr 2026 - 06 Apr 2026 - 05 Apr 2026 - 04 Apr 2026 Missing Diary 03 Apr 2026 - 02 Apr 2026 - 01 Apr 2026 - 31 Mar 2026 Day Not Applicable for Calculation 30 Mar 2026 Day Not Applicable for Calculation 29 Mar 2026 Day Not Applicable for Calculation 3 3 4 - 3 3 4 - - - 1 0 0 0 - 0 0 1 - - - 0 3 3 5 - - N/A N/A N/A N/A N/A N/A
8 77242113UCO3001 Adult Czech Republic DD5-CZ10001 Matej Falc CZ100012002 1 I-2 23 Apr 2026 - - - - - - - - 2 22 Apr 2026 Missing Diary 21 Apr 2026 - 20 Apr 2026 - 19 Apr 2026 - 18 Apr 2026 - 17 Apr 2026 - 16 Apr 2026 - 15 Apr 2026 Day Not Applicable for Calculation 14 Apr 2026 Day Not Applicable for Calculation 13 Apr 2026 Day Not Applicable for Calculation - 3 3 6 5 5 4 - - - 2 - 0 0 1 1 1 1 - - - 1 5 - - N/A N/A N/A N/A N/A N/A
9 77242113UCO3001 Adult Czech Republic DD5-CZ10001 Matej Falc CZ100012002 1 I-4 06 May 2026 - - - - - - - - 1 05 May 2026 - 04 May 2026 - 03 May 2026 - 02 May 2026 - 01 May 2026 - 30 Apr 2026 - 29 Apr 2026 - 28 Apr 2026 Day Not Applicable for Calculation 27 Apr 2026 Day Not Applicable for Calculation 26 Apr 2026 Day Not Applicable for Calculation 6 3 2 3 3 3 3 - - - 1 1 0 0 0 1 1 0 - - - 0 2 - - N/A N/A N/A N/A N/A N/A
10 77242113UCO3001 Adult Czech Republic DD5-CZ10001 Matej Falc CZ100012003 1 I-0 27 May 2026 Yes 13 May 2026 12 May 2026 12 May 2026 - - 3 - 2 26 May 2026 - 25 May 2026 - 24 May 2026 - 23 May 2026 - 22 May 2026 - 21 May 2026 - 20 May 2026 - 19 May 2026 Day Not Applicable for Calculation 18 May 2026 Day Not Applicable for Calculation 17 May 2026 Day Not Applicable for Calculation 6 9 7 8 9 7 8 - - - 3 2 2 2 2 1 1 1 - - - 2 7 8 10 - 27 May 2026 07:24:39 N/A N/A N/A N/A N/A N/A
11 77242113UCO3001 Adult Czech Republic DD5-CZ10006 Michal Konecny CZ100062001 1 I-0 20 Mar 2026 Yes 19 Feb 2026 - - - - 3 - 3 19 Mar 2026 - 18 Mar 2026 - 17 Mar 2026 - 16 Mar 2026 - 15 Mar 2026 - 14 Mar 2026 - 13 Mar 2026 - 12 Mar 2026 Day Not Applicable for Calculation 11 Mar 2026 Day Not Applicable for Calculation 10 Mar 2026 Day Not Applicable for Calculation 7 7 8 8 7 8 5 - - - 3 2 1 1 1 1 1 0 - - - 1 7 7 10 - 20 Mar 2026 07:02:44 N/A N/A N/A N/A N/A N/A
12 77242113UCO3001 Adult Czech Republic DD5-CZ10006 Michal Konecny CZ100062001 1 I-2 08 Apr 2026 - - - - - - - - 2 07 Apr 2026 Medication For Diarrhea 06 Apr 2026 Medication For Diarrhea 05 Apr 2026 Medication For Diarrhea 04 Apr 2026 Medication For Diarrhea 03 Apr 2026 Medication For Diarrhea 02 Apr 2026 Medication For Diarrhea 01 Apr 2026 Medication For Diarrhea 31 Mar 2026 Medication For Diarrhea;Day Not Applicable for Calculation 30 Mar 2026 Medication For Diarrhea;Day Not Applicable for Calculation 29 Mar 2026 Day Not Applicable for Calculation - - - - - - - - - - Non-Evaluable - - - - - - - - - - Non-Evaluable Non-Evaluable Non-Evaluable Non-Evaluable - - N/A N/A N/A N/A N/A N/A
13 77242113UCO3001 Adult Czech Republic DD5-CZ10006 Michal Konecny CZ100062001 1 I-4 15 Apr 2026 - - - - - - - - 3 14 Apr 2026 - 13 Apr 2026 - 12 Apr 2026 - 11 Apr 2026 - 10 Apr 2026 - 09 Apr 2026 - 08 Apr 2026 - 07 Apr 2026 Medication For Diarrhea;Day Not Applicable for Calculation 06 Apr 2026 Medication For Diarrhea;Day Not Applicable for Calculation 05 Apr 2026 Medication For Diarrhea;Day Not Applicable for Calculation 9 22 20 19 17 18 18 - - - 3 1 3 2 2 2 2 2 - - - 2 8 - 04 May 2026 22:06:47 N/A N/A N/A N/A N/A N/A
14 77242113UCO3001 Adult Czech Republic DD5-CZ10006 Michal Konecny CZ100062001 1 I-8 18 May 2026 - - - - - - - - 2 17 May 2026 - 16 May 2026 - 15 May 2026 - 14 May 2026 - 13 May 2026 - 12 May 2026 - 11 May 2026 - 10 May 2026 Day Not Applicable for Calculation 09 May 2026 Day Not Applicable for Calculation 08 May 2026 Day Not Applicable for Calculation 7 5 9 7 7 8 8 - - - 3 1 1 1 1 1 1 1 - - - 1 6 - - N/A N/A N/A N/A N/A N/A
15 77242113UCO3001 Adult Czech Republic DD5-CZ10006 Michal Konecny CZ100062002 1 I-0 26 May 2026 Yes 14 May 2026 13 May 2026 13 May 2026 - - 2 - 2 25 May 2026 - 24 May 2026 - 23 May 2026 - 22 May 2026 - 21 May 2026 - 20 May 2026 - 19 May 2026 - 18 May 2026 Day Not Applicable for Calculation 17 May 2026 Day Not Applicable for Calculation 16 May 2026 Day Not Applicable for Calculation 8 8 6 7 7 6 7 - - - 3 2 2 2 2 2 2 2 - - - 2 7 7 9 - - N/A N/A N/A N/A N/A N/A
16 77242113UCO3001 Adult Czech Republic DD5-CZ10009 Jiri Pumprla CZ100092001 1 I-0 05 May 2026 Yes 24 Apr 2026 23 Apr 2026 23 Apr 2026 - - 2 - 2 04 May 2026 - 03 May 2026 - 02 May 2026 - 01 May 2026 - 30 Apr 2026 - 29 Apr 2026 - 28 Apr 2026 - 27 Apr 2026 Day Not Applicable for Calculation 26 Apr 2026 Day Not Applicable for Calculation 25 Apr 2026 Day Not Applicable for Calculation 5 5 5 5 5 5 5 - - - 2 1 1 1 1 1 1 1 - - - 1 5 5 7 - 05 May 2026 11:19:40 N/A N/A N/A N/A N/A N/A
17 77242113UCO3001 Adult Czech Republic DD5-CZ10009 Jiri Pumprla CZ100092001 1 I-2 19 May 2026 - - - - - - - - 1 18 May 2026 - 17 May 2026 - 16 May 2026 - 15 May 2026 - 14 May 2026 - 13 May 2026 - 12 May 2026 - 11 May 2026 Day Not Applicable for Calculation 10 May 2026 Day Not Applicable for Calculation 09 May 2026 Day Not Applicable for Calculation 5 4 5 5 5 4 6 - - - 2 1 1 1 1 1 1 1 - - - 1 4 - 19 May 2026 10:38:25 N/A N/A N/A N/A N/A N/A
18 77242113UCO3001 Adult Czech Republic DD5-CZ10012 Stefan Konecny CZ100122001 5 I-0 07 Apr 2026 Yes 24 Mar 2026 22 Mar 2026 22 Mar 2026 - - 2 - 2 06 Apr 2026 - 05 Apr 2026 - 04 Apr 2026 - 03 Apr 2026 - 02 Apr 2026 - 01 Apr 2026 - 31 Mar 2026 - 30 Mar 2026 Day Not Applicable for Calculation 29 Mar 2026 Day Not Applicable for Calculation 28 Mar 2026 Day Not Applicable for Calculation 8 11 5 9 11 10 13 - - - 3 1 2 2 2 2 2 2 - - - 2 7 7 9 - 04 May 2026 08:44:52 N/A N/A N/A N/A N/A N/A
19 77242113UCO3001 Adult Czech Republic DD5-CZ10012 Stefan Konecny CZ100122001 5 I-2 22 Apr 2026 - - - - - - - - 2 21 Apr 2026 - 20 Apr 2026 - 19 Apr 2026 - 18 Apr 2026 - 17 Apr 2026 - 16 Apr 2026 - 15 Apr 2026 - 14 Apr 2026 Day Not Applicable for Calculation 13 Apr 2026 Day Not Applicable for Calculation 12 Apr 2026 Day Not Applicable for Calculation 7 5 6 6 7 8 2 - - - 1 1 0 1 1 1 2 0 - - - 1 4 - 04 May 2026 08:45:07 N/A N/A N/A N/A N/A N/A
20 77242113UCO3001 Adult Czech Republic DD5-CZ10012 Stefan Konecny CZ100122001 5 I-4 07 May 2026 - - - - - - - - 1 06 May 2026 - 05 May 2026 - 04 May 2026 - 03 May 2026 - 02 May 2026 - 01 May 2026 - 30 Apr 2026 - 29 Apr 2026 Day Not Applicable for Calculation 28 Apr 2026 Day Not Applicable for Calculation 27 Apr 2026 Day Not Applicable for Calculation 8 7 7 8 4 11 7 - - - 1 2 1 1 1 0 1 1 - - - 1 3 - - N/A N/A N/A N/A N/A N/A
21 77242113UCO3001 Adult Czech Republic DD5-CZ10013 David Stepek CZ100132001 1 I-0 24 Mar 2026 Yes 12 Mar 2026 11 Mar 2026 11 Mar 2026 - - 2 - 2 23 Mar 2026 - 22 Mar 2026 - 21 Mar 2026 - 20 Mar 2026 - 19 Mar 2026 - 18 Mar 2026 - 17 Mar 2026 - 16 Mar 2026 Day Not Applicable for Calculation 15 Mar 2026 Day Not Applicable for Calculation 14 Mar 2026 Day Not Applicable for Calculation 8 6 5 7 6 7 6 - - - 3 1 1 1 0 1 1 1 - - - 1 6 6 8 - 05 Apr 2026 22:41:27 N/A N/A N/A N/A N/A N/A
22 77242113UCO3001 Adult Czech Republic DD5-CZ10013 David Stepek CZ100132001 1 I-2 08 Apr 2026 - - - - - - - - 2 07 Apr 2026 - 06 Apr 2026 - 05 Apr 2026 - 04 Apr 2026 - 03 Apr 2026 - 02 Apr 2026 - 01 Apr 2026 - 31 Mar 2026 Day Not Applicable for Calculation 30 Mar 2026 Day Not Applicable for Calculation 29 Mar 2026 Day Not Applicable for Calculation 5 2 3 6 5 5 5 - - - 2 0 0 0 0 1 1 0 - - - 0 4 - 27 May 2026 12:53:52 N/A N/A N/A N/A N/A N/A
23 77242113UCO3001 Adult Czech Republic DD5-CZ10013 David Stepek CZ100132001 1 I-4 21 Apr 2026 - - - - - - - - 0 20 Apr 2026 - 19 Apr 2026 - 18 Apr 2026 - 17 Apr 2026 - 16 Apr 2026 - 15 Apr 2026 - 14 Apr 2026 - 13 Apr 2026 Day Not Applicable for Calculation 12 Apr 2026 Day Not Applicable for Calculation 11 Apr 2026 Day Not Applicable for Calculation 4 3 4 3 3 4 4 - - - 2 0 0 0 0 0 0 0 - - - 0 2 - 27 May 2026 12:54:41 N/A N/A N/A N/A N/A N/A
24 77242113UCO3001 Adult Czech Republic DD5-CZ10013 David Stepek CZ100132002 1 I-0 12 May 2026 Yes 21 Apr 2026 20 Apr 2026 21 Apr 2026 - - 2 - 2 11 May 2026 - 10 May 2026 - 09 May 2026 - 08 May 2026 - 07 May 2026 - 06 May 2026 - 05 May 2026 Missing Diary 04 May 2026 Day Not Applicable for Calculation 03 May 2026 Day Not Applicable for Calculation 02 May 2026 Day Not Applicable for Calculation 2 1 1 1 1 2 - - - - 0 0 0 0 0 0 0 - - - - 0 2 2 4 - - N/A N/A N/A N/A N/A N/A
25 77242113UCO3001 Adult Czech Republic DD5-CZ10013 David Stepek CZ100132002 1 I-2 26 May 2026 - - - - - - - - 1 25 May 2026 - 24 May 2026 Missing Diary 23 May 2026 - 22 May 2026 - 21 May 2026 - 20 May 2026 - 19 May 2026 - 18 May 2026 Missing Diary;Day Not Applicable for Calculation 17 May 2026 Day Not Applicable for Calculation 16 May 2026 Day Not Applicable for Calculation 1 - 1 2 1 2 2 - - - 1 0 - 0 0 0 0 0 - - - 0 2 - - N/A N/A N/A N/A N/A N/A
26 77242113UCO3001 Adolescent Czech Republic DD5-CZ10020 Lucie Gonsorcikova CZ100201001 1 Unscheduled 1 04 May 2026 Yes 20 Apr 2026 12 Apr 2026 15 Apr 2026 - - 2 - 3 03 May 2026 - 02 May 2026 - 01 May 2026 - 30 Apr 2026 - 29 Apr 2026 - 28 Apr 2026 - 27 Apr 2026 - 26 Apr 2026 Day Not Applicable for Calculation 25 Apr 2026 Day Not Applicable for Calculation 24 Apr 2026 Day Not Applicable for Calculation 5 6 6 7 6 3 3 - - - 2 0 0 0 0 0 0 0 - - - 0 5 4 7 - - N/A N/A N/A N/A N/A N/A
27 77242113UCO3001 Adolescent Czech Republic DD5-CZ10020 Lucie Gonsorcikova CZ100201001 1 I-0 18 May 2026 Yes 01 May 2026 01 May 2026 01 May 2026 - - 2 - 3 17 May 2026 - 16 May 2026 - 15 May 2026 - 14 May 2026 - 13 May 2026 - 12 May 2026 - 11 May 2026 - 10 May 2026 Day Not Applicable for Calculation 09 May 2026 Day Not Applicable for Calculation 08 May 2026 Day Not Applicable for Calculation 6 6 6 6 6 6 6 - - - 3 0 0 0 0 0 0 0 - - - 0 6 5 8 - 04 May 2026 09:51:14 N/A N/A N/A N/A N/A N/A
28 77242113UCO3001 Adult Czech Republic DD5-CZ10021 Martin Bortlik CZ100212001 1 I-0 07 Apr 2026 Yes 16 Mar 2026 15 Mar 2026 16 Mar 2026 - - 3 - 3 06 Apr 2026 - 05 Apr 2026 - 04 Apr 2026 - 03 Apr 2026 - 02 Apr 2026 - 01 Apr 2026 - 31 Mar 2026 - 30 Mar 2026 Day Not Applicable for Calculation 29 Mar 2026 Day Not Applicable for Calculation 28 Mar 2026 Day Not Applicable for Calculation 11 11 10 11 11 10 9 - - - 3 2 2 2 2 2 2 2 - - - 2 8 8 11 - 20 Apr 2026 09:27:58 N/A N/A N/A N/A N/A N/A
29 77242113UCO3001 Adult Czech Republic DD5-CZ10021 Martin Bortlik CZ100212001 1 I-2 20 Apr 2026 - - - - - - - - 3 19 Apr 2026 - 18 Apr 2026 - 17 Apr 2026 - 16 Apr 2026 - 15 Apr 2026 - 14 Apr 2026 - 13 Apr 2026 - 12 Apr 2026 Day Not Applicable for Calculation 11 Apr 2026 Day Not Applicable for Calculation 10 Apr 2026 Day Not Applicable for Calculation 8 7 9 8 8 7 8 - - - 3 2 2 1 1 1 2 1 - - - 1 7 - 20 Apr 2026 09:29:01 N/A N/A N/A N/A N/A N/A
30 77242113UCO3001 Adult Czech Republic DD5-CZ10021 Martin Bortlik CZ100212001 1 I-4 05 May 2026 - - - - - - - - 1 04 May 2026 - 03 May 2026 - 02 May 2026 - 01 May 2026 - 30 Apr 2026 - 29 Apr 2026 - 28 Apr 2026 - 27 Apr 2026 Day Not Applicable for Calculation 26 Apr 2026 Day Not Applicable for Calculation 25 Apr 2026 Day Not Applicable for Calculation 6 6 6 6 7 7 6 - - - 3 0 0 1 1 1 1 1 - - - 1 5 - - N/A N/A N/A N/A N/A N/A
31 77242113UCO3001 Adult Czech Republic DD5-CZ10022 Petr Hrabak CZ100222002 1 I-0 19 Feb 2026 Yes 11 Feb 2026 10 Feb 2026 11 Feb 2026 - - 2 - 2 18 Feb 2026 - 17 Feb 2026 - 16 Feb 2026 - 15 Feb 2026 - 14 Feb 2026 - 13 Feb 2026 - 12 Feb 2026 - 11 Feb 2026 Endoscopy;Bowel Preparation for Procedure;Day Not Applicable for Calculation 10 Feb 2026 Bowel Preparation for Procedure;Day Not Applicable for Calculation 09 Feb 2026 Day Not Applicable for Calculation 3 2 2 3 4 3 2 - - - 1 1 1 0 0 0 2 2 - - - 1 4 4 6 - 19 Feb 2026 15:41:35 N/A N/A N/A N/A N/A N/A
32 77242113UCO3001 Adult Czech Republic DD5-CZ10022 Petr Hrabak CZ100222003 1 I-0 09 Mar 2026 Yes 11 Feb 2026 10 Feb 2026 11 Feb 2026 - - 2 - 2 08 Mar 2026 - 07 Mar 2026 - 06 Mar 2026 - 05 Mar 2026 - 04 Mar 2026 - 03 Mar 2026 Missing Diary 02 Mar 2026 Missing Diary 01 Mar 2026 Missing Diary;Day Not Applicable for Calculation 28 Feb 2026 Missing Diary;Day Not Applicable for Calculation 27 Feb 2026 Missing Diary;Day Not Applicable for Calculation 7 7 6 6 7 - - - - - 3 2 2 2 2 2 - - - - - 2 7 7 9 - 22 Mar 2026 18:34:58 N/A N/A N/A N/A N/A N/A
33 77242113UCO3001 Adult Czech Republic DD5-CZ10022 Petr Hrabak CZ100222003 1 I-2 27 Mar 2026 - - - - - - - - 2 26 Mar 2026 - 25 Mar 2026 - 24 Mar 2026 - 23 Mar 2026 - 22 Mar 2026 - 21 Mar 2026 - 20 Mar 2026 - 19 Mar 2026 Day Not Applicable for Calculation 18 Mar 2026 Day Not Applicable for Calculation 17 Mar 2026 Day Not Applicable for Calculation 7 3 3 3 5 5 5 - - - 2 0 0 1 1 1 1 2 - - - 1 5 - 27 Mar 2026 07:22:31 N/A N/A N/A N/A N/A N/A
34 77242113UCO3001 Adult Czech Republic DD5-CZ10022 Petr Hrabak CZ100222003 1 I-4 08 Apr 2026 - - - - - - - - 2 07 Apr 2026 - 06 Apr 2026 - 05 Apr 2026 - 04 Apr 2026 - 03 Apr 2026 - 02 Apr 2026 - 01 Apr 2026 - 31 Mar 2026 Day Not Applicable for Calculation 30 Mar 2026 Day Not Applicable for Calculation 29 Mar 2026 Day Not Applicable for Calculation 3 3 4 4 5 4 3 - - - 2 1 0 0 2 1 1 2 - - - 1 5 - 08 Apr 2026 07:59:35 N/A N/A N/A N/A N/A N/A
35 77242113UCO3001 Adult Czech Republic DD5-CZ10022 Petr Hrabak CZ100222003 1 I-8 04 May 2026 - - - - - - - - 2 03 May 2026 - 02 May 2026 - 01 May 2026 - 30 Apr 2026 - 29 Apr 2026 - 28 Apr 2026 - 27 Apr 2026 - 26 Apr 2026 Day Not Applicable for Calculation 25 Apr 2026 Day Not Applicable for Calculation 24 Apr 2026 Missing Diary;Day Not Applicable for Calculation 3 5 3 3 3 2 3 - - - 1 0 0 0 0 0 0 0 - - - 0 3 - 04 May 2026 07:52:47 N/A N/A N/A N/A N/A N/A
36 77242113UCO3001 Adult Czech Republic DD5-CZ10022 Petr Hrabak CZ100222005 1 I-0 09 Apr 2026 Yes 08 Apr 2026 31 Mar 2026 01 Apr 2026 - - 2 - 2 08 Apr 2026 Endoscopy 07 Apr 2026 - 06 Apr 2026 - 05 Apr 2026 - 04 Apr 2026 - 03 Apr 2026 - 02 Apr 2026 - 01 Apr 2026 Bowel Preparation for Procedure;Day Not Applicable for Calculation 31 Mar 2026 Bowel Preparation for Procedure;Day Not Applicable for Calculation 30 Mar 2026 - - 3 3 4 3 4 3 - - 3 1 - 2 2 2 2 2 2 - - 2 2 5 5 7 - - N/A N/A N/A N/A N/A N/A
37 77242113UCO3001 Adult Czech Republic DD5-CZ10022 Petr Hrabak CZ100222005 1 I-2 22 Apr 2026 - - - - - - - - 2 21 Apr 2026 - 20 Apr 2026 - 19 Apr 2026 - 18 Apr 2026 - 17 Apr 2026 - 16 Apr 2026 - 15 Apr 2026 - 14 Apr 2026 Day Not Applicable for Calculation 13 Apr 2026 Day Not Applicable for Calculation 12 Apr 2026 Day Not Applicable for Calculation 3 3 5 3 2 3 2 - - - 1 1 2 2 1 1 1 2 - - - 1 4 - 22 Apr 2026 14:03:33 N/A N/A N/A N/A N/A N/A
38 77242113UCO3001 Adult Czech Republic DD5-CZ10022 Petr Hrabak CZ100222005 1 I-4 05 May 2026 - - - - - - - - 2 04 May 2026 - 03 May 2026 - 02 May 2026 - 01 May 2026 - 30 Apr 2026 - 29 Apr 2026 - 28 Apr 2026 - 27 Apr 2026 Day Not Applicable for Calculation 26 Apr 2026 Day Not Applicable for Calculation 25 Apr 2026 Day Not Applicable for Calculation 4 2 2 2 2 2 2 - - - 1 1 1 1 1 2 1 1 - - - 1 4 - 05 May 2026 07:30:02 N/A N/A N/A N/A N/A N/A
+134
View File
@@ -0,0 +1,134 @@
# Clario Report — 77242113UCO3001
| | |
|---|---|
| Verze | 1.2 |
| Datum | 2026-05-27 |
Sada skriptů pro import Clario CSV exportů (MayoScore, MayoDiary) do MongoDB a generování interaktivního Excel reportu pro studii 77242113UCO3001.
---
## Přehled
Skript `create_report.py` generuje Excel report ze dvou MongoDB kolekcí (databáze `Clario`) do adresáře `U:\Dropbox\!!!Days\Downloads Z230\`.
Název výstupního souboru: `YYYY-MM-DD 77242113UCO3001 Clario Reports.xlsm`
Soubor je ve formátu `.xlsm` (Excel s makry). Při otevření je nutné **povolit makra**.
---
## Spuštění
```bash
python create_report.py
```
---
## Listy
### MayoScore
Jeden řádek = jeden záznam (pacient × visit).
Zdroj: `Clario.MayoScore` — 37 záznamů, 14 pacientů, 8 center.
Řazení: Site → Subject ID → Visit (I-0, I-2, I-4, I-8, I-12, Unscheduled).
Řádky s Visit = `I-0` a Modified Mayo Score < 5 jsou zobrazeny **červeně tučně**.
**Interaktivita:** Klik na libovolný řádek automaticky přepne na list EligibleDays a vyfiltruje záznamy pro daného pacienta a visit.
| Sloupec | Popis |
|---|---|
| Site | Kód centra |
| Subject ID | Číslo pacienta |
| Visit | Kód návštěvy |
| Visit Date | Datum návštěvy |
| Baseline Stool Frequency | Výchozí frekvence stolic |
| Central Endoscopy Score | Centrální endoskopické skóre |
| PGA Score | Celkové hodnocení lékaře |
| Stool Frequency Sub-score | Subscore frekvence stolic |
| Rectal Bleeding Sub-score | Subscore rektálního krvácení |
| Partial Mayo Score | Parciální Mayo skóre |
| Modified Mayo Score | Modifikované Mayo skóre |
| Full Mayo Score | Úplné Mayo skóre |
### MayoDiary
Jeden řádek = jeden denní záznam deníku pacienta.
Zdroj: `Clario.MayoDiary` — 1 098 záznamů, 20 pacientů, 10 center.
Řazení: Subject ID → Report Date.
| Sloupec | Popis |
|---|---|
| Subject ID | Číslo pacienta |
| Report Date | Datum záznamu |
| Baseline Stool Count | Výchozí počet stolic |
| Stool Frequency | Frekvence stolic daný den |
| MAYO050 | Popis rektálního krvácení |
| Not Applicable | Záznam nepřipadá v úvahu |
| Constipation | Zácpa |
| Diarrhea | Průjem |
| Irregularity | Nepravidelnost |
### EligibleDays
Jeden řádek = jeden eligible day (-1 až -10) z MayoScore, obohacený o data z MayoDiary pro stejného pacienta a datum.
Řazení: Subject ID → Visit → Den (-1 první).
Dny **nezahrnuté** do výpočtu skóre (Included = No): žluté pozadí, šedý font.
| Sloupec | Popis |
|---|---|
| Included | Byl den zahrnut do výpočtu Mayo skóre? (Yes/No) |
| Subject ID | Číslo pacienta |
| Visit | Kód návštěvy |
| Visit Date | Datum návštěvy |
| Day | Číslo dne (-1 až -10) |
| Report Date | Datum daného dne |
| Baseline Stool Count | Výchozí počet stolic |
| Stool Frequency | Frekvence stolic daný den (z MayoDiary) |
| MAYO050 | Popis rektálního krvácení (z MayoDiary) |
| Not Applicable | Záznam nepřipadá v úvahu (z MayoDiary) |
| Constipation | Zácpa (z MayoDiary) |
| Diarrhea | Průjem (z MayoDiary) |
| Irregularity | Nepravidelnost (z MayoDiary) |
---
## Import dat do MongoDB
Skript `import_to_mongo.py` načte CSV soubory z adresáře `downloads/` a zapíše je do MongoDB.
```bash
python import_to_mongo.py # všechny CSV z downloads/
python import_to_mongo.py downloads/soubor.csv # jeden soubor
```
### Mapování souborů na kolekce
| Vzor v názvu souboru | Kolekce | Klíč záznamu |
|---|---|---|
| `MayoDiary` | `Clario.MayoDiary` | Subject ID + Form Number |
| `MayoScore` | `Clario.MayoScore` | Participant ID + Visit |
### Filtr
Importují se pouze řádky s `Country == "Czech Republic"`.
### Historie změn
Při změně datových polí se předchozí verze uloží do pole `history[]` dokumentu spolu s datem změny. Záznamy se nikdy nemažou.
Po zpracování se soubor přesune do `downloads/Zpracovano/`.
---
## MongoDB
| Parametr | Hodnota |
|---|---|
| URI | `mongodb://192.168.1.76:27017` |
| Databáze | `Clario` |
| Kolekce | `Clario.MayoScore`, `Clario.MayoDiary` |
+402
View File
@@ -0,0 +1,402 @@
"""
create_report.py
Verze: 1.2
Datum: 2026-05-27
Generuje Excel report (.xlsm) pro studii 77242113UCO3001 z MongoDB databáze Clario.
Výstup: U:/Dropbox/!!!Days/Downloads Z230/YYYY-MM-DD 77242113UCO3001 Clario Reports.xlsm
Listy:
MayoScore — jeden řádek = pacient × visit; řádky I-0 s Modified Mayo < 5 červeně tučně
MayoDiary — jeden řádek = denní záznam deníku pacienta
EligibleDays — jeden řádek = jeden eligible day z MayoScore obohacený o data z MayoDiary;
included/excluded flag, excluded dny šedě na žlutém pozadí
VBA makro (Worksheet_SelectionChange na listu MayoScore):
Klik na řádek → automaticky přepne na EligibleDays a vyfiltruje záznamy
pro daného pacienta a visit. Vyžaduje povolení maker při otevření souboru.
"""
from datetime import datetime
from pathlib import Path
from pymongo import MongoClient
from openpyxl import Workbook
from openpyxl.styles import Font, PatternFill, Alignment, Border, Side
from openpyxl.utils import get_column_letter
import xlwings as xw
# ---------------------------------------------------------------------------
# Konfigurace
# ---------------------------------------------------------------------------
MONGO_URI = "mongodb://192.168.1.76:27017"
DB_NAME = "Clario"
OUTPUT_DIR = Path(r"U:\Dropbox\!!!Days\Downloads Z230")
VISIT_ORDER = ["I-0", "I-2", "I-4", "I-8", "I-12"]
COLUMNS_SCORE = [
("Site", lambda d: d.get("site", {}).get("name", "")),
("Subject ID", lambda d: d.get("subject", {}).get("id", "")),
("Visit", lambda d: d["fields"].get("Visit", "")),
("Visit Date", lambda d: d["fields"].get("Visit Date", "")),
("Baseline Stool Frequency", lambda d: _num(d["fields"].get("Baseline Stool Frequency", ""))),
("Central Endoscopy Score", lambda d: _num(d["fields"].get("Central Endoscopy Score", ""))),
("PGA Score", lambda d: _num(d["fields"].get("PGA Score", ""))),
("Stool Frequency Sub-score", lambda d: _num(d["fields"].get("Stool Frequency Sub-score", ""))),
("Rectal Bleeding Sub-score", lambda d: _num(d["fields"].get("Rectal Bleeding Sub-score", ""))),
("Partial Mayo Score", lambda d: _num(d["fields"].get("Partial Mayo Score", ""))),
("Modified Mayo Score", lambda d: _num(d["fields"].get("Modified Mayo Score", ""))),
("Full Mayo Score", lambda d: _num(d["fields"].get("Full Mayo Score", ""))),
]
COLUMNS_DIARY = [
("Subject ID", lambda d: d.get("subject", {}).get("id", "")),
("Report Date", lambda d: d["fields"].get("Report Date", "")),
("Baseline Stool Count", lambda d: _num(d["fields"].get("Baseline Stool Count", ""))),
("Stool Frequency", lambda d: _num(d["fields"].get("Stool Frequency", ""))),
("MAYO050", lambda d: d["fields"].get("MAYO050", "")),
("Not Applicable", lambda d: d["fields"].get("Not Applicable", "")),
("Constipation", lambda d: d["fields"].get("Constipation", "")),
("Diarrhea", lambda d: d["fields"].get("Diarrhea", "")),
("Irregularity", lambda d: d["fields"].get("Irregularity", "")),
]
# ---------------------------------------------------------------------------
# Helpers
# ---------------------------------------------------------------------------
def _num(value):
"""Převede číselný string na int, jinak vrátí původní hodnotu nebo None."""
if value == "" or value is None:
return None
try:
return int(value)
except (ValueError, TypeError):
try:
return float(value)
except (ValueError, TypeError):
return value
def _visit_sort_key(doc):
visit = doc["fields"].get("Visit", "")
try:
idx = VISIT_ORDER.index(visit)
except ValueError:
idx = len(VISIT_ORDER)
return (doc.get("site", {}).get("name", ""), doc.get("subject", {}).get("id", ""), idx, visit)
def _iso_to_date(value):
"""ISO string → Python date pro Excel."""
if not isinstance(value, str):
return value
try:
return datetime.fromisoformat(value).date()
except ValueError:
return value
# ---------------------------------------------------------------------------
# Styly
# ---------------------------------------------------------------------------
HEADER_FILL = PatternFill("solid", fgColor="1F497D")
HEADER_FONT = Font(bold=True, color="FFFFFF", size=10)
CELL_FONT = Font(size=10)
ALIGN_CTR = Alignment(horizontal="center", vertical="center", wrap_text=False)
ALIGN_LEFT = Alignment(horizontal="left", vertical="center")
THIN = Side(style="thin", color="BFBFBF")
BORDER = Border(left=THIN, right=THIN, top=THIN, bottom=THIN)
# zebra
FILL_ODD = PatternFill("solid", fgColor="FFFFFF")
FILL_EVEN = PatternFill("solid", fgColor="EBF1DE")
SCORE_COLS = {"Partial Mayo Score", "Modified Mayo Score", "Full Mayo Score"}
SCORE_FILL = PatternFill("solid", fgColor="FFC7CE") # červená pro skóre ≥ 5 (placeholder — nepoužíváme podmíněné formátování)
# ---------------------------------------------------------------------------
# Sestavení sheetu
# ---------------------------------------------------------------------------
def _build_sheet(ws, docs, columns, date_cols, center_cols, col_widths, row_font_fn=None):
headers = [c[0] for c in columns]
for col_idx, header in enumerate(headers, 1):
cell = ws.cell(row=1, column=col_idx, value=header)
cell.font = HEADER_FONT
cell.fill = HEADER_FILL
cell.alignment = ALIGN_CTR
cell.border = BORDER
ws.row_dimensions[1].height = 28
for row_idx, doc in enumerate(docs, 2):
fill = FILL_EVEN if row_idx % 2 == 0 else FILL_ODD
font = row_font_fn(doc) if row_font_fn else CELL_FONT
for col_idx, (col_name, getter) in enumerate(columns, 1):
value = getter(doc)
if col_name in date_cols and isinstance(value, str):
value = _iso_to_date(value)
cell = ws.cell(row=row_idx, column=col_idx, value=value)
cell.font = font
cell.fill = fill
cell.border = BORDER
cell.alignment = ALIGN_CTR if col_name in center_cols else ALIGN_LEFT
for col_idx, (col_name, _) in enumerate(columns, 1):
ws.column_dimensions[get_column_letter(col_idx)].width = col_widths.get(col_name, 14)
for col_name in date_cols:
if col_name in headers:
letter = get_column_letter(headers.index(col_name) + 1)
for row_idx in range(2, len(docs) + 2):
ws[f"{letter}{row_idx}"].number_format = "DD-MMM-YYYY"
ws.freeze_panes = "A2"
ws.auto_filter.ref = f"A1:{get_column_letter(len(headers))}1"
def _score_row_font(doc):
visit = doc["fields"].get("Visit", "")
try:
mod_mayo = int(doc["fields"].get("Modified Mayo Score", ""))
except (ValueError, TypeError):
mod_mayo = None
if visit == "I-0" and mod_mayo is not None and mod_mayo < 5:
return Font(size=10, bold=True, color="FF0000")
return CELL_FONT
def build_mayo_score_sheet(ws, docs):
_build_sheet(
ws, docs, COLUMNS_SCORE,
date_cols={"Visit Date"},
center_cols={"Visit", "Central Endoscopy Score", "PGA Score",
"Stool Frequency Sub-score", "Rectal Bleeding Sub-score",
"Partial Mayo Score", "Modified Mayo Score", "Full Mayo Score",
"Baseline Stool Frequency"},
col_widths={
"Site": 18, "Subject ID": 16, "Visit": 12, "Visit Date": 14,
"Baseline Stool Frequency": 14, "Central Endoscopy Score": 14,
"PGA Score": 10, "Stool Frequency Sub-score": 14,
"Rectal Bleeding Sub-score": 14, "Partial Mayo Score": 14,
"Modified Mayo Score": 14, "Full Mayo Score": 13,
},
row_font_fn=_score_row_font,
)
def build_mayo_diary_sheet(ws, docs):
_build_sheet(
ws, docs, COLUMNS_DIARY,
date_cols={"Report Date"},
center_cols={"Baseline Stool Count", "Stool Frequency", "Not Applicable",
"Constipation", "Diarrhea", "Irregularity"},
col_widths={
"Subject ID": 16, "Report Date": 14, "Baseline Stool Count": 14,
"Stool Frequency": 14, "MAYO050": 48, "Not Applicable": 14,
"Constipation": 14, "Diarrhea": 12, "Irregularity": 14,
},
)
def build_eligible_days_sheet(ws, score_docs, diary_docs):
# Lookup diary records by (subject_id, date_part YYYY-MM-DD)
diary_lookup: dict[tuple, dict] = {}
for d in diary_docs:
subj = d.get("subject", {}).get("id", "")
date_iso = d["fields"].get("Report Date", "")
date_part = date_iso[:10] if date_iso else ""
if subj and date_part:
diary_lookup[(subj, date_part)] = d
headers = [
"Included", "Subject ID", "Visit", "Visit Date", "Day",
"Report Date", "Baseline Stool Count", "Stool Frequency",
"MAYO050", "Not Applicable", "Constipation", "Diarrhea", "Irregularity",
]
col_widths = {
"Included": 10, "Subject ID": 16, "Visit": 10, "Visit Date": 14, "Day": 8,
"Report Date": 14, "Baseline Stool Count": 14, "Stool Frequency": 14,
"MAYO050": 48, "Not Applicable": 14, "Constipation": 14,
"Diarrhea": 12, "Irregularity": 14,
}
center_cols = {"Included", "Visit", "Day", "Baseline Stool Count", "Stool Frequency",
"Not Applicable", "Constipation", "Diarrhea", "Irregularity"}
date_cols = {"Visit Date", "Report Date"}
no_fill = PatternFill("solid", fgColor="FFF2CC") # žlutá pro excluded dny
for col_idx, header in enumerate(headers, 1):
cell = ws.cell(row=1, column=col_idx, value=header)
cell.font = HEADER_FONT
cell.fill = HEADER_FILL
cell.alignment = ALIGN_CTR
cell.border = BORDER
ws.row_dimensions[1].height = 28
row_idx = 2
for score_doc in score_docs:
subj = score_doc.get("subject", {}).get("id", "")
visit = score_doc["fields"].get("Visit", "")
visit_date = score_doc["fields"].get("Visit Date", "")
for n in range(1, 11):
day_date_iso = score_doc["fields"].get(f"Eligible Day (-{n})")
if not day_date_iso or day_date_iso == "-":
continue
date_part = day_date_iso[:10]
excl_reason = score_doc["fields"].get(f"Day (-{n}) Excluded Reason(s)", "")
included = "No" if excl_reason and excl_reason != "-" else "Yes"
diary = diary_lookup.get((subj, date_part), {})
df = diary.get("fields", {})
fill = no_fill if included == "No" else (FILL_EVEN if row_idx % 2 == 0 else FILL_ODD)
font = Font(size=10, color="808080") if included == "No" else CELL_FONT
values = [
included,
subj,
visit,
_iso_to_date(visit_date) if isinstance(visit_date, str) else visit_date,
f"-{n}",
_iso_to_date(day_date_iso),
_num(df.get("Baseline Stool Count", "")),
_num(df.get("Stool Frequency", "")),
df.get("MAYO050", ""),
df.get("Not Applicable", ""),
df.get("Constipation", ""),
df.get("Diarrhea", ""),
df.get("Irregularity", ""),
]
for col_idx, (header, value) in enumerate(zip(headers, values), 1):
cell = ws.cell(row=row_idx, column=col_idx, value=value)
cell.font = font
cell.fill = fill
cell.border = BORDER
if header in date_cols:
cell.number_format = "DD-MMM-YYYY"
cell.alignment = ALIGN_CTR if header in center_cols else ALIGN_LEFT
row_idx += 1
for col_idx, header in enumerate(headers, 1):
ws.column_dimensions[get_column_letter(col_idx)].width = col_widths.get(header, 14)
ws.freeze_panes = "A2"
ws.auto_filter.ref = f"A1:{get_column_letter(len(headers))}1"
# ---------------------------------------------------------------------------
# Main
# ---------------------------------------------------------------------------
def main():
client = MongoClient(MONGO_URI, serverSelectionTimeoutMS=5000)
client.admin.command("ping")
db = client[DB_NAME]
score_docs = list(db["Clario.MayoScore"].find({}))
diary_docs = list(db["Clario.MayoDiary"].find({}))
client.close()
score_docs.sort(key=_visit_sort_key)
diary_docs.sort(key=lambda d: (
d.get("subject", {}).get("id", ""),
d["fields"].get("Report Date", ""),
))
wb = Workbook()
ws_score = wb.active
ws_score.title = "MayoScore"
build_mayo_score_sheet(ws_score, score_docs)
ws_diary = wb.create_sheet("MayoDiary")
build_mayo_diary_sheet(ws_diary, diary_docs)
ws_days = wb.create_sheet("EligibleDays")
build_eligible_days_sheet(ws_days, score_docs, diary_docs)
OUTPUT_DIR.mkdir(parents=True, exist_ok=True)
today = datetime.now().strftime("%Y-%m-%d")
filename = f"{today} 77242113UCO3001 Clario Reports.xlsx"
output_path = OUTPUT_DIR / filename
# Uložit jako .xlsx nejdřív, pak přepsat na .xlsm přes xlwings + injektovat VBA
xlsx_path = output_path.with_suffix(".xlsx")
xlsm_path = output_path.with_suffix(".xlsm")
wb.save(str(xlsx_path))
inject_vba(xlsx_path, xlsm_path)
xlsx_path.unlink(missing_ok=True)
print(f"Uloženo: {xlsm_path}")
print(f"MayoScore: {len(score_docs)} záznamů")
print(f"MayoDiary: {len(diary_docs)} záznamů")
print(f"EligibleDays: generováno z {len(score_docs)} score záznamů")
def inject_vba(xlsx_path: Path, xlsm_path: Path) -> None:
vba_code = '''\
Private Sub Worksheet_SelectionChange(ByVal Target As Range)
If Target.Row < 2 Or Target.Column < 1 Then Exit Sub
If Target.Rows.Count > 1 Then Exit Sub
Dim subjectId As String
Dim visit As String
subjectId = CStr(Me.Cells(Target.Row, 2).Value)
visit = CStr(Me.Cells(Target.Row, 3).Value)
If subjectId = "" Or visit = "" Then Exit Sub
Dim ws As Worksheet
On Error Resume Next
Set ws = ThisWorkbook.Sheets("EligibleDays")
On Error GoTo 0
If ws Is Nothing Then Exit Sub
Application.ScreenUpdating = False
ws.AutoFilterMode = False
ws.Range("A1").AutoFilter
ws.Range("A1").AutoFilter Field:=2, Criteria1:=subjectId
ws.Range("A1").AutoFilter Field:=3, Criteria1:=visit
ws.Activate
ws.Range("A2").Select
Application.ScreenUpdating = True
End Sub
'''
app = xw.App(visible=False)
try:
wb = app.books.open(str(xlsx_path))
# Najdi VBComponent odpovídající listu "MayoScore" podle tab názvu
vb_comp = None
for comp in wb.api.VBProject.VBComponents:
if comp.Type == 100: # xlSheet
try:
if comp.Properties("Name").Value == "MayoScore":
vb_comp = comp
break
except Exception:
pass
if vb_comp is None:
# fallback: první sheet (Sheet1)
vb_comp = wb.api.VBProject.VBComponents("Sheet1")
vb_comp.CodeModule.AddFromString(vba_code)
wb.api.SaveAs(str(xlsm_path), FileFormat=52) # 52 = xlOpenXMLWorkbookMacroEnabled
wb.close()
finally:
app.quit()
if __name__ == "__main__":
main()
+264
View File
@@ -0,0 +1,264 @@
"""
import_to_mongo.py
Verze: 1.0
Datum: 2026-05-27
Import Clario CSV do MongoDB (databáze: Clario).
Kolekce: Clario.MayoDiary / Clario.MayoScore (dle názvu souboru)
Filtr: pouze řádky s Country == "Czech Republic"
Klíč: MayoDiary → Subject ID + Form Number
MayoScore → Participant ID + Visit
Historie: při změně fields se stará verze uloží do pole history[]
Po importu přesune zpracované CSV do downloads/Zpracovano/
Použití:
python import_to_mongo.py # importuje všechny CSV z downloads/
python import_to_mongo.py downloads/konkretni.csv # jeden soubor
"""
import csv
import re
import shutil
import sys
from datetime import datetime, timezone
from pathlib import Path
from pymongo import MongoClient, ASCENDING
MONGO_URI = "mongodb://192.168.1.76:27017"
DB_NAME = "Clario"
DOWNLOADS_DIR = Path(__file__).parent / "downloads"
PROCESSED_DIR = DOWNLOADS_DIR / "Zpracovano"
COUNTRY_FILTER = "Czech Republic"
# ---------------------------------------------------------------------------
# Konfigurace kolekcí
# ---------------------------------------------------------------------------
COLLECTION_CONFIG = {
"MayoDiary": {
"collection": "Clario.MayoDiary",
"subject_col": "Subject ID",
"key_cols": ("Subject ID", "Form Number"),
},
"MayoScore": {
"collection": "Clario.MayoScore",
"subject_col": "Participant ID",
"key_cols": ("Participant ID", "Visit"),
},
}
DATE_FORMATS = [
"%d-%b-%Y ",
"%d-%b-%Y",
"%d-%b-%Y %H:%M:%S",
"%d %b %Y %H:%M:%S",
"%d %b %Y %H:%M:%S:%f",
"%d %b %Y",
"%d %B %Y",
"%Y%m%d %H:%M:%S.%f",
"%Y-%m-%d %H:%M:%S",
"%m/%d/%Y %I:%M:%S %p",
]
# ---------------------------------------------------------------------------
# Helpers
# ---------------------------------------------------------------------------
def clean_colname(name: str) -> str:
"""Odstraní BOM a okolní uvozovky/mezery z názvu sloupce."""
return name.lstrip("").strip().strip('"')
def parse_date(value: str) -> str | None:
v = value.strip()
for fmt in DATE_FORMATS:
try:
dt = datetime.strptime(v, fmt.strip())
return dt.replace(tzinfo=timezone.utc).isoformat()
except ValueError:
continue
return None
def extract_snapshot_date(filename: str) -> str:
match = re.match(r"(\d{4}-\d{2}-\d{2})", Path(filename).name)
return match.group(1) if match else datetime.now().strftime("%Y-%m-%d")
def detect_collection_type(filename: str) -> str | None:
"""Vrátí klíč do COLLECTION_CONFIG nebo None."""
stem = Path(filename).stem
for key in COLLECTION_CONFIG:
if key in stem:
return key
return None
# ---------------------------------------------------------------------------
# CSV → dokument
# ---------------------------------------------------------------------------
def map_row(row: dict, col_type: str) -> dict:
cfg = COLLECTION_CONFIG[col_type]
doc: dict = {}
fields: dict = {}
cleaned = {clean_colname(k): v.strip() if v else "" for k, v in row.items()}
subject_col = cfg["subject_col"]
doc["subject"] = {"id": cleaned.get(subject_col, "")}
doc["site"] = {"name": cleaned.get("Site", "")}
doc["country"] = cleaned.get("Country", "")
doc["study"] = cleaned.get("Protocol", "")
key_parts = [cleaned.get(c, "") for c in cfg["key_cols"]]
doc["recordKey"] = "_".join(key_parts)
skip_top = {"Protocol", "Country", "Site", subject_col}
for col, value in cleaned.items():
if col in skip_top:
continue
if not value or value == "-":
continue
parsed = parse_date(value)
fields[col] = parsed if parsed else value
doc["fields"] = fields
return doc
# ---------------------------------------------------------------------------
# Import jednoho souboru
# ---------------------------------------------------------------------------
def import_file(csv_path: str, db) -> dict:
filename = Path(csv_path).name
col_type = detect_collection_type(filename)
if col_type is None:
print(f" Preskakuji (neznamy typ): {filename}")
return {"skipped": True}
cfg = COLLECTION_CONFIG[col_type]
col_name = cfg["collection"]
snapshot_date = extract_snapshot_date(filename)
collection = db[col_name]
inserted = changed = unchanged = filtered_out = 0
with open(csv_path, encoding="utf-8-sig", newline="") as f:
reader = csv.DictReader(f, delimiter=",", quotechar='"')
for row in reader:
cleaned_row = {clean_colname(k): v for k, v in row.items()}
country = cleaned_row.get("Country", "").strip()
if country != COUNTRY_FILTER:
filtered_out += 1
continue
doc = map_row(row, col_type)
record_key = doc.get("recordKey")
if not record_key:
continue
doc["sourceFile"] = filename
existing = collection.find_one({"recordKey": record_key})
if existing is None:
doc["firstSeen"] = snapshot_date
doc["lastSeen"] = snapshot_date
doc["history"] = []
collection.insert_one(doc)
inserted += 1
elif existing.get("fields") != doc["fields"]:
old_entry = {
"date": existing.get("lastSeen", snapshot_date),
"fields": existing["fields"],
}
update_doc = {k: v for k, v in doc.items()}
update_doc["lastSeen"] = snapshot_date
collection.update_one(
{"_id": existing["_id"]},
{
"$push": {"history": old_entry},
"$set": update_doc,
},
)
changed += 1
else:
collection.update_one(
{"_id": existing["_id"]},
{"$set": {"lastSeen": snapshot_date, "sourceFile": filename}},
)
unchanged += 1
collection.create_index([("recordKey", ASCENDING)], unique=True)
collection.create_index([("subject.id", ASCENDING)])
collection.create_index([("site.name", ASCENDING)])
stats = {
"collection": col_name,
"snapshot": snapshot_date,
"inserted": inserted,
"changed": changed,
"unchanged": unchanged,
"filtered_out": filtered_out,
}
print(f" {col_name} [{snapshot_date}]: +{inserted} new, ~{changed} changed, ={unchanged} same, -{filtered_out} non-CZ")
return stats
# ---------------------------------------------------------------------------
# Main
# ---------------------------------------------------------------------------
def main():
paths: list[Path] = []
if len(sys.argv) > 1:
for arg in sys.argv[1:]:
p = Path(arg)
if p.is_file():
paths.append(p)
else:
print(f"Soubor nenalezen: {arg}")
else:
paths = sorted(DOWNLOADS_DIR.glob("*.csv"))
if not paths:
print("Zadne CSV soubory k importu.")
return
print(f"Nalezeno {len(paths)} souboru.\n")
client = MongoClient(MONGO_URI, serverSelectionTimeoutMS=5000)
client.admin.command("ping")
db = client[DB_NAME]
PROCESSED_DIR.mkdir(exist_ok=True)
total = {"inserted": 0, "changed": 0, "unchanged": 0}
for csv_path in paths:
print(f"Import: {csv_path.name}")
stats = import_file(str(csv_path), db)
if not stats.get("skipped"):
for k in total:
total[k] += stats.get(k, 0)
dest = PROCESSED_DIR / csv_path.name
shutil.move(str(csv_path), str(dest))
print(f" -> presunut do Zpracovano/")
client.close()
print(f"\nCelkem: +{total['inserted']} new, ~{total['changed']} changed, ={total['unchanged']} same")
if __name__ == "__main__":
main()
+204
View File
@@ -0,0 +1,204 @@
"""
AE Import — scrapes Adverse Events from EvaMed DRY study and upserts into MongoDB.
Run repeatedly; only stores field-level changes (delta) in history[].
Unique key: patient_code + event_number.
"""
import asyncio
import re
from datetime import datetime
from pathlib import Path
from playwright.async_api import async_playwright
from pymongo import MongoClient
BASE_URL = "https://prod.evamed.com/etude/soft/index.php"
LOGIN_URL = f"{BASE_URL}?module=authentification&class=login&client=myopowers-dry"
# Direct filtered URL: CZ1 (center_id=2), Adverse Event (formtype=120), all records
LIST_URL = f"{BASE_URL}?module=monitoring&class=formslisting&center_id=2&formtype=120&l=ALL"
LOGIN = "vbuzalka"
PASSWORD = "Vlado9674+"
MONGO_HOST = "192.168.1.76"
DB_NAME = "Dry"
COLLECTION = "AE"
SESSION_FILE = Path(__file__).parent / "session.json"
DATE_RE = re.compile(r"^(\d{2})/(\d{2})/(\d{4})$")
def parse_value(value):
"""Parse DD/MM/YYYY → datetime, digit-only → int, else str. None if empty."""
if not value or not value.strip():
return None
v = value.strip()
m = DATE_RE.fullmatch(v)
if m:
return datetime(int(m.group(3)), int(m.group(2)), int(m.group(1)))
if re.fullmatch(r"\d+", v):
return int(v)
return v
async def do_login(page):
await page.goto(LOGIN_URL)
await page.wait_for_load_state("networkidle")
await page.locator("#login").fill(LOGIN)
await page.locator('input[type="password"]').first.fill(PASSWORD)
await page.click('input[value="Connection"]')
await page.wait_for_load_state("networkidle")
async def get_form_ids(page):
"""Return list of {form_id, patient_code} from the filtered forms list."""
await page.goto(LIST_URL)
await page.wait_for_load_state("networkidle")
return await page.evaluate("""() => {
const results = [];
document.querySelectorAll('a[title="Open form"]').forEach(a => {
const href = a.getAttribute('href') || '';
const m = href.match(/id=(\\d+)/);
if (!m) return;
// Patient code: "Open directory" link in the same row, text of the anchor
const row = a.closest('tr');
const dirLink = row ? row.querySelector('a[title="Open directory"]') : null;
const patientCode = dirLink ? dirLink.innerText.trim() : '';
results.push({ formId: m[1], patientCode: patientCode });
});
return results;
}""")
async def extract_form_fields(page, form_id):
"""Navigate to AE form and extract all field values."""
url = f"{BASE_URL}?module=dossier&class=file&event=show&id={form_id}#fiche"
await page.goto(url)
await page.wait_for_load_state("networkidle")
raw = await page.evaluate("""() => {
const fields = {};
document.querySelectorAll('.tableauFormulaire span.label').forEach(label => {
const key = label.innerText.trim();
const valEl = label.nextElementSibling;
fields[key] = valEl ? valEl.innerText.trim() || null : null;
});
return fields;
}""")
# Parse values into correct Python types
parsed = {}
for k, v in raw.items():
if k == '_patient_code':
parsed[k] = v
else:
parsed[k] = parse_value(v)
parsed['_form_id'] = int(form_id)
return parsed
def upsert_ae(collection, doc, now):
patient_code = doc.get('_patient_code') or ''
event_number = doc.get('Event Number')
key = {"patient_code": patient_code, "event_number": event_number}
existing = collection.find_one(key)
# Fields we track changes for (exclude internal fields)
skip = {'_patient_code', '_form_id'}
data = {k: v for k, v in doc.items() if k not in skip}
if existing is None:
collection.insert_one({
**key,
"_form_id": doc['_form_id'],
"data": data,
"history": [],
"first_seen_at": now,
"last_seen_at": now,
"deleted_at": None,
})
print(f" NEW {patient_code} AE#{event_number}")
return
# Delta: compare data with stored data
old_data = existing.get("data", {})
changes = {}
for k in set(data) | set(old_data):
old_v = old_data.get(k)
new_v = data.get(k)
if old_v != new_v:
changes[k] = {"old": old_v, "new": new_v}
update = {"$set": {"last_seen_at": now, "deleted_at": None}}
if changes:
update["$set"]["data"] = data
update["$push"] = {"history": {"timestamp": now, "changes": changes}}
print(f" CHANGED {patient_code} AE#{event_number} -> {list(changes.keys())}")
else:
print(f" ok {patient_code} AE#{event_number}")
collection.update_one(key, update)
async def main():
mongo = MongoClient(MONGO_HOST)
col = mongo[DB_NAME][COLLECTION]
now = datetime.now()
async with async_playwright() as p:
browser = await p.chromium.launch(headless=False)
# Reuse saved session if available
if SESSION_FILE.exists():
context = await browser.new_context(storage_state=str(SESSION_FILE))
print("Loaded saved session")
else:
context = await browser.new_context(viewport={"width": 1400, "height": 900})
page = await context.new_page()
# Check if we need to log in
await page.goto(LIST_URL)
await page.wait_for_load_state("networkidle")
if "authentification" in page.url:
print("Logging in...")
await do_login(page)
await context.storage_state(path=str(SESSION_FILE))
print("Session saved")
else:
print("Session valid")
# Get all AE form IDs from filtered list
form_infos = await get_form_ids(page)
current_ids = {info['formId'] for info in form_infos}
print(f"Found {len(form_infos)} AE forms")
# Scrape and upsert each form
for info in form_infos:
fid = info['formId']
print(f"Scraping form {fid} ({info['patientCode']})...")
doc = await extract_form_fields(page, fid)
# Patient code comes from the list (more reliable than form page heading)
doc['_patient_code'] = info['patientCode']
upsert_ae(col, doc, now)
# Mark as deleted any forms that disappeared from the list
for rec in col.find({"deleted_at": None}, {"_form_id": 1, "patient_code": 1, "event_number": 1}):
if str(rec.get('_form_id', '')) not in current_ids:
col.update_one({"_id": rec["_id"]}, {"$set": {"deleted_at": now}})
print(f" DELETED form_id={rec['_form_id']} ({rec.get('patient_code')} AE#{rec.get('event_number')})")
await browser.close()
mongo.close()
print(f"\nDone — {len(form_infos)} forms processed at {now.isoformat()}")
if __name__ == "__main__":
asyncio.run(main())
+184
View File
@@ -0,0 +1,184 @@
"""
Device Deficiency Import — scrapes DD forms from EvaMed DRY study and upserts into MongoDB.
Run repeatedly; only stores field-level changes (delta) in history[].
Unique key: _form_id (each DD form has a unique ID in EvaMed).
"""
import asyncio
import re
from datetime import datetime
from pathlib import Path
from playwright.async_api import async_playwright
from pymongo import MongoClient
BASE_URL = "https://prod.evamed.com/etude/soft/index.php"
LOGIN_URL = f"{BASE_URL}?module=authentification&class=login&client=myopowers-dry"
LIST_URL = f"{BASE_URL}?module=monitoring&class=formslisting&center_id=2&formtype=121&l=ALL"
LOGIN = "vbuzalka"
PASSWORD = "Vlado9674+"
MONGO_HOST = "192.168.1.76"
DB_NAME = "Dry"
COLLECTION = "DevDeficiency"
SESSION_FILE = Path(__file__).parent / "session.json"
DATE_RE = re.compile(r"^(\d{2})/(\d{2})/(\d{4})$")
def parse_value(value):
"""Parse DD/MM/YYYY -> datetime, digit-only -> int, else str. None if empty."""
if not value or not value.strip():
return None
v = value.strip()
m = DATE_RE.fullmatch(v)
if m:
return datetime(int(m.group(3)), int(m.group(2)), int(m.group(1)))
if re.fullmatch(r"\d+", v):
return int(v)
return v
async def do_login(page):
await page.goto(LOGIN_URL)
await page.wait_for_load_state("networkidle")
await page.locator("#login").fill(LOGIN)
await page.locator('input[type="password"]').first.fill(PASSWORD)
await page.click('input[value="Connection"]')
await page.wait_for_load_state("networkidle")
async def get_form_ids(page):
"""Return list of {formId, patientCode} from the filtered forms list."""
await page.goto(LIST_URL)
await page.wait_for_load_state("networkidle")
return await page.evaluate("""() => {
const results = [];
document.querySelectorAll('a[title="Open form"]').forEach(a => {
const href = a.getAttribute('href') || '';
const m = href.match(/id=(\\d+)/);
if (!m) return;
const row = a.closest('tr');
const dirLink = row ? row.querySelector('a[title="Open directory"]') : null;
const patientCode = dirLink ? dirLink.innerText.trim() : '';
results.push({ formId: m[1], patientCode: patientCode });
});
return results;
}""")
async def extract_form_fields(page, form_id):
"""Navigate to DD form and extract all field values."""
url = f"{BASE_URL}?module=dossier&class=file&event=show&id={form_id}#fiche"
await page.goto(url)
await page.wait_for_load_state("networkidle")
raw = await page.evaluate("""() => {
const fields = {};
document.querySelectorAll('.tableauFormulaire span.label').forEach(label => {
const key = label.innerText.trim();
const valEl = label.nextElementSibling;
fields[key] = valEl ? valEl.innerText.trim() || null : null;
});
return fields;
}""")
parsed = {}
for k, v in raw.items():
parsed[k] = parse_value(v)
parsed['_form_id'] = int(form_id)
return parsed
def upsert_dd(collection, doc, patient_code, now):
form_id = doc['_form_id']
key = {"_form_id": form_id}
existing = collection.find_one(key)
skip = {'_form_id'}
data = {k: v for k, v in doc.items() if k not in skip}
if existing is None:
collection.insert_one({
**key,
"patient_code": patient_code,
"data": data,
"history": [],
"first_seen_at": now,
"last_seen_at": now,
"deleted_at": None,
})
print(f" NEW {patient_code} DD form_id={form_id}")
return
old_data = existing.get("data", {})
changes = {}
for k in set(data) | set(old_data):
old_v = old_data.get(k)
new_v = data.get(k)
if old_v != new_v:
changes[k] = {"old": old_v, "new": new_v}
update = {"$set": {"last_seen_at": now, "deleted_at": None, "patient_code": patient_code}}
if changes:
update["$set"]["data"] = data
update["$push"] = {"history": {"timestamp": now, "changes": changes}}
print(f" CHANGED {patient_code} DD form_id={form_id} -> {list(changes.keys())}")
else:
print(f" ok {patient_code} DD form_id={form_id}")
collection.update_one(key, update)
async def main():
mongo = MongoClient(MONGO_HOST)
col = mongo[DB_NAME][COLLECTION]
now = datetime.now()
async with async_playwright() as p:
browser = await p.chromium.launch(headless=False)
if SESSION_FILE.exists():
context = await browser.new_context(storage_state=str(SESSION_FILE))
print("Loaded saved session")
else:
context = await browser.new_context(viewport={"width": 1400, "height": 900})
page = await context.new_page()
await page.goto(LIST_URL)
await page.wait_for_load_state("networkidle")
if "authentification" in page.url:
print("Logging in...")
await do_login(page)
await context.storage_state(path=str(SESSION_FILE))
print("Session saved")
else:
print("Session valid")
form_infos = await get_form_ids(page)
current_ids = {info['formId'] for info in form_infos}
print(f"Found {len(form_infos)} DD forms")
for info in form_infos:
fid = info['formId']
print(f"Scraping form {fid} ({info['patientCode']})...")
doc = await extract_form_fields(page, fid)
upsert_dd(col, doc, info['patientCode'], now)
for rec in col.find({"deleted_at": None}, {"_form_id": 1, "patient_code": 1}):
if str(rec.get('_form_id', '')) not in current_ids:
col.update_one({"_id": rec["_id"]}, {"$set": {"deleted_at": now}})
print(f" DELETED form_id={rec['_form_id']} ({rec.get('patient_code')})")
await browser.close()
mongo.close()
print(f"\nDone -- {len(form_infos)} forms processed at {now.isoformat()}")
if __name__ == "__main__":
asyncio.run(main())
+169
View File
@@ -0,0 +1,169 @@
"""Explorační skript — přihlášení do EvaMed CRF, načtení všech formulářů, nalezení AE."""
import asyncio
from playwright.async_api import async_playwright
BASE_URL = "https://prod.evamed.com/etude/soft/index.php"
LOGIN_URL = "https://prod.evamed.com/etude/soft/index.php?module=authentification&class=login&client=myopowers-dry"
LOGIN = "vbuzalka"
PASSWORD = "Vlado9674+"
SCREENSHOTS_DIR = "screenshots"
async def main():
async with async_playwright() as p:
browser = await p.chromium.launch(headless=False)
context = await browser.new_context(viewport={"width": 1400, "height": 900})
page = await context.new_page()
# 1. Login
await page.goto(LOGIN_URL)
await page.wait_for_load_state("networkidle")
await page.locator('#login').fill(LOGIN)
await page.locator('input[type="password"]').first.fill(PASSWORD)
await page.click('text=Connection')
await page.wait_for_load_state("networkidle")
print("Logged in")
# 2. Go to Forms list
await page.goto(f"{BASE_URL}?module=monitoring&class=formslisting")
await page.wait_for_load_state("networkidle")
print("Forms list loaded (page 1)")
# 3. Switch to ALL records
await page.select_option('select[name="l"]', 'ALL')
print("Switched to ALL, waiting for all rows to load...")
await page.wait_for_function(
"() => document.querySelectorAll('tr').length > 3200",
timeout=120000
)
print(f"All rows loaded")
# 4. Count total rows and find AE rows
stats = await page.evaluate("""() => {
const rows = document.querySelectorAll('tr');
let totalRows = rows.length;
let aeRows = [];
let formCodes = {};
rows.forEach((row, idx) => {
const cells = Array.from(row.querySelectorAll('td'));
cells.forEach(cell => {
// collect all unique form codes from the Formcode column
});
// Look for AE in any cell
const cellTexts = cells.map(c => c.innerText.trim());
// Formcode is typically column index 8 based on the header
if (cells.length > 8) {
const formcode = cells[8]?.innerText?.trim();
formCodes[formcode] = (formCodes[formcode] || 0) + 1;
if (formcode === 'AE') {
aeRows.push({
rowIndex: idx,
subject: cells[0]?.innerText?.trim(),
formcode: formcode,
formName: cells[9]?.innerText?.trim(),
allCells: cellTexts,
links: Array.from(row.querySelectorAll('a')).map(a => ({
href: a.getAttribute('href'),
title: a.title || '',
text: a.innerText.trim().substring(0, 50)
}))
});
}
}
});
return { totalRows, aeCount: aeRows.length, aeRows: aeRows.slice(0, 5), formCodes };
}""")
print(f"Total rows: {stats['totalRows']}")
print(f"AE rows found: {stats['aeCount']}")
print(f"Form codes: {stats['formCodes']}")
if stats['aeRows']:
print(f"\nFirst AE row sample:")
ae = stats['aeRows'][0]
print(f" Subject: {ae['subject']}")
print(f" All cells: {ae['allCells']}")
print(f" Links: {ae['links']}")
# 5. Open first AE form
for link in ae['links']:
if link.get('href') and 'id=' in link['href']:
ae_url = link['href']
if not ae_url.startswith('http'):
ae_url = f"https://prod.evamed.com/etude/soft/{ae_url}"
print(f"\nOpening AE form: {ae_url}")
await page.goto(ae_url)
await page.wait_for_load_state("networkidle")
await page.screenshot(path=f"{SCREENSHOTS_DIR}/05_ae_form.png", full_page=True)
print("Screenshot: AE form")
# Extract all fields from the form
fields = await page.evaluate("""() => {
// Try input-group pattern
const groups = document.querySelectorAll('.input-group');
let inputGroupFields = Array.from(groups).map(g => ({
html: g.outerHTML.substring(0, 800),
text: g.innerText.trim().substring(0, 300)
}));
// Try label/value pattern in tableauFormulaire
const tableFields = [];
document.querySelectorAll('.tableauFormulaire td, .tableauFormulaire th').forEach(el => {
tableFields.push({
tag: el.tagName,
className: el.className,
text: el.innerText.trim().substring(0, 200)
});
});
// Try all form inputs
const inputs = [];
document.querySelectorAll('input, select, textarea').forEach(el => {
inputs.push({
type: el.type,
name: el.name,
id: el.id,
value: el.value?.substring(0, 200),
className: el.className
});
});
return { inputGroupFields, tableFields: tableFields.slice(0, 50), inputs: inputs.slice(0, 50) };
}""")
print(f"\nInput groups: {len(fields['inputGroupFields'])}")
for i, f in enumerate(fields['inputGroupFields'][:10]):
print(f" [{i}] {f['text'][:120]}")
print(f"\nTable fields: {len(fields['tableFields'])}")
for i, f in enumerate(fields['tableFields'][:20]):
print(f" [{i}] <{f['tag']} class='{f['className']}'> {f['text'][:100]}")
print(f"\nForm inputs: {len(fields['inputs'])}")
for i, f in enumerate(fields['inputs'][:20]):
print(f" [{i}] {f['type']} name={f['name']} id={f['id']} val={f['value'][:60] if f['value'] else ''}")
# Save full form HTML for analysis
form_html = await page.content()
with open(f"{SCREENSHOTS_DIR}/05_ae_form_full.html", "w", encoding="utf-8") as f:
f.write(form_html)
print("Saved: full AE form HTML")
break
else:
print("NO AE ROWS FOUND!")
await page.screenshot(path=f"{SCREENSHOTS_DIR}/04_all_forms.png", full_page=False)
# Dump all unique form codes for debugging
print("Available form codes:", list(stats['formCodes'].keys())[:30])
await browser.close()
print("Done")
if __name__ == "__main__":
import os
os.makedirs(SCREENSHOTS_DIR, exist_ok=True)
asyncio.run(main())
+165
View File
@@ -0,0 +1,165 @@
"""Exploration script — Device Deficiency forms in EvaMed DRY study."""
import asyncio
import json
from pathlib import Path
from playwright.async_api import async_playwright
BASE_URL = "https://prod.evamed.com/etude/soft/index.php"
LOGIN_URL = f"{BASE_URL}?module=authentification&class=login&client=myopowers-dry"
LIST_URL = f"{BASE_URL}?module=monitoring&class=formslisting&center_id=2&formtype=121&l=ALL"
LOGIN = "vbuzalka"
PASSWORD = "Vlado9674+"
SCREENSHOTS_DIR = Path(__file__).parent / "screenshots_dd"
SESSION_FILE = Path(__file__).parent / "session.json"
async def main():
SCREENSHOTS_DIR.mkdir(exist_ok=True)
async with async_playwright() as p:
browser = await p.chromium.launch(headless=False)
if SESSION_FILE.exists():
context = await browser.new_context(storage_state=str(SESSION_FILE))
print("Loaded saved session")
else:
context = await browser.new_context(viewport={"width": 1400, "height": 900})
page = await context.new_page()
# Login if needed
await page.goto(LIST_URL)
await page.wait_for_load_state("networkidle")
if "authentification" in page.url:
print("Logging in...")
await page.goto(LOGIN_URL)
await page.wait_for_load_state("networkidle")
await page.locator("#login").fill(LOGIN)
await page.locator('input[type="password"]').first.fill(PASSWORD)
await page.click('input[value="Connection"]')
await page.wait_for_load_state("networkidle")
await context.storage_state(path=str(SESSION_FILE))
print("Session saved")
await page.goto(LIST_URL)
await page.wait_for_load_state("networkidle")
else:
print("Session valid")
await page.screenshot(path=str(SCREENSHOTS_DIR / "01_dd_listing.png"), full_page=False)
print("Screenshot: DD listing")
# Get all DD form links from the listing
form_infos = await page.evaluate("""() => {
const results = [];
document.querySelectorAll('a[title="Open form"]').forEach(a => {
const href = a.getAttribute('href') || '';
const m = href.match(/id=(\\d+)/);
if (!m) return;
const row = a.closest('tr');
const dirLink = row ? row.querySelector('a[title="Open directory"]') : null;
const patientCode = dirLink ? dirLink.innerText.trim() : '';
const cells = row ? Array.from(row.querySelectorAll('td')).map(c => c.innerText.trim()) : [];
results.push({ formId: m[1], patientCode, cells });
});
return results;
}""")
print(f"\nFound {len(form_infos)} Device Deficiency forms")
for i, info in enumerate(form_infos[:5]):
print(f" [{i}] form_id={info['formId']} patient={info['patientCode']} cells={info['cells']}")
if not form_infos:
print("NO DD FORMS FOUND!")
# Save HTML for debugging
html = await page.content()
(SCREENSHOTS_DIR / "01_dd_listing.html").write_text(html, encoding="utf-8")
await browser.close()
return
# Open the first DD form
first = form_infos[0]
form_url = f"{BASE_URL}?module=dossier&class=file&event=show&id={first['formId']}#fiche"
print(f"\nOpening DD form: {form_url}")
await page.goto(form_url)
await page.wait_for_load_state("networkidle")
await page.screenshot(path=str(SCREENSHOTS_DIR / "02_dd_form.png"), full_page=True)
print("Screenshot: DD form")
# Extract fields using the same pattern as AE (span.label + span.valeur)
fields_label_value = await page.evaluate("""() => {
const fields = [];
document.querySelectorAll('.tableauFormulaire span.label').forEach(label => {
const key = label.innerText.trim();
const valEl = label.nextElementSibling;
const value = valEl ? valEl.innerText.trim() : null;
const valClass = valEl ? valEl.className : '';
fields.push({ key, value, valueClass: valClass });
});
return fields;
}""")
print(f"\n=== Fields (span.label -> span.valeur) : {len(fields_label_value)} ===")
for f in fields_label_value:
print(f" {f['key']:40s} = {f['value']}")
# Also explore table structure for any additional patterns
table_structure = await page.evaluate("""() => {
const sections = [];
document.querySelectorAll('.tableauFormulaire').forEach((table, ti) => {
const rows = [];
table.querySelectorAll('tr').forEach((tr, ri) => {
const cells = Array.from(tr.querySelectorAll('td, th')).map(c => ({
tag: c.tagName,
class: c.className,
colspan: c.colSpan,
text: c.innerText.trim().substring(0, 200),
childSpans: Array.from(c.querySelectorAll('span')).map(s => ({
class: s.className,
text: s.innerText.trim().substring(0, 200)
}))
}));
if (cells.length > 0) rows.push({ rowIndex: ri, cells });
});
sections.push({ tableIndex: ti, rowCount: rows.length, rows: rows.slice(0, 30) });
});
return sections;
}""")
print(f"\n=== Table structure: {len(table_structure)} tableauFormulaire blocks ===")
for sec in table_structure:
print(f"\n Table #{sec['tableIndex']} ({sec['rowCount']} rows):")
for row in sec['rows'][:15]:
for cell in row['cells']:
spans_info = " | ".join(f"[{s['class']}]{s['text'][:60]}" for s in cell['childSpans'])
print(f" row{row['rowIndex']} <{cell['tag']} class='{cell['class']}' colspan={cell['colspan']}> "
f"{cell['text'][:80]}")
if spans_info:
print(f" spans: {spans_info}")
# Save full form HTML
html = await page.content()
(SCREENSHOTS_DIR / "02_dd_form.html").write_text(html, encoding="utf-8")
print("\nSaved: full DD form HTML")
# Save extracted data as JSON for easy review
result = {
"form_id": first['formId'],
"patient_code": first['patientCode'],
"listing_cells": first['cells'],
"fields": fields_label_value,
"table_structure": table_structure,
}
(SCREENSHOTS_DIR / "dd_form_data.json").write_text(
json.dumps(result, indent=2, ensure_ascii=False), encoding="utf-8"
)
print("Saved: dd_form_data.json")
await browser.close()
print("\nDone")
if __name__ == "__main__":
asyncio.run(main())
+131
View File
@@ -0,0 +1,131 @@
"""Exploration script — V0 Implantation Visit forms (formtype=10) in EvaMed DRY study."""
import asyncio
import json
from pathlib import Path
from playwright.async_api import async_playwright
BASE_URL = "https://prod.evamed.com/etude/soft/index.php"
LOGIN_URL = f"{BASE_URL}?module=authentification&class=login&client=myopowers-dry"
LIST_URL = f"{BASE_URL}?module=monitoring&class=formslisting&center_id=2&formtype=10&l=ALL"
LOGIN = "vbuzalka"
PASSWORD = "Vlado9674+"
SCREENSHOTS_DIR = Path(__file__).parent / "screenshots_surgery"
SESSION_FILE = Path(__file__).parent / "session.json"
async def main():
SCREENSHOTS_DIR.mkdir(exist_ok=True)
async with async_playwright() as p:
browser = await p.chromium.launch(headless=False)
if SESSION_FILE.exists():
context = await browser.new_context(storage_state=str(SESSION_FILE))
print("Loaded saved session")
else:
context = await browser.new_context(viewport={"width": 1400, "height": 900})
page = await context.new_page()
# Login if needed
await page.goto(LIST_URL)
await page.wait_for_load_state("networkidle")
if "authentification" in page.url:
print("Logging in...")
await page.goto(LOGIN_URL)
await page.wait_for_load_state("networkidle")
await page.locator("#login").fill(LOGIN)
await page.locator('input[type="password"]').first.fill(PASSWORD)
await page.click('input[value="Connection"]')
await page.wait_for_load_state("networkidle")
await context.storage_state(path=str(SESSION_FILE))
print("Session saved")
await page.goto(LIST_URL)
await page.wait_for_load_state("networkidle")
else:
print("Session valid")
await page.screenshot(path=str(SCREENSHOTS_DIR / "01_listing.png"), full_page=False)
print("Screenshot: listing")
# Get all form links from the listing
form_infos = await page.evaluate("""() => {
const results = [];
document.querySelectorAll('a[title="Open form"]').forEach(a => {
const href = a.getAttribute('href') || '';
const m = href.match(/id=(\\d+)/);
if (!m) return;
const row = a.closest('tr');
const dirLink = row ? row.querySelector('a[title="Open directory"]') : null;
const patientCode = dirLink ? dirLink.innerText.trim() : '';
const cells = row ? Array.from(row.querySelectorAll('td')).map(c => c.innerText.trim()) : [];
results.push({ formId: m[1], patientCode, cells });
});
return results;
}""")
print(f"\nFound {len(form_infos)} Implantation Visit forms")
for i, info in enumerate(form_infos[:5]):
print(f" [{i}] form_id={info['formId']} patient={info['patientCode']} cells={info['cells']}")
if not form_infos:
print("NO FORMS FOUND!")
html = await page.content()
(SCREENSHOTS_DIR / "01_listing.html").write_text(html, encoding="utf-8")
await browser.close()
return
# Open the first form
first = form_infos[0]
form_url = f"{BASE_URL}?module=dossier&class=file&event=show&id={first['formId']}#fiche"
print(f"\nOpening form: {form_url}")
await page.goto(form_url)
await page.wait_for_load_state("networkidle")
await page.screenshot(path=str(SCREENSHOTS_DIR / "02_form.png"), full_page=True)
print("Screenshot: form")
# Extract fields using span.label + span.valeur pattern
fields_label_value = await page.evaluate("""() => {
const fields = [];
document.querySelectorAll('.tableauFormulaire span.label').forEach(label => {
const key = label.innerText.trim();
const valEl = label.nextElementSibling;
const value = valEl ? valEl.innerText.trim() : null;
const valClass = valEl ? valEl.className : '';
fields.push({ key, value, valueClass: valClass });
});
return fields;
}""")
print(f"\n=== Fields (span.label -> span.valeur) : {len(fields_label_value)} ===")
for f in fields_label_value:
key = f['key'].encode('ascii', 'replace').decode()
val = (f['value'] or '').encode('ascii', 'replace').decode()
print(f" {key:50s} = {val}")
# Save full form HTML
html = await page.content()
(SCREENSHOTS_DIR / "02_form.html").write_text(html, encoding="utf-8")
print("\nSaved: full form HTML")
# Save extracted data as JSON
result = {
"form_id": first['formId'],
"patient_code": first['patientCode'],
"listing_cells": first['cells'],
"fields": fields_label_value,
}
(SCREENSHOTS_DIR / "form_data.json").write_text(
json.dumps(result, indent=2, ensure_ascii=False), encoding="utf-8"
)
print("Saved: form_data.json")
await browser.close()
print("\nDone")
if __name__ == "__main__":
asyncio.run(main())
+108
View File
@@ -0,0 +1,108 @@
"""
EvaMed DRY study — form type selectors.
Usage:
Filter URL: formtype={value}
Checkbox: #formtype_{value}
Example:
await page.check('#formtype_120') # Adverse Event
await page.check('#formtype_121') # Device Deficiency
"""
FORMTYPES = {
1: "Eligibility Criteria",
8: "V-3 : Baseline Within 3 weeks before the implant procedure",
122: "V-3 : Day 1 - Voiding diary",
123: "V-3 : Day 2 - Voiding diary",
124: "V-3 : Day 3 - Voiding diary",
2: "V-3 : ICIQ-MLUTS",
3: "V-3 : ICIQ-LUTSQol",
4: "V-3 : EQ-5D-5L",
5: "V-3 : MSHQ",
9: "V-1 : Phone Call (1 Week before Implantation)",
10: "V0 : Implantation Visit",
11: "DV : Discharge Visit",
12: "V1 : 6 Weeks Post-Operative Period (Device Activation)",
129: "V1 : Device Activation",
125: "V1 : Physician Usability Questionnaire",
13: "V2 : 8 Weeks Post-Operative Period",
130: "V2 : Device Adjustment",
127: "V2 : Physician Usability Questionnaire",
14: "V3 : 3 Months Post-Operative Period",
131: "V3 : Device Adjustment",
128: "V3 : Physician Usability Questionnaire",
15: "V4 - Phone Call (10 Weeks after device activation)",
16: "V5 : 3 Months Post-Device Activation",
138: "V5 : Day 1 - Voiding diary",
139: "V5 : Day 2 - Voiding diary",
140: "V5 : Day 3 - Voiding diary",
132: "V5 : Device Adjustment",
135: "V5 : Unlocking additional modes",
17: "V5 : ICIQ-MLUTS",
18: "V5 : ICIQ-LUTSQol",
19: "V5 : EQ-5D-5L",
20: "V5 : MSHQ",
21: "V5 : PGI-I",
22: "V5 : Subject Usability Questionnaire",
23: "V5 : Physician Usability Questionnaire",
24: "V6 : Phone Call (22 Weeks after Device activation)",
25: "V7 : 6 Months Post-Device Activation",
142: "V7 : Day 1 - Voiding diary",
143: "V7 : Day 2 - Voiding diary",
144: "V7 : Day 3 - Voiding diary",
150: "V7 : Device Adjustment",
180: "V7 - Unlocking additional mode",
26: "V7 : ICIQ-MLUTS",
27: "V7 : ICIQ-LUTSQol",
29: "V7 : EQ-5D-5L",
31: "V7 : MSHQ",
32: "V7 : PGI-I",
33: "V7 : Subject Usability Questionnaire",
34: "V7 : Physician Usability Questionnaire",
35: "V8 : Phone Call (46 Weeks after Device activation)",
36: "V9 : 12 Months Post-Device Activation",
146: "V9 : Day 1 - Voiding diary",
147: "V9 : Day 2 - Voiding diary",
148: "V9 : Day 3 - Voiding diary",
151: "V9 : Device Adjustment",
181: "V9 - Unlocking additional mode",
37: "V9 : ICIQ-MLUTS",
38: "V9 : ICIQ-LUTSQol",
39: "V9 : EQ-5D-5L",
40: "V9 : MSHQ",
41: "V9 : PGI-I",
42: "V9 : Subject Usability Questionnaire",
43: "V9 : Physician Usability Questionnaire",
44: "V10 : Long-term annual Follow-up",
153: "V10 : Device Adjustment",
162: "V10 : Unlocking additional modes",
45: "V10 : ICIQ-MLUTS",
47: "V10 : ICIQ-LUTSQol",
48: "V10 : EQ-5D-5L",
49: "V10 : MSHQ",
50: "V10 : PGI-I",
51: "V10 : Subject Usability Questionnaire",
52: "V10 : Physician Usability Questionnaire",
53: "V11 : Long-term annual Follow-up",
154: "V11 : Device Adjustment",
163: "V11 : Unlocking additional modes",
54: "V11 : ICIQ-MLUTS",
55: "V11 : ICIQ-LUTSQol",
56: "V11 : EQ-5D-5L",
57: "V11 : MSHQ",
58: "V11 : PGI-I",
59: "V11 : Subject Usability Questionnaire",
60: "V11 : Physician Usability Questionnaire",
119: "UV : Unscheduled Visit",
183: "UV : Voiding diary - Day 1 to Day 3 (if applicable)",
173: "UV : Device Adjustment",
174: "UV : Unlocking additional modes",
175: "UV : Physician Usability Questionnaire",
177: "Concomitant Medication",
120: "Adverse Event",
121: "Device Deficiency",
178: "Deviation",
182: "Subsequent surgery",
176: "Study Termination",
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 61 KiB

+24
View File
@@ -0,0 +1,24 @@
<table style="margin: auto;">
<tbody><tr>
<td>
<a href="?module=monitoring&amp;class=formslisting&amp;center_code=&amp;patientfile_code=&amp;center_id=&amp;filetype=&amp;formtype=&amp;dateinc_inf=&amp;dateinc_sup=&amp;dateint_inf=&amp;dateint_sup=&amp;datet0_inf=&amp;datet0_sup=&amp;datefiche_inf=&amp;datefiche_sup=&amp;delai_inf=&amp;delai_sup=&amp;visits=&amp;status=&amp;pff_exists=&amp;nb_open_query_fields=&amp;tx_remplissage_inf=&amp;tx_remplissage_sup=&amp;l=0&amp;DOWNLOAD=Excel2007">
<img src="img/dl/ms-excel2007-128x128.png" alt="Download"><br>
MS Excel 2007 (.xlsx)</a>
</td>
<td>
<a href="?module=monitoring&amp;class=formslisting&amp;center_code=&amp;patientfile_code=&amp;center_id=&amp;filetype=&amp;formtype=&amp;dateinc_inf=&amp;dateinc_sup=&amp;dateint_inf=&amp;dateint_sup=&amp;datet0_inf=&amp;datet0_sup=&amp;datefiche_inf=&amp;datefiche_sup=&amp;delai_inf=&amp;delai_sup=&amp;visits=&amp;status=&amp;pff_exists=&amp;nb_open_query_fields=&amp;tx_remplissage_inf=&amp;tx_remplissage_sup=&amp;l=0&amp;DOWNLOAD=Excel5">
<img src="img/dl/ms-excel5-128x128.png" alt="Download"><br>
MS Excel 5 (.xls)</a>
</td>
<td>
<a href="?module=monitoring&amp;class=formslisting&amp;center_code=&amp;patientfile_code=&amp;center_id=&amp;filetype=&amp;formtype=&amp;dateinc_inf=&amp;dateinc_sup=&amp;dateint_inf=&amp;dateint_sup=&amp;datet0_inf=&amp;datet0_sup=&amp;datefiche_inf=&amp;datefiche_sup=&amp;delai_inf=&amp;delai_sup=&amp;visits=&amp;status=&amp;pff_exists=&amp;nb_open_query_fields=&amp;tx_remplissage_inf=&amp;tx_remplissage_sup=&amp;l=0&amp;DOWNLOAD=csv">
<img src="img/dl/csv-128x128.png" alt="Download"><br>
CSV (.csv)</a>
</td>
<td>
<a href="?module=monitoring&amp;class=formslisting&amp;center_code=&amp;patientfile_code=&amp;center_id=&amp;filetype=&amp;formtype=&amp;dateinc_inf=&amp;dateinc_sup=&amp;dateint_inf=&amp;dateint_sup=&amp;datet0_inf=&amp;datet0_sup=&amp;datefiche_inf=&amp;datefiche_sup=&amp;delai_inf=&amp;delai_sup=&amp;visits=&amp;status=&amp;pff_exists=&amp;nb_open_query_fields=&amp;tx_remplissage_inf=&amp;tx_remplissage_sup=&amp;l=0&amp;DOWNLOAD=XML">
<img src="img/dl/xml-128x128.png" alt="Download"><br>
XML (.xml)</a>
</td>
</tr>
</tbody></table>
Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

File diff suppressed because one or more lines are too long
Binary file not shown.

After

Width:  |  Height:  |  Size: 161 KiB

+107
View File
@@ -0,0 +1,107 @@
{
"form_id": "461",
"patient_code": "CZ1-01",
"listing_cells": [
"CZ1-01",
"Male",
"Subject",
"16/02/2024",
"28/02/2024",
"17/04/2024",
"CZ1 - Fakultní Thomayerova nemocnice",
"DD",
"Device Deficiency",
"0",
"0",
"30",
"",
"",
"",
"23/02/2025",
"Accepted",
"",
"",
"0",
"100",
"0",
"",
"",
"1",
"Open",
""
],
"fields": [
{
"key": "Date of Onset",
"value": "23/02/2025",
"valueClass": "valeur DTEONSET"
},
{
"key": "Date device deficiency discovered by site",
"value": "04/03/2025",
"valueClass": "valeur DTEDEVIC"
},
{
"key": "Title of device deficiency",
"value": null,
"valueClass": ""
},
{
"key": "1 - Type of Device Deficiency",
"value": "Malfunction (failure of device to operate as intended when used per IFU and protocol)",
"valueClass": "valeur "
},
{
"key": "Specify other type of device deficiency",
"value": null,
"valueClass": ""
},
{
"key": "2 - Description of Event",
"value": "Patient reported to site device malfunction. Device switched to emergency regime and kept being permanently open. It is not possible to control device. The sponsor informed abou the deficiency immediately. Patient has no pain, no urine retention, as per X-ray, positioning of control unit and cuff is correct.",
"valueClass": "valeur DESC"
},
{
"key": "3 - Information about Device(s) (name, lot and serial number)",
"value": "Remote control 052300185, control unit 210011, cuff 22-0224",
"valueClass": "valeur INFO"
},
{
"key": "4 - Consequence of Device Deficiency",
"value": "Led to adverse event",
"valueClass": "valeur "
},
{
"key": "Lead to AE number",
"value": null,
"valueClass": ""
},
{
"key": "Action(s) taken",
"value": "Other",
"valueClass": "valeur "
},
{
"key": "If other action(s), specify",
"value": "Implementation of the new sofware leading to continence, time to activation emergency regime increased from 8 to 12hours",
"valueClass": "valeur ACTIONP"
},
{
"key": "Event Outcome",
"value": "Resolved without Sequelae",
"valueClass": "valeur "
},
{
"key": "Event End Date",
"value": "07/04/2025",
"valueClass": "valeur DTEEND"
}
],
"table_structure": [
{
"tableIndex": 0,
"rowCount": 0,
"rows": []
}
]
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

File diff suppressed because one or more lines are too long
Binary file not shown.

After

Width:  |  Height:  |  Size: 208 KiB

+385
View File
@@ -0,0 +1,385 @@
{
"form_id": "10",
"patient_code": "CZ1-01",
"listing_cells": [
"CZ1-01",
"Male",
"Subject",
"16/02/2024",
"28/02/2024",
"17/04/2024",
"CZ1 - Fakultní Thomayerova nemocnice",
"VISIT0",
"V0 : Implantation Visit",
"0",
"1",
"1",
"",
"",
"",
"28/02/2024",
"Accepted",
"",
"",
"0",
"",
"0",
"",
"",
"1",
"Open",
""
],
"fields": [
{
"key": "Date of surgery (or date of the attempt)",
"value": "28/02/2024",
"valueClass": "valeur DTET0"
},
{
"key": "Has the patient been implanted with ARTUS®?",
"value": "Yes",
"valueClass": "valeur "
},
{
"key": "How many implantation attempts have there been?",
"value": null,
"valueClass": ""
},
{
"key": "Please explain why and describe the difficulty(ies) experienced:",
"value": null,
"valueClass": ""
},
{
"key": "The results of the 24-hour Pad Weight Test have been entered in the Baseline visit to validate the inclusion of the subject",
"value": "Yes",
"valueClass": "valeur "
},
{
"key": "Was the clinical examination performed",
"value": "Yes",
"valueClass": "valeur "
},
{
"key": "Exam date",
"value": "27/02/2024",
"valueClass": "valeur DTEEXAM"
},
{
"key": "Weight",
"value": "114   kg",
"valueClass": "valeur WGT"
},
{
"key": "Body Mass Index",
"value": "32.3   kg/cm²",
"valueClass": "valeur BMI"
},
{
"key": "Explain why clinical examination was not performed",
"value": null,
"valueClass": ""
},
{
"key": "The charge of the TWO Remote Controls was done correctly before the surgery (for 5 hours each)",
"value": "Yes",
"valueClass": "valeur "
},
{
"key": "Describe the difficulty(ies) experienced and alternative or solution provided",
"value": null,
"valueClass": ""
},
{
"key": "All steps for the \"Start procedure\" of the two Remote Controls have been completed",
"value": "Yes",
"valueClass": "valeur "
},
{
"key": "Describe the difficulty(ies) experienced and alternative or solution provided",
"value": null,
"valueClass": ""
},
{
"key": "Comments",
"value": null,
"valueClass": ""
},
{
"key": "All steps for \"Pairing procedure\" of the Remote Control and the Control Unit have been completed",
"value": "Yes",
"valueClass": "valeur "
},
{
"key": "Describe the difficulty(ies) experienced and alternative or solution provided",
"value": null,
"valueClass": ""
},
{
"key": "Comments",
"value": null,
"valueClass": ""
},
{
"key": "All the steps of the 'Calibration procedure' have been completed",
"value": "Yes",
"valueClass": "valeur "
},
{
"key": "Describe the difficulty(ies) experienced and alternative or solution provided",
"value": null,
"valueClass": ""
},
{
"key": "Comments",
"value": null,
"valueClass": ""
},
{
"key": "LOT of the ARTUS® Cuff S",
"value": "22-0224",
"valueClass": "valeur CUFF"
},
{
"key": "SN of the ARTUS® Control Unit",
"value": "210011",
"valueClass": "valeur CONTSN"
},
{
"key": "SN of the ARTUS® Remote Control #1",
"value": "052300185",
"valueClass": "valeur REMOSN"
},
{
"key": "SN of the ARTUS® Remote Control #2",
"value": null,
"valueClass": ""
},
{
"key": "The Back-up Material was used",
"value": "No",
"valueClass": "valeur "
},
{
"key": "LOT of the ARTUS® Cuff S",
"value": null,
"valueClass": ""
},
{
"key": "SN of the ARTUS® Control Unit",
"value": null,
"valueClass": ""
},
{
"key": "SN of the ARTUS® Remote Control",
"value": null,
"valueClass": ""
},
{
"key": "Beginning of the surgery, start of the incision (hh:mm)",
"value": "10:00",
"valueClass": "valeur START"
},
{
"key": "End of the surgery, closure of the incision (hh:mm)",
"value": "11:15",
"valueClass": "valeur STOP"
},
{
"key": "What type of anesthesia performed ?",
"value": "General",
"valueClass": "valeur "
},
{
"key": "Size of Foley catheter used",
"value": "14 CH",
"valueClass": "valeur "
},
{
"key": "Did a surgical dissection of the bulbospongiosus muscle has been performed?",
"value": null,
"valueClass": ""
},
{
"key": "Locking Position of the cuff around the urethra",
"value": "1",
"valueClass": "valeur "
},
{
"key": "Tightening of the urethra",
"value": null,
"valueClass": ""
},
{
"key": "If you have encountered difficulties, please describe the difficulty(ies) experienced and alternative or solution provided",
"value": "no difficulties",
"valueClass": "valeur ENCOUNT"
},
{
"key": "Comment",
"value": null,
"valueClass": ""
},
{
"key": "All steps for the \"Surgery Test procedure\" have been completed",
"value": "Yes",
"valueClass": "valeur "
},
{
"key": "Describe the difficulty(ies) experienced and alternative or solution provided",
"value": null,
"valueClass": ""
},
{
"key": "Comments",
"value": null,
"valueClass": ""
},
{
"key": "All steps for the \"Implantation of the control unit\" have been completed",
"value": "Yes",
"valueClass": "valeur "
},
{
"key": "Describe the difficulty(ies) experienced and alternative or solution provided",
"value": null,
"valueClass": ""
},
{
"key": "Comments",
"value": null,
"valueClass": ""
},
{
"key": "All steps for the \"Completion of implantation\" have been completed",
"value": "Yes",
"valueClass": "valeur "
},
{
"key": "Describe the difficulty(ies) experienced and alternative or solution provided",
"value": null,
"valueClass": ""
},
{
"key": "Comments",
"value": null,
"valueClass": ""
},
{
"key": "Was a Picture of the Cuff final position around the urethra taken intra-operatively",
"value": "Yes",
"valueClass": "valeur "
},
{
"key": "Was a Picture of the Control Unit final position taken intra-operatively",
"value": "Yes",
"valueClass": "valeur "
},
{
"key": "Was the Pelvis radiography performed?",
"value": "Yes",
"valueClass": "valeur "
},
{
"key": "Date of most recent pelvis radiography",
"value": "04/03/2024",
"valueClass": "valeur DTEPEL"
},
{
"key": "Was the Usability Questionnaire Surgeon (intra-operative) performed",
"value": "Yes",
"valueClass": "valeur "
},
{
"key": "Explain why Usability Questionnaire Surgeon was not performed",
"value": null,
"valueClass": ""
},
{
"key": "1. The implantation of Artus® is technically simple",
"value": "2 : Agree",
"valueClass": "valeur "
},
{
"key": "2. The handling of the shell screwed on the end of the transmission cable is easy",
"value": "2 : Agree",
"valueClass": "valeur "
},
{
"key": "3. The cuff is easy to insert around the urethra",
"value": "2 : Agree",
"valueClass": "valeur "
},
{
"key": "4. Positioning the Cuff around the urethra is easy to perform",
"value": "3 : Not sure",
"valueClass": "valeur "
},
{
"key": "5. The Cuff loop around the urethra is easy to adjust",
"value": "2 : Agree",
"valueClass": "valeur "
},
{
"key": "6. The implantation technique of the Control Unit in the abdominal wall is easy to perform",
"value": "2 : Agree",
"valueClass": "valeur "
},
{
"key": "7. The fixing technique for the Control Unit in the abdominal wall is easy to perform",
"value": "2 : Agree",
"valueClass": "valeur "
},
{
"key": "8. The connection of the transmission cable and the Control Unit is easy to perform",
"value": "2 : Agree",
"valueClass": "valeur "
},
{
"key": "9. The remote control is easy to manipulate in the sterile bag",
"value": "2 : Agree",
"valueClass": "valeur "
},
{
"key": "10. The sequence to be carried out to reach the screen proposing the password to access the Physician interface is simple",
"value": "2 : Agree",
"valueClass": "valeur "
},
{
"key": "11. Matching between the Remote Control and the implanted Control Unit is easy to perform",
"value": "2 : Agree",
"valueClass": "valeur "
},
{
"key": "12. Visual evaluation of the correct operation of the device (Surgery mode) is easy to perform",
"value": "2 : Agree",
"valueClass": "valeur "
},
{
"key": "Do you have any comments regarding the intra-operative ARTUS implant and its use",
"value": "No",
"valueClass": "valeur "
},
{
"key": "Please complete your comment below",
"value": null,
"valueClass": ""
},
{
"key": "Device deficiency(ies) occurred during the procedure",
"value": "No",
"valueClass": "valeur "
},
{
"key": "Is the subject receiving any concomitant medication",
"value": "Yes",
"valueClass": "valeur "
},
{
"key": "Did new adverse event(s) occur since the informed consent signature",
"value": "No",
"valueClass": "valeur "
}
]
}
+1
View File
@@ -0,0 +1 @@
{"cookies": [{"name": "i18n_lang", "value": "en", "domain": "prod.evamed.com", "path": "/etude/soft", "expires": 1810975810.980863, "httpOnly": false, "secure": false, "sameSite": "Lax"}, {"name": "browser_compat", "value": "true", "domain": "prod.evamed.com", "path": "/etude/soft", "expires": 1779958212, "httpOnly": false, "secure": false, "sameSite": "Lax"}, {"name": "isMobileDevice", "value": "n", "domain": "prod.evamed.com", "path": "/etude/soft", "expires": 1779958212, "httpOnly": false, "secure": false, "sameSite": "Lax"}, {"name": "Evamed_RepClient", "value": "myopowers-dry", "domain": "prod.evamed.com", "path": "/etude/soft", "expires": 1810975813.361198, "httpOnly": false, "secure": false, "sameSite": "Lax"}, {"name": "AreCookiesEnabled", "value": "286", "domain": "prod.evamed.com", "path": "/etude/soft", "expires": 1779958212, "httpOnly": false, "secure": false, "sameSite": "Lax"}, {"name": "EE_Index", "value": "o54t426bm3kaktihcmsi7mrerf", "domain": "prod.evamed.com", "path": "/", "expires": -1, "httpOnly": false, "secure": false, "sameSite": "Lax"}], "origins": []}
+185
View File
@@ -0,0 +1,185 @@
"""
Surgery (V0 Implantation Visit) Import — scrapes from EvaMed DRY study and upserts into MongoDB.
Run repeatedly; only stores field-level changes (delta) in history[].
Unique key: _form_id (each form has a unique ID in EvaMed).
MongoDB: db=Dry, collection=Surgery
"""
import asyncio
import re
from datetime import datetime
from pathlib import Path
from playwright.async_api import async_playwright
from pymongo import MongoClient
BASE_URL = "https://prod.evamed.com/etude/soft/index.php"
LOGIN_URL = f"{BASE_URL}?module=authentification&class=login&client=myopowers-dry"
LIST_URL = f"{BASE_URL}?module=monitoring&class=formslisting&center_id=2&formtype=10&l=ALL"
LOGIN = "vbuzalka"
PASSWORD = "Vlado9674+"
MONGO_HOST = "192.168.1.76"
DB_NAME = "Dry"
COLLECTION = "Surgery"
SESSION_FILE = Path(__file__).parent / "session.json"
DATE_RE = re.compile(r"^(\d{2})/(\d{2})/(\d{4})$")
def parse_value(value):
"""Parse DD/MM/YYYY -> datetime, digit-only -> int, else str. None if empty."""
if not value or not value.strip():
return None
v = value.strip()
m = DATE_RE.fullmatch(v)
if m:
return datetime(int(m.group(3)), int(m.group(2)), int(m.group(1)))
if re.fullmatch(r"\d+", v):
return int(v)
return v
async def do_login(page):
await page.goto(LOGIN_URL)
await page.wait_for_load_state("networkidle")
await page.locator("#login").fill(LOGIN)
await page.locator('input[type="password"]').first.fill(PASSWORD)
await page.click('input[value="Connection"]')
await page.wait_for_load_state("networkidle")
async def get_form_ids(page):
"""Return list of {formId, patientCode} from the filtered forms list."""
await page.goto(LIST_URL)
await page.wait_for_load_state("networkidle")
return await page.evaluate("""() => {
const results = [];
document.querySelectorAll('a[title="Open form"]').forEach(a => {
const href = a.getAttribute('href') || '';
const m = href.match(/id=(\\d+)/);
if (!m) return;
const row = a.closest('tr');
const dirLink = row ? row.querySelector('a[title="Open directory"]') : null;
const patientCode = dirLink ? dirLink.innerText.trim() : '';
results.push({ formId: m[1], patientCode: patientCode });
});
return results;
}""")
async def extract_form_fields(page, form_id):
"""Navigate to form and extract all field values."""
url = f"{BASE_URL}?module=dossier&class=file&event=show&id={form_id}#fiche"
await page.goto(url)
await page.wait_for_load_state("networkidle")
raw = await page.evaluate("""() => {
const fields = {};
document.querySelectorAll('.tableauFormulaire span.label').forEach(label => {
const key = label.innerText.trim();
const valEl = label.nextElementSibling;
fields[key] = valEl ? valEl.innerText.trim() || null : null;
});
return fields;
}""")
parsed = {}
for k, v in raw.items():
parsed[k] = parse_value(v)
parsed['_form_id'] = int(form_id)
return parsed
def upsert(collection, doc, patient_code, now):
form_id = doc['_form_id']
key = {"_form_id": form_id}
existing = collection.find_one(key)
skip = {'_form_id'}
data = {k: v for k, v in doc.items() if k not in skip}
if existing is None:
collection.insert_one({
**key,
"patient_code": patient_code,
"data": data,
"history": [],
"first_seen_at": now,
"last_seen_at": now,
"deleted_at": None,
})
print(f" NEW {patient_code} Surgery form_id={form_id}")
return
old_data = existing.get("data", {})
changes = {}
for k in set(data) | set(old_data):
old_v = old_data.get(k)
new_v = data.get(k)
if old_v != new_v:
changes[k] = {"old": old_v, "new": new_v}
update = {"$set": {"last_seen_at": now, "deleted_at": None, "patient_code": patient_code}}
if changes:
update["$set"]["data"] = data
update["$push"] = {"history": {"timestamp": now, "changes": changes}}
print(f" CHANGED {patient_code} Surgery form_id={form_id} -> {list(changes.keys())}")
else:
print(f" ok {patient_code} Surgery form_id={form_id}")
collection.update_one(key, update)
async def main():
mongo = MongoClient(MONGO_HOST)
col = mongo[DB_NAME][COLLECTION]
now = datetime.now()
async with async_playwright() as p:
browser = await p.chromium.launch(headless=False)
if SESSION_FILE.exists():
context = await browser.new_context(storage_state=str(SESSION_FILE))
print("Loaded saved session")
else:
context = await browser.new_context(viewport={"width": 1400, "height": 900})
page = await context.new_page()
await page.goto(LIST_URL)
await page.wait_for_load_state("networkidle")
if "authentification" in page.url:
print("Logging in...")
await do_login(page)
await context.storage_state(path=str(SESSION_FILE))
print("Session saved")
else:
print("Session valid")
form_infos = await get_form_ids(page)
current_ids = {info['formId'] for info in form_infos}
print(f"Found {len(form_infos)} Surgery forms")
for info in form_infos:
fid = info['formId']
print(f"Scraping form {fid} ({info['patientCode']})...")
doc = await extract_form_fields(page, fid)
upsert(col, doc, info['patientCode'], now)
for rec in col.find({"deleted_at": None}, {"_form_id": 1, "patient_code": 1}):
if str(rec.get('_form_id', '')) not in current_ids:
col.update_one({"_id": rec["_id"]}, {"$set": {"deleted_at": now}})
print(f" DELETED form_id={rec['_form_id']} ({rec.get('patient_code')})")
await browser.close()
mongo.close()
print(f"\nDone -- {len(form_infos)} forms processed at {now.isoformat()}")
if __name__ == "__main__":
asyncio.run(main())
@@ -0,0 +1,223 @@
# Název: janssenpc_file_send.py
# Verze: 2.0
# Datum: 2026-05-27
# Popis: Přejmenuje soubory ve složce ##JNJPrenos, odešle je na msgs.buzalka.cz
# a přesune do podsložky Trash. Loguje průběh do file_send.log vedle skriptu.
# Podporuje: Panorama Dashboard (xlsx), Site Visit Report (xlsx),
# Follow-Up Letter (xlsx), Clario MayoScore (csv), Clario MayoDiary (csv).
import os
import time
import shutil
import requests
import pandas as pd
from pathlib import Path
from datetime import datetime
TOKEN = "13e1bb01-9fd5-44a8-8ce9-4ee27133d340"
UPLOAD_URL = "https://msgs.buzalka.cz/upload-dropbox"
SOURCE_DIR = Path(r"C:\Users\vbuzalka\OneDrive - JNJ\##JNJPrenos")
TRASH_DIR = SOURCE_DIR / "Trash"
LOG_FILE = Path(__file__).parent / "file_send.log"
MAYO_DIARY_COLUMNS = [
'Protocol', 'Country', 'Site', 'PI Name', 'Subject ID',
'Report Date', 'Report Start Date/Time', 'Report End Date/Time',
'Stool Frequency', 'Form Number', 'Role', 'Original Source',
]
MAYO_SCORE_COLUMNS = [
'Protocol', 'Study Population', 'Country', 'Site', 'Principal Investigator',
'Participant ID', 'Baseline Stool Frequency', 'Visit', 'Visit Date',
'Endoscopy Completed?', 'Central Endoscopy Score', 'Local Endoscopy Score',
'Partial Mayo Score', 'Full Mayo Score',
]
PANORAMA_COLUMNS = [
'Part', 'Source', 'Sector', 'TA', 'Protocol ID', 'Interventional',
'Region', 'Country Name', 'Institution Name', 'Site City',
'Site Zip/Postal Code', 'Site Address', 'MSID', 'Site ID',
'Site Status', 'SM Full Name', 'PI Name', 'St F Subj Enr Act',
'ID', 'Category', 'Type', 'Priority', 'Severity', 'Description',
'Brief Description - Subject ID', 'Comments', 'Created By',
'Create Date', 'Last Modified Date', 'Start Date', 'Due Date',
'End Date', 'Status', 'Days Outstanding', 'Action Taken',
'Escalated To', 'Visit Report Status', 'Visit Report Approved',
'Visit Report Type', 'Visit Report Status End Date', 'Active',
'Association', 'Deviation', 'Deviation Closed Date', 'Reason For Exclusion'
]
def log(msg: str):
ts = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
line = f"[{ts}] {msg}"
print(line)
with LOG_FILE.open("a", encoding="utf-8") as lf:
lf.write(line + "\n")
def move_to_trash(f: Path):
TRASH_DIR.mkdir(exist_ok=True)
dest = TRASH_DIR / f.name
if dest.exists():
ts = datetime.now().strftime('%Y%m%d_%H%M%S')
dest = TRASH_DIR / f"{f.stem}_{ts}{f.suffix}"
shutil.move(str(f), dest)
def get_timestamp(file_path: str) -> str:
return datetime.fromtimestamp(os.path.getmtime(file_path)).strftime('%Y-%m-%d_%H-%M-%S')
def prejmenuj(directory: Path) -> None:
log(f"--- Přejmenování, adresář: {directory} ---")
files = [f for f in directory.iterdir() if f.is_file()]
log(f" Nalezeno souborů: {len(files)}{[f.name for f in files]}")
for f in files:
filename = f.name
file_path = str(f)
# 0a. CLARIO MAYO DIARY (CSV)
if 'MAYO-DIARY' in filename and filename.endswith('.csv'):
log(f" Detekován MayoDiary: {filename}")
try:
df = pd.read_csv(file_path)
missing = set(MAYO_DIARY_COLUMNS) - set(df.columns)
if not missing:
protocols = df['Protocol'].dropna().unique()
log(f" Protocol: {list(protocols)}")
if len(protocols) > 0:
study = str(protocols[0]).strip()
new_name = f"{get_timestamp(file_path)} {study} Clario MayoDiary.csv"
f.rename(directory / new_name)
log(f" ÚSPĚCH: -> '{new_name}'")
else:
log(f" VAROVÁNÍ: Sloupec Protocol je prázdný.")
else:
log(f" PŘESKOČENO: Chybí sloupce: {missing}")
except Exception as e:
log(f" CHYBA: {e}")
continue
# 0b. CLARIO MAYO SCORE (CSV)
if 'Custom.MayoScoreReport' in filename and filename.endswith('.csv'):
log(f" Detekován MayoScore: {filename}")
try:
df = pd.read_csv(file_path)
missing = set(MAYO_SCORE_COLUMNS) - set(df.columns)
if not missing:
protocols = df['Protocol'].dropna().unique()
log(f" Protocol: {list(protocols)}")
if len(protocols) > 0:
study = str(protocols[0]).strip()
new_name = f"{get_timestamp(file_path)} {study} Clario MayoScore.csv"
f.rename(directory / new_name)
log(f" ÚSPĚCH: -> '{new_name}'")
else:
log(f" VAROVÁNÍ: Sloupec Protocol je prázdný.")
else:
log(f" PŘESKOČENO: Chybí sloupce: {missing}")
except Exception as e:
log(f" CHYBA: {e}")
continue
# Ostatní — jen xlsx
if not filename.endswith('.xlsx'):
log(f" Přeskočeno (neznámý typ): {filename}")
continue
# 1. PANORAMA DASHBOARD (XLSX)
if 'Panorama Dashboard' in filename:
log(f" Detekován Panorama: {filename}")
try:
df = pd.read_excel(file_path, skiprows=5)
missing = set(PANORAMA_COLUMNS) - set(df.columns)
if not missing:
ids = df['Protocol ID'].dropna().unique()
log(f" Protocol ID: {list(ids)}")
if len(ids) > 0:
study = str(ids[0]).strip()
new_name = f"{get_timestamp(file_path)} {study} Panorama Deviations and Issues.xlsx"
f.rename(directory / new_name)
log(f" ÚSPĚCH: -> '{new_name}'")
else:
log(f" VAROVÁNÍ: Protocol ID je prázdný.")
else:
log(f" PŘESKOČENO: Chybí sloupce: {missing}")
except Exception as e:
log(f" CHYBA: {e}")
continue
# 2. SITE VISIT REPORT A FOLLOW-UP LETTER (XLSX)
try:
df_a1 = pd.read_excel(file_path, nrows=1, header=None)
if not df_a1.empty:
a1 = str(df_a1.iloc[0, 0])
log(f" A1: {a1[:80]}")
is_site_visit = "Title: Site Visit Report Details" in a1
is_follow_up = "Title: Follow-Up Letter Details" in a1
if is_site_visit or is_follow_up:
suffix = "Site Visit Details.xlsx" if is_site_visit else "FUL details.xlsx"
log(f" Detekován {'Site Visit' if is_site_visit else 'Follow-Up Letter'}: {filename}")
df = pd.read_excel(file_path, skiprows=5)
if 'Protocol ID' in df.columns:
ids = df['Protocol ID'].dropna().unique()
log(f" Protocol ID: {list(ids)}")
if len(ids) > 0:
study = str(ids[0]).strip()
new_name = f"{get_timestamp(file_path)} {study} {suffix}"
f.rename(directory / new_name)
log(f" ÚSPĚCH: -> '{new_name}'")
else:
log(f" VAROVÁNÍ: Protocol ID je prázdný.")
else:
log(f" PŘESKOČENO: Chybí sloupec Protocol ID.")
else:
log(f" Přeskočeno (neznámý xlsx obsah): {filename}")
except Exception as e:
log(f" CHYBA: {e}")
log("--- Přejmenování dokončeno ---")
# === HLAVNÍ LOGIKA ===
log("=== Spuštění ===")
log(f"Zdrojový adresář: {SOURCE_DIR} (existuje: {SOURCE_DIR.exists()})")
# 1. Přejmenuj
prejmenuj(SOURCE_DIR)
# 2. Počkej 10 vteřin
log("Čekám 10 vteřin...")
time.sleep(10)
# 3. Odešli soubory
files = [f for f in SOURCE_DIR.iterdir() if f.is_file()]
log(f"Souborů k odeslání: {len(files)}")
for f in files:
log(f" Nalezen: {f.name}")
if not files:
log("Žádné soubory k odeslání.")
else:
for f in files:
try:
with f.open("rb") as fh:
resp = requests.post(
UPLOAD_URL,
headers={"Authorization": f"Bearer {TOKEN}"},
files={"file": (f.name, fh, "application/octet-stream")},
timeout=120,
)
resp.raise_for_status()
status = resp.json().get('status', '?').upper()
log(f" {status:10} | {f.name}")
move_to_trash(f)
log(f" PŘESUNUTO | {f.name} -> Trash")
except Exception as e:
log(f" CHYBA | {f.name} | {e}")
log("=== Hotovo ===")
@@ -0,0 +1,49 @@
# Název: janssenpc_file_watch.py
# Verze: 1.1
# Datum: 2026-05-27
# Popis: Démon hlídající složku ##JNJPrenos (watchdog). Při objevení nového souboru
# spustí janssenpc_file_send.py, který zajistí přejmenování, upload a přesun do Trash.
import subprocess
import sys
import time
from pathlib import Path
from watchdog.observers import Observer
from watchdog.events import FileSystemEventHandler
SOURCE_DIR = Path(r"C:\Users\vbuzalka\OneDrive - JNJ\##JNJPrenos")
SEND_SCRIPT = Path(__file__).parent / "janssenpc_file_send.py"
def run_send():
subprocess.run([sys.executable, str(SEND_SCRIPT)], check=False)
class NewFileHandler(FileSystemEventHandler):
def on_created(self, event):
if event.is_directory:
return
run_send()
def on_moved(self, event):
if event.is_directory:
return
run_send()
if __name__ == "__main__":
# Při startu zpracuj soubory, které už tam jsou
if any(f for f in SOURCE_DIR.iterdir() if f.is_file()):
run_send()
observer = Observer()
observer.schedule(NewFileHandler(), str(SOURCE_DIR), recursive=False)
observer.start()
print(f"Hlídám: {SOURCE_DIR}")
try:
while True:
time.sleep(1)
except KeyboardInterrupt:
observer.stop()
observer.join()
@@ -0,0 +1,196 @@
# Název: 02 PřejmenujSouboryReportu.py
# Verze: 1.2
# Datum: 2026-05-27
# Popis: Prochází zadaný adresář a přejmenuje známé typy reportů na standardizovaný
# formát "datum čas studie typ.přípona". Podporuje: Panorama Dashboard (xlsx),
# Site Visit Report (xlsx), Follow-Up Letter (xlsx),
# Clario MayoScore (csv), Clario MayoDiary (csv).
# Loguje průběh do prejmenuj.log vedle skriptu.
import os
import pandas as pd
from datetime import datetime
from pathlib import Path
LOG_FILE = Path(__file__).parent / "prejmenuj.log"
def log(msg: str):
ts = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
line = f"[{ts}] {msg}"
print(line)
with LOG_FILE.open("a", encoding="utf-8") as lf:
lf.write(line + "\n")
def zpracuj_reporty(directory_path):
mayo_diary_columns = [
'Protocol', 'Country', 'Site', 'PI Name', 'Subject ID',
'Report Date', 'Report Start Date/Time', 'Report End Date/Time',
'Stool Frequency', 'Form Number', 'Role', 'Original Source',
]
mayo_columns = [
'Protocol', 'Study Population', 'Country', 'Site', 'Principal Investigator',
'Participant ID', 'Baseline Stool Frequency', 'Visit', 'Visit Date',
'Endoscopy Completed?', 'Central Endoscopy Score', 'Local Endoscopy Score',
'Partial Mayo Score', 'Full Mayo Score',
]
panorama_columns = [
'Part', 'Source', 'Sector', 'TA', 'Protocol ID', 'Interventional',
'Region', 'Country Name', 'Institution Name', 'Site City',
'Site Zip/Postal Code', 'Site Address', 'MSID', 'Site ID',
'Site Status', 'SM Full Name', 'PI Name', 'St F Subj Enr Act',
'ID', 'Category', 'Type', 'Priority', 'Severity', 'Description',
'Brief Description - Subject ID', 'Comments', 'Created By',
'Create Date', 'Last Modified Date', 'Start Date', 'Due Date',
'End Date', 'Status', 'Days Outstanding', 'Action Taken',
'Escalated To', 'Visit Report Status', 'Visit Report Approved',
'Visit Report Type', 'Visit Report Status End Date', 'Active',
'Association', 'Deviation', 'Deviation Closed Date', 'Reason For Exclusion'
]
log(f"=== Spuštění přejmenování, adresář: {directory_path} ===")
if not os.path.exists(directory_path):
log(f"CHYBA: Adresář '{directory_path}' neexistuje.")
return
all_files = [f for f in os.listdir(directory_path) if os.path.isfile(os.path.join(directory_path, f))]
log(f"Nalezeno souborů: {len(all_files)}{all_files}")
for filename in all_files:
file_path = os.path.join(directory_path, filename)
# ---------------------------------------------------------
# 0a. CLARIO MAYO DIARY (CSV)
# ---------------------------------------------------------
if 'MAYO-DIARY' in filename and filename.endswith('.csv'):
log(f"Detekován MayoDiary: {filename}")
try:
df = pd.read_csv(file_path)
actual_columns = set(df.columns)
missing = set(mayo_diary_columns) - actual_columns
if not missing:
protocols = df['Protocol'].dropna().unique()
log(f" Protocol hodnoty: {list(protocols)}")
if len(protocols) > 0:
study_name = str(protocols[0]).strip()
file_time = datetime.fromtimestamp(os.path.getmtime(file_path))
timestamp = file_time.strftime('%Y-%m-%d_%H-%M-%S')
new_filename = f"{timestamp} {study_name} Clario MayoDiary.csv"
os.rename(file_path, os.path.join(directory_path, new_filename))
log(f" ÚSPĚCH: -> '{new_filename}'")
else:
log(f" VAROVÁNÍ: Sloupec Protocol je prázdný.")
else:
log(f" PŘESKOČENO: Chybí sloupce: {missing}")
except Exception as e:
log(f" CHYBA: {e}")
continue
# ---------------------------------------------------------
# 0b. CLARIO MAYO SCORE (CSV)
# ---------------------------------------------------------
if 'Custom.MayoScoreReport' in filename and filename.endswith('.csv'):
log(f"Detekován MayoScore: {filename}")
try:
df = pd.read_csv(file_path)
actual_columns = set(df.columns)
missing = set(mayo_columns) - actual_columns
if not missing:
protocols = df['Protocol'].dropna().unique()
log(f" Protocol hodnoty: {list(protocols)}")
if len(protocols) > 0:
study_name = str(protocols[0]).strip()
file_time = datetime.fromtimestamp(os.path.getmtime(file_path))
timestamp = file_time.strftime('%Y-%m-%d_%H-%M-%S')
new_filename = f"{timestamp} {study_name} Clario MayoScore.csv"
os.rename(file_path, os.path.join(directory_path, new_filename))
log(f" ÚSPĚCH: -> '{new_filename}'")
else:
log(f" VAROVÁNÍ: Sloupec Protocol je prázdný.")
else:
log(f" PŘESKOČENO: Chybí sloupce: {missing}")
except Exception as e:
log(f" CHYBA: {e}")
continue
# Ostatní typy — jen xlsx
if not filename.endswith('.xlsx'):
log(f"Přeskočeno (neznámý typ): {filename}")
continue
# ---------------------------------------------------------
# 1. PANORAMA DASHBOARD (XLSX)
# ---------------------------------------------------------
if 'Panorama Dashboard' in filename:
log(f"Detekován Panorama: {filename}")
try:
df = pd.read_excel(file_path, skiprows=5)
actual_columns = set(df.columns)
missing = set(panorama_columns) - actual_columns
if not missing:
protocol_ids = df['Protocol ID'].dropna().unique()
log(f" Protocol ID hodnoty: {list(protocol_ids)}")
if len(protocol_ids) > 0:
study_name = str(protocol_ids[0]).strip()
file_time = datetime.fromtimestamp(os.path.getmtime(file_path))
timestamp = file_time.strftime('%Y-%m-%d_%H-%M-%S')
new_filename = f"{timestamp} {study_name} Panorama Deviations and Issues.xlsx"
os.rename(file_path, os.path.join(directory_path, new_filename))
log(f" ÚSPĚCH: -> '{new_filename}'")
else:
log(f" VAROVÁNÍ: Sloupec Protocol ID je prázdný.")
else:
log(f" PŘESKOČENO: Chybí sloupce: {missing}")
except Exception as e:
log(f" CHYBA: {e}")
# ---------------------------------------------------------
# 2. SITE VISIT REPORT A FOLLOW-UP LETTER (XLSX)
# ---------------------------------------------------------
else:
try:
df_a1 = pd.read_excel(file_path, nrows=1, header=None)
if not df_a1.empty:
a1_text = str(df_a1.iloc[0, 0])
log(f" A1 obsah: {a1_text[:80]}")
is_site_visit = "Title: Site Visit Report Details" in a1_text
is_follow_up = "Title: Follow-Up Letter Details" in a1_text
if is_site_visit or is_follow_up:
suffix = "Site Visit Details.xlsx" if is_site_visit else "FUL details.xlsx"
log(f"Detekován {'Site Visit' if is_site_visit else 'Follow-Up Letter'}: {filename}")
df = pd.read_excel(file_path, skiprows=5)
if 'Protocol ID' in df.columns:
protocol_ids = df['Protocol ID'].dropna().unique()
log(f" Protocol ID hodnoty: {list(protocol_ids)}")
if len(protocol_ids) > 0:
study_name = str(protocol_ids[0]).strip()
file_time = datetime.fromtimestamp(os.path.getmtime(file_path))
timestamp = file_time.strftime('%Y-%m-%d_%H-%M-%S')
new_filename = f"{timestamp} {study_name} {suffix}"
os.rename(file_path, os.path.join(directory_path, new_filename))
log(f" ÚSPĚCH: -> '{new_filename}'")
else:
log(f" VAROVÁNÍ: Sloupec Protocol ID je prázdný.")
else:
log(f" PŘESKOČENO: Soubor neobsahuje sloupec 'Protocol ID'.")
else:
log(f"Přeskočeno (neznámý xlsx obsah): {filename}")
except Exception as e:
log(f" CHYBA: {e}")
log("=== Přejmenování dokončeno ===")
if __name__ == "__main__":
cesta_k_adresari = r"c:\Users\vbuzalka\OneDrive - JNJ\##JNJPrenos"
zpracuj_reporty(cesta_k_adresari)
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,38 @@
"Protocol","Study Population","Country","Site","Principal Investigator","Participant ID","Baseline Stool Frequency","Visit","Visit Date","Endoscopy Completed?","Endoscopy Date","Bowel Preparation Start Date 1","Bowel Preparation End Date 1","Bowel Preparation Start Date 2","Bowel Preparation End Date 2","Central Endoscopy Score","Local Endoscopy Score","PGA Score","Eligible Day (-1)","Day (-1) Excluded Reason(s)","Eligible Day (-2)","Day (-2) Excluded Reason(s)","Eligible Day (-3)","Day (-3) Excluded Reason(s)","Eligible Day (-4)","Day (-4) Excluded Reason(s)","Eligible Day (-5)","Day (-5) Excluded Reason(s)","Eligible Day (-6)","Day (-6) Excluded Reason(s)","Eligible Day (-7)","Day (-7) Excluded Reason(s)","Eligible Day (-8)","Day (-8) Excluded Reason(s)","Eligible Day (-9)","Day (-9) Excluded Reason(s)","Eligible Day (-10)","Day (-10) Excluded Reason(s)","Eligible Day (-1) Stool Count","Eligible Day (-2) Stool Count","Eligible Day (-3) Stool Count","Eligible Day (-4) Stool Count","Eligible Day (-5) Stool Count","Eligible Day (-6) Stool Count","Eligible Day (-7) Stool Count","Eligible Day (-8) Stool Count","Eligible Day (-9) Stool Count","Eligible Day (-10) Stool Count","Stool Frequency Sub-score","Eligible Day (-1) Rectal Bleeding Score","Eligible Day (-2) Rectal Bleeding Score","Eligible Day (-3) Rectal Bleeding Score","Eligible Day (-4) Rectal Bleeding Score","Eligible Day (-5) Rectal Bleeding Score","Eligible Day (-6) Rectal Bleeding Score","Eligible Day (-7) Rectal Bleeding Score","Eligible Day (-8) Rectal Bleeding Score","Eligible Day (-9) Rectal Bleeding Score","Eligible Day (-10) Rectal Bleeding Score","Rectal Bleeding Sub-score","Partial Mayo Score","Modified Mayo Score","Full Mayo Score","Site Action","Last Mayo Score Submission","Week I-12 Clinical Responder","Week I-12 Clinical Remission","Clinical Flare","Loss of Response","Partial Mayo Response Post Loss of Response","Partial Mayo Response for Clinical Non-Responders"
"77242113UCO3001","Adult","Czech Republic","DD5-CZ10001","Matej Falc","CZ100012001","1","I-0","19 Feb 2026","Yes","05 Feb 2026","04 Feb 2026","04 Feb 2026","-","-","2","-","3","18 Feb 2026","-","17 Feb 2026","-","16 Feb 2026","-","15 Feb 2026","-","14 Feb 2026","-","13 Feb 2026","-","12 Feb 2026","-","11 Feb 2026","Day Not Applicable for Calculation","10 Feb 2026","Day Not Applicable for Calculation","09 Feb 2026","Day Not Applicable for Calculation","10","8","7","5","7","8","8","-","-","-","3","1","1","1","0","1","1","1","-","-","-","1","7","6","9","-","08 Apr 2026 07:11:25","N/A","N/A","N/A","N/A","N/A","N/A"
"77242113UCO3001","Adult","Czech Republic","DD5-CZ10001","Matej Falc","CZ100012001","1","I-2","04 Mar 2026","-","-","-","-","-","-","-","-","3","03 Mar 2026","-","02 Mar 2026","-","01 Mar 2026","-","28 Feb 2026","-","27 Feb 2026","-","26 Feb 2026","-","25 Feb 2026","-","24 Feb 2026","Day Not Applicable for Calculation","23 Feb 2026","Day Not Applicable for Calculation","22 Feb 2026","Day Not Applicable for Calculation","5","4","5","4","5","6","6","-","-","-","2","1","0","1","0","1","0","1","-","-","-","1","6","","","-","-","N/A","N/A","N/A","N/A","N/A","N/A"
"77242113UCO3001","Adult","Czech Republic","DD5-CZ10001","Matej Falc","CZ100012001","1","I-4","18 Mar 2026","-","-","-","-","-","-","-","-","2","17 Mar 2026","-","16 Mar 2026","-","15 Mar 2026","-","14 Mar 2026","-","13 Mar 2026","-","12 Mar 2026","-","11 Mar 2026","-","10 Mar 2026","Day Not Applicable for Calculation","09 Mar 2026","Day Not Applicable for Calculation","08 Mar 2026","Day Not Applicable for Calculation","5","5","5","4","5","4","5","-","-","-","2","1","0","0","1","1","1","0","-","-","-","1","5","","","-","08 Apr 2026 11:04:49","N/A","N/A","N/A","N/A","N/A","N/A"
"77242113UCO3001","Adult","Czech Republic","DD5-CZ10001","Matej Falc","CZ100012001","1","I-8","05 May 2026","-","-","-","-","-","-","-","-","1","04 May 2026","-","03 May 2026","-","02 May 2026","-","01 May 2026","-","30 Apr 2026","-","29 Apr 2026","-","28 Apr 2026","-","27 Apr 2026","Day Not Applicable for Calculation","26 Apr 2026","Day Not Applicable for Calculation","25 Apr 2026","Day Not Applicable for Calculation","3","3","4","4","5","4","4","-","-","-","2","1","1","1","1","1","1","1","-","-","-","1","4","","","-","-","N/A","N/A","N/A","N/A","N/A","N/A"
"77242113UCO3001","Adult","Czech Republic","DD5-CZ10001","Matej Falc","CZ100012001","1","I-12","13 May 2026","Yes","06 May 2026","05 May 2026","05 May 2026","-","-","1","-","1","12 May 2026","-","11 May 2026","-","10 May 2026","-","09 May 2026","-","08 May 2026","-","07 May 2026","-","06 May 2026","Endoscopy","05 May 2026","Bowel Preparation for Procedure;Day Not Applicable for Calculation","04 May 2026","-","03 May 2026","Day Not Applicable for Calculation","5","4","6","5","5","5","-","-","3","-","2","1","0","1","1","1","1","-","-","1","-","1","4","4","5","-","-","Clinical Responder","No","N/A","N/A","N/A","N/A"
"77242113UCO3001","Adult","Czech Republic","DD5-CZ10001","Matej Falc","CZ100012002","1","I-0","08 Apr 2026","Yes","18 Mar 2026","17 Mar 2026","18 Mar 2026","-","-","2","-","2","07 Apr 2026","-","06 Apr 2026","-","05 Apr 2026","-","04 Apr 2026","Missing Diary","03 Apr 2026","-","02 Apr 2026","-","01 Apr 2026","-","31 Mar 2026","Day Not Applicable for Calculation","30 Mar 2026","Day Not Applicable for Calculation","29 Mar 2026","Day Not Applicable for Calculation","3","3","4","-","3","3","4","-","-","-","1","0","0","0","-","0","0","1","-","-","-","0","3","3","5","-","-","N/A","N/A","N/A","N/A","N/A","N/A"
"77242113UCO3001","Adult","Czech Republic","DD5-CZ10001","Matej Falc","CZ100012002","1","I-2","23 Apr 2026","-","-","-","-","-","-","-","-","2","22 Apr 2026","Missing Diary","21 Apr 2026","-","20 Apr 2026","-","19 Apr 2026","-","18 Apr 2026","-","17 Apr 2026","-","16 Apr 2026","-","15 Apr 2026","Day Not Applicable for Calculation","14 Apr 2026","Day Not Applicable for Calculation","13 Apr 2026","Day Not Applicable for Calculation","-","3","3","6","5","5","4","-","-","-","2","-","0","0","1","1","1","1","-","-","-","1","5","","","-","-","N/A","N/A","N/A","N/A","N/A","N/A"
"77242113UCO3001","Adult","Czech Republic","DD5-CZ10001","Matej Falc","CZ100012002","1","I-4","06 May 2026","-","-","-","-","-","-","-","-","1","05 May 2026","-","04 May 2026","-","03 May 2026","-","02 May 2026","-","01 May 2026","-","30 Apr 2026","-","29 Apr 2026","-","28 Apr 2026","Day Not Applicable for Calculation","27 Apr 2026","Day Not Applicable for Calculation","26 Apr 2026","Day Not Applicable for Calculation","6","3","2","3","3","3","3","-","-","-","1","1","0","0","0","1","1","0","-","-","-","0","2","","","-","-","N/A","N/A","N/A","N/A","N/A","N/A"
"77242113UCO3001","Adult","Czech Republic","DD5-CZ10001","Matej Falc","CZ100012003","1","I-0","27 May 2026","Yes","13 May 2026","12 May 2026","12 May 2026","-","-","3","-","2","26 May 2026","-","25 May 2026","-","24 May 2026","-","23 May 2026","-","22 May 2026","-","21 May 2026","-","20 May 2026","-","19 May 2026","Day Not Applicable for Calculation","18 May 2026","Day Not Applicable for Calculation","17 May 2026","Day Not Applicable for Calculation","6","9","7","8","9","7","8","-","-","-","3","2","2","2","2","1","1","1","-","-","-","2","7","8","10","-","27 May 2026 07:24:39","N/A","N/A","N/A","N/A","N/A","N/A"
"77242113UCO3001","Adult","Czech Republic","DD5-CZ10006","Michal Konecny","CZ100062001","1","I-0","20 Mar 2026","Yes","19 Feb 2026","-","-","-","-","3","-","3","19 Mar 2026","-","18 Mar 2026","-","17 Mar 2026","-","16 Mar 2026","-","15 Mar 2026","-","14 Mar 2026","-","13 Mar 2026","-","12 Mar 2026","Day Not Applicable for Calculation","11 Mar 2026","Day Not Applicable for Calculation","10 Mar 2026","Day Not Applicable for Calculation","7","7","8","8","7","8","5","-","-","-","3","2","1","1","1","1","1","0","-","-","-","1","7","7","10","-","20 Mar 2026 07:03:23","N/A","N/A","N/A","N/A","N/A","N/A"
"77242113UCO3001","Adult","Czech Republic","DD5-CZ10006","Michal Konecny","CZ100062001","1","I-2","08 Apr 2026","-","-","-","-","-","-","-","-","2","07 Apr 2026","Medication For Diarrhea","06 Apr 2026","Medication For Diarrhea","05 Apr 2026","Medication For Diarrhea","04 Apr 2026","Medication For Diarrhea","03 Apr 2026","Medication For Diarrhea","02 Apr 2026","Medication For Diarrhea","01 Apr 2026","Medication For Diarrhea","31 Mar 2026","Medication For Diarrhea;Day Not Applicable for Calculation","30 Mar 2026","Medication For Diarrhea;Day Not Applicable for Calculation","29 Mar 2026","Day Not Applicable for Calculation","-","-","-","-","-","-","-","-","-","-","Non-Evaluable","-","-","-","-","-","-","-","-","-","-","Non-Evaluable","Non-Evaluable","Non-Evaluable","Non-Evaluable","-","-","N/A","N/A","N/A","N/A","N/A","N/A"
"77242113UCO3001","Adult","Czech Republic","DD5-CZ10006","Michal Konecny","CZ100062001","1","I-4","15 Apr 2026","-","-","-","-","-","-","-","-","3","14 Apr 2026","-","13 Apr 2026","-","12 Apr 2026","-","11 Apr 2026","-","10 Apr 2026","-","09 Apr 2026","-","08 Apr 2026","-","07 Apr 2026","Medication For Diarrhea;Day Not Applicable for Calculation","06 Apr 2026","Medication For Diarrhea;Day Not Applicable for Calculation","05 Apr 2026","Medication For Diarrhea;Day Not Applicable for Calculation","9","22","20","19","17","18","18","-","-","-","3","1","3","2","2","2","2","2","-","-","-","2","8","","","-","04 May 2026 22:06:03","N/A","N/A","N/A","N/A","N/A","N/A"
"77242113UCO3001","Adult","Czech Republic","DD5-CZ10006","Michal Konecny","CZ100062001","1","I-8","18 May 2026","-","-","-","-","-","-","-","-","2","17 May 2026","-","16 May 2026","-","15 May 2026","-","14 May 2026","-","13 May 2026","-","12 May 2026","-","11 May 2026","-","10 May 2026","Day Not Applicable for Calculation","09 May 2026","Day Not Applicable for Calculation","08 May 2026","Day Not Applicable for Calculation","7","5","9","7","7","8","8","-","-","-","3","1","1","1","1","1","1","1","-","-","-","1","6","","","-","-","N/A","N/A","N/A","N/A","N/A","N/A"
"77242113UCO3001","Adult","Czech Republic","DD5-CZ10006","Michal Konecny","CZ100062002","1","I-0","26 May 2026","Yes","14 May 2026","13 May 2026","13 May 2026","-","-","2","-","2","25 May 2026","-","24 May 2026","-","23 May 2026","-","22 May 2026","-","21 May 2026","-","20 May 2026","-","19 May 2026","-","18 May 2026","Day Not Applicable for Calculation","17 May 2026","Day Not Applicable for Calculation","16 May 2026","Day Not Applicable for Calculation","8","8","6","7","7","6","7","-","-","-","3","2","2","2","2","2","2","2","-","-","-","2","7","7","9","-","-","N/A","N/A","N/A","N/A","N/A","N/A"
"77242113UCO3001","Adult","Czech Republic","DD5-CZ10009","Jiri Pumprla","CZ100092001","1","I-0","05 May 2026","Yes","24 Apr 2026","23 Apr 2026","23 Apr 2026","-","-","2","-","2","04 May 2026","-","03 May 2026","-","02 May 2026","-","01 May 2026","-","30 Apr 2026","-","29 Apr 2026","-","28 Apr 2026","-","27 Apr 2026","Day Not Applicable for Calculation","26 Apr 2026","Day Not Applicable for Calculation","25 Apr 2026","Day Not Applicable for Calculation","5","5","5","5","5","5","5","-","-","-","2","1","1","1","1","1","1","1","-","-","-","1","5","5","7","-","05 May 2026 11:19:40","N/A","N/A","N/A","N/A","N/A","N/A"
"77242113UCO3001","Adult","Czech Republic","DD5-CZ10009","Jiri Pumprla","CZ100092001","1","I-2","19 May 2026","-","-","-","-","-","-","-","-","1","18 May 2026","-","17 May 2026","-","16 May 2026","-","15 May 2026","-","14 May 2026","-","13 May 2026","-","12 May 2026","-","11 May 2026","Day Not Applicable for Calculation","10 May 2026","Day Not Applicable for Calculation","09 May 2026","Day Not Applicable for Calculation","5","4","5","5","5","4","6","-","-","-","2","1","1","1","1","1","1","1","-","-","-","1","4","","","-","19 May 2026 10:38:25","N/A","N/A","N/A","N/A","N/A","N/A"
"77242113UCO3001","Adult","Czech Republic","DD5-CZ10012","Stefan Konecny","CZ100122001","5","I-0","07 Apr 2026","Yes","24 Mar 2026","22 Mar 2026","22 Mar 2026","-","-","2","-","2","06 Apr 2026","-","05 Apr 2026","-","04 Apr 2026","-","03 Apr 2026","-","02 Apr 2026","-","01 Apr 2026","-","31 Mar 2026","-","30 Mar 2026","Day Not Applicable for Calculation","29 Mar 2026","Day Not Applicable for Calculation","28 Mar 2026","Day Not Applicable for Calculation","8","11","5","9","11","10","13","-","-","-","3","1","2","2","2","2","2","2","-","-","-","2","7","7","9","-","04 May 2026 08:44:52","N/A","N/A","N/A","N/A","N/A","N/A"
"77242113UCO3001","Adult","Czech Republic","DD5-CZ10012","Stefan Konecny","CZ100122001","5","I-2","22 Apr 2026","-","-","-","-","-","-","-","-","2","21 Apr 2026","-","20 Apr 2026","-","19 Apr 2026","-","18 Apr 2026","-","17 Apr 2026","-","16 Apr 2026","-","15 Apr 2026","-","14 Apr 2026","Day Not Applicable for Calculation","13 Apr 2026","Day Not Applicable for Calculation","12 Apr 2026","Day Not Applicable for Calculation","7","5","6","6","7","8","2","-","-","-","1","1","0","1","1","1","2","0","-","-","-","1","4","","","-","04 May 2026 08:45:07","N/A","N/A","N/A","N/A","N/A","N/A"
"77242113UCO3001","Adult","Czech Republic","DD5-CZ10012","Stefan Konecny","CZ100122001","5","I-4","07 May 2026","-","-","-","-","-","-","-","-","1","06 May 2026","-","05 May 2026","-","04 May 2026","-","03 May 2026","-","02 May 2026","-","01 May 2026","-","30 Apr 2026","-","29 Apr 2026","Day Not Applicable for Calculation","28 Apr 2026","Day Not Applicable for Calculation","27 Apr 2026","Day Not Applicable for Calculation","8","7","7","8","4","11","7","-","-","-","1","2","1","1","1","0","1","1","-","-","-","1","3","","","-","-","N/A","N/A","N/A","N/A","N/A","N/A"
"77242113UCO3001","Adult","Czech Republic","DD5-CZ10013","David Stepek","CZ100132001","1","I-0","24 Mar 2026","Yes","12 Mar 2026","11 Mar 2026","11 Mar 2026","-","-","2","-","2","23 Mar 2026","-","22 Mar 2026","-","21 Mar 2026","-","20 Mar 2026","-","19 Mar 2026","-","18 Mar 2026","-","17 Mar 2026","-","16 Mar 2026","Day Not Applicable for Calculation","15 Mar 2026","Day Not Applicable for Calculation","14 Mar 2026","Day Not Applicable for Calculation","8","6","5","7","6","7","6","-","-","-","3","1","1","1","0","1","1","1","-","-","-","1","6","6","8","-","05 Apr 2026 22:41:27","N/A","N/A","N/A","N/A","N/A","N/A"
"77242113UCO3001","Adult","Czech Republic","DD5-CZ10013","David Stepek","CZ100132001","1","I-2","08 Apr 2026","-","-","-","-","-","-","-","-","2","07 Apr 2026","-","06 Apr 2026","-","05 Apr 2026","-","04 Apr 2026","-","03 Apr 2026","-","02 Apr 2026","-","01 Apr 2026","-","31 Mar 2026","Day Not Applicable for Calculation","30 Mar 2026","Day Not Applicable for Calculation","29 Mar 2026","Day Not Applicable for Calculation","5","2","3","6","5","5","5","-","-","-","2","0","0","0","0","1","1","0","-","-","-","0","4","","","-","27 May 2026 12:53:52","N/A","N/A","N/A","N/A","N/A","N/A"
"77242113UCO3001","Adult","Czech Republic","DD5-CZ10013","David Stepek","CZ100132001","1","I-4","21 Apr 2026","-","-","-","-","-","-","-","-","0","20 Apr 2026","-","19 Apr 2026","-","18 Apr 2026","-","17 Apr 2026","-","16 Apr 2026","-","15 Apr 2026","-","14 Apr 2026","-","13 Apr 2026","Day Not Applicable for Calculation","12 Apr 2026","Day Not Applicable for Calculation","11 Apr 2026","Day Not Applicable for Calculation","4","3","4","3","3","4","4","-","-","-","2","0","0","0","0","0","0","0","-","-","-","0","2","","","-","27 May 2026 12:54:41","N/A","N/A","N/A","N/A","N/A","N/A"
"77242113UCO3001","Adult","Czech Republic","DD5-CZ10013","David Stepek","CZ100132002","1","I-0","12 May 2026","Yes","21 Apr 2026","20 Apr 2026","21 Apr 2026","-","-","2","-","2","11 May 2026","-","10 May 2026","-","09 May 2026","-","08 May 2026","-","07 May 2026","-","06 May 2026","-","05 May 2026","Missing Diary","04 May 2026","Day Not Applicable for Calculation","03 May 2026","Day Not Applicable for Calculation","02 May 2026","Day Not Applicable for Calculation","2","1","1","1","1","2","-","-","-","-","0","0","0","0","0","0","0","-","-","-","-","0","2","2","4","-","-","N/A","N/A","N/A","N/A","N/A","N/A"
"77242113UCO3001","Adult","Czech Republic","DD5-CZ10013","David Stepek","CZ100132002","1","I-2","26 May 2026","-","-","-","-","-","-","-","-","1","25 May 2026","-","24 May 2026","Missing Diary","23 May 2026","-","22 May 2026","-","21 May 2026","-","20 May 2026","-","19 May 2026","-","18 May 2026","Missing Diary;Day Not Applicable for Calculation","17 May 2026","Day Not Applicable for Calculation","16 May 2026","Day Not Applicable for Calculation","1","-","1","2","1","2","2","-","-","-","1","0","-","0","0","0","0","0","-","-","-","0","2","","","-","-","N/A","N/A","N/A","N/A","N/A","N/A"
"77242113UCO3001","Adolescent","Czech Republic","DD5-CZ10020","Lucie Gonsorcikova","CZ100201001","1","Unscheduled 1","04 May 2026","Yes","20 Apr 2026","12 Apr 2026","15 Apr 2026","-","-","2","-","3","03 May 2026","-","02 May 2026","-","01 May 2026","-","30 Apr 2026","-","29 Apr 2026","-","28 Apr 2026","-","27 Apr 2026","-","26 Apr 2026","Day Not Applicable for Calculation","25 Apr 2026","Day Not Applicable for Calculation","24 Apr 2026","Day Not Applicable for Calculation","5","6","6","7","6","3","3","-","-","-","2","0","0","0","0","0","0","0","-","-","-","0","5","4","7","-","-","N/A","N/A","N/A","N/A","N/A","N/A"
"77242113UCO3001","Adolescent","Czech Republic","DD5-CZ10020","Lucie Gonsorcikova","CZ100201001","1","I-0","18 May 2026","Yes","01 May 2026","01 May 2026","01 May 2026","-","-","2","-","3","17 May 2026","-","16 May 2026","-","15 May 2026","-","14 May 2026","-","13 May 2026","-","12 May 2026","-","11 May 2026","-","10 May 2026","Day Not Applicable for Calculation","09 May 2026","Day Not Applicable for Calculation","08 May 2026","Day Not Applicable for Calculation","6","6","6","6","6","6","6","-","-","-","3","0","0","0","0","0","0","0","-","-","-","0","6","5","8","-","18 May 2026 08:38:55","N/A","N/A","N/A","N/A","N/A","N/A"
"77242113UCO3001","Adult","Czech Republic","DD5-CZ10021","Martin Bortlik","CZ100212001","1","I-0","07 Apr 2026","Yes","16 Mar 2026","15 Mar 2026","16 Mar 2026","-","-","3","-","3","06 Apr 2026","-","05 Apr 2026","-","04 Apr 2026","-","03 Apr 2026","-","02 Apr 2026","-","01 Apr 2026","-","31 Mar 2026","-","30 Mar 2026","Day Not Applicable for Calculation","29 Mar 2026","Day Not Applicable for Calculation","28 Mar 2026","Day Not Applicable for Calculation","11","11","10","11","11","10","9","-","-","-","3","2","2","2","2","2","2","2","-","-","-","2","8","8","11","-","20 Apr 2026 09:27:58","N/A","N/A","N/A","N/A","N/A","N/A"
"77242113UCO3001","Adult","Czech Republic","DD5-CZ10021","Martin Bortlik","CZ100212001","1","I-2","20 Apr 2026","-","-","-","-","-","-","-","-","3","19 Apr 2026","-","18 Apr 2026","-","17 Apr 2026","-","16 Apr 2026","-","15 Apr 2026","-","14 Apr 2026","-","13 Apr 2026","-","12 Apr 2026","Day Not Applicable for Calculation","11 Apr 2026","Day Not Applicable for Calculation","10 Apr 2026","Day Not Applicable for Calculation","8","7","9","8","8","7","8","-","-","-","3","2","2","1","1","1","2","1","-","-","-","1","7","","","-","20 Apr 2026 09:29:01","N/A","N/A","N/A","N/A","N/A","N/A"
"77242113UCO3001","Adult","Czech Republic","DD5-CZ10021","Martin Bortlik","CZ100212001","1","I-4","05 May 2026","-","-","-","-","-","-","-","-","1","04 May 2026","-","03 May 2026","-","02 May 2026","-","01 May 2026","-","30 Apr 2026","-","29 Apr 2026","-","28 Apr 2026","-","27 Apr 2026","Day Not Applicable for Calculation","26 Apr 2026","Day Not Applicable for Calculation","25 Apr 2026","Day Not Applicable for Calculation","6","6","6","6","7","7","6","-","-","-","3","0","0","1","1","1","1","1","-","-","-","1","5","","","-","-","N/A","N/A","N/A","N/A","N/A","N/A"
"77242113UCO3001","Adult","Czech Republic","DD5-CZ10022","Petr Hrabak","CZ100222002","1","I-0","19 Feb 2026","Yes","11 Feb 2026","10 Feb 2026","11 Feb 2026","-","-","2","-","2","18 Feb 2026","-","17 Feb 2026","-","16 Feb 2026","-","15 Feb 2026","-","14 Feb 2026","-","13 Feb 2026","-","12 Feb 2026","-","11 Feb 2026","Endoscopy;Bowel Preparation for Procedure;Day Not Applicable for Calculation","10 Feb 2026","Bowel Preparation for Procedure;Day Not Applicable for Calculation","09 Feb 2026","Day Not Applicable for Calculation","3","2","2","3","4","3","2","-","-","-","1","1","1","0","0","0","2","2","-","-","-","1","4","4","6","-","19 Feb 2026 15:41:35","N/A","N/A","N/A","N/A","N/A","N/A"
"77242113UCO3001","Adult","Czech Republic","DD5-CZ10022","Petr Hrabak","CZ100222003","1","I-0","09 Mar 2026","Yes","11 Feb 2026","10 Feb 2026","11 Feb 2026","-","-","2","-","2","08 Mar 2026","-","07 Mar 2026","-","06 Mar 2026","-","05 Mar 2026","-","04 Mar 2026","-","03 Mar 2026","Missing Diary","02 Mar 2026","Missing Diary","01 Mar 2026","Missing Diary;Day Not Applicable for Calculation","28 Feb 2026","Missing Diary;Day Not Applicable for Calculation","27 Feb 2026","Missing Diary;Day Not Applicable for Calculation","7","7","6","6","7","-","-","-","-","-","3","2","2","2","2","2","-","-","-","-","-","2","7","7","9","-","22 Mar 2026 18:34:58","N/A","N/A","N/A","N/A","N/A","N/A"
"77242113UCO3001","Adult","Czech Republic","DD5-CZ10022","Petr Hrabak","CZ100222003","1","I-2","27 Mar 2026","-","-","-","-","-","-","-","-","2","26 Mar 2026","-","25 Mar 2026","-","24 Mar 2026","-","23 Mar 2026","-","22 Mar 2026","-","21 Mar 2026","-","20 Mar 2026","-","19 Mar 2026","Day Not Applicable for Calculation","18 Mar 2026","Day Not Applicable for Calculation","17 Mar 2026","Day Not Applicable for Calculation","7","3","3","3","5","5","5","-","-","-","2","0","0","1","1","1","1","2","-","-","-","1","5","","","-","27 Mar 2026 07:22:31","N/A","N/A","N/A","N/A","N/A","N/A"
"77242113UCO3001","Adult","Czech Republic","DD5-CZ10022","Petr Hrabak","CZ100222003","1","I-4","08 Apr 2026","-","-","-","-","-","-","-","-","2","07 Apr 2026","-","06 Apr 2026","-","05 Apr 2026","-","04 Apr 2026","-","03 Apr 2026","-","02 Apr 2026","-","01 Apr 2026","-","31 Mar 2026","Day Not Applicable for Calculation","30 Mar 2026","Day Not Applicable for Calculation","29 Mar 2026","Day Not Applicable for Calculation","3","3","4","4","5","4","3","-","-","-","2","1","0","0","2","1","1","2","-","-","-","1","5","","","-","08 Apr 2026 07:59:35","N/A","N/A","N/A","N/A","N/A","N/A"
"77242113UCO3001","Adult","Czech Republic","DD5-CZ10022","Petr Hrabak","CZ100222003","1","I-8","04 May 2026","-","-","-","-","-","-","-","-","2","03 May 2026","-","02 May 2026","-","01 May 2026","-","30 Apr 2026","-","29 Apr 2026","-","28 Apr 2026","-","27 Apr 2026","-","26 Apr 2026","Day Not Applicable for Calculation","25 Apr 2026","Day Not Applicable for Calculation","24 Apr 2026","Missing Diary;Day Not Applicable for Calculation","3","5","3","3","3","2","3","-","-","-","1","0","0","0","0","0","0","0","-","-","-","0","3","","","-","04 May 2026 07:52:47","N/A","N/A","N/A","N/A","N/A","N/A"
"77242113UCO3001","Adult","Czech Republic","DD5-CZ10022","Petr Hrabak","CZ100222005","1","I-0","09 Apr 2026","Yes","08 Apr 2026","31 Mar 2026","01 Apr 2026","-","-","2","-","2","08 Apr 2026","Endoscopy","07 Apr 2026","-","06 Apr 2026","-","05 Apr 2026","-","04 Apr 2026","-","03 Apr 2026","-","02 Apr 2026","-","01 Apr 2026","Bowel Preparation for Procedure;Day Not Applicable for Calculation","31 Mar 2026","Bowel Preparation for Procedure;Day Not Applicable for Calculation","30 Mar 2026","-","-","3","3","4","3","4","3","-","-","3","1","-","2","2","2","2","2","2","-","-","2","2","5","5","7","-","-","N/A","N/A","N/A","N/A","N/A","N/A"
"77242113UCO3001","Adult","Czech Republic","DD5-CZ10022","Petr Hrabak","CZ100222005","1","I-2","22 Apr 2026","-","-","-","-","-","-","-","-","2","21 Apr 2026","-","20 Apr 2026","-","19 Apr 2026","-","18 Apr 2026","-","17 Apr 2026","-","16 Apr 2026","-","15 Apr 2026","-","14 Apr 2026","Day Not Applicable for Calculation","13 Apr 2026","Day Not Applicable for Calculation","12 Apr 2026","Day Not Applicable for Calculation","3","3","5","3","2","3","2","-","-","-","1","1","2","2","1","1","1","2","-","-","-","1","4","","","-","05 May 2026 07:29:35","N/A","N/A","N/A","N/A","N/A","N/A"
"77242113UCO3001","Adult","Czech Republic","DD5-CZ10022","Petr Hrabak","CZ100222005","1","I-4","05 May 2026","-","-","-","-","-","-","-","-","2","04 May 2026","-","03 May 2026","-","02 May 2026","-","01 May 2026","-","30 Apr 2026","-","29 Apr 2026","-","28 Apr 2026","-","27 Apr 2026","Day Not Applicable for Calculation","26 Apr 2026","Day Not Applicable for Calculation","25 Apr 2026","Day Not Applicable for Calculation","4","2","2","2","2","2","2","-","-","-","1","1","1","1","1","2","1","1","-","-","-","1","4","","","-","05 May 2026 07:28:55","N/A","N/A","N/A","N/A","N/A","N/A"
1 Protocol Study Population Country Site Principal Investigator Participant ID Baseline Stool Frequency Visit Visit Date Endoscopy Completed? Endoscopy Date Bowel Preparation Start Date 1 Bowel Preparation End Date 1 Bowel Preparation Start Date 2 Bowel Preparation End Date 2 Central Endoscopy Score Local Endoscopy Score PGA Score Eligible Day (-1) Day (-1) Excluded Reason(s) Eligible Day (-2) Day (-2) Excluded Reason(s) Eligible Day (-3) Day (-3) Excluded Reason(s) Eligible Day (-4) Day (-4) Excluded Reason(s) Eligible Day (-5) Day (-5) Excluded Reason(s) Eligible Day (-6) Day (-6) Excluded Reason(s) Eligible Day (-7) Day (-7) Excluded Reason(s) Eligible Day (-8) Day (-8) Excluded Reason(s) Eligible Day (-9) Day (-9) Excluded Reason(s) Eligible Day (-10) Day (-10) Excluded Reason(s) Eligible Day (-1) Stool Count Eligible Day (-2) Stool Count Eligible Day (-3) Stool Count Eligible Day (-4) Stool Count Eligible Day (-5) Stool Count Eligible Day (-6) Stool Count Eligible Day (-7) Stool Count Eligible Day (-8) Stool Count Eligible Day (-9) Stool Count Eligible Day (-10) Stool Count Stool Frequency Sub-score Eligible Day (-1) Rectal Bleeding Score Eligible Day (-2) Rectal Bleeding Score Eligible Day (-3) Rectal Bleeding Score Eligible Day (-4) Rectal Bleeding Score Eligible Day (-5) Rectal Bleeding Score Eligible Day (-6) Rectal Bleeding Score Eligible Day (-7) Rectal Bleeding Score Eligible Day (-8) Rectal Bleeding Score Eligible Day (-9) Rectal Bleeding Score Eligible Day (-10) Rectal Bleeding Score Rectal Bleeding Sub-score Partial Mayo Score Modified Mayo Score Full Mayo Score Site Action Last Mayo Score Submission Week I-12 Clinical Responder Week I-12 Clinical Remission Clinical Flare Loss of Response Partial Mayo Response Post Loss of Response Partial Mayo Response for Clinical Non-Responders
2 77242113UCO3001 Adult Czech Republic DD5-CZ10001 Matej Falc CZ100012001 1 I-0 19 Feb 2026 Yes 05 Feb 2026 04 Feb 2026 04 Feb 2026 - - 2 - 3 18 Feb 2026 - 17 Feb 2026 - 16 Feb 2026 - 15 Feb 2026 - 14 Feb 2026 - 13 Feb 2026 - 12 Feb 2026 - 11 Feb 2026 Day Not Applicable for Calculation 10 Feb 2026 Day Not Applicable for Calculation 09 Feb 2026 Day Not Applicable for Calculation 10 8 7 5 7 8 8 - - - 3 1 1 1 0 1 1 1 - - - 1 7 6 9 - 08 Apr 2026 07:11:25 N/A N/A N/A N/A N/A N/A
3 77242113UCO3001 Adult Czech Republic DD5-CZ10001 Matej Falc CZ100012001 1 I-2 04 Mar 2026 - - - - - - - - 3 03 Mar 2026 - 02 Mar 2026 - 01 Mar 2026 - 28 Feb 2026 - 27 Feb 2026 - 26 Feb 2026 - 25 Feb 2026 - 24 Feb 2026 Day Not Applicable for Calculation 23 Feb 2026 Day Not Applicable for Calculation 22 Feb 2026 Day Not Applicable for Calculation 5 4 5 4 5 6 6 - - - 2 1 0 1 0 1 0 1 - - - 1 6 - - N/A N/A N/A N/A N/A N/A
4 77242113UCO3001 Adult Czech Republic DD5-CZ10001 Matej Falc CZ100012001 1 I-4 18 Mar 2026 - - - - - - - - 2 17 Mar 2026 - 16 Mar 2026 - 15 Mar 2026 - 14 Mar 2026 - 13 Mar 2026 - 12 Mar 2026 - 11 Mar 2026 - 10 Mar 2026 Day Not Applicable for Calculation 09 Mar 2026 Day Not Applicable for Calculation 08 Mar 2026 Day Not Applicable for Calculation 5 5 5 4 5 4 5 - - - 2 1 0 0 1 1 1 0 - - - 1 5 - 08 Apr 2026 11:04:49 N/A N/A N/A N/A N/A N/A
5 77242113UCO3001 Adult Czech Republic DD5-CZ10001 Matej Falc CZ100012001 1 I-8 05 May 2026 - - - - - - - - 1 04 May 2026 - 03 May 2026 - 02 May 2026 - 01 May 2026 - 30 Apr 2026 - 29 Apr 2026 - 28 Apr 2026 - 27 Apr 2026 Day Not Applicable for Calculation 26 Apr 2026 Day Not Applicable for Calculation 25 Apr 2026 Day Not Applicable for Calculation 3 3 4 4 5 4 4 - - - 2 1 1 1 1 1 1 1 - - - 1 4 - - N/A N/A N/A N/A N/A N/A
6 77242113UCO3001 Adult Czech Republic DD5-CZ10001 Matej Falc CZ100012001 1 I-12 13 May 2026 Yes 06 May 2026 05 May 2026 05 May 2026 - - 1 - 1 12 May 2026 - 11 May 2026 - 10 May 2026 - 09 May 2026 - 08 May 2026 - 07 May 2026 - 06 May 2026 Endoscopy 05 May 2026 Bowel Preparation for Procedure;Day Not Applicable for Calculation 04 May 2026 - 03 May 2026 Day Not Applicable for Calculation 5 4 6 5 5 5 - - 3 - 2 1 0 1 1 1 1 - - 1 - 1 4 4 5 - - Clinical Responder No N/A N/A N/A N/A
7 77242113UCO3001 Adult Czech Republic DD5-CZ10001 Matej Falc CZ100012002 1 I-0 08 Apr 2026 Yes 18 Mar 2026 17 Mar 2026 18 Mar 2026 - - 2 - 2 07 Apr 2026 - 06 Apr 2026 - 05 Apr 2026 - 04 Apr 2026 Missing Diary 03 Apr 2026 - 02 Apr 2026 - 01 Apr 2026 - 31 Mar 2026 Day Not Applicable for Calculation 30 Mar 2026 Day Not Applicable for Calculation 29 Mar 2026 Day Not Applicable for Calculation 3 3 4 - 3 3 4 - - - 1 0 0 0 - 0 0 1 - - - 0 3 3 5 - - N/A N/A N/A N/A N/A N/A
8 77242113UCO3001 Adult Czech Republic DD5-CZ10001 Matej Falc CZ100012002 1 I-2 23 Apr 2026 - - - - - - - - 2 22 Apr 2026 Missing Diary 21 Apr 2026 - 20 Apr 2026 - 19 Apr 2026 - 18 Apr 2026 - 17 Apr 2026 - 16 Apr 2026 - 15 Apr 2026 Day Not Applicable for Calculation 14 Apr 2026 Day Not Applicable for Calculation 13 Apr 2026 Day Not Applicable for Calculation - 3 3 6 5 5 4 - - - 2 - 0 0 1 1 1 1 - - - 1 5 - - N/A N/A N/A N/A N/A N/A
9 77242113UCO3001 Adult Czech Republic DD5-CZ10001 Matej Falc CZ100012002 1 I-4 06 May 2026 - - - - - - - - 1 05 May 2026 - 04 May 2026 - 03 May 2026 - 02 May 2026 - 01 May 2026 - 30 Apr 2026 - 29 Apr 2026 - 28 Apr 2026 Day Not Applicable for Calculation 27 Apr 2026 Day Not Applicable for Calculation 26 Apr 2026 Day Not Applicable for Calculation 6 3 2 3 3 3 3 - - - 1 1 0 0 0 1 1 0 - - - 0 2 - - N/A N/A N/A N/A N/A N/A
10 77242113UCO3001 Adult Czech Republic DD5-CZ10001 Matej Falc CZ100012003 1 I-0 27 May 2026 Yes 13 May 2026 12 May 2026 12 May 2026 - - 3 - 2 26 May 2026 - 25 May 2026 - 24 May 2026 - 23 May 2026 - 22 May 2026 - 21 May 2026 - 20 May 2026 - 19 May 2026 Day Not Applicable for Calculation 18 May 2026 Day Not Applicable for Calculation 17 May 2026 Day Not Applicable for Calculation 6 9 7 8 9 7 8 - - - 3 2 2 2 2 1 1 1 - - - 2 7 8 10 - 27 May 2026 07:24:39 N/A N/A N/A N/A N/A N/A
11 77242113UCO3001 Adult Czech Republic DD5-CZ10006 Michal Konecny CZ100062001 1 I-0 20 Mar 2026 Yes 19 Feb 2026 - - - - 3 - 3 19 Mar 2026 - 18 Mar 2026 - 17 Mar 2026 - 16 Mar 2026 - 15 Mar 2026 - 14 Mar 2026 - 13 Mar 2026 - 12 Mar 2026 Day Not Applicable for Calculation 11 Mar 2026 Day Not Applicable for Calculation 10 Mar 2026 Day Not Applicable for Calculation 7 7 8 8 7 8 5 - - - 3 2 1 1 1 1 1 0 - - - 1 7 7 10 - 20 Mar 2026 07:03:23 N/A N/A N/A N/A N/A N/A
12 77242113UCO3001 Adult Czech Republic DD5-CZ10006 Michal Konecny CZ100062001 1 I-2 08 Apr 2026 - - - - - - - - 2 07 Apr 2026 Medication For Diarrhea 06 Apr 2026 Medication For Diarrhea 05 Apr 2026 Medication For Diarrhea 04 Apr 2026 Medication For Diarrhea 03 Apr 2026 Medication For Diarrhea 02 Apr 2026 Medication For Diarrhea 01 Apr 2026 Medication For Diarrhea 31 Mar 2026 Medication For Diarrhea;Day Not Applicable for Calculation 30 Mar 2026 Medication For Diarrhea;Day Not Applicable for Calculation 29 Mar 2026 Day Not Applicable for Calculation - - - - - - - - - - Non-Evaluable - - - - - - - - - - Non-Evaluable Non-Evaluable Non-Evaluable Non-Evaluable - - N/A N/A N/A N/A N/A N/A
13 77242113UCO3001 Adult Czech Republic DD5-CZ10006 Michal Konecny CZ100062001 1 I-4 15 Apr 2026 - - - - - - - - 3 14 Apr 2026 - 13 Apr 2026 - 12 Apr 2026 - 11 Apr 2026 - 10 Apr 2026 - 09 Apr 2026 - 08 Apr 2026 - 07 Apr 2026 Medication For Diarrhea;Day Not Applicable for Calculation 06 Apr 2026 Medication For Diarrhea;Day Not Applicable for Calculation 05 Apr 2026 Medication For Diarrhea;Day Not Applicable for Calculation 9 22 20 19 17 18 18 - - - 3 1 3 2 2 2 2 2 - - - 2 8 - 04 May 2026 22:06:03 N/A N/A N/A N/A N/A N/A
14 77242113UCO3001 Adult Czech Republic DD5-CZ10006 Michal Konecny CZ100062001 1 I-8 18 May 2026 - - - - - - - - 2 17 May 2026 - 16 May 2026 - 15 May 2026 - 14 May 2026 - 13 May 2026 - 12 May 2026 - 11 May 2026 - 10 May 2026 Day Not Applicable for Calculation 09 May 2026 Day Not Applicable for Calculation 08 May 2026 Day Not Applicable for Calculation 7 5 9 7 7 8 8 - - - 3 1 1 1 1 1 1 1 - - - 1 6 - - N/A N/A N/A N/A N/A N/A
15 77242113UCO3001 Adult Czech Republic DD5-CZ10006 Michal Konecny CZ100062002 1 I-0 26 May 2026 Yes 14 May 2026 13 May 2026 13 May 2026 - - 2 - 2 25 May 2026 - 24 May 2026 - 23 May 2026 - 22 May 2026 - 21 May 2026 - 20 May 2026 - 19 May 2026 - 18 May 2026 Day Not Applicable for Calculation 17 May 2026 Day Not Applicable for Calculation 16 May 2026 Day Not Applicable for Calculation 8 8 6 7 7 6 7 - - - 3 2 2 2 2 2 2 2 - - - 2 7 7 9 - - N/A N/A N/A N/A N/A N/A
16 77242113UCO3001 Adult Czech Republic DD5-CZ10009 Jiri Pumprla CZ100092001 1 I-0 05 May 2026 Yes 24 Apr 2026 23 Apr 2026 23 Apr 2026 - - 2 - 2 04 May 2026 - 03 May 2026 - 02 May 2026 - 01 May 2026 - 30 Apr 2026 - 29 Apr 2026 - 28 Apr 2026 - 27 Apr 2026 Day Not Applicable for Calculation 26 Apr 2026 Day Not Applicable for Calculation 25 Apr 2026 Day Not Applicable for Calculation 5 5 5 5 5 5 5 - - - 2 1 1 1 1 1 1 1 - - - 1 5 5 7 - 05 May 2026 11:19:40 N/A N/A N/A N/A N/A N/A
17 77242113UCO3001 Adult Czech Republic DD5-CZ10009 Jiri Pumprla CZ100092001 1 I-2 19 May 2026 - - - - - - - - 1 18 May 2026 - 17 May 2026 - 16 May 2026 - 15 May 2026 - 14 May 2026 - 13 May 2026 - 12 May 2026 - 11 May 2026 Day Not Applicable for Calculation 10 May 2026 Day Not Applicable for Calculation 09 May 2026 Day Not Applicable for Calculation 5 4 5 5 5 4 6 - - - 2 1 1 1 1 1 1 1 - - - 1 4 - 19 May 2026 10:38:25 N/A N/A N/A N/A N/A N/A
18 77242113UCO3001 Adult Czech Republic DD5-CZ10012 Stefan Konecny CZ100122001 5 I-0 07 Apr 2026 Yes 24 Mar 2026 22 Mar 2026 22 Mar 2026 - - 2 - 2 06 Apr 2026 - 05 Apr 2026 - 04 Apr 2026 - 03 Apr 2026 - 02 Apr 2026 - 01 Apr 2026 - 31 Mar 2026 - 30 Mar 2026 Day Not Applicable for Calculation 29 Mar 2026 Day Not Applicable for Calculation 28 Mar 2026 Day Not Applicable for Calculation 8 11 5 9 11 10 13 - - - 3 1 2 2 2 2 2 2 - - - 2 7 7 9 - 04 May 2026 08:44:52 N/A N/A N/A N/A N/A N/A
19 77242113UCO3001 Adult Czech Republic DD5-CZ10012 Stefan Konecny CZ100122001 5 I-2 22 Apr 2026 - - - - - - - - 2 21 Apr 2026 - 20 Apr 2026 - 19 Apr 2026 - 18 Apr 2026 - 17 Apr 2026 - 16 Apr 2026 - 15 Apr 2026 - 14 Apr 2026 Day Not Applicable for Calculation 13 Apr 2026 Day Not Applicable for Calculation 12 Apr 2026 Day Not Applicable for Calculation 7 5 6 6 7 8 2 - - - 1 1 0 1 1 1 2 0 - - - 1 4 - 04 May 2026 08:45:07 N/A N/A N/A N/A N/A N/A
20 77242113UCO3001 Adult Czech Republic DD5-CZ10012 Stefan Konecny CZ100122001 5 I-4 07 May 2026 - - - - - - - - 1 06 May 2026 - 05 May 2026 - 04 May 2026 - 03 May 2026 - 02 May 2026 - 01 May 2026 - 30 Apr 2026 - 29 Apr 2026 Day Not Applicable for Calculation 28 Apr 2026 Day Not Applicable for Calculation 27 Apr 2026 Day Not Applicable for Calculation 8 7 7 8 4 11 7 - - - 1 2 1 1 1 0 1 1 - - - 1 3 - - N/A N/A N/A N/A N/A N/A
21 77242113UCO3001 Adult Czech Republic DD5-CZ10013 David Stepek CZ100132001 1 I-0 24 Mar 2026 Yes 12 Mar 2026 11 Mar 2026 11 Mar 2026 - - 2 - 2 23 Mar 2026 - 22 Mar 2026 - 21 Mar 2026 - 20 Mar 2026 - 19 Mar 2026 - 18 Mar 2026 - 17 Mar 2026 - 16 Mar 2026 Day Not Applicable for Calculation 15 Mar 2026 Day Not Applicable for Calculation 14 Mar 2026 Day Not Applicable for Calculation 8 6 5 7 6 7 6 - - - 3 1 1 1 0 1 1 1 - - - 1 6 6 8 - 05 Apr 2026 22:41:27 N/A N/A N/A N/A N/A N/A
22 77242113UCO3001 Adult Czech Republic DD5-CZ10013 David Stepek CZ100132001 1 I-2 08 Apr 2026 - - - - - - - - 2 07 Apr 2026 - 06 Apr 2026 - 05 Apr 2026 - 04 Apr 2026 - 03 Apr 2026 - 02 Apr 2026 - 01 Apr 2026 - 31 Mar 2026 Day Not Applicable for Calculation 30 Mar 2026 Day Not Applicable for Calculation 29 Mar 2026 Day Not Applicable for Calculation 5 2 3 6 5 5 5 - - - 2 0 0 0 0 1 1 0 - - - 0 4 - 27 May 2026 12:53:52 N/A N/A N/A N/A N/A N/A
23 77242113UCO3001 Adult Czech Republic DD5-CZ10013 David Stepek CZ100132001 1 I-4 21 Apr 2026 - - - - - - - - 0 20 Apr 2026 - 19 Apr 2026 - 18 Apr 2026 - 17 Apr 2026 - 16 Apr 2026 - 15 Apr 2026 - 14 Apr 2026 - 13 Apr 2026 Day Not Applicable for Calculation 12 Apr 2026 Day Not Applicable for Calculation 11 Apr 2026 Day Not Applicable for Calculation 4 3 4 3 3 4 4 - - - 2 0 0 0 0 0 0 0 - - - 0 2 - 27 May 2026 12:54:41 N/A N/A N/A N/A N/A N/A
24 77242113UCO3001 Adult Czech Republic DD5-CZ10013 David Stepek CZ100132002 1 I-0 12 May 2026 Yes 21 Apr 2026 20 Apr 2026 21 Apr 2026 - - 2 - 2 11 May 2026 - 10 May 2026 - 09 May 2026 - 08 May 2026 - 07 May 2026 - 06 May 2026 - 05 May 2026 Missing Diary 04 May 2026 Day Not Applicable for Calculation 03 May 2026 Day Not Applicable for Calculation 02 May 2026 Day Not Applicable for Calculation 2 1 1 1 1 2 - - - - 0 0 0 0 0 0 0 - - - - 0 2 2 4 - - N/A N/A N/A N/A N/A N/A
25 77242113UCO3001 Adult Czech Republic DD5-CZ10013 David Stepek CZ100132002 1 I-2 26 May 2026 - - - - - - - - 1 25 May 2026 - 24 May 2026 Missing Diary 23 May 2026 - 22 May 2026 - 21 May 2026 - 20 May 2026 - 19 May 2026 - 18 May 2026 Missing Diary;Day Not Applicable for Calculation 17 May 2026 Day Not Applicable for Calculation 16 May 2026 Day Not Applicable for Calculation 1 - 1 2 1 2 2 - - - 1 0 - 0 0 0 0 0 - - - 0 2 - - N/A N/A N/A N/A N/A N/A
26 77242113UCO3001 Adolescent Czech Republic DD5-CZ10020 Lucie Gonsorcikova CZ100201001 1 Unscheduled 1 04 May 2026 Yes 20 Apr 2026 12 Apr 2026 15 Apr 2026 - - 2 - 3 03 May 2026 - 02 May 2026 - 01 May 2026 - 30 Apr 2026 - 29 Apr 2026 - 28 Apr 2026 - 27 Apr 2026 - 26 Apr 2026 Day Not Applicable for Calculation 25 Apr 2026 Day Not Applicable for Calculation 24 Apr 2026 Day Not Applicable for Calculation 5 6 6 7 6 3 3 - - - 2 0 0 0 0 0 0 0 - - - 0 5 4 7 - - N/A N/A N/A N/A N/A N/A
27 77242113UCO3001 Adolescent Czech Republic DD5-CZ10020 Lucie Gonsorcikova CZ100201001 1 I-0 18 May 2026 Yes 01 May 2026 01 May 2026 01 May 2026 - - 2 - 3 17 May 2026 - 16 May 2026 - 15 May 2026 - 14 May 2026 - 13 May 2026 - 12 May 2026 - 11 May 2026 - 10 May 2026 Day Not Applicable for Calculation 09 May 2026 Day Not Applicable for Calculation 08 May 2026 Day Not Applicable for Calculation 6 6 6 6 6 6 6 - - - 3 0 0 0 0 0 0 0 - - - 0 6 5 8 - 18 May 2026 08:38:55 N/A N/A N/A N/A N/A N/A
28 77242113UCO3001 Adult Czech Republic DD5-CZ10021 Martin Bortlik CZ100212001 1 I-0 07 Apr 2026 Yes 16 Mar 2026 15 Mar 2026 16 Mar 2026 - - 3 - 3 06 Apr 2026 - 05 Apr 2026 - 04 Apr 2026 - 03 Apr 2026 - 02 Apr 2026 - 01 Apr 2026 - 31 Mar 2026 - 30 Mar 2026 Day Not Applicable for Calculation 29 Mar 2026 Day Not Applicable for Calculation 28 Mar 2026 Day Not Applicable for Calculation 11 11 10 11 11 10 9 - - - 3 2 2 2 2 2 2 2 - - - 2 8 8 11 - 20 Apr 2026 09:27:58 N/A N/A N/A N/A N/A N/A
29 77242113UCO3001 Adult Czech Republic DD5-CZ10021 Martin Bortlik CZ100212001 1 I-2 20 Apr 2026 - - - - - - - - 3 19 Apr 2026 - 18 Apr 2026 - 17 Apr 2026 - 16 Apr 2026 - 15 Apr 2026 - 14 Apr 2026 - 13 Apr 2026 - 12 Apr 2026 Day Not Applicable for Calculation 11 Apr 2026 Day Not Applicable for Calculation 10 Apr 2026 Day Not Applicable for Calculation 8 7 9 8 8 7 8 - - - 3 2 2 1 1 1 2 1 - - - 1 7 - 20 Apr 2026 09:29:01 N/A N/A N/A N/A N/A N/A
30 77242113UCO3001 Adult Czech Republic DD5-CZ10021 Martin Bortlik CZ100212001 1 I-4 05 May 2026 - - - - - - - - 1 04 May 2026 - 03 May 2026 - 02 May 2026 - 01 May 2026 - 30 Apr 2026 - 29 Apr 2026 - 28 Apr 2026 - 27 Apr 2026 Day Not Applicable for Calculation 26 Apr 2026 Day Not Applicable for Calculation 25 Apr 2026 Day Not Applicable for Calculation 6 6 6 6 7 7 6 - - - 3 0 0 1 1 1 1 1 - - - 1 5 - - N/A N/A N/A N/A N/A N/A
31 77242113UCO3001 Adult Czech Republic DD5-CZ10022 Petr Hrabak CZ100222002 1 I-0 19 Feb 2026 Yes 11 Feb 2026 10 Feb 2026 11 Feb 2026 - - 2 - 2 18 Feb 2026 - 17 Feb 2026 - 16 Feb 2026 - 15 Feb 2026 - 14 Feb 2026 - 13 Feb 2026 - 12 Feb 2026 - 11 Feb 2026 Endoscopy;Bowel Preparation for Procedure;Day Not Applicable for Calculation 10 Feb 2026 Bowel Preparation for Procedure;Day Not Applicable for Calculation 09 Feb 2026 Day Not Applicable for Calculation 3 2 2 3 4 3 2 - - - 1 1 1 0 0 0 2 2 - - - 1 4 4 6 - 19 Feb 2026 15:41:35 N/A N/A N/A N/A N/A N/A
32 77242113UCO3001 Adult Czech Republic DD5-CZ10022 Petr Hrabak CZ100222003 1 I-0 09 Mar 2026 Yes 11 Feb 2026 10 Feb 2026 11 Feb 2026 - - 2 - 2 08 Mar 2026 - 07 Mar 2026 - 06 Mar 2026 - 05 Mar 2026 - 04 Mar 2026 - 03 Mar 2026 Missing Diary 02 Mar 2026 Missing Diary 01 Mar 2026 Missing Diary;Day Not Applicable for Calculation 28 Feb 2026 Missing Diary;Day Not Applicable for Calculation 27 Feb 2026 Missing Diary;Day Not Applicable for Calculation 7 7 6 6 7 - - - - - 3 2 2 2 2 2 - - - - - 2 7 7 9 - 22 Mar 2026 18:34:58 N/A N/A N/A N/A N/A N/A
33 77242113UCO3001 Adult Czech Republic DD5-CZ10022 Petr Hrabak CZ100222003 1 I-2 27 Mar 2026 - - - - - - - - 2 26 Mar 2026 - 25 Mar 2026 - 24 Mar 2026 - 23 Mar 2026 - 22 Mar 2026 - 21 Mar 2026 - 20 Mar 2026 - 19 Mar 2026 Day Not Applicable for Calculation 18 Mar 2026 Day Not Applicable for Calculation 17 Mar 2026 Day Not Applicable for Calculation 7 3 3 3 5 5 5 - - - 2 0 0 1 1 1 1 2 - - - 1 5 - 27 Mar 2026 07:22:31 N/A N/A N/A N/A N/A N/A
34 77242113UCO3001 Adult Czech Republic DD5-CZ10022 Petr Hrabak CZ100222003 1 I-4 08 Apr 2026 - - - - - - - - 2 07 Apr 2026 - 06 Apr 2026 - 05 Apr 2026 - 04 Apr 2026 - 03 Apr 2026 - 02 Apr 2026 - 01 Apr 2026 - 31 Mar 2026 Day Not Applicable for Calculation 30 Mar 2026 Day Not Applicable for Calculation 29 Mar 2026 Day Not Applicable for Calculation 3 3 4 4 5 4 3 - - - 2 1 0 0 2 1 1 2 - - - 1 5 - 08 Apr 2026 07:59:35 N/A N/A N/A N/A N/A N/A
35 77242113UCO3001 Adult Czech Republic DD5-CZ10022 Petr Hrabak CZ100222003 1 I-8 04 May 2026 - - - - - - - - 2 03 May 2026 - 02 May 2026 - 01 May 2026 - 30 Apr 2026 - 29 Apr 2026 - 28 Apr 2026 - 27 Apr 2026 - 26 Apr 2026 Day Not Applicable for Calculation 25 Apr 2026 Day Not Applicable for Calculation 24 Apr 2026 Missing Diary;Day Not Applicable for Calculation 3 5 3 3 3 2 3 - - - 1 0 0 0 0 0 0 0 - - - 0 3 - 04 May 2026 07:52:47 N/A N/A N/A N/A N/A N/A
36 77242113UCO3001 Adult Czech Republic DD5-CZ10022 Petr Hrabak CZ100222005 1 I-0 09 Apr 2026 Yes 08 Apr 2026 31 Mar 2026 01 Apr 2026 - - 2 - 2 08 Apr 2026 Endoscopy 07 Apr 2026 - 06 Apr 2026 - 05 Apr 2026 - 04 Apr 2026 - 03 Apr 2026 - 02 Apr 2026 - 01 Apr 2026 Bowel Preparation for Procedure;Day Not Applicable for Calculation 31 Mar 2026 Bowel Preparation for Procedure;Day Not Applicable for Calculation 30 Mar 2026 - - 3 3 4 3 4 3 - - 3 1 - 2 2 2 2 2 2 - - 2 2 5 5 7 - - N/A N/A N/A N/A N/A N/A
37 77242113UCO3001 Adult Czech Republic DD5-CZ10022 Petr Hrabak CZ100222005 1 I-2 22 Apr 2026 - - - - - - - - 2 21 Apr 2026 - 20 Apr 2026 - 19 Apr 2026 - 18 Apr 2026 - 17 Apr 2026 - 16 Apr 2026 - 15 Apr 2026 - 14 Apr 2026 Day Not Applicable for Calculation 13 Apr 2026 Day Not Applicable for Calculation 12 Apr 2026 Day Not Applicable for Calculation 3 3 5 3 2 3 2 - - - 1 1 2 2 1 1 1 2 - - - 1 4 - 05 May 2026 07:29:35 N/A N/A N/A N/A N/A N/A
38 77242113UCO3001 Adult Czech Republic DD5-CZ10022 Petr Hrabak CZ100222005 1 I-4 05 May 2026 - - - - - - - - 2 04 May 2026 - 03 May 2026 - 02 May 2026 - 01 May 2026 - 30 Apr 2026 - 29 Apr 2026 - 28 Apr 2026 - 27 Apr 2026 Day Not Applicable for Calculation 26 Apr 2026 Day Not Applicable for Calculation 25 Apr 2026 Day Not Applicable for Calculation 4 2 2 2 2 2 2 - - - 1 1 1 1 1 2 1 1 - - - 1 4 - 05 May 2026 07:28:55 N/A N/A N/A N/A N/A N/A
+111
View File
@@ -0,0 +1,111 @@
"""
EmailMessagingGraph.py
----------------------
Private Microsoft Graph mail sender
Application permissions, shared mailbox
"""
import base64
import msal
import requests
from functools import lru_cache
from pathlib import Path
from typing import Union, List
# =========================
# PRIVATE CONFIG (ONLY YOU)
# =========================
TENANT_ID = "7d269944-37a4-43a1-8140-c7517dc426e9"
CLIENT_ID = "4b222bfd-78c9-4239-a53f-43006b3ed07f"
CLIENT_SECRET = "Txg8Q~MjhocuopxsJyJBhPmDfMxZ2r5WpTFj1dfk"
SENDER = "reports@buzalka.cz"
AUTHORITY = f"https://login.microsoftonline.com/{TENANT_ID}"
SCOPE = ["https://graph.microsoft.com/.default"]
@lru_cache(maxsize=1)
def _get_token() -> str:
app = msal.ConfidentialClientApplication(
CLIENT_ID,
authority=AUTHORITY,
client_credential=CLIENT_SECRET,
)
token = app.acquire_token_for_client(scopes=SCOPE)
if "access_token" not in token:
raise RuntimeError(f"Graph auth failed: {token}")
return token["access_token"]
def send_mail(
to: Union[str, List[str]],
subject: str,
body: str = "",
*,
html: bool = False,
attachments: Union[str, Path, List[Union[str, Path]], None] = None,
):
"""
Send email via Microsoft Graph.
:param to: email or list of emails
:param subject: subject
:param body: email body (default empty)
:param html: True = HTML, False = plain text
:param attachments: file path or list of file paths to attach
"""
if isinstance(to, str):
to = [to]
if attachments is None:
attachments = []
elif isinstance(attachments, (str, Path)):
attachments = [attachments]
attachment_payloads = []
for path in attachments:
path = Path(path)
attachment_payloads.append({
"@odata.type": "#microsoft.graph.fileAttachment",
"name": path.name,
"contentType": "application/octet-stream",
"contentBytes": base64.b64encode(path.read_bytes()).decode(),
})
payload = {
"message": {
"subject": subject,
"body": {
"contentType": "HTML" if html else "Text",
"content": body,
},
"toRecipients": [
{"emailAddress": {"address": addr}} for addr in to
],
**({"attachments": attachment_payloads} if attachment_payloads else {}),
},
"saveToSentItems": "true",
}
headers = {
"Authorization": f"Bearer {_get_token()}",
"Content-Type": "application/json",
}
r = requests.post(
f"https://graph.microsoft.com/v1.0/users/{SENDER}/sendMail",
headers=headers,
json=payload,
timeout=30,
)
if r.status_code != 202:
raise RuntimeError(
f"sendMail failed [{r.status_code}]: {r.text}"
)
+62
View File
@@ -0,0 +1,62 @@
import winreg
import json
import os
def get_dropbox_root() -> str:
"""
Vrátí kořenovou cestu složky Dropbox na tomto počítači.
Dropbox může být nainstalován na různých discích (C:, U:, Z: …),
ale struktura složek uvnitř zůstává vždy stejná. Tato funkce zjistí
aktuální umístění, takže ostatní skripty nemusí cestu napevno zadávat.
Postup hledání (v tomto pořadí):
1. Registr HKCU\\Software\\Dropbox\\ks — hlavní klíč, hodnota "Personal"
je uložena jako byte array v kódování UTF-16 LE.
2. Registr HKCU\\Software\\Dropbox\\ks1 — alternativní klíč používaný
novějšími verzemi klienta Dropbox.
3. Soubor info.json v %APPDATA%\\Dropbox\\ nebo %LOCALAPPDATA%\\Dropbox\\
— záložní metoda, pokud registr cestu neobsahuje.
Vrací:
str: Absolutní cesta ke kořenové složce Dropboxu, např. "U:\\Dropbox".
Vyvolá:
RuntimeError: Pokud se cestu nepodaří zjistit žádnou z metod.
Příklad použití:
from Knihovny.najdi_dropbox import get_dropbox_root
import os
ROOT = get_dropbox_root()
PACIENTI = os.path.join(ROOT, "Ordinace", "Pacienti")
"""
# Metoda 1 a 2: registr HKCU\Software\Dropbox\ks a ks1
for subkey in (r"Software\Dropbox\ks", r"Software\Dropbox\ks1"):
try:
with winreg.OpenKey(winreg.HKEY_CURRENT_USER, subkey) as key:
value, _ = winreg.QueryValueEx(key, "Personal")
path = bytes(value).decode("utf-16-le").rstrip("\x00")
if path:
return path
except (OSError, UnicodeDecodeError):
continue
# Metoda 3: záložní — info.json v AppData
for base in (os.getenv("APPDATA", ""), os.getenv("LOCALAPPDATA", "")):
info_path = os.path.join(base, "Dropbox", "info.json")
if os.path.isfile(info_path):
with open(info_path, encoding="utf-8") as f:
info = json.load(f)
path = (info.get("personal") or info.get("business") or {}).get("path", "")
if path:
return path
raise RuntimeError("Nepodařilo se zjistit cestu k Dropboxu.")
if __name__ == "__main__":
root = get_dropbox_root()
print(f"Dropbox root: {root}")
@@ -1,3 +1,10 @@
"""
download_report.py
NAHRAZENO skriptem download_edc_datalistings.py
Původně: stahování Data Listing reportů pro studii MDD3003 (CZE).
"""
import os
import sys
from datetime import datetime, timedelta
@@ -1,8 +1,8 @@
"""
Stahuje Data Listing reporty (ReportID=92) pro studii UCO3001.
Použití:
download_datalisting_reports_3001("Trial Disposition (Completion / Discontinuation)")
download_datalisting_reports_3001("Trial Disposition (Completion / Discontinuation)", country="CZE")
download_uco3001.py
NAHRAZENO skriptem download_edc_datalistings.py
Původně: stahování Data Listing reportů (ReportID=92) pro studii UCO3001.
"""
import os
+1 -1
View File
File diff suppressed because one or more lines are too long
+472
View File
@@ -0,0 +1,472 @@
"""
download_edc_datalistings.py
Verze: 2.0
Datum: 2026-05-27
Univerzální stahování EDC Data Listing reportů (ReportID=92) z Medidata Rave.
Parametry:
study vyhledávací řetězec studie (např. "77242113UCO3001")
forms seznam názvů formulářů ke stažení
country kód země / site group (např. "CZE"), None = všechny
Prohlížeč se otevře jednou, přihlásí se, a stáhne všechny formuláře v jedné session.
Použití:
from download_edc import download_datalisting
download_datalisting(
study="77242113UCO3001",
forms=["Date of Visit", "Concomitant Therapy"],
country="CZE",
)
"""
import os
import re
import sys
from datetime import datetime, timedelta
from pathlib import Path
from dotenv import load_dotenv
from playwright.sync_api import sync_playwright, TimeoutError as PWTimeout
import tkinter as tk
from tkinter import simpledialog
load_dotenv(Path(__file__).parent / ".env")
USERNAME = os.getenv("IMEDIDATA_USERNAME", "vladimir.buzalka")
PASSWORD = os.getenv("IMEDIDATA_PASSWORD", "")
DOWNLOAD_DIR = Path(__file__).parent / "downloads"
AUTH_FILE = Path(__file__).parent / "auth.json"
AUTH_MAX_AGE_DAYS = 7
LOGIN_URL = "https://login.imedidata.com/login"
SELECT_ROLE_URL = (
"https://jnjja.mdsol.com/MedidataRave/SelectRole.aspx"
"?client_division_uuid=e5de55d5-a414-4bd1-9abe-18e96fd5475d"
"&study_group_uuid=b0793ca6-33ec-44e8-883b-6fc1a4b671c4"
"&studygroup_id=107981"
)
REPORT_ID = 92
# ---------------------------------------------------------------------------
# Helpers
# ---------------------------------------------------------------------------
def auth_valid():
if not AUTH_FILE.exists():
return False
age = datetime.now() - datetime.fromtimestamp(AUTH_FILE.stat().st_mtime)
return age < timedelta(days=AUTH_MAX_AGE_DAYS)
def wait_load(page, extra_ms=1000):
try:
page.wait_for_load_state("load", timeout=20_000)
except PWTimeout:
pass
page.wait_for_timeout(extra_ms)
def dbg(page, label):
print(f"[{label}] URL: {page.url}")
def extract_study_label(study_search: str) -> str:
match = re.search(r'[A-Z]+\d+$', study_search)
return match.group(0) if match else study_search
# ---------------------------------------------------------------------------
# Login
# ---------------------------------------------------------------------------
def _ask_otp_popup():
root = tk.Tk()
root.withdraw()
root.lift()
root.attributes("-topmost", True)
otp = simpledialog.askstring("OKTA MFA", "Zadej OTP kód z OKTA (6 číslic):", parent=root)
root.destroy()
return (otp or "").strip()
def do_login(page, context):
print("Přihlašuji se do iMedidata...")
page.goto(LOGIN_URL)
wait_load(page, 500)
page.wait_for_selector('input[name="session[username]"]', timeout=10_000)
page.fill('input[name="session[username]"]', USERNAME)
page.fill('input[name="session[password]"]', PASSWORD)
page.click('button[type="submit"]')
wait_load(page, 2000)
dbg(page, "after-signin")
if _okta_mfa_present(page):
print("\n*** OKTA MFA vyžadována! ***")
otp = _ask_otp_popup()
if not otp:
print("CHYBA: OTP nebylo zadáno.")
sys.exit(1)
_fill_otp(page, otp)
wait_load(page, 3000)
try:
page.wait_for_url("**/home.imedidata.com**", timeout=30_000)
except PWTimeout:
dbg(page, "wait-home-timeout")
if "home.imedidata.com" not in page.url:
print("CHYBA: Přihlášení se nezdařilo!")
sys.exit(1)
context.storage_state(path=str(AUTH_FILE))
print("Session uložena do auth.json")
def _okta_mfa_present(page):
if "okta" in page.url.lower():
return True
for sel in ['input[name="answer"]', 'input[name*="otp"]',
'input[name*="code"]', 'input[placeholder*="code" i]']:
if page.query_selector(sel):
return True
return False
def _fill_otp(page, otp):
for sel in ['input[name="answer"]', 'input[name*="otp"]',
'input[name*="code"]', 'input[type="tel"]', 'input[placeholder*="code" i]']:
el = page.query_selector(sel)
if el:
el.fill(otp)
page.keyboard.press("Enter")
return
page.keyboard.type(otp)
page.keyboard.press("Enter")
# ---------------------------------------------------------------------------
# Navigace
# ---------------------------------------------------------------------------
def go_to_select_role(page):
print("Navigace na SelectRole...")
try:
page.goto(SELECT_ROLE_URL)
except Exception:
pass
wait_load(page, 1500)
dbg(page, "select-role")
return "login" not in page.url.lower() and "okta" not in page.url.lower()
def select_role(page):
print("Vybírám roli Site Manager...")
try:
page.wait_for_selector("select", timeout=10_000)
except PWTimeout:
return
for sel_el in page.query_selector_all("select"):
for opt in sel_el.query_selector_all("option"):
txt = (opt.inner_text() or "").strip()
if "site manager" in txt.lower():
sel_el.select_option(label=txt)
print(f" Vybráno: '{txt}'")
break
for btn_sel in ['input[value="Continue"]', 'input[type="submit"]',
'button:has-text("Continue")', 'button[type="submit"]']:
try:
btn = page.query_selector(btn_sel)
except Exception:
break
if btn:
btn.click()
wait_load(page, 2000)
break
dbg(page, "after-role")
def navigate_to_reporter(page):
print("Klikám na Reporter...")
page.wait_for_selector('a:has-text("Reporter")', timeout=15_000)
page.click('a:has-text("Reporter")')
wait_load(page, 1500)
dbg(page, "reporter")
def open_report(page):
print(f"Otevírám report ID={REPORT_ID} (Data Listing - Data Stream)...")
selector = f'a[href="PromptsPage.aspx?ReportID={REPORT_ID}"]'
page.wait_for_selector(selector, timeout=15_000)
page.click(selector)
wait_load(page, 2000)
dbg(page, "report-opened")
# ---------------------------------------------------------------------------
# Parametry reportu
# ---------------------------------------------------------------------------
def set_study_param(page, study_search: str):
print(f" Parametr Study: hledám '{study_search}'...")
page.click('#PromptsBox_st_ShowHideBtn')
page.wait_for_timeout(1500)
page.wait_for_selector('input[id^="PromptsBox_st_FrontEndCBList_"]', timeout=10_000)
checkboxes = page.query_selector_all('input[id^="PromptsBox_st_FrontEndCBList_"]')
found = False
for cb in checkboxes:
cb_id = cb.get_attribute("id")
label_text = page.evaluate(
"""id => {
const el = document.getElementById(id);
if (!el) return '';
const row = el.closest('tr') || el.closest('td') || el.parentElement;
return row ? row.innerText : '';
}""",
cb_id
)
print(f" [{cb_id}] label: {label_text.strip()[:80]}")
if study_search.upper() in label_text.upper():
if not page.locator(f"#{cb_id}").is_checked():
page.locator(f"#{cb_id}").check()
print(f" Nalezeno a zaškrtnuto: '{label_text.strip()}'")
found = True
break
if not found:
print(f" VAROVÁNÍ: Studie '{study_search}' nenalezena! Zkouším index 0...")
cb0 = page.locator('#PromptsBox_st_FrontEndCBList_0')
if not cb0.is_checked():
cb0.check()
wait_load(page, 3000)
dbg(page, "after-study")
def set_site_group_param(page, country: str):
print(f" Parametr Site Group: {country}")
page.click('#PromptsBox_sg_ShowHideBtn')
page.wait_for_timeout(1500)
page.wait_for_selector('#PromptsBox_sg_List', timeout=10_000)
page.select_option('#PromptsBox_sg_List', label=country)
page.evaluate(
"document.querySelector('#PromptsBox_sg_List').dispatchEvent(new Event('change', {bubbles:true}))"
)
wait_load(page, 2000)
cb = page.locator('#PromptsBox_sg_CheckBox')
if not cb.is_checked():
cb.check()
page.evaluate(
"document.querySelector('#PromptsBox_sg_CheckBox').dispatchEvent(new Event('change', {bubbles:true}))"
)
wait_load(page, 2000)
page.click('#PromptsBox_sg_ShowHideBtn')
wait_load(page, 3000)
dbg(page, "after-site-group")
def set_form_param(page, form_name: str):
print(f" Parametr Form: {form_name}")
is_closed = page.locator('#PromptsBox_fm2_div').evaluate('el => el.style.display') == 'none'
if is_closed:
page.click('#PromptsBox_fm2_ShowHideBtn')
page.wait_for_timeout(2000)
if page.locator('#PromptsBox_fm2_PageModeBtn').is_visible():
page.click('#PromptsBox_fm2_PageModeBtn')
page.wait_for_timeout(1000)
page.click('#PromptsBox_fm2_PageModeBtn')
page.wait_for_timeout(2000)
search = page.locator('#PromptsBox_fm2_SearchTxt')
search.wait_for(state='visible', timeout=10_000)
search.click()
search.fill(form_name)
page.wait_for_timeout(2000)
search.press('Enter')
page.wait_for_timeout(2000)
cb_locator = page.locator('input[id^="PromptsBox_fm2_FrontEndCBList_"]').first
try:
cb_locator.wait_for(state='visible', timeout=8_000)
except PWTimeout:
print(f" VAROVÁNÍ: '{form_name}' nenalezen!")
return
if not cb_locator.is_checked():
cb_locator.click()
print(f" '{form_name}' zaškrtnuto")
page.wait_for_timeout(2000)
# ---------------------------------------------------------------------------
# Submit a download
# ---------------------------------------------------------------------------
def submit_and_download(page, context, form_name: str, country: str | None, study_label: str):
print("Odesílám report...")
with context.expect_page() as new_page_info:
page.locator('input[value="Submit Report"], button:has-text("Submit Report")').first.click()
new_page = new_page_info.value
new_page.wait_for_url(lambda url: url != 'about:blank', timeout=30_000)
print(" Čekám na vygenerování reportu (max 5 min)...")
new_page.wait_for_selector(
'input[value="Download File"], button:has-text("Download File")',
timeout=300_000
)
new_page.wait_for_timeout(500)
dbg(new_page, "download-window")
target_frame = new_page.main_frame
for frame in new_page.frames:
if frame.query_selector('select') or frame.query_selector('input[value="Download File"]'):
target_frame = frame
break
for sel in target_frame.query_selector_all('select'):
for opt in sel.query_selector_all('option'):
val = opt.get_attribute('value') or ''
if 'vnd.ms-excel' in val:
sel.select_option(value=val)
print(" File type: .csv (application/vnd.ms-excel)")
break
for sel in target_frame.query_selector_all('select'):
for opt in sel.query_selector_all('option'):
if 'attachment' in (opt.get_attribute('value') or '').lower():
sel.select_option(value='attachment')
break
timestamp = datetime.now().strftime("%Y-%m-%d_%H-%M")
country_slug = country if country else "ALL"
form_slug = form_name.replace(" ", "").replace("/", "-").replace("(", "").replace(")", "")
filename = f"{timestamp}_EDC_{study_label}_{country_slug}_{form_slug}_DataListing.csv"
output_path = DOWNLOAD_DIR / filename
print("Stahuji CSV...")
with new_page.expect_download(timeout=60_000) as dl_info:
btn = target_frame.query_selector('input[value="Download File"], button:has-text("Download File")')
if btn:
btn.click()
else:
new_page.locator('input[value="Download File"], button:has-text("Download File")').first.click()
dl_info.value.save_as(str(output_path))
print(f" Uloženo: {output_path}")
try:
new_page.close()
except Exception:
pass
return output_path
# ---------------------------------------------------------------------------
# Hlavní funkce
# ---------------------------------------------------------------------------
def download_datalisting(study: str, forms: list[str], country: str | None = None):
"""
Stáhne EDC Data Listing reporty pro zadanou studii.
Args:
study: Vyhledávací řetězec studie, např. "77242113UCO3001"
forms: Seznam názvů formulářů ke stažení
country: Kód site group, např. "CZE". None = všechny země.
"""
if not PASSWORD:
print("Chyba: nastav IMEDIDATA_PASSWORD v souboru .env")
sys.exit(1)
if not forms:
print("Žádné formuláře ke stažení.")
return []
DOWNLOAD_DIR.mkdir(exist_ok=True)
study_label = extract_study_label(study)
results = []
with sync_playwright() as p:
browser = p.chromium.launch(headless=False, slow_mo=200)
ctx_kwargs = {"accept_downloads": True}
use_saved = auth_valid()
if use_saved:
print("Načítám uloženou session (auth.json)...")
ctx_kwargs["storage_state"] = str(AUTH_FILE)
context = browser.new_context(**ctx_kwargs)
page = context.new_page()
logged_in = go_to_select_role(page)
if not logged_in:
if use_saved:
print("Session expirovala, přihlašuji znovu...")
AUTH_FILE.unlink(missing_ok=True)
do_login(page, context)
go_to_select_role(page)
select_role(page)
navigate_to_reporter(page)
open_report(page)
prompts_url = page.url
print("\nNastavuji parametry reportu...")
set_study_param(page, study)
if country:
set_site_group_param(page, country)
else:
print(" Parametr Site Group: přeskočen (všechny země)")
for i, form_name in enumerate(forms):
print(f"\n=== [{i+1}/{len(forms)}] Stahuji formulář: {form_name} ===")
if i > 0:
print("Navigace zpět na report...")
page.goto(prompts_url)
wait_load(page, 2000)
set_study_param(page, study)
if country:
set_site_group_param(page, country)
set_form_param(page, form_name)
output = submit_and_download(page, context, form_name, country, study_label)
results.append(output)
browser.close()
print(f"\nHotovo! Staženo {len(results)} formulářů. Prohlížeč zavřen.")
return results
# ---------------------------------------------------------------------------
# CLI
# ---------------------------------------------------------------------------
if __name__ == "__main__":
country_arg = sys.argv[1] if len(sys.argv) > 1 else None
download_datalisting(
study="77242113UCO3001",
forms=["Trial Disposition (Completion / Discontinuation)"],
country=country_arg,
)
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+5
View File
@@ -1,9 +1,14 @@
"""
import_to_mongo.py
Verze: 1.0
Datum: 2026-05-27
Import EDC Data Listing CSV do MongoDB (databáze: edc).
Kolekce: {STUDY}.{FormName} (např. UCO3001.ConcomitantTherapy)
Filtr: pouze řádky s SiteGroupName == "CZE"
Historie: při změně fields se stará verze uloží do pole history[]
Po importu přesune zpracované CSV do downloads/Zpracovano/
Použití:
python import_to_mongo.py # importuje všechny CSV z downloads/
+11
View File
@@ -0,0 +1,11 @@
from download_edc_datalistings import download_datalisting
download_datalisting(
study="77242113UCO3001",
forms=[
"Trial Disposition (Completion / Discontinuation)",
"Date of Visit",
"Concomitant Therapy",
],
country="CZE",
)
-13
View File
@@ -1,13 +0,0 @@
from download_uco3001 import download_datalisting_reports_3001
# === Vyber jeden řádek, odkomentuj ho a spusť ===
# --- Trial Disposition ---
# download_datalisting_reports_3001("Trial Disposition (Completion / Discontinuation)")
# download_datalisting_reports_3001("Date of Visit")
download_datalisting_reports_3001("Concomitant Therapy", country="CZE")
# download_datalisting_reports_3001("Trial Disposition (Completion / Discontinuation)", country="CZE")
# --- Date of Visit ---
# download_datalisting_reports_3001("Date of Visit")
# download_datalisting_reports_3001("Date of Visit", country="CZE")
+161
View File
@@ -0,0 +1,161 @@
#!/usr/bin/env python3
"""
MCP server pro MongoDB — používá FastMCP.
Spustit: python mcp_mongo.py
"""
import json
import sys
import traceback
from datetime import datetime, date
from typing import Optional
from bson import ObjectId
from mcp.server.fastmcp import FastMCP
from pymongo import MongoClient
MONGO_HOST = "192.168.1.76"
def log(msg: str):
print(msg, file=sys.stderr, flush=True)
try:
client = MongoClient(MONGO_HOST, serverSelectionTimeoutMS=5000)
client.server_info()
log(f"Connected to MongoDB ({MONGO_HOST})")
except Exception as e:
log(f"MongoDB connection failed: {e}")
sys.exit(1)
def serialize(obj):
"""Make MongoDB documents JSON-serializable."""
if isinstance(obj, ObjectId):
return str(obj)
if isinstance(obj, datetime):
return obj.isoformat()
if isinstance(obj, date):
return obj.isoformat()
if isinstance(obj, bytes):
return obj.decode("utf-8", errors="replace")
if isinstance(obj, dict):
return {k: serialize(v) for k, v in obj.items()}
if isinstance(obj, list):
return [serialize(v) for v in obj]
return obj
def parse_filter(filter_json: Optional[str]) -> dict:
"""Parse JSON string to dict. Returns {} on None/empty."""
if not filter_json or not filter_json.strip():
return {}
return json.loads(filter_json)
mcp = FastMCP("janssen-mongo")
@mcp.tool()
def list_databases() -> dict:
"""List all databases on the MongoDB server (excludes admin/config/local)."""
try:
skip = {"admin", "config", "local"}
dbs = [d["name"] for d in client.list_databases() if d["name"] not in skip]
return {"count": len(dbs), "databases": dbs}
except Exception:
log(f"list_databases error: {traceback.format_exc()}")
raise
@mcp.tool()
def list_collections(db: str) -> dict:
"""List all collections in a database."""
try:
cols = sorted(client[db].list_collection_names())
return {"db": db, "count": len(cols), "collections": cols}
except Exception:
log(f"list_collections error: {traceback.format_exc()}")
raise
@mcp.tool()
def collection_stats(db: str, collection: str) -> dict:
"""Returns document count + schema sample (fields and types from first document)."""
try:
col = client[db][collection]
count = col.estimated_document_count()
sample = col.find_one()
schema = {}
if sample:
for k, v in sample.items():
schema[k] = type(v).__name__
return {"db": db, "collection": collection, "count": count, "schema": schema}
except Exception:
log(f"collection_stats error: {traceback.format_exc()}")
raise
@mcp.tool()
def find_documents(
db: str,
collection: str,
filter_json: Optional[str] = None,
projection_json: Optional[str] = None,
sort_json: Optional[str] = None,
limit: int = 50,
) -> dict:
"""Query documents. filter/projection/sort are JSON strings, e.g. '{"patient_code":"CZ1-01"}'.
sort example: '{"last_seen_at": -1}'. Limit max 500.
"""
try:
col = client[db][collection]
filt = parse_filter(filter_json)
proj = parse_filter(projection_json) or None
sort_spec = parse_filter(sort_json)
limit = min(limit, 500)
cursor = col.find(filt, proj)
if sort_spec:
cursor = cursor.sort(list(sort_spec.items()))
cursor = cursor.limit(limit)
docs = [serialize(doc) for doc in cursor]
return {"count": len(docs), "docs": docs}
except Exception:
log(f"find_documents error: {traceback.format_exc()}")
raise
@mcp.tool()
def aggregate(db: str, collection: str, pipeline_json: str) -> dict:
"""Run a MongoDB aggregation pipeline. pipeline_json is a JSON array of stages,
e.g. '[{"$group": {"_id": "$patient_code", "count": {"$sum": 1}}}]'.
"""
try:
col = client[db][collection]
pipeline = json.loads(pipeline_json)
results = [serialize(doc) for doc in col.aggregate(pipeline)]
return {"count": len(results), "results": results}
except Exception:
log(f"aggregate error: {traceback.format_exc()}")
raise
@mcp.tool()
def distinct_values(db: str, collection: str, field: str, filter_json: Optional[str] = None) -> dict:
"""Return distinct values of a field, optionally filtered."""
try:
col = client[db][collection]
filt = parse_filter(filter_json)
values = [serialize(v) for v in col.distinct(field, filt)]
return {"field": field, "count": len(values), "values": values}
except Exception:
log(f"distinct_values error: {traceback.format_exc()}")
raise
if __name__ == "__main__":
log("MCP MongoDB server started (FastMCP)")
mcp.run()