Review ask

As a clinical trial statistician or programmer, challenge anything in this benchmark: describe a problem in Comments, or propose a fix with the Edit button on any source file.

  1. Task: Would a real study need this derivation, specified this way? Does it follow CDISC SDTM: variable names, controlled terms, record structure? Flag any rule that is ambiguous or that a sponsor would handle differently.
  2. Inputs: Do they look like data collected in a real trial, and do they include the situations you would expect to meet in one?
  3. Expected output: Would independent QC programming reproduce every value from these inputs and rules?

The other tabs beside Comments are background for assessment, not under review.

Summary

Lifecycle: draftEditUnder review
What this benchmark means
README.md

Goal: build the administered exposure records from the exposure as collected: tablet counts, a weight-based dose, a blinded kit, and an AUC target, adding EXSEQ, EXTRT, EXDOSE, EXDOSU, EXSTDTC, and EXENDTC.

Input: long-form Operational Data Model (ODM) data with one row per collected item, carrying the study, subject, visit, form, and form repeat (StudyOID, SubjectKey, StudyEventOID, FormOID, FormRepeatKey), the item (ItemOID), and the stored value (Value). Exposure items live on the FO.EC form (IT.EC.ECOCCUR, IT.EC.ECTRT, IT.EC.FORM, IT.EC.TABLETS, IT.EC.STRENGTHMG, IT.EC.DOSEMKG, IT.EC.AUCTARGET, IT.EC.KIT, IT.EC.ECSTDTC, IT.EC.ECENDTC); body weight is the IT.VS.WEIGHT item on the FO.VS form at the same visit. The kit list comes from the interactive response technology (IRT) system, not electronic data capture (EDC), so it stays a separate input (input/kit_list.csv) mapping kit numbers to treatments and doses.

Variables:

  • EXSEQ is the order of the administration within the subject, numbered by start date and then by the form's repeat number within the visit.
  • EXTRT is the administered treatment: the kit list's treatment for a blinded kit, otherwise as collected.
  • EXDOSE is the administered dose: tablets times strength, the mg/kg dose times the visit's body weight, the kit list's dose for a blinded kit, and the AUC target as collected.
  • EXDOSU is mg, except the AUC target keeps AUC.

Note: only a form whose occurrence item (IT.EC.ECOCCUR) is Y gives an exposure record, so a skipped dose leaves none. The placebo kit keeps its zero dose.

Inputs

Under review
2 source files

input/kit_list.csv

Edit
2 rows
input/kit_list.csv
KITTREATMENTDOSE_MG
KIT-104DRUG X100
KIT-207PLACEBO0

input/odm.csv

