Friday, May 24, 2013

PC Show 2013

2 more weeks to PC Show and I think I need to get quite a lot of electronics gadget from this show.

Details of the upcoming PC Show as follows:
6 - 9 June
Singapore Expo Hall 5 & 6
12noon - 9pm daily

* Click here to find out more about 'PC Show 2013'.
^ Click here for some useful tips in finding your way around the upcoming 'PC Show'.

Friday, May 17, 2013

Charles: Tampering Data

Being a developer or user, there might be numerous situations where you are going to send/fecth some data to a web service. And there might be numerous situations where there's a need to tamper some of the data. Therefore...

'Charles'
Click here to download and install 'Charles' before moving on to the next step.

Step 1 - Open up the website that you are going to tamper
and also run the 'Charles' application.

Step 2 - Right Click on the domain that you are going to
tamper in 'Charles'.

Step 3 - Make sure that the option 'Breakpoints' have
been selected on the Right-Click Menu.

Step 4 - As you send an request out to the domain, the you will be
given the option of tampering the request under the 'Breakpoints'
tab in 'Charles'. Remember to click on the 'Execute' button to send
out the tampered request.

Step 4.1 - As you receive some data from the domain, you can also
tamper the data too. It will also appear under the 'Breakpoints'
tab in 'Charles'. Similar to the previous step you will also need
to click on the 'Execute' button to fetch the tampered response.

By the way, if it is a Request, the tab 'Edit Request' will be shown
and the tab 'Edit Response' will be shown for a Response.

Enjoy playing with all the tampered data.

Friday, May 10, 2013

Flex: Stacking Column Chart

There might be a situation where you would want to stack 2 different set of column data together. (For example, you are managing a toys department and you wanted to show the total of the number of toy cars and toy aeroplane that you have sold on that day. On top of that, you also want to find out the breakdown of the number of toy cars and toy aeroplanes that you have sold that particular day.) So how to stack all the column data together? Here's a simple example that I have created.

