///Refletion nodes on a type
        public static UnityEditor.GenericMenu AppendTypeReflectionNodesMenu(this FlowGraph graph, UnityEditor.GenericMenu menu, System.Type type, string baseCategory, Vector2 pos, Port sourcePort, object dropInstance)
        {
            if (!string.IsNullOrEmpty(baseCategory))
            {
                baseCategory += "/";
            }

            var typeCategory = baseCategory + type.FriendlyName();

            var icon = UserTypePrefs.GetTypeIcon(type);

            if (type.IsValueType && !type.IsPrimitive)
            {
                if (sourcePort == null || (sourcePort is ValueOutput && type.IsAssignableFrom(sourcePort.type)))
                {
                    var extractName = string.Format("Extract {0}", type.FriendlyName());
                    menu.AddItem(new GUIContent(typeCategory + "/" + extractName, icon, null), false, () => { graph.AddReflectedExtractorNode(type, pos, sourcePort, dropInstance); });
                }
            }

            if (sourcePort is ValueInput)
            {
                if (sourcePort.type == type)
                {
                    var portValue = (sourcePort as ValueInput).serializedValue;
                    menu.AddItem(new GUIContent("Make Constant Variable", icon, null), false, (o) => { graph.AddVariableGet((System.Type)o, null, pos, sourcePort, portValue); }, type);
                    menu.AddItem(new GUIContent("Make Linked Variable", icon, null), false, (o) =>
                    {
                        var bbVar = graph.blackboard.AddVariable(sourcePort.name, sourcePort.type);
                        graph.AddVariableGet((System.Type)o, bbVar.name, pos, sourcePort, portValue);
                    }, type);
                    menu.AddSeparator("/");
                }
            }


            //Constructors
            if (!type.IsAbstract && !type.IsInterface && !type.IsPrimitive && type != typeof(string))
            {
                foreach (var _c in type.RTGetConstructors())
                {
                    var c = _c;
                    if (!c.IsPublic || c.IsObsolete())
                    {
                        continue;
                    }

                    if (sourcePort is FlowInput || sourcePort is FlowOutput)
                    {
                        continue;
                    }

                    var parameters = c.GetParameters();
                    if (sourcePort is ValueOutput)
                    {
                        if (!parameters.Any(p => p.ParameterType.IsAssignableFrom(sourcePort.type)))
                        {
                            continue;
                        }
                    }

                    if (sourcePort is ValueInput)
                    {
                        if (!sourcePort.type.IsAssignableFrom(type))
                        {
                            continue;
                        }
                    }

                    var categoryName = typeCategory + "/" + "Constructors/";
                    var name         = categoryName + c.SignatureName();

                    if (typeof(Component).IsAssignableFrom(type))
                    {
                        if (type == typeof(Transform))
                        {
                            continue;
                        }
                        var stubType = typeof(AddComponent <>).MakeGenericType(type);
                        menu.AddItem(new GUIContent(name, icon, null), false, () => { graph.AddSimplexNode(stubType, pos, sourcePort, dropInstance); });
                        continue;
                    }

                    if (typeof(ScriptableObject).IsAssignableFrom(type))
                    {
                        var stubType = typeof(NewScriptableObject <>).MakeGenericType(type);
                        menu.AddItem(new GUIContent(name, icon, null), false, () => { graph.AddSimplexNode(stubType, pos, sourcePort, dropInstance); });
                        continue;
                    }

                    //exclude types like Mathf, Random, Time etc (they are not static)
                    if (!UserTypePrefs.functionalTypesBlacklist.Contains(type))
                    {
                        menu.AddItem(new GUIContent(name, icon, null), false, (o) => { graph.AddContructorNode((ConstructorInfo)o, pos, sourcePort, dropInstance); }, c);
                    }
                }
            }

            //Methods
            var methods = type.RTGetMethods().ToList();

            methods.AddRange(type.GetExtensionMethods());
            foreach (var _m in methods.OrderBy(_m => !_m.IsStatic).OrderBy(_m => _m.GetMethodSpecialType()).OrderBy(_m => _m.DeclaringType != type))
            {
                var m = _m;
                if (!m.IsPublic || m.IsObsolete())
                {
                    continue;
                }

                //convertions are handled automatically at a connection level
                if (m.Name == "op_Implicit" || m.Name == "op_Explicit")
                {
                    continue;
                }

                var isGeneric = m.IsGenericMethod && m.GetGenericArguments().Length == 1;
                if (isGeneric)
                {
                    if (sourcePort != null && sourcePort.IsValuePort())
                    {
                        if (m.CanBeMadeGenericWith(sourcePort.type))
                        {
                            m = m.MakeGenericMethod(sourcePort.type);
                        }
                        else
                        {
                            continue;
                        }
                    }
                }

                var parameters = m.GetParameters();
                if (sourcePort is ValueOutput)
                {
                    if (type != sourcePort.type || m.IsStatic)
                    {
                        if (!parameters.Any(p => p.ParameterType.IsAssignableFrom(sourcePort.type)))
                        {
                            continue;
                        }
                    }
                }

                if (sourcePort is ValueInput)
                {
                    if (!sourcePort.type.IsAssignableFrom(m.ReturnType) && !parameters.Any(p => p.IsOut && sourcePort.type.IsAssignableFrom(p.ParameterType)))
                    {
                        continue;
                    }
                }

                if (sourcePort is FlowInput || sourcePort is FlowOutput)
                {
                    if (m.ReturnType != typeof(void))
                    {
                        continue;
                    }
                }

                var categoryName  = typeCategory;
                var signatureName = m.SignatureName();
                var specialType   = m.GetMethodSpecialType();
                if (specialType == ReflectionTools.MethodType.Normal)
                {
                    categoryName += "/Methods/";
                }
                if (specialType == ReflectionTools.MethodType.PropertyAccessor)
                {
                    categoryName += "/Properties/";
                }
                if (specialType == ReflectionTools.MethodType.Operator)
                {
                    categoryName += "/Operators/";
                }
                if (specialType == ReflectionTools.MethodType.Event)
                {
                    categoryName += "/Events/";
                }

                //Unity Event special case
                if (typeof(UnityEventBase).IsAssignableFrom(m.ReturnType) && specialType == ReflectionTools.MethodType.PropertyAccessor)
                {
                    categoryName = typeCategory + "/Events/";
                }

                var isExtension = m.IsExtensionMethod();
                if (m.DeclaringType != type)
                {
                    categoryName += isExtension? "Extensions/" : "Inherited/";
                }
                var name = categoryName + signatureName;
                menu.AddItem(new GUIContent(name, icon, null), false, (o) => { graph.AddMethodNode((MethodInfo)o, pos, sourcePort, dropInstance); }, m);
            }

            //Fields
            foreach (var _f in type.RTGetFields())
            {
                var f = _f;
                if (!f.IsPublic || f.IsObsolete())
                {
                    continue;
                }

                var isReadOnly = f.IsReadOnly();
                var isConstant = f.IsConstant();

                if (sourcePort is ValueOutput)
                {
                    if (type != sourcePort.type || isConstant)
                    {
                        if (isReadOnly || !f.FieldType.IsAssignableFrom(sourcePort.type))
                        {
                            continue;
                        }
                    }
                }

                if (sourcePort is ValueInput)
                {
                    if (!sourcePort.type.IsAssignableFrom(f.FieldType))
                    {
                        continue;
                    }
                }

                var isUnityEvent = typeof(UnityEventBase).IsAssignableFrom(f.FieldType);
                var categoryName = typeCategory + (isUnityEvent? "/Events/" :  "/Fields/");
                if (f.DeclaringType != type)
                {
                    categoryName += "Inherited/";
                }

                //Unity Event
                if (isUnityEvent)
                {
                    menu.AddItem(new GUIContent(categoryName + f.Name + " (Auto Subscribe)", icon, null), false, (o) => { graph.AddUnityEventAutoCallbackNode((FieldInfo)o, pos, sourcePort, dropInstance); }, f);
                    menu.AddItem(new GUIContent(categoryName + f.Name + " (Get Reference)", icon, null), false, (o) => { graph.AddFieldGetNode((FieldInfo)o, pos, sourcePort, dropInstance); }, f);
                    continue;
                }

                var nameForGet = categoryName + (isConstant? "constant " + f.Name : "Get " + f.Name);
                menu.AddItem(new GUIContent(nameForGet, icon, null), false, (o) => { graph.AddFieldGetNode((FieldInfo)o, pos, sourcePort, dropInstance); }, f);

                if (!isReadOnly)
                {
                    var nameForSet = categoryName + "Set " + f.Name;
                    menu.AddItem(new GUIContent(nameForSet, icon, null), false, (o) => { graph.AddFieldSetNode((FieldInfo)o, pos, sourcePort, dropInstance); }, f);
                }
            }


            //C# Events
            foreach (var _info in type.RTGetEvents())
            {
                var info         = _info;
                var categoryName = typeCategory + "/Events/";
                menu.AddItem(new GUIContent(categoryName + info.Name + " (Auto Subscribe)", icon), false, (o) => { graph.AddCSharpEventAutoCallbackNode((EventInfo)o, pos, sourcePort, dropInstance); }, info);
                menu.AddItem(new GUIContent(categoryName + info.Name + " (Get Reference)", icon), false, (o) => { graph.AddCSharpGetNode((EventInfo)o, pos, sourcePort, dropInstance); }, info);
            }

            return(menu);
        }
        //FlowNode
        public static UnityEditor.GenericMenu AppendFlowNodesMenu(this FlowGraph graph, UnityEditor.GenericMenu menu, string baseCategory, Vector2 pos, Port sourcePort, object dropInstance)
        {
            var infos       = EditorUtils.GetScriptInfosOfType(typeof(FlowNode));
            var generalized = new List <System.Type>();

            foreach (var _info in infos)
            {
                var info = _info;
                if (sourcePort != null)
                {
                    if (generalized.Contains(info.originalType))
                    {
                        continue;
                    }

                    if (sourcePort.IsValuePort())
                    {
                        if (info.originalType.IsGenericTypeDefinition)
                        {
                            var genericInfo = info.MakeGenericInfo(sourcePort.type);
                            if (genericInfo != null)
                            {
                                info = genericInfo;
                                generalized.Add(info.originalType);
                            }
                        }
                    }

                    var           definedInputTypesAtts  = info.type.RTGetAttributesRecursive <FlowNode.ContextDefinedInputsAttribute>();
                    var           definedOutputTypesAtts = info.type.RTGetAttributesRecursive <FlowNode.ContextDefinedOutputsAttribute>();
                    System.Type[] concreteInputTypes     = null;
                    if (definedInputTypesAtts.Length > 0)
                    {
                        concreteInputTypes = definedInputTypesAtts.Select(att => att.types).Aggregate((x, y) => { return(x.Union(y).ToArray()); });
                        concreteInputTypes = AlterTypesDefinition(concreteInputTypes, info.type);
                    }
                    System.Type[] concreteOutputTypes = null;
                    if (definedOutputTypesAtts.Length > 0)
                    {
                        concreteOutputTypes = definedOutputTypesAtts.Select(att => att.types).Aggregate((x, y) => { return(x.Union(y).ToArray()); });
                        concreteOutputTypes = AlterTypesDefinition(concreteOutputTypes, info.type);
                    }

                    if (sourcePort is ValueOutput || sourcePort is FlowOutput)
                    {
                        if (concreteInputTypes == null || !concreteInputTypes.Any(t => t != null && t.IsAssignableFrom(sourcePort.type)))
                        {
                            continue;
                        }
                    }

                    if (sourcePort is ValueInput || sourcePort is FlowInput)
                    {
                        if (concreteOutputTypes == null || !concreteOutputTypes.Any(t => t != null && sourcePort.type.IsAssignableFrom(t)))
                        {
                            continue;
                        }
                    }
                }
                var category = string.Join("/", new string[] { baseCategory, info.category, info.name }).TrimStart('/');
                menu.AddItem(new GUIContent(category, info.icon, info.description), false, () => { graph.AddFlowNode(info.type, pos, sourcePort, dropInstance); });
            }
            return(menu);
        }
        ///Simplex Nodes
        public static UnityEditor.GenericMenu AppendSimplexNodesMenu(this FlowGraph graph, UnityEditor.GenericMenu menu, string baseCategory, Vector2 pos, Port sourcePort, object dropInstance)
        {
            var infos       = EditorUtils.GetScriptInfosOfType(typeof(SimplexNode));
            var generalized = new List <System.Type>();

            foreach (var _info in infos)
            {
                var info = _info;
                if (sourcePort != null)
                {
                    if (generalized.Contains(info.originalType))
                    {
                        continue;
                    }

                    if (sourcePort.IsValuePort())
                    {
                        if (info.originalType.IsGenericTypeDefinition)
                        {
                            var genericInfo = info.MakeGenericInfo(sourcePort.type);
                            if (genericInfo != null)
                            {
                                info = genericInfo;
                                generalized.Add(info.originalType);
                            }
                        }
                    }


                    var outProperties = info.type.GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.DeclaredOnly);
                    var method        = info.type.GetMethod("Invoke");
                    if (method != null)
                    {
                        if (sourcePort is ValueOutput)
                        {
                            var parameterTypes = method.GetParameters().Select(p => p.ParameterType).ToArray();
                            if (parameterTypes.Length == 0 || !parameterTypes.Any(t => t.IsAssignableFrom(sourcePort.type)))
                            {
                                continue;
                            }
                        }
                        if (sourcePort is ValueInput)
                        {
                            if (!sourcePort.type.IsAssignableFrom(method.ReturnType) && !outProperties.Any(p => sourcePort.type.IsAssignableFrom(p.PropertyType)))
                            {
                                continue;
                            }
                        }
                        if (sourcePort is FlowOutput || sourcePort is FlowInput)
                        {
                            if (method.ReturnType != typeof(void) && method.ReturnType != typeof(System.Collections.IEnumerator))
                            {
                                continue;
                            }
                            if (info.type.IsSubclassOf(typeof(ExtractorNode)))
                            {
                                continue;
                            }
                        }
                    }
                }

                var category = string.Join("/", new string[] { baseCategory, info.category, info.name }).TrimStart('/');
                menu.AddItem(new GUIContent(category, info.icon, info.description), false, () => { graph.AddSimplexNode(info.type, pos, sourcePort, dropInstance); });
            }
            return(menu);
        }
 //...
 public static T AddFlowNode <T>(this FlowGraph graph, Vector2 pos, Port sourcePort, object dropInstance) where T : FlowNode
 {
     return((T)AddFlowNode(graph, typeof(T), pos, sourcePort, dropInstance));
 }