Returns a list of possible status ids that are valid entry points
        into this ISCM. For each status, there is a list of phases that need
        to be executed, i.e.:

        [
         { status_id: "ykyk...", run_phases: [ ] },
         { status_id: "znzn...", run_phases: [ <phase3> ] },
         { status_id: "xyxy...", run_phases: [ <phase2>, <phase3> ] },
         { status_id: "",        run_phases: [ <phase1>, <phase2>, <phase3> ] },
        ]

        the array is sorted in such a way that entries with the least pending
        phases are found first.

        When purpose = PURPOSE_BUILD, each runnable path contains a list of the
        buildable targets and the phases that need to be run to achieve them:

        [
         { status_id: "ykyk...", targets = [] },
         { status_id: "znzn...", targets=[
          { target_id: "ykyk...", run_phases: [ <phase3> ] },
         ]},
         { status_id: "xyxy...", targets=[
          { target_id: "ykyk...", run_phases: [ <phase2>, <phase3> ] },
          { target_id: "znzn...", run_phases: [ <phase2> ] },
         ]},
         { status_id: "", targets=[
          { target_id: "ykyk...", run_phases: [ <phase1>, <phase2>, <phase3> ] },
          { target_id: "znzn...", run_phases: [ <phase1>, <phase2> ] },
          { target_id: "xyxy...", run_phases: [ <phase1> ] },
         ]}
        ]

def get_possible_builds(self, purpose=PURPOSE_RUN):
        """
        Returns a list of possible status ids that are valid entry points
        into this ISCM. For each status, there is a list of phases that need
        to be executed, i.e.:

        [
         { status_id: "ykyk...", run_phases: [ ] },
         { status_id: "znzn...", run_phases: [ <phase3> ] },
         { status_id: "xyxy...", run_phases: [ <phase2>, <phase3> ] },
         { status_id: "",        run_phases: [ <phase1>, <phase2>, <phase3> ] },
        ]

        the array is sorted in such a way that entries with the least pending
        phases are found first.

        When purpose = PURPOSE_BUILD, each runnable path contains a list of the
        buildable targets and the phases that need to be run to achieve them:

        [
         { status_id: "ykyk...", targets = [] },
         { status_id: "znzn...", targets=[
          { target_id: "ykyk...", run_phases: [ <phase3> ] },
         ]},
         { status_id: "xyxy...", targets=[
          { target_id: "ykyk...", run_phases: [ <phase2>, <phase3> ] },
          { target_id: "znzn...", run_phases: [ <phase2> ] },
         ]},
         { status_id: "", targets=[
          { target_id: "ykyk...", run_phases: [ <phase1>, <phase2>, <phase3> ] },
          { target_id: "znzn...", run_phases: [ <phase1>, <phase2> ] },
          { target_id: "xyxy...", run_phases: [ <phase1> ] },
         ]}
        ]
        """
        import hashlib
        from copy import copy
        
        phases = self.phases
        pending_list = copy(phases)
        must_run_list = []
        stages = [ dict(status_id="", must_run=copy(must_run_list), pending=copy(pending_list)) ]
        hashsum = hashlib.sha256()
        status_id_after = {}    # after phase_name
        #
        for p in copy(pending_list):
            hashsum.update(_dict_to_stable_str(p.get_dict_repr()))
            status_id_after[p.phase_name] = hashsum.hexdigest()
            pending_list = pending_list[1:]
            if p.phase_type == RUN_EVERY_TIME:
                must_run_list.append(p)
                continue
            elif p.phase_type == RUN_ON_UPDATE and purpose == PURPOSE_BUILD:
                must_run_list.append(p)
                continue
            elif p.phase_type == RUN_ONCE:
                # possible point of entry for AMIs
                stages.insert(0, dict(status_id=hashsum.hexdigest(), must_run=copy(must_run_list), pending=copy(pending_list)))
            elif p.phase_type == RUN_ON_DEPLOY:
                # no more saved entry points possible
                break
        #
        # If we are building images, add possible builds from each entry point
        if purpose == PURPOSE_BUILD:
            for rp in stages:
                targets = []
                must_run = rp["must_run"]
                pending = rp["pending"]
                del rp["must_run"]
                del rp["pending"]
                iterated = []
                for p in pending:
                    iterated.append(p)
                    if p.phase_type == RUN_ONCE:
                        # this makes a new target
                        target = dict(target_id=status_id_after[p.phase_name], run_phases=must_run + iterated)
                        targets.insert(0, target)
                rp["targets"] = targets
        else:
            for rp in stages:
                rp["run_phases"] = rp["must_run"] + rp["pending"]
                del rp["must_run"]
                del rp["pending"]
        #
        return stages