Here's the source code of my main application - SimpleStackingColumn.mxml
<?xml version="1.0" encoding="utf-8"?>
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009" 
      xmlns:s="library://ns.adobe.com/flex/spark" 
      xmlns:mx="library://ns.adobe.com/flex/mx"
      backgroundColor="#CDCDCD"
      creationComplete="creationCompleteEvent(event)"> 
 <fx:Declarations>
  <!-- 
  We need to specify the types of animations over here
  -->
  <s:Parallel id="parallelEffect">
   <s:Fade duration="1000" alphaFrom="0" alphaTo="1"/>
   <mx:SeriesSlide duration="1000" direction="up"/>
  </s:Parallel>
  <s:Parallel id="parallelCarEffect">
   <s:Fade duration="1000" alphaFrom="0" alphaTo="1"/>
  </s:Parallel>
 </fx:Declarations>
 <fx:Script>
  <![CDATA[
   import flashx.textLayout.conversion.TextConverter;
   
   import mx.charts.HitData;
   import mx.charts.chartClasses.IChartElement2;
   import mx.charts.chartClasses.Series;
   import mx.charts.series.ColumnSeries;
   import mx.charts.series.LineSeries;
   import mx.collections.ArrayCollection;
   import mx.collections.Sort;
   import mx.collections.SortField;
   import mx.events.FlexEvent;
   import mx.formatters.DateFormatter;
   import mx.graphics.Stroke;
   
   import spark.events.IndexChangeEvent;
   
   //Records used in the chart
   [Bindable]
   private var myData:XML = 
    <records> 
     <record>
      <date>01/09/2013</date>
      <people>63</people>
      <car>23</car>
     </record>
     <record>
      <date>02/09/2013</date>
      <people>61</people>
      <car>81</car>
     </record>
     <record>
      <date>03/09/2013</date>
      <people>67</people>
      <car>47</car>
     </record>
     <record>
      <date>04/09/2013</date>
      <people>75</people>
      <car>95</car>
     </record>
     <record>
      <date>05/09/2013</date>
      <people>65</people>
      <car>45</car>
     </record>
     <record>
      <date>06/09/2013</date>
      <people>32</people>
      <car>52</car>
     </record>
     <record>
      <date>07/09/2013</date>
      <people>66</people>
      <car>46</car>
     </record>
     <record>
      <date>08/09/2013</date>
      <people>85</people>
      <car>105</car>
     </record>
     <record>
      <date>09/09/2013</date>
      <people>37</people>
      <car>57</car>
     </record>
     <record>
      <date>10/09/2013</date>
      <people>80</people>
      <car>100</car>
     </record>
    </records>;
   
   private var localSeries:ColumnSeries = new ColumnSeries();
   private var localCarSeries:ColumnSeries = new ColumnSeries();
   
   protected function creationCompleteEvent(event:FlexEvent):void
   {
    //Create the SortField object for the "time" field in 
    //the ArrayCollection object, and make sure we do a 
    //numeric sort.
    var dataSortField:SortField = new SortField();
    dataSortField.name = "time";
    dataSortField.numeric = true;
    
    //Create the Sort object and add the SortField object 
    //created earlier to the array of fields to sort on.
    var numericDataSort:Sort = new Sort();
    numericDataSort.fields = [dataSortField];
    
    // Parsing the xml data into ArrayCollection
    var objArray:ArrayCollection = new ArrayCollection();
    var tempObj:Object;
    var dateArray:Array;
    var tempDate:Date;
    for(var i:int = 0; i < myData.record.length(); i ++)
    {
     tempObj = new Object();
     dateArray = String(myData.record[i].date).split("/");
     //Convert the date data into a Date Object
     tempDate = new Date(dateArray[2], 
      Number(dateArray[1]) - 1, 
      dateArray[0]);
     tempObj.date = tempDate;
     tempObj.time = tempDate.time;
     //Adding the values of all the series together
     tempObj.data = Number(myData.record[i].people) + 
      Number(myData.record[i].car);
     //Create a new object for the data tooltip
     tempObj.people = myData.record[i].people;
     tempObj.label = dateFormatter(tempDate);
     objArray.addItem(tempObj);
    }
    
    objArray.sort = numericDataSort;
    objArray.refresh();
    
    //Create the new series and set its properties.
    localSeries.dataProvider = objArray;
    localSeries.yField = "data";
    localSeries.xField = "date";
    //Create alternate colors for the columns
    localSeries.setStyle("fill", 0xCDFFCD);
    //Create the strokes for the columns
    localSeries.setStyle("stroke", 
     new Stroke(0xFFFFFF, 0.1, 0.5));
    localSeries.displayName = "col_people";
    
    objArray = new ArrayCollection();
    for(i = 0; i < myData.record.length(); i ++)
    {
     tempObj = new Object();
     dateArray = String(myData.record[i].date).split("/");
     //Convert the date data into a Date Object
     tempDate = new Date(dateArray[2], 
      Number(dateArray[1]) - 1, 
      dateArray[0]);
     tempObj.date = tempDate;
     tempObj.time = tempDate.time;
     //Don't need to adding the values of all the 
     //series together
     tempObj.data = myData.record[i].car;
     //Create a new object for the data tooltip
     tempObj.car = myData.record[i].car;
     tempObj.label = dateFormatter(tempDate);
     objArray.addItem(tempObj);
    } 
    
    objArray.sort = numericDataSort;
    objArray.refresh();
    
    //Create the new series and set its properties.
    localCarSeries.dataProvider = objArray;
    localCarSeries.yField = "data";
    localCarSeries.xField = "date";
    //Create alternate colors for the columns
    localCarSeries.setStyle("fill", 0xCDCDFF);
    //Create the strokes for the columns
    localCarSeries.setStyle("stroke", 
     new Stroke(0xFFFFFF, 0.1, 0.5));
    localCarSeries.displayName = "line_car";
    
    //We will remove all the series attach to the chart
    //first
    chart.series = null;
    
    //End all the effects first, else some glich will
    //appear.
    parallelEffect.end();
    parallelCarEffect.end();
    
    //Base on the type of animation selected, attach 
    //the effect to the column
    localSeries.setStyle("creationCompleteEffect", 
     parallelEffect);
    localCarSeries.setStyle("creationCompleteEffect", 
     parallelCarEffect);
    
    // Back up the current series on the chart.
    var currentSeries:Array = chart.series;
    // Add the new series to the current Array of series.
    currentSeries.push(localSeries);
    currentSeries.push(localCarSeries);
    // Add the new Array of series to the chart.
    chart.series = currentSeries;
   }
   
   //This function will return a string based on the
   //Date format DD/MM/YYYY.
   private function dateFormatter(tempDate:Date):String
   {
    var fmt:DateFormatter = new DateFormatter();
    fmt.formatString = "DD/MM/YYYY";
    return fmt.format(tempDate);
   }
   
   //We are customizing the datatip / tool tip of the
   //chart data.
   public function myDataTipFunction(e:HitData):String {
    var s:String = "";
    var tempDate:Date = e.item.date as Date;
    s += "Date: " + dateFormatter(tempDate) + "<br>";
    if(Series(e.element).displayName == "col_people")
    {
     s += "No. of People: " + e.item.people;
    }else{
     s += "No. of Cars: " + e.item.car;
    }
    return s;
   }
   
   //This function will be used to change the date labels of
   //the chart to match the data.
   public function createDate(s:Date):Date {    
    var newDate:Date = new Date();
    newDate.time = s.time;
    //We need to increase a day to the labels.
    newDate.date += 1;
    return newDate;
   }
  ]]>
 </fx:Script>
 <s:VGroup width="100%" 
     height="100%"
     verticalAlign="middle"
     horizontalAlign="center">
  <s:BorderContainer width="100%"
         backgroundAlpha="0"
         borderVisible="false">
   <s:HGroup verticalAlign="middle" horizontalAlign="center"
       width="100%"
       height="100%">
    <!-- Need to set the gutterLeft and 
    gutterTop of the chart -->
    <mx:CartesianChart id="chart"
           gutterTop="0"
           gutterLeft="50"
           showDataTips="true" 
           width="80%"
           height="80%"
           dataTipFunction="myDataTipFunction">
     <mx:horizontalAxis>
      <mx:DateTimeAxis dataUnits="days" id="dateAxis" 
           alignLabelsToUnits="false" 
           parseFunction="createDate"/> 
     </mx:horizontalAxis>
    </mx:CartesianChart>
   </s:HGroup>
  </s:BorderContainer>
 </s:VGroup>
