Thursday, March 8, 2012

Number Formatter in JAVASCRIPT

Hi friends,

When we want to format, type cast and convert numbers in JAVASCRIPT with multilingual support, there are none. So came out with this.

This supports European & English both kind of number formatting. While using this, just set the basic 3 variables.

Save the code with any name, say NumberFormatter.js then call like this with jQuery

jQuery.getScript(
{
  url: 'NumberFormatter.js',
  dataType: "script",
  success: function(){
NumberFormatter._tSep = '<get the data from user profile with server side code&gt>';
               NumberFormatter._dSep = '<get the data from user profile with server side code>';
               NumberFormatter.DEFAULT_PRECISION = <get the data from user profile with server side code>; 
}
}
);



 The code for Javascript file starts from here....

String.prototype.trim = function() { return this.replace(/^\s+|\s+$/g, ""); };

function NumberFormatter(){}

NumberFormatter._tSep = ',';
NumberFormatter._dSep = '.';
NumberFormatter.DEFAULT_PRECISION = 2;
NumberFormatter.IS_STRICT_THOUSAND_SEPARATOR_VALIDATION = false;

NumberFormatter.setThousandSeparator = function(tSep){
    NumberFormatter._tSep = tSep;
}

NumberFormatter.setDecimalSeparator = function(dSep){
    NumberFormatter._dSep = dSep;
}

NumberFormatter.getInteger = function(num2Get){
    return NumberFormatter.parseNumber(num2Get, true);
}

NumberFormatter.getDecimal = function(num2Get, decimalPrecision){
    return NumberFormatter.parseNumber(num2Get, false, decimalPrecision);
}

/**
 * this function is to be used before sending
 * to server side.
 */
NumberFormatter.parseNumber = function(num2Get, isNumberOnly, a_decimalPrecision){
    if(num2Get == ""){
        return "";
    }
    var tSep = NumberFormatter._tSep;
    var dSep = NumberFormatter._dSep;
    var parts = (num2Get + "").split(dSep);
    var firstPart = parts[0];
    var decPrec = (typeof(a_decimalPrecision) != "undefined"  && !isNaN(a_decimalPrecision) && a_decimalPrecision >= 0) ? a_decimalPrecision : NumberFormatter.DEFAULT_PRECISION;
    var secondPart = parts.length > 1 ? parts[1] : "00";  
    if(secondPart.trim() == ""){
        secondPart = "00";
    }
  
    var tSepIndex = firstPart.indexOf(tSep);
    while(tSepIndex >= 0){
        firstPart = firstPart.replace(tSep, "");
        tSepIndex = firstPart.indexOf(tSep, tSepIndex);
    }
    if(isNumberOnly){
        return parseInt(firstPart);
    }else{
        if(isNaN(firstPart) || isNaN(secondPart))
        {
            return NaN;
        }  
        //alert(Math.round(parseFloat(firstPart + "." + secondPart)*Math.pow(10,decPrec))/Math.pow(10,decPrec));
        return Math.round(parseFloat(firstPart + "." + secondPart)*Math.pow(10, decPrec)) / Math.pow(10, decPrec);
    }
}

function roundVal(val, decPrec){
    var result = Math.round(val * Math.pow(10, decPrec)) / Math.pow(10, decPrec);
    return result;
}

/**
 * please do not use this, use the formatDecimal instead
 *
 * @deprecated
 */
NumberFormatter.formatNumber = function(num2Format){
    return NumberFormatter.formatDecimal(num2Format, true);
}

