class GenerateConditionalGFunctionClass {
        // key:name such as g,g2  value:user-role mapping
        private static Map<String, Map<String, AviatorBoolean>> memorizedMap = new ConcurrentHashMap<>();

        /**
         * GenerateConditionalGFunction is the factory method of the g(_, _[, _]) function with conditions.
         *
         * @param name the name of the g(_, _) function, can be "g", "g2", ..
         * @param condRm  the conditional role manager used by the function.
         * @return the function.
         */
        public static AviatorFunction generateConditionalGFunction(String name, ConditionalRoleManager condRm) {
            memorizedMap.put(name, new ConcurrentHashMap<>());

            return new AbstractVariadicFunction() {
                @Override
                public AviatorObject variadicCall(Map<String, Object> env, AviatorObject... args) {
                    Map<String, AviatorBoolean> memorized = memorizedMap.get(name);
                    int len = args.length;
                    if (len < 2) {
                        return AviatorBoolean.valueOf(false);
                    }
                    String name1 = FunctionUtils.getStringValue(args[0], env);
                    String name2 = FunctionUtils.getStringValue(args[1], env);

                    String key = "";
                    for (AviatorObject arg : args) {
                        String name = FunctionUtils.getStringValue(arg, env);
                        key += ";" + name;
                    }

                    AviatorBoolean value = memorized.get(key);
                    if (value != null) {
                        return value;
                    }

                    boolean hasLink;
                    if (condRm == null) {
                        hasLink = name1.equals(name2);
                    } else if (len == 2) {
                        hasLink = condRm.hasLink(name1, name2);
                    } else if (len == 3) {
                        String domain = FunctionUtils.getStringValue(args[2], env);
                        hasLink = condRm.hasLink(name1, name2, domain);
                    } else {
                        hasLink = false;
                    }
                    value = AviatorBoolean.valueOf(hasLink);
                    memorized.put(key, value);
                    return value;
                }

                @Override
                public String getName() {
                    return name;
                }
            };
        }
    }

    /**
     * eval calculates the stringified boolean expression and return its result.
     *
     * @param eval        the stringified boolean expression.
     * @param env         the key-value pair of the parameters in the expression.
     * @param aviatorEval the AviatorEvaluatorInstance object which contains built-in functions and custom functions.
     * @return the result of the eval.
     */
    public static boolean eval(String eval, Map<String, Object> env, AviatorEvaluatorInstance aviatorEval) {
        boolean res;
        if (aviatorEval != null) {
            try {
                res = (boolean) aviatorEval.execute(eval, env);
            } catch (Exception e) {
                Util.logPrintfWarn("Execute 'eval' function error, nested exception is: {}", e.getMessage());
                res = false;
            }
        } else {
            res = (boolean) AviatorEvaluator.execute(eval, env);
        }
        return res;
    }

    // builtin LinkConditionFunc

    /**
     * timeMatchFunc is the wrapper for TimeMatch.
     */
    public static boolean timeMatchFunc(String... args) {
        try {
            validateVariadicStringArgs(2, args);
            return timeMatch(args[0], args[1]);
        } catch (IllegalArgumentException e) {
            System.err.println("TimeMatch: " + e.getMessage());
            return false;
        }
    }

    /**
     * TimeMatch determines whether the current time is between startTime and endTime.
     * You can use "_" to indicate that the parameter is ignored
     */
    public static boolean timeMatch(String startTime, String endTime) {<FILL_FUNCTION_BODY>

        LocalDateTime now = LocalDateTime.now();

        if (!startTime.equals("_")) {
            LocalDateTime start;
            // special process for "0000" year,LocalDateTime range is 1-999999999
            if (startTime.startsWith("0000")){
                start = LocalDateTime.MIN;
            }else {
                start = LocalDateTime.parse(startTime, DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
            }
            if (!now.isAfter(start)) {
                return false;
            }
        }

        if (!endTime.equals("_")) {

            LocalDateTime end;
            // special process for "0000" year,LocalDateTime range is 1-999999999
            if (endTime.startsWith("0000")){
                end = LocalDateTime.MIN;
            }else {
                end = LocalDateTime.parse(endTime, DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
            }
            if (!now.isBefore(end)) {
                return false;
            }
        }

        return true;
    
<no_super_class>