```json
{
  "sym_variables": [
    ("x0", "grams of fat"),
    ("x1", "milligrams of iron"),
    ("x2", "grams of fiber")
  ],
  "objective_function": "5.49 * x0 + 5.92 * x1 + 3.77 * x2",
  "constraints": [
    "4 * x0 + 15 * x1 + 8 * x2 >= 24",
    "4 * x0 + 8 * x2 >= 23",
    "4 * x0 + 15 * x1 + 8 * x2 >= 23",
    "27 * x0 + 13 * x1 >= 32",
    "13 * x1 + 3 * x2 >= 36",
    "27 * x0 + 3 * x2 >= 31",
    "27 * x0 + 13 * x1 + 3 * x2 >= 31",
    "29 * x0 + 28 * x2 >= 50",
    "29 * x0 + 5 * x1 >= 44",
    "29 * x0 + 5 * x1 + 28 * x2 >= 44",
    "-9 * x1 + 8 * x2 >= 0",
    "2 * x0 - x2 >= 0",
    "29 * x0 + 28 * x2 <= 79"
  ]
}
```

```python
import gurobipy as gp
from gurobipy import GRB

try:
    # Create a new model
    m = gp.Model("nutrition_optimization")

    # Create variables
    fat = m.addVar(vtype=GRB.CONTINUOUS, name="fat")
    iron = m.addVar(vtype=GRB.INTEGER, name="iron")
    fiber = m.addVar(vtype=GRB.INTEGER, name="fiber")

    # Set objective function
    m.setObjective(5.49 * fat + 5.92 * iron + 3.77 * fiber, GRB.MINIMIZE)

    # Add constraints
    m.addConstr(4 * fat + 15 * iron + 8 * fiber >= 24, "immune_support_1")
    m.addConstr(4 * fat + 8 * fiber >= 23, "immune_support_2")
    m.addConstr(4 * fat + 15 * iron + 8 * fiber >= 23, "immune_support_3")
    
    m.addConstr(27 * fat + 13 * iron >= 32, "muscle_growth_1")
    m.addConstr(13 * iron + 3 * fiber >= 36, "muscle_growth_2")
    m.addConstr(27 * fat + 3 * fiber >= 31, "muscle_growth_3")
    m.addConstr(27 * fat + 13 * iron + 3 * fiber >= 31, "muscle_growth_4")
    
    m.addConstr(29 * fat + 28 * fiber >= 50, "cardio_support_1")
    m.addConstr(29 * fat + 5 * iron >= 44, "cardio_support_2")
    m.addConstr(29 * fat + 5 * iron + 28 * fiber >= 44, "cardio_support_3")

    m.addConstr(-9 * iron + 8 * fiber >= 0, "constraint_1")
    m.addConstr(2 * fat - fiber >= 0, "constraint_2")
    m.addConstr(29 * fat + 28 * fiber <= 79, "cardio_support_4")


    # Optimize model
    m.optimize()

    if m.status == GRB.OPTIMAL:
        print('Obj: %g' % m.objVal)
        print('Fat: %g' % fat.x)
        print('Iron: %g' % iron.x)
        print('Fiber: %g' % fiber.x)
    elif m.status == GRB.INFEASIBLE:
        print('The model is infeasible.')
    else:
        print('Optimization ended with status %d' % m.status)


except gp.GurobiError as e:
    print('Error code ' + str(e.errno) + ': ' + str(e))

except AttributeError:
    print('Encountered an attribute error')
```