mirror of
https://github.com/hybridgroup/gobot.git
synced 2025-04-24 13:48:49 +08:00
docs: remove Master unless needed for less code
Signed-off-by: deadprogram <ron@hybridgroup.com>
This commit is contained in:
parent
4230d2ab2f
commit
900bf1d9ea
@ -20,8 +20,6 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
gbot := gobot.NewMaster()
|
||||
|
||||
ardroneAdaptor := ardrone.NewArdroneAdaptor("Drone")
|
||||
drone := ardrone.NewArdroneDriver(ardroneAdaptor, "Drone")
|
||||
|
||||
@ -39,11 +37,11 @@ func main() {
|
||||
[]gobot.Device{drone},
|
||||
work,
|
||||
)
|
||||
gbot.AddRobot(robot)
|
||||
|
||||
gbot.Start()
|
||||
robot.Start()
|
||||
}
|
||||
```
|
||||
|
||||
## How to Connect
|
||||
|
||||
The ARDrone is a WiFi device, so there is no additional work to establish a connection to a single drone. However, in order to connect to multiple drones, you need to perform some configuration steps on each drone via SSH.
|
||||
|
@ -17,8 +17,6 @@ Example:
|
||||
)
|
||||
|
||||
func main() {
|
||||
gbot := gobot.NewMaster()
|
||||
|
||||
ardroneAdaptor := ardrone.NewAdaptor()
|
||||
drone := ardrone.NewDriver(ardroneAdaptor)
|
||||
|
||||
@ -36,9 +34,8 @@ Example:
|
||||
[]gobot.Device{drone},
|
||||
work,
|
||||
)
|
||||
gbot.AddRobot(robot)
|
||||
|
||||
gbot.Start()
|
||||
robot.Start()
|
||||
}
|
||||
|
||||
For more information refer to the ardrone README:
|
||||
|
@ -39,13 +39,11 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/hybridgroup/gobot"
|
||||
"github.com/hybridgroup/gobot/platforms/beaglebone"
|
||||
"github.com/hybridgroup/gobot/drivers/gpio"
|
||||
"github.com/hybridgroup/gobot/platforms/beaglebone"
|
||||
)
|
||||
|
||||
func main() {
|
||||
gbot := gobot.NewMaster()
|
||||
|
||||
beagleboneAdaptor := beaglebone.NewAdaptor()
|
||||
led := gpio.NewLedDriver(beagleboneAdaptor, "P9_12")
|
||||
|
||||
@ -61,8 +59,6 @@ func main() {
|
||||
work,
|
||||
)
|
||||
|
||||
gbot.AddRobot(robot)
|
||||
|
||||
gbot.Start()
|
||||
robot.Start()
|
||||
}
|
||||
```
|
||||
|
@ -13,13 +13,11 @@ Example:
|
||||
"time"
|
||||
|
||||
"github.com/hybridgroup/gobot"
|
||||
"github.com/hybridgroup/gobot/platforms/beaglebone"
|
||||
"github.com/hybridgroup/gobot/drivers/gpio"
|
||||
"github.com/hybridgroup/gobot/platforms/beaglebone"
|
||||
)
|
||||
|
||||
func main() {
|
||||
gbot := gobot.NewMaster()
|
||||
|
||||
beagleboneAdaptor := beaglebone.NewAdaptor()
|
||||
led := gpio.NewLedDriver(beagleboneAdaptor, "P9_12")
|
||||
|
||||
@ -35,9 +33,7 @@ Example:
|
||||
work,
|
||||
)
|
||||
|
||||
gbot.AddRobot(robot)
|
||||
|
||||
gbot.Start()
|
||||
robot.Start()
|
||||
}
|
||||
|
||||
For more information refer to the beaglebone README:
|
||||
|
@ -20,8 +20,6 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
gbot := gobot.NewMaster()
|
||||
|
||||
bebopAdaptor := bebop.NewAdaptor()
|
||||
drone := bebop.NewDriver(bebopAdaptor)
|
||||
|
||||
@ -40,9 +38,8 @@ func main() {
|
||||
[]gobot.Device{drone},
|
||||
work,
|
||||
)
|
||||
gbot.AddRobot(robot)
|
||||
|
||||
gbot.Start()
|
||||
robot.Start()
|
||||
}
|
||||
```
|
||||
|
||||
|
@ -41,13 +41,11 @@ import (
|
||||
"fmt"
|
||||
|
||||
"github.com/hybridgroup/gobot"
|
||||
"github.com/hybridgroup/gobot/platforms/chip"
|
||||
"github.com/hybridgroup/gobot/drivers/gpio"
|
||||
"github.com/hybridgroup/gobot/platforms/chip"
|
||||
)
|
||||
|
||||
func main() {
|
||||
gbot := gobot.NewMaster()
|
||||
|
||||
chipAdaptor := chip.NewAdaptor()
|
||||
button := gpio.NewButtonDriver(chipAdaptor, "XIO-P0")
|
||||
|
||||
@ -66,7 +64,7 @@ func main() {
|
||||
[]gobot.Device{button},
|
||||
work,
|
||||
)
|
||||
gbot.AddRobot(robot)
|
||||
gbot.Start()
|
||||
|
||||
robot.Start()
|
||||
}
|
||||
```
|
||||
|
@ -39,13 +39,11 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/hybridgroup/gobot"
|
||||
"github.com/hybridgroup/gobot/platforms/digispark"
|
||||
"github.com/hybridgroup/gobot/drivers/gpio"
|
||||
"github.com/hybridgroup/gobot/platforms/digispark"
|
||||
)
|
||||
|
||||
func main() {
|
||||
gbot := gobot.NewMaster()
|
||||
|
||||
digisparkAdaptor := digispark.NewAdaptor()
|
||||
led := gpio.NewLedDriver(digisparkAdaptor, "0")
|
||||
|
||||
@ -61,9 +59,7 @@ func main() {
|
||||
work,
|
||||
)
|
||||
|
||||
gbot.AddRobot(robot)
|
||||
|
||||
gbot.Start()
|
||||
robot.Start()
|
||||
}
|
||||
```
|
||||
## How to Connect
|
||||
|
@ -16,13 +16,11 @@ Example:
|
||||
"time"
|
||||
|
||||
"github.com/hybridgroup/gobot"
|
||||
"github.com/hybridgroup/gobot/platforms/digispark"
|
||||
"github.com/hybridgroup/gobot/drivers/gpio"
|
||||
"github.com/hybridgroup/gobot/platforms/digispark"
|
||||
)
|
||||
|
||||
func main() {
|
||||
gbot := gobot.NewMaster()
|
||||
|
||||
digisparkAdaptor := digispark.NewAdaptor()
|
||||
led := gpio.NewLedDriver(digisparkAdaptor, "0")
|
||||
|
||||
@ -38,9 +36,7 @@ Example:
|
||||
work,
|
||||
)
|
||||
|
||||
gbot.AddRobot(robot)
|
||||
|
||||
gbot.Start()
|
||||
robot.Start()
|
||||
}
|
||||
|
||||
For further information refer to digispark README:
|
||||
|
@ -21,13 +21,11 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/hybridgroup/gobot"
|
||||
"github.com/hybridgroup/gobot/platforms/firmata"
|
||||
"github.com/hybridgroup/gobot/drivers/gpio"
|
||||
"github.com/hybridgroup/gobot/platforms/firmata"
|
||||
)
|
||||
|
||||
func main() {
|
||||
gbot := gobot.NewMaster()
|
||||
|
||||
firmataAdaptor := firmata.NewAdaptor("/dev/ttyACM0")
|
||||
led := gpio.NewLedDriver(firmataAdaptor, "13")
|
||||
|
||||
@ -43,9 +41,7 @@ func main() {
|
||||
work,
|
||||
)
|
||||
|
||||
gbot.AddRobot(robot)
|
||||
|
||||
gbot.Start()
|
||||
robot.Start()
|
||||
}
|
||||
```
|
||||
|
||||
|
@ -13,13 +13,11 @@ Example:
|
||||
"time"
|
||||
|
||||
"github.com/hybridgroup/gobot"
|
||||
"github.com/hybridgroup/gobot/platforms/firmata"
|
||||
"github.com/hybridgroup/gobot/drivers/gpio"
|
||||
"github.com/hybridgroup/gobot/platforms/firmata"
|
||||
)
|
||||
|
||||
func main() {
|
||||
gbot := gobot.NewMaster()
|
||||
|
||||
firmataAdaptor := firmata.NewAdaptor("/dev/ttyACM0")
|
||||
led := gpio.NewLedDriver(firmataAdaptor, "13")
|
||||
|
||||
@ -35,9 +33,7 @@ Example:
|
||||
work,
|
||||
)
|
||||
|
||||
gbot.AddRobot(robot)
|
||||
|
||||
gbot.Start()
|
||||
robot.Start()
|
||||
}
|
||||
|
||||
For further information refer to firmata readme:
|
||||
|
@ -59,8 +59,6 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
gbot := gobot.NewMaster()
|
||||
|
||||
e := edison.NewAdaptor()
|
||||
led := gpio.NewLedDriver(e, "13")
|
||||
|
||||
@ -76,9 +74,7 @@ func main() {
|
||||
work,
|
||||
)
|
||||
|
||||
gbot.AddRobot(robot)
|
||||
|
||||
gbot.Start()
|
||||
robot.Start()
|
||||
}
|
||||
```
|
||||
|
||||
|
@ -30,8 +30,6 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
gbot := gobot.NewMaster()
|
||||
|
||||
e := joule.NewAdaptor()
|
||||
led := gpio.NewLedDriver(e, "103")
|
||||
|
||||
@ -47,9 +45,7 @@ func main() {
|
||||
work,
|
||||
)
|
||||
|
||||
gbot.AddRobot(robot)
|
||||
|
||||
gbot.Start()
|
||||
robot.Start()
|
||||
}
|
||||
```
|
||||
|
||||
|
@ -151,8 +151,6 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
gbot := gobot.NewMaster()
|
||||
|
||||
joystickAdaptor := joystick.NewAdaptor()
|
||||
joystick := joystick.NewDriver(joystickAdaptor,
|
||||
"./platforms/joystick/configs/dualshock3.json",
|
||||
@ -191,8 +189,6 @@ func main() {
|
||||
work,
|
||||
)
|
||||
|
||||
gbot.AddRobot(robot)
|
||||
|
||||
gbot.Start()
|
||||
robot.Start()
|
||||
}
|
||||
```
|
||||
|
@ -20,8 +20,6 @@ Example:
|
||||
)
|
||||
|
||||
func main() {
|
||||
gbot := gobot.NewMaster()
|
||||
|
||||
joystickAdaptor := joystick.NewAdaptor()
|
||||
joystick := joystick.NewDriver(joystickAdaptor,
|
||||
"./platforms/joystick/configs/dualshock3.json",
|
||||
@ -60,9 +58,7 @@ Example:
|
||||
work,
|
||||
)
|
||||
|
||||
gbot.AddRobot(robot)
|
||||
|
||||
gbot.Start()
|
||||
robot.Start()
|
||||
}
|
||||
|
||||
For further information refer to joystick README:
|
||||
|
@ -23,8 +23,6 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
gbot := gobot.NewMaster()
|
||||
|
||||
keys := keyboard.NewDriver("keyboard")
|
||||
|
||||
work := func() {
|
||||
@ -45,8 +43,6 @@ func main() {
|
||||
work,
|
||||
)
|
||||
|
||||
gbot.AddRobot(robot)
|
||||
|
||||
gbot.Start()
|
||||
robot.Start()
|
||||
}
|
||||
```
|
||||
|
@ -19,8 +19,6 @@ Example:
|
||||
)
|
||||
|
||||
func main() {
|
||||
gbot := gobot.NewMaster()
|
||||
|
||||
keys := keyboard.NewDriver()
|
||||
|
||||
work := func() {
|
||||
@ -41,8 +39,6 @@ Example:
|
||||
work,
|
||||
)
|
||||
|
||||
gbot.AddRobot(robot)
|
||||
|
||||
gbot.Start()
|
||||
}
|
||||
|
||||
|
@ -27,8 +27,6 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
gbot := gobot.NewMaster()
|
||||
|
||||
leapMotionAdaptor := leap.NewAdaptor("127.0.0.1:6437")
|
||||
l := leap.NewDriver(leapMotionAdaptor)
|
||||
|
||||
@ -44,9 +42,7 @@ func main() {
|
||||
work,
|
||||
)
|
||||
|
||||
gbot.AddRobot(robot)
|
||||
|
||||
gbot.Start()
|
||||
robot.Start()
|
||||
}
|
||||
```
|
||||
|
||||
|
@ -20,8 +20,6 @@ Example:
|
||||
)
|
||||
|
||||
func main() {
|
||||
gbot := gobot.NewMaster()
|
||||
|
||||
leapMotionAdaptor := leap.NewAdaptor("127.0.0.1:6437")
|
||||
l := leap.NewDriver(leapMotionAdaptor)
|
||||
|
||||
@ -37,9 +35,7 @@ Example:
|
||||
work,
|
||||
)
|
||||
|
||||
gbot.AddRobot(robot)
|
||||
|
||||
gbot.Start()
|
||||
robot.Start()
|
||||
}
|
||||
|
||||
For more information refer to the leap README:
|
||||
|
@ -23,8 +23,6 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
gbot := gobot.NewMaster()
|
||||
|
||||
adaptor := mavlink.NewAdaptor("/dev/ttyACM0")
|
||||
iris := mavlink.NewDriver(adaptor)
|
||||
|
||||
@ -66,8 +64,6 @@ func main() {
|
||||
work,
|
||||
)
|
||||
|
||||
gbot.AddRobot(robot)
|
||||
|
||||
gbot.Start()
|
||||
robot.Start()
|
||||
}
|
||||
```
|
||||
|
@ -18,8 +18,6 @@ Example:
|
||||
)
|
||||
|
||||
func main() {
|
||||
gbot := gobot.NewMaster()
|
||||
|
||||
adaptor := mavlink.NewAdaptor("/dev/ttyACM0")
|
||||
iris := mavlink.NewDriver(adaptor)
|
||||
|
||||
@ -61,9 +59,7 @@ Example:
|
||||
work,
|
||||
)
|
||||
|
||||
gbot.AddRobot(robot)
|
||||
|
||||
gbot.Start()
|
||||
robot.Start()
|
||||
}
|
||||
|
||||
For further information refer to mavlink README:
|
||||
|
@ -22,8 +22,6 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
gbot := gobot.NewMaster()
|
||||
|
||||
// use "/dev/ttyUSB0" if connecting with USB cable
|
||||
// use "/dev/ttyAMA0" on devices older than Raspberry Pi 3 Model B
|
||||
megaPiAdaptor := megapi.NewAdaptor("/dev/ttyS0")
|
||||
@ -48,8 +46,6 @@ func main() {
|
||||
work,
|
||||
)
|
||||
|
||||
gbot.AddRobot(robot)
|
||||
|
||||
gbot.Start()
|
||||
robot.Start()
|
||||
}
|
||||
```
|
||||
|
@ -29,8 +29,6 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
gbot := gobot.NewMaster()
|
||||
|
||||
mqttAdaptor := mqtt.NewAdaptor("tcp://0.0.0.0:1883", "pinger")
|
||||
|
||||
work := func() {
|
||||
@ -54,9 +52,7 @@ func main() {
|
||||
work,
|
||||
)
|
||||
|
||||
gbot.AddRobot(robot)
|
||||
|
||||
gbot.Start()
|
||||
robot.Start()
|
||||
}
|
||||
```
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
# NATS
|
||||
|
||||
NATS is a lightweight messaging protocol perfect for your IoT/Robotics projects. It operates over TCP, offers a great number of features but an incredibly simple Pub Sub style model of communicating broadcast messages. NATS is blazingly fast as it is written in Go.
|
||||
NATS is a lightweight messaging protocol perfect for your IoT/Robotics projects. It operates over TCP, offers a great number of features but an incredibly simple Pub Sub style model of communicating broadcast messages. NATS is blazingly fast as it is written in Go.
|
||||
|
||||
This repository contains the Gobot adaptor/drivers to connect to NATS servers. It uses the NATS Go Client available at https://github.com/nats-io/nats. The NATS project is maintained by Nats.io and sponsored by Apcera. Find more information on setting up a NATS server and its capability at http://nats.io/.
|
||||
|
||||
@ -30,8 +30,6 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
gbot := gobot.NewMaster()
|
||||
|
||||
natsAdaptor := nats.NewNatsAdaptor("nats", "localhost:4222", 1234)
|
||||
|
||||
work := func() {
|
||||
@ -55,9 +53,7 @@ func main() {
|
||||
work,
|
||||
)
|
||||
|
||||
gbot.AddRobot(robot)
|
||||
|
||||
gbot.Start()
|
||||
robot.Start()
|
||||
}
|
||||
```
|
||||
|
||||
|
@ -57,8 +57,6 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
gbot := gobot.NewMaster()
|
||||
|
||||
adaptor := neurosky.NewAdaptor("/dev/rfcomm0")
|
||||
neuro := neurosky.NewDriver(adaptor)
|
||||
|
||||
@ -101,7 +99,6 @@ func main() {
|
||||
work,
|
||||
)
|
||||
|
||||
gbot.AddRobot(robot)
|
||||
gbot.Start()
|
||||
robot.Start()
|
||||
}
|
||||
```
|
||||
|
@ -17,8 +17,6 @@ Example:
|
||||
)
|
||||
|
||||
func main() {
|
||||
gbot := gobot.NewMaster()
|
||||
|
||||
adaptor := neurosky.NewAdaptor("/dev/rfcomm0")
|
||||
neuro := neurosky.NewDriver(adaptor)
|
||||
|
||||
@ -61,8 +59,7 @@ Example:
|
||||
work,
|
||||
)
|
||||
|
||||
gbot.AddRobot(robot)
|
||||
gbot.Start()
|
||||
robot.Start()
|
||||
}
|
||||
|
||||
For further information refer to neuroky README:
|
||||
|
@ -50,8 +50,6 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
gbot := gobot.NewMaster()
|
||||
|
||||
window := opencv.NewWindowDriver()
|
||||
camera := opencv.NewCameraDriver(0)
|
||||
|
||||
@ -66,8 +64,6 @@ func main() {
|
||||
work,
|
||||
)
|
||||
|
||||
gbot.AddRobot(robot)
|
||||
|
||||
gbot.Start()
|
||||
robot.Start()
|
||||
}
|
||||
```
|
||||
|
@ -20,8 +20,6 @@ Example:
|
||||
)
|
||||
|
||||
func main() {
|
||||
gbot := gobot.NewMaster()
|
||||
|
||||
window := opencv.NewWindowDriver()
|
||||
camera := opencv.NewCameraDriver(0)
|
||||
|
||||
@ -36,9 +34,7 @@ Example:
|
||||
work,
|
||||
)
|
||||
|
||||
gbot.AddRobot(robot)
|
||||
|
||||
gbot.Start()
|
||||
robot.Start()
|
||||
}
|
||||
|
||||
For further information refer to opencv README:
|
||||
|
@ -26,8 +26,6 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
gbot := gobot.NewMaster()
|
||||
|
||||
core := particle.NewAdaptor("device_id", "access_token")
|
||||
led := gpio.NewLedDriver(core, "D7")
|
||||
|
||||
@ -43,8 +41,6 @@ func main() {
|
||||
work,
|
||||
)
|
||||
|
||||
gbot.AddRobot(robot)
|
||||
|
||||
gbot.Start()
|
||||
robot.Start()
|
||||
}
|
||||
```
|
||||
|
@ -18,8 +18,6 @@ Example:
|
||||
)
|
||||
|
||||
func main() {
|
||||
gbot := gobot.NewMaster()
|
||||
|
||||
core := paticle.NewAdaptor("device_id", "access_token")
|
||||
led := gpio.NewLedDriver(core, "D7")
|
||||
|
||||
@ -35,9 +33,7 @@ Example:
|
||||
work,
|
||||
)
|
||||
|
||||
gbot.AddRobot(robot)
|
||||
|
||||
gbot.Start()
|
||||
robot.Start()
|
||||
}
|
||||
|
||||
For further information refer to Particle readme:
|
||||
|
@ -29,8 +29,8 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
gbot := gobot.NewMaster()
|
||||
api.NewAPI(gbot).Start()
|
||||
master := gobot.NewMaster()
|
||||
api.NewAPI(master).Start()
|
||||
|
||||
pebbleAdaptor := pebble.NewAdaptor()
|
||||
watch := pebble.NewDriver(pebbleAdaptor)
|
||||
@ -52,9 +52,9 @@ func main() {
|
||||
work,
|
||||
)
|
||||
|
||||
gbot.AddRobot(robot)
|
||||
master.AddRobot(robot)
|
||||
|
||||
gbot.Start()
|
||||
master.Start()
|
||||
}
|
||||
|
||||
```
|
||||
|
@ -23,8 +23,8 @@ Before running the example, make sure configuration settings match with your pro
|
||||
)
|
||||
|
||||
func main() {
|
||||
gbot := gobot.NewMaster()
|
||||
api.NewAPI(gbot).Start()
|
||||
master := gobot.NewMaster()
|
||||
api.NewAPI(master).Start()
|
||||
|
||||
pebbleAdaptor := pebble.NewAdaptor()
|
||||
watch := pebble.NewDriver(pebbleAdaptor)
|
||||
@ -46,9 +46,9 @@ Before running the example, make sure configuration settings match with your pro
|
||||
work,
|
||||
)
|
||||
|
||||
gbot.AddRobot(robot)
|
||||
master.AddRobot(robot)
|
||||
|
||||
gbot.Start()
|
||||
master.Start()
|
||||
}
|
||||
|
||||
For more information refer to the pebble README:
|
||||
|
@ -74,8 +74,6 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
gbot := gobot.NewMaster()
|
||||
|
||||
r := raspi.NewAdaptor()
|
||||
led := gpio.NewLedDriver(r, "7")
|
||||
|
||||
@ -91,8 +89,6 @@ func main() {
|
||||
work,
|
||||
)
|
||||
|
||||
gbot.AddRobot(robot)
|
||||
|
||||
gbot.Start()
|
||||
robot.Start()
|
||||
}
|
||||
```
|
||||
|
@ -58,8 +58,6 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
gbot := gobot.NewMaster()
|
||||
|
||||
adaptor := sphero.NewAdaptor("/dev/rfcomm0")
|
||||
driver := sphero.NewSpheroDriver(adaptor)
|
||||
|
||||
@ -75,8 +73,6 @@ func main() {
|
||||
work,
|
||||
)
|
||||
|
||||
gbot.AddRobot(robot)
|
||||
|
||||
gbot.Start()
|
||||
robot.Start()
|
||||
}
|
||||
```
|
||||
|
@ -18,8 +18,6 @@ Example:
|
||||
)
|
||||
|
||||
func main() {
|
||||
gbot := gobot.NewMaster()
|
||||
|
||||
adaptor := sphero.NewAdaptor("/dev/rfcomm0")
|
||||
driver := sphero.NewSpheroDriver(adaptor)
|
||||
|
||||
@ -35,9 +33,7 @@ Example:
|
||||
work,
|
||||
)
|
||||
|
||||
gbot.AddRobot(robot)
|
||||
|
||||
gbot.Start()
|
||||
robot.Start()
|
||||
}
|
||||
|
||||
For further information refer to sphero readme:
|
||||
|
Loading…
x
Reference in New Issue
Block a user