</s:Application>
* Click here for the demo shown in this post.
^ Click here for the source files for the demo.

Saturday, May 4, 2013

Facebook: Symbols and Emotions

Facebook, one of the biggest social networking website in the world with more than 1 billion users across the globe. From time to time, you will/might be coming across numerous situation where posting an image is much more appropriate than typing a big chunk of text. But how do all the users out there do it?

Well basically, it seems that there are numerous websites that helps us to create all these cute and interesting symbols and emotions for your comments and chats. The following are some examples of such websites. Do take a look. I personally find them pretty interesting. :D


Friday, April 26, 2013

Flex: Chart Data interaction

There might be numerous situations where you have to interact with a chart data and at the same time, perform some type of actions. Therefore, I'm going to show you how you can perform a simple action upon clicking on a chart data.

Here's the source code of my main application - SimpleChartDataClick.mxml
<?xml version="1.0" encoding="utf-8"?>
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009" 
      xmlns:s="library://ns.adobe.com/flex/spark" 
      xmlns:mx="library://ns.adobe.com/flex/mx"
      backgroundColor="#CDCDCD"
      creationComplete="creationCompleteEvent(event)"> 
 <fx:Declarations>
  <!-- 
  We need to specify the types of animations over here
  -->
  <s:Parallel id="parallelEffect">
   <s:Fade duration="1000" alphaFrom="0" alphaTo="1"/>
   <mx:SeriesSlide duration="1000" direction="up"/>
  </s:Parallel>
  <s:Parallel id="parallelCarEffect">
   <s:Fade duration="1000" alphaFrom="0" alphaTo="1"/>
  </s:Parallel>
 </fx:Declarations>
 <fx:Script>
  <![CDATA[
   import flashx.textLayout.conversion.TextConverter;
   
   import mx.charts.HitData;
   import mx.charts.chartClasses.IChartElement2;
   import mx.charts.chartClasses.Series;
   import mx.charts.events.ChartItemEvent;
   import mx.charts.series.ColumnSeries;
   import mx.charts.series.LineSeries;
   import mx.collections.ArrayCollection;
   import mx.collections.Sort;
   import mx.collections.SortField;
   import mx.events.FlexEvent;
   import mx.formatters.DateFormatter;
   import mx.graphics.Stroke;
   
   import spark.events.IndexChangeEvent;
   
   //Records used in the chart
   [Bindable]
   private var myData:XML = 
    <records> 
     <record>
      <date>01/09/2013</date>
      <people>63</people>
      <car>23</car>
     </record>
     <record>
      <date>02/09/2013</date>
      <people>61</people>
      <car>81</car>
     </record>
     <record>
      <date>03/09/2013</date>
      <people>67</people>
      <car>47</car>
     </record>
     <record>
      <date>04/09/2013</date>
      <people>75</people>
      <car>95</car>
     </record>
     <record>
      <date>05/09/2013</date>
      <people>65</people>
      <car>45</car>
     </record>
     <record>
      <date>06/09/2013</date>
      <people>32</people>
      <car>52</car>
     </record>
     <record>
      <date>07/09/2013</date>
      <people>66</people>
      <car>46</car>
     </record>
     <record>
      <date>08/09/2013</date>
      <people>85</people>
      <car>105</car>
     </record>
     <record>
      <date>09/09/2013</date>
      <people>37</people>
      <car>57</car>
     </record>
     <record>
      <date>10/09/2013</date>
      <people>80</people>
      <car>100</car>
     </record>
    </records>;
   
   private var localSeries:ColumnSeries = new ColumnSeries();
   private var localCarSeries:ColumnSeries = new ColumnSeries();
   
   protected function creationCompleteEvent(event:FlexEvent):void
   {
    //Create the SortField object for the "time" field in 
    //the ArrayCollection object, and make sure we do a 
    //numeric sort.
    var dataSortField:SortField = new SortField();
    dataSortField.name = "time";
    dataSortField.numeric = true;
    
    //Create the Sort object and add the SortField object 
    //created earlier to the array of fields to sort on.
    var numericDataSort:Sort = new Sort();
    numericDataSort.fields = [dataSortField];
    
    // Parsing the xml data into ArrayCollection
    var objArray:ArrayCollection = new ArrayCollection();
    var tempObj:Object;
    var dateArray:Array;
    var tempDate:Date;
    for(var i:int = 0; i < myData.record.length(); i ++)
    {
     tempObj = new Object();
     dateArray = String(myData.record[i].date).split("/");
     //Convert the date data into a Date Object
     tempDate = new Date(dateArray[2], 
      Number(dateArray[1]) - 1, 
      dateArray[0]);
     tempObj.date = tempDate;
     tempObj.time = tempDate.time;
     tempObj.people = myData.record[i].people;
     tempObj.label = dateFormatter(tempDate);
     objArray.addItem(tempObj);
    }
    
    objArray.sort = numericDataSort;
    objArray.refresh();
    
    //Create the new series and set its properties.
    localSeries.dataProvider = objArray;
    localSeries.yField = "people";
    localSeries.xField = "date";
    //Create alternate colors for the columns
    localSeries.setStyle("fill", 0xCDFFCD);
    //Create the strokes for the columns
    localSeries.setStyle("stroke", 
     new Stroke(0xFFFFFF, 0.1, 0.5));
    localSeries.displayName = "col_people";
    //Set the width(%) of the column 
    localSeries.columnWidthRatio = 0.3;
    //Set the offset
    localSeries.offset = -0.15;
    
    objArray = new ArrayCollection();
    for(i = 0; i < myData.record.length(); i ++)
    {
     tempObj = new Object();
     dateArray = String(myData.record[i].date).split("/");
     //Convert the date data into a Date Object
     tempDate = new Date(dateArray[2], 
      Number(dateArray[1]) - 1, 
      dateArray[0]);
     tempObj.date = tempDate;
     tempObj.time = tempDate.time;
     tempObj.car = myData.record[i].car;
     tempObj.label = dateFormatter(tempDate);
     objArray.addItem(tempObj);
    } 
    
    objArray.sort = numericDataSort;
    objArray.refresh();
    
    //Create the new series and set its properties.
    localCarSeries.dataProvider = objArray;
    localCarSeries.yField = "car";
    localCarSeries.xField = "date";
    //Create alternate colors for the columns
    localCarSeries.setStyle("fill", 0xCDCDFF);
    //Create the strokes for the columns
    localCarSeries.setStyle("stroke", 
     new Stroke(0xFFFFFF, 0.1, 0.5));
    localCarSeries.displayName = "line_car";
    //Set the width(%) of the column 
    localCarSeries.columnWidthRatio = 0.3;
    //Set the offset
    localCarSeries.offset = 0.15;
    
    //We will remove all the series attach to the chart
    //first
    chart.series = null;
    
    //End all the effects first, else some glich will
    //appear.
    parallelEffect.end();
    parallelCarEffect.end();
    
    //Base on the type of animation selected, attach 
    //the effect to the column
    localSeries.setStyle("creationCompleteEffect", 
     parallelEffect);
    localCarSeries.setStyle("creationCompleteEffect", 
     parallelCarEffect);
    
    // Back up the current series on the chart.
    var currentSeries:Array = chart.series;
    // Add the new series to the current Array of series.
    currentSeries.push(localCarSeries);
    currentSeries.push(localSeries);
    // Add the new Array of series to the chart.
    chart.series = currentSeries;
   }
   
   //This function will return a string based on the
   //Date format DD/MM/YYYY.
   private function dateFormatter(tempDate:Date):String
   {
    var fmt:DateFormatter = new DateFormatter();
    fmt.formatString = "DD/MM/YYYY";
    return fmt.format(tempDate);
   }
   
   //We are customizing the datatip / tool tip of the
   //chart data.
   public function myDataTipFunction(e:HitData):String {
    var s:String = "";
    var tempDate:Date = e.item.date as Date;
    s += "Date: " + dateFormatter(tempDate) + "<br>";
    if(Series(e.element).displayName == "col_people")
    {
     s += "No. of People: " + e.item.people;
    }else{
     s += "No. of Cars: " + e.item.car;
    }
    return s;
   }
   
   //This function will be used to change the date labels of
   //the chart to match the data.
   public function createDate(s:Date):Date {    
    var newDate:Date = new Date();
    newDate.time = s.time;
    //We need to increase a day to the labels.
    newDate.date += 1;
    return newDate;
   }  
   
   //This function will toggle the visibility of the chart
   //Data based on the values of the respective check boxes.
   protected function chkChartChangeEvent(event:Event):void
   {
    var showCarData:Boolean = chkCar.selected;
    var showPeopleData:Boolean = chkPeople.selected;
    for(var i:int = 0; i < chart.series.length; i ++)
    {
     if(chart.series[i].displayName == "line_car")
     {
      chart.series[i].visible = showCarData;
     }
     if(chart.series[i].displayName == "col_people")
     {
      chart.series[i].visible = showPeopleData;
     }
    }
   }
   
   //Upon clicking on one of the columns, this function
   //will update the label 'lblResult' based on the data
   //from the selected chart item.
   protected function itemClickEvent(e:ChartItemEvent):void
   {
    var str:String = "You have click on the item on ";
    var tempDate:Date = new Date();
    tempDate.time = e.hitData.item.date.time;
    str += dateFormatter(tempDate) + " with the data ";
    var tempValue:String = "";
    if(Series(e.hitData.element).displayName == "col_people")
    {
     str += "People: "; 
     tempValue = e.hitData.item.people;
    }else{
     str += "Car: ";
     tempValue = e.hitData.item.car;
    }
    str += tempValue;
    lblResult.text = str;
   }
   
  ]]>
 </fx:Script>
 <s:VGroup width="100%" 
     height="100%"
     verticalAlign="middle"
     horizontalAlign="center">
  <s:BorderContainer width="100%"
         backgroundAlpha="0"
         borderVisible="false">
   <s:HGroup verticalAlign="middle" horizontalAlign="center"
       width="100%"
       height="100%">
    <!-- Need to set the gutterLeft and 
    gutterTop of the chart -->
    <mx:CartesianChart id="chart"
           gutterTop="0"
           gutterLeft="50"
           showDataTips="true" 
           width="80%"
           height="80%"
           itemClick="itemClickEvent(event)"
           dataTipFunction="myDataTipFunction">
     <mx:horizontalAxis>
      <mx:DateTimeAxis dataUnits="days" id="dateAxis" 
           alignLabelsToUnits="false" 
           parseFunction="createDate"/> 
     </mx:horizontalAxis>
    </mx:CartesianChart>
   </s:HGroup>
  </s:BorderContainer>
  <s:HGroup width="100%" horizontalAlign="center" 
      verticalAlign="middle">
   <s:CheckBox id="chkCar"
      change="chkChartChangeEvent(event)" 
      selected="true"
      label="Show Car Data"/>
   <s:CheckBox id="chkPeople"
      change="chkChartChangeEvent(event)" 
      selected="true"
      label="Show People Data"/>
  </s:HGroup>
  <s:Spacer height="10"/>
  <s:HGroup width="100%" horizontalAlign="center" 
      verticalAlign="middle">
   <s:Label text="For your info:"/>
  </s:HGroup>
  <s:HGroup width="100%" horizontalAlign="center" 
      verticalAlign="middle">
   <s:Label id="lblResult"/>
  </s:HGroup>
 </s:VGroup>
