Saturday, October 27, 2012

Add Native Support to JS in Android HTML5 Apps

Running HTML 5 apps in Android , is not effective as you loss a lot of native power , Android provides the ability to expose native power to JS so you can use the powerful native support in your app.

Here is the simple steps:


1. Create any class and name it any thing like JavaScriptInterface
Example:


public class JavaScriptInterface {
        Context mContext;

        JavaScriptInterface(Context c) {
            mContext = c;
        }

        public void doSomething() {
         System.err.println("inside do something");
        }
}

2. The class should have constructor that take Context as parameter

3. During instatiation send the activity object in the constructor and add nick(prefix) name to be used inside JS to call this class methods:

     webView.addJavascriptInterface(new JavaScriptInterface(this), "Android");


Example:

    public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_crazy);
    WebView webView=(WebView)findViewById(R.id.webView);
    webView.setWebChromeClient(new WebChromeClient());
    webView.getSettings().setJavaScriptEnabled(true); 
    webView.getSettings().setDatabaseEnabled(true);
    webView.getSettings().setDatabasePath("/data/data/osa.ora.test/databases/");
    webView.getSettings().setDomStorageEnabled(true);
    //remove this line for emulator bug in Android 2.3
    webView.addJavascriptInterface(new JavaScriptInterface(this), "Android");
       //the following line to prevent the backlight from going during application running.
    getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
    webView.loadUrl("file:///android_asset/www/index.html");    
    }


4. In the JS call this methods

Example:
Android.doSomething();

You can see in the console the outcome of the sys err statement.
(Android is the prefix we have specified during creating instance of this JS interface)

5. Of course we can have many interfaces each for specific purpose.

Simple and straightforward but there is a bug in android emulator in 2.3 so better to test it on mobile devices direct in case you need to test it on such platform.

Monday, October 22, 2012

"Hit The Ball" .. Android Game

I have published 1st version of my game "Hit The Ball" over Android platform.


Links:

Here is the link for the demo version :
https://play.google.com/store/apps/details?id=hit.ball.game.demo

And this is the link to commercial version :
https://play.google.com/store/apps/details?id=hit.ball.game

Description:
The game is based on HTML 5 technology and use Java Script Interface for some native work.
It uses Box2D implementation as physics engine for the game.

The idea behind this game is you play with a ball and you need to hit the other ball in the scene.
If you hit the other ball , you go to next level, where it get complicated little bit.
You can select the destination of the shoot by your click/finger.
If you didn't shoot the ball , the ball will be automatically shoot to a default location.
If you pick small ball you get extra trial.
Pay attention to the speed bar during shooting.
You can resume the game from the last successful level which is auto-saved.

Game screen shots:




Saturday, October 6, 2012

Java Fork Join & Parallel Programming

After emerging of multi-cores programs , a major shift to the application development to utilize these cores by forking many threads/process for the applications esp. in the intensive processing procedure.

Java came lately to the paradigm shift with concurrency APIs in Java 7  (JSR 166) (which was initially planned in Java 5), the framework will go under another improvement to facilitate the current complex way in Java 8.

Best fit algorithms for paralization is divide-and-conquer algorithms.
In this post we will go through example of using the fork-join to develop quick sort enhancement..

1) Framework important parts:
-ForkJoinTask : this is a task to be forked and joined after processing.
It has lifecycle methods as doJoin , doInvoke , doExecute plus status.

- RecursiveAction extends ForkJoinTask: represent a recursive action..
It has important method which is compute..
We will extend this class and override compute method to do what we need.

-ForkJoinPool : represents the pool for fork and join framework , you can initialize it by the number of cores or by fixed magic number ...
Note: To get the number of processors/cores:
int processors = Runtime.getRuntime().availableProcessors();

2) Non-parallel Quick sort:
Static method that process the numbers[] to sort them...


//non-parallellll...
private static int[] numbers;
private static void quicksort(int low, int high) {
int i = low, j = high;
// Get the pivot element from the middle of the list
int pivot = numbers[low + (high-low)/2];

// Divide into two lists
while (i <= j) {
// If the current value from the left list is smaller then the pivot
// element then get the next element from the left list
while (numbers[i] < pivot) {
i++;
}
// If the current value from the right list is larger then the pivot
// element then get the next element from the right list
while (numbers[j] > pivot) {
j--;
}

// If we have found a values in the left list which is larger then
// the pivot element and if we have found a value in the right list
// which is smaller then the pivot element then we exchange the
// values.
// As we are done we can increase i and j
if (i <= j) {
exchange(i, j);
i++;
j--;
}
}
// Recursion
if (low < j)
quicksort(low, j);
if (i < high)
quicksort(i, high);
}

private static void exchange(int i, int j) {
int temp = numbers[i];
numbers[i] = numbers[j];
numbers[j] = temp;
}



3) Using Fork-Join:


public class ParallelQuickSort extends RecursiveAction {
    Phaser phaser;
    int[] arr = null;
    int left;
    int right;

    ParallelQuickSort(Phaser phaser, int[] arr) {
        this(phaser, arr, 0, arr.length - 1);
    }

    ParallelQuickSort(Phaser phaser, int[] arr, int left, int right) {
        this.phaser = phaser;
        this.arr = arr;
        this.left = left;
        this.right = right;
        phaser.register();  //important
    }


    private ParallelQuickSort leftSorter(int pivotI) {
        return new ParallelQuickSort(phaser, arr, left, --pivotI);
    }

    private ParallelQuickSort rightSorter(int pivotI) {
        return new ParallelQuickSort(phaser, arr, pivotI, right);
    }

    private void recurSort(int leftI, int rightI) {
        if (rightI - leftI > 7) {
            int pIdx = partition(leftI, rightI, getPivot(arr, leftI, rightI));
            recurSort(leftI, pIdx - 1);
            recurSort(pIdx, rightI);
        } else if (rightI - leftI > 0) {
            insertionSort(leftI, rightI);
        }
    }


