Monday, December 5, 2016

I need a backup plan

In the year of 2016, I was planning to write more code about game development but struggling where could I get start. Well, I start off making the fundamental stuff and end up making a tutorial on game development quick start guide. No! This isn't my objective. I want to make a real person of myself while I'm coding on a game. Somehow in one day, my hard disk failed to boot up and all my hard work effort are gone. The most unlucky thing was I don't have a "real" backup plan, thus restoring my files has turn into nightmare. I spend few months doing the recovery until now, there are still missing parts.

In the past few months while doing my recovery job and also trying my best to recover the code, I started to realize on the disaster recovery plan. I put this at the top and highest priority in my working queue. And I have come up a draft plan for the design. Since my backup files are scattered around in different computers and the external medium, I would need a tool to consolidate all my backup files in one place. And also house keeping the backup files is a must to maintain storage capacity.

The high level design would be something like this: as for now, the backup files are currently scattered around in different computer. There will be relocated to a central storage and I'm pretty sure there must be the same files locate in others PC as well, thus I need to have the central storage setup.

Figure 1: When all PCs come online

After that all files on other computers will be synced up together. Well, that's about the plan. If I want to automate the process, how complicate will it be?

Thursday, March 24, 2016

Why default GL library crash with string declaration on Linux?

How can this simple OpenGL program can throw a segmentation fault?
#include "GL/glew.h"
#include "GL/freeglut.h"
#include <iostream>


std::string a;

int main(int argc, char **argv)
{
   return 0;
}

I don't think this is a joke. Even if I omit the string, the program will still running fine with cout. Am I wrongly setup the IDE? Things were settled until I found this bug report, this could be a serious problem. I run the ldd check and find it there isn't any linkage to pthread.

kokhoe@KOKHOE:~/workspacec/OpenGL1/Debug$ ldd OpenGL1
 linux-vdso.so.1 =>  (0x00007ffe14f5e000)
 libglut.so.3 => /usr/lib/x86_64-linux-gnu/libglut.so.3 (0x00007f9b24659000)
 libGL.so.1 => /usr/lib/nvidia-352/libGL.so.1 (0x00007f9b24329000)
 libstdc++.so.6 => /usr/lib/x86_64-linux-gnu/libstdc++.so.6 (0x00007f9b24025000)
 libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007f9b23e0f000)
 libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f9b23a4a000)
 libX11.so.6 => /usr/lib/x86_64-linux-gnu/libX11.so.6 (0x00007f9b23715000)
 libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007f9b2340f000)
 libXi.so.6 => /usr/lib/x86_64-linux-gnu/libXi.so.6 (0x00007f9b231ff000)
 libXxf86vm.so.1 => /usr/lib/x86_64-linux-gnu/libXxf86vm.so.1 (0x00007f9b22ff9000)
 libnvidia-tls.so.352.63 => /usr/lib/nvidia-352/tls/libnvidia-tls.so.352.63 (0x00007f9b22df6000)
 libnvidia-glcore.so.352.63 => /usr/lib/nvidia-352/libnvidia-glcore.so.352.63 (0x00007f9b20363000)
 libXext.so.6 => /usr/lib/x86_64-linux-gnu/libXext.so.6 (0x00007f9b20151000)
 libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007f9b1ff4d000)
 /lib64/ld-linux-x86-64.so.2 (0x00007f9b248a3000)
 libxcb.so.1 => /usr/lib/x86_64-linux-gnu/libxcb.so.1 (0x00007f9b1fd2e000)
 libXau.so.6 => /usr/lib/x86_64-linux-gnu/libXau.so.6 (0x00007f9b1fb2a000)
 libXdmcp.so.6 => /usr/lib/x86_64-linux-gnu/libXdmcp.so.6 (0x00007f9b1f924000)

But interestingly, I see there is a link with nVidia driver. I then find out there is another libGL did installed in /usr/lib/nvidia-352. If I link my program with this GL library, everything would go fine.

Hmmm... Could it be the permanent workaround for this problem?

Saturday, February 27, 2016

I forget to install NVIDIA driver

What!! The supported OpenGL shader language version is only 1.3? I was shocked when I am first seeing this.

