You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cordova.apache.org by lo...@apache.org on 2013/05/07 17:19:00 UTC

[23/30] [BlackBerry10] Adding support for new BlackBerry10 platform

http://git-wip-us.apache.org/repos/asf/cordova-plugman/blob/a65d10ed/spec/plugins/cordova.echo/src/blackberry10/native/public/json_writer.cpp
----------------------------------------------------------------------
diff --git a/spec/plugins/cordova.echo/src/blackberry10/native/public/json_writer.cpp b/spec/plugins/cordova.echo/src/blackberry10/native/public/json_writer.cpp
new file mode 100644
index 0000000..cdf4188
--- /dev/null
+++ b/spec/plugins/cordova.echo/src/blackberry10/native/public/json_writer.cpp
@@ -0,0 +1,829 @@
+#include <json/writer.h>
+#include <utility>
+#include <assert.h>
+#include <stdio.h>
+#include <string.h>
+#include <iostream>
+#include <sstream>
+#include <iomanip>
+
+#if _MSC_VER >= 1400 // VC++ 8.0
+#pragma warning( disable : 4996 )   // disable warning about strdup being deprecated.
+#endif
+
+namespace Json {
+
+static bool isControlCharacter(char ch)
+{
+   return ch > 0 && ch <= 0x1F;
+}
+
+static bool containsControlCharacter( const char* str )
+{
+   while ( *str ) 
+   {
+      if ( isControlCharacter( *(str++) ) )
+         return true;
+   }
+   return false;
+}
+static void uintToString( unsigned int value, 
+                          char *&current )
+{
+   *--current = 0;
+   do
+   {
+      *--current = (value % 10) + '0';
+      value /= 10;
+   }
+   while ( value != 0 );
+}
+
+std::string valueToString( Int value )
+{
+   char buffer[32];
+   char *current = buffer + sizeof(buffer);
+   bool isNegative = value < 0;
+   if ( isNegative )
+      value = -value;
+   uintToString( UInt(value), current );
+   if ( isNegative )
+      *--current = '-';
+   assert( current >= buffer );
+   return current;
+}
+
+
+std::string valueToString( UInt value )
+{
+   char buffer[32];
+   char *current = buffer + sizeof(buffer);
+   uintToString( value, current );
+   assert( current >= buffer );
+   return current;
+}
+
+std::string valueToString( double value )
+{
+   char buffer[32];
+#if defined(_MSC_VER) && defined(__STDC_SECURE_LIB__) // Use secure version with visual studio 2005 to avoid warning. 
+   sprintf_s(buffer, sizeof(buffer), "%#.16g", value); 
+#else	
+   sprintf(buffer, "%#.16g", value); 
+#endif
+   char* ch = buffer + strlen(buffer) - 1;
+   if (*ch != '0') return buffer; // nothing to truncate, so save time
+   while(ch > buffer && *ch == '0'){
+     --ch;
+   }
+   char* last_nonzero = ch;
+   while(ch >= buffer){
+     switch(*ch){
+     case '0':
+     case '1':
+     case '2':
+     case '3':
+     case '4':
+     case '5':
+     case '6':
+     case '7':
+     case '8':
+     case '9':
+       --ch;
+       continue;
+     case '.':
+       // Truncate zeroes to save bytes in output, but keep one.
+       *(last_nonzero+2) = '\0';
+       return buffer;
+     default:
+       return buffer;
+     }
+   }
+   return buffer;
+}
+
+
+std::string valueToString( bool value )
+{
+   return value ? "true" : "false";
+}
+
+std::string valueToQuotedString( const char *value )
+{
+   // Not sure how to handle unicode...
+   if (strpbrk(value, "\"\\\b\f\n\r\t") == NULL && !containsControlCharacter( value ))
+      return std::string("\"") + value + "\"";
+   // We have to walk value and escape any special characters.
+   // Appending to std::string is not efficient, but this should be rare.
+   // (Note: forward slashes are *not* rare, but I am not escaping them.)
+   unsigned maxsize = strlen(value)*2 + 3; // allescaped+quotes+NULL
+   std::string result;
+   result.reserve(maxsize); // to avoid lots of mallocs
+   result += "\"";
+   for (const char* c=value; *c != 0; ++c)
+   {
+      switch(*c)
+      {
+         case '\"':
+            result += "\\\"";
+            break;
+         case '\\':
+            result += "\\\\";
+            break;
+         case '\b':
+            result += "\\b";
+            break;
+         case '\f':
+            result += "\\f";
+            break;
+         case '\n':
+            result += "\\n";
+            break;
+         case '\r':
+            result += "\\r";
+            break;
+         case '\t':
+            result += "\\t";
+            break;
+         //case '/':
+            // Even though \/ is considered a legal escape in JSON, a bare
+            // slash is also legal, so I see no reason to escape it.
+            // (I hope I am not misunderstanding something.
+            // blep notes: actually escaping \/ may be useful in javascript to avoid </ 
+            // sequence.
+            // Should add a flag to allow this compatibility mode and prevent this 
+            // sequence from occurring.
+         default:
+            if ( isControlCharacter( *c ) )
+            {
+               std::ostringstream oss;
+               oss << "\\u" << std::hex << std::uppercase << std::setfill('0') << std::setw(4) << static_cast<int>(*c);
+               result += oss.str();
+            }
+            else
+            {
+               result += *c;
+            }
+            break;
+      }
+   }
+   result += "\"";
+   return result;
+}
+
+// Class Writer
+// //////////////////////////////////////////////////////////////////
+Writer::~Writer()
+{
+}
+
+
+// Class FastWriter
+// //////////////////////////////////////////////////////////////////
+
+FastWriter::FastWriter()
+   : yamlCompatiblityEnabled_( false )
+{
+}
+
+
+void 
+FastWriter::enableYAMLCompatibility()
+{
+   yamlCompatiblityEnabled_ = true;
+}
+
+
+std::string 
+FastWriter::write( const Value &root )
+{
+   document_ = "";
+   writeValue( root );
+   document_ += "\n";
+   return document_;
+}
+
+
+void 
+FastWriter::writeValue( const Value &value )
+{
+   switch ( value.type() )
+   {
+   case nullValue:
+      document_ += "null";
+      break;
+   case intValue:
+      document_ += valueToString( value.asInt() );
+      break;
+   case uintValue:
+      document_ += valueToString( value.asUInt() );
+      break;
+   case realValue:
+      document_ += valueToString( value.asDouble() );
+      break;
+   case stringValue:
+      document_ += valueToQuotedString( value.asCString() );
+      break;
+   case booleanValue:
+      document_ += valueToString( value.asBool() );
+      break;
+   case arrayValue:
+      {
+         document_ += "[";
+         int size = value.size();
+         for ( int index =0; index < size; ++index )
+         {
+            if ( index > 0 )
+               document_ += ",";
+            writeValue( value[index] );
+         }
+         document_ += "]";
+      }
+      break;
+   case objectValue:
+      {
+         Value::Members members( value.getMemberNames() );
+         document_ += "{";
+         for ( Value::Members::iterator it = members.begin(); 
+               it != members.end(); 
+               ++it )
+         {
+            const std::string &name = *it;
+            if ( it != members.begin() )
+               document_ += ",";
+            document_ += valueToQuotedString( name.c_str() );
+            document_ += yamlCompatiblityEnabled_ ? ": " 
+                                                  : ":";
+            writeValue( value[name] );
+         }
+         document_ += "}";
+      }
+      break;
+   }
+}
+
+
+// Class StyledWriter
+// //////////////////////////////////////////////////////////////////
+
+StyledWriter::StyledWriter()
+   : rightMargin_( 74 )
+   , indentSize_( 3 )
+{
+}
+
+
+std::string 
+StyledWriter::write( const Value &root )
+{
+   document_ = "";
+   addChildValues_ = false;
+   indentString_ = "";
+   writeCommentBeforeValue( root );
+   writeValue( root );
+   writeCommentAfterValueOnSameLine( root );
+   document_ += "\n";
+   return document_;
+}
+
+
+void 
+StyledWriter::writeValue( const Value &value )
+{
+   switch ( value.type() )
+   {
+   case nullValue:
+      pushValue( "null" );
+      break;
+   case intValue:
+      pushValue( valueToString( value.asInt() ) );
+      break;
+   case uintValue:
+      pushValue( valueToString( value.asUInt() ) );
+      break;
+   case realValue:
+      pushValue( valueToString( value.asDouble() ) );
+      break;
+   case stringValue:
+      pushValue( valueToQuotedString( value.asCString() ) );
+      break;
+   case booleanValue:
+      pushValue( valueToString( value.asBool() ) );
+      break;
+   case arrayValue:
+      writeArrayValue( value);
+      break;
+   case objectValue:
+      {
+         Value::Members members( value.getMemberNames() );
+         if ( members.empty() )
+            pushValue( "{}" );
+         else
+         {
+            writeWithIndent( "{" );
+            indent();
+            Value::Members::iterator it = members.begin();
+            while ( true )
+            {
+               const std::string &name = *it;
+               const Value &childValue = value[name];
+               writeCommentBeforeValue( childValue );
+               writeWithIndent( valueToQuotedString( name.c_str() ) );
+               document_ += " : ";
+               writeValue( childValue );
+               if ( ++it == members.end() )
+               {
+                  writeCommentAfterValueOnSameLine( childValue );
+                  break;
+               }
+               document_ += ",";
+               writeCommentAfterValueOnSameLine( childValue );
+            }
+            unindent();
+            writeWithIndent( "}" );
+         }
+      }
+      break;
+   }
+}
+
+
+void 
+StyledWriter::writeArrayValue( const Value &value )
+{
+   unsigned size = value.size();
+   if ( size == 0 )
+      pushValue( "[]" );
+   else
+   {
+      bool isArrayMultiLine = isMultineArray( value );
+      if ( isArrayMultiLine )
+      {
+         writeWithIndent( "[" );
+         indent();
+         bool hasChildValue = !childValues_.empty();
+         unsigned index =0;
+         while ( true )
+         {
+            const Value &childValue = value[index];
+            writeCommentBeforeValue( childValue );
+            if ( hasChildValue )
+               writeWithIndent( childValues_[index] );
+            else
+            {
+               writeIndent();
+               writeValue( childValue );
+            }
+            if ( ++index == size )
+            {
+               writeCommentAfterValueOnSameLine( childValue );
+               break;
+            }
+            document_ += ",";
+            writeCommentAfterValueOnSameLine( childValue );
+         }
+         unindent();
+         writeWithIndent( "]" );
+      }
+      else // output on a single line
+      {
+         assert( childValues_.size() == size );
+         document_ += "[ ";
+         for ( unsigned index =0; index < size; ++index )
+         {
+            if ( index > 0 )
+               document_ += ", ";
+            document_ += childValues_[index];
+         }
+         document_ += " ]";
+      }
+   }
+}
+
+
+bool 
+StyledWriter::isMultineArray( const Value &value )
+{
+   int size = value.size();
+   bool isMultiLine = size*3 >= rightMargin_ ;
+   childValues_.clear();
+   for ( int index =0; index < size  &&  !isMultiLine; ++index )
+   {
+      const Value &childValue = value[index];
+      isMultiLine = isMultiLine  ||
+                     ( (childValue.isArray()  ||  childValue.isObject())  &&  
+                        childValue.size() > 0 );
+   }
+   if ( !isMultiLine ) // check if line length > max line length
+   {
+      childValues_.reserve( size );
+      addChildValues_ = true;
+      int lineLength = 4 + (size-1)*2; // '[ ' + ', '*n + ' ]'
+      for ( int index =0; index < size  &&  !isMultiLine; ++index )
+      {
+         writeValue( value[index] );
+         lineLength += int( childValues_[index].length() );
+         isMultiLine = isMultiLine  &&  hasCommentForValue( value[index] );
+      }
+      addChildValues_ = false;
+      isMultiLine = isMultiLine  ||  lineLength >= rightMargin_;
+   }
+   return isMultiLine;
+}
+
+
+void 
+StyledWriter::pushValue( const std::string &value )
+{
+   if ( addChildValues_ )
+      childValues_.push_back( value );
+   else
+      document_ += value;
+}
+
+
+void 
+StyledWriter::writeIndent()
+{
+   if ( !document_.empty() )
+   {
+      char last = document_[document_.length()-1];
+      if ( last == ' ' )     // already indented
+         return;
+      if ( last != '\n' )    // Comments may add new-line
+         document_ += '\n';
+   }
+   document_ += indentString_;
+}
+
+
+void 
+StyledWriter::writeWithIndent( const std::string &value )
+{
+   writeIndent();
+   document_ += value;
+}
+
+
+void 
+StyledWriter::indent()
+{
+   indentString_ += std::string( indentSize_, ' ' );
+}
+
+
+void 
+StyledWriter::unindent()
+{
+   assert( int(indentString_.size()) >= indentSize_ );
+   indentString_.resize( indentString_.size() - indentSize_ );
+}
+
+
+void 
+StyledWriter::writeCommentBeforeValue( const Value &root )
+{
+   if ( !root.hasComment( commentBefore ) )
+      return;
+   document_ += normalizeEOL( root.getComment( commentBefore ) );
+   document_ += "\n";
+}
+
+
+void 
+StyledWriter::writeCommentAfterValueOnSameLine( const Value &root )
+{
+   if ( root.hasComment( commentAfterOnSameLine ) )
+      document_ += " " + normalizeEOL( root.getComment( commentAfterOnSameLine ) );
+
+   if ( root.hasComment( commentAfter ) )
+   {
+      document_ += "\n";
+      document_ += normalizeEOL( root.getComment( commentAfter ) );
+      document_ += "\n";
+   }
+}
+
+
+bool 
+StyledWriter::hasCommentForValue( const Value &value )
+{
+   return value.hasComment( commentBefore )
+          ||  value.hasComment( commentAfterOnSameLine )
+          ||  value.hasComment( commentAfter );
+}
+
+
+std::string 
+StyledWriter::normalizeEOL( const std::string &text )
+{
+   std::string normalized;
+   normalized.reserve( text.length() );
+   const char *begin = text.c_str();
+   const char *end = begin + text.length();
+   const char *current = begin;
+   while ( current != end )
+   {
+      char c = *current++;
+      if ( c == '\r' ) // mac or dos EOL
+      {
+         if ( *current == '\n' ) // convert dos EOL
+            ++current;
+         normalized += '\n';
+      }
+      else // handle unix EOL & other char
+         normalized += c;
+   }
+   return normalized;
+}
+
+
+// Class StyledStreamWriter
+// //////////////////////////////////////////////////////////////////
+
+StyledStreamWriter::StyledStreamWriter( std::string indentation )
+   : document_(NULL)
+   , rightMargin_( 74 )
+   , indentation_( indentation )
+{
+}
+
+
+void
+StyledStreamWriter::write( std::ostream &out, const Value &root )
+{
+   document_ = &out;
+   addChildValues_ = false;
+   indentString_ = "";
+   writeCommentBeforeValue( root );
+   writeValue( root );
+   writeCommentAfterValueOnSameLine( root );
+   *document_ << "\n";
+   document_ = NULL; // Forget the stream, for safety.
+}
+
+
+void 
+StyledStreamWriter::writeValue( const Value &value )
+{
+   switch ( value.type() )
+   {
+   case nullValue:
+      pushValue( "null" );
+      break;
+   case intValue:
+      pushValue( valueToString( value.asInt() ) );
+      break;
+   case uintValue:
+      pushValue( valueToString( value.asUInt() ) );
+      break;
+   case realValue:
+      pushValue( valueToString( value.asDouble() ) );
+      break;
+   case stringValue:
+      pushValue( valueToQuotedString( value.asCString() ) );
+      break;
+   case booleanValue:
+      pushValue( valueToString( value.asBool() ) );
+      break;
+   case arrayValue:
+      writeArrayValue( value);
+      break;
+   case objectValue:
+      {
+         Value::Members members( value.getMemberNames() );
+         if ( members.empty() )
+            pushValue( "{}" );
+         else
+         {
+            writeWithIndent( "{" );
+            indent();
+            Value::Members::iterator it = members.begin();
+            while ( true )
+            {
+               const std::string &name = *it;
+               const Value &childValue = value[name];
+               writeCommentBeforeValue( childValue );
+               writeWithIndent( valueToQuotedString( name.c_str() ) );
+               *document_ << " : ";
+               writeValue( childValue );
+               if ( ++it == members.end() )
+               {
+                  writeCommentAfterValueOnSameLine( childValue );
+                  break;
+               }
+               *document_ << ",";
+               writeCommentAfterValueOnSameLine( childValue );
+            }
+            unindent();
+            writeWithIndent( "}" );
+         }
+      }
+      break;
+   }
+}
+
+
+void 
+StyledStreamWriter::writeArrayValue( const Value &value )
+{
+   unsigned size = value.size();
+   if ( size == 0 )
+      pushValue( "[]" );
+   else
+   {
+      bool isArrayMultiLine = isMultineArray( value );
+      if ( isArrayMultiLine )
+      {
+         writeWithIndent( "[" );
+         indent();
+         bool hasChildValue = !childValues_.empty();
+         unsigned index =0;
+         while ( true )
+         {
+            const Value &childValue = value[index];
+            writeCommentBeforeValue( childValue );
+            if ( hasChildValue )
+               writeWithIndent( childValues_[index] );
+            else
+            {
+	       writeIndent();
+               writeValue( childValue );
+            }
+            if ( ++index == size )
+            {
+               writeCommentAfterValueOnSameLine( childValue );
+               break;
+            }
+            *document_ << ",";
+            writeCommentAfterValueOnSameLine( childValue );
+         }
+         unindent();
+         writeWithIndent( "]" );
+      }
+      else // output on a single line
+      {
+         assert( childValues_.size() == size );
+         *document_ << "[ ";
+         for ( unsigned index =0; index < size; ++index )
+         {
+            if ( index > 0 )
+               *document_ << ", ";
+            *document_ << childValues_[index];
+         }
+         *document_ << " ]";
+      }
+   }
+}
+
+
+bool 
+StyledStreamWriter::isMultineArray( const Value &value )
+{
+   int size = value.size();
+   bool isMultiLine = size*3 >= rightMargin_ ;
+   childValues_.clear();
+   for ( int index =0; index < size  &&  !isMultiLine; ++index )
+   {
+      const Value &childValue = value[index];
+      isMultiLine = isMultiLine  ||
+                     ( (childValue.isArray()  ||  childValue.isObject())  &&  
+                        childValue.size() > 0 );
+   }
+   if ( !isMultiLine ) // check if line length > max line length
+   {
+      childValues_.reserve( size );
+      addChildValues_ = true;
+      int lineLength = 4 + (size-1)*2; // '[ ' + ', '*n + ' ]'
+      for ( int index =0; index < size  &&  !isMultiLine; ++index )
+      {
+         writeValue( value[index] );
+         lineLength += int( childValues_[index].length() );
+         isMultiLine = isMultiLine  &&  hasCommentForValue( value[index] );
+      }
+      addChildValues_ = false;
+      isMultiLine = isMultiLine  ||  lineLength >= rightMargin_;
+   }
+   return isMultiLine;
+}
+
+
+void 
+StyledStreamWriter::pushValue( const std::string &value )
+{
+   if ( addChildValues_ )
+      childValues_.push_back( value );
+   else
+      *document_ << value;
+}
+
+
+void 
+StyledStreamWriter::writeIndent()
+{
+  /*
+    Some comments in this method would have been nice. ;-)
+
+   if ( !document_.empty() )
+   {
+      char last = document_[document_.length()-1];
+      if ( last == ' ' )     // already indented
+         return;
+      if ( last != '\n' )    // Comments may add new-line
+         *document_ << '\n';
+   }
+  */
+   *document_ << '\n' << indentString_;
+}
+
+
+void 
+StyledStreamWriter::writeWithIndent( const std::string &value )
+{
+   writeIndent();
+   *document_ << value;
+}
+
+
+void 
+StyledStreamWriter::indent()
+{
+   indentString_ += indentation_;
+}
+
+
+void 
+StyledStreamWriter::unindent()
+{
+   assert( indentString_.size() >= indentation_.size() );
+   indentString_.resize( indentString_.size() - indentation_.size() );
+}
+
+
+void 
+StyledStreamWriter::writeCommentBeforeValue( const Value &root )
+{
+   if ( !root.hasComment( commentBefore ) )
+      return;
+   *document_ << normalizeEOL( root.getComment( commentBefore ) );
+   *document_ << "\n";
+}
+
+
+void 
+StyledStreamWriter::writeCommentAfterValueOnSameLine( const Value &root )
+{
+   if ( root.hasComment( commentAfterOnSameLine ) )
+      *document_ << " " + normalizeEOL( root.getComment( commentAfterOnSameLine ) );
+
+   if ( root.hasComment( commentAfter ) )
+   {
+      *document_ << "\n";
+      *document_ << normalizeEOL( root.getComment( commentAfter ) );
+      *document_ << "\n";
+   }
+}
+
+
+bool 
+StyledStreamWriter::hasCommentForValue( const Value &value )
+{
+   return value.hasComment( commentBefore )
+          ||  value.hasComment( commentAfterOnSameLine )
+          ||  value.hasComment( commentAfter );
+}
+
+
+std::string 
+StyledStreamWriter::normalizeEOL( const std::string &text )
+{
+   std::string normalized;
+   normalized.reserve( text.length() );
+   const char *begin = text.c_str();
+   const char *end = begin + text.length();
+   const char *current = begin;
+   while ( current != end )
+   {
+      char c = *current++;
+      if ( c == '\r' ) // mac or dos EOL
+      {
+         if ( *current == '\n' ) // convert dos EOL
+            ++current;
+         normalized += '\n';
+      }
+      else // handle unix EOL & other char
+         normalized += c;
+   }
+   return normalized;
+}
+
+
+std::ostream& operator<<( std::ostream &sout, const Value &root )
+{
+   Json::StyledStreamWriter writer;
+   writer.write(sout, root);
+   return sout;
+}
+
+
+} // namespace Json