NumberFormatter.formatDecimal = function(num2Format, isNumberOnly, a_decimalPrecision){
    if(isNaN(num2Format)){
        return num2Format;
    }
  
    if(!isFinite(num2Format)){
        return num2Format;
    }
  
    if(typeof(num2Format) == 'number'){
        num2Format = num2Format.toString();
    }
  
    if(num2Format == ""){
        return "";
    }
  
    var tSep = NumberFormatter._tSep;
    var dSep = NumberFormatter._dSep;
    var decPrec = (typeof(a_decimalPrecision) != "undefined" && !isNaN(a_decimalPrecision) && a_decimalPrecision >= 0) ? a_decimalPrecision : NumberFormatter.DEFAULT_PRECISION;
    var formattedNum = parseFloat(num2Format).toFixed(decPrec);
    var isMinus = formattedNum < 0;
    var parts = String(Math.abs(formattedNum)).split('.');
    var firstPart = parts[0];
    var secondPart = parts.length > 1 ? parts[1] + NumberFormatter.getLeading0s(decPrec - parts[1].length) : NumberFormatter.getLeading0s(decPrec);
    if(firstPart.length <= 3){      
        if(isMinus){
            firstPart = "-" + firstPart;
        }
      
        if(decPrec > 0 && !isNumberOnly) {
            return (firstPart + dSep + secondPart);
        }
      
        return firstPart;                  
    }
  
    var newStr = "";
    for(var i = firstPart.length - 1; i >= 0; i--){
        newStr = firstPart.charAt(i) + newStr ;
        if(i == firstPart.length - 1){
            continue;
        }
        if(i == 0){
            continue;
        }
        var d = (firstPart.length - i) / 3;
        if(Math.ceil(d) == Math.floor(d)){
            newStr = tSep + newStr;
        }
    }
    if(isMinus){
        newStr = "-" + newStr;
    }
    if(isNumberOnly){
        return newStr;
    }
    return newStr + (decPrec > 0 ? (dSep + secondPart) : "");
}

NumberFormatter.validateInput = function(inputText, isNumberOnly, isToAllowNegetive, isMandatory, a_decimalPrecision){
    if(typeof(inputText) == 'number'){
        inputText = inputText.toString();
    }
  
    var returnObject = new Object();
    var decPrec = (typeof(a_decimalPrecision) != "undefined"  && !isNaN(a_decimalPrecision) && a_decimalPrecision >= 0) ? a_decimalPrecision : NumberFormatter.DEFAULT_PRECISION;
  
    //lets test blank input
    if(isMandatory && String(inputText).trim().length <= 0){
        returnObject.message = "BLANK_INPUT";
        returnObject.isValid = false;
        return returnObject;
    }
  
    //no white space is allowed
    if(inputText.indexOf(" ") >= 0){
        returnObject.message = "WHITE_SPACE_IN_INPUT";
        returnObject.isValid = false;
        return returnObject;
    }
  
    //check valid chars
    var ln = inputText.length;
    for(var iCounter = 0; iCounter < ln; iCounter++){
        var currentChar = inputText.charAt(iCounter);
        //if the first char is minus then let it go
        if(isToAllowNegetive && iCounter == 0 && currentChar == '-'){
            continue;
        }
        if(isValidChar(currentChar) == false){
            returnObject.message = "INVALID_CHARACTER_IN_INPUT";
            returnObject.isValid = false;
            return returnObject;
        }
    }
  
    if(isNumberOnly && inputText.indexOf(NumberFormatter._dSep) >= 0){
        returnObject.message = "DECIMAL_NOT_ALLOWED";
        returnObject.isValid = false;
        return returnObject;
    }
  
    var firstChar = inputText.charAt(0);
    var lnToTest = inputText.split(NumberFormatter._tSep).join("").length;
    if(firstChar == '-'){
        lnToTest = lnToTest - 1;
    }
    if(lnToTest > 15){
        returnObject.message = "TOO_LONG_INPUT";
        returnObject.isValid = false;
        return returnObject;
    }
  
    //check single decimal separator
    var parts = inputText.split(NumberFormatter._dSep);              
    if(parts.length > 2){
        returnObject.message = "MULTIPLE_DECIMAL_SEPARATOR";
        returnObject.isValid = false;
        return returnObject;
    }
  
    var firstPart = parts[0];
    var secondPart = parts[1];
  
    //in the decimal part there can not be thousand separator
    if(secondPart!= null && secondPart.length > 0 && secondPart.indexOf(NumberFormatter._tSep) >= 0){
        returnObject.message = "THOUSAND_SEPARATOR_IN_DECIMAL_PART";
        returnObject.isValid = false;
        return returnObject;
    }
  
    if(NumberFormatter.IS_STRICT_THOUSAND_SEPARATOR_VALIDATION){
        var thousandParts = firstPart.split(NumberFormatter._tSep);
        for(var iCounter = thousandParts.length - 1; iCounter > 0; iCounter--){
            if(thousandParts[iCounter].length != 3){
                returnObject.message = "INVALID_POSITIONING_OF_THOUSAND_SEPARATOR";
                returnObject.isValid = false;
                return returnObject;
            }
        }
    }
  
    /*if(secondPart.length > decPrec){
        returnObject.message = "TOO_LONG_DECIMAL_PART";
        returnObject.isValid = false;
        return returnObject;
    }*/
  
    returnObject.message = "VALID_NUMBER";
    returnObject.isValid = true;
    return returnObject;
}