I'm just feeling bored from my daily coding routine, thus thinking to try out something new to get some new inspiration. I grab the piece from learnopengl.com hoping to get some sparkling idea:
const GLchar* vertexShaderSource = "#version 330 core\n"
    "layout (location = 0) in vec3 position;\n"
    "void main()\n"
    "{\n"
    "gl_Position = vec4(position.x, position.y, position.z, 1.0);\n"
    "}\0";

int main(int argc, char **argv)
{
    ...

    GLuint vertexShader = glCreateShader(GL_VERTEX_SHADER);
    glShaderSource(vertexShader, 1, &vertexShaderSource, NULL);
    glCompileShader(vertexShader);
    // Check for compile time errors
    GLint success;
    GLchar infoLog[512];
    glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &success);
    if (!success)
    {
        glGetShaderInfoLog(vertexShader, 512, NULL, infoLog);
        std::cout << "ERROR::SHADER::VERTEX::COMPILATION_FAILED\n" << infoLog << std::endl;
    }

    ...
}

But what's surprising me is that the program failed to run even though I have NVIDIA GT 610 installed. What even surprising me when I issue the following command:
kokhoe@KOKHOE:~$ lspci -vnn | grep -i VGA -A 12
01:00.0 VGA compatible controller [0300]: NVIDIA Corporation GF119 [GeForce GT 610] [10de:104a] (rev a1) (prog-if 00 [VGA controller])
 Subsystem: ASUSTeK Computer Inc. Device [1043:8496]
 Flags: bus master, fast devsel, latency 0, IRQ 45
 Memory at f6000000 (32-bit, non-prefetchable) [size=16M]
 Memory at e8000000 (64-bit, prefetchable) [size=128M]
 Memory at f0000000 (64-bit, prefetchable) [size=32M]
 I/O ports at e000 [size=128]
 Expansion ROM at f7000000 [disabled] [size=512K]
 Capabilities: <access denied="">
 Kernel driver in use: nouveau

01:00.1 Audio device [0403]: NVIDIA Corporation GF119 HDMI Audio Controller [10de:0e08] (rev a1)
 Subsystem: ASUSTeK Computer Inc. Device [1043:8496]

Notice that the Kernel driver in use is showing nouveau?! That means I have not yet install the driver since the first day I got the NVIDIA card. To fix this error, I installed the driver (see here to see how I do the installation), make a final verification:
kokhoe@KOKHOE:~$ lspci -vnn | grep -i VGA -A 12
01:00.0 VGA compatible controller [0300]: NVIDIA Corporation GF119 [GeForce GT 610] [10de:104a] (rev a1) (prog-if 00 [VGA controller])
 Subsystem: ASUSTeK Computer Inc. Device [1043:8496]
 Flags: bus master, fast devsel, latency 0, IRQ 46
 Memory at f6000000 (32-bit, non-prefetchable) [size=16M]
 Memory at e8000000 (64-bit, prefetchable) [size=128M]
 Memory at f0000000 (64-bit, prefetchable) [size=32M]
 I/O ports at e000 [size=128]
 [virtual] Expansion ROM at f7000000 [disabled] [size=512K]
 Capabilities: <access denied="">
 Kernel driver in use: nvidia

01:00.1 Audio device [0403]: NVIDIA Corporation GF119 HDMI Audio Controller [10de:0e08] (rev a1)
 Subsystem: ASUSTeK Computer Inc. Device [1043:8496]

Ah ha~ now it shows nvidia is the current driver in use. Before I run the program, I just want to make sure the supported shader language is 3.3.
kokhoe@KOKHOE:~$ glxinfo | grep 'version'
server glx version string: 1.4
client glx version string: 1.4
GLX version: 1.4
OpenGL core profile version string: 4.3.0 NVIDIA 352.63
OpenGL core profile shading language version string: 4.30 NVIDIA via Cg compiler
OpenGL version string: 4.5.0 NVIDIA 352.63
OpenGL shading language version string: 4.50 NVIDIA
Now my OpenGL info shows me version 4.5, it is far more advance than the expected version. This shouldn't be a problem with my program.

Monday, February 15, 2016

Does Flyweigh pattern really help in memory management?

