rearrange some code. add caching mechanism