NumberFormatter.formatCurrency = function(num2Format){
    return NumberFormatter.formatDecimal(num2Format);
}

NumberFormatter.getLeading0s = function(decPrec) {
    var s0s=[];
    for(var i = 0; i < decPrec; i++) {
        s0s.push('0');
    }
    return s0s.join('');
}

function isValidChar(charToTest){
    switch(charToTest){
        case '0':
            return true;
        case '1':
            return true;
        case '2':
            return true;
        case '3':
            return true;
        case '4':
            return true;
        case '5':
            return true;
        case '6':
            return true;
        case '7':
            return true;
        case '8':
            return true;
        case '9':
            return true;
        case '.':
            return true;
        case ',':
            return true;
        default:
            return false;
    }  
}



Hope this will help you all. So long till next time...



Saturday, November 12, 2011

Java Hibernate Multiple Map into One Table

Hi Friends,

Recently I was trying to do something different. I could not find exact solution what I was looking for. Thus sharing here. Some one else might be benefited by this.

Now I will get straight to the point. First the problem statement:

I have a Java class like this


import java.io.Serializable;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

import org.apache.log4j.Logger;

/**
 * @author: Aniruddha Dutta Chowdhury

 *
 */
public class HibernateDemo implements Serializable {
    private static Logger        logger            = Logger.getLogger(HibernateDemo.class);

    private Map    requestData        = new HashMap();
    private Map    contextData        = new HashMap();
    private Map    responsetData    = new HashMap();
    private Date                timeOfAction    = null;
    private Long                id                = null;
   
    public Map getResponsetData() {
        return responsetData;
    }
   
    public void setResponsetData(Map responsetData) {
        this.responsetData = responsetData;
    }

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public Date getTimeOfAction() {
        return timeOfAction;
    }

    public void setTimeOfAction(Date timeOfAction) {
        this.timeOfAction = timeOfAction;
    }

    public Map getRequestData() {
        return requestData;
    }

    public void setRequestData(Map requestData) {
        this.requestData = requestData;
    }

    public Map getContextData() {
        return contextData;
    }

    public void setContextData(Map contextData) {
        this.contextData = contextData;
    }

    public Map getResponseData() {
        return responseData;
    }

    public void setResponseData(Map responseData) {
        this.responseData = responseData;
    }

    private Map    responseData    = new HashMap();
}


And I wanted only two tables for this whole class. One for the main class and another one for all the map members.

Desired tables are as follows:


MAIN_TABLE
ID PK
ACTION_TIME


AND the child table would be


CHILD_TABLE
PARENT_ID FK
KEY
VALUE
DISCRIMINATOR