In a game architecture design, memory allocator is one of the core modules sit in the game system. I’m so wondering how could I implement this module and why do I need this? After reading many articles from the experts, understand that this is a crucial part of game performance when there are thousands of game objects being spawned at a time. Due to the slow performance of the new/delete operator, it is advisable to implement a very own or game specific memory allocator. But how could I do it?

Forget about those big games adopting very advance features of memory allocator. I should focus on my game since my game is categorized as a casual game. So the most basic need for me would be:
  1. Able to allocate from OS and release memory back to the OS.
  2. The memory pool should be expandable and return the memory back into the pool.
  3. The memory pool should not release the memory back to OS until the game exit.
For this purpose, I’m borrowing the idea of Flyweigh pattern, the idea of this pattern is to minimize the memory usage by sharing as much data as possible with other similar objects. First thing first, I define a default pool size of 10 whenever a new memory pool was created:
template <typename T>
class GameObjectPool
{
private:
 static const int POOL_SIZE = 10;

 T *freshPiece; 
}
Notice the use of template for this class, it is to allow the game to be able to allocate different kinds of game object (eg. particle, sprite) in the pool. freshPiece will be responsible for holding the available memory chunk for the game object. When the pool is first constructed, freshPiece was empty. There isn't any game object hold by freshPiece. Thus, the pool will first acquire some memory from the OS. This was done in the constructor:
template <typename T>
class GameObjectPool
{
public:
 GameObjectPool () {
  fillUpMemory();
 }
 ...
private:
 void fillUpMemory() {
  T *curObj = new T();
  freshPiece = curObj;

  for (int i = 0; i < POOL_SIZE - 1; i++) {
   curObj->setNext(new T());
   curObj = curObj->getNext();
  }

  curObj->setNext(nullptr);
 }

}
Once the game was finished, the memory is released back to the OS:
template <typename T>
class GameObjectPool
{
public:
 ~GameObjectPool() { 
  Particle *curObj = freshPiece;

  if (freshPiece != nullptr) {
   for (; curObj; curObj = freshPiece) {
    freshPiece = freshPiece->getNext();
    delete curObj;
   }
  }
 }
}
During the game runtime, the game object will acquire the memory from the pool instead of using the new keyword:
template <typename T>
class GameObjectPool
{
public:
 inline T *create() {
  if (freshPiece == nullptr)
   fillUpMemory();

  T *curObj = freshPiece;
  freshPiece = freshPiece->getNext();

  return curObj;
 }

}
Once the game object has done his job, the memory will release back to the pool. Same thing as acquiring the memory, no delete keyword is used:
template <typename T>
class GameObjectPool
{
public:
 inline void release(T* obj) {
  obj->setNext(freshPiece);
  freshPiece = obj;
 }
}
Notice the POOL_SIZE I pre-code it to 10, this is due to my laziness. I let the pool automatically allocate the predefined pool size if it exceeds the available pool size. May be in the future, I will need a more elegant way to adjust the pool size as shown below:
template <typename T>
class GameObjectPool
{
public:
GameObjectPool() {
  fillUpMemory();
 }

 GameObjectPool(int poolSize) : mPoolSize(poolSize) {
  fillUpMemory();
 }

...

private:
 void expandPoolSize() {
  T *curObj = new T();
  particleHead = curObj;

  for (int i = 0; i < mPoolSize - 1; i++) {
   curObj->setNext(new T());
   curObj = curObj->getNext();
  }

  curObj->setNext(nullptr);
 }

private:
 int mPoolSize = 10;

 T *freshPiece; 
}
Well, this is my very first version that meets the most basic fundamental of my game.

Thursday, December 31, 2015

Two classes have the same XML type name?

When I'm generating the SEI stub object from a WSDL using following command:
   <plugin>
       <groupId>org.codehaus.mojo</groupId>
       <artifactId>jaxws-maven-plugin</artifactId>
       <executions>
         <execution>
           <goals>
             <goal>wsimport</goal>
           </goals>
             <configuration>
             <wsdlUrls>
               <wsdlUrl>http://localhost:8080/ws2?wsdl</wsdlUrl>
             </wsdlUrls>
           <keep>true</keep>
           <packageName>org.huahsin.jaxws.staff</packageName>
           <sourceDestDir>${basedir}/src</sourceDestDir>             
         </configuration>
         </execution>
       </executions>
   </plugin>
