<SYSTEM_TASK:>
Solve the following problem using Python, implementing the functions described below, one line at a time
<END_TASK>
<USER_TASK:>
Description:
 def handleContractDetails(self, msg, end=False):
 """ handles contractDetails and contractDetailsEnd """


        if end:
            # mark as downloaded
            self._contract_details[msg.reqId]['downloaded'] = True

            # move details from temp to permanent collector
            self.contract_details[msg.reqId] = self._contract_details[msg.reqId]
            del self._contract_details[msg.reqId]

            # adjust fields if multi contract
            if len(self.contract_details[msg.reqId]["contracts"]) > 1:
                self.contract_details[msg.reqId]["m_contractMonth"] = ""
                # m_summary should hold closest expiration
                expirations = self.getExpirations(self.contracts[msg.reqId], expired=0)
                contract = self.contract_details[msg.reqId]["contracts"][-len(expirations)]
                self.contract_details[msg.reqId]["m_summary"] = vars(contract)
            else:
                self.contract_details[msg.reqId]["m_summary"] = vars(
                    self.contract_details[msg.reqId]["contracts"][0])

            # update local db with correct contractString
            for tid in self.contract_details:
                oldString = self.tickerIds[tid]
                newString = self.contractString(self.contract_details[tid]["contracts"][0])

                if len(self.contract_details[msg.reqId]["contracts"]) > 1:
                    self.tickerIds[tid] = newString
                    if newString != oldString:
                        if oldString in self._portfolios:
                            self._portfolios[newString] = self._portfolios[oldString]
                        if oldString in self._positions:
                            self._positions[newString] = self._positions[oldString]

            # fire callback
            self.ibCallback(caller="handleContractDetailsEnd", msg=msg)

            # exit
            return

        # continue...

        # collect data on all contract details
        # (including those with multiple expiry/strike/sides)
        details  = vars(msg.contractDetails)
        contract = details["m_summary"]

        if msg.reqId in self._contract_details:
            details['contracts'] = self._contract_details[msg.reqId]["contracts"]
        else:
            details['contracts'] = []

        details['contracts'].append(contract)
        details['downloaded'] = False
        self._contract_details[msg.reqId] = details

        # add details to local symbol list
        if contract.m_localSymbol not in self.localSymbolExpiry:
            self.localSymbolExpiry[contract.m_localSymbol] = details["m_contractMonth"]

        # add contract's multiple expiry/strike/sides to class collectors
        contractString = self.contractString(contract)
        tickerId = self.tickerId(contractString)
        self.contracts[tickerId] = contract

        # continue if this is a "multi" contract
        if tickerId == msg.reqId:
            self._contract_details[msg.reqId]["m_summary"] = vars(contract)
        else:
            # print("+++", tickerId, contractString)
            self.contract_details[tickerId] = details.copy()
            self.contract_details[tickerId]["m_summary"] = vars(contract)
            self.contract_details[tickerId]["contracts"] = [contract]

        # fire callback
        self.ibCallback(caller="handleContractDetails", msg=msg)