commit-gnuradio
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Commit-gnuradio] r3977 - gnuradio/branches/developers/eb/mb/mblock/src/


From: eb
Subject: [Commit-gnuradio] r3977 - gnuradio/branches/developers/eb/mb/mblock/src/lib
Date: Mon, 13 Nov 2006 13:48:33 -0700 (MST)

Author: eb
Date: 2006-11-13 13:48:33 -0700 (Mon, 13 Nov 2006)
New Revision: 3977

Modified:
   gnuradio/branches/developers/eb/mb/mblock/src/lib/Makefile.am
   gnuradio/branches/developers/eb/mb/mblock/src/lib/mb_mblock.cc
   gnuradio/branches/developers/eb/mb/mblock/src/lib/mb_mblock.h
   gnuradio/branches/developers/eb/mb/mblock/src/lib/mb_mblock_impl.cc
   gnuradio/branches/developers/eb/mb/mblock/src/lib/mb_mblock_impl.h
   gnuradio/branches/developers/eb/mb/mblock/src/lib/qa_mblock_prims.cc
Log:
work-in-progress

Modified: gnuradio/branches/developers/eb/mb/mblock/src/lib/Makefile.am
===================================================================
--- gnuradio/branches/developers/eb/mb/mblock/src/lib/Makefile.am       
2006-11-13 05:13:03 UTC (rev 3976)
+++ gnuradio/branches/developers/eb/mb/mblock/src/lib/Makefile.am       
2006-11-13 20:48:33 UTC (rev 3977)
@@ -32,6 +32,7 @@
 
 # These are the source files that go into the mblock shared library
 libmblock_la_SOURCES =                 \
+       mb_connection.cc                \
        mb_mblock.cc                    \
        mb_mblock_impl.cc               \
        mb_message.cc                   \
@@ -61,6 +62,8 @@
 
 
 noinst_HEADERS =                       \
+       mb_connection.h                 \
+       mb_endpoint.h                   \
        mb_mblock_impl.h                \
        mb_runtime_impl.h               \
        qa_mblock.h                     \

Modified: gnuradio/branches/developers/eb/mb/mblock/src/lib/mb_mblock.cc
===================================================================
--- gnuradio/branches/developers/eb/mb/mblock/src/lib/mb_mblock.cc      
2006-11-13 05:13:03 UTC (rev 3976)
+++ gnuradio/branches/developers/eb/mb/mblock/src/lib/mb_mblock.cc      
2006-11-13 20:48:33 UTC (rev 3977)
@@ -25,13 +25,58 @@
 
 #include <mb_mblock.h>
 #include <mb_mblock_impl.h>
-#include <mb_protocol_class.h>
-#include <mb_port.h>
 
+#if 0
+static pmt_t s_self = pmt_intern("self");
+
+////////////////////////////////////////////////////////////////////////
+
+inline static bool
+port_is_defined(mb_mblock_impl *impl, pmt_t name)
+{
+  return pmt_eq(name, s_self) || impl->d_port_map.count(name) != 0;
+}
+
+inline static bool
+port_is_defined(mb_mblock_impl *impl, const std::string &name)
+{
+  return port_is_defined(impl, pmt_intern(name));
+}
+
+inline static bool
+comp_is_defined(mb_mblock_impl *impl, pmt_t name)
+{
+  return pmt_eq(name, s_self) || impl->d_comp_map.count(name) != 0;
+}
+
+inline static bool
+comp_is_defined(mb_mblock_impl *impl, const std::string &name)
+{
+  return comp_is_defined(impl, pmt_intern(name));
+}
+
+
+static void
+no_such_comp(const std::string &comp_name)
+{
+  std::string msg = "No such component: " + comp_name;
+  throw std::invalid_argument(msg);
+}
+
+static void
+already_connected(const std::string &comp_name, const std::string &port_name)
+{
+  std::string msg = "Port is already connected: " + comp_name + ":" + 
port_name;
+  throw std::invalid_argument(msg);
+}
+
+#endif
+
+////////////////////////////////////////////////////////////////////////
+
 mb_mblock::mb_mblock()
-  : d_impl(new mb_mblock_impl())
+  : d_impl(new mb_mblock_impl(this))
 {
-  // FIXME more?
 }
 
 mb_mblock::~mb_mblock()