http://git-wip-us.apache.org/repos/asf/cordova-plugman/blob/a65d10ed/spec/plugins/cordova.echo/src/blackberry10/native/public/plugin.cpp
----------------------------------------------------------------------
diff --git a/spec/plugins/cordova.echo/src/blackberry10/native/public/plugin.cpp b/spec/plugins/cordova.echo/src/blackberry10/native/public/plugin.cpp
new file mode 100644
index 0000000..6906275
--- /dev/null
+++ b/spec/plugins/cordova.echo/src/blackberry10/native/public/plugin.cpp
@@ -0,0 +1,320 @@
+#include "plugin.h"
+#include "tokenizer.h"
+
+#ifdef _WINDOWS
+#include <windows.h>
+BOOL APIENTRY DllMain( HANDLE hModule,
+                       DWORD ul_reason_for_call,
+                       LPVOID lpReserved )
+{
+    return TRUE;
+}
+#else
+#include <errno.h>
+#include <string.h>
+
+extern int errno;
+#endif
+
+SendPluginEv SendPluginEvent;
+
+string g_GetSysErrMsg( void )
+{
+    string strError = "Unknown";
+    // Problem loading
+#ifdef _WINDOWS
+    int nErrorCode = GetLastError();
+    LPTSTR s;
+    if ( ::FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
+    NULL, nErrorCode, 0, ( LPTSTR ) &s, 0, NULL ) )
+    {
+        strError = s;
+    }
+    else
+    {
+        char szBuf[ 20 ];
+        _snprintf_s( szBuf, _countof(szBuf), 19, "%d", nErrorCode );
+        strError = szBuf;
+    }
+#else
+    char szError[80];
+    if ( strerror_r( errno, szError, sizeof(szError)  ) )
+    {
+        strError = "no description found";
+    }
+    else
+    {
+        strError = szError;
+    }
+#endif
+    return strError;
+}
+
+void g_sleep( unsigned int mseconds )
+{
+#ifdef _WINDOWS
+    Sleep( mseconds );
+#else
+    usleep( mseconds * 1000 );
+#endif
+}
+
+string& g_trim( string& str )
+{
+    // Whitespace characters
+    char whspc[] = " \t\r\n\v\f";
+
+    // Whack off first part
+    size_t pos = str.find_first_not_of( whspc );
+
+    if ( pos != string::npos )
+        str.replace( 0, pos, "" );
+
+    // Whack off trailing stuff
+    pos = str.find_last_not_of( whspc );
+
+    if ( pos != string::npos )
+        str.replace( pos + 1, str.length() - pos, "" );
+
+    return str;
+}
+
+void g_tokenize( const string& str, const string& delimiters, vector<string>& tokens )
+{
+    tokenize( str, tokens, delimiters );
+}
+
+char* SetEventFunc( SendPluginEv funcPtr )
+{
+    static char * szObjList = onGetObjList();
+    SendPluginEvent = funcPtr;
+    return szObjList;
+}
+
+
+const int nMAXSIZE = 512;
+char* g_pszRetVal = NULL;
+
+//-----------------------------------------------------------
+// Map from an object Id to an object instance
+//-----------------------------------------------------------
+typedef std::map<string, JSExt*> StringToJExt_T;
+
+//-----------------------------------------------------------
+// Map from a browser context to an id mapping
+//-----------------------------------------------------------
+typedef std::map<void*, StringToJExt_T*> VoidToMap_T;
+
+VoidToMap_T g_context2Map;
+
+class GlobalSharedModule
+{
+
+public:
+    GlobalSharedModule( void )
+    {
+        g_pszRetVal = new char[ nMAXSIZE ];
+    }
+
+    ~GlobalSharedModule()
+    {
+        delete [] g_pszRetVal;
+
+        VoidToMap_T::iterator posMaps;
+
+        for ( posMaps = g_context2Map.begin(); posMaps != g_context2Map.end(); ++posMaps )
+        {
+            StringToJExt_T& id2Obj = *posMaps->second;
+            StringToJExt_T::iterator posMap;
+
+            for ( posMap = id2Obj.begin(); posMap != id2Obj.end(); ++posMap )
+            {
+                JSExt* pJSExt = posMap->second;
+
+                if ( pJSExt->CanDelete() )
+                {
+                    delete pJSExt;
+                }
+            }
+
+            id2Obj.erase( id2Obj.begin(), id2Obj.end() );
+        }
+
+        g_context2Map.erase( g_context2Map.begin(), g_context2Map.end() );
+    }
+};
+
+GlobalSharedModule g_sharedModule;
+
+char* g_str2global( const string& strRetVal )
+{
+    int nLen = strRetVal.size();
+
+    if ( nLen >= nMAXSIZE )
+    {
+        delete [] g_pszRetVal;
+        g_pszRetVal = new char[ nLen + 1 ];
+    }
+
+    else
+    {
+        // To minimaize the number of memory reallocations, the assumption
+        // is that in most times this will be the case
+        delete [] g_pszRetVal;
+        g_pszRetVal = new char[ nMAXSIZE ];
+    }
+
+    strcpy( g_pszRetVal, strRetVal.c_str() );
+    return g_pszRetVal;
+}
+
+bool g_unregisterObject( const string& strObjId, void* pContext )
+{
+    // Called by the plugin extension implementation
+    // if the extension handles the deletion of its object
+
+    StringToJExt_T * pID2Obj = NULL;
+
+    VoidToMap_T::iterator iter = g_context2Map.find( pContext );
+
+    if ( iter != g_context2Map.end() )
+    {
+        pID2Obj = iter->second;
+    }
+    else
+    {
+        return false;
+    }
+
+    StringToJExt_T& mapID2Obj = *pID2Obj;
+
+    StringToJExt_T::iterator r = mapID2Obj.find( strObjId );
+
+    if ( r == mapID2Obj.end() )
+    {
+        return false;
+    }
+
+    mapID2Obj.erase( strObjId );
+    return true;
+}
+
+char* InvokeFunction( const char* szCommand, void* pContext )
+{
+    StringToJExt_T * pID2Obj = NULL;
+
+    VoidToMap_T::iterator iter = g_context2Map.find( pContext );
+
+    if ( iter != g_context2Map.end() )
+    {
+        pID2Obj = iter->second;
+    }
+    else
+    {
+        pID2Obj = new StringToJExt_T;
+        g_context2Map[ pContext ] = pID2Obj;
+    }
+
+    StringToJExt_T& mapID2Obj = *pID2Obj;
+
+    string strFullCommand = szCommand;
+    vector<string> arParams;
+    g_tokenize( strFullCommand, " ", arParams );
+    string strCommand = arParams[ 0 ];
+    string strRetVal = szERROR;
+
+    if ( strCommand == szCREATE )
+    {
+        string strClassName = arParams[ 1 ];
+        string strObjId = arParams[ 2 ];
+
+        StringToJExt_T::iterator r = mapID2Obj.find( strObjId );
+
+        if ( r != mapID2Obj.end() )
+        {
+            strRetVal += strObjId;
+            strRetVal += " :Object already exists.";
+            return g_str2global( strRetVal );
+        }
+
+        JSExt* pJSExt = onCreateObject( strClassName, strObjId );
+
+        if ( pJSExt == NULL )
+        {
+            strRetVal += strObjId;
+            strRetVal += " :Unknown object type ";
+            strRetVal += strClassName;
+            return g_str2global( strRetVal );
+        }
+
+        pJSExt->m_pContext = pContext;
+        mapID2Obj[ strObjId ] = pJSExt;
+
+        strRetVal = szOK;
+        strRetVal += strObjId;
+        return g_str2global( strRetVal );
+    }
+    else
+    if ( strCommand == szINVOKE )
+    {
+        string strObjId = arParams[ 1 ];
+        string strMethod = arParams[ 2 ];
+
+        StringToJExt_T::iterator r = mapID2Obj.find( strObjId );
+
+        if ( r == mapID2Obj.end() )
+        {
+            strRetVal += strObjId;
+            strRetVal += " :No object found for id.";
+            return g_str2global( strRetVal );
+        }
+
+        JSExt* pJSExt = r->second;
+
+        size_t nLoc = strFullCommand.find( strObjId );
+
+        if ( nLoc == string::npos )
+        {
+            strRetVal += strObjId;
+            strRetVal += " :Internal InvokeMethod error.";
+            return g_str2global( strRetVal );
+        }
+
+        if ( strMethod == szDISPOSE )
+        {
+            StringToJExt_T::iterator r = mapID2Obj.find( strObjId );
+
+            if ( r == mapID2Obj.end() )
+            {
+                strRetVal = szERROR;
+                strRetVal += strObjId;
+                return g_str2global( strRetVal );
+            }
+
+            JSExt * pJSExt = mapID2Obj[ strObjId ];
+
+            if ( pJSExt->CanDelete() )
+            {
+                delete pJSExt;
+            }
+
+            mapID2Obj.erase( strObjId );
+            strRetVal = szOK;
+            strRetVal += strObjId;
+            return g_str2global( strRetVal );
+        }
+
+        size_t nSuffixLoc = nLoc + strObjId.size();
+        string strInvoke = strFullCommand.substr( nSuffixLoc );
+        strInvoke = g_trim( strInvoke );
+        strRetVal = pJSExt->InvokeMethod( strInvoke );
+        return g_str2global( strRetVal );
+    }
+
+    strRetVal += " :Unknown command ";
+    strRetVal += strCommand;
+    return g_str2global( strRetVal );
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+

http://git-wip-us.apache.org/repos/asf/cordova-plugman/blob/a65d10ed/spec/plugins/cordova.echo/src/blackberry10/native/public/plugin.h
----------------------------------------------------------------------
diff --git a/spec/plugins/cordova.echo/src/blackberry10/native/public/plugin.h b/spec/plugins/cordova.echo/src/blackberry10/native/public/plugin.h
new file mode 100644
index 0000000..4ef7116
--- /dev/null
+++ b/spec/plugins/cordova.echo/src/blackberry10/native/public/plugin.h
@@ -0,0 +1,70 @@
+#ifndef _PLUGIN_H
+#define _PLUGIN_H
+
+#include <map>
+#include <string>
+#include <vector>
+#include <unistd.h>
+//#include "tokenizer.h"
+
+using namespace std;
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+//%% Functions exported by this DLL
+//%% Should always be only SetEventFunc and InvokeFunction
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+// g++ requires extern "C" otherwise the names of SetEventFunc and InvokeFunction
+// are mangled C++ style. MS Visual Studio doesn't seem to care though.
+extern "C"
+{
+    typedef void (*SendPluginEv)( const char* szEvent, void* pContext );
+    char* SetEventFunc(SendPluginEv funcPtr);
+    char* InvokeFunction( const char* szCommand, void* pContext );
+}
+
+// JNEXT Framework function of the form:
+// typedef void (*SendPluginEv)( const char* szEvent );
+// used to notify JavaScript of an asynchronous event
+extern SendPluginEv SendPluginEvent;
+
+/////////////////////////////////////////////////////////////////////////
+// Constants and methods common to all JNEXT extensions types
+/////////////////////////////////////////////////////////////////////////
+#define szERROR         "Error "
+#define szOK            "Ok "
+
+#define szDISPOSE       "Dispose"
+#define szINVOKE        "InvokeMethod"
+#define szCREATE        "CreateObj"
+
+/////////////////////////////////////////////////////////////////////////
+// Utility functions
+/////////////////////////////////////////////////////////////////////////
+string& g_trim( string& str );
+void g_tokenize(const string& str,const string& delimiters, vector<string>& tokens);
+char* g_str2static( const string& strRetVal );
+void g_sleep( unsigned int mseconds );
+bool g_unregisterObject( const string& strObjId, void* pContext );
+
+
+/////////////////////////////////////////////////////////////////////////
+// Abstract extension object
+/////////////////////////////////////////////////////////////////////////
+class JSExt
+{
+public:
+    virtual ~JSExt() {};
+    virtual string InvokeMethod( const string& strCommand ) = 0;
+    virtual bool CanDelete( void ) = 0;
+    virtual void TryDelete( void ) {}
+public:
+    void* m_pContext;
+};
+
+/////////////////////////////////////////////////////////////////////////
+// Callback functions to be implemented by the plugin implementation
+/////////////////////////////////////////////////////////////////////////
+extern char* onGetObjList( void );
+extern JSExt* onCreateObject( const string& strClassName, const string& strObjId );
+
+#endif

http://git-wip-us.apache.org/repos/asf/cordova-plugman/blob/a65d10ed/spec/plugins/cordova.echo/src/blackberry10/native/public/tokenizer.cpp
----------------------------------------------------------------------
diff --git a/spec/plugins/cordova.echo/src/blackberry10/native/public/tokenizer.cpp b/spec/plugins/cordova.echo/src/blackberry10/native/public/tokenizer.cpp
new file mode 100644
index 0000000..4a39573
--- /dev/null
+++ b/spec/plugins/cordova.echo/src/blackberry10/native/public/tokenizer.cpp
@@ -0,0 +1,222 @@
+/************************************************************************
+The zlib/libpng License
+
+Copyright (c) 2006 Joerg Wiedenmann
+
+This software is provided 'as-is', without any express or implied warranty.
+In no event will the authors be held liable for any damages arising from
+the use of this software.
+
+Permission is granted to anyone to use this software for any purpose,
+including commercial applications, and to alter it and redistribute it
+freely, subject to the following restrictions:
+
+1. The origin of this software must not be misrepresented;
+you must not claim that you wrote the original software.
+If you use this software in a product, an acknowledgment
+in the product documentation would be appreciated but is
+not required.
+
+2. Altered source versions must be plainly marked as such,
+and must not be misrepresented as being the original software.
+
+3. This notice may not be removed or altered from any source distribution.
+
+***********************************************************************/
+
+/********************************************************************
+	created:	2006-01-28
+	filename: 	tokenizer.cpp
+	author:		J�rg Wiedenmann
+	
+	purpose:	A tokenizer function which provides a very
+				customizable way of breaking up strings.
+
+	history:	2006-01-28, Original version
+				2006-03-04, Fixed a small parsing bug, thanks Elias.
+*********************************************************************/
+
+#include "tokenizer.h"
+
+using namespace std;
+
+void tokenize ( const string& str, vector<string>& result,
+			   const string& delimiters, const string& delimiters_preserve,
+			   const string& quote, const string& esc )
+{
+	// clear the vector
+	if ( false == result.empty() )
+	{
+		result.clear();
+	}
+
+	string::size_type pos = 0; // the current position (char) in the string
+	char ch = 0; // buffer for the current character
+	char delimiter = 0;	// the buffer for the delimiter char which
+							// will be added to the tokens if the delimiter
+							// is preserved
+	char current_quote = 0; // the char of the current open quote
+	bool quoted = false; // indicator if there is an open quote
+	string token;  // string buffer for the token
+	bool token_complete = false; // indicates if the current token is
+								 // read to be added to the result vector
+	string::size_type len = str.length();  // length of the input-string
+
+	// for every char in the input-string
+	while ( len > pos )
+	{
+		// get the character of the string and reset the delimiter buffer
+		ch = str.at(pos);
+		delimiter = 0;
+
+		// assume ch isn't a delimiter
+		bool add_char = true;
+
+		// check ...
+
+		// ... if the delimiter is an escaped character
+		bool escaped = false; // indicates if the next char is protected
+		if ( false == esc.empty() ) // check if esc-chars are  provided
+		{
+			if ( string::npos != esc.find_first_of(ch) )
+			{
+				// get the escaped char
+				++pos;
+				if ( pos < len ) // if there are more chars left
+				{
+					// get the next one
+					ch = str.at(pos);
+
+					// add the escaped character to the token
+					add_char = true;
+				}
+				else // cannot get any more characters
+				{
+					// don't add the esc-char
+					add_char = false;
+				}
+
+				// ignore the remaining delimiter checks
+				escaped = true;
+			}
+		}
+
+		// ... if the delimiter is a quote
+		if ( false == quote.empty() && false == escaped )
+		{
+			// if quote chars are provided and the char isn't protected
+			if ( string::npos != quote.find_first_of(ch) )
+			{
+				// if not quoted, set state to open quote and set
+				// the quote character
+				if ( false == quoted )
+				{
+					quoted = true;
+					current_quote = ch;
+
+					// don't add the quote-char to the token
+					add_char = false;
+				}
+				else // if quote is open already
+				{
+					// check if it is the matching character to close it
+					if ( current_quote == ch )
+					{
+						// close quote and reset the quote character
+						quoted = false;
+						current_quote = 0;
+
+						// don't add the quote-char to the token
+						add_char = false;
+					}
+				} // else
+			}
+		}
+
+		// ... if the delimiter isn't preserved
+		if ( false == delimiters.empty() && false == escaped &&
+			 false == quoted )
+		{
+			// if a delimiter is provided and the char isn't protected by
+			// quote or escape char
+			if ( string::npos != delimiters.find_first_of(ch) )
+			{
+				// if ch is a delimiter and the token string isn't empty
+				// the token is complete
+				if ( false == token.empty() ) // BUGFIX: 2006-03-04
+				{
+					token_complete = true;
+				}
+
+				// don't add the delimiter to the token
+				add_char = false;
+			}
+		}
+
+		// ... if the delimiter is preserved - add it as a token
+		bool add_delimiter = false;
+		if ( false == delimiters_preserve.empty() && false == escaped &&
+			 false == quoted )
+		{
+			// if a delimiter which will be preserved is provided and the
+			// char isn't protected by quote or escape char
+			if ( string::npos != delimiters_preserve.find_first_of(ch) )
+			{
+				// if ch is a delimiter and the token string isn't empty
+				// the token is complete
+				if ( false == token.empty() ) // BUGFIX: 2006-03-04
+				{
+					token_complete = true;
+				}
+
+				// don't add the delimiter to the token
+				add_char = false;
+
+				// add the delimiter
+				delimiter = ch;
+				add_delimiter = true;
+			}
+		}
+
+
+		// add the character to the token
+		if ( true == add_char )
+		{
+			// add the current char
+			token.push_back( ch );
+		}
+
+		// add the token if it is complete
+		if ( true == token_complete && false == token.empty() )
+		{
+			// add the token string
+			result.push_back( token );
+
+			// clear the contents
+			token.clear();
+
+			// build the next token
+			token_complete = false;
+		}
+
+		// add the delimiter
+		if ( true == add_delimiter )
+		{
+			// the next token is the delimiter
+			string delim_token;
+			delim_token.push_back( delimiter );
+			result.push_back( delim_token );
+
+			// REMOVED: 2006-03-04, Bugfix
+		}
+
+		// repeat for the next character
+		++pos;
+	} // while
+
+	// add the final token
+	if ( false == token.empty() )
+	{
+		result.push_back( token );
+	}
+}

http://git-wip-us.apache.org/repos/asf/cordova-plugman/blob/a65d10ed/spec/plugins/cordova.echo/src/blackberry10/native/public/tokenizer.h
----------------------------------------------------------------------
diff --git a/spec/plugins/cordova.echo/src/blackberry10/native/public/tokenizer.h b/spec/plugins/cordova.echo/src/blackberry10/native/public/tokenizer.h
new file mode 100644
index 0000000..75f567c
--- /dev/null
+++ b/spec/plugins/cordova.echo/src/blackberry10/native/public/tokenizer.h
@@ -0,0 +1,55 @@
+/************************************************************************
+The zlib/libpng License
+
+Copyright (c) 2006 Joerg Wiedenmann
+
+This software is provided 'as-is', without any express or implied warranty.
+In no event will the authors be held liable for any damages arising from
+the use of this software.
+
+Permission is granted to anyone to use this software for any purpose,
+including commercial applications, and to alter it and redistribute it
+freely, subject to the following restrictions:
+
+1. The origin of this software must not be misrepresented;
+	you must not claim that you wrote the original software.
+	If you use this software in a product, an acknowledgment
+	in the product documentation would be appreciated but is
+	not required.
+
+2. Altered source versions must be plainly marked as such,
+	and must not be misrepresented as being the original software.
+
+3. This notice may not be removed or altered from any source distribution.
+
+***********************************************************************/
+
+/********************************************************************
+	created:	2006-01-28
+	filename: 	tokenizer.cpp
+	author:		J�rg Wiedenmann
+
+	purpose:	A tokenizer function which provides a very
+				customizable way of breaking up strings.
+*********************************************************************/
+
+#include <vector>
+#include <string>
+using namespace std;
+
+// Function to break up a string into tokens
+//
+// Parameters:
+//-----------
+// str = the input string that will be tokenized
+// result = the tokens for str
+// delimiters = the delimiter characters
+// delimiters preserve = same as above, but the delimiter characters
+//		will be put into the result as a token
+// quote = characters to protect the enclosed characters
+// esc = characters to protect a single character
+//
+
+void tokenize ( const string& str, vector<string>& result,
+			const string& delimiters, const string& delimiters_preserve = "",
+			const string& quote = "\"", const string& esc = "\\" );

http://git-wip-us.apache.org/repos/asf/cordova-plugman/blob/a65d10ed/spec/plugins/cordova.echo/src/blackberry10/native/simulator/echoJnext.so
----------------------------------------------------------------------
diff --git a/spec/plugins/cordova.echo/src/blackberry10/native/simulator/echoJnext.so b/spec/plugins/cordova.echo/src/blackberry10/native/simulator/echoJnext.so
new file mode 100644
index 0000000..2b3c5f5
Binary files /dev/null and b/spec/plugins/cordova.echo/src/blackberry10/native/simulator/echoJnext.so differ

http://git-wip-us.apache.org/repos/asf/cordova-plugman/blob/a65d10ed/spec/plugins/cordova.echo/src/blackberry10/native/src/echo.cpp
----------------------------------------------------------------------
diff --git a/spec/plugins/cordova.echo/src/blackberry10/native/src/echo.cpp b/spec/plugins/cordova.echo/src/blackberry10/native/src/echo.cpp
new file mode 100644
index 0000000..0d5cc2f
--- /dev/null
+++ b/spec/plugins/cordova.echo/src/blackberry10/native/src/echo.cpp
@@ -0,0 +1,121 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+*/
+
+
+#include <../public/json/reader.h>
+#include <string>
+#include <sstream>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include "echo.hpp"
+
+using namespace std;
+
+/**
+ * Default constructor.
+ */
+Echo::Echo(const std::string& id) : m_id(id) {
+}
+
+/**
+ * Memory destructor.
+ */
+Echo::~Echo() {
+}
+
+/**
+ * This method returns the list of objects implemented by this native
+ * extension.
+ */
+char* onGetObjList() {
+    static char name[] = "Echo";
+    return name;
+}
+
+/**
+ * This method is used by JNext to instantiate the Memory object when
+ * an object is created on the JavaScript server side.
+ */
+JSExt* onCreateObject(const string& className, const string& id) {
+    if (className == "Echo") {
+        return new Echo(id);
+    }
+
+    return NULL;
+}
+
+/**
+ * Method used by JNext to determine if the object can be deleted.
+ */
+bool Echo::CanDelete() {
+    return true;
+}
+
+/**
+ * It will be called from JNext JavaScript side with passed string.
+ * This method implements the interface for the JavaScript to native binding
+ * for invoking native code. This method is triggered when JNext.invoke is
+ * called on the JavaScript side with this native objects id.
+ */
+string Echo::InvokeMethod(const string& command) {
+    int index = command.find_first_of(" ");
+    std::string method = command.substr(0, index);
+    
+    // read in arguments
+    Json::Value obj;
+    if (static_cast<int>(command.length()) > index && index != -1) {
+        std::string jsonObject = command.substr(index + 1, command.length());
+        Json::Reader reader;
+
+        bool parse = reader.parse(jsonObject, obj);
+        if (!parse) {
+            fprintf(stderr, "%s", "error parsing\n");
+            return "Cannot parse JSON object";
+        }
+    }    
+    
+    // Determine which function should be executed
+    if (method == "doEcho") {
+        std::string message = obj["message"].asString();
+        if(message.length() > 0) {
+            return doEcho(message);
+        }else{
+             return doEcho("Nothing to echo.");
+        }
+    }else{
+        return doEcho("Unsupported Method");
+    }
+}
+
+/**
+ * Method that sends off Event message
+ */
+string Echo::doEcho(const std::string& message) {
+    std::string eventString = m_id;
+    eventString.append(" ");
+    eventString.append("cordova.echo.callback");
+    eventString.append(" ");
+    eventString.append(message);
+    SendPluginEvent(eventString.c_str(), m_pContext);
+    return eventString;
+}

http://git-wip-us.apache.org/repos/asf/cordova-plugman/blob/a65d10ed/spec/plugins/cordova.echo/src/blackberry10/native/src/echo.hpp
----------------------------------------------------------------------
diff --git a/spec/plugins/cordova.echo/src/blackberry10/native/src/echo.hpp b/spec/plugins/cordova.echo/src/blackberry10/native/src/echo.hpp
new file mode 100644
index 0000000..408be69
--- /dev/null
+++ b/spec/plugins/cordova.echo/src/blackberry10/native/src/echo.hpp
@@ -0,0 +1,45 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+*/
+
+#ifndef ECHO_HPP_
+#define ECHO_HPP_
+
+#include <string>
+#include <pthread.h>
+#include "../public/plugin.h"
+
+class Echo: public JSExt {
+
+public:
+    explicit Echo(const std::string& id);
+    virtual ~Echo();
+
+// Interfaces of JSExt
+    virtual bool CanDelete();
+    virtual std::string InvokeMethod(const std::string& command);
+
+private:
+    std::string doEcho(const std::string& message);
+
+    std::string m_id;
+};
+
+#endif /* ECHO_HPP_ */

http://git-wip-us.apache.org/repos/asf/cordova-plugman/blob/a65d10ed/spec/plugins/cordova.echo/src/device/echoJnext.so
----------------------------------------------------------------------
diff --git a/spec/plugins/cordova.echo/src/device/echoJnext.so b/spec/plugins/cordova.echo/src/device/echoJnext.so
deleted file mode 100755
index 169714a..0000000
Binary files a/spec/plugins/cordova.echo/src/device/echoJnext.so and /dev/null differ

http://git-wip-us.apache.org/repos/asf/cordova-plugman/blob/a65d10ed/spec/plugins/cordova.echo/src/simulator/echoJnext.so
----------------------------------------------------------------------
diff --git a/spec/plugins/cordova.echo/src/simulator/echoJnext.so b/spec/plugins/cordova.echo/src/simulator/echoJnext.so
deleted file mode 100644
index 2b3c5f5..0000000
Binary files a/spec/plugins/cordova.echo/src/simulator/echoJnext.so and /dev/null differ

http://git-wip-us.apache.org/repos/asf/cordova-plugman/blob/a65d10ed/spec/plugins/cordova.echo/www/client.js
----------------------------------------------------------------------
diff --git a/spec/plugins/cordova.echo/www/client.js b/spec/plugins/cordova.echo/www/client.js
new file mode 100644
index 0000000..4e7a1b3
--- /dev/null
+++ b/spec/plugins/cordova.echo/www/client.js
@@ -0,0 +1,53 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+*/
+
+var _self = {},
+    _ID = require("./manifest.json").namespace,
+    win = null,
+    fail = null;
+
+function handleCallback(result) {
+    if (result) {
+        if(win){
+            win(result);
+        }
+    } else {
+        if(fail){
+            fail(result);
+        }
+    }
+    win = null;
+    fail = null;
+}
+
+_self.doEcho = function (args, theWin, theFail) {
+    var data = { "message" : args.message || "" };
+    
+    win = theWin;
+    fail = theFail;
+    
+    window.webworks.event.add(_ID, "echoCallback", handleCallback);
+    
+    return window.webworks.execSync(_ID, "doEcho", data);
+};
+
+
+module.exports = _self;

http://git-wip-us.apache.org/repos/asf/cordova-plugman/blob/a65d10ed/spec/projects/blackberry/www/config.xml
----------------------------------------------------------------------
diff --git a/spec/projects/blackberry/www/config.xml b/spec/projects/blackberry/www/config.xml
deleted file mode 100644
index 6b132c2..0000000
--- a/spec/projects/blackberry/www/config.xml
+++ /dev/null
@@ -1,97 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- 
-       Licensed to the Apache Software Foundation (ASF) under one
-       or more contributor license agreements.  See the NOTICE file
-       distributed with this work for additional information
-       regarding copyright ownership.  The ASF licenses this file
-       to you under the Apache License, Version 2.0 (the
-       "License"); you may not use this file except in compliance
-       with the License.  You may obtain a copy of the License at
-
-         http://www.apache.org/licenses/LICENSE-2.0
-
-       Unless required by applicable law or agreed to in writing,
-       software distributed under the License is distributed on an
-       "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-       KIND, either express or implied.  See the License for the
-       specific language governing permissions and limitations
-       under the License.
--->
-<!--
-  Widget Configuration Reference:
-    http://docs.blackberry.com/en/developers/deliverables/15274/
--->
-
-<widget xmlns="http://www.w3.org/ns/widgets"
-        xmlns:rim="http://www.blackberry.com/ns/widgets"
-	version="1.0.0.0" id="cordovaExample">
-
-  <name>cordovaExample</name>
-
-  <author>Your Name Here</author>
-
-  <description>
-       A sample Apache Cordova application that responds to the deviceready event.
-  </description>
-    
-  <license href="http://opensource.org/licenses/alphabetical">
-  </license>
-
-  <!-- Cordova API -->
-  <feature id="blackberry.system" required="true" version="1.0.0.0" />
-  <feature id="org.apache.cordova" required="true" version="1.0.0" />
-  <feature id="blackberry.find" required="true" version="1.0.0.0" />
-  <feature id="blackberry.identity" required="true" version="1.0.0.0" />
-  <feature id="blackberry.identity.phone" required="true" version="1.0.0.0" />
-  <feature id="blackberry.pim.Address" required="true" version="1.0.0.0" />
-  <feature id="blackberry.pim.Contact" required="true" version="1.0.0.0" />
-  <feature id="blackberry.io.file" required="true" version="1.0.0.0" />
-  <feature id="blackberry.utils" required="true" version="1.0.0.0" />
-  <feature id="blackberry.io.dir" required="true" version="1.0.0.0" />
-  <feature id="blackberry.app" required="true" version="1.0.0.0" />
-  <feature id="blackberry.app.event" required="true" version="1.0.0.0" />
-  <feature id="blackberry.system.event" required="true" version="1.0.0.0"/>
-  <feature id="blackberry.widgetcache" required="true" version="1.0.0.0"/>
-  <feature id="blackberry.media.camera" />
-  <feature id="blackberry.ui.dialog" />
-  <feature id="blackberry.connection" />
-  <feature id="blackberry.bbm.platform" />
-  <feature id="blackberry.invoke.card" />
-  <feature id="blackberry.pim.contacts" />
-  <feature id="blackberry.ui.contextmenu" />
-  <feature id="blackberry.io.filetransfer" />
-  <feature id="blackberry.io" />
-  <feature id="blackberry.invoke" />
-  <feature id="blackberry.invoked" />
-  <feature id="blackberry.push" />
-  <feature id="blackberry.media.microphone" required="true" version="1.0.0.0"/>
-  
-  <!-- Cordova API -->
-  <access subdomains="true" uri="file:///store/home" />
-  <access subdomains="true" uri="file:///SDCard" />
-
-  <!-- Expose access to all URIs, including the file and http protocols -->
-  <access subdomains="true" uri="*" />
-
-  
-  <icon rim:hover="false" src="res/icon/blackberry/icon-80.png" />
-  <icon rim:hover="true" src="res/icon/blackberry/icon-80.png" />
-
-  <rim:loadingScreen backgroundColor="#CFCFCF"
-                     foregroundImage="res/screen/blackberry/screen-225.png"
-		     onFirstLaunch="true">
-    <rim:transitionEffect type="fadeOut" />
-  </rim:loadingScreen>
-
-  <content src="index.html" />
-
-  <rim:permissions>
-    <rim:permit>use_camera</rim:permit>
-    <rim:permit>read_device_identifying_information</rim:permit>
-    <rim:permit>access_shared</rim:permit>
-    <rim:permit>read_geolocation</rim:permit>
-    <rim:permit>record_audio</rim:permit> 
-    <rim:permit>access_pimdomain_contacts</rim:permit> 
-  </rim:permissions>
-
-</widget>

http://git-wip-us.apache.org/repos/asf/cordova-plugman/blob/a65d10ed/spec/projects/blackberry/www/plugins.xml
----------------------------------------------------------------------
diff --git a/spec/projects/blackberry/www/plugins.xml b/spec/projects/blackberry/www/plugins.xml
deleted file mode 100644
index 3d41236..0000000
--- a/spec/projects/blackberry/www/plugins.xml
+++ /dev/null
@@ -1,35 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- 
-       Licensed to the Apache Software Foundation (ASF) under one
-       or more contributor license agreements.  See the NOTICE file
-       distributed with this work for additional information
-       regarding copyright ownership.  The ASF licenses this file
-       to you under the Apache License, Version 2.0 (the
-       "License"); you may not use this file except in compliance
-       with the License.  You may obtain a copy of the License at
-
-         http://www.apache.org/licenses/LICENSE-2.0
-
-       Unless required by applicable law or agreed to in writing,
-       software distributed under the License is distributed on an
-       "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-       KIND, either express or implied.  See the License for the
-       specific language governing permissions and limitations
-       under the License.
--->
-<plugins>
-  <plugin name="App"            value="org.apache.cordova.app.App"/>
-  <plugin name="Device"         value="org.apache.cordova.device.Device"/>
-  <plugin name="Camera"         value="org.apache.cordova.camera.Camera"/>
-  <plugin name="NetworkStatus"  value="org.apache.cordova.network.Network"/>
-  <plugin name="Notification"   value="org.apache.cordova.notification.Notification"/>
-  <plugin name="Accelerometer"  value="org.apache.cordova.accelerometer.Accelerometer"/>
-  <plugin name="Geolocation"    value="org.apache.cordova.geolocation.Geolocation"/>
-  <plugin name="File"           value="org.apache.cordova.file.FileManager"/>
-  <plugin name="FileTransfer"   value="org.apache.cordova.http.FileTransfer"/>
-  <plugin name="Contacts"       value="org.apache.cordova.pim.Contact"/>
-  <plugin name="Capture"        value="org.apache.cordova.capture.MediaCapture"/>
-  <plugin name="Battery"        value="org.apache.cordova.battery.Battery"/>
-  <plugin name="Media"          value="org.apache.cordova.media.Media"/>
-  <plugin name="Globalization"  value="org.apache.cordova.globalization.Globalization"/>
-</plugins>

http://git-wip-us.apache.org/repos/asf/cordova-plugman/blob/a65d10ed/spec/projects/blackberry10/www/config.xml
----------------------------------------------------------------------
diff --git a/spec/projects/blackberry10/www/config.xml b/spec/projects/blackberry10/www/config.xml
new file mode 100644
index 0000000..6b132c2
--- /dev/null
+++ b/spec/projects/blackberry10/www/config.xml
@@ -0,0 +1,97 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+       Licensed to the Apache Software Foundation (ASF) under one
+       or more contributor license agreements.  See the NOTICE file
+       distributed with this work for additional information
+       regarding copyright ownership.  The ASF licenses this file
+       to you under the Apache License, Version 2.0 (the
+       "License"); you may not use this file except in compliance
+       with the License.  You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+       Unless required by applicable law or agreed to in writing,
+       software distributed under the License is distributed on an
+       "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+       KIND, either express or implied.  See the License for the
+       specific language governing permissions and limitations
+       under the License.
+-->
+<!--
+  Widget Configuration Reference:
+    http://docs.blackberry.com/en/developers/deliverables/15274/
+-->
+
+<widget xmlns="http://www.w3.org/ns/widgets"
+        xmlns:rim="http://www.blackberry.com/ns/widgets"
+	version="1.0.0.0" id="cordovaExample">
+
+  <name>cordovaExample</name>
+
+  <author>Your Name Here</author>
+
+  <description>
+       A sample Apache Cordova application that responds to the deviceready event.
+  </description>
+    
+  <license href="http://opensource.org/licenses/alphabetical">
+  </license>
+
+  <!-- Cordova API -->
+  <feature id="blackberry.system" required="true" version="1.0.0.0" />
+  <feature id="org.apache.cordova" required="true" version="1.0.0" />
+  <feature id="blackberry.find" required="true" version="1.0.0.0" />
+  <feature id="blackberry.identity" required="true" version="1.0.0.0" />
+  <feature id="blackberry.identity.phone" required="true" version="1.0.0.0" />
+  <feature id="blackberry.pim.Address" required="true" version="1.0.0.0" />
+  <feature id="blackberry.pim.Contact" required="true" version="1.0.0.0" />
+  <feature id="blackberry.io.file" required="true" version="1.0.0.0" />
+  <feature id="blackberry.utils" required="true" version="1.0.0.0" />
+  <feature id="blackberry.io.dir" required="true" version="1.0.0.0" />
+  <feature id="blackberry.app" required="true" version="1.0.0.0" />
+  <feature id="blackberry.app.event" required="true" version="1.0.0.0" />
+  <feature id="blackberry.system.event" required="true" version="1.0.0.0"/>
+  <feature id="blackberry.widgetcache" required="true" version="1.0.0.0"/>
+  <feature id="blackberry.media.camera" />
+  <feature id="blackberry.ui.dialog" />
+  <feature id="blackberry.connection" />
+  <feature id="blackberry.bbm.platform" />
+  <feature id="blackberry.invoke.card" />
+  <feature id="blackberry.pim.contacts" />
+  <feature id="blackberry.ui.contextmenu" />
+  <feature id="blackberry.io.filetransfer" />
+  <feature id="blackberry.io" />
+  <feature id="blackberry.invoke" />
+  <feature id="blackberry.invoked" />
+  <feature id="blackberry.push" />
+  <feature id="blackberry.media.microphone" required="true" version="1.0.0.0"/>
+  
+  <!-- Cordova API -->
+  <access subdomains="true" uri="file:///store/home" />
+  <access subdomains="true" uri="file:///SDCard" />
+
+  <!-- Expose access to all URIs, including the file and http protocols -->
+  <access subdomains="true" uri="*" />
+
+  
+  <icon rim:hover="false" src="res/icon/blackberry/icon-80.png" />
+  <icon rim:hover="true" src="res/icon/blackberry/icon-80.png" />
+
+  <rim:loadingScreen backgroundColor="#CFCFCF"
+                     foregroundImage="res/screen/blackberry/screen-225.png"
+		     onFirstLaunch="true">
+    <rim:transitionEffect type="fadeOut" />
+  </rim:loadingScreen>
+
+  <content src="index.html" />
+
+  <rim:permissions>
+    <rim:permit>use_camera</rim:permit>
+    <rim:permit>read_device_identifying_information</rim:permit>
+    <rim:permit>access_shared</rim:permit>
+    <rim:permit>read_geolocation</rim:permit>
+    <rim:permit>record_audio</rim:permit> 
+    <rim:permit>access_pimdomain_contacts</rim:permit> 
+  </rim:permissions>
+
+</widget>

http://git-wip-us.apache.org/repos/asf/cordova-plugman/blob/a65d10ed/spec/uninstall.spec.js
----------------------------------------------------------------------
diff --git a/spec/uninstall.spec.js b/spec/uninstall.spec.js
index c912321..278beb8 100644
--- a/spec/uninstall.spec.js
+++ b/spec/uninstall.spec.js
@@ -2,7 +2,7 @@ var uninstall = require('../src/uninstall'),
     install = require('../src/install'),
     android = require('../src/platforms/android'),
     ios     = require('../src/platforms/ios'),
-    blackberry = require('../src/platforms/blackberry'),
+    blackberry10 = require('../src/platforms/blackberry10'),
     plugman = require('../plugman'),
     fs      = require('fs'),
     os      = require('osenv'),
@@ -14,7 +14,7 @@ var uninstall = require('../src/uninstall'),
     variableplugin = path.join(__dirname, 'plugins', 'VariablePlugin'),
     faultyplugin = path.join(__dirname, 'plugins', 'FaultyPlugin'),
     android_one_project = path.join(__dirname, 'projects', 'android_one', '*');
-    blackberry_project = path.join(__dirname, 'projects', 'blackberry', '*');
+    blackberry10_project = path.join(__dirname, 'projects', 'blackberry10', '*');
     ios_project = path.join(__dirname, 'projects', 'ios-config-xml', '*');
     plugins_dir = path.join(temp, 'cordova', 'plugins');
 
@@ -48,6 +48,6 @@ describe('uninstall', function() {
                 uninstall('android', temp, 'SomePlugin', plugins_dir, {});
             }).toThrow('Plugin "SomePlugin" not found. Already uninstalled?');
         });
