Example #1
0
        /// <summary>
        /// Extended match syntax, can use details from a graph and node
        /// </summary>
        /// <param name="frame">The data frame to select off</param>
        /// <param name="globalMeta">The global meta</param>
        /// <param name="meta">The meta</param>
        /// <param name="node">The current node</param>
        /// <param name="properties">The property bag</param>
        /// <param name="uuid">The uuid for private meta names</param>
        /// <returns>True if the filter matches</returns>
        public bool IsMatch(DataFrame frame, MetaDictionary meta, MetaDictionary globalMeta,
                            PropertyBag properties, Guid uuid, BasePipelineNode node)
        {
            bool ret = true;

            foreach (IDataFrameFilter filter in _filters)
            {
                ret = filter.IsMatch(frame, meta, globalMeta, properties, uuid, node);

                if (_matchAll)
                {
                    if (!ret)
                    {
                        break;
                    }
                }
                else
                {
                    if (ret)
                    {
                        break;
                    }
                }
            }

            if (Invert)
            {
                return(!ret);
            }
            else
            {
                return(ret);
            }
        }
Example #2
0
        private void comboBoxConnection_SelectedIndexChanged(object sender, EventArgs e)
        {
            NetGraph selected = comboBoxConnection.SelectedItem as NetGraph;

            if (selected != null)
            {
                BasePipelineNode selectedNode = comboBoxNodes.SelectedItem as BasePipelineNode;

                comboBoxNodes.Items.Clear();
                AddGraphToComboBox(selected);

                if (selectedNode != null)
                {
                    foreach (BasePipelineNode node in comboBoxNodes.Items)
                    {
                        if (node.Name == selectedNode.Name)
                        {
                            comboBoxNodes.SelectedItem = node;
                            break;
                        }
                    }
                }
            }
            else
            {
                comboBoxNodes.Items.Clear();
            }
        }
        /// <summary>
        /// Create a new pipeline node based on this factory
        /// </summary>
        /// <param name="graph">The netgraph associated with this node</param>
        /// <param name="logger">The logger associated with the graph</param>
        /// <param name="stateDictionary">A dictionary which can be used to store construction state</param>
        /// <returns>The new node</returns>
        public BasePipelineNode Create(Logger logger, NetGraph graph, Dictionary <string, object> stateDictionary)
        {
            BasePipelineNode node = null;

            try
            {
                node = OnCreate(logger, graph, stateDictionary);
                if (node != null)
                {
                    foreach (var pair in Properties)
                    {
                        node.Properties[pair.Key] = pair.Value;
                    }

                    node.Enabled   = Enabled;
                    node.Hidden    = Hidden;
                    node.LogInput  = LogInput;
                    node.LogOutput = LogOutput;
                }
            }
            catch (Exception e)
            {
                throw new NodeFactoryException(String.Format(CANAPE.Properties.Resources.BaseNodeFactory_Create, this.Label, e.Message), e);
            }

            return(node);
        }
Example #4
0
        private void toggleEnableToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (listViewNetGraph.SelectedItems.Count > 0)
            {
                BasePipelineNode node = (BasePipelineNode)listViewNetGraph.SelectedItems[0].Tag;

                node.Enabled = !node.Enabled;
            }
        }
Example #5
0
        private static NetGraph CreateGraph(string name, Logger logger, NetGraph parent, MetaDictionary globalMeta, MetaDictionary meta,
                                            IEnumerable <GraphNodeEntry> nodes, IEnumerable <GraphLineEntry> lines, Dictionary <string, string> props, PropertyBag connectionProperties,
                                            Dictionary <string, object> stateDictionary)
        {
            NetGraph       netGraph        = new NetGraph(logger, parent, globalMeta, meta, connectionProperties);
            HashSet <Guid> referencedNodes = new HashSet <Guid>();

            netGraph.Name = name != null ? name : String.Empty;

            foreach (GraphNodeEntry n in nodes)
            {
                BasePipelineNode pipeNode = n.Factory.Create(logger, netGraph, stateDictionary);
                if (pipeNode == null)
                {
                    throw new InvalidOperationException("One of the nodes failed to create");
                }

                pipeNode.Graph = netGraph;
                pipeNode.Name  = n.Factory.Label;
                pipeNode.Uuid  = n.Id;
                netGraph.AddNode(n.Factory.Id, pipeNode);
            }

            foreach (GraphLineEntry l in lines)
            {
                netGraph.Nodes[l.SourceNode].AddOutput(netGraph.Nodes[l.DestNode], l.PathName, l.WeakPath);
                referencedNodes.Add(l.DestNode);

                if (l.BiDirection)
                {
                    netGraph.Nodes[l.DestNode].AddOutput(netGraph.Nodes[l.SourceNode], l.PathName, l.WeakPath);
                }
            }

            foreach (KeyValuePair <string, string> pair in props)
            {
                netGraph.Meta[pair.Key] = pair.Value;
            }

            foreach (Guid uuid in referencedNodes)
            {
                BasePipelineNode node = netGraph.Nodes[uuid];

                node.SetupShutdownOutputs();

                //foreach (BasePipelineNode output in node.Outputs)
                //{
                //    output.AddShutdownInput(node);
                //}
            }

            return(netGraph);
        }