@@ -46,7 +91,6 @@
   }
 }
 
-////////////////////////////////////////////////////////////////////////
 
 void
 mb_mblock::init_fsm()
@@ -61,6 +105,8 @@
 }
 
 ////////////////////////////////////////////////////////////////////////
+//           Forward other methods to implementation class            //
+////////////////////////////////////////////////////////////////////////
 
 void
 mb_mblock::define_port(const std::string &port_name_string,
@@ -68,73 +114,49 @@
                       bool conjugated,
                       mb_port_class::port_type_t port_type)
 {
-  pmt_t port_name = pmt_intern(port_name_string);
-
-  if (port_type == mb_port_class::RELAY)
-    throw pmt_notimplemented(
-        "mb_block_impl::define_port: RELAY ports are not implemented",
-       port_name);
-  
-  if (d_impl->lookup_port(port_name))
-    throw pmt_exception(
-        "mb_mblock::define_port: port_name already defined",
-       port_name);
-
-  mb_port_sptr p = mb_port_sptr(new mb_port(port_name, protocol_class_name,
-                                           conjugated, port_type));
-  d_impl->d_ports.push_back(p);
+  d_impl->define_port(port_name_string, protocol_class_name,
+                     conjugated, port_type);
 }
 
 void
 mb_mblock::define_component(const std::string &component_name,
                            mb_mblock_sptr component)
 {
-  pmt_t name = pmt_intern(component_name);
-  if (d_impl->lookup_component(name))
-    throw pmt_exception(
-       "mb_mblock::define_component: component_name already defined",
-       name);
-
-  d_impl->d_components.push_back(mb_component(name, component));
+  d_impl->define_component(component_name, component);
 }
 
 void
 mb_mblock::connect(const std::string &comp_name1, const std::string 
&port_name1,
                   const std::string &comp_name2, const std::string &port_name2)
 {
-  //  mb_endpoint ep1 = lookup_endpoint(comp_name1, port_name1);
-  //  mb_endpoint ep2 = lookup_endpoint(comp_name2, port_name2);
-}
+  d_impl->connect(comp_name1, port_name1,
+                 comp_name2, port_name2);
+}                              
 
+
 void
 mb_mblock::disconnect(const std::string &comp_name1, const std::string 
&port_name1,
                      const std::string &comp_name2, const std::string 
&port_name2)
 {
-  // FIXME
+  d_impl->disconnect(comp_name1, port_name1,
+                    comp_name2, port_name2);
 }
 
 void
 mb_mblock::disconnect_component(const std::string component_name)
 {
-  // FIXME
+  d_impl->disconnect_component(component_name);
 }
 
 void
 mb_mblock::disconnect_all()
 {
-  // FIXME
+  d_impl->disconnect_all();
 }
 
 void
 mb_mblock::send(pmt_t port_name, pmt_t signal,
                pmt_t data, pmt_t metadata, mb_pri_t priority)
 {
-  // FIXME
+  d_impl->send(port_name, signal, data, metadata, priority);
 }
-
-
-const std::vector<mb_port_class_sptr>
-mb_mblock::peer_interface() const
-{
-  return d_impl->peer_interface();
-}

Modified: gnuradio/branches/developers/eb/mb/mblock/src/lib/mb_mblock.h
===================================================================
--- gnuradio/branches/developers/eb/mb/mblock/src/lib/mb_mblock.h       
2006-11-13 05:13:03 UTC (rev 3976)
+++ gnuradio/branches/developers/eb/mb/mblock/src/lib/mb_mblock.h       
2006-11-13 20:48:33 UTC (rev 3977)
@@ -181,7 +181,7 @@
   /*!
    * \brief Return a vector that describes this mblock's peer-interface
    */
-  const std::vector<mb_port_class_sptr> peer_interface() const;
+  // const std::vector<mb_port_class_sptr> peer_interface() const;
 };
 
 

Modified: gnuradio/branches/developers/eb/mb/mblock/src/lib/mb_mblock_impl.cc
===================================================================
--- gnuradio/branches/developers/eb/mb/mblock/src/lib/mb_mblock_impl.cc 
2006-11-13 05:13:03 UTC (rev 3976)
+++ gnuradio/branches/developers/eb/mb/mblock/src/lib/mb_mblock_impl.cc 
2006-11-13 20:48:33 UTC (rev 3977)
@@ -23,52 +23,167 @@
 #include <config.h>
 #endif
 #include <mb_mblock_impl.h>
