Revision: 6907
          http://playerstage.svn.sourceforge.net/playerstage/?rev=6907&view=rev
Author:   thjc
Date:     2008-07-23 05:30:31 +0000 (Wed, 23 Jul 2008)

Log Message:
-----------
Fix for python blackboard proxy, the second time you subscribed to a key 
with the same group that has not been set it would throw an exception.

Modified Paths:
--------------
    
code/player/branches/release-2-1-patches/client_libs/libplayerc/bindings/python/playerc.i

Modified: 
code/player/branches/release-2-1-patches/client_libs/libplayerc/bindings/python/playerc.i
===================================================================
--- 
code/player/branches/release-2-1-patches/client_libs/libplayerc/bindings/python/playerc.i
   2008-07-23 05:01:11 UTC (rev 6906)
+++ 
code/player/branches/release-2-1-patches/client_libs/libplayerc/bindings/python/playerc.i
   2008-07-23 05:30:31 UTC (rev 6907)
@@ -422,15 +422,17 @@
 #define LIST_EVENTS_INDEX 2
 #define BOOL_QUEUE_EVENTS_INDEX 3
 
-// Helper function to convert a c blackboard_entry_t into a python dictionary 
object
+// Helper function to convert a c blackboard_entry_t into a python dictionary 
object.
+// Returns a new reference to a dictionary object.
 PyObject *__convert_blackboard_entry__(player_blackboard_entry_t *entry)
 {
   PyObject *entry_dict, *data;
   char* str;
   int i;
   double d;
+  int ok;
 
-  entry_dict = PyDict_New();
+  entry_dict = PyDict_New(); // New reference
   assert (entry_dict);
 
   assert(entry);
@@ -439,22 +441,68 @@
   assert(entry->group);
   assert(entry->group_count > 0);
 
-  PyDict_SetItemString(entry_dict, "key", PyString_FromString(entry->key));
-  PyDict_SetItemString(entry_dict, "group", 
PyString_FromString(entry->group));        
-  PyDict_SetItemString(entry_dict, "type", PyLong_FromLong(entry->type));
-  PyDict_SetItemString(entry_dict, "subtype", PyLong_FromLong(entry->subtype));
-  PyDict_SetItemString(entry_dict, "timestamp_sec", 
PyLong_FromLong(entry->timestamp_sec));
-  PyDict_SetItemString(entry_dict, "timestamp_usec", 
PyLong_FromLong(entry->timestamp_usec));
+  ok = PyDict_SetItemString(entry_dict, "key", 
PyString_FromString(entry->key)); // Steals reference
+  if (ok != 0)
+  {
+       PyErr_SetString(PyExc_RuntimeError, "Could not set dictionary value for 
'key'");
+       Py_XDECREF(entry_dict);
+       return NULL;
+  }
 
+  ok = PyDict_SetItemString(entry_dict, "group", 
PyString_FromString(entry->group)); // Steals reference
+  if (ok != 0)
+  {
+       PyErr_SetString(PyExc_RuntimeError, "Could not set dictionary value for 
'group'");
+       Py_XDECREF(entry_dict);
+       return NULL;
+  }
+       
+  ok = PyDict_SetItemString(entry_dict, "type", PyLong_FromLong(entry->type)); 
// Steals reference
+  if (ok != 0)
+  {
+       PyErr_SetString(PyExc_RuntimeError, "Could not set dictionary value for 
'type'");
+       Py_XDECREF(entry_dict);
+       return NULL;
+  }
+
+  ok = PyDict_SetItemString(entry_dict, "subtype", 
PyLong_FromLong(entry->subtype)); // Steals reference
+  if (ok != 0)
+  {
+       PyErr_SetString(PyExc_RuntimeError, "Could not set dictionary value for 
'subtype'");
+       Py_XDECREF(entry_dict);
+       return NULL;
+  }
+
+  ok = PyDict_SetItemString(entry_dict, "timestamp_sec", 
PyLong_FromLong(entry->timestamp_sec)); // Steals reference
+  if (ok != 0)
+  {
+       PyErr_SetString(PyExc_RuntimeError, "Could not set dictionary value for 
'timestamp_sec'");
+       Py_XDECREF(entry_dict);
+       return NULL;
+  }
+
+  ok = PyDict_SetItemString(entry_dict, "timestamp_usec", 
PyLong_FromLong(entry->timestamp_usec)); // Steals reference
+  if (ok != 0)
+  {
+       PyErr_SetString(PyExc_RuntimeError, "Could not set dictionary value for 
'timestamp_usec'");
+       Py_XDECREF(entry_dict);
+       return NULL;
+  }
+
   switch(entry->subtype)
   {
     case PLAYERC_BLACKBOARD_DATA_SUBTYPE_NONE:
       data = Py_None;
+      Py_INCREF(data);
     break;
     case PLAYERC_BLACKBOARD_DATA_SUBTYPE_STRING:
       assert(entry->type == PLAYERC_BLACKBOARD_DATA_TYPE_COMPLEX);
       str = malloc(entry->data_count);
-      assert(str);
+      if (!str)
+      {
+           Py_XDECREF(entry_dict);
+           return PyErr_NoMemory();
+      }
       memcpy(str, entry->data, entry->data_count);
       data = PyString_FromString(str);
     break;
@@ -472,17 +520,27 @@
     break;
     default:
       data = Py_None;
+      Py_INCREF(data);
     break;
   }
 
-  PyDict_SetItemString(entry_dict, "data", data);
+  ok = PyDict_SetItemString(entry_dict, "data", data); // Steals reference
+  if (ok != 0)
+  {
+       PyErr_SetString(PyExc_RuntimeError, "Could not set dictionary value for 
'data'");
+       Py_XDECREF(entry_dict);
+       return NULL;
+  }
+  
   return entry_dict;
 }
 
 // Helper function which sets a value in a nested dictionary. Equivalent of 
dict['group']['key'] = value.
+// Steals the entry reference.
 PyObject *__set_nested_dictionary_entry__(PyObject *dict, const char* key, 
const char* group, PyObject *entry)
 {
   PyObject *group_dict;
+  int ok;
   int create_dict = 0;
 
   // Check we got valid arguments.
@@ -511,19 +569,34 @@
   }
 
   // Get the dictionary for the entry's group. If it doesn't exist, create it.
-  group_dict = (PyObject*)PyDict_GetItemString(dict, group);
+  group_dict = (PyObject*)PyDict_GetItemString(dict, group); // Borrowed 
reference
   if (!group_dict)
   {
     create_dict = 1;
-    group_dict = PyDict_New();
+    group_dict = PyDict_New(); // New reference    
   }
 
-  PyDict_SetItemString(group_dict, key, entry);
+  ok = PyDict_SetItemString(group_dict, key, entry); // Steals reference
+  if (ok != 0)
+  {
+    PyErr_SetString(PyExc_RuntimeError, "Failed to set dictionary entry");
+    if (create_dict)
+    {
+       Py_XDECREF(group_dict);
+    }
+    return NULL;
+  }
 
   // If we created the dictionary, we need to put it in the parent dictionary.
   if (create_dict == 1)
   {
-    PyDict_SetItemString(dict, group, group_dict);
+    ok = PyDict_SetItemString(dict, group, group_dict); // Steals reference
+    if (ok != 0)
+    {
+       PyErr_SetString(PyExc_RuntimeError, "Failed to set dictionary entry");
+       Py_XDECREF(group_dict);
+       return NULL;
+    }
   }
 
   Py_RETURN_NONE;
@@ -535,21 +608,31 @@
   PyObject *group_dict, *entry;
   int old_value, new_value;
 
-  // Get the dictionary for the entry's group. If it doesn't exist, create it 
and increment it.
-  group_dict = (PyObject*)PyDict_GetItemString(dict, group);
+  // Get the dictionary for the entry's group. If it doesn't exist.
+  group_dict = (PyObject*)PyDict_GetItemString(dict, group); // Borrowed 
reference
   if (!group_dict)
   {
-    playerc_blackboard___set_nested_dictionary_entry__(self, dict, key, group, 
(PyObject*)PyInt_FromLong(inc));
+    playerc_blackboard___set_nested_dictionary_entry__(self, dict, key, group, 
(PyObject*)PyInt_FromLong(inc)); // Steals reference to entry
     return inc;
   }
 
-  entry = PyDict_GetItemString(group_dict, key);
-  old_value = PyLong_AsLong(entry);
+  entry = PyDict_GetItemString(group_dict, key); // Borrowed reference
+  if (entry)
+  {
+       old_value = PyLong_AsLong(entry);
+  }
+  else
+  {
+       old_value = 0;
+  }
+  
   new_value = old_value + inc;
   if (new_value < 0)
+  {
        new_value = 0;
+  }
 
-  playerc_blackboard___set_nested_dictionary_entry__(self, dict, key, group, 
PyInt_FromLong(new_value));
+  playerc_blackboard___set_nested_dictionary_entry__(self, dict, key, group, 
PyInt_FromLong(new_value)); // Steals reference to entry
 
   return new_value;
 }
@@ -561,24 +644,25 @@
 
   // Get the main groups dictionary
   assert(device->py_private);
-  groups_dict = (PyObject*)PyTuple_GetItem(device->py_private, 
DICT_GROUPS_INDEX);
+  groups_dict = (PyObject*)PyTuple_GetItem(device->py_private, 
DICT_GROUPS_INDEX); // Borrowed reference
   assert(groups_dict);
 
   // Get a dictionary of the entry
-  entry_dict = playerc_blackboard___convert_blackboard_entry__(device, &entry);
+  entry_dict = playerc_blackboard___convert_blackboard_entry__(device, 
&entry); // New reference
   assert(entry_dict);
-  // Set the entry in the groups dictionary
-  playerc_blackboard___set_nested_dictionary_entry__(device, groups_dict, 
entry.key, entry.group, entry_dict);
-
+  
   // If we are queueing events, add them to the list
-  queue_events = PyTuple_GetItem(device->py_private, BOOL_QUEUE_EVENTS_INDEX);
+  queue_events = PyTuple_GetItem(device->py_private, BOOL_QUEUE_EVENTS_INDEX); 
// Borrowed reference
   assert(queue_events);
   if (PyLong_AsLong(queue_events) != 0)
   {
-    list = (PyObject*)PyTuple_GetItem(device->py_private, LIST_EVENTS_INDEX);
+    list = (PyObject*)PyTuple_GetItem(device->py_private, LIST_EVENTS_INDEX); 
// Borrowed reference
     assert(list);
-    PyList_Append(list, PyDict_Copy(entry_dict));
+    PyList_Append(list, entry_dict); // Increments refcount for us
   }
+  
+  // Set the entry in the groups dictionary
+  playerc_blackboard___set_nested_dictionary_entry__(device, groups_dict, 
entry.key, entry.group, entry_dict); // Steals reference to entry_dict
 }
 
 // Returns a list of dictionary objects containing the entries.
@@ -588,20 +672,32 @@
 %feature("autodoc", "1");
 PyObject *GetEvents()
 {
-  PyObject *list, *copy;
-  int i, j;
+  PyObject *list, *copy, *item;
+  int i, j, ok;
 
   assert(self->py_private);
-  list = (PyObject*)PyTuple_GetItem(self->py_private, LIST_EVENTS_INDEX);
+  list = (PyObject*)PyTuple_GetItem(self->py_private, LIST_EVENTS_INDEX); // 
Borrowed reference
   assert(list);
 
-  copy = PyList_New(0);
   j = PyList_Size(list);
+  copy = PyList_New(j); // New reference
+  
   for (i = 0; i < j; i++)
   {
-    PyList_Append(copy, PyList_GetItem(list, 0));
+       item = PyList_GetItem(list, 0); // Borrowed reference
+       Py_INCREF(item);
+       assert(item);
+    ok = PyList_SetItem(copy, i, item); // Steals reference
+    if (ok != 0)
+    {
+       PyErr_SetString(PyExc_RuntimeError, "Failed to set list entry");
+       Py_XDECREF(copy);
+       Py_XDECREF(item);
+       return NULL;
+    }
     PySequence_DelItem(list,0);
   }
+
   return copy;
 }
 
@@ -610,28 +706,21 @@
 // Will always return a dictionary object.
 PyObject *GetDict()
 {
-  PyObject *dict, *copy, *list, *pair;
-  int i, j;
+  PyObject *dict, *copy;
 
   assert(self->py_private);
-  dict = (PyObject*)PyTuple_GetItem(self->py_private, DICT_GROUPS_INDEX);
+  dict = (PyObject*)PyTuple_GetItem(self->py_private, DICT_GROUPS_INDEX); // 
Borrowed reference
   assert(dict);
 
-  copy = PyDict_New();
-  list = PyDict_Items(dict);
-  j = PyList_Size(list);
-  for (i = 0; i < j; i++)
-  {
-    pair = PyList_GetItem(list, i);
-    PyDict_SetItem(copy, PyTuple_GetItem(pair, 0), PyTuple_GetItem(pair, 1));
-  }
-
+  copy = PyDict_Copy(dict); // New reference
   return copy;
 }
 
 // Set whether events should be put into the list, to be retrieved by 
get_events_list().
 PyObject *SetQueueEvents(PyObject *boolean)
 {
+  int ok;
+
   if(!PyBool_Check(boolean))
   {
     PyErr_SetString(PyExc_TypeError, "Expected type 'bool'");
@@ -639,11 +728,21 @@
   }
   if (boolean == Py_False)
   {
-    PyTuple_SetItem(self->py_private, BOOL_QUEUE_EVENTS_INDEX, 
PyLong_FromLong(0));
+    ok = PyTuple_SetItem((PyObject*)self->py_private, BOOL_QUEUE_EVENTS_INDEX, 
PyLong_FromLong(0)); // Steals reference
+    if (ok != 0)
+    {
+      PyErr_SetString(PyExc_RuntimeError, "Failed to set tuple entry");
+      return NULL;
+    }
   }
   else
   {
-    PyTuple_SetItem(self->py_private, BOOL_QUEUE_EVENTS_INDEX, 
PyLong_FromLong(1));
+    ok = PyTuple_SetItem((PyObject*)self->py_private, BOOL_QUEUE_EVENTS_INDEX, 
PyLong_FromLong(1)); // Steals reference
+    if (ok != 0)
+    {
+      PyErr_SetString(PyExc_RuntimeError, "Failed to set tuple entry");
+      return NULL;
+    }
   }
 
   Py_RETURN_NONE;
@@ -688,14 +787,15 @@
 {
   PyObject *groups_dict, *group_dict, *subscription_data;
   int result, ref_count;
-  subscription_data = PyTuple_GetItem(self->py_private, 
DICT_SUBSCRIPTION_DATA_INDEX);
+
+  subscription_data = PyTuple_GetItem((PyObject*)self->py_private, 
DICT_SUBSCRIPTION_DATA_INDEX); // Borrowed reference
   assert(subscription_data);
   ref_count = playerc_blackboard___increment_reference_count__(self, 
subscription_data, key, group, -1);
   if (ref_count <= 0)
   {
-    groups_dict = PyTuple_GetItem(self->py_private, DICT_GROUPS_INDEX);
+    groups_dict = PyTuple_GetItem((PyObject*)self->py_private, 
DICT_GROUPS_INDEX); // Borrowed reference
     assert(groups_dict);
-    group_dict = PyDict_GetItemString(groups_dict, group);
+    group_dict = PyDict_GetItemString(groups_dict, group); // Borrowed 
reference
     assert(group_dict);
     PyDict_DelItemString(group_dict, key);
   }
@@ -717,14 +817,15 @@
     return NULL;
   }
 
-  entry_dict = playerc_blackboard___convert_blackboard_entry__(self, entry);
-  groups_dict = (PyObject*)PyTuple_GetItem(self->py_private, 
DICT_GROUPS_INDEX);
+  entry_dict = playerc_blackboard___convert_blackboard_entry__(self, entry); 
// New reference
+  assert(entry_dict);
+  groups_dict = (PyObject*)PyTuple_GetItem((PyObject*)self->py_private, 
DICT_GROUPS_INDEX); // Borrowed reference
   assert(groups_dict);
 
-  assert(entry_dict);
-  playerc_blackboard___set_nested_dictionary_entry__(self, groups_dict, key, 
group, entry_dict);
+  Py_INCREF(entry_dict);
+  playerc_blackboard___set_nested_dictionary_entry__(self, groups_dict, key, 
group, entry_dict); // Steals reference to entry_dict
 
-  subscription_data = PyTuple_GetItem(self->py_private, 
DICT_SUBSCRIPTION_DATA_INDEX);
+  subscription_data = PyTuple_GetItem((PyObject*)self->py_private, 
DICT_SUBSCRIPTION_DATA_INDEX); // Borrowed reference
   assert(subscription_data);
 
   playerc_blackboard___increment_reference_count__(self, subscription_data, 
key, group, 1);
@@ -740,40 +841,48 @@
 int UnsubscribeFromGroup(const char *group)
 {
   int i, j, ref_count;
-  PyObject *groups_dict, *group_dict, *list, *tuple, *subscription_data, 
*items;
+  PyObject *groups_dict, *group_dict, *list, *tuple, *subscription_data, 
*items, *item;
   const char* key;
   int result;
+
   result = playerc_blackboard_unsubscribe_from_group(self, group);
 
   assert(self->py_private);
-  groups_dict = PyTuple_GetItem(self->py_private, DICT_GROUPS_INDEX);
+  groups_dict = PyTuple_GetItem((PyObject*)self->py_private, 
DICT_GROUPS_INDEX); // Borrowed reference
   assert(groups_dict);
 
-  group_dict = PyDict_GetItemString(groups_dict, group);
+  group_dict = PyDict_GetItemString(groups_dict, group); // Borrowed reference
   if (group_dict)
   {
-    list = PyList_New(0);
-    subscription_data = PyTuple_GetItem(self->py_private, 
DICT_SUBSCRIPTION_DATA_INDEX);
+    list = PyList_New(0); // New reference
+    subscription_data = PyTuple_GetItem((PyObject*)self->py_private, 
DICT_SUBSCRIPTION_DATA_INDEX); // Borrowed reference
     assert(subscription_data);
 
     items = PyDict_Items(group_dict);
     j = PyList_Size(items);
     for (i = 0; i < j; i++)
     {
-      tuple = PyList_GetItem(items, 0);
-      key = PyString_AsString(PyTuple_GetItem(tuple, 0));
+      tuple = PyList_GetItem(items, 0); // Borrowed reference
+      assert(tuple);
+      item = PyTuple_GetItem(tuple, 0); // Borrowed reference
+      assert(item);
+      key = PyString_AsString(item);
       ref_count = playerc_blackboard___increment_reference_count__(self, 
subscription_data, key, group, 0);
       if (ref_count <= 0)
-      {
-        PyList_Append(list, PyTuple_GetItem(tuple, 0));
+      {  
+        PyList_Append(list, item); // Increments refcount for us
       }
     }
 
     j = PyList_Size(list);
     for (i =0; i < j; i++)
     {
-      PyDict_DelItem(group_dict, PyList_GetItem(list, i));
+      item = PyList_GetItem(list, i); // Borrowed reference
+      assert(item);
+      PyDict_DelItem(group_dict, item);
     }
+
+    Py_DECREF(list);
   }
 
   return result;
@@ -798,12 +907,13 @@
     PyErr_SetString(PyExc_RuntimeError, "Failed to get entry");
     return NULL;
   }
-  entry_dict = playerc_blackboard___convert_blackboard_entry__(self, entry);
+  entry_dict = playerc_blackboard___convert_blackboard_entry__(self, entry); 
// New reference
   
-  groups_dict = PyTuple_GetItem(self->py_private, DICT_GROUPS_INDEX);
+  groups_dict = PyTuple_GetItem((PyObject*)self->py_private, 
DICT_GROUPS_INDEX); // Borrowed reference
   assert(groups_dict);
   assert(entry_dict);
-  playerc_blackboard___set_nested_dictionary_entry__(self, groups_dict, key, 
group, entry_dict);
+  Py_INCREF(entry_dict);
+  playerc_blackboard___set_nested_dictionary_entry__(self, groups_dict, key, 
group, entry_dict); // Steals reference to entry_dict
 
   free(entry->key);
   free(entry->group);
@@ -818,12 +928,12 @@
   int result;
   PyObject *entry_dict, *groups_dict;
   
-  entry_dict = playerc_blackboard___convert_blackboard_entry__(self, entry);
-  groups_dict = PyTuple_GetItem(self->py_private, DICT_GROUPS_INDEX);
+  entry_dict = playerc_blackboard___convert_blackboard_entry__(self, entry); 
// New reference
+  assert(entry_dict);
+  groups_dict = PyTuple_GetItem((PyObject*)self->py_private, 
DICT_GROUPS_INDEX); // Borrowed reference
   assert(groups_dict);
-  assert(entry_dict);
 
-  playerc_blackboard___set_nested_dictionary_entry__(self, groups_dict, 
entry->key, entry->group, entry_dict);
+  playerc_blackboard___set_nested_dictionary_entry__(self, groups_dict, 
entry->key, entry->group, entry_dict); // Steals reference to entry_dict
   result = playerc_blackboard_set_entry(self, entry);
   return PyInt_FromLong(result);
 }
@@ -844,13 +954,13 @@
   player_blackboard_entry_t entry;
   memset(&entry, 0, sizeof(entry));
 
-  key = PyDict_GetItem(dict, PyString_FromString("key"));
-  group = PyDict_GetItem(dict, PyString_FromString("group"));
-  type = PyDict_GetItem(dict, PyString_FromString("type"));
-  subtype = PyDict_GetItem(dict, PyString_FromString("subtype"));
-  timestamp_sec = PyDict_GetItem(dict, PyString_FromString("timestamp_sec"));
-  timestamp_usec = PyDict_GetItem(dict, PyString_FromString("timestamp_usec"));
-  data = PyDict_GetItem(dict, PyString_FromString("data"));
+  key = PyDict_GetItem(dict, PyString_FromString("key")); // Borrowed reference
+  group = PyDict_GetItem(dict, PyString_FromString("group")); // Borrowed 
reference
+  type = PyDict_GetItem(dict, PyString_FromString("type")); // Borrowed 
reference
+  subtype = PyDict_GetItem(dict, PyString_FromString("subtype")); // Borrowed 
reference
+  timestamp_sec = PyDict_GetItem(dict, PyString_FromString("timestamp_sec")); 
// Borrowed reference
+  timestamp_usec = PyDict_GetItem(dict, 
PyString_FromString("timestamp_usec")); // Borrowed reference
+  data = PyDict_GetItem(dict, PyString_FromString("data")); // Borrowed 
reference
 
   if (key == NULL || group == NULL || type == NULL || subtype == NULL || 
timestamp_sec == NULL || timestamp_usec == NULL || data == NULL)
   {
@@ -958,10 +1068,10 @@
   }
 
   result = playerc_blackboard_set_entry(self, &entry);
-  groups_dict = PyTuple_GetItem(self->py_private, DICT_GROUPS_INDEX);
+  groups_dict = PyTuple_GetItem((PyObject*)self->py_private, 
DICT_GROUPS_INDEX); // Borrowed reference
   assert(groups_dict);
-  assert(entry_dict);
-  playerc_blackboard___set_nested_dictionary_entry__(self, groups_dict, 
entry.key, entry.group, dict);
+  Py_INCREF(dict);
+  playerc_blackboard___set_nested_dictionary_entry__(self, groups_dict, 
entry.key, entry.group, dict); // Steals reference to entry
   free(entry.data);
 
   return PyInt_FromLong(result);
@@ -985,7 +1095,7 @@
   // Tuple item 1: Dictionary of keys that have been subscribed to.
   // Tuple item 2: List of all events that have occurred. Need to call 
set_queue_events(True). Updated on client.read() callback.
   // Tuple item 3: Whether to queue all events or not. Default not. (0 for 
false, non-zero for true)
-  device->py_private = Py_BuildValue("({},{},[],i)",0); // tuple of a dict and 
a list to store our keys and events in
+  device->py_private = (void*)Py_BuildValue("({},{},[],i)",0); // tuple of a 
dict and a list to store our keys and events in
   
   device->on_blackboard_event = 
playerc_blackboard___python_on_blackboard_event__;
   return device;
@@ -1000,7 +1110,7 @@
   playerc_device_term(&device->info);
   if (device->py_private != NULL)
   {
-       Py_DECREF((PyObject*)device->py_private);
+       Py_XDECREF((PyObject*)device->py_private);
   }
   free(device);
 }


This was sent by the SourceForge.net collaborative development platform, the 
world's largest Open Source development site.

-------------------------------------------------------------------------
This SF.Net email is sponsored by the Moblin Your Move Developer's challenge
Build the coolest Linux based applications with Moblin SDK & win great prizes
Grand prize is a trip for two to an Open Source event anywhere in the world
http://moblin-contest.org/redirect.php?banner_id=100&url=/
_______________________________________________
Playerstage-commit mailing list
Playerstage-commit@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/playerstage-commit

Reply via email to