Edit
55 rows
input/odm.csv
StudyOIDMetaDataVersionOIDSubjectKeyStudyEventOIDStudyEventRepeatKeyFormOIDFormRepeatKeyItemGroupOIDItemGroupRepeatKeyItemOIDValue
STUDY01MDV.1001V11FO.EC1IG.EC1IT.EC.ECOCCURY
STUDY01MDV.1001V11FO.EC1IG.EC1IT.EC.ECTRTFINASTERIDE
STUDY01MDV.1001V11FO.EC1IG.EC1IT.EC.FORMTABLET
STUDY01MDV.1001V11FO.EC1IG.EC1IT.EC.TABLETS2
STUDY01MDV.1001V11FO.EC1IG.EC1IT.EC.STRENGTHMG5
STUDY01MDV.1001V11FO.EC1IG.EC1IT.EC.ECSTDTC2025-01-02
STUDY01MDV.1001V11FO.EC1IG.EC1IT.EC.ECENDTC2025-01-02
STUDY01MDV.1001V11FO.EC2IG.EC1IT.EC.ECOCCURN
STUDY01MDV.1001V11FO.EC2IG.EC1IT.EC.ECTRTFINASTERIDE
STUDY01MDV.1001V11FO.EC2IG.EC1IT.EC.FORMTABLET
STUDY01MDV.1001V11FO.EC2IG.EC1IT.EC.TABLETS2
STUDY01MDV.1001V11FO.EC2IG.EC1IT.EC.STRENGTHMG5
STUDY01MDV.1001V11FO.EC2IG.EC1IT.EC.ECSTDTC2025-01-09
STUDY01MDV.1001V11FO.EC2IG.EC1IT.EC.ECENDTC2025-01-09
STUDY01MDV.1001V11FO.VS1IG.VS1IT.VS.WEIGHT70
STUDY01MDV.1001V11FO.VS1IG.VS1IT.VS.HEIGHT170
STUDY01MDV.1001V11FO.VS1IG.VS1IT.VS.VSDTC2025-01-02
STUDY01MDV.1001V21FO.EC1IG.EC1IT.EC.ECOCCURY
STUDY01MDV.1001V21FO.EC1IG.EC1IT.EC.ECTRTTRASTUZUMAB
STUDY01MDV.1001V21FO.EC1IG.EC1IT.EC.FORMINFUSION
STUDY01MDV.1001V21FO.EC1IG.EC1IT.EC.DOSEMKG6
STUDY01MDV.1001V21FO.EC1IG.EC1IT.EC.ECSTDTC2025-01-23
STUDY01MDV.1001V21FO.EC1IG.EC1IT.EC.ECENDTC2025-01-23
STUDY01MDV.1001V21FO.VS1IG.VS1IT.VS.WEIGHT72
STUDY01MDV.1001V21FO.VS1IG.VS1IT.VS.VSDTC2025-01-23
STUDY01MDV.1002V11FO.EC1IG.EC1IT.EC.ECOCCURY
STUDY01MDV.1002V11FO.EC1IG.EC1IT.EC.FORMKITDOSE
STUDY01MDV.1002V11FO.EC1IG.EC1IT.EC.KITKIT-104
STUDY01MDV.1002V11FO.EC1IG.EC1IT.EC.ECSTDTC2025-02-05
STUDY01MDV.1002V11FO.EC1IG.EC1IT.EC.ECENDTC2025-02-05
STUDY01MDV.1002V11FO.VS1IG.VS1IT.VS.WEIGHT80
STUDY01MDV.1002V11FO.VS1IG.VS1IT.VS.VSDTC2025-02-05
STUDY01MDV.1002V21FO.EC1IG.EC1IT.EC.ECTRTTRASTUZUMAB
STUDY01MDV.1002V21FO.EC1IG.EC1IT.EC.FORMINFUSION
STUDY01MDV.1002V21FO.EC1IG.EC1IT.EC.DOSEMKG6
STUDY01MDV.1002V21FO.EC1IG.EC1IT.EC.ECOCCURY
STUDY01MDV.1002V21FO.EC1IG.EC1IT.EC.ECSTDTC2025-02-26
STUDY01MDV.1002V21FO.EC1IG.EC1IT.EC.ECENDTC2025-02-26
STUDY01MDV.1002V21FO.VS1IG.VS1IT.VS.WEIGHT80
STUDY01MDV.1002V21FO.VS1IG.VS1IT.VS.VSDTC2025-02-26
STUDY01MDV.1003V11FO.EC1IG.EC1IT.EC.ECOCCURY
STUDY01MDV.1003V11FO.EC1IG.EC1IT.EC.FORMKITDOSE
STUDY01MDV.1003V11FO.EC1IG.EC1IT.EC.KITKIT-207
STUDY01MDV.1003V11FO.EC1IG.EC1IT.EC.ECSTDTC2025-03-04
STUDY01MDV.1003V11FO.EC1IG.EC1IT.EC.ECENDTC2025-03-04
STUDY01MDV.1003V11FO.VS1IG.VS1IT.VS.WEIGHT65
STUDY01MDV.1003V11FO.VS1IG.VS1IT.VS.VSDTC2025-03-04
STUDY01MDV.1003V21FO.EC1IG.EC1IT.EC.ECOCCURY
STUDY01MDV.1003V21FO.EC1IG.EC1IT.EC.ECTRTCARBOPLATIN
STUDY01MDV.1003V21FO.EC1IG.EC1IT.EC.FORMAUCDOSE
STUDY01MDV.1003V21FO.EC1IG.EC1IT.EC.AUCTARGET5
STUDY01MDV.1003V21FO.EC1IG.EC1IT.EC.ECSTDTC2025-03-25
STUDY01MDV.1003V21FO.EC1IG.EC1IT.EC.ECENDTC2025-03-25
STUDY01MDV.1003V21FO.VS1IG.VS1IT.VS.WEIGHT65
STUDY01MDV.1003V21FO.VS1IG.VS1IT.VS.VSDTC2025-03-25