    @Override
    protected void compute() {
        if (right - left > 1000) {   // if more than 1000 (totally arbitrary number i chose) try doing it parallelly
            int pIdx = partition(left, right, getPivot(arr, left, right));
            leftSorter(pIdx).fork();
            rightSorter(pIdx).fork();

        } else if (right - left > 7) {  // less than 1000 sort recursively in this thread
            recurSort(left, right);

        } else if (right - left > 0) {  //if less than 7 try simple insertion sort
            insertionSort(left, right);
        }

        if (isRoot()) { //if this instance is the root one (the one that started the sort process), wait for others
                        // to complete.
            phaser.arriveAndAwaitAdvance();
        } else {  // all not root one just arrive and de register not waiting for others.
            phaser.arriveAndDeregister();
        }
    }

    /** Patition the array segment based on the pivot   **/
    private int partition(int startI, int endI, int pivot) {
        for (int si = startI - 1, ei = endI + 1; ; ) {
            for (; arr[++si] < pivot;) ;
            for (; ei > startI && arr[--ei] > pivot ; ) ;
            if (si >= ei) {
                return si;
            }
            swap(si, ei);
        }
    }

    private void insertionSort(int leftI, int rightI) {
        for (int i = leftI; i < rightI + 1; i++)
            for (int j = i; j > leftI && arr[j - 1] > arr[j]; j--)
                swap(j, j - 1);

    }

    private void swap(int startI, int endI) {
        int temp = arr[startI];
        arr[startI] = arr[endI];
        arr[endI] = temp;
    }

    /**
     * Check to see if this instance is the root, i.e the first one used to sort the array.
     * @return
     */
    private boolean isRoot() {
        return arr.length == (right - left) + 1;
    }

    /**
     * copied from java.util.Arrays
     */
    private int getPivot(int[] arr, int startI, int endI) {
        int len = (endI - startI) + 1;
        // Choose a partition element, v
        int m = startI + (len >> 1);       // Small arrays, middle element
        if (len > 7) {
            int l = startI;
            int n = startI + len - 1;
            if (len > 40) {        // Big arrays, pseudomedian of 9
                int s = len / 8;
                l = med3(arr, l, l + s, l + 2 * s);
                m = med3(arr, m - s, m, m + s);
                n = med3(arr, n - 2 * s, n - s, n);
            }
            m = med3(arr, l, m, n); // Mid-size, med of 3
        }
        int v = arr[m];
        return v;
    }

    /**
     * copied from java.util.Arrays
     */
    private static int med3(int x[], int a, int b, int c) {
        return (x[a] < x[b] ?
                (x[b] < x[c] ? b : x[a] < x[c] ? c : a) :
                (x[b] > x[c] ? b : x[a] > x[c] ? c : a));
    }


4) Testing :
Generate big random array then sort it using both and see the results:

       private static int[] getRandom(int i) {
        Random randomGenerator = new Random(i);
        int[] array = new int[i];
        for (int n = 0; n < i; n++) {
            array[n] = randomGenerator.nextInt();
        }
        return array;
    }

    public static void main(String[] args) throws InterruptedException {
        int[] arr = getRandom(1000000);
        numbers=Arrays.copyOf(arr, arr.length);
        int[] arr2=Arrays.copyOf(arr, arr.length);
        System.out.println("show: " + arr.length+" "+numbers.length);
        System.out.println("show: " + arr[0]+" "+arr[arr.length-1]);
        System.out.println("show: " + numbers[0]+" "+numbers[numbers.length-1]);
        ForkJoinPool pool = new ForkJoinPool();
        StopWatch  stopWatch=new StopWatch();
        Phaser phaser = new Phaser();
        pool.invoke(new ParallelQuickSort(phaser, arr));
        stopWatch.stop();
        System.out.println("Elapsed Time: " + stopWatch.getElapsedTime());
        System.out.println("show: " + arr[0]+" "+arr[arr.length-1]);
        System.out.println("show: " + numbers[0]+" "+numbers[numbers.length-1]);
        numbers=getRandom(1000000);
        stopWatch=new StopWatch();        
        quicksort(0,numbers.length-1);
        stopWatch.stop();
        System.out.println("Elapsed Time: " + stopWatch.getElapsedTime());
        System.out.println("show: " + arr[0]+" "+arr[arr.length-1]);
        System.out.println("show: " + numbers[0]+" "+numbers[numbers.length-1]);     
        stopWatch=new StopWatch();        
        Arrays.sort(arr2);
        stopWatch.stop();
        System.out.println("Elapsed Time: " + stopWatch.getElapsedTime());
    }



5) Output :

Example of output of this code:


show: 1000000 1000000
show: 1608240105 -356486679
show: 1608240105 -356486679
Elapsed Time: 68
show: -2147481329 2147476538
show: 1608240105 -356486679
Elapsed Time: 114
show: -2147481329 2147476538
show: -2147481329 2147476538
Elapsed Time: 92



So sorting 1 million element in the array toke 65 milliseconds using fork-join and 113 milliseconds using single threaded mode, and using java optimized quick sort it takes 92 milliseconds.

Saturday, June 16, 2012

Text To Speech in JSP page (or HTML pages)

In this post we will show how to add text to speech support to your web pages , simplified steps will be followed for that.

We will use eSpeak which is open source project: http://espeak.sourceforge.net/

Link: http://espeak.sourceforge.net/

1) Create Java Web Application : (or HTML page)
2) Create folder JS and place the following files:
- speakWorker.js
- speakGenerator.js
- speakClient.js

3) Edit speakClient.js and change the 3rd line in the file to point to your JS folder :

speakWorker = new Worker('js/speakWorker.js');

4) Create JSP pages (or HTML page) :

