def outputids2words(id_list, vocab, article_oovs):
    """ Maps output ids to words, 
        including mapping in-article OOVs from their temporary ids to the original OOV string
        (applicable in pointer-generator mode).

      Args:
        id_list: list of ids (integers)
        vocab: Vocabulary object
        article_oovs: list of OOV words (strings) in the order corresponding to their temporary article OOV ids
        (that have been assigned in pointer-generator mode), or None (in baseline mode)
    
      Returns:
        words: list of words (strings)
    """
    words = []
    for i in id_list:
        try:
            w = vocab.id2word(i) # might be [UNK]
        except ValueError as e: # w is OOV
            error_info = "Error: model produced a word ID that isn't in the vocabulary. This should not happen in baseline (no pointer-generator) mode"
            assert article_oovs is not None, error_info
            article_oov_idx = i - vocab.size()
            try:
                w = article_oovs[article_oov_idx]
            except IndexError as e: # i doesn't correspond to an article oov
                print(id_list)
                raise ValueError('Error: model produced word ID %i which corresponds to article OOV %i but this example only has %i article OOVs' % (i, article_oov_idx, len(article_oovs)))
        #
        words.append(w)
        #
        
    return words