Now this is not a big deal for hibernate. Using the where clause. But the question comes that how to fill the value for discriminator. Then after going through hibernate api I came up with this. The SQL-INSERT is really very handy in this case.

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping
    PUBLIC "-//Hibernate/Hibernate Mapping DTD//EN"
    "http://hibernate.sourceforge.net/hibernate-mapping-2.0.dtd">
<hibernate-mapping>
    <class name="HibernateDemo" table="MAIN_TABLE">
        <id name="id">
            <generator class="native" />
        </id>
        <property name="timeOfAction" />
        <map name="requestData" table="CHILD_TABLE" where="DISCRIMENATOR='REQUEST'">       
            <key column="PARENT_ID" />
            <index column="KEY" type="string" />
            <element column="VALUE" type="string" />
            <sql-insert>insert into CHILD_TABLE (PARENT_ID, KEY, VALUE, DISCRIMENATOR) values (?, ?, ?, 'REQUEST')</sql-insert>
        </map>
       
        <map name="contextData" table="CHILD_TABLE" where="DISCRIMENATOR='CONTEXT'">       
            <key column="PARENT_ID" />
            <index column="KEY" type="string" />
            <element column="VALUE" type="string" />
            <sql-insert>insert into CHILD_TABLE (PARENT_ID, KEY, VALUE, DISCRIMENATOR) values (?, ?, ?, 'CONTEXT')</sql-insert>
        </map>
       
        <map name="responsetData" table="CHILD_TABLE" where="DISCRIMENATOR='RESPONSE'">       
            <key column="PARENT_ID" />
            <index column="KEY" type="string" />
            <element column="VALUE" type="string" />
            <sql-insert>insert into CHILD_TABLE (PARENT_ID, KEY, VALUE, DISCRIMENATOR) values (?, ?, ?, 'RESPONSE')</sql-insert>
        </map>
    </class>
</hibernate-mapping>



Hope this will help you. Till next time, BYE.

Sunday, September 25, 2011

Start command prompt from context menu in windows

Hi folks,

Again another techie blog.

 This is to solve a simple problem we all face quite often in our daily life. Mainly QA person and developers face this. For getting Command prompt from any opened folder we have to open command prompt then copy the path then paste and ...... long process... Huh..

So here is a simple solution, copy the following text in a .reg file and save that. Now run it once, In some secured system it may ask for admin rights, as it will update the registry. But no worry, just allow it. After that on any right click of any folder will give u an option to open command prompt from there.

Windows Registry Editor Version 5.00

[HKEY_CLASSES_ROOT\Directory\shell\startCmd]
@="Start Command Prompt From Here"
"@author"="Aniruddha Dutta Chowdhury"

[HKEY_CLASSES_ROOT\Directory\shell\startCmd\command]
@="cmd /k pushd \"%1\""

Saturday, August 27, 2011

Apache log4j queue appender

Hi friends,

Starting another techie post. This is regarding apache log4j appenders. I was using log4j for quite some time. It is excellent one. It has got almost everything required for normal to advanced logging, except if we use it extensively then the application tends to slow down a bit, like if we use the mail and DB appender then the application slows down. Thats not a fault of the system. It will slow down. To solve this we have JMS appender. put every thing in the JMS queue and then read from there and again resend to respective appender. In this we have a small catch. That is, the utility have the JMS appender but it does not have a reader. and to avail this we need to be on J2EE container.

So to solve this I just made one small class which can take care of this situation. This is having a internal JDK5 queue and reader as well. So application does not slows down and all kind of logging we can do.


The Java class:

import java.util.Enumeration;
import java.util.Queue;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadFactory;

import org.apache.log4j.Appender;
import org.apache.log4j.AppenderSkeleton;
import org.apache.log4j.LogManager;
import org.apache.log4j.Logger;
import org.apache.log4j.spi.LoggingEvent;