I'm not happy with the package name, so I decide to give a better name by changing the package name in a manual way. But when the client program trying to access the service:
 URL url = new URL("http://localhost:8080/ws2/SeniorManager?wsdl");
 QName qname = new QName("http://staff.huahsin.org/", "SeniorManagerService");
 SeniorManagerService service = new SeniorManagerService(url, qname);
 ISeniorManager manager = service.getSeniorManagerPort();
 System.out.println(manager.getID());
I hit this error:
Exception in thread "main" javax.xml.ws.WebServiceException: Unable to create JAXBContext
 at com.sun.xml.internal.ws.model.AbstractSEIModelImpl.createJAXBContext(AbstractSEIModelImpl.java:156)
 at com.sun.xml.internal.ws.model.AbstractSEIModelImpl.postProcess(AbstractSEIModelImpl.java:84)
 at com.sun.xml.internal.ws.model.RuntimeModeler.buildRuntimeModel(RuntimeModeler.java:234)
 at com.sun.xml.internal.ws.client.WSServiceDelegate.createSEIPortInfo(WSServiceDelegate.java:673)
 at com.sun.xml.internal.ws.client.WSServiceDelegate.addSEI(WSServiceDelegate.java:661)
 at com.sun.xml.internal.ws.client.WSServiceDelegate.getPort(WSServiceDelegate.java:330)
 at com.sun.xml.internal.ws.client.WSServiceDelegate.getPort(WSServiceDelegate.java:313)
 at com.sun.xml.internal.ws.client.WSServiceDelegate.getPort(WSServiceDelegate.java:295)
 at javax.xml.ws.Service.getPort(Service.java:119)
 at org.huahsin.jaxws.SeniorManagerService.getSeniorManagerPort(SeniorManagerService.java:72)
 at org.huahsin.Client.main(Client.java:23)
Caused by: java.security.PrivilegedActionException: com.sun.xml.internal.bind.v2.runtime.IllegalAnnotationsException: 2 counts of IllegalAnnotationExceptions
Two classes have the same XML type name "{http://staff.huahsin.org/}getID". Use @XmlType.name and @XmlType.namespace to assign different names to them.
 this problem is related to the following location:
  at org.huahsin.jaxws.GetID
  at public javax.xml.bind.JAXBElement org.huahsin.jaxws.ObjectFactory.createGetID(org.huahsin.jaxws.GetID)
  at org.huahsin.jaxws.ObjectFactory
 this problem is related to the following location:
  at org.huahsin.jaxws.staff.GetID
Two classes have the same XML type name "{http://staff.huahsin.org/}getIDResponse". Use @XmlType.name and @XmlType.namespace to assign different names to them.
 this problem is related to the following location:
  at org.huahsin.jaxws.GetIDResponse
  at public javax.xml.bind.JAXBElement org.huahsin.jaxws.ObjectFactory.createGetIDResponse(org.huahsin.jaxws.GetIDResponse)
  at org.huahsin.jaxws.ObjectFactory
 this problem is related to the following location:
  at org.huahsin.jaxws.staff.GetIDResponse

 at java.security.AccessController.doPrivileged(Native Method)
 at com.sun.xml.internal.ws.model.AbstractSEIModelImpl.createJAXBContext(AbstractSEIModelImpl.java:143)
 ... 10 more
Caused by: com.sun.xml.internal.bind.v2.runtime.IllegalAnnotationsException: 2 counts of IllegalAnnotationExceptions
Two classes have the same XML type name "{http://staff.huahsin.org/}getID". Use @XmlType.name and @XmlType.namespace to assign different names to them.
 this problem is related to the following location:
  at org.huahsin.jaxws.GetID
  at public javax.xml.bind.JAXBElement org.huahsin.jaxws.ObjectFactory.createGetID(org.huahsin.jaxws.GetID)
  at org.huahsin.jaxws.ObjectFactory
 this problem is related to the following location:
  at org.huahsin.jaxws.staff.GetID