Expected output

Under review
6 expected rows

expected/ex.csv

Edit
6 rows
expected/ex.csv
DOMAINSTUDYIDUSUBJIDEXSEQEXTRTEXDOSEEXDOSUEXSTDTCEXENDTC
EXSTUDY011FINASTERIDE10mg2025-01-022025-01-02
EXSTUDY012TRASTUZUMAB432mg2025-01-232025-01-23
EXSTUDY011DRUG X100mg2025-02-052025-02-05
EXSTUDY012TRASTUZUMAB480mg2025-02-262025-02-26
EXSTUDY011PLACEBO0mg2025-03-042025-03-04
EXSTUDY012CARBOPLATIN5AUC2025-03-252025-03-25
Shaded columns are derived— = missing value

Comments and assessment materials

Comments

Signed in with GitHub; saved in repository Discussions

Mapping spec

Generated from the benchmark YAML; do not edit by hand

Variable NameVariable LabelTypeLengthControlled Terms or FormatOriginCoreConversion DefinitionVariable TypeVariable OrderComments for Define
DOMAINDomain AbbreviationCharAssignedSet constant value "EX".SDTM1
STUDYIDStudy IdentifierCharCollectedCopy value from ODM.StudyOID.SDTM2
USUBJIDUnique Subject IdentifierCharCollectedCopy value from ODM.SubjectKey.SDTM3
EXTRTName of TreatmentCharDerivedIf FORM = 'KITDOSE' then "KITMAP.TREATMENT"; otherwise "EC_ECTRT.Value".SDTM4
EXDOSEDoseNumDerivedIf FORM = 'TABLET' then compute TABLETS * STRENGTHMG; If FORM = 'INFUSION' then compute DOSEMKG * WT_KG; If FORM = 'AUCDOSE' then "AUCTARGET"; otherwise "KIT_DOSE".SDTM5
EXDOSUDose UnitsCharmg, AUCDerivedIf FORM = 'AUCDOSE' then "AUC"; otherwise "mg".SDTM6
EXSTDTCStart Date/Time of TreatmentCharISO 8601DerivedTake Value from the ODM record whose StudyOID equals ODM.StudyOID, SubjectKey equals ODM.SubjectKey, StudyEventOID equals ODM.StudyEventOID, FormOID equals ODM.FormOID and FormRepeatKey equals ODM.FormRepeatKey, where ODM.ItemOID = 'IT.EC.ECSTDTC', and a row with no match is an error.SDTM7
EXENDTCEnd Date/Time of TreatmentCharISO 8601DerivedTake Value from the ODM record whose StudyOID equals ODM.StudyOID, SubjectKey equals ODM.SubjectKey, StudyEventOID equals ODM.StudyEventOID, FormOID equals ODM.FormOID and FormRepeatKey equals ODM.FormRepeatKey, where ODM.ItemOID = 'IT.EC.ECENDTC', and a row with no match is an error.SDTM8
EXSEQSequence NumberNumDerivedRow number within each group of STUDYID, USUBJID, ordered by EXSTDTC then FRMREP.SDTM9
TemplateInclude when
administeredODM.ItemOID = 'IT.EC.ECOCCUR' AND ODM.Value = 'Y'
VariablePermitted values
EXDOSUmg, AUC
VersionDateAuthorDescriptionReviewerSign-off
1.32026-09-29yamaa docs buildShow study codelist names, external dictionaries, and ISO 8601 formats in variable rows; list the document's codelist values and metadata
1.22026-09-29yamaa docs buildClassify ADaM copies from a declared input as Predecessor and recodes as Derived, and SDTM recodes of locally derived columns as Derived
1.12026-09-29yamaa docs buildResolve lookups into the donor record they select, and give every derivation shape a plain-language rule instead of its raw YAML
1.0yamaa docs buildInitial generation from spec.yaml

Agent prompt

The request an agent receives with the input files; each tier states no more than the one above

prompts/sdtm-ex-from-ec/full.md

Edit
23 lines

Following CDISC SDTM standards, use the provided ODM and KITLIST datasets to create an EX dataset with one record per administered exposure.

The output dataset should contain the following columns in this order: DOMAIN, STUDYID, USUBJID, EXSEQ, EXTRT, EXDOSE, EXDOSU, EXSTDTC, EXENDTC