a) Add the following JS imports in the header:
 <script src="js/speakGenerator.js"></script>
  <script src="js/speakClient.js"></script>

b) Add this function in the header as well:
  <script>
    function textToSpeech(text){
       // you can change any of these voice characteristics
        speak(text, { amplitude: 100, wordgap: 1, pitch: 50, speed: 175 });
    }
  </script>

c) Add this div to your page body :
  <div id="audio"></div>

5) In your page use the function we have just created like this:
I have added small icon beside each filed to text to speech its content in human friendly way : Name is ..., City is ...., Country is ......


Name : <input type="text" name="name" id="name" size=50 value="Osama Oransa"><img src="images/tts.png" onclick="textToSpeech('Name is '+document.forms[0].name.value); return false" style="cursor:pointer;vertical-align: middle">

The nice thing in this open source project that it support a lot of languages and different voice with ability to tune each voice using many features and if you didn't find your language you can generate the speech generator for it.



Saturday, June 2, 2012

Accessing WebCam within JSP

I keep getting questions about how we can use web camera inside jsp files , in this post i will show you how to use the web cam from within jsp file.


We will use jQuery wrapper of flash plugin for that..
My reference in that is http://www.xarg.org
There is a guide you can follow instead of my post: http://www.xarg.org/project/jquery-webcam-plugin/
Here is the simplified steps:
1.Create resources folder with the following content from the mentioned web site:
jquery.js
jquery-1.js
either : jscam.swf or jscam_canvas_only.swf

2.Create JSP file and put the following code:
<%@page contentType="text/html" pageEncoding="UTF-8"%>
<title>Test Web Cam</title>
<style type="text/css">
#webcam, #canvas {
    width: 320px;
    border:20px solid #333;
    background:#eee;
    -webkit-border-radius: 20px;
    -moz-border-radius: 20px;
    border-radius: 20px;
}

#webcam {
    position:relative;
    margin-top:50px;
    margin-bottom:50px;
}

#webcam > span {
    z-index:2;
    position:absolute;
    color:#eee;
    font-size:10px;
    bottom: -16px;
    left:152px;
}

#canvas {    border:20px solid #ccc;
    background:#eee;
}
</style><script type="text/javascript" src="resources/jquery-1.js"></script>
<script type="text/javascript" src="resources/jquery.js"></script>
</head><body>
<p id="status" style="height:22px; color:#c00;font-weight:bold;"></p>
<div id="webcam">
    <span>Your WebCam should be here!</span>
</div>

<p style="width:360px;text-align:center; ">
    <a href="javascript:webcam.capture(3);changeFilter();void(0);">Take a picture after 3 seconds</a> |
    <a href="javascript:webcam.capture();changeFilter();void(0);">Take a picture instantly</a></p>

<script type="text/javascript">
var pos = 0;
var ctx = null;
var cam = null;
var image = null;

var filter_on = false;
var filter_id = 0;

$(function() {

        var pos = 0, ctx = null, saveCB, image = [];
        var canvas = document.createElement("canvas");
        canvas.setAttribute('width', 320);
        canvas.setAttribute('height', 240); 
        if (canvas.toDataURL) {
                ctx = canvas.getContext("2d");             
                image = ctx.getImageData(0, 0, 320, 240);
                saveCB = function(data) {                       
                        var col = data.split(";");
                        var img = image;
                        for(var i = 0; i < 320; i++) {
                                var tmp = parseInt(col[i]);
                                img.data[pos + 0] = (tmp >> 16) & 0xff;
                                img.data[pos + 1] = (tmp >> 8) & 0xff;
                                img.data[pos + 2] = tmp & 0xff;
                                img.data[pos + 3] = 0xff;
                                pos+= 4;
                        }
                        if (pos >= 4 * 320 * 240) {
                                ctx.putImageData(img, 0, 0);
                                $.post("/TestWebCam/UploadServlet", {type: "data", image: canvas.toDataURL("image/png")});
                                pos = 0;
                        }
                };
        } else {
                saveCB = function(data) {
                        image.push(data);                       
                        pos+= 4 * 320;                       
                        if (pos >= 4 * 320 * 240) {
                                $.post("/TestWebCam/UploadServlet", {type: "pixel", image: image.join('|')});
                                pos = 0;
                        }
                };
        }
        $("#webcam").webcam({
                width: 320,
                height: 240,
                mode: "callback",
                swffile: "resources/jscam_canvas_only.swf",
                onSave: saveCB,
                onCapture: function () {
                        webcam.save();
                },
                debug: function (type, string) {
                        console.log(type + ": " + string);
                }
        });

});
</script>
</body>
</html>

3.Create a Servlet named: UploadServlet with the following code:
package osa.ora;

import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * UploadServlet
 * Author Osama Oransa
 */
public class UploadServlet extends javax.servlet.http.HttpServlet implements javax.servlet.Servlet {

    private static final long serialVersionUID = 529869125345702992L;
    public UploadServlet() {
        super();
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        System.out.println("SAVING>>>>>>>>>>>>>>>>>>>>");
        String type = request.getParameter("type");
        String image = request.getParameter("image");
        System.out.println("SAVING>>>>>>>>>>>>>>>>>>>>Type=" + type);
        System.out.println("SAVING>>>>>>>>>>>>>>>>>>>>data=" + image);
        if (type != null) {
            return;
        }

        String byteStr = image.split(",")[1];
        byte[] bytes = Base64.decode(byteStr);
//Now you have the image bytes ready to save in File/DB/....etc..

//Or use the pixel data for old browser and convert the pixel comma separated values into int[] then call methods similar to the following one:

public static Image getImageFromArray(int[] pixels, int width, int height) {
BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
WritableRaster raster = (WritableRaster) image.getData();
raster.setPixels(0,0,width,height,pixels);
return image;
}
    }
}
           