Two classes have the same XML type name "{http://staff.huahsin.org/}getIDResponse". Use @XmlType.name and @XmlType.namespace to assign different names to them.
 this problem is related to the following location:
  at org.huahsin.jaxws.GetIDResponse
  at public javax.xml.bind.JAXBElement org.huahsin.jaxws.ObjectFactory.createGetIDResponse(org.huahsin.jaxws.GetIDResponse)
  at org.huahsin.jaxws.ObjectFactory
 this problem is related to the following location:
  at org.huahsin.jaxws.staff.GetIDResponse

 at com.sun.xml.internal.bind.v2.runtime.IllegalAnnotationsException$Builder.check(IllegalAnnotationsException.java:91)
 at com.sun.xml.internal.bind.v2.runtime.JAXBContextImpl.getTypeInfoSet(JAXBContextImpl.java:442)
 at com.sun.xml.internal.bind.v2.runtime.JAXBContextImpl.<init>(JAXBContextImpl.java:274)
 at com.sun.xml.internal.bind.v2.runtime.JAXBContextImpl.<init>(JAXBContextImpl.java:125)
 at com.sun.xml.internal.bind.v2.runtime.JAXBContextImpl$JAXBContextBuilder.build(JAXBContextImpl.java:1127)
 at com.sun.xml.internal.bind.v2.ContextFactory.createContext(ContextFactory.java:173)
 at com.sun.xml.internal.bind.api.JAXBRIContext.newInstance(JAXBRIContext.java:95)
 at com.sun.xml.internal.ws.developer.JAXBContextFactory$1.createJAXBContext(JAXBContextFactory.java:98)
 at com.sun.xml.internal.ws.model.AbstractSEIModelImpl$1.run(AbstractSEIModelImpl.java:151)
 at com.sun.xml.internal.ws.model.AbstractSEIModelImpl$1.run(AbstractSEIModelImpl.java:143)
 ... 12 more
At first, this was really clueless to me. Spending day and night searching whatever clue appears on the stacktrace. And eventually I found nothing. Until in the late night only I found the out root cause. Never change the stub object's package name by hand, if the it does make some noise on you, delete the whole thing and regenerate again.

Like it or not, this is the way.

JAXWS and EJB can live together

If the SEI code were accessible from the client within the same package, do I still need the following code in order to access the service code?
   URL url = new URL("http://localhost:8080/ws1?wsdl");
   QName qname = new QName("http://webmethod.huahsin.org/", "HelloWorldImplService");
   HelloWorldImplService service = new HelloWorldImplService(url, qname);
   IHelloWorld manager = service.getHelloWorldImplPort();
   System.out.println(manager.sayHelloWorld());
Imaging I have the following SEI code and there are sit in the same application:
package org.huahsin.webmethod;
 
…
 
@WebService
@SOAPBinding(style=Style.DOCUMENT)
public interface IHelloWorld {
 
 @WebMethod
 String sayHelloWorld();
}
 
 
package org.huahsin.webmethod;
 
…
 
@WebService(endpointInterface="org.huahsin.webmethod.IHelloWorld")
public class HelloWorldImpl implements IHelloWorld {
 
 @Override
 public String sayHelloWorld() {
  return "Hello World";
 }
 
}
I just feel a bit weird in doing this since both client code and server code are live in the same application. I did a search on the forum and got to know that web service code can be accessed through EJB. Just "top up" the @Stateless and @Remote to the SEI and we are done.
@Remote
@WebService
@SOAPBinding(style=Style.DOCUMENT)
public interface IHelloWorld {
 
 @WebMethod
 String sayHelloWorld();
}
 
 
package org.huahsin.webmethod;
 
…

@Stateless
@WebService(endpointInterface="org.huahsin.webmethod.IHelloWorld")
public class HelloWorldImpl implements IHelloWorld {
 