/**
 * @author: Aniruddha Dutta Chowdhury
 * @since: 11-Aug-2011 : 4:35:01 PM
 */

public class QuedAppender extends AppenderSkeleton {

    private Appender[]            targetAppender        = null;
    private String                adapter                = null;
    private Queue    loggingEventQueue    = null;
    private boolean                isActive            = false;
    private Executor            executor            = null;

    public QuedAppender() {
        loggingEventQueue = new ConcurrentLinkedQueue();
        System.out.println("QuedAppender.QuedAppender()");
        startQueueCheck();
    }

    private void startQueueCheck() {
        Thread l_th = new Thread(new Runnable() {
            @Override
            public void run() {
                callTargetAppender();
            }
        });
        // l_th.setDaemon(true);
        l_th.setName("QuedAppenderChecker");
        l_th.start();
    }

    public void setQueueSize(String a_queueSize) {
        try {
            executor = Executors.newFixedThreadPool(Integer.parseInt(a_queueSize), new ThreadFactory() {

                @Override
                public Thread newThread(Runnable r) {
                    Thread l_th = new Thread(r);
                    l_th.setDaemon(true);
                    return l_th;
                }
            });
        } catch (NumberFormatException a_numberFormatExceptionIgnore) {
        }
    }

    public String getTargetAppender() {
        return adapter;
    }

    public void setTargetAppender(String a_adapter) {
        // System.out.println("QuedAppender.setTargetAppender(" + a_adapter +")");
        if (targetAppender != null) {
            return;
        }

        adapter = a_adapter;
        String[] l_appenders = adapter.split(",");
        targetAppender = new Appender[l_appenders.length];
        int iCounter = 0;
        for (String l_ap : l_appenders) {
            targetAppender[iCounter] = getAppenderById(l_ap.trim());

            if (targetAppender[iCounter] == null) {
                targetAppender = null;
                return;
            }
            iCounter++;
        }
        // targetAppender = getAppenderById(a_adapter);
    }

    public static Appender getAppenderById(String a_strAppenderName) {
        Logger logger = LogManager.getLogger("app.logger.DummyLogger");
        Appender l_targetAppender = logger.getAppender(a_strAppenderName);
        return l_targetAppender;
    }

    private static void printAllAppenders() {
        Enumeration allLoggers = LogManager.getCurrentLoggers();
        while (allLoggers.hasMoreElements()) {
            Logger l = (Logger) allLoggers.nextElement();
            Enumeration appernders = l.getAllAppenders();
            while (appernders.hasMoreElements()) {
                Appender l_ap = (Appender) appernders.nextElement();
                System.out.println("QuedAppender.getAppenderById()" + l_ap.getName());
            }
        }
    }

    @Override
    protected void append(LoggingEvent loggingEvent) {
        if (executor == null) {
            setQueueSize("5");
        }

        if (targetAppender == null) {
            setTargetAppender(adapter);
        }

        if (targetAppender == null || targetAppender.length <= 0) {
            throw new RuntimeException("Target appender is properly not initialised. Please do that first before you start this");
        }

        System.out.println("QuedAppender.append(" + loggingEvent.getLoggerName() + ")");
        loggingEventQueue.offer(loggingEvent);

        try {
            Thread.sleep(100);
        } catch (Throwable a_th) {
        }

        startQueueCheck();
    }

    /**
     * nothing much to do, so just keep it like this
     */
    @Override
    public void close() {
    }

    @Override
    public boolean requiresLayout() {
        return false;
    }

    private void callTargetAppender() {
        LoggingEvent loggingEvent = null;

        /**
         * check is already running then just ignore it
         */
        if (isActive) {
            return;
        }

        /**
         * now mark as this method in action
         */
        isActive = true;

        while ((loggingEvent = loggingEventQueue.poll()) != null) {
            executor.execute(new TargetLogger(loggingEvent, targetAppender));
            try {
                Thread.sleep(100);
            } catch (Throwable a_th) {
            }
        }

        /**
         * lets set it false for others to access
         */
        isActive = false;
    }

