code: def build(
      program_code: str,
      data: Data = frozendict(),
      random_seed: Optional[int] = None,
  ) -> Model:
      """Build (compile) a Stan program.
  
      Arguments:
          program_code: Stan program code describing a Stan model.
          data: A Python dictionary or mapping providing the data for the
              model. Variable names are the keys and the values are their
              associated values. Default is an empty dictionary, suitable
              for Stan programs with no `data` block.
          random_seed: Random seed, a positive integer for random number
              generation. Used to make sure that results can be reproduced.
  
      Returns:
          Model: an instance of Model
  
      Notes:
          C++ reserved words and Stan reserved words may not be used for
          variable names; see the Stan User's Guide for a complete list.
  
      """
      # `data` must be JSON-serializable in order to send to httpstan
      data = json.loads(DataJSONEncoder().encode(data))
  
      async def go():
          io = ConsoleIO()
          # hack: use stdout instead of stderr because httpstan silences stderr during compilation
          building_output = io.section().output
          if not io.supports_ansi():
              building_output.write("<comment>Building...</comment>")
          async with stan.common.HttpstanClient() as client:
              # Check to see if model is in cache.
              model_name = httpstan.models.calculate_model_name(
                  program_code
              )
              resp = await client.post(
                  f"/{model_name}/params", json={"data": data}
              )
              model_in_cache = resp.status != 404
  
              task = asyncio.create_task(
                  client.post(
                      "/models", json={"program_code": program_code}
                  )
              )
              start = time.time()
              while True:
                  done, pending = await asyncio.wait(
                      {task}, timeout=0.1
                  )
                  if done:
                      break
                  if io.supports_ansi():
                      building_output.clear()
                      building_output.write(
                          f"<comment>Building:</comment> {time.time() - start:0.1f}s"
                      )
              building_output.clear() if io.supports_ansi() else building_output.write(
                  "\n"
              )
              # now that httpstan has released stderr, we can use error_output again
              building_output = io.section().error_output
              resp = task.result()
  
              if resp.status != 201:
                  match = re.search(
                      r"""ValueError\(['"](.*)['"]\)""",
                      resp.json()["message"],
                  )
                  if not match:  # unknown error, should not happen
                      raise RuntimeError(resp.json()["message"])
                  exception_body = (
                      match.group(1).encode().decode("unicode_escape")
                  )
                  error_type_match = re.match(
                      r"(Semantic|Syntax) error", exception_body
                  )
                  if error_type_match:
                      error_type = error_type_match.group(0)
                      exception_body_without_first_line = (
                          exception_body.split("\n", 1)[1]
                      )
                      building_output.write_line(
                          f"<info>Building:</info> <error>{error_type}:</error>"
                      )
                      building_output.write_line(
                          f"<error>{exception_body_without_first_line}</error>"
                      )
                      raise ValueError(error_type)
                  else:
                      raise RuntimeError(exception_body)
              building_output.clear() if io.supports_ansi() else building_output.write(
                  "\n"
              )
              if model_in_cache:
                  building_output.write(
                      "<info>Building:</info> found in cache, done."
                  )
              else:
                  building_output.write(
                      f"<info>Building:</info> {time.time() - start:0.1f}s, done."
                  )
              assert model_name == resp.json()["name"]
              if resp.json().get("stanc_warnings"):
                  io.error_line(
                      "<comment>Messages from <fg=cyan;options=bold>stanc</>:</comment>"
                  )
                  io.error_line(resp.json()["stanc_warnings"])
  
              resp = await client.post(
                  f"/{model_name}/params", json={"data": data}
              )
              if resp.status != 200:
                  raise RuntimeError(resp.json()["message"])
              params_list = resp.json()["params"]
              assert len(
                  {param["name"] for param in params_list}
              ) == len(params_list)
              param_names, dims = zip(
                  *(
                      (param["name"], param["dims"])
                      for param in params_list
                  )
              )
              constrained_param_names = sum(
                  (
                      tuple(param["constrained_names"])
                      for param in params_list
                  ),
                  (),
              )
              return Model(
                  model_name,
                  program_code,
                  data,
                  param_names,
                  constrained_param_names,
                  dims,
                  random_seed,
              )
  
      try:
          return asyncio.run(go())
      except KeyboardInterrupt:
          return
  
imports: import asyncio
  import dataclasses
  import json
  import re
  import time
  from typing import Dict, List, Optional, Sequence, Tuple, Union, cast
  import httpstan.models
  import httpstan.schemas
  import httpstan.services.arguments
  import httpstan.utils
  import numpy
  import simdjson
  from clikit.io import ConsoleIO
  import stan.common
  import stan.fit
  import stan.plugins
label_desc: Use image node_id 1 for calling a global function with example usage: build(program_code, data, random_seed) and returns: asyncio, Model