I am trying to build an app in android studio that makes mqtt publishes to the broker which is on a Raspberry Pi. This is my the onCreate function of my main layout, but it returns this error and I can't figure out why. I can publish from a command prompt so there is no problem with the broker.
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_bureau_klein);
final String clientId = "Android1";
final String ip = "192.168.1.198:1883";
final MqttAndroidClient client = new MqttAndroidClient(this.getApplicationContext(), ip, clientId);
try {
IMqttToken token = client.connect();
token.setActionCallback(new IMqttActionListener() {
#Override
public void onSuccess(IMqttToken asyncActionToken) {
// We are connected
Log.d("TAG", "onSuccess");
}
#Override
public void onFailure(IMqttToken asyncActionToken, Throwable exception) {
// Something went wrong e.g. connection timeout or firewall problems
Log.d("TAG", "onFailure "+ clientId + " " + ip);
Log.e("MYAPP", "exception", exception);
Log.e("MYAPP", "exception", asyncActionToken.getException());
}
});
} catch (MqttException e) {
e.printStackTrace();
}
Error:
06-14 20:24:36.825 5891-5891/com.david.domotica2 E/MYAPP: exception
java.lang.IllegalArgumentException: 192.168.1.198:1883
at org.eclipse.paho.client.mqttv3.MqttConnectOptions.validateURI(MqttConnectOptions.java:473)
at org.eclipse.paho.client.mqttv3.MqttAsyncClient.<init>(MqttAsyncClient.java:273)
at org.eclipse.paho.android.service.MqttConnection.connect(MqttConnection.java:282)
at org.eclipse.paho.android.service.MqttService.connect(MqttService.java:323)
at org.eclipse.paho.android.service.MqttAndroidClient.doConnect(MqttAndroidClient.java:462)
at org.eclipse.paho.android.service.MqttAndroidClient.access$200(MqttAndroidClient.java:70)
at org.eclipse.paho.android.service.MqttAndroidClient$MyServiceConnection.onServiceConnected(MqttAndroidClient.java:109)
at android.app.LoadedApk$ServiceDispatcher.doConnected(LoadedApk.java:1685)
at android.app.LoadedApk$ServiceDispatcher$RunConnection.run(LoadedApk.java:1714)
at android.os.Handler.handleCallback(Handler.java:789)
at android.os.Handler.dispatchMessage(Handler.java:98)
at android.os.Looper.loop(Looper.java:164)
at android.app.ActivityThread.main(ActivityThread.java:6798)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:240)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:767)
06-14 20:24:36.825 5891-5891/com.david.domotica2 E/MYAPP: exception
What you are passing to the MqttAndroidClient as an IP address should be a full URI.
e.g. you are passing in 192.168.1.198:1883 which is a IP address and a port but is missing a schema (protocol)
In this case you should be passing in tcp://192.168.1.198:1883
Related
Listener
#JmsListener(destination = "${servicebus.entities.acsTopicToListen.entityName}", containerFactory = "topicJmsListenerContainerFactory", subscription = "${servicebus.entities.acsTopicToListen.subscriptionName}")
public void run(byte[] message, Session session) throws Exception {
try {
acsDataHandler.messageProcessor(new String(message));
} catch (Exception ex) {
LOGGER.error("Exception thrown while listening to acsDataTopic...." + ex.getMessage());
exceptionHelper.handleTransformError(INTERNAL_SERVER_ERROR, "Error from AcsDataReceiver listen()",
ACS0001.name(), ex);
}
Configuration
#Bean
public ConnectionFactory schedulerConnectionFactory(ServicebusConnectionProperties serviceBusJMSProperties) {
final String connectionString = serviceBusJMSProperties.getConnectionString();
final String clientId = serviceBusJMSProperties.getTopiClientId();
final int idleTimeout = serviceBusJMSProperties.getIdleTimeout();
final ServiceBusKey serviceBusKey = ConnectionStringResolver.getServiceBusKey(connectionString);
final String host = serviceBusKey.getHost();
final String sasKeyName = serviceBusKey.getSharedAccessKeyName();
final String sasKey = serviceBusKey.getSharedAccessKey();
final String remoteUri = String.format(AMQP_URI_FORMAT, host, idleTimeout);
final JmsConnectionFactory jmsConnectionFactory = new JmsConnectionFactory();
jmsConnectionFactory.setRemoteURI(remoteUri);
jmsConnectionFactory.setClientID(clientId);
jmsConnectionFactory.setUsername(sasKeyName);
jmsConnectionFactory.setPassword(sasKey);
return new CachingConnectionFactory(jmsConnectionFactory);
}
#Bean
public Destination destination() {
return new JmsTopic(destination);
}
#Bean
public JmsTemplate jmsTemplate(ConnectionFactory jmsConnectionFactory, Destination destination) {
final JmsTemplate jmsTemplate = new JmsTemplate();
jmsTemplate.setConnectionFactory(jmsConnectionFactory);
jmsTemplate.setMessageIdEnabled(true);
jmsTemplate.setDefaultDestination(destination);
return jmsTemplate;
}
#Bean
public JmsListenerContainerFactory<?> topicJmsListenerContainerFactory(ConnectionFactory connectionFactory) {
final DefaultJmsListenerContainerFactory jmsListenerContainerFactory = new DefaultJmsListenerContainerFactory();
jmsListenerContainerFactory.setConnectionFactory(connectionFactory);
jmsListenerContainerFactory.setSubscriptionDurable(Boolean.TRUE);
jmsListenerContainerFactory.setSessionAcknowledgeMode(Session.CLIENT_ACKNOWLEDGE);
return jmsListenerContainerFactory;
}
I am using Azure Service Bus Spring Boot Starter to connect the Servicebus Topic/Subscription which is session enabled , But It's unable to connect with the message below :
It is not possible for an entity that requires sessions to create a non-sessionful message receiver.
In Java, the session support works with azure-servicebus library example
QueuesGettingStarted.java by changing queueClient.registerMessageHandler to queueClient.registerSessionHandler and relevant changes.
But in this case please check :
https://github.com/Azure/azure-service-bus/issues/326#issuecomment-573236250
https://github.com/MicrosoftDocs/azure-dev-docs/issues/285#issuecomment-699573311
This question is specific to a lately strange behavior of the Azure mobile Apps Android sdk. Everything was working fine for weeks. Now, my android client app suddenly can't connect to my web app any more. A Toast says "Error while processing request". In Android Studio debugger, I found the exception inside the SDK file MobileServiceConnection.java.
java.io.IOException: stream was reset: PROTOCOL_ERROR
In Azure Portal, my app shows "Healthy" status, but I can see the HTTP errors. Please help.
Following is my code, which was working fine and now throws error.
// Create the Mobile Service Client instance, using the provided mobile app URL.
try {
mClient = new MobileServiceClient(mMobileBackendUrl, activityContext).withFilter(
new ServiceFilter() {
#Override
public ListenableFuture<ServiceFilterResponse> handleRequest(ServiceFilterRequest request, NextServiceFilterCallback nextServiceFilter) {
// Get the request contents
String url = request.getUrl();
String content = request.getContent();
if (url != null) {
Log.d("Request URL:", url);
}
if (content != null) {
Log.d("Request Content:", content);
}
// Execute the next service filter in the chain
ListenableFuture<ServiceFilterResponse> responseFuture = nextServiceFilter.onNext(request);
Futures.addCallback(responseFuture, new FutureCallback<ServiceFilterResponse>() {
#Override
public void onFailure(Throwable exception) {
Log.d("Exception:", exception.getMessage());
}
#Override
public void onSuccess(ServiceFilterResponse response) {
if (response != null && response.getContent() != null) {
Log.d("Response Content:", response.getContent());
}
}
});
return responseFuture;
}
}
);
setAzureClient(mClient);
}catch(MalformedURLException e){
createAndShowDialog(new Exception("There was an error creating the Mobile Service. Verify the URL"), "Error");
}catch(Exception e){
createAndShowDialog("There was an error creating the Mobile Service. "+ e.toString(), "Error");
}
Toast.makeText(context, context.getString(R.string.online_authentication), Toast.LENGTH_SHORT).show();
authenticate();
}
private void authenticate() { // give access only to authenticated users via Google account authentication
HashMap<String, String> parameters = new HashMap<>();
parameters.put("access_type", "offline");//use "Refresh tokens"
//login with the Google provider. This will create a call to onActivityResult() method inside the context Activity, which will then call the onActivityResult() below.
mClient.login(MobileServiceAuthenticationProvider.Google, url_scheme_of_your_app, GOOGLE_LOGIN_REQUEST_CODE, parameters);
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
// When request completes
if (requestCode == 1) {
try {
MobileServiceActivityResult result = mClient.onActivityResult(data);
if (result.isLoggedIn()) {
Toast.makeText(context, context.getString(R.string.azure_auth_login_success) /*+ " " + mClient.getCurrentUser().getUserId()*/, Toast.LENGTH_SHORT).show();
mUserId = mClient.getCurrentUser().getUserId();
} else {//>>>>THIS IS WHERE I AM GETTING THE ERROR
String errorMessage = result.getErrorMessage();
Toast.makeText(context, errorMessage, Toast.LENGTH_SHORT).show();// Error While processing request (it comes form the MobileServiceConnection.java file inside sdk)
}
}catch(Exception e){
Toast.makeText(context, e.toString(), Toast.LENGTH_LONG).show();
}
}
}
I found the answer myself. The error was due to an Azure App Service HTTP2 connection issue. It has nothing to do with the app code. For anyone facing the same problem, here is the solution.
Go to https://resources.azure.com/
Make sure you are in Read/Write mode by clicking in the option to the left of your name.
From the left column, browse to: https://resources.azure.com/subscriptions/yourSubscriptionId/resourceGroups/yourWebAppResourceGroup/providers/Microsoft.Web/sites/yourWebAppName/config/web
Find and Change the property: "http20Enabled": from true to false by clicking EDIT, Update value to “false” and then clicking in Save or PATCH.
I have two different machine. One is configured with IP 192.168.2.100 and the other one with 192.168.2.101.
This is the code of the first verticle :
public class Sender extends AbstractVerticle {
public static void main(String... args) {
// Configuration du cluster manager
Config config = new Config();
config.getNetworkConfig().getJoin().getTcpIpConfig().addMember("192.168.2.101");
VertxOptions options = new VertxOptions();
options.setClusterManager(new HazelcastClusterManager());
options.setClusterHost("192.168.2.100");
options.setClustered(true);
options.setHAEnabled(true);
Vertx.clusteredVertx(options, vertx ->
vertx.result().deployVerticle(Sender.class.getName(), new DeploymentOptions().setHa(true))
);
}
#Override
public void start() throws Exception {
vertx.setPeriodic(5000, id -> {
vertx.eventBus().send("Address", "message",rep->{
System.out.println("response : "+rep.result().body());
});
});
}
}
And this is the code of the second verticle:
package com.vetx.Consumer;
import com.hazelcast.config.Config;
public class Consumer extends AbstractVerticle {
private String name = null;
public Consumer(String name) {
this.name = name;
}
public Consumer(){
}
public static void main(String... args) {
// Configuration du cluster manager
Config config = new Config();
config.getNetworkConfig().getJoin().getTcpIpConfig().addMember("192.168.2.100");
VertxOptions options = new VertxOptions();
options.setClusterManager(new HazelcastClusterManager());
options.setClusterHost("192.168.2.101");
options.setClustered(true);
options.setHAEnabled(true);
Vertx.clusteredVertx(options, vertx ->
vertx.result().deployVerticle(Consumer.class.getName(), new DeploymentOptions().setHa(true))
);
}
#Override
public void start() throws Exception {
vertx.eventBus().consumer("Address", message -> {
System.out.println(" received message: " +message.body());
message.reply("Success");
});
}
}
I try to use the high availability with cluster to implement a consumer to consume a message and a sender to send the message.When a try to kill the sender in order to redeploy verticle after failover, i got the following exception :
SEVERE: Failed to redeploy verticle after failover
java.lang.ClassNotFoundException: com.vetx.Sender.Sender
at java.net.URLClassLoader.findClass(URLClassLoader.java:381)
at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:338)
at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
at io.vertx.core.impl.JavaVerticleFactory.createVerticle(JavaVerticleFactory.java:37)
at io.vertx.core.impl.DeploymentManager.createVerticles(DeploymentManager.java:229)
at io.vertx.core.impl.DeploymentManager.lambda$doDeployVerticle$2(DeploymentManager.java:202)
at io.vertx.core.impl.FutureImpl.setHandler(FutureImpl.java:76)
at io.vertx.core.impl.DeploymentManager.doDeployVerticle(DeploymentManager.java:171)
at io.vertx.core.impl.DeploymentManager.doDeployVerticle(DeploymentManager.java:143)
at io.vertx.core.impl.DeploymentManager.deployVerticle(DeploymentManager.java:131)
at io.vertx.core.impl.HAManager.doDeployVerticle(HAManager.java:281)
at io.vertx.core.impl.HAManager.processFailover(HAManager.java:553)
at io.vertx.core.impl.HAManager.checkFailover(HAManager.java:489)
at io.vertx.core.impl.HAManager.nodeLeft(HAManager.java:309)
at io.vertx.core.impl.HAManager.access$100(HAManager.java:102)
at io.vertx.core.impl.HAManager$1.nodeLeft(HAManager.java:152)
at io.vertx.spi.cluster.hazelcast.HazelcastClusterManager.memberRemoved(HazelcastClusterManager.java:325)
at com.hazelcast.internal.cluster.impl.ClusterServiceImpl.dispatchEvent(ClusterServiceImpl.java:916)
at com.hazelcast.internal.cluster.impl.ClusterServiceImpl.dispatchEvent(ClusterServiceImpl.java:88)
at com.hazelcast.spi.impl.eventservice.impl.LocalEventDispatcher.run(LocalEventDispatcher.java:56)
at com.hazelcast.util.executor.StripedExecutor$Worker.process(StripedExecutor.java:217)
at com.hazelcast.util.executor.StripedExecutor$Worker.run(StripedExecutor.java:200)
Both of the cluster members should have the class com.vetx.Sender.Sender in their classpath since it will be serialized/deserialized on both sides. Seems like one of the members doesn't have it.
Also, did you make sure members can form a cluster of 2? I see your network config has one ip on each host getTcpIpConfig().addMember("192.168.2.101"), best practice is to add all ip's on all hosts i.e. to have an identical network config on all hosts to avoid confusions.
I am trying to connect my android emulator to my host computer with socket connection.
I have a simple Java server running and lessening in the host on port 6789.
I have the following code:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// Declares streamText to refer to text area to show all messages
TextView streamText = ((TextView) findViewById(R.id.streamText));
streamText.setText("");
streamText.append("Attempting connection at " + serverIP + " : 6789 \n");
try {
connection = new Socket(InetAddress.getByName(serverIP), 6789); // WHAT IP to connect to host, not virtual device host
streamText.append("Connected to: " + connection.getInetAddress().getHostAddress());
}catch(IOException Exception){
streamText.append(Exception.toString());
Exception.printStackTrace();
}
}
And i am getting this error on logcat:
02-05 11:46:52.257 2663-2663/net.ruiruivo.myfirstapp.chatclientv1 E/AndroidRuntime﹕ FATAL EXCEPTION: main
Process: net.ruiruivo.myfirstapp.chatclientv1, PID: 2663
java.lang.RuntimeException: Unable to instantiate activity ComponentInfo{net.ruiruivo.myfirstapp.chatclientv1/net.ruiruivo.myfirstapp.chatclientv1.MainActivity}: java.lang.NullPointerException: Attempt to invoke virtual method 'android.view.View android.view.Window.findViewById(int)' on a null object reference
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2209)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2360)
at android.app.ActivityThread.access$800(ActivityThread.java:144)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1278)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:135)
at android.app.ActivityThread.main(ActivityThread.java:5221)
at java.lang.reflect.Method.invoke(Native Method)
at java.lang.reflect.Method.invoke(Method.java:372)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:899)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:694)
Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'android.view.View android.view.Window.findViewById(int)' on a null object reference
at android.app.Activity.findViewById(Activity.java:2071)
at net.ruiruivo.myfirstapp.chatclientv1.MainActivity.<init>(MainActivity.java:33)
at java.lang.reflect.Constructor.newInstance(Native Method)
at java.lang.Class.newInstance(Class.java:1572)
at android.app.Instrumentation.newActivity(Instrumentation.java:1065)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2199)
And inside my textView window the Exception Says:
java.net.SocketException: socket failed: EACCES (Permission denied)
I have search this and other sites, the answered that appeared the closest to this was <permission android:name="android.permission.INTERNET"></permission> in my manifest but did not solved the problem.
Can anyone help?
Your problem is somewhere else.
1.) post your XML file because it seems that you run into a NPE because streamText is null
2.) You can not do network code in the main thread - this will cause a
android.os.NetworkOnMainThreadException
You have to implement a separate task for that, e.g.:
private class NetworkTask extends AsyncTask<Void, Void, Object>{...}
Update:
Here you go:
#Override
protected void onCreate(Bundle savedInstanceState) {
//your code
new NetworkTask().execute();
}
private class NetworkTask extends AsyncTask<Void, Void, Object>{
#Override
protected Object doInBackground(Void... v) {
try {
//do your network stuff here
return "";
}
catch (HttpException e) {
return e;
}
}
// onPostExecute displays the results of the AsyncTask.
#Override
protected void onPostExecute(Object result) {
if(result instanceof String){
//everything was fine
}
else{
if(((HttpException)result).getMessage()!=null){
//exception occured
}
}
}
}
I wanted to debug the Seed() method in my Entity Framework database configuration class when I run Update-Database from the Package Manager Console but didn't know how to do it. I wanted to share the solution with others in case they have the same issue.
Here is similar question with a solution that works really well.
It does NOT require Thread.Sleep.
Just Launches the debugger using this code.
Clipped from the answer
if (!System.Diagnostics.Debugger.IsAttached)
System.Diagnostics.Debugger.Launch();
The way I solved this was to open a new instance of Visual Studio and then open the same solution in this new instance of Visual Studio. I then attached the debugger in this new instance to the old instance (devenv.exe) while running the update-database command. This allowed me to debug the Seed method.
Just to make sure I didn't miss the breakpoint by not attaching in time I added a Thread.Sleep before the breakpoint.
I hope this helps someone.
If you need to get a specific variable's value, a quick hack is to throw an exception:
throw new Exception(variable);
A cleaner solution (I guess this requires EF 6) would IMHO be to call update-database from code:
var configuration = new DbMigrationsConfiguration<TContext>();
var databaseMigrator = new DbMigrator(configuration);
databaseMigrator.Update();
This allows you to debug the Seed method.
You may take this one step further and construct a unit test (or, more precisely, an integration test) that creates an empty test database, applies all EF migrations, runs the Seed method, and drops the test database again:
var configuration = new DbMigrationsConfiguration<TContext>();
Database.Delete("TestDatabaseNameOrConnectionString");
var databaseMigrator = new DbMigrator(configuration);
databaseMigrator.Update();
Database.Delete("TestDatabaseNameOrConnectionString");
But be careful not to run this against your development database!
I know this is an old question, but if all you want is messages, and you don't care to include references to WinForms in your project, I made some simple debug window where I can send Trace events.
For more serious and step-by-step debugging, I'll open another Visual Studio instance, but it's not necessary for simple stuff.
This is the whole code:
SeedApplicationContext.cs
using System;
using System.Data.Entity;
using System.Diagnostics;
using System.Drawing;
using System.Windows.Forms;
namespace Data.Persistence.Migrations.SeedDebug
{
public class SeedApplicationContext<T> : ApplicationContext
where T : DbContext
{
private class SeedTraceListener : TraceListener
{
private readonly SeedApplicationContext<T> _appContext;
public SeedTraceListener(SeedApplicationContext<T> appContext)
{
_appContext = appContext;
}
public override void Write(string message)
{
_appContext.WriteDebugText(message);
}
public override void WriteLine(string message)
{
_appContext.WriteDebugLine(message);
}
}
private Form _debugForm;
private TextBox _debugTextBox;
private TraceListener _traceListener;
private readonly Action<T> _seedAction;
private readonly T _dbcontext;
public Exception Exception { get; private set; }
public bool WaitBeforeExit { get; private set; }
public SeedApplicationContext(Action<T> seedAction, T dbcontext, bool waitBeforeExit = false)
{
_dbcontext = dbcontext;
_seedAction = seedAction;
WaitBeforeExit = waitBeforeExit;
_traceListener = new SeedTraceListener(this);
CreateDebugForm();
MainForm = _debugForm;
Trace.Listeners.Add(_traceListener);
}
private void CreateDebugForm()
{
var textbox = new TextBox {Multiline = true, Dock = DockStyle.Fill, ScrollBars = ScrollBars.Both, WordWrap = false};
var form = new Form {Font = new Font(#"Lucida Console", 8), Text = "Seed Trace"};
form.Controls.Add(tb);
form.Shown += OnFormShown;
_debugForm = form;
_debugTextBox = textbox;
}
private void OnFormShown(object sender, EventArgs eventArgs)
{
WriteDebugLine("Initializing seed...");
try
{
_seedAction(_dbcontext);
if(!WaitBeforeExit)
_debugForm.Close();
else
WriteDebugLine("Finished seed. Close this window to continue");
}
catch (Exception e)
{
Exception = e;
var einner = e;
while (einner != null)
{
WriteDebugLine(string.Format("[Exception {0}] {1}", einner.GetType(), einner.Message));
WriteDebugLine(einner.StackTrace);
einner = einner.InnerException;
if (einner != null)
WriteDebugLine("------- Inner Exception -------");
}
}
}
protected override void Dispose(bool disposing)
{
if (disposing && _traceListener != null)
{
Trace.Listeners.Remove(_traceListener);
_traceListener.Dispose();
_traceListener = null;
}
base.Dispose(disposing);
}
private void WriteDebugText(string message)
{
_debugTextBox.Text += message;
Application.DoEvents();
}
private void WriteDebugLine(string message)
{
WriteDebugText(message + Environment.NewLine);
}
}
}
And on your standard Configuration.cs
// ...
using System.Windows.Forms;
using Data.Persistence.Migrations.SeedDebug;
// ...
namespace Data.Persistence.Migrations
{
internal sealed class Configuration : DbMigrationsConfiguration<MyContext>
{
public Configuration()
{
// Migrations configuration here
}
protected override void Seed(MyContext context)
{
// Create our application context which will host our debug window and message loop
var appContext = new SeedApplicationContext<MyContext>(SeedInternal, context, false);
Application.Run(appContext);
var e = appContext.Exception;
Application.Exit();
// Rethrow the exception to the package manager console
if (e != null)
throw e;
}
// Our original Seed method, now with Trace support!
private void SeedInternal(MyContext context)
{
// ...
Trace.WriteLine("I'm seeding!")
// ...
}
}
}
Uh Debugging is one thing but don't forget to call:
context.Update()
Also don't wrap in try catch without a good inner exceptions spill to the console.
https://coderwall.com/p/fbcyaw/debug-into-entity-framework-code-first
with catch (DbEntityValidationException ex)
I have 2 workarounds (without Debugger.Launch() since it doesn't work for me):
To print message in Package Manager Console use exception:
throw new Exception("Your message");
Another way is to print message in file by creating a cmd process:
// Logs to file {solution folder}\seed.log data from Seed method (for DEBUG only)
private void Log(string msg)
{
string echoCmd = $"/C echo {DateTime.Now} - {msg} >> seed.log";
System.Diagnostics.Process.Start("cmd.exe", echoCmd);
}