    private class TargetLogger implements Runnable {
        private LoggingEvent    loggingEvent    = null;
        private Appender[]        targetAppenders    = null;

        public TargetLogger(LoggingEvent loggingEvent, Appender[] a_targetAppenders) {
            this.loggingEvent = loggingEvent;
            targetAppenders = a_targetAppenders;
        }

        @Override
        public void run() {
            for (Appender targetAppender : targetAppenders) {
                if (((AppenderSkeleton) targetAppender).getThreshold() == null || ((AppenderSkeleton) targetAppender).getThreshold().toInt() <= loggingEvent.getLevel().toInt()) {
                    targetAppender.doAppend(loggingEvent);
                }
            }
        }
    }
}

The Sample Log4j.properties:

log4j.rootLogger=DEBUG,quedAppender

#a dummy logger to initialized, so that all appenders can be loaded
log4j.logger.app.logger.DummyLogger=DEBUG,sendMail,CA,FA

log4j.appender.sendMail=org.apache.log4j.net.SMTPAppender
log4j.appender.sendMail.Threshold=ERROR
log4j.appender.sendMail.To=to@target.com
log4j.appender.sendMail.From=from@source.com
log4j.appender.sendMail.SMTPHost=smtp.source.com
log4j.appender.sendMail.Subject=iSource @ on []
log4j.appender.sendMail.layout=org.apache.log4j.PatternLayout
log4j.appender.sendMail.layout.ConversionPattern=[%d{ISO8601}]%n%n%-5p%n%n%c%n%n%m%n%n
log4j.appender.sendMail.BufferSize=1
#log4j.appender.sendMail.SMTPDebug=true

log4j.appender.quedAppender=QuedAppender
log4j.appender.quedAppender.Threshold=DEBUG
log4j.appender.quedAppender.targetAppender=sendMail, CA, FA

log4j.appender.RquedAppender=QuedAppender
log4j.appender.RquedAppender.Threshold=DEBUG
log4j.appender.RquedAppender.targetAppender=FA

#Console Appender
log4j.appender.CA=org.apache.log4j.ConsoleAppender
log4j.appender.CA.layout=org.apache.log4j.PatternLayout
log4j.appender.CA.layout.ConversionPattern=%-4r [%t] %-5p %c %x - %m%n
log4j.appender.CA.Threshold=DEBUG

#File Appender
log4j.appender.FA=org.apache.log4j.FileAppender
log4j.appender.FA.File=sample.log
log4j.appender.FA.layout=org.apache.log4j.PatternLayout
log4j.appender.FA.layout.ConversionPattern=%-4r [%t] %-5p %c %x - %m%n
log4j.appender.FA.Threshold=INFO

In this sample log4j.properties the dummy logger is required for finding all required appender. I could not come up with any other mechanism.

If any one has any suggestion or modification proposal, please put forward. I would be glad to know that.

Monday, April 26, 2010

Print text in pattern



This program scans pixels and prints accordingly. It will work with any font. For better output please use bigger size
Few examples this would be as font, I just made image to see properly in web.





import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.image.BufferedImage;
import java.awt.image.PixelGrabber;
import java.util.ArrayList;
import java.util.List;

public class FontAlgo {
      private static final char           CHAR_TO_PATTERN   = '@';
      private static final int            WIDTH             = 50;
      private static final int            HEIGHT            = 50;
      private static final boolean        isReverse         = true;
      private static final Font           appliedFont       = new Font("Couirer new", Font.BOLD, 20);

