commit 87b6529671aebf7876a7910a5c53ed2d3c4d6d7e Author: Pagwin Date: Fri Jun 5 12:04:15 2026 -0400 before LLM fucks things up diff --git a/.python-version b/.python-version new file mode 100644 index 0000000..24ee5b1 --- /dev/null +++ b/.python-version @@ -0,0 +1 @@ +3.13 diff --git a/README.md b/README.md new file mode 100644 index 0000000..e69de29 diff --git a/main.py b/main.py new file mode 100644 index 0000000..89ff5ff --- /dev/null +++ b/main.py @@ -0,0 +1,548 @@ +""" +City Resource Optimization -> CP-SAT (Google OR-Tools) + +Maximise Electrum * Brass * Steel after the gains of step 5. + +The objective is a product of three variables, so this is a constraint- +programming / nonlinear problem, hence CP-SAT (cp_model) rather than the +LP/MIP solver. Read the comments at: + - PARAMETERS (initial pools + arrival schedule + bonus mode) + - "OBJECTIVE IS SET HERE" (the product being maximised -- tweak freely) +""" + +from ortools.sat.python import cp_model + + +# ====================================================================== +# PARAMETERS -- edit these +# ====================================================================== + +# Starting resource pools at the start of step 1: (Electrum, Brass, Steel, Capital) +INITIAL = (3, 3, 3, 3) + +# Arrival schedule. Key = step (1..5), value = list of city types that arrive +# at the START of that step. Types: 'H' Hub, 'F' Foundry, 'M' Metropolis, 'N' Monument. +# Total cities across all steps must be <= 7. Arriving cities act that same step. +ARRIVALS = { + 1: ["H", "F", "H", "N", "F"], + 2: ["M"], + 3: [], + 4: [], + 5: [], +} + +# Collect Bonus (b) adds +1 to whatever a Collect gives. On a foundry that is +# +1 of the resource collected (i.e. the chosen vat's value + 1). This is the +# same uniform rule as Hub (+1 Capital) and Metropolis (+1 resource pick). + +NUM_STEPS = 5 +MAX_RES = ( + 200 # upper bound on any resource pool (raise if you expect more; affects speed) +) +MAX_VAT = 15 # upper bound on a foundry vat value (1 + 2*nsteps is plenty) + + +# ====================================================================== +# MODEL +# ====================================================================== + + +def solve( + initial=INITIAL, + arrivals=ARRIVALS, + max_res=MAX_RES, + max_vat=MAX_VAT, + time_limit=60.0, + num_workers=8, + verbose=True, +): + + # ---- build the city list ----------------------------------------- + cities = [] # list of (arrival_step, arrival_type) + for s in range(1, NUM_STEPS + 1): + for typ in arrivals.get(s, []): + cities.append((s, typ)) + N = len(cities) + assert N <= 7, f"At most 7 cities allowed, got {N}" + + m = cp_model.CpModel() + + def AND(a, b): + """Boolean AND of two 0/1 vars, returned as a new 0/1 var.""" + c = m.NewBoolVar("") + m.AddMultiplicationEquality(c, [a, b]) + return c + + # ---- state variables --------------------------------------------- + # Indexed [i][t]; t in 1..NUM_STEPS+1 for state (t=NUM_STEPS+1 == "after step 5"). + isH, isF, isM, isMon, present = {}, {}, {}, {}, {} + hasA, hasB, hasD = {}, {}, {} + vE, vB, vS = {}, {}, {} # foundry vats at start of step t + + # action variables, t in 1..NUM_STEPS + col, ua, ub, ud = {}, {}, {}, {} # collect / upgrade a,b,d + rH, rF, rM = {}, {}, {} # renovate -> Hub/Foundry/Metro + cvE, cvB, cvS = {}, {}, {} # foundry: which vat collected + mE, mB, mS, mC = {}, {}, {}, {} # metropolis: resources picked (+1 each) + + for i in range(N): + a_step, a_type = cities[i] + for t in range(1, NUM_STEPS + 2): + isH[i, t] = m.NewBoolVar(f"isH_{i}_{t}") + isF[i, t] = m.NewBoolVar(f"isF_{i}_{t}") + isM[i, t] = m.NewBoolVar(f"isM_{i}_{t}") + isMon[i, t] = m.NewBoolVar(f"isMon_{i}_{t}") + present[i, t] = m.NewBoolVar(f"present_{i}_{t}") + hasA[i, t] = m.NewBoolVar(f"hasA_{i}_{t}") + hasB[i, t] = m.NewBoolVar(f"hasB_{i}_{t}") + hasD[i, t] = m.NewBoolVar(f"hasD_{i}_{t}") + vE[i, t] = m.NewIntVar(0, max_vat, f"vE_{i}_{t}") + vB[i, t] = m.NewIntVar(0, max_vat, f"vB_{i}_{t}") + vS[i, t] = m.NewIntVar(0, max_vat, f"vS_{i}_{t}") + + # presence: present from arrival step onward, persists + m.Add(present[i, t] == (1 if t >= a_step else 0)) + # exactly one type iff present + m.Add(isH[i, t] + isF[i, t] + isM[i, t] + isMon[i, t] == present[i, t]) + + for t in range(1, NUM_STEPS + 1): + col[i, t] = m.NewBoolVar(f"col_{i}_{t}") + ua[i, t] = m.NewBoolVar(f"ua_{i}_{t}") + ub[i, t] = m.NewBoolVar(f"ub_{i}_{t}") + ud[i, t] = m.NewBoolVar(f"ud_{i}_{t}") + rH[i, t] = m.NewBoolVar(f"rH_{i}_{t}") + rF[i, t] = m.NewBoolVar(f"rF_{i}_{t}") + rM[i, t] = m.NewBoolVar(f"rM_{i}_{t}") + cvE[i, t] = m.NewBoolVar(f"cvE_{i}_{t}") + cvB[i, t] = m.NewBoolVar(f"cvB_{i}_{t}") + cvS[i, t] = m.NewBoolVar(f"cvS_{i}_{t}") + mE[i, t] = m.NewIntVar(0, 3, f"mE_{i}_{t}") + mB[i, t] = m.NewIntVar(0, 3, f"mB_{i}_{t}") + mS[i, t] = m.NewIntVar(0, 3, f"mS_{i}_{t}") + mC[i, t] = m.NewIntVar(0, 3, f"mC_{i}_{t}") + + # ---- per-step gain/cost accumulators (linear expressions) --------- + gain_E = {t: [] for t in range(1, NUM_STEPS + 1)} + gain_B = {t: [] for t in range(1, NUM_STEPS + 1)} + gain_S = {t: [] for t in range(1, NUM_STEPS + 1)} + gain_C = {t: [] for t in range(1, NUM_STEPS + 1)} + cost_C = {t: [] for t in range(1, NUM_STEPS + 1)} # capital cost (collects) + cost_S = {t: [] for t in range(1, NUM_STEPS + 1)} # steel cost (upgrades b,d) + + # ---- per-city logic ----------------------------------------------- + for i in range(N): + a_step, a_type = cities[i] + + # initial type at arrival step + init = {"H": isH, "F": isF, "M": isM, "N": isMon} + m.Add(init[a_type][i, a_step] == 1) + # no upgrades at arrival + m.Add(hasA[i, a_step] == 0) + m.Add(hasB[i, a_step] == 0) + m.Add(hasD[i, a_step] == 0) + # vats at arrival + m.Add(vE[i, a_step] == 1) + m.Add(vB[i, a_step] == 1) + m.Add(vS[i, a_step] == 1) + + # before arrival: everything zero + for t in range(1, a_step): + for v in (isH, isF, isM, isMon, hasA, hasB, hasD, vE, vB, vS): + m.Add(v[i, t] == 0) + if t <= NUM_STEPS: + for v in (col, ua, ub, ud, rH, rF, rM, cvE, cvB, cvS, mE, mB, mS, mC): + m.Add(v[i, t] == 0) + + # action + transition logic for active steps + for t in range(a_step, NUM_STEPS + 1): + P = present[i, t] + ren = m.NewBoolVar("") # any renovation this step + m.Add(ren == rH[i, t] + rF[i, t] + rM[i, t]) + no_ren = m.NewBoolVar("") + m.Add(no_ren == 1 - ren) + + # exactly one action while present + m.Add( + col[i, t] + + ua[i, t] + + ub[i, t] + + ud[i, t] + + rH[i, t] + + rF[i, t] + + rM[i, t] + == P + ) + + # renovation must change type (renovate-to-X requires not-X now) + m.Add(isH[i, t] == 0).OnlyEnforceIf(rH[i, t]) + m.Add(isF[i, t] == 0).OnlyEnforceIf(rF[i, t]) + m.Add(isM[i, t] == 0).OnlyEnforceIf(rM[i, t]) + + # upgrade legality + m.Add(hasA[i, t] == 0).OnlyEnforceIf(ua[i, t]) # can't re-acquire + m.Add(hasB[i, t] == 0).OnlyEnforceIf(ub[i, t]) + m.Add(hasD[i, t] == 0).OnlyEnforceIf(ud[i, t]) + m.Add(isF[i, t] == 1).OnlyEnforceIf(ud[i, t]) # d is foundry-only + + # LLM allowed renovation into metropolis, need to prevent that now + m.Add(rM[i, t] == 0) + + # Monument constraints due to maximizing resources and not wanting enemy to get free upgrades + m.Add(col[i, t] == 0).OnlyEnforceIf(isMon[i, t]) + m.Add(ua[i, t] == 0).OnlyEnforceIf(isMon[i, t]) + m.Add(ub[i, t] == 0).OnlyEnforceIf(isMon[i, t]) + m.Add(ud[i, t] == 0).OnlyEnforceIf(isMon[i, t]) + + # ---- type transition t -> t+1 ---- + m.Add(isH[i, t + 1] == isH[i, t]).OnlyEnforceIf(no_ren) + m.Add(isF[i, t + 1] == isF[i, t]).OnlyEnforceIf(no_ren) + m.Add(isM[i, t + 1] == isM[i, t]).OnlyEnforceIf(no_ren) + for r, target in ((rH[i, t], isH), (rF[i, t], isF), (rM[i, t], isM)): + m.Add(target[i, t + 1] == 1).OnlyEnforceIf(r) + m.Add(isF[i, t + 1] == 0).OnlyEnforceIf(rH[i, t]) + m.Add(isM[i, t + 1] == 0).OnlyEnforceIf(rH[i, t]) + m.Add(isH[i, t + 1] == 0).OnlyEnforceIf(rF[i, t]) + m.Add(isM[i, t + 1] == 0).OnlyEnforceIf(rF[i, t]) + m.Add(isH[i, t + 1] == 0).OnlyEnforceIf(rM[i, t]) + m.Add(isF[i, t + 1] == 0).OnlyEnforceIf(rM[i, t]) + + # ---- upgrade transition t -> t+1 ---- + # a, b survive renovation and are monotone + m.AddMaxEquality(hasA[i, t + 1], [hasA[i, t], ua[i, t]]) + m.AddMaxEquality(hasB[i, t + 1], [hasB[i, t], ub[i, t]]) + # d is stripped on renovation, else monotone + m.Add(hasD[i, t + 1] == 0).OnlyEnforceIf(ren) + d_keep = m.NewBoolVar("") + m.AddMaxEquality(d_keep, [hasD[i, t], ud[i, t]]) + m.Add(hasD[i, t + 1] == d_keep).OnlyEnforceIf(no_ren) + + # ---- collect sub-choices ---- + fcol = AND(isF[i, t], col[i, t]) + mcol = AND(isM[i, t], col[i, t]) + hcol = AND(isH[i, t], col[i, t]) + # foundry: exactly one vat chosen iff foundry collects + m.Add(cvE[i, t] + cvB[i, t] + cvS[i, t] == fcol) + # metropolis: pick (2 + hasB) resources (+1 each); else nothing + npick = m.NewIntVar(0, 3, "") + m.Add(npick == 2 + hasB[i, t]).OnlyEnforceIf(mcol) + m.Add(npick == 0).OnlyEnforceIf(mcol.Not()) + m.Add(mE[i, t] + mB[i, t] + mS[i, t] + mC[i, t] == npick) + + # ================= COSTS ================= + # foundry & metropolis collect each cost 1 Capital + cost_C[t].append(fcol) + cost_C[t].append(mcol) + # upgrades b,d cost 2 Steel, reduced by 1 if cost-reduction (a) already held + for upg in (ub[i, t], ud[i, t]): + c = m.NewIntVar(0, 2, "") + both = AND(upg, hasA[i, t]) + m.Add(c == 2).OnlyEnforceIf(upg, hasA[i, t].Not()) + m.Add(c == 1).OnlyEnforceIf(both) + m.Add(c == 0).OnlyEnforceIf(upg.Not()) + cost_S[t].append(c) + + # ================= GAINS ================= + # Hub collect: +2 Capital (+1 more if collect-bonus b) + hub_gain = m.NewIntVar(0, 3, "") + m.Add(hub_gain == 2 + hasB[i, t]).OnlyEnforceIf(hcol) + m.Add(hub_gain == 0).OnlyEnforceIf(hcol.Not()) + gain_C[t].append(hub_gain) + + # Metropolis collect: +1 per pick + gain_E[t].append(mE[i, t]) + gain_B[t].append(mB[i, t]) + gain_S[t].append(mS[i, t]) + gain_C[t].append(mC[i, t]) + + # Foundry collect: gain chosen vat's value as that resource + gEf = m.NewIntVar(0, max_vat, "") + gBf = m.NewIntVar(0, max_vat, "") + gSf = m.NewIntVar(0, max_vat, "") + m.AddMultiplicationEquality(gEf, [cvE[i, t], vE[i, t]]) + m.AddMultiplicationEquality(gBf, [cvB[i, t], vB[i, t]]) + m.AddMultiplicationEquality(gSf, [cvS[i, t], vS[i, t]]) + gain_E[t].append(gEf) + gain_B[t].append(gBf) + gain_S[t].append(gSf) + + # Collect Bonus (b): adds +1 to the amount a Collect gives. For a + # foundry that means +1 of the collected resource (vat value + 1), + # the same uniform "+1 to what Collect gives" rule as Hub/Metro. + gain_E[t].append(AND(cvE[i, t], hasB[i, t])) + gain_B[t].append(AND(cvB[i, t], hasB[i, t])) + gain_S[t].append(AND(cvS[i, t], hasB[i, t])) + + # ---- vat update producing vat[i, t+1] ---- + # increment added to the two non-collected vats (1, or 2 with upgrade d) + inc = m.NewIntVar(1, 2, "") + m.Add(inc == 1 + hasD[i, t]) + + # vat_next = result of this step's action (only meaningful if foundry) + vEn = m.NewIntVar(0, max_vat, "") + vBn = m.NewIntVar(0, max_vat, "") + vSn = m.NewIntVar(0, max_vat, "") + # collect E: E->0, B,S += inc + m.Add(vEn == 0).OnlyEnforceIf(cvE[i, t]) + m.Add(vBn == vB[i, t] + inc).OnlyEnforceIf(cvE[i, t]) + m.Add(vSn == vS[i, t] + inc).OnlyEnforceIf(cvE[i, t]) + # collect B + m.Add(vBn == 0).OnlyEnforceIf(cvB[i, t]) + m.Add(vEn == vE[i, t] + inc).OnlyEnforceIf(cvB[i, t]) + m.Add(vSn == vS[i, t] + inc).OnlyEnforceIf(cvB[i, t]) + # collect S + m.Add(vSn == 0).OnlyEnforceIf(cvS[i, t]) + m.Add(vEn == vE[i, t] + inc).OnlyEnforceIf(cvS[i, t]) + m.Add(vBn == vB[i, t] + inc).OnlyEnforceIf(cvS[i, t]) + # foundry but not collecting (upgrade / renovate-away): vats unchanged + f_noncollect = AND(isF[i, t], col[i, t].Not()) + m.Add(vEn == vE[i, t]).OnlyEnforceIf(f_noncollect) + m.Add(vBn == vB[i, t]).OnlyEnforceIf(f_noncollect) + m.Add(vSn == vS[i, t]).OnlyEnforceIf(f_noncollect) + + # assign vat[i, t+1]: + # renovate-to-foundry -> reset to 1 + # continuing foundry -> vat_next + # otherwise (not foundry next) -> 0 + cont_F = AND(isF[i, t], no_ren) # stays a foundry next step + for vnext, vn in ( + (vE[i, t + 1], vEn), + (vB[i, t + 1], vBn), + (vS[i, t + 1], vSn), + ): + m.Add(vnext == 1).OnlyEnforceIf(rF[i, t]) + m.Add(vnext == vn).OnlyEnforceIf(cont_F) + m.Add(isF[i, t + 1] == 0).OnlyEnforceIf( + rF[i, t].Not(), cont_F.Not() + ) # tautology guard + not_F_next = isF[i, t + 1].Not() + m.Add(vE[i, t + 1] == 0).OnlyEnforceIf(not_F_next) + m.Add(vB[i, t + 1] == 0).OnlyEnforceIf(not_F_next) + m.Add(vS[i, t + 1] == 0).OnlyEnforceIf(not_F_next) + + # ---- resource pool recursion -------------------------------------- + E = {1: m.NewIntVar(initial[0], initial[0], "E1")} + B = {1: m.NewIntVar(initial[1], initial[1], "B1")} + S = {1: m.NewIntVar(initial[2], initial[2], "S1")} + C = {1: m.NewIntVar(initial[3], initial[3], "C1")} + for t in range(1, NUM_STEPS + 1): + E[t + 1] = m.NewIntVar(0, max_res, f"E_{t + 1}") + B[t + 1] = m.NewIntVar(0, max_res, f"B_{t + 1}") + S[t + 1] = m.NewIntVar(0, max_res, f"S_{t + 1}") + C[t + 1] = m.NewIntVar(0, max_res, f"C_{t + 1}") + # costs are paid from the START-of-step pool (must work out before gains) + m.Add(C[t] - sum(cost_C[t]) >= 0) + m.Add(S[t] - sum(cost_S[t]) >= 0) + # next pool = start - costs + gains + m.Add(E[t + 1] == E[t] + sum(gain_E[t])) + m.Add(B[t + 1] == B[t] + sum(gain_B[t])) + m.Add(S[t + 1] == S[t] - sum(cost_S[t]) + sum(gain_S[t])) + m.Add(C[t + 1] == C[t] - sum(cost_C[t]) + sum(gain_C[t])) + + finalE, finalB, finalS = E[NUM_STEPS + 1], B[NUM_STEPS + 1], S[NUM_STEPS + 1] + + # ---- Phase 1: real per-resource ceilings (fast LINEAR maximisations) ---- + # The triple product E*B*S has a very loose relaxation, so proving optimality + # directly is slow. We first find the true max each resource can reach on its + # own (a linear objective, solved to optimality quickly), then clamp the final + # pools to those ceilings. This tightens the product's propagation enough to + # prove optimality, and is valid because no feasible solution can exceed an + # individual resource's standalone maximum. + def _ceiling(var): + s = cp_model.CpSolver() + s.parameters.max_time_in_seconds = 20.0 + s.parameters.num_search_workers = num_workers + m.Maximize(var) + st = s.Solve(m) + return ( + int(s.ObjectiveValue()) + if st in (cp_model.OPTIMAL, cp_model.FEASIBLE) + else max_res + ) + + capE = _ceiling(finalE) + capB = _ceiling(finalB) + capS = _ceiling(finalS) + m.Add(finalE <= capE) + m.Add(finalB <= capB) + m.Add(finalS <= capS) + + # ====================================================================== + # OBJECTIVE IS SET HERE -- maximise Electrum * Brass * Steel (post step 5) + # To change the objective, edit the three "final" pools and/or the product + # below. (finalE/finalB/finalS are the pools after step 5's gains.) + # ====================================================================== + ## NOTE: product can be changed here + prodEB = m.NewIntVar(0, capE * capB, "prodEB") + m.AddMultiplicationEquality(prodEB, [finalE, finalB]) + obj = m.NewIntVar(0, capE * capB * capS, "obj") + m.AddMultiplicationEquality(obj, [prodEB, finalS]) + m.Maximize(obj) + + # ---- Phase 2: solve the product to optimality ---- + solver = cp_model.CpSolver() + solver.parameters.max_time_in_seconds = time_limit + solver.parameters.num_search_workers = num_workers + status = solver.Solve(m) + + if verbose: + print(f"(resource ceilings used: E<={capE} B<={capB} S<={capS})") + _report( + solver, + status, + cities, + N, + isH, + isF, + isM, + isMon, + col, + ua, + ub, + ud, + rH, + rF, + rM, + cvE, + cvB, + cvS, + mE, + mB, + mS, + mC, + hasA, + hasB, + hasD, + vE, + vB, + vS, + E, + B, + S, + C, + finalE, + finalB, + finalS, + ) + return solver, status + + +def _report( + solver, + status, + cities, + N, + isH, + isF, + isM, + isMon, + col, + ua, + ub, + ud, + rH, + rF, + rM, + cvE, + cvB, + cvS, + mE, + mB, + mS, + mC, + hasA, + hasB, + hasD, + vE, + vB, + vS, + E, + B, + S, + C, + finalE, + finalB, + finalS, +): + print("status:", solver.StatusName(status)) + if status not in (cp_model.OPTIMAL, cp_model.FEASIBLE): + return + typ_name = {} + for i in range(N): + for t in range(1, NUM_STEPS + 1): + if solver.Value(isH[i, t]): + typ_name[i, t] = "Hub" + elif solver.Value(isF[i, t]): + typ_name[i, t] = "Foundry" + elif solver.Value(isM[i, t]): + typ_name[i, t] = "Metro" + elif solver.Value(isMon[i, t]): + typ_name[i, t] = "Monument" + else: + typ_name[i, t] = "-" + + def action_str(i, t): + if solver.Value(col[i, t]): + if typ_name[i, t] == "Foundry": + v = ( + "E" + if solver.Value(cvE[i, t]) + else "B" + if solver.Value(cvB[i, t]) + else "S" + ) + return f"Collect vat {v}" + if typ_name[i, t] == "Metro": + picks = [] + for nm, var in (("E", mE), ("B", mB), ("S", mS), ("C", mC)): + picks += [nm] * solver.Value(var[i, t]) + return "Collect {" + ",".join(picks) + "}" + return "Collect (+Capital)" + if solver.Value(ua[i, t]): + return "Upgrade a (cost-reduction)" + if solver.Value(ub[i, t]): + return "Upgrade b (collect-bonus)" + if solver.Value(ud[i, t]): + return "Upgrade d (vat-increment)" + if solver.Value(rH[i, t]): + return "Renovate -> Hub" + if solver.Value(rF[i, t]): + return "Renovate -> Foundry" + if solver.Value(rM[i, t]): + return "Renovate -> Metro" + return "(inactive)" + + print("\nPer-step pools (start of step):") + print(" step: E B S C") + for t in range(1, NUM_STEPS + 2): + label = f"after5" if t == NUM_STEPS + 1 else f"start {t}" + print( + f" {label:>8}: {solver.Value(E[t]):3} {solver.Value(B[t]):3} " + f"{solver.Value(S[t]):3} {solver.Value(C[t]):3}" + ) + + print("\nActions:") + for i in range(N): + a_step, a_type = cities[i] + print(f" City {i} (arrives step {a_step} as {a_type}):") + for t in range(a_step, NUM_STEPS + 1): + ups = "".join( + n + for n, h in (("a", hasA), ("b", hasB), ("d", hasD)) + if solver.Value(h[i, t]) + ) + extra = ( + f" vats(E{solver.Value(vE[i, t])},B{solver.Value(vB[i, t])},S{solver.Value(vS[i, t])})" + if typ_name[i, t] == "Foundry" + else "" + ) + print( + f" step {t}: [{typ_name[i, t]:7}] {action_str(i, t):28}" + f" upg[{ups}]{extra}" + ) + + fe, fb, fs = solver.Value(finalE), solver.Value(finalB), solver.Value(finalS) + print(f"\nFINAL E={fe} B={fb} S={fs} product = {fe * fb * fs}") + + +if __name__ == "__main__": + solve() diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..08f8dde --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,9 @@ +[project] +name = "solve" +version = "0.1.0" +description = "Add your description here" +readme = "README.md" +requires-python = ">=3.13" +dependencies = [ + "ortools>=9.15.6755", +] diff --git a/uv.lock b/uv.lock new file mode 100644 index 0000000..35f6311 --- /dev/null +++ b/uv.lock @@ -0,0 +1,217 @@ +version = 1 +revision = 3 +requires-python = ">=3.13" +resolution-markers = [ + "python_full_version >= '3.14' and sys_platform == 'win32'", + "python_full_version >= '3.14' and sys_platform == 'emscripten'", + "python_full_version >= '3.14' and sys_platform != 'emscripten' and sys_platform != 'win32'", + "python_full_version < '3.14' and sys_platform == 'win32'", + "python_full_version < '3.14' and sys_platform == 'emscripten'", + "python_full_version < '3.14' and sys_platform != 'emscripten' and sys_platform != 'win32'", +] + +[[package]] +name = "absl-py" +version = "2.4.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/64/c7/8de93764ad66968d19329a7e0c147a2bb3c7054c554d4a119111b8f9440f/absl_py-2.4.0.tar.gz", hash = "sha256:8c6af82722b35cf71e0f4d1d47dcaebfff286e27110a99fc359349b247dfb5d4", size = 116543, upload-time = "2026-01-28T10:17:05.322Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/18/a6/907a406bb7d359e6a63f99c313846d9eec4f7e6f7437809e03aa00fa3074/absl_py-2.4.0-py3-none-any.whl", hash = "sha256:88476fd881ca8aab94ffa78b7b6c632a782ab3ba1cd19c9bd423abc4fb4cd28d", size = 135750, upload-time = "2026-01-28T10:17:04.19Z" }, +] + +[[package]] +name = "immutabledict" +version = "4.3.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/1d/e6/718471048fea0366c3e3d1df3acfd914ca66d571cdffcf6d37bbcd725708/immutabledict-4.3.1.tar.gz", hash = "sha256:f844a669106cfdc73f47b1a9da003782fb17dc955a54c80972e0d93d1c63c514", size = 7806, upload-time = "2026-02-15T10:32:34.668Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a3/ce/f9018bf69ae91b273b6391a095e7c93fa5e1617f25b6ba81ad4b20c9df10/immutabledict-4.3.1-py3-none-any.whl", hash = "sha256:c9facdc0ff30fdb8e35bd16532026cac472a549e182c94fa201b51b25e4bf7bf", size = 5000, upload-time = "2026-02-15T10:32:33.672Z" }, +] + +[[package]] +name = "numpy" +version = "2.4.6" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/d0/ad/fed0499ce6a338d2a03ebae59cd15093910c8875328855781952abf6c2fe/numpy-2.4.6.tar.gz", hash = "sha256:f3a3570c4a2a16746ac2c31a7c7c7b0c186b95ce902e33db6f28094ed7387dda", size = 20735807, upload-time = "2026-05-18T23:37:14.07Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/fb/82/bdab26d7438c6791ca31b7c024ca37c1eab8b726ba236129005cd4a06e45/numpy-2.4.6-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:511dbaf848decaaaf4b4ca48032619fb3138710c4bf7da7617765edad1ef96b0", size = 16684648, upload-time = "2026-05-18T23:34:29.41Z" }, + { url = "https://files.pythonhosted.org/packages/1b/30/a80189bcc7f5e4258b3fbc3968d909d1756f54d023299ecc39ad6fdb9ef8/numpy-2.4.6-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:bf162abab1c1a736333192707cef898e735a5ca00f38f27eeedf44b39d9e85eb", size = 14693902, upload-time = "2026-05-18T23:34:33.013Z" }, + { url = "https://files.pythonhosted.org/packages/97/12/70b5d0d7c15e1ebb8a6a84a8caa1d19e181d84fb58bb6d70aca29099dec1/numpy-2.4.6-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:043191bfa8eab18c776647b62723ac9dddece59743b13f49b2016094129c2b3f", size = 5198992, upload-time = "2026-05-18T23:34:36.132Z" }, + { url = "https://files.pythonhosted.org/packages/ba/8c/ebd2a8f8a83541f8d38cc5667e8c2b69cecfd30da6e45693e8158857d44b/numpy-2.4.6-cp313-cp313-macosx_14_0_x86_64.whl", hash = "sha256:6180d8b35af935aed8ece3a85e0a43f87393ae0ac87c8d2c8bd2c993f7270ef3", size = 6546944, upload-time = "2026-05-18T23:34:38.484Z" }, + { url = "https://files.pythonhosted.org/packages/bb/c5/7b863a97a91671a0338f4253bd3b5a3d3852f0692dae91711c9f4a10e787/numpy-2.4.6-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:72fbe16c6fac95aedf5937fa873445cec2110be35d8a4e9433d7501fd98dae6b", size = 15669392, upload-time = "2026-05-18T23:34:41.257Z" }, + { url = "https://files.pythonhosted.org/packages/a5/9d/3584b9984ca4c047aea75214ce1a4c4c73d849bd71b604264b7f5653f8a8/numpy-2.4.6-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a7830bab239b79cda9c08c2da014761cafb48da6150e1da17ac06283f43b6089", size = 16633220, upload-time = "2026-05-18T23:34:45.075Z" }, + { url = "https://files.pythonhosted.org/packages/05/ae/7c67fba23bd98caec7c99261f3a16072ade14813486b0282cb29846de832/numpy-2.4.6-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:ef4aea96ce4d3b074422cb4f2f64e216bf9e213004bb58ecfdf50ea02ea8eb9a", size = 17020800, upload-time = "2026-05-18T23:34:49.065Z" }, + { url = "https://files.pythonhosted.org/packages/d9/5d/3b6725cb31d983c5e66916f5d36f6d7e5521129e4c4404d64f918292a5b6/numpy-2.4.6-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:dfa20cc6ca228e6b155b11da03825975ce66aea520985dbbddf0f2a5a495c605", size = 18357600, upload-time = "2026-05-18T23:34:52.709Z" }, + { url = "https://files.pythonhosted.org/packages/f7/da/2ccc6c2fe8898dee01d90c75c5f5f914a23daf99e3e0f59516a08760c8b5/numpy-2.4.6-cp313-cp313-win32.whl", hash = "sha256:56b39e5e0622a09a25bf5baf62f4bcf0cb8a41ae6e2819cf49bbc5a74c083f91", size = 5961134, upload-time = "2026-05-18T23:34:55.618Z" }, + { url = "https://files.pythonhosted.org/packages/b5/cd/9cc4dc876fb065d5c220aae4d5e14826b2715331bb7618ce1fb07a679d99/numpy-2.4.6-cp313-cp313-win_amd64.whl", hash = "sha256:c4fc99836233ea196540b17ab0983aff60ed07941751930f5f4d05bc3b3b7359", size = 12318598, upload-time = "2026-05-18T23:34:58.928Z" }, + { url = "https://files.pythonhosted.org/packages/39/1e/c0bcba1f8694116485fe28fd1be698c278fcda4141c5b0e53a2aed8b12a8/numpy-2.4.6-cp313-cp313-win_arm64.whl", hash = "sha256:a7c711e21628b52034bb5ab8d1bce291f752fcc5e92accc615778acee1ff4778", size = 10222272, upload-time = "2026-05-18T23:35:02.167Z" }, + { url = "https://files.pythonhosted.org/packages/63/6d/cc5619247c8f4204e507f5883528372e4ac4bb189e579fb859a12e480b1f/numpy-2.4.6-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:112b06a867b235ef466ed3508ddf0238050df9c727cafb5301ac385b899189a1", size = 14821197, upload-time = "2026-05-18T23:35:05.468Z" }, + { url = "https://files.pythonhosted.org/packages/00/58/f1c39161c87d9e9bed660f1ed4bafc0e403d5ec9650b6dd77aead07d489b/numpy-2.4.6-cp313-cp313t-macosx_14_0_arm64.whl", hash = "sha256:eaf7fa2de5c0be8ae6ff8e9bea2ccd725e980541244521d8d4b5f3354a27babe", size = 5326287, upload-time = "2026-05-18T23:35:08.693Z" }, + { url = "https://files.pythonhosted.org/packages/af/57/3917ab0fd97f271a8694513581b8a36c655f111c446852c302f04ccdb6fc/numpy-2.4.6-cp313-cp313t-macosx_14_0_x86_64.whl", hash = "sha256:7265a2f3d436e54ef9f2b52b5c937e6be778781bd97a590319d7348f1c1ca997", size = 6646763, upload-time = "2026-05-18T23:35:11.459Z" }, + { url = "https://files.pythonhosted.org/packages/eb/0f/037e64c494b67581ae18193d770adef354c41f3f2c8ebf865602d949bf8f/numpy-2.4.6-cp313-cp313t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f74a575920ab21fe304421a3fc28793d82e299cae9eccb37084e9fc7f3617c20", size = 15728070, upload-time = "2026-05-18T23:35:14.79Z" }, + { url = "https://files.pythonhosted.org/packages/21/a6/5d2bae9c9542eb4df16dc9c46dc79c186e9bad53805dfa5399a6023c6db0/numpy-2.4.6-cp313-cp313t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ede83e07a75dd06bc501566c1eca2afc0d61677c1472ac9ad93fdee6e638a48d", size = 16681752, upload-time = "2026-05-18T23:35:18.836Z" }, + { url = "https://files.pythonhosted.org/packages/92/14/23d1dfb410ae362cd59ce53e936b1513d545eb40db3949ced632e19a459e/numpy-2.4.6-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:68bb27509ac1b9a3443094260f6326150663b06abe40b73a2f81160623da5b67", size = 17086024, upload-time = "2026-05-18T23:35:22.52Z" }, + { url = "https://files.pythonhosted.org/packages/4b/6e/23595a2c642cdf3bc567877064bdd7f91c8b0038a4453cf2daf7248eafe9/numpy-2.4.6-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:a0df0043bdb289bde1f62da130d20df23d58b45429f752bc7a8fc5325a225ecd", size = 18403398, upload-time = "2026-05-18T23:35:26.398Z" }, + { url = "https://files.pythonhosted.org/packages/8a/90/0ac3bc947217e66dec77e7cbc6a1979d1af70b6461b82f620d3bccd5e4c8/numpy-2.4.6-cp313-cp313t-win32.whl", hash = "sha256:29a287e0cf63ff528da061de6b9f64a4618da591ca1046aafc54062e40ca7eab", size = 6084971, upload-time = "2026-05-18T23:35:29.387Z" }, + { url = "https://files.pythonhosted.org/packages/77/71/5673e351671a1d2bd6063b91b44f70c0affea7d1516fa7a6572941ba4aa1/numpy-2.4.6-cp313-cp313t-win_amd64.whl", hash = "sha256:25c692919ac5a01f170a3bfcd62d745b24fd095c353d50812637d6fcab442e75", size = 12458532, upload-time = "2026-05-18T23:35:32.175Z" }, + { url = "https://files.pythonhosted.org/packages/3f/88/19d3503c5046e688f049274b27a3ef3d771152fa80d3ba3d01a3dff61abe/numpy-2.4.6-cp313-cp313t-win_arm64.whl", hash = "sha256:1e978ec1e8bd0e0e4de6bb75de9d30cbb74db6b6a2bb727618613703ca0167dd", size = 10291881, upload-time = "2026-05-18T23:35:35.465Z" }, + { url = "https://files.pythonhosted.org/packages/f8/91/3ab2044d05fd16d343c5ac2e69b127f1b2854040dd20b193257c78028bd3/numpy-2.4.6-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:06ca2f61ec4385a07a6977c55ba998a4466c123642b4a32694d3128fce18c079", size = 16683458, upload-time = "2026-05-18T23:35:38.353Z" }, + { url = "https://files.pythonhosted.org/packages/8e/62/764ce66fa4147ae6d73071a3abf804ffe606f174618697c571acdf26a7c9/numpy-2.4.6-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:38efbc8de75c7a0fc1ac190162d892787f3f47b57cc291231aafee36b80982b7", size = 14704559, upload-time = "2026-05-18T23:35:42.14Z" }, + { url = "https://files.pythonhosted.org/packages/60/61/23f27c172f022e04025b7dc2367f4d63c1a398120607ec896228649a6f48/numpy-2.4.6-cp314-cp314-macosx_14_0_arm64.whl", hash = "sha256:d581b735e177fdcdce6fed8e7e8880a3fb6ee4e3653a3ac6af01c6f4c03effc5", size = 5209716, upload-time = "2026-05-18T23:35:45.377Z" }, + { url = "https://files.pythonhosted.org/packages/03/71/21cf70dc6ea3e3acb95fc53a265b2fc248b981f0194ceb5b475271b8809d/numpy-2.4.6-cp314-cp314-macosx_14_0_x86_64.whl", hash = "sha256:0a041d3d761dc3c35cc56ce0351506a02bcbc25f7b169f652435141a17db9096", size = 6543947, upload-time = "2026-05-18T23:35:47.926Z" }, + { url = "https://files.pythonhosted.org/packages/d5/91/64288395ee1799bd2e0b04a305dce9666da90c961e1f3fe982a05ee1c036/numpy-2.4.6-cp314-cp314-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:40fdc1ae7125e518ea98e53e69a4ebc27e1fd50510c47b7ea130cf21e5e1d42b", size = 15685197, upload-time = "2026-05-18T23:35:50.863Z" }, + { url = "https://files.pythonhosted.org/packages/f3/eb/ebffaa97dc55502df69584a8f0dcf07f69a3e0b3e2323670a2722db9aa39/numpy-2.4.6-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a2c306dea656c12c68f51f4cea133cbe78ca7435eb28c735eac1d3ebe73be6e8", size = 16638245, upload-time = "2026-05-18T23:35:54.752Z" }, + { url = "https://files.pythonhosted.org/packages/b8/0b/54f9da33128d7e350fab89c7455902eeae70349ee52bddb448dc4a576f45/numpy-2.4.6-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:33111801a01c12a8a1e3721f0a9232f8cfc8ae2c6b7098167e6f623c6073f402", size = 17036587, upload-time = "2026-05-18T23:35:58.355Z" }, + { url = "https://files.pythonhosted.org/packages/b6/f0/fdebc1052db1cc37c64beb22072d67cd6d1c71adca1299f53dec2b5e20d3/numpy-2.4.6-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:ae506e6902902557576a26ff33eda8695e7ecb3cb36c3b573a0765dee114ebdb", size = 18363226, upload-time = "2026-05-18T23:36:02.845Z" }, + { url = "https://files.pythonhosted.org/packages/aa/b4/298628d98c72b57e57f7165ae6a481a1deaf6f3c28262a6e4c739c275930/numpy-2.4.6-cp314-cp314-win32.whl", hash = "sha256:aaf159caa35993cb1f56fb9b8e4610d35758e7ca005412eb1daa856a78c9c4b1", size = 6010196, upload-time = "2026-05-18T23:36:05.92Z" }, + { url = "https://files.pythonhosted.org/packages/df/ac/46de6dda46478f7942f839e094970be2d4a861e005c4b3bf07c92e291a09/numpy-2.4.6-cp314-cp314-win_amd64.whl", hash = "sha256:b507f5c4c1d508876d1819b6bf9a49d365b96320b5d4993426b33a23ca4b8261", size = 12450334, upload-time = "2026-05-18T23:36:09.107Z" }, + { url = "https://files.pythonhosted.org/packages/78/92/b8b798ac784102c0da830d2257d59358e3d3d90d1e2b3f2575dad976c5cf/numpy-2.4.6-cp314-cp314-win_arm64.whl", hash = "sha256:6f41ae150c4e32db4f3310cdaf64b1593a03dbabe29eec77fc9b50fe64061df6", size = 10495678, upload-time = "2026-05-18T23:36:12.766Z" }, + { url = "https://files.pythonhosted.org/packages/30/34/ec28d1aa8115971537c01469ab2011ee96827930f0a124de1000cc2a7ed7/numpy-2.4.6-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:ece3d2cfe132e7d51f44a832b303895e6f2d499c5e74dfbdb06ee246147a304a", size = 14823672, upload-time = "2026-05-18T23:36:16.473Z" }, + { url = "https://files.pythonhosted.org/packages/16/bd/f6d1fede4e54e8042a7ff97bb495510f3c220f94bcd9e8b228e87c92cc0d/numpy-2.4.6-cp314-cp314t-macosx_14_0_arm64.whl", hash = "sha256:e3e5193ef5a3dc73bceee50f7fdc2c90dbb76c42df8d8fae3d1067a583df579e", size = 5328731, upload-time = "2026-05-18T23:36:19.767Z" }, + { url = "https://files.pythonhosted.org/packages/f4/f0/e105b9e2fd728a9910103884decd6951d9dd73896b914a98d9a231de02ee/numpy-2.4.6-cp314-cp314t-macosx_14_0_x86_64.whl", hash = "sha256:17f9ade344e7d9b464a084d69bcf18fc691cb1db67c62ed80820bf4926d78f0e", size = 6649805, upload-time = "2026-05-18T23:36:22.266Z" }, + { url = "https://files.pythonhosted.org/packages/82/dd/1206a7ca6ab15e3f02069707ca96222e202af681bb73756da7527f3cb837/numpy-2.4.6-cp314-cp314t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9cd5ffd25db4e7ba6a375693b3fc0fc1791ec636c17db3720da19bde7180ec43", size = 15730496, upload-time = "2026-05-18T23:36:25.713Z" }, + { url = "https://files.pythonhosted.org/packages/51/e7/38d3ea825dcab85a591734decb2f6c67caa7c8367d374df1a1c3842f9b07/numpy-2.4.6-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7d92c3819208a60205a12a245c91ad70cb0a85336659b19b834205573ac8456e", size = 16679616, upload-time = "2026-05-18T23:36:29.652Z" }, + { url = "https://files.pythonhosted.org/packages/93/b7/caabfdf53edf663e0b4eb74d7d405d83baef09eb5e83bcd32d601d72b93e/numpy-2.4.6-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:e85b752a1e912b70eaad4fafbd4d1238007ab221de2009b9a2f5ae7461239895", size = 17085145, upload-time = "2026-05-18T23:36:33.449Z" }, + { url = "https://files.pythonhosted.org/packages/f9/45/68d7c33a6bcf3e5aa3bdbd57a367e6f615286dfd6482f97e8ffeb734306e/numpy-2.4.6-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:29cb7f67d10b479ff07c17d33e39f78c07f71c40ef30d63c153d340e96cd3fb4", size = 18403813, upload-time = "2026-05-18T23:36:37.369Z" }, + { url = "https://files.pythonhosted.org/packages/9c/50/0753655aa844c99cd9e018aacf76f130f1bd81d881bb74bc0aef5d73a8ba/numpy-2.4.6-cp314-cp314t-win32.whl", hash = "sha256:260a5d70215b61ab4fadf5c7baacd64821842975eea312125ed3c39a6391b063", size = 6156982, upload-time = "2026-05-18T23:36:40.817Z" }, + { url = "https://files.pythonhosted.org/packages/b2/d4/7c67becf668f973cb490cec3e98dfd799d866f9c989a54d355672cfa0db6/numpy-2.4.6-cp314-cp314t-win_amd64.whl", hash = "sha256:81a1cca95ed5bb92aa8b10dd2cdc9a0d3853a50fad926c28b5d7e8ea54389627", size = 12638908, upload-time = "2026-05-18T23:36:43.996Z" }, + { url = "https://files.pythonhosted.org/packages/43/bb/e1c71a4295b1b1d1393d50dbb4f2a36283c6859d9d3892e84f00ec5a91d5/numpy-2.4.6-cp314-cp314t-win_arm64.whl", hash = "sha256:0c9136e14ed34a9e343a31c533d78a9813a69a3148332bce5e9821cb2f996e66", size = 10565867, upload-time = "2026-05-18T23:36:47.114Z" }, +] + +[[package]] +name = "ortools" +version = "9.15.6755" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "absl-py" }, + { name = "immutabledict" }, + { name = "numpy" }, + { name = "pandas" }, + { name = "protobuf" }, + { name = "typing-extensions" }, +] +wheels = [ + { url = "https://files.pythonhosted.org/packages/f1/53/e21c54ff10002cc2e2b9748012ffc324ec32ea4acdcc85e190a920ab2766/ortools-9.15.6755-cp313-cp313-macosx_10_15_x86_64.whl", hash = "sha256:27a10474e62c9dceed37cfa0e4845c5ffaf792138ebf5b61483771b96f1290b6", size = 23927705, upload-time = "2026-01-14T15:39:07.29Z" }, + { url = "https://files.pythonhosted.org/packages/ce/e6/f7019048ffdf41f8a1bff6815b2203cf7b9117ba9e26bf46c4585421d1c4/ortools-9.15.6755-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:076565b803c85c4f87863e0616f537dd37f99c03e6f092e4068404f7b425d2b0", size = 21914246, upload-time = "2026-01-14T15:39:10.584Z" }, + { url = "https://files.pythonhosted.org/packages/8d/ad/aaacd340918b03e22c42f6ae4a9c72aac09810b4b398e99a7eeee58d9c42/ortools-9.15.6755-cp313-cp313-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b85bd20259b146abce5e0721ce1bfd8fd273efc904216aa3be178c31b6d34057", size = 27646600, upload-time = "2026-01-14T15:38:04.79Z" }, + { url = "https://files.pythonhosted.org/packages/08/b9/28d5efb832190b6edfccc5a703e88e64779c1eda34a42ea96d03307236c0/ortools-9.15.6755-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ebd5aea00374e3aad7a78de59058aca5e871a26a3c385cd0860ef1d685d03c9a", size = 29838741, upload-time = "2026-01-14T15:38:07.945Z" }, + { url = "https://files.pythonhosted.org/packages/be/22/ab894b6f846b4b1a89795c1ba966834e56cac394c4cf2b72433909739982/ortools-9.15.6755-cp313-cp313-win_amd64.whl", hash = "sha256:caac1d48b967adb877da2abcaf82c28f0f908a7cc208a6a1bbe01bc69590816c", size = 23908100, upload-time = "2026-01-14T15:39:48.398Z" }, + { url = "https://files.pythonhosted.org/packages/a3/53/ada4146ae491d7798c6eb045d93135158c0b66030853c7cd9607768dda59/ortools-9.15.6755-cp313-cp313t-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:82b4a8e6e4f9380b453ab5fa4382ea7ee91e628f9b8be89d9ad760b33fca3323", size = 27681510, upload-time = "2026-01-14T15:38:11.033Z" }, + { url = "https://files.pythonhosted.org/packages/32/e6/239e96912fc8c4e0e917e72ec413983bc042cd9a0b20c3c6a7e43fc3002b/ortools-9.15.6755-cp313-cp313t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2d1f2fb2088e8953ccb902e68ffd06032cce0c7dcf7268b6135f3b6c553ca52b", size = 29850935, upload-time = "2026-01-14T15:38:14.595Z" }, + { url = "https://files.pythonhosted.org/packages/53/ef/53a172ad12cf0d762b9a5af681b1f13f1b4105b38bf65c2b383d530ed97f/ortools-9.15.6755-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:acdf06a167933307608e7eba23a9490255933504df44c8de5f62c48656c29688", size = 23916963, upload-time = "2026-01-14T15:39:13.282Z" }, + { url = "https://files.pythonhosted.org/packages/13/54/ed73ec00369fb6d6c71049d62e4b7c87c918b61f86ddd55a11c20ada395e/ortools-9.15.6755-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:1a0677270b0cd317a6b8dae42514264eaf5da5756c5bc7215eeea409424577df", size = 21923649, upload-time = "2026-01-14T15:39:16.831Z" }, + { url = "https://files.pythonhosted.org/packages/1c/e0/ac57dd43eaadd73748bb542b30912e16c7dbf3a75f393f69efb8a1a2f032/ortools-9.15.6755-cp314-cp314-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:899b92afe3f775ab5867b9a8aa2850f81f2d95232db9b4ceec3456d69e6b8528", size = 27657273, upload-time = "2026-01-14T15:38:18.375Z" }, + { url = "https://files.pythonhosted.org/packages/b2/e0/11144feb4ddadc491dc9d833d3a2080e6556245f912bebe2c0c7e174f2a1/ortools-9.15.6755-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7181183cdcafe2b0d83ca5505b65048c7953dc7b5ad479361dded607964cc1b3", size = 29843939, upload-time = "2026-01-14T15:38:21.457Z" }, + { url = "https://files.pythonhosted.org/packages/96/97/771515ba3a05da3903b7da55a190d9f88f36a08c4bf848852e0ea4e3a731/ortools-9.15.6755-cp314-cp314-win_amd64.whl", hash = "sha256:afabb869e5fabeb704bd8147b22bf8139dee042e55fabd0d447a996428009e0c", size = 24673633, upload-time = "2026-01-14T15:39:51.212Z" }, + { url = "https://files.pythonhosted.org/packages/46/99/0932d6d7d6ad326adf68f4ce9063ef07db7e9859859dddbcd200102aedff/ortools-9.15.6755-cp314-cp314t-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d9d07cddca201e25e2e219006a9d6cda10c7e9ee2c712c50d19d508f9ed8a888", size = 27682088, upload-time = "2026-01-14T15:38:25.174Z" }, + { url = "https://files.pythonhosted.org/packages/0e/4d/bd75961e2c82db69bb41dd2c4a82131ca580e997485be2d5f59f8d26f31e/ortools-9.15.6755-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:990838ad66a052e72a50e69da500878710e3420e91717fe88bf3071995caba9e", size = 29851493, upload-time = "2026-01-14T15:38:28.168Z" }, +] + +[[package]] +name = "pandas" +version = "3.0.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "numpy" }, + { name = "python-dateutil" }, + { name = "tzdata", marker = "sys_platform == 'emscripten' or sys_platform == 'win32'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/f8/87/4341c6252d1c47b08768c3d25ac487362bf403f0313ddae4a2a26c9b1b4c/pandas-3.0.3.tar.gz", hash = "sha256:696a4a00a2a2a35d4e5deb3fc946641b96c944f02230e4f76137fe35d806c4fc", size = 4651414, upload-time = "2026-05-11T18:54:29.21Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c5/90/62d8302883c44308c477e222c3daf7c813a34c8e96985882fbd53d964352/pandas-3.0.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:67b3b64c11910cfa29f4e94a14d3bff9ee693b6fc76055e7cad549cee0aec5fa", size = 10331071, upload-time = "2026-05-11T18:52:58.838Z" }, + { url = "https://files.pythonhosted.org/packages/7f/ae/6a6493c783a101f165e4356953ba3c74d6f77f0042fa7d753da9dfbb640c/pandas-3.0.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:39436b377d56d2a2e52d0395bdbee171f01068e99af5250509aceeb929f765c7", size = 9875690, upload-time = "2026-05-11T18:53:01.431Z" }, + { url = "https://files.pythonhosted.org/packages/62/7c/5df8e9f56c69a2769fbe9382a5ef8f2658c007e376434e1e2cbb57ad895f/pandas-3.0.3-cp313-cp313-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d4be06d68f9ddcfc645b87534911da79a8fbffc7573c80e0edcf42a5020624d8", size = 10381634, upload-time = "2026-05-11T18:53:04.393Z" }, + { url = "https://files.pythonhosted.org/packages/99/68/1237369725aa617bb358263d535803e3053fdbc593513ec5ed9c9896b5b6/pandas-3.0.3-cp313-cp313-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a4eeb6830daf35a71cc09649bd823e2b542dac246cdee9614c6e4bd65028cd6a", size = 10891243, upload-time = "2026-05-11T18:53:07.643Z" }, + { url = "https://files.pythonhosted.org/packages/25/93/77d108e8af7222b4a503ebde0e30215b1c2e4f8e53a526431890f22d5586/pandas-3.0.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:1928e07221f82db493cd4af1e23c1bfca524a19a4699887975bff68f49a72bfb", size = 11388659, upload-time = "2026-05-11T18:53:10.634Z" }, + { url = "https://files.pythonhosted.org/packages/d0/bd/eff5b4399f332ac386c853f6cd2bd3fa2ca0061b9f36ecd9c4d7c4265649/pandas-3.0.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:51b1fe551acb77dac643c6fda86084d8d446c10fe64b06a9cc29c4cc8540e7f2", size = 11942880, upload-time = "2026-05-11T18:53:13.536Z" }, + { url = "https://files.pythonhosted.org/packages/2c/20/559ace4200982c3887d0b86bfd0d856a2143ef8ddab63cc07934951a964c/pandas-3.0.3-cp313-cp313-win_amd64.whl", hash = "sha256:a82d532a3351d435432cd913edbccaf8b8e01d4dd0e5ced5a8d2e8ecd94c7e44", size = 9757091, upload-time = "2026-05-11T18:53:16.306Z" }, + { url = "https://files.pythonhosted.org/packages/3a/66/69055a09fe200f29f922a3eeec4804611900b95f52d932ece3393c3c0c19/pandas-3.0.3-cp313-cp313-win_arm64.whl", hash = "sha256:275c14e0fce14a2ec20eee474aecd305478ea3c1e6f6a9d8fe219a165542717e", size = 9057282, upload-time = "2026-05-11T18:53:18.768Z" }, + { url = "https://files.pythonhosted.org/packages/57/0e/efe801b0e6811e8e650cd21b7f2608e30f08a7067e2bf6e8752b0d56ee3c/pandas-3.0.3-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:46997386d528eb40376ecd6b033cf4a8a1e5282580f68f43de875b78cba2199d", size = 10767016, upload-time = "2026-05-11T18:53:21.227Z" }, + { url = "https://files.pythonhosted.org/packages/ea/dc/eb55135a1d5f0f0519f28da1f609a206d2cad1f9c35c32d51e38dd7261ae/pandas-3.0.3-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:261e308dfb22448384b7580cf719d2f998fe2966c92893c3e77d14008af1f066", size = 10420210, upload-time = "2026-05-11T18:53:23.982Z" }, + { url = "https://files.pythonhosted.org/packages/c6/3e/b1d5d955ce33ffecb407465a60bc32769d74fcf68224b7ae67ae11d4dea4/pandas-3.0.3-cp313-cp313t-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:dd1a5d1def6a46002e964510bdc67c368aa0951df5d1d9f8365336f5a1f490cd", size = 10336126, upload-time = "2026-05-11T18:53:26.731Z" }, + { url = "https://files.pythonhosted.org/packages/f5/76/a01261711ab60a22d71b862f0de20e4c504bf80457270ad8cb42110f6abc/pandas-3.0.3-cp313-cp313t-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d72828c20c6d6e83e1e22a6a3b47b326b71664112fa9705dcbccfd7a39b62085", size = 10728051, upload-time = "2026-05-11T18:53:29.125Z" }, + { url = "https://files.pythonhosted.org/packages/e9/21/ea191195e587b18cf682e97f433f81b2d0fbe341380e80a3e0d6e4403c8e/pandas-3.0.3-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:d26cbe1fcfc12e8fd900e2454163e466b2d3af84f7c75481df7683ffc073d870", size = 11350796, upload-time = "2026-05-11T18:53:32.056Z" }, + { url = "https://files.pythonhosted.org/packages/64/69/f0eaaf54939f0e8c6768fd06be9af2cef9b36048b96dfb9e1b2c685a807e/pandas-3.0.3-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:3e91cec1879ada0624fc3dc9953c5cbd60208e59c0db28f540c5d6d47502422f", size = 11799741, upload-time = "2026-05-11T18:53:34.985Z" }, + { url = "https://files.pythonhosted.org/packages/45/a4/865e0e510cae5fc2194de4db28be638952de942571ba9125934fd9c01d47/pandas-3.0.3-cp313-cp313t-win_amd64.whl", hash = "sha256:08d789b41f87e0905880e293cedf6197ce71fe67cc081358b1e148a491b9bd13", size = 10499958, upload-time = "2026-05-11T18:53:37.857Z" }, + { url = "https://files.pythonhosted.org/packages/86/54/effdcc3c0ff7a08037889200e148ebe94c16c4f653be078c7b3675955df1/pandas-3.0.3-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:3650109c0f22879df8bd6179ab9ee3d7f1d1d4e7e0094a3f0032d9f51e2e64ac", size = 10336065, upload-time = "2026-05-11T18:53:41.099Z" }, + { url = "https://files.pythonhosted.org/packages/68/10/bf2d6738d72748b961a3751ab89522d58c54efc36a8e1a12161216cd45cf/pandas-3.0.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:bab900348131a7db1f69a7309ef141fd5680f1487094193bcbbb61791573bf8f", size = 9926101, upload-time = "2026-05-11T18:53:43.515Z" }, + { url = "https://files.pythonhosted.org/packages/ae/e9/e35cf11c8a136e757b956f5f0efdcaa50aecde85ea055f1898dfc68262f3/pandas-3.0.3-cp314-cp314-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ba7e08b9ac1d54569cd1e256e3668975ed624d6826f7b68df0342b012007bddb", size = 10457553, upload-time = "2026-05-11T18:53:46.394Z" }, + { url = "https://files.pythonhosted.org/packages/58/3b/1cdec6772bdbaf7b25dab360c59f03cadf05492dd724c6540af905389b07/pandas-3.0.3-cp314-cp314-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9d71c63ae4ebdbf70209742096f1fc46a83a0613c99d4b23766cced9ff8cd62a", size = 10914065, upload-time = "2026-05-11T18:53:49.134Z" }, + { url = "https://files.pythonhosted.org/packages/c4/c2/1ef644445fcd72e3627bceec77e3560636f87ddce4ed841afe76b83b5bf9/pandas-3.0.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:e3a2ec42c98ffa2565a67e08e218d06d72576d758d90facb7c00805194d8f360", size = 11459188, upload-time = "2026-05-11T18:53:52.527Z" }, + { url = "https://files.pythonhosted.org/packages/7e/49/4d8d4f42cbc9c4adc7a1870f269c02cbd6cd40d059622c06fb298addcbad/pandas-3.0.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:335f62418ed562cfc3c49e9e196375c28b729dcef8543abf4f9438e381bf3c76", size = 11982966, upload-time = "2026-05-11T18:53:55.043Z" }, + { url = "https://files.pythonhosted.org/packages/38/55/792619469bab9882d8bbd5865d45a72f6478762d04a9af4bf0d08c503e95/pandas-3.0.3-cp314-cp314-win_amd64.whl", hash = "sha256:3c20a521bbb85902f79f7270c80a59e1b5452d96d170c034f207181870f97ac5", size = 9876755, upload-time = "2026-05-11T18:53:58.067Z" }, + { url = "https://files.pythonhosted.org/packages/2a/af/33c469653b0ba03b50c3a98192d4c07f0c75c66b263ceb097fce0ee97d31/pandas-3.0.3-cp314-cp314-win_arm64.whl", hash = "sha256:a2d2dff8a04f3917b55ab3910c32990f8ddf7eceba114947838cefa976a68977", size = 9198658, upload-time = "2026-05-11T18:54:00.733Z" }, + { url = "https://files.pythonhosted.org/packages/a2/fa/b8c257bd76b8bd060c3a9151c1fca05e9b9c5e3af5d0f549c0356f6d143d/pandas-3.0.3-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:0d589105b3c14645af1738ff279b2995102d8f7a03b0a66dc8d95550eb513e04", size = 10787242, upload-time = "2026-05-11T18:54:03.564Z" }, + { url = "https://files.pythonhosted.org/packages/54/eb/f19206ffb0bf1919002969aa448b4702c6594845156a6f8050674855aac3/pandas-3.0.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:13fc1e853d9e04743d11ba75a985ccbc2a317fe07d8af61e445a6fd24dacd6a6", size = 10436369, upload-time = "2026-05-11T18:54:06.311Z" }, + { url = "https://files.pythonhosted.org/packages/fd/24/c7c39fb4fe22b71a0c2d78bf0c585c600092d85f94f086d2b3b2f6ca27e2/pandas-3.0.3-cp314-cp314t-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:819959dab7bbd0049c15623fbac4e29a191b9528160a61fb1032242d8ced2d9c", size = 10358306, upload-time = "2026-05-11T18:54:09.085Z" }, + { url = "https://files.pythonhosted.org/packages/16/ec/dd2a9eb7fa1204df88c0864164e35b228ac581062ac612ba0a67fd812e4c/pandas-3.0.3-cp314-cp314t-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:60ae316d3fd75d1858d450d0db0103ea2be3e7d4a95ec2f064f7e2ae63f7b028", size = 10758394, upload-time = "2026-05-11T18:54:11.956Z" }, + { url = "https://files.pythonhosted.org/packages/95/6e/00c61ea8e85b4f6d8d35e11852a1a4998fc7fafc91c6a602d1cc9c972d64/pandas-3.0.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:bd3a518890b400d32f9023722dc9a9a5c969f00b415419a3c06c043f09bb5d7d", size = 11375717, upload-time = "2026-05-11T18:54:14.539Z" }, + { url = "https://files.pythonhosted.org/packages/31/89/8fc1c268969fac43688d65fd92e67df24bd128d53cb4d2eee534cd307399/pandas-3.0.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:9c39be2d709d01fa972a0cabc522389fceca4f3969332ba25a7d6c5802cf976a", size = 11828897, upload-time = "2026-05-11T18:54:17.146Z" }, + { url = "https://files.pythonhosted.org/packages/56/3b/e7d20dea247a3e6dc0bd8a6953854afbedc03951def4e7371e05e7263e25/pandas-3.0.3-cp314-cp314t-win_amd64.whl", hash = "sha256:4db8c527972a821cf5286b40ccc57642a39bc62e62022b42f99f8a67fca8c3a1", size = 10900855, upload-time = "2026-05-11T18:54:19.72Z" }, + { url = "https://files.pythonhosted.org/packages/0f/54/68a0978d1ef8502b8492099beaa6e7a0c1b32e3b5d4f677f5810cb08711c/pandas-3.0.3-cp314-cp314t-win_arm64.whl", hash = "sha256:b2c95f8bfc1ee412bf482605d7bfd30c12d1d26bd59fdd91efeef1d4718decb1", size = 9466464, upload-time = "2026-05-11T18:54:22.754Z" }, +] + +[[package]] +name = "protobuf" +version = "6.33.6" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/66/70/e908e9c5e52ef7c3a6c7902c9dfbb34c7e29c25d2f81ade3856445fd5c94/protobuf-6.33.6.tar.gz", hash = "sha256:a6768d25248312c297558af96a9f9c929e8c4cee0659cb07e780731095f38135", size = 444531, upload-time = "2026-03-18T19:05:00.988Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/fc/9f/2f509339e89cfa6f6a4c4ff50438db9ca488dec341f7e454adad60150b00/protobuf-6.33.6-cp310-abi3-win32.whl", hash = "sha256:7d29d9b65f8afef196f8334e80d6bc1d5d4adedb449971fefd3723824e6e77d3", size = 425739, upload-time = "2026-03-18T19:04:48.373Z" }, + { url = "https://files.pythonhosted.org/packages/76/5d/683efcd4798e0030c1bab27374fd13a89f7c2515fb1f3123efdfaa5eab57/protobuf-6.33.6-cp310-abi3-win_amd64.whl", hash = "sha256:0cd27b587afca21b7cfa59a74dcbd48a50f0a6400cfb59391340ad729d91d326", size = 437089, upload-time = "2026-03-18T19:04:50.381Z" }, + { url = "https://files.pythonhosted.org/packages/5c/01/a3c3ed5cd186f39e7880f8303cc51385a198a81469d53d0fdecf1f64d929/protobuf-6.33.6-cp39-abi3-macosx_10_9_universal2.whl", hash = "sha256:9720e6961b251bde64edfdab7d500725a2af5280f3f4c87e57c0208376aa8c3a", size = 427737, upload-time = "2026-03-18T19:04:51.866Z" }, + { url = "https://files.pythonhosted.org/packages/ee/90/b3c01fdec7d2f627b3a6884243ba328c1217ed2d978def5c12dc50d328a3/protobuf-6.33.6-cp39-abi3-manylinux2014_aarch64.whl", hash = "sha256:e2afbae9b8e1825e3529f88d514754e094278bb95eadc0e199751cdd9a2e82a2", size = 324610, upload-time = "2026-03-18T19:04:53.096Z" }, + { url = "https://files.pythonhosted.org/packages/9b/ca/25afc144934014700c52e05103c2421997482d561f3101ff352e1292fb81/protobuf-6.33.6-cp39-abi3-manylinux2014_s390x.whl", hash = "sha256:c96c37eec15086b79762ed265d59ab204dabc53056e3443e702d2681f4b39ce3", size = 339381, upload-time = "2026-03-18T19:04:54.616Z" }, + { url = "https://files.pythonhosted.org/packages/16/92/d1e32e3e0d894fe00b15ce28ad4944ab692713f2e7f0a99787405e43533a/protobuf-6.33.6-cp39-abi3-manylinux2014_x86_64.whl", hash = "sha256:e9db7e292e0ab79dd108d7f1a94fe31601ce1ee3f7b79e0692043423020b0593", size = 323436, upload-time = "2026-03-18T19:04:55.768Z" }, + { url = "https://files.pythonhosted.org/packages/c4/72/02445137af02769918a93807b2b7890047c32bfb9f90371cbc12688819eb/protobuf-6.33.6-py3-none-any.whl", hash = "sha256:77179e006c476e69bf8e8ce866640091ec42e1beb80b213c3900006ecfba6901", size = 170656, upload-time = "2026-03-18T19:04:59.826Z" }, +] + +[[package]] +name = "python-dateutil" +version = "2.9.0.post0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "six" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/66/c0/0c8b6ad9f17a802ee498c46e004a0eb49bc148f2fd230864601a86dcf6db/python-dateutil-2.9.0.post0.tar.gz", hash = "sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3", size = 342432, upload-time = "2024-03-01T18:36:20.211Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl", hash = "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427", size = 229892, upload-time = "2024-03-01T18:36:18.57Z" }, +] + +[[package]] +name = "six" +version = "1.17.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/94/e7/b2c673351809dca68a0e064b6af791aa332cf192da575fd474ed7d6f16a2/six-1.17.0.tar.gz", hash = "sha256:ff70335d468e7eb6ec65b95b99d3a2836546063f63acc5171de367e834932a81", size = 34031, upload-time = "2024-12-04T17:35:28.174Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl", hash = "sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274", size = 11050, upload-time = "2024-12-04T17:35:26.475Z" }, +] + +[[package]] +name = "solve" +version = "0.1.0" +source = { virtual = "." } +dependencies = [ + { name = "ortools" }, +] + +[package.metadata] +requires-dist = [{ name = "ortools", specifier = ">=9.15.6755" }] + +[[package]] +name = "typing-extensions" +version = "4.15.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/72/94/1a15dd82efb362ac84269196e94cf00f187f7ed21c242792a923cdb1c61f/typing_extensions-4.15.0.tar.gz", hash = "sha256:0cea48d173cc12fa28ecabc3b837ea3cf6f38c6d1136f85cbaaf598984861466", size = 109391, upload-time = "2025-08-25T13:49:26.313Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/18/67/36e9267722cc04a6b9f15c7f3441c2363321a3ea07da7ae0c0707beb2a9c/typing_extensions-4.15.0-py3-none-any.whl", hash = "sha256:f0fa19c6845758ab08074a0cfa8b7aecb71c999ca73d62883bc25cc018c4e548", size = 44614, upload-time = "2025-08-25T13:49:24.86Z" }, +] + +[[package]] +name = "tzdata" +version = "2026.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/ba/19/1b9b0e29f30c6d35cb345486df41110984ea67ae69dddbc0e8a100999493/tzdata-2026.2.tar.gz", hash = "sha256:9173fde7d80d9018e02a662e168e5a2d04f87c41ea174b139fbef642eda62d10", size = 198254, upload-time = "2026-04-24T15:22:08.651Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ce/e4/dccd7f47c4b64213ac01ef921a1337ee6e30e8c6466046018326977efd95/tzdata-2026.2-py2.py3-none-any.whl", hash = "sha256:bbe9af844f658da81a5f95019480da3a89415801f6cc966806612cc7169bffe7", size = 349321, upload-time = "2026-04-24T15:22:05.876Z" }, +]