some parts rewritten.