Target zones, clothing and DUI screens on the client.

## Target

Works with ox_target and qb-target through one API.

```lua
ObsiLib.target.addBox('mechanic_desk', vec3(-347.4, -133.2, 39.0), vec3(1.5, 1.0, 2.0), 70.0, {
    { name = 'duty', label = 'Toggle duty', icon = 'clock', onSelect = function() TriggerServerEvent('mechanic:duty') end },
})

ObsiLib.target.addSphere('atm_1', coords, 1.0, options)

ObsiLib.target.addEntity(vehicle, {
    {
        name = 'trunk', label = 'Open trunk', icon = 'car',
        canInteract = function(entity) return true end,
        onSelect = function(entity) end,
    },
})

ObsiLib.target.removeEntity(vehicle, 'trunk')
ObsiLib.target.remove('mechanic_desk')
ObsiLib.target.provider()   -- 'ox_target' | 'qb-target' | 'none'
```

Icons take a FontAwesome class (`'fas fa-box'`) or a short name (`'box'`, `'car'`, `'key'`, ...).
Add your own short names in `ObsiConfig.TargetIcons`.

## Clothing

Works with illenium-appearance, fivem-appearance, qb-clothing and esx_skin.

```lua
local outfit = ObsiLib.clothing.get()   -- { components = {...}, props = {...} }

ObsiLib.clothing.apply({
    components = { { component_id = 11, drawable = 55, texture = 0 } },
    props = { { prop_id = 0, drawable = 46, texture = 0 } },
})

ObsiLib.clothing.restore()              -- back to the saved clothes
```

`apply` also takes qb-clothing `outfitData` tables and esx_skin `tshirt_1` style tables, so job uniforms written for either work as they are.

## DUI

Render a web page onto an in-game texture:

```lua
local screen = ObsiLib.dui.create({ url = 'https://example.com', width = 1280, height = 720 })
screen.replace('prop_tv_flat_01', 'script_rt_tvscreen')
screen.send({ action = 'play' })
screen.setUrl('https://example.org')
screen.destroy()
```
