moved some logic out of the mainloop, into its own function for clarity