```json
{
  "sym_variables": [
    ("x0", "apples"),
    ("x1", "strips of bacon"),
    ("x2", "slices of pizza"),
    ("x3", "cornichons")
  ],
  "objective_function": "9.98 * x0 + 3.57 * x1 + 3.58 * x2 + 8.96 * x3",
  "constraints": [
    "9 * x0 + 32 * x1 + 35 * x2 + 4 * x3 <= 325",
    "34 * x0 + 3 * x1 + 17 * x2 + 10 * x3 <= 135",
    "9 * x0 + 32 * x1 >= 78",
    "3 * x1 + 10 * x3 >= 39",
    "34 * x0 + 17 * x2 >= 39",
    "3 * x1 + 17 * x2 >= 21",
    "35 * x2 + 4 * x3 <= 310",
    "9 * x0 + 32 * x1 <= 180",
    "32 * x1 + 35 * x2 <= 214",
    "9 * x0 + 4 * x3 <= 201",
    "9 * x0 + 35 * x2 <= 325",
    "17 * x2 + 10 * x3 <= 202",
    "34 * x0 + 10 * x3 <= 213",
    "3 * x1 + 10 * x3 <= 175",
    "34 * x0 + 3 * x1 <= 135"
  ]
}
```

```python
import gurobipy as gp

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

    # Create variables
    apples = m.addVar(lb=0, vtype=gp.GRB.CONTINUOUS, name="apples")
    bacon = m.addVar(lb=0, vtype=gp.GRB.CONTINUOUS, name="strips of bacon")
    pizza = m.addVar(lb=0, vtype=gp.GRB.CONTINUOUS, name="slices of pizza")
    cornichons = m.addVar(lb=0, vtype=gp.GRB.CONTINUOUS, name="cornichons")

    # Set objective function
    m.setObjective(9.98 * apples + 3.57 * bacon + 3.58 * pizza + 8.96 * cornichons, gp.GRB.MAXIMIZE)

    # Add constraints
    m.addConstr(9 * apples + 32 * bacon + 35 * pizza + 4 * cornichons <= 325, "total_cost")
    m.addConstr(34 * apples + 3 * bacon + 17 * pizza + 10 * cornichons <= 135, "total_tastiness")
    m.addConstr(9 * apples + 32 * bacon >= 78, "apples_bacon_cost_min")
    m.addConstr(3 * bacon + 10 * cornichons >= 39, "bacon_cornichons_tastiness_min")
    m.addConstr(34 * apples + 17 * pizza >= 39, "apples_pizza_tastiness_min")
    m.addConstr(3 * bacon + 17 * pizza >= 21, "bacon_pizza_tastiness_min")
    m.addConstr(35 * pizza + 4 * cornichons <= 310, "pizza_cornichons_cost_max")
    m.addConstr(9 * apples + 32 * bacon <= 180, "apples_bacon_cost_max")
    m.addConstr(32 * bacon + 35 * pizza <= 214, "bacon_pizza_cost_max")
    m.addConstr(9 * apples + 4 * cornichons <= 201, "apples_cornichons_cost_max")
    m.addConstr(9 * apples + 35 * pizza <= 325, "apples_pizza_cost_max")
    m.addConstr(17 * pizza + 10 * cornichons <= 202, "pizza_cornichons_tastiness_max")
    m.addConstr(34 * apples + 10 * cornichons <= 213, "apples_cornichons_tastiness_max")
    m.addConstr(3 * bacon + 10 * cornichons <= 175, "bacon_cornichons_tastiness_max")
    m.addConstr(34 * apples + 3 * bacon <= 135, "apples_bacon_tastiness_max")


    # Optimize model
    m.optimize()

    if m.status == gp.GRB.OPTIMAL:
        print('Obj: %g' % m.objVal)
        for v in m.getVars():
            print('%s %g' % (v.varName, v.x))
    elif m.status == gp.GRB.INFEASIBLE:
        print("The model is infeasible.")
    else:
        print("Optimization ended with status:", m.status)


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

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