-        it('should handle a failed uninstall by passing completed transactions into appropriate handler\'s uninstall method'); 
+        it('should handle a failed uninstall by passing completed transactions into appropriate handler\'s uninstall method');
     });
 });

http://git-wip-us.apache.org/repos/asf/cordova-plugman/blob/a65d10ed/src/platforms.js
----------------------------------------------------------------------
diff --git a/src/platforms.js b/src/platforms.js
index 3171ee5..6fe4528 100644
--- a/src/platforms.js
+++ b/src/platforms.js
@@ -1,7 +1,7 @@
 module.exports = {
     'android': require('./platforms/android'),
     'ios': require('./platforms/ios'),
-    'blackberry': require('./platforms/blackberry'),
+    'blackberry10': require('./platforms/blackberry10'),
     'wp7': require('./platforms/wp7'),
     'wp8': require('./platforms/wp8')
 };

http://git-wip-us.apache.org/repos/asf/cordova-plugman/blob/a65d10ed/src/platforms/blackberry.js
----------------------------------------------------------------------
diff --git a/src/platforms/blackberry.js b/src/platforms/blackberry.js
deleted file mode 100644
index 029378a..0000000
--- a/src/platforms/blackberry.js
+++ /dev/null
@@ -1,101 +0,0 @@
-/*
- *
- * Copyright 2013 Anis Kadri
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
-*/
-
-var fs = require('fs')  // use existsSync in 0.6.x
-   , path = require('path')
-   , shell = require('shelljs')
-   , et = require('elementtree')
-   , getConfigChanges = require('../util/config-changes')
-   , common = require('./common')
-   , xml_helpers = require(path.join(__dirname, '..', 'util', 'xml-helpers'));
-
-module.exports = {
-    install:function(transactions, plugin_id, project_dir, plugin_dir, variables, callback) {
-        handlePlugin('install', plugin_id, transactions, project_dir, plugin_dir, variables, callback);
-    },
-    uninstall:function(transactions, plugin_id, project_dir, plugin_dir, callback) {
-        handlePlugin('uninstall', plugin_id, transactions, project_dir, plugin_dir, null, callback);
-    },
-    www_dir:function(project_dir) {
-        return path.join(project_dir, 'www');
-    }
-};
-
-function handlePlugin(action, plugin_id, txs, project_dir, plugin_dir, variables, callback) {
-    var completed = [];
-    while(txs.length) {
-        var mod = txs.shift();
-        try {
-            switch(mod.tag.toLowerCase()) {
-                case 'source-file':
-                    var destFile = path.join(mod.attrib['target-dir'], path.basename(mod.attrib['src']));
-
-                    if (action == 'install') {
-                        common.straightCopy(plugin_dir, mod.attrib['src'], project_dir, destFile);
-                    } else {
-                        common.deleteJava(project_dir, destFile);
-                    }
-                    break;
-                case 'config-file':
-                    // Only modify config files that exist.
-                    var config_file = path.resolve(project_dir, mod.attrib['target']);
-                    if (fs.existsSync(config_file)) {
-                        var xmlDoc = xml_helpers.parseElementtreeSync(config_file);
-                        var selector = mod.attrib["parent"];
-                        var children = mod.findall('*');
-
-                        if (action == 'install') {
-                            if (!xml_helpers.graftXML(xmlDoc, children, selector)) {
-                                throw new Error('failed to add config-file children to "' + filename + '"');
-                            }
-                        } else {
-                            if (!xml_helpers.pruneXML(xmlDoc, children, selector)) {
-                                throw new Error('failed to remove config-file children from "' + filename + '"');
-                            }
-                        }
-
-                        var output = xmlDoc.write({indent: 4});
-                        fs.writeFileSync(config_file, output);
-                    }
-                    break;
-                case 'asset':
-                    if (action == 'uninstall') {
-                        var target = mod.attrib.target;
-                        shell.rm('-rf', path.resolve(module.exports.www_dir(project_dir), target));
-                        shell.rm('-rf', path.resolve(module.exports.www_dir(project_dir), 'plugins', plugin_id));
-                    }
-                    break;
-                default:
-                    throw new Error('Unrecognized plugin.xml element/action in blackberry installer: ' + mod.tag);
-                    break;
-            }
-        } catch(e) {
-            // propagate error up and provide completed tx log
-            e.transactions = {
-                executed:completed,
-                incomplete:txs.unshift(mod)
-            };
-            if (callback) callback(e);
-            else throw e;
-            return;
-        }
-        completed.push(mod);
-    }
-    if (callback) callback();
-}