STUDYID is the ODM StudyOID and USUBJID is the SubjectKey, each as given.

Only a form whose occurrence is Y gives a record, so a skipped dose leaves none; the placebo kit keeps its zero dose. EXSEQ numbers the administrations within the subject by start date and then by the form repeat number within the visit. EXTRT is the kit list treatment for a blinded kit, and the collected treatment otherwise. EXDOSE is the administered dose: for tablets, the tablets taken at the collected strength; for infusion, the collected amount per kilogram at the visit body weight; for a blinded kit, the kit list dose; and for an AUC target, the collected target. EXDOSU is mg, except the AUC target keeps AUC. EXSTDTC and EXENDTC are the collected start and end dates. Body weight comes from the VS form at the same visit.

Read the source datasets from /app/input and save the completed dataset as /app/output/ex.csv.

prompts/sdtm-ex-from-ec/conventions.md

Edit
9 lines

Following CDISC SDTM standards, use the provided ODM and KITLIST datasets to create an EX dataset with one record per administered exposure.

The output dataset should contain the following columns in this order: DOMAIN, STUDYID, USUBJID, EXSEQ, EXTRT, EXDOSE, EXDOSU, EXSTDTC, EXENDTC

Read the source datasets from /app/input and save the completed dataset as /app/output/ex.csv.

prompts/sdtm-ex-from-ec/brief.md

Edit
9 lines

Following CDISC SDTM standards, use the provided ODM and KITLIST datasets to create an EX dataset with one record per administered exposure.

The output dataset should contain the following columns in this order: DOMAIN, STUDYID, USUBJID, EXSEQ, EXTRT, EXDOSE, EXDOSU, EXSTDTC, EXENDTC

Read the source datasets from /app/input and save the completed dataset as /app/output/ex.csv.

yamaa code

Runs the yamaa specification; its result must match the expected output

run.R

Edit
4 lines
library(yamaa)ex <- yamaa_domain("spec.yaml")$outputex

run.py

Edit
4 lines
import yamaaex = yamaa.yamaa_domain("spec.yaml").outputex

Solution without yamaa

Written from the full prompt and the inputs alone; CI checks it reproduces the expected output

solutions/sdtm-ex-from-ec/result.R

Edit
73 lines
# Reference solution for the yamaa benchmark sdtm-ex-from-ec (R track).## Written from the benchmark's full prompt and its inputs alone, as an agent# would write it. Harbor's oracle agent runs it to check that the prompt can# be solved and that the grader scores a correct answer 1.library(dplyr, warn.conflicts = FALSE)library(readr)library(tidyr)odm <- read_csv(  "/app/input/odm.csv",  col_types = cols(.default = col_character()))kit <- read_csv(  "/app/input/kit_list.csv",  col_types = cols(.default = col_character()))kit_trt <- setNames(kit$TREATMENT, kit$KIT)kit_dose <- setNames(suppressWarnings(as.numeric(kit$DOSE_MG)), kit$KIT)ec_forms <- odm |> filter(FormOID == "FO.EC")vs_weight <- odm |>  filter(FormOID == "FO.VS", ItemOID == "IT.VS.WEIGHT") |>  group_by(StudyOID, SubjectKey, StudyEventOID, StudyEventRepeatKey) |>  summarise(WEIGHT = suppressWarnings(as.numeric(first(Value))), .groups = "drop")ec_wide <- ec_forms |>  group_by(StudyOID, SubjectKey, StudyEventOID, StudyEventRepeatKey, FormRepeatKey) |>  summarise(    ECOCCUR = Value[ItemOID == "IT.EC.ECOCCUR"][1],    ECTRT = Value[ItemOID == "IT.EC.ECTRT"][1],    FORM = Value[ItemOID == "IT.EC.FORM"][1],    TABLETS = suppressWarnings(as.numeric(Value[ItemOID == "IT.EC.TABLETS"][1])),    STRENGTHMG = suppressWarnings(as.numeric(Value[ItemOID == "IT.EC.STRENGTHMG"][1])),    DOSEMKG = suppressWarnings(as.numeric(Value[ItemOID == "IT.EC.DOSEMKG"][1])),    KIT = Value[ItemOID == "IT.EC.KIT"][1],    AUCTARGET = suppressWarnings(as.numeric(Value[ItemOID == "IT.EC.AUCTARGET"][1])),    ECSTDTC = Value[ItemOID == "IT.EC.ECSTDTC"][1],    ECENDTC = Value[ItemOID == "IT.EC.ECENDTC"][1],    .groups = "drop"  ) |>  left_join(vs_weight, by = c("StudyOID", "SubjectKey", "StudyEventOID", "StudyEventRepeatKey")) |>  filter(ECOCCUR == "Y")ex <- ec_wide |>  rowwise() |>  mutate(    DOMAIN = "EX",    STUDYID = StudyOID,    USUBJID = SubjectKey,    EXTRT = if (FORM == "KITDOSE") unname(kit_trt[KIT]) else ECTRT,    EXDOSE = case_when(      FORM == "TABLET" ~ TABLETS * STRENGTHMG,      FORM == "INFUSION" ~ DOSEMKG * WEIGHT,      FORM == "KITDOSE" ~ unname(kit_dose[KIT]),      FORM == "AUCDOSE" ~ AUCTARGET,      .default = NA_real_    ),    EXDOSU = ifelse(FORM == "AUCDOSE", "AUC", "mg"),    FORMREPEAT = suppressWarnings(as.integer(FormRepeatKey)),    EXSTDTC_DATE = suppressWarnings(as.Date(na_if(ECSTDTC, "")))  ) |>  ungroup() |>  arrange(STUDYID, USUBJID, EXSTDTC_DATE, FORMREPEAT) |>  group_by(STUDYID, USUBJID) |>  mutate(EXSEQ = row_number()) |>  ungroup() |>  select(DOMAIN, STUDYID, USUBJID, EXSEQ, EXTRT, EXDOSE, EXDOSU, EXSTDTC = ECSTDTC, EXENDTC = ECENDTC)dir.create("/app/output", showWarnings = FALSE)write_csv(ex, "/app/output/ex.csv", na = "")

