code: def wait_for_nodes(
      num_nodes: int,
      timeout: float = 300.0,
      feedback_interval: float = 10.0,
  ):
      start = time.time()
  
      max_time = start + timeout
      next_feedback = start + feedback_interval
  
      curr_nodes = len(ray.nodes())
      while curr_nodes < num_nodes:
          now = time.time()
  
          if now >= max_time:
              raise RuntimeError(
                  f"Maximum wait time reached, but only "
                  f"{curr_nodes}/{num_nodes} nodes came up. Aborting."
              )
  
          if now >= next_feedback:
              passed = now - start
              print(
                  f"Waiting for more nodes to come up: "
                  f"{curr_nodes}/{num_nodes} "
                  f"({passed:.0f} seconds passed)"
              )
              next_feedback = now + feedback_interval
  
          time.sleep(5)
          curr_nodes = len(ray.nodes())
  
imports: import argparse
  import csv
  import io
  import tarfile
  from dataclasses import dataclass
  import json
  import os
  import pickle
  import platform
  import re
  import shutil
  import signal
  import subprocess
  import tempfile
  import time
  from typing import Any, Callable, Dict, Iterable, List, Optional, Tuple
  import ray
  from ray.train._internal.storage import StorageContext
  from ray.tune.execution.experiment_state import _find_newest_experiment_checkpoint
  from ray.tune.result import _get_defaults_results_dir
  from ray.tune.utils.serialization import TuneFunctionDecoder
label_desc: Use image node_id 4 for calling a global function with example usage: wait_for_nodes(num_nodes, timeout, feedback_interval) without return types