</s:Application>
* Click here for the demo shown in this post.
^ Click here for the source files for the demo.
~ Click here to find out more about Chart Data Interactions in Flex.

Saturday, April 20, 2013

Apache Ant: Executing a target in another target

As my current workplace we were using 'Jenkins' and 'Apache Ant' to automate and release the updated files of the respective projects once in a while, therefore I ended up trying out something on the 'Apache Ant' script. :P

So how to run a 'target' in another 'target'?
First of all, you probably have a 'target' like the following.
 <target name="building" description="Building a project">
 </target>
And then, you probably have a added a 'sequential' node, because you wanted to execute a series of tasks.
 <target name="building" description="Building a project">
  <sequential>
  </sequential>
 </target>
So how to execute another 'target' in the current 'target'? Well you can either add a 'antcall' or a 'antcallback' node. But what's the difference between the both of them? 'antcall' will execute another 'target' while 'antcallback' will execute another 'target' but at the same time allows you to return the 'property' that was created in the executed 'target'.
 <target name="building" description="Building a project">
  <sequential>
   <antcallback target="generateTimeStamp" return="timestamp"/>
   <antcall target="echoMsg"/>
  </sequential>
 </target>
Finally, you might end up with something like the following. I'm running 2 'target' in another 'target'. The 1st 'target' will create a 'property' and the 'property' will be passed into the 2nd 'target' and 'echo' the value of the 'property' as a message.
 <target name="building" description="Building a project">
  <sequential>
   <antcallback target="generateTimeStamp" return="timestamp"/>
   <antcall target="echoMsg"/>
  </sequential>
 </target>

 <target name="generateTimeStamp">
  <tstamp>
   <format property="timestamp" pattern="ddMMyyyyHHmmss"/>
  </tstamp>
 </target>
 
 <target name="echoMsg">
  <echo message="Generated Timestamp: ${timestamp}"/>
 </target>