This will show you the encoded png data ...you can decode it or keep it encoded , save it to DB ...etc...
If you are doing a video chat application you need to capture the images in periodic manner and upload it , you may include the source & destination ids to distribute the chat images correctly..

This code only works with integrated camera in the laptop not with USB external camera.

These are simplified steps so you can copy and paste and let it work easily.
But in case you need more details , you may refer to the original URL for more clarification on how to control it more..

NOTE:
Another alternative is to use the following project:  https://github.com/jhuckaby/webcamjs

Tuesday, April 3, 2012

WebCam Video Capture in Java

I got a lot of requests asking for how to do video capturing in Java as comments on my previous post :

Capture photo / image from Web Cam / USB Camera using Java

In this quick post i will highlight how i did this functionality in Interactive4j

We will use the library LTI-CIVIL which is part of FMJ (Freedom for Media in Java).



PreRequisities:

-Download the library and place it correctly in your classpath and load the native library using JVM parameter exactly as the previous mentioned post above.
Download from here:  https://sourceforge.net/projects/lti-civil/

Steps:

1) Create Interface For Captured Images:
public interface CaptureListener {
/**
* Method called once capturing of the web cam jpg file is done.
* @param filename
*/
public void setCaptureFile(File filename);
}

2) Create A Wrapper Class:
This class wrap the camera functionality..

/**
* JHCaptureUtil class
* Used for capture images through the usb (camera, scanner,...etc)
* Osama Oransa
* Interactive4J
* (c) 2011
**/
package osa.ora.utils;

import com.lti.civil.*;
import com.lti.civil.awt.AWTImageConverter;
import com.sun.image.codec.jpeg.JPEGCodec;
import com.sun.image.codec.jpeg.JPEGImageEncoder;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import osa.ora.utils.faces.CaptureListener;

/**
*
* @author mabdelmo
*/
public class JHCaptureUtil implements CaptureObserver {

CaptureStream captureStream = null;
CaptureListener captureListener;
String fileName;
/**
* Constructor accept the listener and file to save image into.
* @param captureListener
* @param fileName
*/
public JHCaptureUtil(CaptureListener captureListener, String fileName) {
this.fileName = fileName;
this.captureListener = captureListener;
init();
}
private void init(){
System.out.println("Init....");
/*
* initialize capturing to use the current devices...
*/
CaptureSystemFactory factory = DefaultCaptureSystemFactorySingleton.instance();
CaptureSystem system;
try {
system = factory.createCaptureSystem();
system.init();
List list = system.getCaptureDeviceInfoList();
int i = 0;
if (i < list.size()) {
CaptureDeviceInfo info = (CaptureDeviceInfo) list.get(i);
System.out.println((new StringBuilder()).append("Device ID ").append(i).append(": ").append(info.getDeviceID()).toString());
System.out.println((new StringBuilder()).append("Description ").append(i).append(": ").append(info.getDescription()).toString());
captureStream = system.openCaptureDeviceStream(info.getDeviceID());
captureStream.setObserver(this);
}
} catch (CaptureException ex) {
Logger.getLogger(JHCaptureUtil.class.getName()).log(Level.SEVERE, null, ex);
}
}
/**
* Start capture method
*/
public void start() {
//System.out.println("Start....");
try {
captureStream.start();
} catch (CaptureException ex) {
Logger.getLogger(JHCaptureUtil.class.getName()).log(Level.SEVERE, null, ex);
}
}
/**
* Stop capture method
*/
public void stop() {
//System.out.println("Stop....");
try {
captureStream.stop();
} catch (CaptureException ex) {
Logger.getLogger(JHCaptureUtil.class.getName()).log(Level.SEVERE, null, ex);
}
}
/**
*
* @param stream
* @param image
*/
public void onNewImage(CaptureStream stream, Image image) {
//System.out.println("get new image....");
byte bytes[] = null;
try {
if (image == null) {
return;
}
try {
ByteArrayOutputStream os = new ByteArrayOutputStream();
JPEGImageEncoder jpeg = JPEGCodec.createJPEGEncoder(os);
jpeg.encode(AWTImageConverter.toBufferedImage(image));
os.close();
bytes = os.toByteArray();
if (bytes == null) {
return;
}
} catch (Throwable t) {
t.printStackTrace();
bytes = null;
return;
}
ByteArrayInputStream is = new ByteArrayInputStream(bytes);
File currentImageFile = new File(fileName);
FileOutputStream fos = new FileOutputStream(currentImageFile);
fos.write(bytes);
fos.close();
captureListener.setCaptureFile(currentImageFile);
} catch (IOException ex) {
Logger.getLogger(JHCaptureUtil.class.getName()).log(Level.SEVERE, null, ex);
}
}
/**
*
* @param stream
* @param ce
*/
public void onError(CaptureStream stream, CaptureException ce) {
System.out.println("Error : "+ce.getStackTrace());
}
}




3) Write the code that control your wrapper class:
Here is sample usage code that display a dialog with one image or a video .. You need to add 2 buttons 1 for image capture and 1 for video capture and add the action listeners on these buttons..


int mode=0;
static int ONE_PHOTO=0;
static int MULTI_PHOTO=1;
JHCaptureUtil webCam;

//this method to capture one image

private void captureImageButtonActionPerformed(java.awt.event.ActionEvent evt) {
mode=ONE_PHOTO;
if(webCam==null) webCam=new JHCaptureUtil(this, "/myWebCamPic.jpg");
webCam.start();
}

private void captureVideoActionPerformed(java.awt.event.ActionEvent evt) {
mode=MULTI_PHOTO;
if(webCam==null) webCam=new JHCaptureUtil(this, "/myWebCamPic.jpg");
webCam.start();
}


You class must implements : CaptureListener , this interface has 1 method inside it :
public void setCaptureFile(File filename);

And this is the interface method implementation that display the image without saving the photos (you can change the implementation)


JDialog monitorjDialog;
JLabel monitorLabel;
JScrollPane monitorScroll;

