public static UIComponent findPersistent(
      FacesContext context, ServletRequest req, UIComponent parent, String id) throws Exception {
    if (context == null) context = FacesContext.getCurrentInstance();

    BodyContent body = null;

    if (parent == null) {
      UIComponentClassicTagBase parentTag =
          (UIComponentClassicTagBase) req.getAttribute("caucho.jsf.parent");

      parent = parentTag.getComponentInstance();

      body = parentTag.getBodyContent();
    }

    if (parent != null) {
      List<UIComponent> children = parent.getChildren();
      int size = children.size();

      String prevId = null;
      for (int i = 0; i < size; i++) {
        UIComponent child = children.get(i);

        if (id.equals(child.getId())) {
          if (body != null) addVerbatim(parent, prevId, body);

          return child;
        }

        if (child.getId() != null) prevId = child.getId();
      }
    }

    return null;
  }
  private static void renderHandler(
      FacesContext context,
      UIComponent component,
      Collection<ClientBehaviorContext.Parameter> params,
      String handlerName,
      Object handlerValue,
      String behaviorEventName)
      throws IOException {

    ResponseWriter writer = context.getResponseWriter();
    String userHandler = getNonEmptyUserHandler(handlerValue);
    List<ClientBehavior> behaviors = getClientBehaviors(component, behaviorEventName);

    if ((null != behaviors) && (behaviors.size() > 0) && componentIsDisabled(component)) {
      behaviors = null;
    }

    if (params == null) {
      params = Collections.emptyList();
    }
    String handler = null;
    switch (getHandlerType(behaviors, params, userHandler)) {
      case USER_HANDLER_ONLY:
        handler = userHandler;
        break;

      case SINGLE_BEHAVIOR_ONLY:
        handler =
            getSingleBehaviorHandler(
                context, component, behaviors.get(0), params, behaviorEventName);
        break;

      case SUBMIT_ONLY:
        handler = getSubmitHandler(context, component, params, true);
        break;

      case CHAIN:
        handler =
            getChainedHandler(
                context, component, behaviors, params, behaviorEventName, userHandler);
        break;
      default:
        assert (false);
    }

    writer.writeAttribute(handlerName, handler, null);
  }
  private static HandlerType getHandlerType(
      List<ClientBehavior> behaviors,
      Collection<ClientBehaviorContext.Parameter> params,
      String userHandler) {

    if ((behaviors == null) || (behaviors.isEmpty())) {

      if (params.isEmpty()) return HandlerType.USER_HANDLER_ONLY;

      return (userHandler == null) ? HandlerType.SUBMIT_ONLY : HandlerType.CHAIN;
    }

    if ((behaviors.size() == 1) && (userHandler == null)) {
      ClientBehavior behavior = behaviors.get(0);

      if (isSubmitting(behavior) || params.isEmpty()) return HandlerType.SINGLE_BEHAVIOR_ONLY;
    }

    return HandlerType.CHAIN;
  }
  private static void addChild(UIComponent parent, String prevId, UIComponent child) {
    if (parent != null) {
      List<UIComponent> children = parent.getChildren();
      int size = children.size();
      boolean hasPrev = prevId == null;

      int i = 0;
      for (; i < size; i++) {
        UIComponent oldChild = children.get(i);

        if (hasPrev && oldChild.getId() != null) {
          children.add(i, child);

          return;
        } else if (prevId != null && prevId.equals(oldChild.getId())) hasPrev = true;
      }

      parent.getChildren().add(child);
    }
  }