text: """
  A library of various helpers functions and classes
  """
  import inspect
  import sys
  import socket
  import logging
  import threading
  import time
  import random
  from pyaedt.third_party.ironpython.rpyc_27.lib.compat import maxint  # noqa: F401
  
  
  class MissingModule(object):
      __slots__ = ["__name"]
  
      def __init__(self, name):
          self.__name = name
  
      def __getattr__(self, name):
          if name.startswith("__"):  # issue 71
              raise AttributeError("module %r not found" % (self.__name,))
          raise ImportError("module %r not found" % (self.__name,))
  
      def __bool__(self):
          return False
  
      __nonzero__ = __bool__
  
  
  def safe_import(name):
      try:
          mod = __import__(name, None, None, "*")
      except ImportError:
          mod = MissingModule(name)
      except Exception:
          # issue 72: IronPython on Mono
          if sys.platform == "cli" and name == "signal":  # os.name == "posix":
              mod = MissingModule(name)
          else:
              raise
      return mod
  
  
  def setup_logger(quiet=False, logfile=None):
      opts = {}
      if quiet:
          opts["level"] = logging.ERROR
      else:
          opts["level"] = logging.DEBUG
      if logfile:
          opts["filename"] = logfile
      logging.basicConfig(**opts)
  
  
  class hybridmethod(object):
      """Decorator for hybrid instance/class methods that will act like a normal
      method if accessed via an instance, but act like classmethod if accessed
      via the class."""
  
      def __init__(self, func):
          self.func = func
  
      def __get__(self, obj, cls):
          return self.func.__get__(cls if obj is None else obj, obj)
  
      def __set__(self, obj, val):
          raise AttributeError("Cannot overwrite method")
  
  
  def spawn(*args, **kwargs):
      """Start and return daemon thread. ``spawn(func, *args, **kwargs)``."""
      func, args = args[0], args[1:]
      thread = threading.Thread(target=func, args=args, kwargs=kwargs)
      thread.daemon = True
      thread.start()
      return thread
  
  
  def spawn_waitready(init, main):
      """
      Start a thread that runs ``init`` and then ``main``. Wait for ``init`` to
      be finished before returning.
  
      Returns a tuple ``(thread, init_result)``.
      """
      event = threading.Event()
      stack = [event]  # used to exchange arguments with thread, so `event`
      # can be deleted when it has fulfilled its purpose.
  
      def start():
          stack.append(init())
          stack.pop(0).set()
          return main()
  
      thread = spawn(start)
      event.wait()
      return thread, stack.pop()
  
  
  class Timeout(object):
      def __init__(self, timeout):
          if isinstance(timeout, Timeout):
              self.finite = timeout.finite
              self.tmax = timeout.tmax
          else:
              self.finite = timeout is not None and timeout >= 0
              self.tmax = time.time() + timeout if self.finite else None
  
      def expired(self):
          return self.finite and time.time() >= self.tmax
  
      def timeleft(self):
          return max((0, self.tmax - time.time())) if self.finite else None
  
      def sleep(self, interval):
          time.sleep(min(interval, self.timeleft()) if self.finite else interval)
  
  
  def socket_backoff_connect(family, socktype, proto, addr, timeout, attempts):
      """connect will backoff if the response is not ready for a pseudo random number greater than zero and less than
          51e-6, 153e-6, 358e-6, 768e-6, 1587e-6, 3225e-6, 6502e-6, 13056e-6, 26163e-6, 52377e-6
      this should help avoid congestion.
      """
      sock = socket.socket(family, socktype, proto)
      collision = 0
      connecting = True
      while connecting:
          collision += 1
          try:
              sock.settimeout(timeout)
              sock.connect(addr)
              connecting = False
          except socket.timeout:
              if collision == attempts or attempts < 1:
                  raise
              else:
                  sock.close()
                  sock = socket.socket(family, socktype, proto)
                  time.sleep(exp_backoff(collision))
      return sock
  
  
  def exp_backoff(collision):
      """Exponential backoff algorithm from
      Peterson, L.L., and Davie, B.S. Computer Networks: a systems approach. 5th ed. pp. 127
      """
      n = min(collision, 10)
      supremum_adjustment = 1 if n > 3 else 0
      k = random.uniform(0, 2 ** n - supremum_adjustment)
      return k * 0.0000512
  
  
  def get_id_pack(obj):
      """introspects the given "local" object, returns id_pack as expected by BaseNetref
  
      The given object is "local" in the sense that it is from the local cache. Any object in the local cache exists
      in the current address space or is a netref. A netref in the local cache could be from a chained-connection.
      To handle type related behavior properly, the attribute `__class__` is a descriptor for netrefs.
  
      So, check thy assumptions regarding the given object when creating `id_pack`.
      """
      if hasattr(obj, "____id_pack__"):
          # netrefs are handled first since __class__ is a descriptor
          return obj.____id_pack__
      elif inspect.ismodule(obj) or getattr(obj, "__name__", None) == "module":
          # TODO: not sure about this, need to enumerate cases in units
          if isinstance(obj, type):  # module
              obj_cls = type(obj)
              name_pack = "{0}.{1}".format(obj_cls.__module__, obj_cls.__name__)
              return (name_pack, id(type(obj)), id(obj))
          else:
              if inspect.ismodule(obj) and obj.__name__ != "module":
                  if obj.__name__ in sys.modules:
                      name_pack = obj.__name__
                  else:
                      name_pack = "{0}.{1}".format(obj.__class__.__module__, obj.__name__)
              elif inspect.ismodule(obj):
                  name_pack = "{0}.{1}".format(obj.__module__, obj.__name__)
                  print(name_pack)
              elif hasattr(obj, "__module__"):
                  name_pack = "{0}.{1}".format(obj.__module__, obj.__name__)
              else:
                  obj_cls = type(obj)
                  name_pack = "{0}".format(obj.__name__)
              return (name_pack, id(type(obj)), id(obj))
      elif not inspect.isclass(obj):
          name_pack = "{0}.{1}".format(obj.__class__.__module__, obj.__class__.__name__)
          return (name_pack, id(type(obj)), id(obj))
      else:
          name_pack = "{0}.{1}".format(obj.__module__, obj.__name__)
          return (name_pack, id(obj), 0)
  
  
  def get_methods(obj_attrs, obj):
      """introspects the given (local) object, returning a list of all of its
      methods (going up the MRO).
  
      :param obj: any local (not proxy) python object
  
      :returns: a list of ``(method name, docstring)`` tuples of all the methods
                of the given object
      """
      methods = {}
      attrs = {}
      if isinstance(obj, type):
          # don't forget the darn metaclass
          mros = list(reversed(type(obj).__mro__)) + list(reversed(obj.__mro__))
      else:
          mros = reversed(type(obj).__mro__)
      for basecls in mros:
          attrs.update(basecls.__dict__)
      for name, attr in attrs.items():
          if name not in obj_attrs and hasattr(attr, "__call__"):
              try:
                  methods[name] = inspect.getdoc(attr)
              except:
                  pass
      return methods.items()
  