Tuesday, October 11, 2011

How to generate JSON in app engine servlet

Well, I was working on pass json to map to draw polygone shape. Easily, I can use stringbuffer to assemble it.but, while I am looking at GSON api, it looks so easy. there is a few things I need to consider.

1. your data type should match with json output. for example, if you are using string, gson will add "" around. so, if you do not want, use long,float, int based on your need.
2. make sure setHtmlSafe = false, if not, it will add unicode that you do not want.
3. make sure your httpserveltresponse = application/json
4. HashMap messages is HashMap of dao object collection. nothing is special here.


public void doGet(HttpServletRequest request, HttpServletResponse response)
    throws IOException, ServletException {
    processRequest(request, response);
}


public void doPost(HttpServletRequest request, HttpServletResponse response)
    throws IOException, ServletException {
processRequest(request, response);
}

@SuppressWarnings("unchecked")
public void processRequest(HttpServletRequest request, HttpServletResponse response)
      throws ServletException, IOException {


PrintWriter print = response.getWriter();
response.setContentType("application/json");
response.setCharacterEncoding("UTF-8");

DataAct da = new DataAct();
try {
    HashMap messages = da.getNotification();
    JsonWriter writer = new JsonWriter(print);

   

    writer.setHtmlSafe(false);
    writer.setIndent("    ");
    writeMessagesArray(writer, messages);
    writer.close();

     

} catch (ServiceException e) {
e.printStackTrace();
}

 

}


public void writeJsonStream(OutputStream out, HashMap messages) throws IOException {
    JsonWriter writer = new JsonWriter(new OutputStreamWriter(out, "UTF-8"));

   

    writer.setHtmlSafe(false);
    writer.setIndent("    ");
    writeMessagesArray(writer, messages);
    writer.toString();
    writer.close();
  }

  public void writeMessagesArray(JsonWriter writer, HashMap messages) throws IOException {
    writer.beginArray();

     

    for(int i = 0; i < messages.size(); i++){
    writeMessage(writer, (Notification)messages.get(new Integer(i)));
    }

    writer.endArray();
  }

  public void writeMessage(JsonWriter writer, Notification message) throws IOException {
    writer.beginObject();
    writer.name("id").value(message.getId());
    writer.name("title").value(message.getTitle());
    writer.name("type").value(message.getType());
    writer.name("lat").value(message.getLat());
    writer.name("lon").value(message.getLon());
    writer.name("description").value(message.getDescription());
    writer.name("imgURL").value(message.getImgURL());
    writer.endObject();
  }

MashMap message is collection of :

public class Notification {
private int id;
private String title;
private String description;
private String type;
private float lat;
private float lon;
private String imgURL;
.........

}

Wednesday, August 10, 2011

How to create zip file in App Engine

As you all know, File can't be created in App Engine. So, regular java approach won't work. so, I was wonder what I should do and how I can approach to resolve the issue.
In the end, it was extremely simple to create ZIP file in App Eninge.


private void createZipFile() throws IOException {

        ByteArrayOutputStream baos = new ByteArrayOutputStream();

        ZipOutputStream zos = new ZipOutputStream(baos);

      

        zos.putNextEntry(new ZipEntry("First")); 

        String s = "test1";

        zos.write(s.getBytes());

        zos.closeEntry();


        zos.putNextEntry(new ZipEntry("Second"));

        String s2 = "test2";

        zos.write(s2.getBytes());

        zos.closeEntry();        


        zos.flush();

        baos.flush();

       

        zos.close();

        baos.close();

}

Friday, April 15, 2011

Appengine twitter

While I am looking for answer how my app engine application can twitt automaitcally when it gets data, I found that there is no clear answers.

I do not really need to have oAuth since it is my twitter account and app engine server side needs to twitter.

Also, I didn't want to write to get consumer key or secret. all tutorials on web is started how to generate consumer key/secret from coding...

Eventually, by registering your app via https://dev.twitter.com/apps/new  will give all keys what I need. basically, you can get cinsuer_key. consumer_secret, access_token, access_token_secret from the panel once you register.very simple.


Then, now, as you can see the below code, it can make your app engine to tweet via your twitter acount whenever data is received fron your client app to app engine server. easy and fun!




import twitter4j.Twitter;

import twitter4j.TwitterException;

import twitter4j.TwitterFactory;

import twitter4j.auth.AccessToken;


