Theory of Computing: A Gentle Introduction