solutions/sdtm-ex-from-ec/result.py

Edit
144 lines
# Reference solution for the yamaa benchmark sdtm-ex-from-ec (Python track).## Written from the benchmark's full prompt and its inputs alone, as an agent# would write it. Harbor's oracle agent runs it to check that the prompt can# be solved and that the grader scores a correct answer 1.from pathlib import Pathimport polars as plodm = pl.read_csv("/app/input/odm.csv", infer_schema=False)kit = pl.read_csv("/app/input/kit_list.csv", infer_schema=False)kit_map = {r["KIT"]: (r["TREATMENT"], r["DOSE_MG"]) for r in kit.to_dicts()}ec_forms = odm.filter(pl.col("FormOID") == "FO.EC")vs_forms = odm.filter(pl.col("FormOID") == "FO.VS")# Body weight per visit: SubjectKey + StudyEventOID + StudyEventRepeatKey.vs_wide = (    vs_forms.filter(pl.col("ItemOID") == "IT.VS.WEIGHT")    .group_by("StudyOID", "SubjectKey", "StudyEventOID", "StudyEventRepeatKey")    .agg(pl.col("Value").first().alias("WEIGHT"))    .with_columns(pl.col("WEIGHT").cast(pl.Float64, strict=False)))ec_wide = (    ec_forms.group_by(        "StudyOID",        "SubjectKey",        "StudyEventOID",        "StudyEventRepeatKey",        "FormRepeatKey",    )    .agg(        pl.col("Value").filter(pl.col("ItemOID") == "IT.EC.ECOCCUR").first().alias("ECOCCUR"),        pl.col("Value").filter(pl.col("ItemOID") == "IT.EC.ECTRT").first().alias("ECTRT"),        pl.col("Value").filter(pl.col("ItemOID") == "IT.EC.FORM").first().alias("FORM"),        pl.col("Value").filter(pl.col("ItemOID") == "IT.EC.TABLETS").first().alias("TABLETS"),        pl.col("Value").filter(pl.col("ItemOID") == "IT.EC.STRENGTHMG").first().alias("STRENGTHMG"),        pl.col("Value").filter(pl.col("ItemOID") == "IT.EC.DOSEMKG").first().alias("DOSEMKG"),        pl.col("Value").filter(pl.col("ItemOID") == "IT.EC.KIT").first().alias("KIT"),        pl.col("Value").filter(pl.col("ItemOID") == "IT.EC.AUCTARGET").first().alias("AUCTARGET"),        pl.col("Value").filter(pl.col("ItemOID") == "IT.EC.ECSTDTC").first().alias("ECSTDTC"),        pl.col("Value").filter(pl.col("ItemOID") == "IT.EC.ECENDTC").first().alias("ECENDTC"),    )    .join(        vs_wide,        on=["StudyOID", "SubjectKey", "StudyEventOID", "StudyEventRepeatKey"],        how="left",    )    .filter(pl.col("ECOCCUR") == "Y"))def num(v):    if v is None or v == "":        return None    try:        return float(v)    except ValueError:        return Nonerecords: list[dict] = []for row in ec_wide.to_dicts():    study = row["StudyOID"]    subj = row["SubjectKey"]    form = row["FORM"] or ""    usubjid = subj    if form == "KITDOSE":        treatment, dose_mg = kit_map.get(row["KIT"] or "", (None, None))        trt = treatment        dose = num(dose_mg)        dosu = "mg"    elif form == "TABLET":        trt = row["ECTRT"] or None        tablets = num(row["TABLETS"])        strength = num(row["STRENGTHMG"])        dose = tablets * strength if tablets is not None and strength is not None else None        dosu = "mg"    elif form == "INFUSION":        trt = row["ECTRT"] or None        perkg = num(row["DOSEMKG"])        weight = row["WEIGHT"]        dose = perkg * weight if perkg is not None and weight is not None else None        dosu = "mg"    elif form == "AUCDOSE":        trt = row["ECTRT"] or None        dose = num(row["AUCTARGET"])        dosu = "AUC"    else:        trt = row["ECTRT"] or None        dose = None        dosu = "mg"    records.append(        {            "STUDYID": study,            "USUBJID": usubjid,            "EXTRT": trt,            "EXDOSE": dose,            "EXDOSU": dosu,            "EXSTDTC": row["ECSTDTC"] or None,            "EXENDTC": row["ECENDTC"] or None,            "FORMREPEAT": int(row["FormRepeatKey"]) if row["FormRepeatKey"] else 0,        }    )ex = (    pl.DataFrame(        records,        schema={            "STUDYID": pl.String,            "USUBJID": pl.String,            "EXTRT": pl.String,            "EXDOSE": pl.Float64,            "EXDOSU": pl.String,            "EXSTDTC": pl.String,            "EXENDTC": pl.String,            "FORMREPEAT": pl.Int64,        },    )    .with_columns(        DOMAIN=pl.lit("EX"),        EXSTDTC_DT=pl.col("EXSTDTC").str.to_date(strict=False),    )    .sort(["STUDYID", "USUBJID", "EXSTDTC_DT", "FORMREPEAT"], nulls_last=True)    .with_columns(EXSEQ=pl.col("USUBJID").cum_count().over(["STUDYID", "USUBJID"]))    .with_columns(EXSEQ=pl.col("EXSEQ").cast(pl.Int64))    .select(        "DOMAIN",        "STUDYID",        "USUBJID",        "EXSEQ",        "EXTRT",        "EXDOSE",        "EXDOSU",        "EXSTDTC",        "EXENDTC",    ))Path("/app/output").mkdir(exist_ok=True)ex.write_csv("/app/output/ex.csv")

