docs: def connect(ipAddr, port, password):
      """Connect to cjdns admin with this attributes"""
  
      sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
      sock.connect((ipAddr, port))
      sock.settimeout(2)
  
      # Make sure it pongs.
      sock.send(b'd1:q4:pinge')
      data = sock.recv(BUFFER_SIZE)
      if not data.endswith(b'1:q4:ponge'):
          raise exceptions.NotACjdnsAdminSocket("Looks like %s:%d is to a non-cjdns socket.",
                                                (ipAddr, port))
  
      # Get the functions and make the object
      page = 0
      availableFunctions = {}
      while True:
          sock.send(bytearray(
              'd1:q24:Admin_availableFunctions4:argsd4:pagei%seee' % page,
              'utf-8'))
          data = sock.recv(BUFFER_SIZE)
          benc = bdecode(data)
          for func in benc['availableFunctions']:
              availableFunctions[func] = benc['availableFunctions'][func]
          if 'more' not in benc:
              break
          page = page+1
  
      funcArgs = {}
      funcOargs = {}
  
      for (i, func) in availableFunctions.items():
          items = func.items()
  
          # grab all the required args first
          # append all the optional args
          rargList = [arg for arg, atts in items if atts['required']]
          argList = rargList + [
              arg for arg, atts in items if not atts['required']]
  
          # for each optional arg setup a default value with
          # a type which will be ignored by the core.
          oargList = {}
          for (arg, atts) in items:
              if not atts['required']:
                  oargList[arg] = (
                      "''" if func[arg]['type'] == 'Int'
                      else "")
  
          setattr(Session, i, _functionFabric(
              i, argList, oargList, password))
  
          funcArgs[i] = rargList
          funcOargs[i] = oargList
  
      session = Session(sock)
  
      kat = threading.Thread(target=_receiverThread, args=[session])
      kat.setDaemon(True)
      kat.start()
  
      # Check our password.
      ret = _callFunc(session, "ping", password, {})
      if 'error' in ret:
          raise exceptions.InvalidAdminPassword(ret.get("error"))
  
      session._functions = ""
  
      funcOargs_c = {}
      for func in funcOargs:
          funcOargs_c[func] = list([
              key + "=" + str(value) for (key, value) in funcOargs[func].items()
          ])
  
      for func in availableFunctions:
          session._functions += (
              func + "(" + ', '.join(funcArgs[func] + funcOargs_c[func]) + ")\n")
  
      return session