<SYSTEM_TASK:>
Solve the following problem using Python, implementing the functions described below, one line at a time
<END_TASK>
<USER_TASK:>
Description:
 def _calibrate_junction_tree(self, operation):
 """ Generalized calibration of junction tree or clique using belief propagation. This method can be used for both calibrating as well as max-calibrating. Uses Lauritzen-Spiegelhalter algorithm or belief-update message passing. Parameters operation: str ('marginalize' | 'maximize') The operation to do for passing messages between nodes. Reference --------- Algorithm 10.3 Calibration using belief propagation in clique tree Probabilistic Graphical Models: Principles and Techniques Daphne Koller and Nir Friedman. """

        # Initialize clique beliefs as well as sepset beliefs
        self.clique_beliefs = {clique: self.junction_tree.get_factors(clique)
                               for clique in self.junction_tree.nodes()}
        self.sepset_beliefs = {frozenset(edge): None for edge in self.junction_tree.edges()}

        for clique in self.junction_tree.nodes():
            if not self._is_converged(operation=operation):
                neighbors = self.junction_tree.neighbors(clique)
                # update root's belief using nieighbor clique's beliefs
                # upward pass
                for neighbor_clique in neighbors:
                    self._update_beliefs(neighbor_clique, clique, operation=operation)
                bfs_edges = nx.algorithms.breadth_first_search.bfs_edges(self.junction_tree, clique)
                # update the beliefs of all the nodes starting from the root to leaves using root's belief
                # downward pass
                for edge in bfs_edges:
                    self._update_beliefs(edge[0], edge[1], operation=operation)
            else:
                break