public void setCaptureFile(File filename) {
if(mode==ONE_PHOTO){
System.out.println("No more photos");
JDialog jDialog=new JDialog(this.getFrame(),true);
Image image=ImageUtils.loadJPG(filename.getAbsolutePath());
jDialog.setBounds(this.getFrame().getX()+50,this.getFrame().getY()+50,500, 500);
JLabel label=new JLabel(new ImageIcon(image));
JScrollPane jscroll=new JScrollPane(label);
jDialog.add(jscroll);
jDialog.setVisible(true);
jDialog.validate();
webCam.stop();
}else{
System.out.println("display new photo");
if(monitorjDialog==null) {
monitorjDialog=new JDialog(this.getFrame(),false);
monitorjDialog.addWindowListener(new WindowAdapter() {
@Override
public void windowClosing(WindowEvent e) {
webCam.stop();
}
});
Image image=ImageUtils.loadJPG(filename.getAbsolutePath());
monitorjDialog.setBounds(this.getFrame().getX()+50,this.getFrame().getY()+50,image.getWidth(null), image.getHeight(null));
monitorLabel=new JLabel(new ImageIcon(image));
monitorScroll=new JScrollPane(monitorLabel);
monitorjDialog.add(monitorScroll);
monitorjDialog.setVisible(true);
monitorjDialog.validate();
}else{
Image image=ImageUtils.loadJPG(filename.getAbsolutePath());
monitorjDialog.remove(monitorScroll);
monitorScroll.remove(monitorLabel);
monitorLabel=new JLabel(new ImageIcon(image));
monitorScroll=new JScrollPane(monitorLabel);
monitorjDialog.add(monitorScroll);
monitorjDialog.validate();
}
}
}

4) Utility method used: ImageUtils.loadJPG ..
public static Image loadJPG(String filename) {
FileInputStream in = null;
try {
in = new FileInputStream(filename);
} catch (java.io.FileNotFoundException io) {
System.out.println("File Not Found");
}
JPEGImageDecoder decoder = JPEGCodec.createJPEGDecoder(in);
BufferedImage bi = null;
try {
bi = decoder.decodeAsBufferedImage();
in.close();
} catch (java.io.IOException io) {
System.out.println("IOException");
}
return bi;
}

That's all needed !

Tuesday, March 20, 2012

Developing HTML 5 Application for Android

Developing HTML 5 Application for Android is an easy process, we will list the few steps needed to achieve this..

1) Create Your Normal Android Project:
-Define the activity and package name in new project wizard.
For example: Activity is TestActivity and package name is osa.ora.test

2) In the main.xml change it to looks like the following:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>
<WebView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:id="@+id/webView"
/>
</LinearLayout>

This define a web view with the id: webView.

3) In our activity : the following code is needed according to your needs:

public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
WebView webView=(WebView)findViewById(R.id.webView);
webView.setWebChromeClient(new WebChromeClient());
webView.getSettings().setJavaScriptEnabled(true);
webView.getSettings().setDatabaseEnabled(true);
webView.getSettings().setDatabasePath("/data/data/osa.ora.test/databases/");
webView.getSettings().setDomStorageEnabled(true);
webView.loadUrl("file:///android_asset/www/index.html");

}

4) In asset folder create a folder with the name "www":

Place all the HTML, JS and CSS (and images) files under it, you must have the index.html that we refereed in our code (or another file name but match what in our java code).

5) Run the emulator , test it then sign it and upload :)

This is example application running in the emulator:


A lot of video tutorials exist showing the same way to develop such application.
Click here to watch.

Thursday, March 15, 2012

Using AES encryption in Java Script

Using encryption in Java Script could potentially help establishing secure data communication between the client and the server.

In this post we will wrap existing APIs to do that: JSAES

JSAES:

jsaes is a compact JavaScript implementation of the AES block cipher. Key lengths of 128, 192 and 256 bits are supported.

jsaes is free software, written in 2006 by B. Poettering. The code is licensed under the GNU GPL. The well-functioning of the encryption/decryption routines has been verified for different key lengths with the test vectors given in FIPS-197, Appendix C.

URL:
http://point-at-infinity.org/jsaes/


Download URL:
http://point-at-infinity.org/jsaes/jsaes.js

Our Wrapper code: jsaes_wrapper.js

function init(myKey){
AES_Init();
var key = string2Bin(myKey);
AES_ExpandKey(key);
return key;
}

function encrypt ( inputStr,key ) {
var block = string2Bin(inputStr);
AES_Encrypt(block, key);
var data=bin2String(block);
return data;
}
function decrypt ( inputStr,key ) {
block = string2Bin(inputStr);
AES_Decrypt(block, key);
var data=bin2String(block);
return data;
}
function encryptLongString ( myString,key ) {
if(myString.length>16){
var data='';
for(var i=0;i<myString.length;i=i+16){
data+=encrypt(myString.substr(i,16),key);
}
return data;
}else{
return encrypt(myString,key);
}
}
function decryptLongString ( myString,key ) {
if(myString.length>16){
var data='';
for(var i=0;i<myString.length;i=i+16){
data+=decrypt(myString.substr(i,16),key);
}
return data;
}else{
return decrypt(myString,key);
}
}
function finish(){
AES_Done();
}
function bin2String(array) {
var result = "";
for (var i = 0; i < array.length; i++) {
result += String.fromCharCode(parseInt(array[i], 2));
}
return result;
}
function string2Bin(str) {
var result = [];
for (var i = 0; i < str.length; i++) {
result.push(str.charCodeAt(i));
}
return result;
}

function bin2String(array) {
return String.fromCharCode.apply(String, array);
}

Usage:
This wrapper is adjusted to use key with 16 bytes length.

