Splitted Class Management — Equipe Extension
Groups two halves of a splitted class into a single ranked list and writes the qualified riders into an Equipe list.
1. What it does
When a class is too big it is split into two competitions (Group 1 / Group 2) that run in parallel and are ranked separately. The qualified riders for the next round have to come from both groups, merged fairly.
The extension:
- reads the results of the two group competitions,
- interleaves them — 1st of Group 1, 1st of Group 2, 2nd of Group 1, 2nd of Group 2, and so on,
- removes riders who have no result yet, and removes duplicate horse numbers,
- shows the merged list for checking,
- on confirmation, empties the destination list in Equipe and re-creates it with the merged order.
Interleaving is what makes the merge fair: it preserves the rank inside each group instead of comparing times or faults across two different judgings.
2. Requirements
| Item | Value |
|---|---|
| Equipe show | online, API enabled |
| API key | passed inside the JWT (api_key claim) |
| JWT secret | shared HS256 secret, ±60 s leeway |
The extension is launched by Equipe with a signed token:
splitted_get.php?token=<JWT>
The token payload must contain meeting_url, target (modal or browser),
style_url, and the top-level api_key.
3. Using the extension
Step 1 — Open it
Launch the extension from the Equipe show. Three drop-downs and two buttons appear.
Step 2 — Select the sources
| Field | What to pick | Filter applied |
|---|---|---|
| Splitted Class Group 1 | first half of the split class | competitions (z = H), excluding Do not compete |
| Splitted Class Group 2 | second half of the split class | same |
| Grouped List | the destination list that will receive the qualified riders | lists (z = L) that are not multi-use and have no FEI id |
The destination list must exist in Equipe before running the extension. Only lists without an FEI identifier are offered, so an official FEI class can never be overwritten by mistake.
Step 3 — Generate
Click Generate Qualified riders list. A table is displayed:
# · Horse # · Rider Name · Horse · Nation · Result Preview · From
The From badge shows whether the line comes from Group 1 or Group 2. Check the order and the count before importing — nothing has been written to Equipe at this point.
Step 4 — Import
Click Import Qualified riders to Equipe. A spinner runs while the extension:
- deletes all existing starts in the destination list,
- creates one start per rider of the merged list,
- updates each start with its horse number, its starting order and the result preview.
Then reopen the list in Equipe to verify.
⚠️ The import is destructive. Everything already present in the destination list is deleted first. Always point the import at a list dedicated to this purpose.
4. Selection rules
A rider from a group is kept only if:
result_previewis not empty — riders who have not started, or who have no published result, are dropped;- the horse number (
hnr) has not already been used by an earlier line — the first occurrence wins. This protects against the same horse appearing in both groups (same horse number, different rider).
Numbering (compteur) is assigned during the merge and becomes the starting
order (st) in Equipe.
5. Data flow
Equipe ──JWT──> splitted_get.php ──GET /competitions.json──> Equipe
│
user selects Q1 / Q2 / destination
│
├─GET splitted_class.php?id1&id2&url&apikey
│ └─GET /competitions/{id}/results.json (×2)
│ └─merge + filter ──> JSON to the browser
│
└─POST splitted_import.php (destination, JsonData)
├─GET /competitions/{id}/starts.json
├─DELETE /competitions/{id}/starts
├─POST /competitions/{id}/starts (×N)
└─PATCH /competitions/{id}/starts/updates
Fields read from results.json
| Merged field | Equipe source |
|---|---|
nom_cavalier |
rider_name |
cheval |
horse_name |
nation |
rider_country |
hnr |
horse_no |
penalite |
grundf |
temps |
grundt |
Result_preview |
result_preview |
Fields written to the destination list
| Equipe field | Value |
|---|---|
horse_no |
hnr |
st |
merged position (compteur) |
start_custom_fields_results_preview |
Result_preview |
6. Troubleshooting
| Symptom | Likely cause |
|---|---|
| Empty table after Generate | no rider has a result_preview yet — the results are not published |
| Fewer riders than expected | duplicate horse numbers between the two groups, or missing results |
| Import button stays disabled | Generate has not been run successfully; check the browser console |
Curl error on load |
wrong meeting_url or API key in the token |
| JWT decode failure | clock drift beyond 60 s, or wrong shared secret |
| Destination list not in the drop-down | the list has an FEI id, or is flagged multi-use, or is not of type L |
Errors from the AJAX calls are written to the browser console (F12), not to the
page.
7. Known limitations
These are current behaviours of the code, worth knowing before relying on it in production:
- Only two groups. A class split into three or more cannot be merged.
- Start creation is incomplete. In
splitted_import.php, the creation loop posts empty start records: the variable$cavalieris never assigned (the loop uses$i), sorider_nameandhnrare sent blank and only filled by the laterPATCHpass, matched by position. Any mismatch between created and patched records shifts the whole list. - Off-by-one. The loop runs
$i <= $counter, creating one start too many. - Hardcoded API key. The
POST .../startscommand carries a literalX-API-KEYinstead of the key received in the request — the import fails on any other show. shell_exec+curl. The import shells out with values coming from the request; they are not escaped. Rewriting these calls with PHP cURL (as already done insplitted_get.php) removes both the injection risk and the dependency on thecurlbinary.- No user-visible confirmation. The success response of the import is not displayed; only the spinner stops.
- No undo. The deletion of the destination list is not snapshotted.