Example #6
0
        /// <summary>
        /// Select a single node
        /// </summary>
        /// <param name="path">The path to select</param>
        /// <param name="frame">The data frame to select off</param>
        /// <param name="globalMeta">Global meta</param>
        /// <param name="meta">Meta</param>
        /// <param name="properties">PropertyBag</param>
        /// <param name="uuid">Uuid to use for private values</param>
        /// <param name="node">The current node</param>
        /// <returns>The first selected node or null if not found</returns>
        public static DataNode SelectSingleNode(string path, DataFrame frame, MetaDictionary meta, MetaDictionary globalMeta, 
            PropertyBag properties, Guid uuid, BasePipelineNode node)
        {
            DataNode[] nodes = SelectNodes(path, frame, meta, globalMeta, properties, uuid, node);

            if (nodes.Length > 0)
            {
                return nodes[0];
            }
            else
            {
                return null;
            }
        }
Example #7
0
        private void shutdownNodeToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (listViewNetGraph.SelectedItems.Count > 0)
            {
                BasePipelineNode node = (BasePipelineNode)listViewNetGraph.SelectedItems[0].Tag;

                try
                {
                    node.Shutdown(null);
                }
                catch
                {
                }
            }
        }
Example #8
0
        private void UpdateNetGraph()
        {
            listViewNetGraph.BeginUpdate();
            foreach (ListViewItem item in listViewNetGraph.Items)
            {
                BasePipelineNode node = (BasePipelineNode)item.Tag;

                item.SubItems[0].Text = node.ToString();
                item.SubItems[1].Text = node.Enabled.ToString();
                item.SubItems[2].Text = node.IsShutdown.ToString();
                item.SubItems[3].Text = node.InputPacketCount.ToString();
                item.SubItems[4].Text = node.OutputPacketCount.ToString();
                item.SubItems[5].Text = node.ByteCount.ToString();
            }
            listViewNetGraph.EndUpdate();
        }
Example #9
0
        private void pastePacketsToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (listViewNetGraph.SelectedItems.Count > 0)
            {
                BasePipelineNode node = (BasePipelineNode)listViewNetGraph.SelectedItems[0].Tag;
                if (!node.IsShutdown)
                {
                    LogPacket[] packets = (LogPacket[])Clipboard.GetData(LogPacket.LogPacketArrayFormat);

                    foreach (LogPacket packet in packets)
                    {
                        node.Input(packet.Frame.CloneFrame());
                    }
                }
            }
        }
Example #10
0
        /// <summary>
        /// Extended match syntax, can use details from a graph and node
        /// </summary>
        /// <param name="frame">The data frame to select off</param>
        /// <param name="globalMeta">The global meta</param>
        /// <param name="meta">Meta</param>
        /// <param name="node">The current node</param>
        /// <param name="properties">Property bag</param>
        /// <param name="uuid">The uuid for private names</param>
        /// <returns>True if the filter matches</returns>
        public bool IsMatch(DataFrame frame, MetaDictionary meta, MetaDictionary globalMeta, PropertyBag properties,
                            Guid uuid, BasePipelineNode node)
        {
            bool match = false;

            DataNode[] nodes = GeneralUtils.SelectNodes(Path, frame, meta, globalMeta, properties, uuid, node);

            match = OnMatch(nodes);

            if (Invert)
            {
                return(!match);
            }
            else
            {
                return(match);
            }
        }