 @Override
 public String sayHelloWorld() {
  return "Hello World";
 }
 
}
To access the web service code in EJB way, do the following (excuse myself, I'm doing it in JSF bean):
@ManagedBean
@RequestScoped
public class HelloWorldController {

 @EJB
 private IHelloWorld helloWorld;
 ...
 ...
Sound cool? The best part of this is no more generating stub code.

Saturday, December 26, 2015

Asynchronous web service is a real thing

It has been so long for my wish to come true. And finally, it is proven that asynchronous web service can be done. First, I make a regular SEI:
package org.huahsin.webmethod;

…

@WebService
@SOAPBinding(style=Style.DOCUMENT)
public interface IHelloWorld {

 @WebMethod
 String sayHelloWorld();
}


package org.huahsin.webmethod;

…

@WebService(endpointInterface="org.huahsin.webmethod.IHelloWorld")
public class HelloWorldImpl implements IHelloWorld {

 @Override
 public String sayHelloWorld() {
  return "Hello World";
 }

}
And then construct the following wsimport plugin in POM.xml to generate Java artifact. But this will only generate synchronous method.
    <plugin>
        <groupId>org.codehaus.mojo</groupId>
        <artifactId>jaxws-maven-plugin</artifactId>
        <executions>
            <execution>
                <goals>
                    <goal>wsimport</goal>
                </goals>
                <configuration>
                    <wsdlUrls>
                        <wsdlUrl>http://localhost:8080/ws1?wsdl</wsdlUrl>
                    </wsdlUrls>
                    <bindingDirectory>${basedir}/resources/jaxws</bindingDirectory>
                    <keep>true</keep>
                    <packageName>org.huahsin.jaxws</packageName>
                    <sourceDestDir>${basedir}/src</sourceDestDir>             
                </configuration>
            </execution>
        </executions>
    </plugin>
To generate asynchronous method, I would require additional file to bind onto wsimport. It is just a regular XML file located at the path where <buildingDirectory> is pointing to, and the content is as shown in below:
<bindings
    xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
    wsdlLocation="http://localhost:8080/ws1?wsdl"
    xmlns="http://java.sun.com/xml/ns/jaxws">

    <!-- applies to wsdl:definitions node, that would mean the entire wsdl -->
    <enableAsyncMapping>false</enableAsyncMapping>

    <!-- wsdl:portType operation customization -->
    <bindings node="wsdl:definitions/wsdl:portType [@name='IHelloWorld']/wsdl:operation[@name='sayHelloWorld']">
        <enableAsyncMapping>true</enableAsyncMapping>
    </bindings>
  
</bindings>
It's job scope is to locate the sayHelloWorld method using XPath and then convert this method to support asynchronous. While not affecting to the other's behaviour, I remain the rest of the methods as synchronous. Once everything is ready, I would first need a publisher to start the engine before I can do the conversion:
public class Publisher {
 public static void main(String args[]) {
  Endpoint.publish("http://localhost:8080/ws1", new HelloWorldImpl());
 }
}
Then fire the command mvn compile to generate Java artifact. This will have additional two methods generated for asynchronous (as shown in the code snippet below) compare to the default generation.
public interface IHelloWorld {
    public Response<SayHelloWorldResponse> sayHelloWorldAsync();

    public Future<?>sayHelloWorldAsync(
        @WebParam(name = "asyncHandler", targetNamespace = "")
        AsyncHandler<SayHelloWorldResponse> asyncHandler);

    ...
}
Now, to test my code is really works? I would have this simple program firing the asynchronous method:
...

import org.huahsin.jaxws.HelloWorldImplService;
import org.huahsin.jaxws.IHelloWorld;
import org.huahsin.jaxws.SayHelloWorldResponse;

...


public class Client {
 static private String msg = "";
 
 public static void main(String[] args) … {
  System.out.println("before: " + msg);
  e.sayHelloWorldMethod();
  Thread.sleep(1000);
  System.out.println("after: " + msg);
 }

 private void sayHelloWorldMethod() throws MalformedURLException, InterruptedException, ExecutionException {
  URL url = new URL("http://localhost:8080/ws1?wsdl");
  QName qname = new QName("http://webmethod.huahsin.org/", "HelloWorldImplService");
  HelloWorldImplService service = new HelloWorldImplService(url, qname);
  IHelloWorld hello = service.getHelloWorldImplPort();
  
  Response res = hello.sayHelloWorldAsync();
  SayHelloWorldResponse output = (SayHelloWorldResponse) res.get();
  output.getReturn();
  
  hello.sayHelloWorldAsync(new AsyncHandler() {

   @Override
   public void handleResponse(Response res) {
    try {
     setMessage(((SayHelloWorldResponse)res.get()).getReturn());
    }
    catch (InterruptedException | ExecutionException e) {
     e.printStackTrace();
    }
   }
   
  });
 }

 private void setMessage(String msg) {
   this.msg = msg;
 }

}