a runable version, TODO: add cache