http://git-wip-us.apache.org/repos/asf/cordova-plugman/blob/a65d10ed/src/platforms/blackberry10.js
----------------------------------------------------------------------
diff --git a/src/platforms/blackberry10.js b/src/platforms/blackberry10.js
new file mode 100644
index 0000000..8a74968
--- /dev/null
+++ b/src/platforms/blackberry10.js
@@ -0,0 +1,91 @@
+/*
+ *
+ * Copyright 2013 Anis Kadri
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+*/
+
+var fs = require('fs')  // use existsSync in 0.6.x
+   , path = require('path')
+   , shell = require('shelljs')
+   , et = require('elementtree')
+   , getConfigChanges = require('../util/config-changes')
+   , common = require('./common')
+   , xml_helpers = require(path.join(__dirname, '..', 'util', 'xml-helpers'));
+
+module.exports = {
+    install:function(transactions, plugin_id, project_dir, plugin_dir, variables, callback) {
+        handlePlugin('install', plugin_id, transactions, project_dir, plugin_dir, variables, callback);
+    },
+    uninstall:function(transactions, plugin_id, project_dir, plugin_dir, callback) {
+        handlePlugin('uninstall', plugin_id, transactions, project_dir, plugin_dir, null, callback);
+    },
+    www_dir:function(project_dir) {
+        return path.join(project_dir, 'www');
+    }
+};
+
+function handlePlugin(action, plugin_id, txs, project_dir, plugin_dir, variables, callback) {
+    var completed = [];
+    while(txs.length) {
+        var mod = txs.shift();
+        try {
+            switch(mod.tag.toLowerCase()) {
+                case 'config-file':
+                    // Only modify config files that exist.
+                    var config_file = path.resolve(project_dir, mod.attrib['target']);
+                    if (fs.existsSync(config_file)) {
+                        var xmlDoc = xml_helpers.parseElementtreeSync(config_file);
+                        var selector = mod.attrib["parent"];
+                        var children = mod.findall('*');
+
+                        if (action == 'install') {
+                            if (!xml_helpers.graftXML(xmlDoc, children, selector)) {
+                                throw new Error('failed to add config-file children to "' + filename + '"');
+                            }
+                        } else {
+                            if (!xml_helpers.pruneXML(xmlDoc, children, selector)) {
+                                throw new Error('failed to remove config-file children from "' + filename + '"');
+                            }
+                        }
+
+                        var output = xmlDoc.write({indent: 4});
+                        fs.writeFileSync(config_file, output);
+                    }
+                    break;
+                case 'asset':
+                    if (action == 'uninstall') {
+                        var target = mod.attrib.target;
+                        shell.rm('-rf', path.resolve(module.exports.www_dir(project_dir), target));
+                        shell.rm('-rf', path.resolve(module.exports.www_dir(project_dir), 'plugins', plugin_id));
+                    }
+                    break;
+                default:
+                    throw new Error('Unrecognized plugin.xml element/action in blackberry10 installer: ' + mod.tag);
+            }
+        } catch(e) {
+            // propagate error up and provide completed tx log
+            e.transactions = {
+                executed:completed,
+                incomplete:txs.unshift(mod)
+            };
+            if (callback) callback(e);
+            else throw e;
+            return;
+        }
+        completed.push(mod);
+    }
+    if (callback) callback();
+}

