listen for events instead of polling