Example #11
0
        private void AddGraphToList(List <ListViewItem> items, NetGraph graph)
        {
            foreach (var pair in graph.Nodes)
            {
                BasePipelineNode node = pair.Value;

                if (_showHidden || !node.Hidden)
                {
                    NetGraphContainerNode container = node as NetGraphContainerNode;

                    if (node is NetGraphContainerNode)
                    {
                        AddGraphToList(items, ((NetGraphContainerNode)node).ContainedGraph);
                    }
                    else if (node is LayerSectionNode)
                    {
                        LayerSectionNode layerNode = (LayerSectionNode)node;

                        if (layerNode.IsMaster)
                        {
                            foreach (NetGraph subGraph in layerNode.Graphs)
                            {
                                AddGraphToList(items, subGraph);
                            }
                        }
                    }
                    else
                    {
                        ListViewItem item = new ListViewItem(node.ToString());
                        item.SubItems.Add(node.Enabled.ToString());
                        item.SubItems.Add(node.IsShutdown.ToString());
                        item.SubItems.Add(node.InputPacketCount.ToString());
                        item.SubItems.Add(node.OutputPacketCount.ToString());
                        item.SubItems.Add(node.ByteCount.ToString());
                        item.Tag = node;
                        items.Add(item);
                    }
                }
            }
        }
Example #12
0
        /// <summary>
        /// Create a new pipeline node based on this factory
        /// </summary>
        /// <param name="graph">The netgraph associated with this node</param>
        /// <param name="logger">The logger associated with the graph</param>
        /// <param name="stateDictionary">A dictionary which can be used to store construction state</param>
        /// <returns>The new node</returns>
        public BasePipelineNode Create(Logger logger, NetGraph graph, Dictionary <string, object> stateDictionary)
        {
            BasePipelineNode node = null;

            try
            {
                node = OnCreate(logger, graph, stateDictionary);
                if (node != null)
                {
                    foreach (var pair in Properties)
                    {
                        node.Properties[pair.Key] = pair.Value;
                    }

                    DataFrameFilterExpression filters = new DataFrameFilterExpression(MatchAllFilters);

                    foreach (DataFrameFilterFactory factory in Filters)
                    {
                        if (factory.Enabled)
                        {
                            filters.Add(factory.CreateFilter());
                        }
                    }

                    node.Filters       = filters;
                    node.Enabled       = Enabled;
                    node.SelectionPath = SelectionPath;
                    node.Hidden        = Hidden;
                    node.LogInput      = LogInput;
                    node.LogOutput     = LogOutput;
                }
            }
            catch (Exception e)
            {
                throw new NodeFactoryException(String.Format(CANAPE.Properties.Resources.BaseNodeFactory_Create, this.Label, e.Message), e);
            }

            return(node);
        }
Example #13
0
            public bool IsMatch(DataFrame frame, MetaDictionary meta, MetaDictionary globalMeta, PropertyBag properties, Guid uuid, BasePipelineNode node)
            {
                switch (_arrity)
                {
                case 1:
                    return(_filterFunc(frame));

                case 2:
                    return(_filterFunc(frame, meta));

                case 3:
                    return(_filterFunc(frame, meta, globalMeta));

                case 4:
                    return(_filterFunc(frame, meta, globalMeta, properties));

                case 5:
                    return(_filterFunc(frame, meta, globalMeta, properties, uuid));

                case 6:
                    return(_filterFunc(frame, meta, globalMeta, properties, uuid, node));

                default:
                    break;
                }

                return(false);
            }
Example #14
0
 /// <summary>
 /// Constructor
 /// </summary>
 /// <param name="graph">The current netgraph</param>
 /// <param name="input">The input pipeline node</param>
 /// <param name="output">The output pipeline node</param>
 internal TestGraphContainer(NetGraph graph, BasePipelineNode input, BasePipelineNode output)
 {
     Graph  = graph;
     Input  = input;
     Output = output;
 }