http://git-wip-us.apache.org/repos/asf/cordova-plugman/blob/a65d10ed/test/blackberry-install.js
----------------------------------------------------------------------
diff --git a/test/blackberry-install.js b/test/blackberry-install.js
deleted file mode 100644
index fd41098..0000000
--- a/test/blackberry-install.js
+++ /dev/null
@@ -1,105 +0,0 @@
-/*
- *
- * Copyright 2013 Anis Kadri
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
-*/
-
-var fs = require('fs')
-  , path = require('path')
-  , shell = require('shelljs')
-  , et = require('elementtree')
-  , osenv = require('osenv')
-  , blackberry = require(path.join(__dirname, '..', 'platforms', 'blackberry'))
-  , plugin_loader = require('../util/plugin_loader')
-  , test_dir = path.join(osenv.tmpdir(), 'test_plugman')
-  , test_project_dir = path.join(test_dir, 'projects', 'blackberry', 'www')
-  , test_plugin_dir = path.join(test_dir, 'plugins', 'cordova.echo')
-  , xml_path     = path.join(test_dir, 'plugins', 'cordova.echo', 'plugin.xml')
-  , xml_text, plugin_et
-  , plugman = require('../plugman')
-  , plugins_dir = path.join(test_dir, 'plugins')
-  , silent = require('../util/test-helpers').suppressOutput
-  , srcDir = path.resolve(test_project_dir, 'ext-qnx/cordova.echo');
-
-exports.setUp = function(callback) {
-    shell.mkdir('-p', test_dir);
-    
-    // copy the blackberry test project to a temp directory
-    shell.cp('-r', path.join(__dirname, 'projects'), test_dir);
-
-    // copy the blackberry test plugin to a temp directory
-    shell.cp('-r', path.join(__dirname, 'plugins'), test_dir);
-
-    // parse the plugin.xml into an elementtree object
-    xml_text   = fs.readFileSync(xml_path, 'utf-8')
-    plugin_et  = new et.ElementTree(et.XML(xml_text));
-
-    callback();
-}
-
-exports.tearDown = function(callback) {
-    // remove the temp files (projects and plugins)
-    shell.rm('-rf', test_dir);
-    callback();
-}
-
-exports['should move the source files'] = function (test) {
-    // run the platform-specific function
-    silent(function() {
-        plugman.handlePlugin('install', 'blackberry', test_project_dir, 'cordova.echo', plugins_dir);
-    });
-
-    test.ok(fs.existsSync(srcDir + '/client.js'));
-    test.ok(fs.existsSync(srcDir + '/index.js'));
-    test.ok(fs.existsSync(srcDir + '/manifest.json'));
-    test.ok(fs.existsSync(srcDir + '/device/echoJnext.so'));
-    test.ok(fs.existsSync(srcDir + '/simulator/echoJnext.so'));
-    test.done();
-};
-
-exports['should move the js file'] = function (test) {
-    // run the platform-specific function
-    silent(function() {
-        plugman.handlePlugin('install', 'blackberry', test_project_dir, 'DummyPlugin', plugins_dir);
-    });
-
-    var jsPath = path.join(test_project_dir, 'www', 'dummyplugin.js');
-    test.ok(fs.existsSync(jsPath));
-    test.done();
-}
-
-exports['should edit config.xml'] = function (test) {
-    silent(function() {
-        plugman.handlePlugin('install', 'blackberry', test_project_dir, 'cordova.echo', plugins_dir);
-    });
-
-    var configXmlPath = path.join(test_project_dir, 'config.xml');
-    var pluginsTxt = fs.readFileSync(configXmlPath, 'utf-8'),
-        pluginsDoc = new et.ElementTree(et.XML(pluginsTxt)),
-        expected = 'feature[@id="cordova.echo"]';
-    test.ok(pluginsDoc.find(expected));
-
-    test.done();
-}
-
-exports['should not install a plugin that is already installed'] = function (test) {
-    blackberry.handlePlugin('install', test_project_dir, test_plugin_dir, plugin_et);
-
-    test.throws(function(){blackberry.handlePlugin('install', test_project_dir, test_plugin_dir, plugin_et); }, 
-                /already installed/
-               );
-    test.done();
-}

