wrapped client-side js so we don't pollute the DOM