+#include <mb_mblock.h>
+#include <mb_protocol_class.h>
 #include <mb_port.h>
 
-mb_mblock_impl::mb_mblock_impl()
+static pmt_t s_self = pmt_intern("self");
+
+////////////////////////////////////////////////////////////////////////
+
+static void
+no_such_comp(const std::string &comp_name)
 {
-  // FIXME
+  std::string msg = "No such component: " + comp_name;
+  throw std::invalid_argument(msg);
 }
 
+static void
+already_connected(const std::string &comp_name, const std::string &port_name)
+{
+  std::string msg = "Port is already connected: " + comp_name + ":" + 
port_name;
+  throw std::invalid_argument(msg);
+}
+
+////////////////////////////////////////////////////////////////////////
+
+bool
+mb_mblock_impl::port_is_defined(pmt_t name)
+{
+  return d_port_map.count(name) != 0;
+}
+
+bool 
+mb_mblock_impl::port_is_defined(const std::string &name)
+{
+  return port_is_defined(pmt_intern(name));
+}
+
+bool
+mb_mblock_impl::comp_is_defined(pmt_t name)
+{
+  return pmt_eq(name, s_self) || d_comp_map.count(name) != 0;
+}
+
+bool
+mb_mblock_impl::comp_is_defined(const std::string &name)
+{
+  return comp_is_defined(pmt_intern(name));
+}
+
+////////////////////////////////////////////////////////////////////////
+
+mb_mblock_impl::mb_mblock_impl(mb_mblock *mb)
+  : d_mb(mb)
+{
+}
+
 mb_mblock_impl::~mb_mblock_impl()
 {
-  // FIXME
+  d_mb = 0;
 }
 
+
+void
+mb_mblock_impl::define_port(const std::string &port_name_string,
+                           const std::string &protocol_class_name,
+                           bool conjugated,
+                           mb_port_class::port_type_t port_type)
+{
+  pmt_t port_name = pmt_intern(port_name_string);
+
+  if (port_type == mb_port_class::RELAY)
+    throw pmt_notimplemented(
+        "mb_block_impl::define_port: RELAY ports are not implemented",
+       port_name);
+  
+  if (port_is_defined(port_name))
+    throw pmt_exception(
+        "mb_mblock_impl::define_port: port_name already defined",
+       port_name);
+
+  mb_port_sptr p = mb_port_sptr(new mb_port(port_name, protocol_class_name,
+                                           conjugated, port_type));
+  d_port_map[port_name] = p;
+}
+
+mb_endpoint
+mb_mblock_impl::check_and_resolve_endpoint(const std::string &comp_name,
+                                          const std::string &port_name)
+{
+  mb_conn_iter it;
+  int          which_ep;
+  mb_port_sptr port;
+
+  if (d_conn_table.lookup_conn_by_name(comp_name, port_name, &it, &which_ep))
+    already_connected(comp_name, port_name);
+
+  port = resolve_port(comp_name, port_name);
+  return mb_endpoint(comp_name, port_name, port);
+}
+
 mb_port_sptr
