<SYSTEM_TASK:>
Solve the following problem using Python, implementing the functions described below, one line at a time
<END_TASK>
<USER_TASK:>
Description:
 def iter_memory_snapshot(self, minAddr = None, maxAddr = None):
 """ Returns an iterator that allows you to go through the memory contents of a process. It's basically the same as the L{take_memory_snapshot} method, but it takes the snapshot of each memory region as it goes, as opposed to taking the whole snapshot at once. This allows you to work with very large snapshots without a significant performance penalty. Example:: # Print the memory contents of a process. process.suspend() try: snapshot = process.generate_memory_snapshot() for mbi in snapshot: print HexDump.hexblock(mbi.content, mbi.BaseAddress) finally: process.resume() The downside of this is the process must remain suspended while iterating the snapshot, otherwise strange things may happen. The snapshot can only iterated once. To be able to iterate indefinitely call the L{generate_memory_snapshot} method instead. You can also iterate the memory of a dead process, just as long as the last open handle to it hasn't been closed. @see: L{take_memory_snapshot} @type minAddr: int @param minAddr: (Optional) Starting address in address range to query. @type maxAddr: int @param maxAddr: (Optional) Ending address in address range to query. @rtype: iterator of L{win32.MemoryBasicInformation} @return: Iterator of memory region information objects. Two extra properties are added to these objects: - C{filename}: Mapped filename, or C{None}. - C{content}: Memory contents, or C{None}. """


        # One may feel tempted to include calls to self.suspend() and
        # self.resume() here, but that wouldn't work on a dead process.
        # It also wouldn't be needed when debugging since the process is
        # already suspended when the debug event arrives. So it's up to
        # the user to suspend the process if needed.

        # Get the memory map.
        memory = self.get_memory_map(minAddr, maxAddr)

        # Abort if the map couldn't be retrieved.
        if not memory:
            return

        # Get the mapped filenames.
        # Don't fail on access denied errors.
        try:
            filenames = self.get_mapped_filenames(memory)
        except WindowsError:
            e = sys.exc_info()[1]
            if e.winerror != win32.ERROR_ACCESS_DENIED:
                raise
            filenames = dict()

        # Trim the first memory information block if needed.
        if minAddr is not None:
            minAddr = MemoryAddresses.align_address_to_page_start(minAddr)
            mbi = memory[0]
            if mbi.BaseAddress < minAddr:
                mbi.RegionSize  = mbi.BaseAddress + mbi.RegionSize - minAddr
                mbi.BaseAddress = minAddr

        # Trim the last memory information block if needed.
        if maxAddr is not None:
            if maxAddr != MemoryAddresses.align_address_to_page_start(maxAddr):
                maxAddr = MemoryAddresses.align_address_to_page_end(maxAddr)
            mbi = memory[-1]
            if mbi.BaseAddress + mbi.RegionSize > maxAddr:
                mbi.RegionSize = maxAddr - mbi.BaseAddress

        # Read the contents of each block and yield it.
        while memory:
            mbi = memory.pop(0) # so the garbage collector can take it
            mbi.filename = filenames.get(mbi.BaseAddress, None)
            if mbi.has_content():
                mbi.content = self.read(mbi.BaseAddress, mbi.RegionSize)
            else:
                mbi.content = None
            yield mbi