Example #15
0
        private static NetGraph BuildGraph(ScriptContainer container, string classname, string selectionPath, out BasePipelineNode input, out ParseWithPipelineNode output)
        {
            DynamicNodeFactory           factory          = new DynamicNodeFactory("", Guid.NewGuid(), container, classname, null);
            ParseWithPipelineNodeFactory parseWithFactory = new ParseWithPipelineNodeFactory();

            factory.SelectionPath = selectionPath;

            NetGraphBuilder builder = new NetGraphBuilder();

            builder.AddNode(factory);
            builder.AddNode(parseWithFactory);
            builder.AddLine(factory, parseWithFactory, null);

            NetGraph graph = builder.Factory.Create(Logger.GetSystemLogger(), null, new MetaDictionary(), new MetaDictionary(), new PropertyBag("Connection"));

            input  = graph.Nodes[factory.Id];
            output = (ParseWithPipelineNode)graph.Nodes[parseWithFactory.Id];

            return(graph);
        }
Example #16
0
        /// <summary>
        ///
        /// </summary>
        /// <returns></returns>
        protected override BasePipelineNode OnCreate(Logger logger, NetGraph graph, Dictionary <string, object> stateDictionary)
        {
            BasePipelineNode node = null;

            if (Container != null)
            {
                try
                {
                    if (String.IsNullOrWhiteSpace(ClassName))
                    {
                        throw new ArgumentException(String.Format(CANAPE.Scripting.Properties.Resources.DynamicNodeFactory_MustSpecifyClassName, Label));
                    }

                    // Determine what type of object we create, if it is an BasePipelineNode then return as is,
                    // if it is a parser then create the parsing pipeline node to contain it
                    object o = ScriptUtils.GetInstance(Container, ClassName);
                    if (o is BasePipelineNode)
                    {
                        node = o as BasePipelineNode;
                        if (State != null)
                        {
                            IPersistNode persist = node as IPersistNode;
                            if (persist != null)
                            {
                                persist.SetState(State, logger);
                            }
                        }
                    }
                    else if (o is IDataStreamParser)
                    {
                        // If we are selecting the whole packet, then we convert a binary stream
                        if (SelectionPath == "/")
                        {
                            DynamicBinaryStreamPipelineNode stmNode = new DynamicBinaryStreamPipelineNode();
                            stmNode.Container = DynamicScriptContainer.Create(Container, ClassName);
                            stmNode.State     = State;

                            node = stmNode;
                        }
                        else
                        {
                            DynamicStreamPipelineNode dynNode = new DynamicStreamPipelineNode();

                            dynNode.Container = DynamicScriptContainer.Create(Container, ClassName);
                            dynNode.State     = State;

                            node = dynNode;
                        }
                    }
                    else if (o is IDataArrayParser)
                    {
                        DynamicArrayPipelineNode dynNode = new DynamicArrayPipelineNode();

                        dynNode.Container = DynamicScriptContainer.Create(Container, ClassName);
                        dynNode.State     = State;

                        node = dynNode;
                    }
                    else if (o is IDataStringParser)
                    {
                        DynamicStringPipelineNode dynNode = new DynamicStringPipelineNode();

                        dynNode.Container = DynamicScriptContainer.Create(Container, ClassName);
                        dynNode.State     = State;

                        node = dynNode;
                    }
                    else if (o == null)
                    {
                        throw new InvalidOperationException(String.Format(CANAPE.Scripting.Properties.Resources.DynamicNodeFactory_CannotCreateType, ClassName, Label));
                    }
                    else
                    {
                        throw new InvalidOperationException(String.Format(CANAPE.Scripting.Properties.Resources.DynamicNodeFactory_InvalidNodeType, o.GetType().Name, Label));
                    }

                    node.Enabled = Enabled;
                }
                catch (EndOfStreamException)
                {
                    // End of stream
                }
                catch (ThreadAbortException)
                {
                }
            }
            else
            {
                throw new ArgumentException(String.Format(CANAPE.Scripting.Properties.Resources.DynamicNodeFactory_NoScriptSpecified, Label));
            }

            return(node);
        }