-mb_mblock_impl::lookup_port(pmt_t port_name)
+mb_mblock_impl::resolve_port(const std::string &comp_name,
+                            const std::string &port_name)
 {
-  for (std::vector<mb_port_sptr>::const_iterator p = d_ports.begin();
-       p != d_ports.end(); p++){
-    if (pmt_eq(port_name, (*p)->port_name()))
-      return *p;
+  mb_port_sptr port;
+
+  if (comp_name == "self"){
+    
   }
+  else {
+  }
 
-  return mb_port_sptr();       // equivalent to the NULL pointer
+  return port;
 }
 
-mb_mblock_sptr
-mb_mblock_impl::lookup_component(pmt_t component_name)
+
+
+void
+mb_mblock_impl::define_component(const std::string &component_name,
+                                mb_mblock_sptr component)
 {
-  for (std::vector<mb_component>::const_iterator p = d_components.begin();
-       p != d_components.end(); p++){
-    if (pmt_eq(component_name, p->name()))
-      return p->component();
-  }
+  pmt_t name = pmt_intern(component_name);
 
-  return mb_mblock_sptr();     // equivalent to the NULL pointer
+  // check for duplicate name
+  if (comp_is_defined(name))
+    throw pmt_exception(
+       "mb_mblock_impl::define_component: component_name already defined",
+       name);
+
+  d_comp_map[name] = component;
 }
 
+void
+mb_mblock_impl::connect(const std::string &comp_name1, const std::string 
&port_name1,
+                       const std::string &comp_name2, const std::string 
&port_name2)
+{
+  mb_endpoint  ep0 = check_and_resolve_endpoint(comp_name1, port_name1);
+  mb_endpoint  ep1 = check_and_resolve_endpoint(comp_name2, port_name2);
+}
 
-const std::vector<mb_port_class_sptr>
-mb_mblock_impl::peer_interface() const
+void
+mb_mblock_impl::disconnect(const std::string &comp_name1, const std::string 
&port_name1,
+                          const std::string &comp_name2, const std::string 
&port_name2)
 {
-  std::vector<mb_port_class_sptr>      r;
+  // FIXME
+}
 
-  for (std::vector<mb_port_sptr>::const_iterator p = d_ports.begin();
-       p != d_ports.end(); p++){
-    r.push_back((*p)->port_class());
-  }
+void
+mb_mblock_impl::disconnect_component(const std::string component_name)
+{
+  // FIXME
+}
 
-  return r;
+void
+mb_mblock_impl::disconnect_all()
+{
+  // FIXME
 }
+
+void
+mb_mblock_impl::send(pmt_t port_name, pmt_t signal,
+                    pmt_t data, pmt_t metadata, mb_pri_t priority)
+{
+  // FIXME
+}

Modified: gnuradio/branches/developers/eb/mb/mblock/src/lib/mb_mblock_impl.h
===================================================================
--- gnuradio/branches/developers/eb/mb/mblock/src/lib/mb_mblock_impl.h  
2006-11-13 05:13:03 UTC (rev 3976)
+++ gnuradio/branches/developers/eb/mb/mblock/src/lib/mb_mblock_impl.h  
2006-11-13 20:48:33 UTC (rev 3977)
@@ -22,120 +22,173 @@
 #define INCLUDED_MB_MBLOCK_IMPL_H
 
 #include <mb_mblock.h>
+#include <mb_connection.h>
 #include <list>
 #include <map>
 
 
-class mb_component
-{
-  pmt_t                        d_name;
-  mb_mblock_sptr       d_component;
-
-public:
-  mb_component(pmt_t name, mb_mblock_sptr component)
-    : d_name(name), d_component(component) {}
-  
-  pmt_t name() const { return d_name; }
-  mb_mblock_sptr component() const { return d_component; }
+#if 1
+/*!
+ * \brief Define an operator usable for a comparison function for pmt_t's
+ *
+ * This sorts them by address, not particularly useful, but does
+ * keep the std::map template happy.
+ */
+struct _pmt_less {
+  bool operator()(const pmt_t a, const pmt_t b) const {
+    return (unsigned long int) a.get() < (unsigned long int) b.get();
+  }
 };
 
+typedef std::map<pmt_t, mb_port_sptr,   _pmt_less> mb_port_map_t;
+typedef std::map<pmt_t, mb_mblock_sptr, _pmt_less> mb_comp_map_t;
 
-typedef std::map<pmt_t, mb_port_sptr, std::less<unsigned long int> > 
mb_port_map_t;
+#else
 
-/*!
- * \brief Endpoint specification for connection
- */
-class mb_endpoint
-{
-  std::string  d_component_name;
-  std::string  d_port_name;
+typedef std::map<std::string, mb_port_sptr>   mb_port_map_t;
+typedef std::map<std::string, mb_mblock_sptr> mb_comp_map_t;
 
-  mb_port_sptr d_port;                 // the port object that this maps to
+#endif
 
-public:
-  mb_endpoint(const std::string &component_name,
-             const std::string &port_name,
-             mb_port_sptr port)
-    : d_component_name(component_name),
-      d_port_name(port_name),
-      d_port(port) {}
 
-  const std::string &component_name() const { return d_component_name; }
-  const std::string &port_name() const { return d_port_name; }
-  mb_port_sptr port() const { return d_port; }
-};
-
 /*!
- * \brief Representation of a connection
+ * \brief The private implementation details of the mblock system.
  */
-class mb_connection {
-  mb_endpoint  d_ep[2];
-};
+class mb_mblock_impl : boost::noncopyable
+{
+  mb_mblock                   *d_mb;           // pointer to our associated 
mblock
 
-typedef std::list<mb_connection>::iterator mb_conn_iter;
+  mb_port_map_t                        d_port_map;     // our ports
+  mb_comp_map_t                        d_comp_map;     // our components
+  mb_conn_table                        d_conn_table;   // our connections
 
-/*!
- * \brief data structure that keeps track of connections
- */
-class mb_conn_table {
-  std::list<mb_connection> d_connections;
-
 public:
-  mb_conn_iter
-  lookup_conn0_by_name(const std::string &component_name,
-                      const std::string &port_name) const;
-  mb_conn_iter
-  lookup_conn1_by_name(const std::string &component_name,
-                      const std::string &port_name) const;
-  mb_conn_iter
-  lookup_conn_by_name(const std::string &component_name,
-                     const std::string &port_name, int &which_ep) const;
+  mb_mblock_impl(mb_mblock *mb);
+  ~mb_mblock_impl();
 
-  mb_conn_iter
-  lookup_conn0_by_port(mb_port_sptr port) const;
+  /*!
+   * \brief Define a port.
+   *
+   * EXTERNAL and RELAY ports are part of our peer interface.
+   * INTERNAL ports are used to talk to sub-components.
+   *
+   * \param port_name    The name of the port (must be unique within this 
mblock).
+   * \param protocol_class_name        The name of the protocol class 
associated with
+   *                           this port.  It must already be defined.
+   * \param conjugated   Are the incoming and outgoing message sets swapped?
+   * \param port_type    INTERNAL, EXTERNAL or RELAY.
+   */
+  void
+  define_port(const std::string &port_name,
+             const std::string &protocol_class_name,
+             bool conjugated,
+             mb_port_class::port_type_t port_type);
 
-  mb_conn_iter
-  lookup_conn1_by_port(mb_port_sptr port) const;
+  /*!
+   * \brief Define a subcomponent by name.
+   *
+   * Called within the constructor to tell the system the
+   * names and identities of our sub-component mblocks.
+   *
+   * \param component_name  The name of the sub-component (must be unique with 
this mblock).
+   * \param component       The sub-component instance.
+   */
+  void
+  define_component(const std::string &component_name,
+                  mb_mblock_sptr component);
 
-  mb_conn_iter
-  lookup_conn_by_port(mb_port_sptr port, int &which_ep) const;
+  /*!
+   * \brief connect endpoint_1 to endpoint_2
+   *
+   * \param comp_name1  component on one of the connection
+   * \param port_name1  the name of the port on comp1
+   * \param comp_name2  component on the other end the connection
+   * \param port_name2  the name of the port on comp2
+   *
+   * An endpoint is specified by the component's local name (given as
+   * component_name in the call to register_component) and the name of
+   * the port on that component.
+   *
+   * To connect an internal or relay port, use "self" as the component name.
+   */
+  void
+  connect(const std::string &comp_name1, const std::string &port_name1,
+         const std::string &comp_name2, const std::string &port_name2);
 
+  /*!
+   * \brief disconnect endpoint_1 from endpoint_2
+   *
+   * \param comp_name1  component on one of the connection
+   * \param port_name1  the name of the port on comp1
+   * \param comp_name2  component on the other end the connection
+   * \param port_name2  the name of the port on comp2
+   *
+   * An endpoint is specified by the component's local name (given as
+   * component_name in the call to register_component) and the name of
+   * the port on that component.
+   *
+   * To disconnect an internal or relay port, use "self" as the component name.
+   */
   void
-  create_conn(const mb_endpoint &ep0, const mb_endpoint &ep1);
-};
+  disconnect(const std::string &comp_name1, const std::string &port_name1,
+            const std::string &comp_name2, const std::string &port_name2);
 
+  /*!
+   * \brief disconnect all connections to specified component
+   * \param component_name component to disconnect
+   */
+  void
+  disconnect_component(const std::string component_name);
 
+  /*!
+   * \brief disconnect all connections to all components
+   */
+  void
+  disconnect_all();
 
+  /*!
+   * \brief send a message
+   *
+   * \param port_name  name of the port via which we send the message
+   * \param signal     the event name
+   * \param data       optional data
+   * \param metadata   optional metadata
+   * \param priority   the urgency at which the message is sent
+   */
+  void
+  send(pmt_t port_name,
+       pmt_t signal,
+       pmt_t data,
+       pmt_t metadata,
+       mb_pri_t priority);
 
-/*!
- * \brief The private implementation details of the mblock system.
- */
-class mb_mblock_impl : boost::noncopyable
-{
+  
+  /*
+   * Our implemenation methods
+   */
 private:
+  bool port_is_defined(pmt_t name);
+  bool port_is_defined(const std::string &name);
+  bool comp_is_defined(pmt_t name);
+  bool comp_is_defined(const std::string &name);
 
-  std::vector<mb_port_sptr>    d_ports;        // our ports
-  std::vector<mb_component>    d_components;   // our components
+  mb_endpoint 
+  check_and_resolve_endpoint(const std::string &comp_name,
+                            const std::string &port_name);
 
-  mb_port_map_t                        d_port_map;
+#if 0
+  mb_port_sptr
+  resolve_our_port(const std::string &port_name);
 
-  mb_mblock_impl();
+  mb_port_sptr
+  resolve_childs_port(const std::string &comp_name,
+                     const std::string &port_name);
+#endif
 
-  friend class mb_mblock;
-
-  ////////////////////////////////////////////////////////////////////////
-
   mb_port_sptr
-  lookup_port(pmt_t port_name);
+  resolve_port(const std::string &comp_name,
+              const std::string &port_name);
 
-  mb_mblock_sptr
-  lookup_component(pmt_t component_name);
-
-  const std::vector<mb_port_class_sptr>
-  peer_interface() const;
-
-public:
-  ~mb_mblock_impl();
 };
 
 

Modified: gnuradio/branches/developers/eb/mb/mblock/src/lib/qa_mblock_prims.cc
===================================================================
--- gnuradio/branches/developers/eb/mb/mblock/src/lib/qa_mblock_prims.cc        
2006-11-13 05:13:03 UTC (rev 3976)
+++ gnuradio/branches/developers/eb/mb/mblock/src/lib/qa_mblock_prims.cc        
2006-11-13 20:48:33 UTC (rev 3977)
@@ -87,11 +87,11 @@
 qa_mblock_prims::test_define_ports()
 {
   mb_runtime_sptr      rt = mb_make_runtime();
-  std::vector<mb_port_class_sptr>      intf;
+  // std::vector<mb_port_class_sptr>   intf;
 
   mb_mblock_sptr       mb1 = mb_mblock_sptr(new dp_1());
-  intf = mb1->peer_interface();
-  CPPUNIT_ASSERT_EQUAL(size_t(0), intf.size());
+  // intf = mb1->peer_interface();
+  // CPPUNIT_ASSERT_EQUAL(size_t(0), intf.size());
 
   // raises runtime_error because of unknown protocol "cs-protocol"
   CPPUNIT_ASSERT_THROW(mb_mblock_sptr(new dp_2()), std::runtime_error);
@@ -107,9 +107,9 @@
 
   mb_mblock_sptr mb2 = mb_mblock_sptr(new dp_2());
 
-  intf = mb2->peer_interface();
-  CPPUNIT_ASSERT_EQUAL(size_t(1), intf.size());
-  CPPUNIT_ASSERT(pmt_eq(s_cs, intf[0]->port_name()));
+  // intf = mb2->peer_interface();
+  // CPPUNIT_ASSERT_EQUAL(size_t(1), intf.size());
+  // CPPUNIT_ASSERT(pmt_eq(s_cs, intf[0]->port_name()));
 
 
   // raises pmt_exception because of duplicate port definition of "cs"
@@ -230,10 +230,10 @@
     // OK
     connect("cin0", "data", "cout0", "data");
 
-#if 0
     // No:  No such component name
     CPPUNIT_ASSERT_THROW(connect("foo", "data", "cout0", "data"), 
std::invalid_argument);
 
+#if 1
     // No:  No such port name
     CPPUNIT_ASSERT_THROW(connect("cin0", "data", "cout0", "foo"), 
std::invalid_argument);
 





reply via email to

[Prev in Thread] Current Thread [Next in Thread]