solutions/sdtm-ex-from-ec/result.sas

Edit
70 lines
/* opensas reference solution for the yamaa benchmark sdtm-ex-from-ec.   Reads the benchmark inputs and derives the requested output.   Execute with the existing opensas runtime: opensas /app/output/result.sas. */data kit_list;  length KIT TREATMENT DOSE_MG $1024;  infile "/app/input/kit_list.csv" dsd dlm="," firstobs=2 truncover lrecl=32767;  input KIT : $char1024. TREATMENT : $char1024. DOSE_MG : $char1024.;run;data odm;  length StudyOID MetaDataVersionOID SubjectKey StudyEventOID StudyEventRepeatKey FormOID FormRepeatKey ItemGroupOID ItemGroupRepeatKey ItemOID Value $1024;  infile "/app/input/odm.csv" dsd dlm="," firstobs=2 truncover lrecl=32767;  input StudyOID : $char1024. MetaDataVersionOID : $char1024. SubjectKey : $char1024. StudyEventOID : $char1024. StudyEventRepeatKey : $char1024. FormOID : $char1024. FormRepeatKey : $char1024. ItemGroupOID : $char1024. ItemGroupRepeatKey : $char1024. ItemOID : $char1024. Value : $char1024.;run;proc sort data=odm out=ordered; by StudyOID SubjectKey StudyEventOID StudyEventRepeatKey FormRepeatKey; run;data doses;  length ECTRT ECSTDTC ECENDTC ECOCCUR FORM TABLETS STRENGTHMG DOSEMKG KIT AUCTARGET $1024;  retain ECTRT ECSTDTC ECENDTC ECOCCUR FORM TABLETS STRENGTHMG DOSEMKG KIT AUCTARGET;  set ordered;  where FormOID='FO.EC';  by StudyOID SubjectKey StudyEventOID StudyEventRepeatKey FormRepeatKey;  if first.FormRepeatKey then do;    ECTRT=''; ECSTDTC=''; ECENDTC=''; ECOCCUR=''; FORM=''; TABLETS=''; STRENGTHMG=''; DOSEMKG=''; KIT=''; AUCTARGET='';  end;    if ItemOID='IT.EC.ECTRT' then ECTRT=Value;  if ItemOID='IT.EC.ECSTDTC' then ECSTDTC=Value;  if ItemOID='IT.EC.ECENDTC' then ECENDTC=Value;  if ItemOID='IT.EC.ECOCCUR' then ECOCCUR=Value;  if ItemOID='IT.EC.FORM' then FORM=Value;  if ItemOID='IT.EC.TABLETS' then TABLETS=Value;  if ItemOID='IT.EC.STRENGTHMG' then STRENGTHMG=Value;  if ItemOID='IT.EC.DOSEMKG' then DOSEMKG=Value;  if ItemOID='IT.EC.KIT' then KIT=Value;  if ItemOID='IT.EC.AUCTARGET' then AUCTARGET=Value;  if last.FormRepeatKey then output;run;proc sort data=odm out=ordered; by StudyOID SubjectKey StudyEventOID StudyEventRepeatKey; run;data weights;  length VISITWEIGHT $1024;  retain VISITWEIGHT;  set ordered;  where FormOID='FO.VS';  by StudyOID SubjectKey StudyEventOID StudyEventRepeatKey;  if first.StudyEventRepeatKey then do;    VISITWEIGHT='';  end;    if ItemOID='IT.VS.WEIGHT' then VISITWEIGHT=Value;  if last.StudyEventRepeatKey then output;run;proc sql;create table joined as select a.*,b.VISITWEIGHT,c.TREATMENT,c.DOSE_MG from doses a left join weights b on a.StudyOID=b.StudyOID and a.SubjectKey=b.SubjectKey and a.StudyEventOID=b.StudyEventOID and a.StudyEventRepeatKey=b.StudyEventRepeatKey left join kit_list c on a.KIT=c.KIT; quit;data prepared; set joined; if ECOCCUR='Y'; length DOMAIN $2 STUDYID USUBJID EXTRT EXDOSU EXSTDTC EXENDTC $1024;DOMAIN='EX'; STUDYID=StudyOID; USUBJID=SubjectKey; EXTRT=ECTRT; EXSTDTC=ECSTDTC; EXENDTC=ECENDTC; EXDOSU='mg'; EXDOSE=.;if FORM='TABLET' then EXDOSE=input(TABLETS,best32.)*input(STRENGTHMG,best32.);if FORM='INFUSION' then EXDOSE=input(DOSEMKG,best32.)*input(VISITWEIGHT,best32.);if FORM='KITDOSE' then do; EXTRT=TREATMENT; EXDOSE=input(DOSE_MG,best32.); end;if FORM='AUCDOSE' then do; EXDOSE=input(AUCTARGET,best32.); EXDOSU='AUC'; end;FORMREP=input(FormRepeatKey,best32.); NODATE=missing(EXSTDTC); run;proc sort data=prepared; by STUDYID USUBJID NODATE EXSTDTC FORMREP; run;data result; set prepared; by STUDYID USUBJID; retain EXSEQ;  if first.USUBJID then EXSEQ=0;  EXSEQ+1;run;proc sql;  create table final as select DOMAIN, STUDYID, USUBJID, EXSEQ, EXTRT, EXDOSE, EXDOSU, EXSTDTC, EXENDTC from result;quit;proc export data=final outfile="/app/output/ex.csv" dbms=csv replace; run;