<html>
<head>
<meta charset="utf-8">
<title>Encryption Example</title>
<script src="jsaes.js"></script>
<script src="jsaes_wrapper.js"></script>
<script>
usedKey="World678World678";
myStr="Osama Oransa2012Osama Oransa2011RashaOsama Oransa2012Osama Oransa2011RashaOsama Oransa2012Osama Oransa2011RashaOsama Oransa2012Osama Oransa2011Rasha";
alert(myStr);
alert(usedKey);
var key=init(usedKey);
alert(key);
encrypted=encryptLongString(myStr,key);
alert('after encrypt='+encrypted);
decrypted=decryptLongString(encrypted,key);
alert('after decrypt='+decrypted);
finish();
</script>
</head>
<body>
</body>
</html>

Sunday, March 11, 2012

HTML 5 Game Development - JDC 2012


Yesterday I gave a session about HTML 5 game development.. It was a very nice experience to give a session out of the Java topics in such conference :)

Abstract:

HTML 5 is the 5th major revision of the core language of the World Wide Web: the Hypertext Markup Language (HTML). In this version, new features are introduced to help Web application authors, new elements are introduced based on research into prevailing authoring practices, and special attention has been given to defining clear conformance criteria for user agents in an effort to improve interoperability.
In our session we will cover quick orientation about HTML 5 new features, then we will dig on how to create games using html5 new features, we will cover all basic components of the gaming including: Animations, Interactions, Controls, Effects, Boundaries, Entry Points, Physics and AI rules.
A step by step game development will be covered in this session to guide the attendees about how to create the game and how to package this into a deployable application for different smart phone devices.
Some advanced topics will be covered like using Box2d Physics engine plus AI engine example.



Materials:



Saturday, January 21, 2012

Statistical Machine Translation - SMT

Machine translation like Google Web Based services , is based on statistical machine translation where statistics play the big role in the selection of the proper translation matching.


1) Introduction:
a) Word-based translation
The fundamental unit of translation is a word in some natural language.
Typically, the number of words in translated sentences are different, because of compound words, morphology and idioms.
The ratio of the lengths of sequences of translated words is called fertility, which tells how many foreign words each native word produces.
Simple word-based translation can't translate between languages with different fertility.
An example of a word-based translation system is the freely available GIZA++ package (GPLed), which includes the training program for IBM models and HMM model and Model 6
Not widely used today

b) Phrase-based translation
Aim is to reduce the restrictions of word-based translation by translating whole sequences of words, where the lengths may differ.
The sequences of words are called blocks or phrases, but typically are not linguistic phrases but phrases found using statistical methods from corpora.
Most commonly used nowadays.

**Syntax-based translation
Based on the idea of translating syntactic units, rather than single words or strings of words (as in phrase-based MT), i.e. (partial) parse trees of sentences/utterances.
The idea of syntax-based translation is quite old in MT, though its statistical counterpart did not take off until the advent of strong stochastic parsers in the 1990s.
Examples of this approach include DOP-based MT and, more recently, synchronous context-free grammars.

2) Challenges :
-Sentence alignment:
In parallel corpora single sentences in one language can be found translated into several sentences in the other and vice versa.
Sentence aligning can be performed through the Gale-Church alignment algorithm.
-Compound words : Idioms
Depending on the corpora used, idioms may not translate "idiomatically". For example, using Canadian Hansard as the bilingual corpus, "hear" may almost invariably be translated to "Bravo!" since in Parliament "Hear, Hear!" becomes "Bravo!"
-Morphology : Different word orders
Word order in languages differ. Some classification can be done by naming the typical order of subject (S), verb (V) and object (O) in a sentence and one can talk, for instance, of SVO or VSO languages. There are also additional differences in word orders, for instance, where modifiers for nouns are located, or where the same words are used as a question or a statement.
-Syntax : Out of vocabulary (OOV) words
SMT systems store different word forms as separate symbols without any relation to each other and word forms or phrases that were not in the training data cannot be translated. This might be because of the lack of training data, changes in the human domain where the system is used, or differences in morphology.

3) Models:
A) Language Model:
P(statement)
For fluency and grammar-well structured statements.
N-Gram model.
Needs single corpus.
B) Translation Model:
P(target statement | source statement)
For Translation
Needs parallel corpus.

4) Our work :
We will use “Phrase-based translation”
We will work on translating English into Arabic.
We will uses Moses and SRILM and GIZA.

a) Environment Setup:
-Download Ubontu 10.04 LTS
http://www.ubuntu.com/download/ubuntu/download
-Install Virtual Box
Install Ubontu on a virtual box.
-Setup a shared folder between Win & Ubontu:
apt-get install virtualbox-ose-guest-modules-2.6.26-2-686 (somehow get, e.g. over ftp, previously saved file /sbin/mount.vboxsf)
chmod +rx /sbin/mount.vboxsf
modprobe vboxvfs
mount -t vboxsf
e.g. sudo chmod +rx /sbin/mount.vboxsf
sudo mount.vboxsf shared-folder /mnt/xp
Or sudo mount -t vboxsf c:/shared-folder /mnt/xp

https://forums.virtualbox.org/viewtopic.php?p=4586

-Install needed tools:
http://cl.naist.jp/~eric-n/ubuntu-nlp/dists/lucid/nlp/

b)Data Preparation:
Corpus Files : Bi-lingual , In our case Arabic and English.. (We Will use UN corpus)
*Needed data files:
-A large sentence-aligned bilingual parallel corpus.
We refer to this set as the training data, , since it will be used to train the translation model.
-A larger monolingual corpus.
We need data in the target language to train the language model. You could simply use the target side of the parallel corpus, but it is better to assemble to large amounts of monolingual text, since it will help improve the fluency of your translations.
-A small sentence-aligned bilingual corpus
To use as a development set (somewhere around 1000 sentence pairs ought to be sufficient).
This data should disjoint from your training data.
It will be used to optimize the parameters of your model in minimum error rate training (MERT).
-A small sentence-aligned bilingual corpus
To use as a test set to evaluate the translation quality of your system and any modifications that you make to it.
The test set should be disjoint from the dev and training sets.