http://git-wip-us.apache.org/repos/asf/cordova-plugman/blob/a65d10ed/test/blackberry-uninstall.js
----------------------------------------------------------------------
diff --git a/test/blackberry-uninstall.js b/test/blackberry-uninstall.js
deleted file mode 100644
index 3f76642..0000000
--- a/test/blackberry-uninstall.js
+++ /dev/null
@@ -1,117 +0,0 @@
-/*
- *
- * Copyright 2013 Anis Kadri
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
-*/
-
-var fs = require('fs')
-  , path = require('path')
-  , shell = require('shelljs')
-  , et = require('elementtree')
-  , osenv = require('osenv')
-  , blackberry = require(path.join(__dirname, '..', 'platforms', 'blackberry'))
-  , test_dir = path.join(osenv.tmpdir(), 'test_plugman')
-  , test_project_dir = path.join(test_dir, 'projects', 'blackberry', 'www')
-  , test_plugin_dir = path.join(test_dir, 'plugins', 'cordova.echo')
-  , xml_path     = path.join(test_dir, 'plugins', 'cordova.echo', 'plugin.xml')
-  , xml_text, plugin_et
-  , plugman = require('../plugman')
-  , plugins_dir = path.join(test_dir, 'plugins')
-  , silent = require('../util/test-helpers').suppressOutput
-  , srcDir = path.resolve(test_project_dir, 'ext-qnx/cordova.echo');
-  
-exports.setUp = function(callback) {
-    shell.mkdir('-p', test_dir);
-    
-    // copy the blackberry test project to a temp directory
-    shell.cp('-r', path.join(__dirname, 'projects'), test_dir);
-
-    // copy the blackberry test plugin to a temp directory
-    shell.cp('-r', path.join(__dirname, 'plugins'), test_dir);
-
-    // parse the plugin.xml into an elementtree object
-    xml_text   = fs.readFileSync(xml_path, 'utf-8')
-    plugin_et  = new et.ElementTree(et.XML(xml_text));
-
-    callback();
-}
-
-exports.tearDown = function(callback) {
-    // remove the temp files (projects and plugins)
-    shell.rm('-rf', test_dir);
-    callback();
-}
-
-exports['should remove cordova echo plugin'] = function (test) {
-    // run the platform-specific function
-    silent(function() {
-        plugman.handlePlugin('install', 'blackberry', test_project_dir, 'cordova.echo', plugins_dir);
-        plugman.handlePlugin('uninstall', 'blackberry', test_project_dir, 'cordova.echo', plugins_dir);
-    });
-
-    test.done();
-}
-
-
-exports['should remove the js file'] = function (test) {
-    silent(function() {
-        plugman.handlePlugin('install', 'blackberry', test_project_dir, 'DummyPlugin', plugins_dir);
-        plugman.handlePlugin('uninstall', 'blackberry', test_project_dir, 'DummyPlugin', plugins_dir);
-    });
-
-    var jsPath = path.join(test_dir, 'projects', 'blackberry', 'www', 'dummyplugin.js');
-    test.ok(!fs.existsSync(jsPath))
-    test.done();
-}
-
-
-exports['should remove the source files'] = function (test) {
-    // run the platform-specific function
-    silent(function() {
-        plugman.handlePlugin('install', 'blackberry', test_project_dir, 'cordova.echo', plugins_dir);
-        plugman.handlePlugin('uninstall', 'blackberry', test_project_dir, 'cordova.echo', plugins_dir);
-    });
-
-    test.ok(!fs.existsSync(srcDir + '/index.js'))
-    test.ok(!fs.existsSync(srcDir + '/client.js'))
-    test.ok(!fs.existsSync(srcDir + '/manifest.json'))
-    test.ok(!fs.existsSync(srcDir + '/device/echoJnext.so'))
-    test.ok(!fs.existsSync(srcDir + '/simulator/echoJnext.so'))
-    test.done();
-}
-
-exports['should edit config.xml'] = function (test) {
-    // run the platform-specific function
-    silent(function() {
-        plugman.handlePlugin('install', 'blackberry', test_project_dir, 'cordova.echo', plugins_dir);
-        plugman.handlePlugin('uninstall', 'blackberry', test_project_dir, 'cordova.echo', plugins_dir);
-    });
-
-    var configXmlPath = path.join(test_project_dir, 'config.xml');
-    var pluginsTxt = fs.readFileSync(configXmlPath, 'utf-8'),
-        pluginsDoc = new et.ElementTree(et.XML(pluginsTxt)),
-        expected = 'feature[@id="cordova.echo"]';
-
-    test.ok(!pluginsDoc.find(expected));
-    test.done();
-}
-
-exports['should not uninstall a plugin that is not installed'] = function (test) {
-    test.throws(function(){blackberry.handlePlugin('uninstall', test_project_dir, test_plugin_dir, plugin_et); }, 
-                /not installed/
-               );
-    test.done();
-}