Example #17
0
        private void btnInject_Click(object sender, EventArgs e)
        {
            if (_injectGraph != null)
            {
                CancelInject();
            }
            else
            {
                try
                {
                    NetGraph selectedGraph = comboBoxConnection.SelectedItem as NetGraph;

                    while ((selectedGraph == null) || (selectedGraph.CheckShutdown()))
                    {
                        PopulateConnections();

                        if (comboBoxConnection.Items.Count == 0)
                        {
                            selectedGraph = null;
                            break;
                        }

                        comboBoxConnection.SelectedItem = comboBoxConnection.Items[0];

                        selectedGraph = comboBoxConnection.SelectedItem as NetGraph;
                    }

                    if (selectedGraph != null)
                    {
                        if (logPacketControl.Packets.Length > 0)
                        {
                            if (comboBoxNodes.SelectedItem != null)
                            {
                                int repeatCount       = (int)numericRepeatCount.Value;
                                BasePipelineNode node = (BasePipelineNode)comboBoxNodes.SelectedItem;

                                LogPacket[] basePackets = checkBoxInjectSelected.Checked ? logPacketControl.SelectedPackets : logPacketControl.Packets;

                                List <LogPacket> packets = new List <LogPacket>();

                                for (int i = 0; i < repeatCount; ++i)
                                {
                                    packets.AddRange((LogPacket[])GeneralUtils.CloneObject(basePackets));
                                }

                                NetGraphBuilder builder = new NetGraphBuilder();

                                ClientEndpointFactory client = builder.AddClient("client", Guid.NewGuid());
                                ServerEndpointFactory server = builder.AddServer("server", Guid.NewGuid());
                                DynamicNodeFactory    dyn    = null;

                                BaseNodeFactory startNode = client;

                                if (_config.EnablePacketDelay && (_config.PacketDelayMs > 0))
                                {
                                    DelayNodeFactory delay = builder.AddNode(new DelayNodeFactory("delay", Guid.NewGuid())
                                    {
                                        PacketDelayMs = (int)_config.PacketDelayMs
                                    });
                                    builder.AddLine(startNode, delay, null);
                                    startNode = delay;
                                }

                                if (_config.EnableScripting && _config.ScriptDocumentId != Guid.Empty && !String.IsNullOrWhiteSpace(_config.ScriptDocumentClass))
                                {
                                    ScriptDocument doc = CANAPEProject.CurrentProject.GetDocumentByUuid(_config.ScriptDocumentId) as ScriptDocument;

                                    if (doc != null)
                                    {
                                        dyn = new DynamicNodeFactory("dyn", Guid.NewGuid(), doc.Container, _config.ScriptDocumentClass, null);

                                        builder.AddNode(dyn);
                                        builder.AddLine(startNode, dyn, null);
                                        startNode = dyn;
                                    }
                                }

                                builder.AddLine(startNode, server, null);

                                _injectGraph = builder.Factory.Create(selectedGraph.Logger, selectedGraph, selectedGraph.GlobalMeta,
                                                                      new MetaDictionary(), new PropertyBag("root"));

                                QueuedDataAdapter inputAdapter = new QueuedDataAdapter();
                                foreach (LogPacket p in packets)
                                {
                                    inputAdapter.Enqueue(p.Frame);
                                }
                                inputAdapter.StopEnqueue();

                                _injectGraph.BindEndpoint(client.Id, inputAdapter);


                                _injectGraph.BindEndpoint(server.Id, new DelegateDataAdapter(
                                                              () => this.CancelInject(),
                                                              frame => node.Input(frame),
                                                              null
                                                              ));

                                // Start injection
                                (_injectGraph.Nodes[client.Id] as IPipelineEndpoint).Start();

                                // Check if the dynamic node was an endpoint (so a generator), start as well
                                if ((dyn != null) && (_injectGraph.Nodes[dyn.Id] is PipelineEndpoint))
                                {
                                    (_injectGraph.Nodes[dyn.Id] as IPipelineEndpoint).Start();
                                }

                                // Start cancel timer
                                timerCancel.Start();

                                btnInject.Text = CANAPE.Properties.Resources.InjectPacketControl_CancelButtonText;
                            }
                            else
                            {
                                MessageBox.Show(this, CANAPE.Properties.Resources.InjectPacketForm_SelectNode,
                                                CANAPE.Properties.Resources.MessageBox_ErrorString, MessageBoxButtons.OK,
                                                MessageBoxIcon.Error);
                            }
                        }
                    }
                    else
                    {
                        MessageBox.Show(this, CANAPE.Properties.Resources.InjectPacketForm_SelectGraph,
                                        CANAPE.Properties.Resources.MessageBox_ErrorString, MessageBoxButtons.OK,
                                        MessageBoxIcon.Error);
                    }
                }
                catch (NotSupportedException)
                {
                    MessageBox.Show(this, CANAPE.Properties.Resources.InjectPacketForm_NotSupported,
                                    CANAPE.Properties.Resources.MessageBox_ErrorString, MessageBoxButtons.OK, MessageBoxIcon.Error);
                }
                catch (InvalidOperationException ex)
                {
                    MessageBox.Show(this, ex.Message,
                                    CANAPE.Properties.Resources.MessageBox_ErrorString, MessageBoxButtons.OK, MessageBoxIcon.Error);
                }
                catch (NodeFactoryException ex)
                {
                    MessageBox.Show(this, ex.Message,
                                    CANAPE.Properties.Resources.MessageBox_ErrorString, MessageBoxButtons.OK, MessageBoxIcon.Error);
                }
            }
        }
