diff --git a/src/main/java/com/fr/function/TREENODEFINDER.java b/src/main/java/com/fr/function/TREENODEFINDER.java
new file mode 100644
index 0000000..96abe94
--- /dev/null
+++ b/src/main/java/com/fr/function/TREENODEFINDER.java
@@ -0,0 +1,126 @@
+//
+// Source code recreated from a .class file by IntelliJ IDEA
+// (powered by Fernflower decompiler)
+//
+
+package com.fr.function;
+
+import com.fr.base.BaseUtils;
+import com.fr.base.SynchronizedLiveDataModelUtils;
+import com.fr.data.impl.RecursionDataModel;
+import com.fr.general.FArray;
+import com.fr.general.GeneralUtils;
+import com.fr.general.data.DataModel;
+import com.fr.invoke.Reflect;
+import com.fr.script.AbstractFunction;
+import com.fr.script.Calculator;
+import com.fr.security.function.RestrictScript;
+import com.fr.stable.Primitive;
+import com.fr.stable.StringUtils;
+import com.fr.stable.exception.FormulaException;
+
+import java.util.Map;
+
+@RestrictScript
+public class TREENODEFINDER extends AbstractFunction {
+    public TREENODEFINDER() {
+    }
+
+    public Object run(Object[] args) throws FormulaException {
+        if (!this.validateArgs(args)) {
+            return Primitive.ERROR_NAME;
+        } else {
+            boolean noLiveDataModel = !this.liveDataModel4ShareExists();
+            DataModel dataModel = this.generateDataModel(args);
+
+            try {
+                if (args.length != 2) {
+                    return Primitive.NULL;
+                }
+                if (args[0] instanceof FArray) {
+                    FArray nodeArray = (FArray) args[0];
+                    FArray result = new FArray();
+                    for (int i = 0; i < nodeArray.length(); i++) {
+                        result.simpleAdd(this.run(GeneralUtils.objectToString(nodeArray.elementAt(i)), dataModel));
+                    }
+                    return result;
+                } else {
+                    return this.run(GeneralUtils.objectToString(args[0]), dataModel);
+                }
+            } finally {
+                if (noLiveDataModel && dataModel != null) {
+                    try {
+                        dataModel.release();
+                    } catch (Exception var11) {
+                        this.log(var11.getMessage(), var11);
+                    }
+                }
+
+            }
+        }
+    }
+
+    private boolean liveDataModel4ShareExists() {
+        Calculator calculatorProvider = this.getCalculator();
+        if (calculatorProvider == null) {
+            return false;
+        } else {
+            Map var1 = (Map) calculatorProvider.getAttribute(SynchronizedLiveDataModelUtils.CUR_LIVE_RS);
+            return var1 != null && !var1.isEmpty();
+        }
+    }
+
+    public Object run(String nodeValue, DataModel dataModel) {
+        try {
+            RecursionDataModel rdm = Reflect.on(dataModel).get("dataModel");
+            int treeStart = 0;
+
+            int m;
+            for (m = 0; m < rdm.getColumnCount(); ++m) {
+                String colName = rdm.getColumnName(m);
+                if (colName.startsWith("FR_GEN_")) {
+                    treeStart = m;
+                    break;
+                }
+            }
+
+            m = 0;
+
+            for (int len = rdm.getRowCount(); m < len; ++m) {
+                int i = 0;
+
+                for (int colCount = rdm.getColumnCount(); i < colCount; ++i) {
+                    String value = GeneralUtils.objectToString(rdm.getValueAt(m, i));
+                    if (StringUtils.equals(nodeValue, value)) {
+                        FArray array = new FArray();
+
+                        for (int j = treeStart; j < colCount; ++j) {
+                            String val = GeneralUtils.objectToString(rdm.getValueAt(m, j));
+                            if (StringUtils.isNotEmpty(val)) {
+                                array.add(val);
+                            }
+                        }
+
+                        return array;
+                    }
+                }
+            }
+        } catch (Exception var13) {
+            this.log(var13.getMessage(), var13);
+        }
+
+        return Primitive.NULL;
+    }
+
+    public boolean validateArgs(Object[] args) {
+        return args != null && args.length >= 1;
+    }
+
+    public DataModel generateDataModel(Object[] args) {
+        return BaseUtils.getDataModelFromTableDataName(this.getCalculator(), args[1].toString());
+    }
+
+    public Type getType() {
+        return REPORT;
+    }
+}