-Data Tokenization:
Like using whitespace to delineate words.
For many languages, tokenization can be as simple as separating punctuation off as its own token.

-Data Normalization:
Normalize your data by lowercasing it.
The system treats words with variant capitalization as distinct, which can lead to worse probability estimates for their translation, since the counts are fragmented.
For each language you might want to normalize the text in other ways.
Another example is to transfer all numbers into words.
Using Moses scripts:
lowercase.perl < training.ar > training.ar

-Sentences length:
You can remove the long sentences to enhance processing speed ..
Using Moses scripts:
clean-corpus-n.perl training en ar training.clean 1 40
…..
…..
results: Input sentences: 36615 Output sentences: 36615


c) Creating Language Model:
-Statistical Language Modeling is to build a statistical language model that can estimate the distribution of natural language as accurate as possible.
-A statistical language model (SLM) is a probability distribution P(s) over strings S that attempts to reflect how frequently a string S occurs as a sentence.
-By expressing various language phenomena in terms of simple parameters in a statistical model, SLMs provide an easy way to deal with complex natural language in computer.
-Used in many natural language processing applications such as speech recognition, machine translation, part-of-speech tagging, parsing and information retrieval.
**Types:
i-Unigram models
-Used in information retrieval
-It splits the probabilities of different terms in a context, e.g. from P(t1t2t3) = P(t1)P(t2 | t1)P(t3 | t1t2) to Puni(t1t2t3) = P(t1)P(t2)P(t3).
-The probability to hit each word all depends on its own, so we only have one-state finite automations as units.
-For each automation, we only have one way to hit its only state, assigned with one probability. Viewing from the whole model, the sum of all the one-state-hitting probabilities should be 1.
-In information retrieval contexts, unigram language models are often smoothed to avoid instances where P(term) = 0.


ii-N-Gram Language Model:
-The goal of a language model is to determine the probability of a word sequence.
-In n-gram language models, we condition the probability of a word on the identity of the last (n −1) words.
-The choice of n is based on a trade-off between detail and reliability, and will be dependent on the available quantity of training data.
-Most widely used and many tools exist to generate this model.
We used:
SRILM
http://www-speech.sri.com/projects/srilm/
NGramTool
URL: http://www.nlplab.cn/zhangle/ngram.html

**N-Gram Format = ARPA: SRILM format (standard format) SYNOPSIS:
\data\
ngram 1=n1
ngram 2=n2
...
ngram N=nN
\1-grams:
p w [bow]
...
\2-grams:
p w1 w2 [bow]
...
\N-grams:
p w1
... wN ...
\end

-DESCRIPTION
The so-called ARPA (or Doug Paul) format for N-gram backoff models starts with a header, introduced by the keyword \data\, listing the number of N-grams of each length. Following that, N-grams are listed one per line, grouped into sections by length, each section starting with the keyword \N-gram:, where N is the length of the N-grams to follow.
Each N-gram line:
Starts with the logarithm (base 10) of conditional probability p of that N-gram
Followed by the words w1...wN making up the N-gram.
These are optionally followed by the logarithm (base 10) of the backoff weight for the N-gram.
The keyword \end\ concludes the model representation.
Note : Backoff weights are required only for those N-grams that form a prefix of longer N-grams in the model. The highest-order N-grams in particular will not need backoff weights (they would be useless). (so in our example 3-gram won’t have it , but 1st, 2nd gram will have it)
Important Tags:
start sentence marker
end sentence marker
class of unknown words


**Generation:
Using SRLIM and We will use tri-gram model:
For Arabic: (Arbaic to English translation)
ngram-count -order 3 -interpolate -kndiscount -unk -text training.en -lm lm/english.lm
For English: (English to Arabic translation)
ngram-count -order 3 -interpolate -kndiscount -unk -text training.ar -lm lm/arabic.lm



d) Translation Model:
Using Moses: (Arabic to English)
nohup nice train-model.perl -scripts-root-dir /usr/share/moses/scripts/ -root-dir /mnt/xp -corpus training -f ar -e en -alignment grow-diag-final-and -reordering msd-bidirectional-fe -lm 0:3:/mnt/xp/lm/english.lm &>training.out
Will take time so we sent it to the background.
Training will be completed once the training.out file show the statement:
(9) create moses.ini @ Mon Nov 7 14:26:51 EET 2011

Using Moses: (English to Arabic)
nohup nice train-model.perl -scripts-root-dir /usr/share/moses/scripts/ -root-dir /mnt/xp -corpus training -f en -e ar -alignment grow-diag-final-and -reordering msd-bidirectional-fe -lm 0:3:/mnt/xp/lm/arabic.lm &>training.out
Will take time so we sent it to the background.(if you are using 5-gram change 0:3 into 0:5
Training will be completed once the training.out file show the statement:
(9) create moses.ini @ Mon Nov 7 19:28:37 EET 2011

**This generate a lot of files consist the translation model like phrase table , re-order tables, configuration tables, ...etc.

Example of phrase tables:


** moses.ini describe the whole model parts, looks like:
#########################
### MOSES CONFIG FILE ###
#########################
[ttable-file]
0 0 0 5 /mnt/xp/model/phrase-table.gz
# language models: type(srilm/irstlm), factors, order, file
[lmodel-file]
0 0 3 /mnt/xp/lm/english.lm
# distortion (reordering) files
[distortion-file]
0-0 wbe-msd-bidirectional-fe-allff 6 /mnt/xp/model/reordering-table.wbe-msd-bidirectional-fe.gz
…….
…….
…….
…….

e) Validate The Generated Models:
echo “resolution” | TMP=/tmp moses –f model/moses.ini
….
….
….
Best Translation: القرار [1] [Total=-8.393]