Example #18
0
        /// <summary>
        /// Extend selection syntax for nodes to handle global and meta parameters through
        /// # and $ prefixes
        /// </summary>
        /// <param name="path">The path to select</param>
        /// <param name="frame">The data frame to select off</param>
        /// <param name="node">The current node</param>
        /// <param name="globalMeta">Global meta</param>
        /// <param name="properties">Property bag</param>
        /// <param name="uuid">The uuid for private names</param>
        /// <param name="meta">Meta</param>
        /// <returns>An array of nodes</returns>
        public static DataNode[] SelectNodes(string path, DataFrame frame, MetaDictionary meta, MetaDictionary globalMeta, 
            PropertyBag properties, Guid uuid, BasePipelineNode node)
        {
            DataNode[] nodes = new DataNode[0];

            path = path.Trim();

            if (path.StartsWith("#"))
            {
                if (meta != null)
                {
                    string name = path.Substring(1);
                    object n = meta.GetMeta(MakePrivateMetaName(uuid, name));
                    if(n == null)
                    {
                        n = meta.GetMeta(name);
                    }

                    if (n != null)
                    {
                        nodes = new DataNode[1];
                        nodes[0] = new StringDataValue(path, n.ToString());
                    }
                }
            }
            else if (path.StartsWith("$"))
            {
                if (globalMeta != null)
                {
                    string name = path.Substring(1);
                    object n = globalMeta.GetMeta(MakePrivateMetaName(uuid, name));
                    if (n == null)
                    {
                        n = globalMeta.GetMeta(name);
                    }

                    if (n != null)
                    {
                        nodes = new DataNode[1];
                        nodes[0] = new StringDataValue(path, n.ToString());
                    }
                }
            }
            else if (path.StartsWith("~"))
            {
                if(properties != null)
                {
                    string name = path.Substring(1);
                    dynamic val = properties.GetRelativeValue(name);

                    if (val != null)
                    {
                        nodes = new DataNode[1];
                        nodes[0] = new StringDataValue(path, val.ToString());
                    }
                }
            }
            else if (path.StartsWith("&"))
            {
                DataNode n = null;

                if (path.Equals("&incount", StringComparison.OrdinalIgnoreCase))
                {
                    n = new GenericDataValue<int>(path, node != null ? node.InputPacketCount : 0);
                }
                else if (path.Equals("&outcount", StringComparison.OrdinalIgnoreCase))
                {
                    n = new GenericDataValue<int>(path, node != null ? node.OutputPacketCount : 0);
                }
                else if (path.Equals("&bytecount", StringComparison.OrdinalIgnoreCase))
                {
                    n = new GenericDataValue<long>(path, node != null ? node.ByteCount : 0);
                }
                else if (path.Equals("&length", StringComparison.OrdinalIgnoreCase))
                {
                    n = new GenericDataValue<long>(path, frame.Length);
                }
                else if (path.Equals("&md5", StringComparison.OrdinalIgnoreCase))
                {
                    n = new StringDataValue(path, frame.Hash);
                }
                else if (path.Equals("&display", StringComparison.OrdinalIgnoreCase))
                {
                    n = new StringDataValue(path, frame.ToString());
                }

                if (n != null)
                {
                    nodes = new DataNode[1];
                    nodes[0] = n;
                }
            }
            else
            {
                nodes = frame.SelectNodes(path);
            }

            return nodes;
        }