http://git-wip-us.apache.org/repos/asf/cordova-plugman/blob/a65d10ed/test/blackberry10-install.js
----------------------------------------------------------------------
diff --git a/test/blackberry10-install.js b/test/blackberry10-install.js
new file mode 100644
index 0000000..fd41098
--- /dev/null
+++ b/test/blackberry10-install.js
@@ -0,0 +1,105 @@
+/*
+ *
+ * Copyright 2013 Anis Kadri
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+*/
+
+var fs = require('fs')
+  , path = require('path')
+  , shell = require('shelljs')
+  , et = require('elementtree')
+  , osenv = require('osenv')
+  , blackberry = require(path.join(__dirname, '..', 'platforms', 'blackberry'))
+  , plugin_loader = require('../util/plugin_loader')
+  , test_dir = path.join(osenv.tmpdir(), 'test_plugman')
+  , test_project_dir = path.join(test_dir, 'projects', 'blackberry', 'www')
+  , test_plugin_dir = path.join(test_dir, 'plugins', 'cordova.echo')
+  , xml_path     = path.join(test_dir, 'plugins', 'cordova.echo', 'plugin.xml')
+  , xml_text, plugin_et
+  , plugman = require('../plugman')
+  , plugins_dir = path.join(test_dir, 'plugins')
+  , silent = require('../util/test-helpers').suppressOutput
+  , srcDir = path.resolve(test_project_dir, 'ext-qnx/cordova.echo');
+
+exports.setUp = function(callback) {
+    shell.mkdir('-p', test_dir);
+    
+    // copy the blackberry test project to a temp directory
+    shell.cp('-r', path.join(__dirname, 'projects'), test_dir);
+
+    // copy the blackberry test plugin to a temp directory
+    shell.cp('-r', path.join(__dirname, 'plugins'), test_dir);
+
+    // parse the plugin.xml into an elementtree object
+    xml_text   = fs.readFileSync(xml_path, 'utf-8')
+    plugin_et  = new et.ElementTree(et.XML(xml_text));
+
+    callback();
+}
+
+exports.tearDown = function(callback) {
+    // remove the temp files (projects and plugins)
+    shell.rm('-rf', test_dir);
+    callback();
+}
+
+exports['should move the source files'] = function (test) {
+    // run the platform-specific function
+    silent(function() {
+        plugman.handlePlugin('install', 'blackberry', test_project_dir, 'cordova.echo', plugins_dir);
+    });
+
+    test.ok(fs.existsSync(srcDir + '/client.js'));
+    test.ok(fs.existsSync(srcDir + '/index.js'));
+    test.ok(fs.existsSync(srcDir + '/manifest.json'));
+    test.ok(fs.existsSync(srcDir + '/device/echoJnext.so'));
+    test.ok(fs.existsSync(srcDir + '/simulator/echoJnext.so'));
+    test.done();
+};
+
+exports['should move the js file'] = function (test) {
+    // run the platform-specific function
+    silent(function() {
+        plugman.handlePlugin('install', 'blackberry', test_project_dir, 'DummyPlugin', plugins_dir);
+    });
+
+    var jsPath = path.join(test_project_dir, 'www', 'dummyplugin.js');
+    test.ok(fs.existsSync(jsPath));
+    test.done();
+}
+
+exports['should edit config.xml'] = function (test) {
+    silent(function() {
+        plugman.handlePlugin('install', 'blackberry', test_project_dir, 'cordova.echo', plugins_dir);
+    });
+
+    var configXmlPath = path.join(test_project_dir, 'config.xml');
+    var pluginsTxt = fs.readFileSync(configXmlPath, 'utf-8'),
+        pluginsDoc = new et.ElementTree(et.XML(pluginsTxt)),
+        expected = 'feature[@id="cordova.echo"]';
+    test.ok(pluginsDoc.find(expected));
+
+    test.done();
+}
+
+exports['should not install a plugin that is already installed'] = function (test) {
+    blackberry.handlePlugin('install', test_project_dir, test_plugin_dir, plugin_et);
+
+    test.throws(function(){blackberry.handlePlugin('install', test_project_dir, test_plugin_dir, plugin_et); }, 
+                /already installed/
+               );
+    test.done();
+}