* Click here to find out more about 'Jenkins'.
^ Click here to find out more about 'Apache Ant'.

Saturday, April 13, 2013

FB + Adobe AIR: Posting Bug

My friends were asking me to help them to debug an interest problem that they are facing with the Facebook Graph Desktop API.

The scenario as follows. A user log in to the desktop application (Adobe AIR) through Facebook and he decided to post something on his Facebook wall through the application and decides to log out of the Facebook and Application. If a second user tries to log in and post something to his Facebook wall using the application, the message will appear on the wall on the first user, rather than the second user. Therefore here's a fix to that issue if you are using the source files of the 'Facebook Graph Desktop API'.
You have to modify the following function of the following file - com\facebook\graph\FacebookDesktop.as From
    public static function api(method:String,
                     callback:Function,
                     params:* = null,
                     requestMethod:String = 'GET'
    ):void {
      getInstance().api(method,
        callback,
        params,
        requestMethod
      );
    }
To
    public static function api(method:String,
                     callback:Function,
                     params:* = null,
                     requestMethod:String = 'GET'
    ):void {

      if(params != null)
      {
        if (getInstance().session != null) {
          params.access_token = getInstance().session.accessToken;
        }
      }
      getInstance().api(method,
        callback,
        params,
        requestMethod
      );
    }
* Click here for the updated file 'FacebookDesktop.as'.
^ Click here to find out more about the 'Facebook Graph Desktop API'.