def uploads(self, requests, peers, history):
        """
        requests -- a list of the requests for this peer for this round
        peers -- available info about all the peers
        history -- history for all previous rounds

        returns: list of Upload objects.

        In each round, this will be called after requests().
        """
        ##################################################################
        ########### updating d_js ########################################
        ##################################################################

        alpha = 0.2
        gamma = 0.1
        round = history.current_round()
        self.bandwidthHistory.append(self.up_bw)

        if round == 0:
            for peer in peers:
                self.downloadRate[peer.id] = 1
                self.uploadRate[peer.id] = 1
                self.slots[peer.id] = 4
                self.downloadUploadRatio[peer.id] = self.downloadRate[peer.id]/self.uploadRate[peer.id] 
        else:
            for peer in peers:
                for download in history.downloads[round-1]:
                    if peer.id == download.from_id:
                        self.downloadRate[peer.id] = download.blocks
                        if download.blocks == 0: print "!!!!!! %s uploaded %s block(s)" % (peer.id, download.blocks)
                        self.slots[peer.id] = mean(self.bandwidthHistory)/float(self.downloadRate[peer.id]) # Find how to find out max and min bw or infer from personal history
                        
                        if round >= 3:
                            peer_download = 0
                            for download2 in history.downloads[round-2]:
                                if peer.id == download2.from_id:
                                    for download3 in history.downloads[round-3]:
                                        if peer.id == download3.from_id:
                                            peer_download += 1
                            if peer_download > 0:
                                self.uploadRate[peer.id] *= 1 - gamma
                        break 
                    
                    if len(peer.available_pieces) > 0:
                        av_pieces = float(len(peer.available_pieces))
                        rnd = float(round)
                        slots = float(self.slots[peer.id])
                        self.downloadRate[peer.id] = av_pieces/(rnd * slots)
                        #self.downloadRate[peer.id] = float((len(peer.available_pieces)/float(round)))/float(self.slots[peer.id])
                        self.uploadRate[peer.id] *= 1 + alpha
                        if self.downloadRate[peer.id] == 0:
                            print str(peer.id) + ": " + str(peer.available_pieces)
                            print "Peer %s has %s available pieces" % (peer.id, len(peer.available_pieces))

        print "downloadUploadRatio"
        print self.downloadUploadRatio
        ########### updating current ratio ###############################

        if round == 0:
            for peer in peers:
                self.downloadUploadRatio[peer.id] = 1
        else:
            for peer in peers:
                self.downloadUploadRatio[peer.id] =  self.downloadRate[peer.id]/self.uploadRate[peer.id]   

        ###################################################################

        print "download rates"
        print self.downloadRate
        print "Upload rates"
        print self.uploadRate
        print "donwload upload ratio"
        print self.downloadUploadRatio
        print "slots"
        print self.slots

        
        logging.debug("%s again.  It's round %d." % (
            self.id, round))
        # One could look at other stuff in the history too here.
        # For example, history.downloads[round-1] (if round != 0, of course)
        # has a list of Download objects for each Download to this peer in
        # the previous round.

        if len(requests) == 0:
            logging.debug("No one wants my pieces!")
            chosen = []
            bws = []
            uploads = []
        else:
            logging.debug("Still here: uploading to a random peer")
            # change my internal state for no reason
            self.dummy_state["cake"] = "pie"

        ########### Building upload list #################################

            sumUpload = 0
            chosen = {}
            downloadUploadRatio_tmp = {}
            
            # creating list with ratios for only peers in requests
            for request in requests:
                downloadUploadRatio_tmp[request.requester_id] = self.downloadUploadRatio[request.requester_id]
                print self.downloadUploadRatio[request.requester_id]

            while (sumUpload <= len(peers) and len(downloadUploadRatio_tmp) > 0):
                peer_id = max(downloadUploadRatio_tmp, key = downloadUploadRatio_tmp.get)
                chosen[peer_id] = downloadUploadRatio_tmp.pop(peer_id)
                sumUpload += self.uploadRate[peer_id]
                # print "sumUpload of %s" % (peer_id)
                # print sumUpload
                # print downloadUploadRatio_tmp[peer_id]
                # print self.uploadRate[peer_id]

            """ Calculate the total proportional BW allocated to other peers """
            totalUploadBW = 0
            for choice in chosen:
                totalUploadBW += chosen[choice]
                # print chosen[choice]

            """ Make each BW as a proportion of totalUploadBW """
            for choice in chosen:
                chosen[choice] = 100 * float(chosen[choice]) / float(totalUploadBW)

            # print "Vector of choices for this round:"
            # print chosen

            """ Now need to divide our BW as integers according to chosen vector """
            peerWeights = [value for (key, value) in sorted(chosen.items())]
            peerNames = sorted(chosen)

            # print "original chosen: %s" % (chosen)
            # print "names: %s" % (peerNames)
            # print "weights: %s" % (peerWeights)

            # request = random.choice(requests)
            # chosen = [request.requester_id]
            # Evenly "split" my upload bandwidth among the one chosen requester
            # bws = even_split(self.up_bw, len(chosen))

            bws = proportional_split(self.up_bw, peerWeights)

            # create actual uploads out of the list of peer ids and bandwidths
            uploads = [Upload(self.id, peer_id, bw)
                for (peer_id, bw) in zip(chosen, bws)]

            
        


        return uploads
    def uploads(self, requests, peers, history):
        """
        requests -- a list of the requests for this peer for this round
        peers -- available info about all the peers
        history -- history for all previous rounds
        returns: list of Upload objects.
        In each round, this will be called after requests().
        """
        
        ##################################################################
        ########### updating d_js ########################################
        ##################################################################
        
        alpha = 0.2
        gamma = 0.1
        round = history.current_round()
        self.bandwidthHistory.append(self.up_bw)
        
        if round == 0:
            bw_list = even_split(self.up_bw,len(peers))
            for peer,i in zip(peers,range(len(peers))):
                self.downloadRate[peer.id] = 1
                if bw_list[i] == 0:
                    self.uploadRate[peer.id] = 0.5
                else:
                    self.uploadRate[peer.id] = bw_list[i]
                self.slots[peer.id] = 4
                self.downloadUploadRatio[peer.id] = 1
        else:
            for peer in peers:
                for download in history.downloads[round-1]:
                    if peer.id == download.from_id:
                        self.downloadRate[peer.id] = download.blocks
                        if download.blocks == 0: print "!!!!!! %s uploaded %s block(s)" % (peer.id, download.blocks)
                        self.slots[peer.id] = mean(self.bandwidthHistory)/float(self.downloadRate[peer.id]) # Find how to find out max and min bw or infer from personal history
                        if round >= 3:
                            peer_download = 0
                            for download2 in history.downloads[round-2]:
                                if peer.id == download2.from_id:
                                    for download3 in history.downloads[round-3]:
                                        if peer.id == download3.from_id:
                                            peer_download += 1
                            if peer_download > 0:
                                self.uploadRate[peer.id] *= 1 - gamma
                        break
                    if len(peer.available_pieces) > 0:
                        av_pieces = float(len(peer.available_pieces))
                        rnd = float(round)
                        slots = float(self.slots[peer.id])
                        self.downloadRate[peer.id] = av_pieces/(rnd * self.conf.blocks_per_piece * slots)
                        self.uploadRate[peer.id] *= 1 + alpha
                        #if self.downloadRate[peer.id] == 0:
                        #    print str(peer.id) + ": " + str(peer.available_pieces)
                        #    print "Peer %s has %s available pieces" % (peer.id, len(peer.available_pieces))
                self.downloadUploadRatio[peer.id] =  self.downloadRate[peer.id]/self.uploadRate[peer.id]
        
        logging.debug("%s again.  It's round %d." % (
            self.id, round))
        
        
       

        ########### Dynamic Optimistic Unchoking #################################
        ########### Eallocate each 3 rounds ######################################

        ### Choose peer to uchoke every 3 round
        ### Choose # of peers divided by x:
        
        x = 3
        if round % 3 ==0:
            self.optUnchokedPeers = random.sample(peers, len(peers)/x)

        ### Initial share to uchoke:
        a = 0.5

        availPiecesShare = float(sum(self.pieces))/float(self.conf.num_pieces*self.conf.blocks_per_piece)
        ### Allocate BW to opt unchoking
        bwToOptUnchoking = (a*self.up_bw - availPiecesShare * self.up_bw * a) + 0.001
        ### Divide this BW among number of neighbors divided by x
        bwToOptUnchoking = bwToOptUnchoking/(len(peers)/x)
        
        optUnchokedAllocation = {}


        for peer in self.optUnchokedPeers:
            optUnchokedAllocation[peer.id] = float(100 * bwToOptUnchoking) /(float((a*self.up_bw - availPiecesShare * self.up_bw * a)) +0.001)

        up_bw_available = self.up_bw - bwToOptUnchoking*(len(peers)/x)


        # Removing optimistically unchoked peers from consideration
        peers_tmp = list(peers)
        for peer in self.optUnchokedPeers:
            if peer in peers_tmp:
                peers_tmp.remove(peer)

        #########################################################################
        ########### Building upload list ########################################
        #########################################################################


        if len(requests) == 0:
            logging.debug("No one wants my pieces!")
            chosen = []
            bws = []
            uploads = []
        else:
            sumUpload = 0
            chosen = {}
            downloadUploadRatio_tmp = {}
            
            # creating list with ratios for only peers in requests

            for request in requests:
                for peer in peers_tmp:
                    if request.requester_id == peer.id:
                        downloadUploadRatio_tmp[request.requester_id] = self.downloadUploadRatio[request.requester_id]


            for key in downloadUploadRatio_tmp:
                if downloadUploadRatio_tmp[key] in self.optUnchokedPeers:
                    downloadUploadRatio_tmp.pop(key)
            
            needed = lambda i: self.pieces[i] < self.conf.blocks_per_piece
            needed_pieces = filter(needed, range(len(self.pieces)))
            
            while (sumUpload <= up_bw_available * 0.75 and len(downloadUploadRatio_tmp) > 0):
                peer_id = max(downloadUploadRatio_tmp, key = downloadUploadRatio_tmp.get)
                chosen[peer_id] = downloadUploadRatio_tmp.pop(peer_id)
                sumUpload += self.uploadRate[peer_id]

            """ Calculate the total proportional BW allocated to other peers """
            
            totalUploadBW = 0
            for choice in chosen:
                totalUploadBW += chosen[choice]
            
            """ Make each BW as a proportion of totalUploadBW """

            if (float(totalUploadBW) * len(optUnchokedAllocation) == 0):
                uploads = []
            else:
                for choice in chosen:
                    chosen[choice] = 100 * float(chosen[choice]) / float(totalUploadBW)


                ### Connecting optimistic unchoking list to tyrant list
                # chosen.update(optUnchokedAllocation)
                
                # print "Vector of choices for this round:"
                # print chosen
                
                """ Now need to divide our BW as integers according to chosen vector """
                
                peerWeights = [value for (key, value) in sorted(chosen.items())]
                peerNames = sorted(chosen)
                
                # print "original chosen: %s" % (chosen)
                # print "names: %s" % (peerNames)
                # print "weights: %s" % (peerWeights)

                bws = proportional_split(int(math.floor(up_bw_available)), peerWeights)

                
            
                # create actual uploads out of the list of peer ids and bandwidths
            
                uploads = [Upload(self.id, peer_id, bw)
                    for (peer_id, bw) in zip(chosen, bws)]

                peerWeights = [value for (key, value) in sorted(optUnchokedAllocation.items())]
                peerNames = sorted(optUnchokedAllocation)
                bws = proportional_split(self.up_bw - int(up_bw_available), peerWeights)

                uploads2 = [Upload(self.id, peer_id, bw)
                    for (peer_id, bw) in zip(peerNames, bws)]

                uploads = uploads + uploads2

                if (round + 1) % 5 == 0:
                    request = random.choice(requests)
                    chosen = [request.requester_id]
                    # Evenly "split" my upload bandwidth among the one chosen requester
                    bws = even_split(self.up_bw, len(chosen))



                #uploads = uploads.append([Upload(self.id, peer_id, bw)
                #    for (peer_id, bw) in zip(optUnchokedAllocation, bws)])

            
        return uploads