      private static TextualChar getTextualChar(char a_char) throws Throwable {
            BufferedImage bImg = new BufferedImage(WIDTH, HEIGHT, BufferedImage.TYPE_INT_RGB);
            Graphics g = bImg.getGraphics();
            g.setColor(Color.green);
            g.fillRect(0, 0, WIDTH, HEIGHT);

            g.setFont(appliedFont);
            g.setColor(Color.black);
            g.drawString(new String(new char[] { a_char }), 10, g.getFontMetrics().getHeight());
            PixelGrabber p = new PixelGrabber(bImg, 0, 0, WIDTH, HEIGHT, true);

            if (p.grabPixels()) {
                  char[][] pattern = new char[WIDTH][HEIGHT];
                  int baseColourPixel = 0, contrastColourPixel = 0, x1 = 0, x2 = 0, y1 = 0, y2 = 0;
                  int[] pixels = (int[]) p.getPixels();
                  baseColourPixel = pixels[0];
                  // System.out.println("base: " + base);
                  int xCounter = 0, yCounter = 0;
                  for (int iPixel : pixels) {
                        // System.out.println(iX + " - " + iY);
                        if (isReverse) {
                              pattern[xCounter][yCounter] = iPixel == baseColourPixel ? CHAR_TO_PATTERN : ' ';
                        } else {
                              pattern[xCounter][yCounter] = iPixel != baseColourPixel ? CHAR_TO_PATTERN : ' ';
                        }

                        yCounter++;
                        if (yCounter > 49) {
                              xCounter++;
                              yCounter = 0;
                        }

                        if (contrastColourPixel == 0 && iPixel != baseColourPixel) {
                              contrastColourPixel = iPixel;
                              x1 = xCounter - 2;
                              y1 = yCounter - 3;
                              y2 = yCounter + 3;
                        }

                        if (contrastColourPixel == iPixel) {
                              x2 = xCounter + 3;

                              if (y1 > (yCounter - 3)) {
                                    y1 = yCounter - 3;
                              }

                              if (y2 < (yCounter + 3)) {
                                    y2 = yCounter + 3;
                              }
                        }
                  }
                  return new TextualChar(x1, x2, y1, y2, pattern);
            }
            return null;
      }

      private static List getTexualChars(String strText) throws Throwable {
            List returnList = new ArrayList();
            for (byte lbyte : strText.getBytes()) {
                  TextualChar tChar = getTextualChar((char) lbyte);
                  returnList.add(tChar);
            }
            return returnList;
      }

      public static void main(String[] args) throws Throwable {
            List textualCharList = getTexualChars("Ayantika");

            TextualChar tChar1 = textualCharList.get(0);
            int endPos = tChar1.getxPos2();
            for (int iCounter = tChar1.getxPos1(); iCounter < endPos; iCounter++) {

                  for (TextualChar tChar : textualCharList) {
                        if (endPos < tChar.getxPos2()) {
                              endPos = tChar.getxPos2();
                        }
                        for (int iInnerCounter = tChar.getyPos1(); iInnerCounter < tChar.getyPos2(); iInnerCounter++) {
                              System.out.print(tChar.getPixelPattern()[iCounter][iInnerCounter]);
                        }
                  }
                  System.out.println();
            }
      }

      static class TextualChar {
            private int             xPos1             = 0;
            private int             xPos2             = 0;

            private int             yPos1             = 0;
            private int             yPos2             = 0;

            private char[][]  pixelPattern      = new char[WIDTH][HEIGHT];

            public TextualChar(int xPos1, int xPos2, int yPos1, int yPos2, char[][] a_pattern) {
                  this.xPos1 = xPos1;
                  this.xPos2 = xPos2;
                  this.yPos1 = yPos1;
                  this.yPos2 = yPos2;
                  this.pixelPattern = a_pattern;
            }

            public char[][] getPixelPattern() {
                  return pixelPattern;
            }

            public int getxPos1() {
                  return xPos1;
            }

            public int getxPos2() {
                  return xPos2;
            }

            public int getyPos1() {
                  return yPos1;
            }

            public int getyPos2() {
                  return yPos2;
            }
      }
}