## Problem Description and Formulation

The problem is a mixed-integer linear programming (MILP) problem. We need to minimize the objective function:

`8 * x0 + 7 * x1 + 3 * x2`

subject to various constraints.

## Constraints

The constraints can be categorized into several groups:

### Resource Constraints

* Usefulness rating constraints:
	+ `8 * x0 + 8 * x1 >= 19`
	+ `8 * x1 + 3 * x2 >= 17`
	+ `8 * x0 + 8 * x1 + 3 * x2 >= 17`
* Portability rating constraints:
	+ `2 * x1 + 10 * x2 >= 17`
	+ `9 * x0 + 2 * x1 + 10 * x2 >= 15`
	+ `9 * x0 + 2 * x1 + 10 * x2 >= 15`
* Storage space constraints:
	+ `2 * x0 + 5 * x1 >= 11`
	+ `2 * x0 + 6 * x2 >= 8`
	+ `2 * x0 + 5 * x1 + 6 * x2 >= 22`
	+ `2 * x0 + 5 * x1 + 6 * x2 >= 22`

### Bounds Constraints

* `9 * x0 + 2 * x1 <= 60`
* `2 * x1 + 10 * x2 <= 75`
* `2 * x0 + 5 * x1 + 6 * x2 <= 42`

### Linear Constraints

* `-7 * x0 + 8 * x2 >= 0`
* `-9 * x1 + 9 * x2 >= 0`

### Integrality Constraints

* `x0`, `x1`, and `x2` are integers.

## Gurobi Code

```python
import gurobi

# Create a new Gurobi model
m = gurobi.Model()

# Define the variables
x0 = m.addVar(name="packs of napkins", vtype=gurobi.GRB.INTEGER)
x1 = m.addVar(name="candles", vtype=gurobi.GRB.INTEGER)
x2 = m.addVar(name="lightbulbs", vtype=gurobi.GRB.INTEGER)

# Define the objective function
m.setObjective(8 * x0 + 7 * x1 + 3 * x2, gurobi.GRB.MINIMIZE)

# Add constraints
m.addConstr(8 * x0 + 8 * x1 >= 19, name="usefulness_rating_constraint_1")
m.addConstr(8 * x1 + 3 * x2 >= 17, name="usefulness_rating_constraint_2")
m.addConstr(8 * x0 + 8 * x1 + 3 * x2 >= 17, name="usefulness_rating_constraint_3")
m.addConstr(2 * x1 + 10 * x2 >= 17, name="portability_rating_constraint_1")
m.addConstr(9 * x0 + 2 * x1 + 10 * x2 >= 15, name="portability_rating_constraint_2")
m.addConstr(2 * x0 + 5 * x1 >= 11, name="storage_space_constraint_1")
m.addConstr(2 * x0 + 6 * x2 >= 8, name="storage_space_constraint_2")
m.addConstr(2 * x0 + 5 * x1 + 6 * x2 >= 22, name="storage_space_constraint_3")
m.addConstr(9 * x0 + 2 * x1 <= 60, name="portability_rating_bound_1")
m.addConstr(2 * x1 + 10 * x2 <= 75, name="portability_rating_bound_2")
m.addConstr(2 * x0 + 5 * x1 + 6 * x2 <= 42, name="storage_space_bound")
m.addConstr(-7 * x0 + 8 * x2 >= 0, name="linear_constraint_1")
m.addConstr(-9 * x1 + 9 * x2 >= 0, name="linear_constraint_2")

# Optimize the model
m.optimize()

# Print the solution
if m.status == gurobi.GRB.OPTIMAL:
    print("Objective: ", m.objVal)
    print("packs of napkins: ", x0.varValue)
    print("candles: ", x1.varValue)
    print("lightbulbs: ", x2.varValue)
else:
    print("The problem is infeasible")
```