public class TwitterManager {

private static final String betaCONSUMER_KEY = "Jd28exxxxxxxxxxxxxOw";

private static final String betaCONSUMER_SECRET = "2aCSkyWxxxxxxxxxxg";

private static final String betaACCESS_TOKEN = "2658xxxxxxxxxxxxxxxxBD";

private static final String betaACCESS_TOKEN_SECRET = "tExxxxxxxxxxnYGHbk";


public TwitterManager() {

// TODO Auto-generated constructor stub

}


public String updateStatus(String message, boolean isBeta) throws TwitterException{

    String s = "No";

    AccessToken accessToken;

    

    accessToken = new AccessToken(betaACCESS_TOKEN, betaACCESS_TOKEN_SECRET);

    

    

    Twitter twitter = new TwitterFactory().getInstance();

     twitter.setOAuthConsumer(betaCONSUMER_KEY, betaCONSUMER_SECRET);  

    twitter.setOAuthAccessToken(accessToken);

try {

twitter.updateStatus(message);

s = "Successfully updated the status.";

} catch (TwitterException e) {

s = e.getMessage();

}

       

        return s;

}

Saturday, March 19, 2011

Japanese character reading & sending

While I developed to save Japanese characters, I didn't pay attend to UTF-8 since I was able to see Japanese characters in datastore properly.

The issue was found when I loaded data into my android device. It was a line of code to address this issue.

I just need to set contentType..

public void doGet(HttpServletRequest request, HttpServletResponse response)

throws IOException {

response.setContentType("text/html;charset=UTF-8");

PrintWriter writer=response.getWriter();

......

}



Sunday, November 28, 2010

Blob data limit on Google Appengine with Android

Image files are pretty headache while I am posting data into datastore on Google Appengine as blob.
While I am searching solution, Google appengine java user group already had tons of discussion of it and different ways to resolve the issue since google app engine allows unto 1MB data store is allowed.
My solution was pretty simple although there are a few mistakes.
This was my first step that I overlooked the issue.

1. user takes photos
2. user send photos to appengine
3. appengine gets data and resize photos
4. store resize photos into datastore as blob and post data using Gdata API

step 3, resize was to prevent 1MB data limit and handle it properly. Unfortunately, when application can't resize if original photo data is greater 1MB already. Yes, I got this issue and pull my hairs to resolve it.
Believe or not, I didn't want to resize my data on client side app. but, this issue didn't give any choice so that I added addition step on before i post data into appengine.

1. user takes photos
2. application checks file size if file size is greater than 1MB, app resize image.
3. user send photos to appengine
4. appengine gets data and resize photos
5. store resize photos into datastore as blob and post data using Gdata API

Yes, this addition step resolved the issue. See the below code step to resolve the issue.

1. User takes photos
private function btn_onClickPhoto():void{
if (CameraUI.isSupported)
{
var cameraUI:CameraUI = new CameraUI();
cameraUI.addEventListener(MediaEvent.COMPLETE, function(event:MediaEvent):void {
i.source = event.data.file.url;
photoURL = event.data.file.url;
file = event.data.file;
});
cameraUI.launch(MediaType.IMAGE);
}
else
{
l.text = "CameraUI not supported";
}

2/3 Android application photo resize. Then, send to GOOGLE AppEngine
private function resizePhoto():File{
var bmpd:BitmapData = new BitmapData(2000,1800);
bmpd.draw(iTrack);
var jPEGEncoder:JPEGEncoder = new JPEGEncoder(80);
var imageByteArray:ByteArray = jPEGEncoder.encode(bmpd);


var fl:File = File.applicationStorageDirectory.resolvePath(photoURL);


var fs:FileStream = new FileStream();
try{
fs.open(fl,FileMode.WRITE);
fs.writeBytes(imageByteArray);
fs.close();
}catch(e:Error){
trace(e.message);
}


return fl;
}

private function btn_onClickGoogleUpload():void{
var uploadURL:URLRequest = new URLRequest();
uploadURL.url = "YOUR GOOGLE APPENGINE URL";
var filref:FileReference;


file = new File(photoURL);
if(file.size < 1000000){
filref = FileReference(file);
}
else{
filref = FileReference(resizePhoto());
}


filref.addEventListener(DataEvent.UPLOAD_COMPLETE_DATA,uploadCompleteDataHandler);
filref.addEventListener(Event.COMPLETE, completeHandler);
filref.addEventListener(Event.CANCEL, cancelHandler);

uploadURL.method = URLRequestMethod.GET;

filref.upload(uploadURL);
}

<s:Image id="iTrack" width="100%" height="100%" scaleMode="stretch" />

4 Google AppEngine application code to resize photos.

ImagesService imagesService = ImagesServiceFactory.getImagesService();
Image oldImage = ImagesServiceFactory.makeImage(contentBytes);

int width = oldImage.getWidth();
int height = oldImage.getHeight();

int MAZ_SIZE = 3000;

if(width > MAZ_SIZE || height > MAZ_SIZE){
width = (int) (width*0.5);
height= (int) (height*0.5);
}


Transform resize = ImagesServiceFactory.makeResize(width, height);
Image image = imagesService.applyTransform(resize, oldImage, ImagesService.OutputEncoding.JPEG);

4 Post to PICASA using GData API
private void addToPicasa(String blobKey, String id) {
ImagesService imagesService = ImagesServiceFactory.getImagesService();
BlobKey bk = new BlobKey(blobKey);
Image oldImage = ImagesServiceFactory.makeImageFromBlob(bk);
Transform resize = ImagesServiceFactory.makeResize(1024, 768);
Image image = imagesService.applyTransform(resize, oldImage, ImagesService.OutputEncoding.JPEG);


PicasawebService myService = new PicasawebService("PICTURESHOP");
try {
myService.setUserCredentials("mypicasaaccount@gmail.com", "my.password");
String albumid = "5495486978942507441";

URL albumPostUrl = 


PhotoEntry myPhoto = new PhotoEntry();
myPhoto.setTitle(new PlainTextConstruct(id));


MediaSource myMedia = new MediaByteArraySource(image.getImageData(), "image/jpeg");
myPhoto.setMediaSource(myMedia);


PhotoEntry returnedPhoto = myService.insert(albumPostUrl, myPhoto);            
} catch (Exception e) {
logger.error(e);
}
}

Thursday, October 7, 2010

Manifest for Air Application and Android

While I am package androd app for air, I got error of invalid attribute on application manifest file. After I googled it, I found the below fix

Incorrect Manifest of Air Application and Android

<?xml version="1.0" encoding="utf-8" standalone="no"?>
<android>
<manifestAdditions>
<manifest>
<![CDATA[ 
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.RECORD_AUDIO"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
]]> 
</manifest>
</manifestAdditions>
</android>
<id>VoiceNotes</id>
<filename>VoiceNotes</filename>
<name>Voice Notes</name>
<versionNumber>1.0.0</versionNumber>
<supportedProfiles>mobileDevice</supportedProfiles>
<initialWindow>
<content>VoiceNotes.swf</content>
<visible>true</visible>
<!-- <autoOrients>true</autoOrients> -->
</initialWindow>
</application>


Updated Manifest of Air application and Andorid

<?xml version="1.0" encoding="utf-8" standalone="no"?>
<android>
    <manifestAdditions>
    <![CDATA[
    <manifest android:installLocation="auto">
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.RECORD_AUDIO"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
    </manifest>
    ]]>
    </manifestAdditions>
</android>

<id>VoiceNotes</id>
<filename>VoiceNotes</filename>
<name>Voice Notes</name>
<versionNumber>1.0.0</versionNumber>
<supportedProfiles>mobileDevice</supportedProfiles>
<initialWindow>
<content>VoiceNotes.swf</content>
<visible>true</visible>
<!-- <autoOrients>true</autoOrients> -->
</initialWindow>
</application>

Friday, September 10, 2010

QRCode & Adobe Air2.0 & AlivePDF



Recently, i needed to print QRCode based name badge for attendees. So, I have checked some existing free application. Unfortunately, I didn't like all of them since I needed to print into 4x6 size. Well, so, I decided to write my own application. Here is some constrains on this application

  1. Eventbrite Attendee's list : Eventbrite has public API to get conference info & Attendees. unfortunately, attendee's info is controlled by event organizer. Most organizer doesn't want to expose too much attendee's info. so, I had to get attend's list from event organizer directly. So, we should assume that we are using static exported data.

  2. Garbage data : When I parse each row, i found event brite use "" with delimiter of each field. assume that delimiter is , and inside of each field has ,. it messed up my string parse so that I had to remove , manually. mostly, it is premature data from EventBrite

Step 1.
Create Adobe AIR Application from your flashbuilder

Step 2.
We need to a library that will used for PDF file generation. Get it and place it into your lib folder
Step 3.
  • Be familiar with google ZXING that is used to generate QRCode. ZXing (pronounced "zebra crossing") is an open-source, multi-format 1D/2D barcode image processing library implemented in Java. http://code.google.com/p/zxing/
  • Get ZXING 1.5. When you unzip it, you can find actionscript folder. it contain zxing API so that we can use to generate QRCode. Place it under your src folder or you can make it library and place into lib folder.


Step 4.
Write QRCode generation actionscript class.

package vo
{
import flash.display.Bitmap;
import core.src.com.google.zxing.common.BitMatrix;
import mx.core.BitmapAsset;
import core.src.com.google.zxing.common.flexdatatypes.HashTable;
import flash.net.FileReference;
import flash.display.*;
import flash.net.URLRequest;
import flash.events.Event;
import mx.controls.Alert;
import core.src.com.google.zxing.common.GlobalHistogramBinarizer;
import core.src.com.google.zxing.common.ByteMatrix;
import core.src.com.google.zxing.client.result.ParsedResult;
import core.src.com.google.zxing.client.result.ResultParser;
import core.src.com.google.zxing.DecodeHintType;
import core.src.com.google.zxing.BarcodeFormat;
import core.src.com.google.zxing.BinaryBitmap;
import core.src.com.google.zxing.BufferedImageLuminanceSource;
import core.src.com.google.zxing.MultiFormatReader;
import core.src.com.google.zxing.MultiFormatWriter;
import core.src.com.google.zxing.Result;
public class QRCodeHandler
{
public function QRCodeHandler()
{
}
public function generateQRCode(contents:String):Bitmap
{
var myWriter:MultiFormatWriter = new MultiFormatWriter();
try
{

var result:ByteMatrix = (myWriter.encode(contents,BarcodeFormat.QR_CODE,300,300)) as ByteMatrix;
}
catch (e:Error)
{
Alert.show('An error occurred during the encoding process');
}

var bmpd:BitmapData = new BitmapData(300, 300, false, 0x009900);
var bmp:Bitmap = new Bitmap(bmpd);

for (var h:int=0;h<300;h++)
{
for (var w:int=0;w<300;w++)
{
if (result._get(w,h) == 0)
{
bmpd.setPixel(w,h, 0);
}
else
{
bmpd.setPixel(w,h, 0xFFFFFF);
}
}
}
return bmp;
}
}
}


Step 5.
Here is your application code that read .cvs file and generate it into final version.


<?xml version="1.0" encoding="utf-8"?>
<s:WindowedApplication xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx" creationComplete="loadFile();">
<fx:Style source="FileReader.css"/>
<fx:Script>
<![CDATA[
import flash.display.DisplayObject;
import flash.filesystem.File;
import flash.filesystem.FileStream;
import flash.sampler.NewObjectSample;
import flash.utils.ByteArray;
import mx.collections.ArrayCollection;
import mx.collections.XMLListCollection;
import mx.events.CollectionEvent;
import mx.events.CollectionEventKind;
import mx.events.DataGridEvent;
import mx.events.FlexEvent;
import mx.events.ListEvent;
import org.alivepdf.fonts.CoreFont;
import org.alivepdf.fonts.FontFamily;
import org.alivepdf.fonts.IFont;
import org.alivepdf.images.ColorSpace;
import org.alivepdf.layout.Align;
import org.alivepdf.layout.Mode;
import org.alivepdf.layout.Orientation;
import org.alivepdf.layout.Position;
import org.alivepdf.layout.Resize;
import org.alivepdf.layout.Size;
import org.alivepdf.layout.Unit;
import org.alivepdf.links.ILink;
import org.alivepdf.links.InternalLink;
import org.alivepdf.pages.Page;
import org.alivepdf.pdf.PDF;
import org.alivepdf.saving.Method;
import vo.Attendee;
import vo.AttendeeType;
import vo.QRCodeHandler;
[bindable]
private var currentSelectedItemID:String;
[bindable]
private var iColor:uint = 0x0000FF;
public function createPDF(obj:DisplayObject):void
{
var uf:IFont = new CoreFont ( FontFamily.HELVETICA_BOLD );
var customsize:Size = new Size([400,600],"customsize", [4,6],[101.6,152.4]) ;
var p:PDF = new PDF( Orientation.PORTRAIT, Unit.MM, customsize);
p.setMargins(0,15,0,0);
p.addPage();
p.addImage( obj );
var f:FileStream = new FileStream();
var sFileName:String = "sdcPdf/"+ currentSelectedItemID + ".pdf"
var file:File = File.desktopDirectory.resolvePath( sFileName);
if(!file.exists) {
f.open( file, FileMode.WRITE);
var bytes:ByteArray = p.save( Method.LOCAL );
f.writeBytes(bytes);
f.close();
}
}
private function displayInfo(evt:ListEvent):void{
var aFirstName:String = String(evt.currentTarget.selectedItem.firstname);
var aLastName:String = String(evt.currentTarget.selectedItem.lastname);
this.setBadge(aFirstName, aLastName);
//badge layout
aTitle.text = String(evt.currentTarget.selectedItem.title) ;
aCompany.text = String(evt.currentTarget.selectedItem.company) ;
aTwitter.text = String(evt.currentTarget.selectedItem.twitter) ;
firstname.text = aFirstName.toUpperCase() ;
lastname.text = aLastName.toUpperCase() ;
//QRCode generation
var qrInfo:String = aFirstName + " ";
qrInfo = qrInfo + aLastName + "\n";
if(!isEmpty(String(evt.currentTarget.selectedItem.title))){
qrInfo = qrInfo + String(evt.currentTarget.selectedItem.title) + "\n";}
if(!isEmpty(String(evt.currentTarget.selectedItem.company))){
qrInfo = qrInfo + String(evt.currentTarget.selectedItem.company) + "\n";}
qrInfo = qrInfo + String(evt.currentTarget.selectedItem.email) + "\n";
if(!isEmpty(String(evt.currentTarget.selectedItem.tel))){
qrInfo = qrInfo + String(evt.currentTarget.selectedItem.tel) + "\n";}
if(!isEmpty(String(evt.currentTarget.selectedItem.website))){
qrInfo = qrInfo + String(evt.currentTarget.selectedItem.website) + "\n";}
qrInfo = qrInfo + String(evt.currentTarget.selectedItem.asa) + "\n";
qrInfo = qrInfo + String(evt.currentTarget.selectedItem.asa_event) + "\n";
QRImage.source = new QRCodeHandler().generateQRCode(qrInfo);
var sFileStart:String = aLastName;
var sFileEnd:String = String(evt.currentTarget.selectedItem.id);
sFileStart = sFileStart.replace(' ', '');
sFileEnd = sFileEnd.replace(' ', '');
this.currentSelectedItemID = sFileStart + "_" + sFileEnd;
}
private function isEmpty(text:String):Boolean{
if(text == null|| text == ""){
return true;
}
else{
return false;}
}
private function setBadge(fname:String, lname:String):void{
var objType:AttendeeType = new AttendeeType();
if( objType.isStaff(fname, lname)){
color.selectedColor = objType.staffColor;
this.badgeTitle.text = "STAFF";
}
else if( objType.isSpeaker(fname,lname)){
color.selectedColor= objType.speakerColor;
this.badgeTitle.text = "SPEAKER";
}
else if( objType.isSponsor(fname,lname)){
color.selectedColor = objType.sponosorColor;
this.badgeTitle.text = "SPONSOR";
} else
{
color.selectedColor = objType.attendeeColor;
this.badgeTitle.text = "ATTENDEE";
//this.badgeTitle.text = "PRESS";
}
}

private function loadFile():void{
var file:File = File.applicationDirectory.resolvePath("data/SDC0813.csv");
var stream:FileStream = new FileStream();
stream.open(file, FileMode.READ);
var str:String = stream.readUTFBytes(stream.bytesAvailable);
stream.close();
var recordsetCollection:ArrayCollection = new ArrayCollection();
var rowRecordSet:Array = str.split(/\n/gi);
for (var i:String in rowRecordSet)
{
var sTempRecord:String = rowRecordSet[i];
sTempRecord = sTempRecord.replace( /["]/gi,'');
var eachRecord:Array = sTempRecord.split(/,/gi);
var attendee:Attendee = new Attendee();
attendee.id = eachRecord[0];
attendee.lastname = trimWord(eachRecord[1]);
attendee.firstname= trimWord(eachRecord[2]);
attendee.email= trimWord(eachRecord[3]);
attendee.tel= eachRecord[4];
attendee.twitter= reformatTwitter(trimWord(eachRecord[5]));
attendee.title= trimWord(eachRecord[6]);
attendee.company = trimWord(eachRecord[7]);
attendee.website = eachRecord[8];
attendee.asa= "http://m.aspaceapart.net/profiles/" + trimWord(eachRecord[2]) + "_" + trimWord(eachRecord[1]);
attendee.hasBadge = this.hasBadgePDF(eachRecord[0], eachRecord[1]);
recordsetCollection.addItem(attendee);
}
grid.dataProvider = recordsetCollection;
}
private function trimFirstNameForASA(fname:String):String{
if(fname == null)
return '';
fname = fname.replace(' ', '');
return fname;
}
private function hasBadgePDF(sID:String, lName:String):Boolean{
if( lName != null)
{
lName = lName.replace(' ', '');}
if(sID !=null){
sID = sID.replace(' ', '');}
var sFileName:String = "sdcPdf/"+lName+"_"+ sID + ".pdf"
var file:File = File.desktopDirectory.resolvePath( sFileName);
if(file.exists) {
return true;
}
else
return false;
}
private function trimWord(text:String):String{
if(text == null || text == "-"){
text = "";}
if(text.charAt(0) == " "){
text.substr(1, text.length);}
return text;
}
private function reformatTwitter(strTwitter:String):String{
if(strTwitter == null)
return "";
strTwitter = strTwitter.toLocaleUpperCase();
if(strTwitter == "" || strTwitter == " " || strTwitter == "." || strTwitter == "@" || strTwitter == "-")
{
return "";
}
if(strTwitter =="NA" || strTwitter == "N/A" || strTwitter == "N\A" || strTwitter == "NONE" || strTwitter == "NO")
{
return "";
}
if(strTwitter.substring(0) != "@")
{
strTwitter = "@" + strTwitter;
}


strTwitter = strTwitter.replace("@@", "@");
return strTwitter;
}
]]>
</fx:Script>
<s:layout>
<s:VerticalLayout />
</s:layout>
<mx:ColorPicker id="color" color="0x000000"/>
<s:Button label="Generate PDF" click="{createPDF(this.infoPanel);}" />
<s:Panel title="DataGrid Control"
color="0x000000"
borderAlpha="0.15"
width="100%" height="100%">
<s:layout>
<s:HorizontalLayout paddingTop="0" />
</s:layout>
<mx:DataGrid id="grid"
width="600" height="700"
sortableColumns="true"
draggableColumns="true" itemClick="{displayInfo(event);}">
<mx:columns>
<mx:DataGridColumn dataField="id" headerText="ID"/>
<mx:DataGridColumn dataField="firstname" headerText="First"/>
<mx:DataGridColumn dataField="lastname" headerText="Last"/>
<mx:DataGridColumn dataField="title" headerText="Title"/>
<mx:DataGridColumn dataField="company" headerText="Company"/>
<mx:DataGridColumn dataField="email" headerText="eMail"/>
<mx:DataGridColumn dataField="twitter" headerText="twitter"/>
<mx:DataGridColumn dataField="hasBadge" headerText="Badge" />
</mx:columns>
</mx:DataGrid>
<s:BorderContainer width="400" height="600" borderColor="#000000">
<s:layout>
<s:VerticalLayout paddingLeft="0" paddingRight="0" paddingTop="0" paddingBottom="0"/>
</s:layout>
<s:VGroup width="400" height="600" id="infoPanel" horizontalAlign="center">
<s:VGroup width="400" height="130" paddingTop="30" paddingLeft="10">
<mx:Text id="firstname" fontSize="40" fontFamily="Helvetica" fontWeight="bold" width="100%" />
<mx:Text id="lastname" fontSize="40" fontFamily="Helvetica" fontWeight="bold" width="100%" />
</s:VGroup>
<s:HGroup width="400" height="250" verticalAlign="top" paddingTop="45" paddingRight="10" >
<s:VGroup width="240" height="300" paddingLeft="10">
<mx:Text text=" " />
<mx:Text id="aTitle" width="235" fontSize="20" fontFamily="Helvetica" />
<mx:Text id="aCompany" width="235" fontSize="20" fontFamily="Helvetica" />
<mx:Text id="aTwitter" width="235" fontSize="20" fontFamily="Helvetica" />
</s:VGroup>
<mx:Image layoutDirection="ltr" id="QRImage" width="150" verticalAlign="top" />
</s:HGroup>
<s:VGroup width="400" height="220">
<mx:Image horizontalAlign="center" id="sdclogo" source="assets/SDCLOGO.png" height="131" width="400" maintainAspectRatio="true" scaleContent="true"/>
<s:BorderContainer id="badgeBox" backgroundColor="{color.selectedColor}" width="400" height="70">
<mx:Text paddingTop="7" text="ATTENDEE" id="badgeTitle" paddingBottom="0" width="100%" fontFamily="Helvetica" fontWeight="bold" fontSize="40" color="#FFFFFF" textAlign="center"/>
</s:BorderContainer>
</s:VGroup>

</s:VGroup>
</s:BorderContainer>

</s:Panel>
</s:WindowedApplication>