f) Test The Model:
Using moses:
moses -config model/moses.ini -input-file test.en 1>output1.out 2> output2.out &
Keep monitor the output files or ps until the process execution end.

First output file , contain the translated file:
Example of content:
62 / 174 . معهد الأمم المتحدة الأفريقي منع الجريمة ومعاملة المجرمين
الجمعية العامة
تشير قرارها 61 / 182 المؤرخ 20 كانون 2006 وسائر قرارات ،
وإذ الأميــن ،
مراعاة بالحاجة الملحة إنشاء فعالة استراتيجيات منع الجريمة لأفريقيا وكذلك أهمية إنفاذ القوانين و القضائي الإقليمي ودون الإقليمي ،
مراعاة أيضا ) الفترة 2006-2010 ، الذي أقره اجتماع المائدة المستديرة لأفريقيا في أبوجا يومي 5 ( 6 أيلــول 2005

g) Evaluation Of The Translation:
-Re-case : Not needed in Arabic (need train the re-caser 1st)
-Detokenize the output:
detokenizer.perl -l en < first.out > first.detokenized
-Wrap output in XML file:
wrap-xml.perl data/devtest/nc-test2007-ref.en.sgm en osama-oransa < first.detokenized > output.sgm
-Score the translation:
mteval-v12b.pl -s test.en.sgm -r test.ar.sgm -t output.ar.sgm -c

Results:
Evaluation of en-to-ar translation using:
src set “un" (1 docs, 2007 segs)
ref set "nc-test2007" (1 refs)
tst set "nc-test2007" (1 systems)

NIST score = 9.1469 BLEU score = 0.6776 for system “osama-oransa"

** Manual sgm wrapping:
-Remove “ to avoid excel issues.
-Use excel to add <seg id=“1...n”>statement</seg> for each line.
*Source test data: (test.en.sgm)
Header:
<srcset setid="un" srclang="en">
<doc docid="un-test" genre="wb" origlang="en">
Footer:
</doc></srcset>
*Target test data: (test.ar.sgm)
Header:
<refset trglang="ar" setid="un" srclang="en">
<doc sysid=“osama-oransa" docid="un-test" genre=“wb" origlang="en">
*Result test data: (output.ar.sgm)
Header:
<tstset trglang="ar" setid="un" srclang="en">
<doc sysid=“osama-oransa" docid="un-test" genre=“wb" origlang="en">
You could have multiple doc(s) in the same set (src, ref, tst) each with unique id.
You could wrap each few <seg> with <p>…</p>


5) References:
-Moses step by step: http://www.statmt.org/moses_steps.html
-Wikipedia: http://en.wikipedia.org/wiki/Language_model
-Joshua step by step: http://cs.jhu.edu/~ccb/joshua/
-Evaluation plan : BLEU scoring reference: http://www.itl.nist.gov/iad/mig/tests/mt/2009/MT09_EvalPlan.pdf

Tuesday, January 10, 2012

Overview of my Open Source Projects



Thanks God, I have completed posting 12 open source projects since April 2010, all the projects are hosted on SourceForgue , here is the list of these projects and links to them, all these projects are described in details in a separate blog post for each project.

1) Free Instant Messenger
SourceForgue Project click Here.
My blog post click Here.

2) Hidden Parent Eye
SourceForgue Project click Here.
My blog post click Here.

3) Interactive Calculator
SourceForgue Project click Here.
My blog post click Here.

4) Java Home Monitor
SourceForgue Project click Here.
My blog post click Here.

5) Java Web Chat
SourceForgue Project click Here.
My blog post click Here.

6) Dynamic Parser
SourceForgue Project click Here.
My blog post click Here.

7) Java Simple Interactive Browser
SourceForgue Project click Here.
My blog post click Here.

8) Secure End-To-End Chat
SourceForgue Project click Here.
My blog post click Here.

9) Interactive4J
SourceForgue Project click Here.
My blog post click Here.

10) Log Filter Utility
SourceForgue Project click Here.
My blog post click Here.

11) Balloon Gamehttp://www.blogger.com/img/blank.gif
SourceForgue Project click Here.
My blog post click Here.

12) Java Online Exam System
SourceForgue Project click Here.
My blog post click Here.

Monday, January 9, 2012

Java Online Exam System

I have posted a new open source project on sourceforge.net

Overview:
Online examination system using JEE where system can be customized to work in universities , schools and companies (interview tool).

URL:
http://sourceforge.net/projects/online-exam4j/

Features:
- Online Customizable Examination System.
- Auto-submit when time ends up.
- Support single selection and multiple selection.
- Easy navigation.
- Support text and Image-based questions.
- Configurable (even question per page, email sending, ...)
- Send emails to examine and examiner according to configurations.
- Auto-submit when time ends up.
- Work well with IE and FF and other browsers.
- Work well with page reload/refresh (no answers/timer lost)
- Used Ajax for better efficiency.
- Voucher based system (can be renewed after expired)
- Audit user actions.
- No admin interface currently and uses Query Browser of MySQL instead.
- Support pauses for 5 min.
- Support UTF8 for all languages.

How To Run:
1-Import DB schema into MySQL DB.
2-Open the DB "Exam" schema, do few changes in Config table per your custom data.
3-Deploy the WAR file into Glassfish V3 server (you may need to create the DataSource but mostly you won't need this step).
4.Test the application using : valid vouchers: 123456 or 123455
Application URL would looks like:

http://localhost:8080/ExamSystem/

-localhost and port could differ according to your server IP and port.


Future Work:
-Add admin interface.
-Support Voucher Types (each voucher for a dedicated exam).
-Support report and print certificate/report/exam.
-Statistical analysis of the exam data.


Screen shots:

Main Exam Screen :



Text Based Questions :




Image-Based Questions :



Navigation :



Pause Screen :



Help Screen :