Posts Tagged ‘ Flex ’

iOS Packaging from Flex

My latest experience on converting Flex App to iOS, might be of use for beginners.

Debug version ipa generation is faster than rest, make sure you select Ad Hoc Distribution for testing the app on any device with Developer licence and Developer Provisioning Profile.

Make sure you use Mac for porting the application with Apple’s iPhone Configuration Utility, otherwise with windows use iTunes for porting the app into Device.

Reason:

You cannot install IPA files to the device via Apple’s iPhone Configuration Utility on WIN, got error “Could not install application on device. Error kAMDReceiveMessageError”. Workaround is to install IPA with iTunes on Windows or iTunes/iPhone Configuration Utility on Mac OS (2810687) (source : http://kb2.adobe.com/cps/891/cpsid_89107.html)

The list of Device Capabilities to work with Camera

<key>UIRequiredDeviceCapabilities</key>
<array>
   <string>front-facing-camera</string>
   <string>auto-focus-camera</string>
   <string>camera-flash</string>
   <string>video-camera</string>
 </array>

Flex Mobile Apps

Demo Videos List

Apps Github Source Android Market BlackBerry AppWorld Amazon AppStore
eStud Link Link Link Link
UniversalCurrency Link Link Link Link
FlexMock Link Link Link Link
EduTube Link Link Link Link
CartoonTV Link Link Link Link
RhymeTV Link Link Link Link
AnimatorWatch Link Link Link Link

ByteArray Util

ByteArray to Encode and Decode Objects as String
https://gist.github.com/1051042 based on http://goo.gl/8WdQu

Swiz Framework for Mobile Development (Source Example)

Source for Android/ iOS/ Blackberry Mobile App Universal-Currency.
Developed with Flex 4.5.1 SDK and AIR 2.7 SDK

The project does currency conversion, using HTTPService via SwizDAO Framework

Check the code base:

https://github.com/nsdevaraj/Universal-Currency

Move Scroll bar on left side Flex4

I struggled a lot, but fixed it with easy tweak.
s:List Property -> layoutDirection=”rtl”
Note, in case you were using itemRenderer , make the reverse there to avoid arabic right to left effect by :
s:ItemRenderer Property -> layoutDirection=”ltr”

Parallel Computing in AS3 //P

Managed to create a Master – Slave architecture between a group of SWF Files.
This group will have a Master SWF which will command other slave swf’s to do certain processing.

This architecture might be helpful in distributing the processing to many files thus reducing the Memory being occupied in a Single SWF.

With IoC in proper form in future, will be successful editing the Slave SWF’s Dynamically.

Code for Master : https://gist.github.com/9bd094ac172d336004c6

Code for Slaves : https://gist.github.com/a840cea1258e019176d8

This Architecture avails running multiple threads with different SWF files at same time

Find the User Country from Flex

First of All, we need JSP / ASP for getting the IP Address, Example code: Link
After getting the IP, using the below IP Web Service we can find the End- User’s Country.

http://www.webservicex.net/geoipservice.asmx?op=GetGeoIP

XML to Object

The Project i have created converts the XML into required object in simple steps. Have a look on it : XSLT

Convert int to String

The AS3 Util Function is posted on the below link
Utility to convert number or integer to String. The util function is useful in many applications.
https://gist.github.com/703108

Things i learnt new from ACE -Flex4

ACE exam was a good learning experience for me, I came to learn about these new things yesterday.

  • saveCache is used in LCDS for offline mode saving.
  • Native Platform style is default setting for AIR.
  • FileMode.Update is used to make the both file writing and reading.
  • AcceptDragDrop is the method used to accept an DragObject and DoDrag is to initiate the dragging.
  • SQLConnection is the class used for setting SQLLite into write mode.
  • SQLStatement class property “text” is used for the sql querying purpose.
  • mouseDownEffect also can be used to set the Effect on MouseClick.
  • widthInChars is new property for TextInput which can be used to set width.
  • AIR can access the methods of loaded SWF by default.

Flex 4 ACE Questions

Passed ACE Certification with Flex4.

The differences of Flex3 and Flex 4 certifications
1/ more questions – 59 questions (previously 50)
2/ more time – 90 minutes (previously 60 min) Don’t bother about time factor you will have at least 30 minutes spare time for review.
3/ UI have more share among questions 35 %
4/ In Flex_Exam_Guide – They didn’t mentioned about LCDS, but we got Questions from LCDS too.

Tips:
1/ Do use attest, as it is the only resource we have for mockup
2/ Unlike Attest the questions will be in shuffled order
3/ While you attend ACE, don’t forget to use “Flag for review”, whenever you have doubt on your answer.
4/ The Questionnaire will be different for everyone

The below are some important topics, these areas required to be refreshed before attempting ACE.

LCDS
RemoteObject vs. Webservice vs. HTTPService

Flex3
[RemoteClass],[Bindable] Metadatas,E4X xml query, Labelfunction and Labelfield usage,Custom Event, Producer, consumer, validator,TabNavigator ,viewstack, setStyle, BlendMode, Modules vs. Sub Applications and formatter

OOPS
Interface, Encapsulation, Design patterns, access modifiers, Constructor and getter setters

AIR:
native platform in AIR Application,File management in AIR, Preloader, Drag and Drop in AIR, Security Sandbox in AIR, SQL Lite in AIR, create a Native AIR Application, Badge Installer in AIR

Spark :
working with state, ArrayList vs. Arraycollection, Animate, constraint layout in Spark Components, orientation of Child components,effects, create a custom component, Two-Way Binding, IVisualElement, ItemRenderer, LayoutBase, SkinnableComponent, TextInput, CSS namespace declaration, Descendant ID Type Class CSS types and Group

Dynamic Injection on runtime using BeanFactory

Met with requirement to inject object dynamically at runtime based on Push Message received.

Had a bit hard time finding solution, unusual with Swiz Framework.
Thought of sharing my experience here..
Step 1: In swiz Context assign the bean factory to your Bean Class

messenger.beanFactory = this.beanFactory;

Step 2:
In your bean class, Implement Interface IBeanFactoryAware
public class NativeMessenger implements IBeanFactoryAware

Step 3:
To Satisfy the implementation add the below code:
private var _beanFactory:IBeanFactory;
public function set beanFactory( beanFactory:IBeanFactory ):void{
_beanFactory = beanFactory;
}
Step 4:
Got access to Beanfactory
public var dynamicDAO:AbstractDAO;
protected function consumeHandler(event:MessageEvent =null) : void
{
var daoName:String = event.message.headers["dynamicdao"];
dynamicDAO = _beanFactory.getBeanByName(daoName).source as AbstractDAO;
}

Now the dynamicDAO is assigned with the bean dynamically based on the consumer Message.

Flash Builder Network Monitor Bug

When a sequence of service calls made to server using, Blaze DS.

I got the below error, where as i used to get the result handler and fault handler responses for the same request.
There was nothing wrong in server side,
[FaultEvent fault=[RPC Fault faultString="Error #2006: The supplied index is out of bounds." faultCode="InvokeFailed" faultDetail="null"] messageId=”" type=”fault” bubbles=false cancelable=true eventPhase=2]

At last, i got it by disabling the Network Monitor of Flash builder things were back in shape..

Record FLV with Screensharing

With AIR 2 Native Process help,  Print.jar helps press PrintScreen and the data from clipboard is used to get Screen Shots  to be written in FLV using FlvWriter.as
The Main Application file used to write FLV using the screen shot images is in this link.

Merge / Combine two ArrayCollections

// ArrayCollection 1
var arrC1:ArrayCollection;
// ArrayCollection 2
var arrC2:ArrayCollection; 
var array1:Array = arrC1.source
var array2:Array = arrC2.source
public function arrayContainsValue(arr:Array, value:Object):Boolean
{
       return (arr.indexOf(value) != -1);
}  
public function createUniqueCopy(a:Array):Array{
       var newArray:Array = new Array();        
       var len:Number = a.length;
       var item:Object;        
       for (var i:uint = 0; i < len; ++i)
       {
               item = a[i];                
               if(arrayContainsValue(newArray, item))
               {
                       continue;
               }
               newArray.push(item);
       }
       return newArray;
}  
var combinedArr:Array = createUniqueCopy(array1.concat(array2) );
var resultArrC:ArrayCollection =new ArrayCollection( combinedArr );

Camstudio video annotation

“unable to detect webcam / video source”

The above is the message i got continuously after trying a lot, so fixed it with Flex by creating a AIR to show the Webcam Video.
Source:

<?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" maxHeight="150" maxWidth="200" showStatusBar="false" skinClass="assets.DTApplicationSkin" alwaysInFront="true"> <fx:Script> <![CDATA[ private function videoDisplay_creationComplete():void { var camera:Camera = Camera.getCamera(); if (camera) { videoDisplay.attachCamera(camera); } } ]]> </fx:Script> <mx:VideoDisplay id="videoDisplay" creationComplete="videoDisplay_creationComplete();" width="100%" height="100%" horizontalCenter="0" verticalCenter="0"/> </s:WindowedApplication>


The link have the AIR file required. Download

How to Modify SWF without Recompilation

I could n’t access my Laptop last week, but i had some urgent work to do (recompile a old SWF). Here is how i did it.
This post is just a reference and guide based on the Post.
Find the Point which you want to modify using any of the available SWF Decompilers
Decompress the SWF using java.util.zip.DeflaterInputStream : Java Source Code file link
Jar File Download Link
Usage :  java -jar SWFCompress.jar c 'YourSWF.swf'
Download the Nemo440.AIR , to view the hex code.
Notice the exact place of the code to be modified using
The conventions of u30 encrypted Hex code is provided by Adobe.
Download any Free Hex Editors like HxD, to edit the SWF
Find the code part and modify the -decompressed SWF
Compress the decompressed SWF, back to the form, using SWFCompress.jar.
Usage :  java -jar SWFCompress.jar d 'YourSWF.swf'

Now the re compressed SWF is ready to go. Have Fun Cracking, Hacking SWF’s

Project: Swiz DAO

Libraries Used:  Swiz, AS3Signals and FoomongerSwizFramework.
Objective:
To create GenericDAO framework, like IBM Generic DAO (Java /Spring/ Hibernate)
About GenericDAO:
DAO is the Object which manages to perform CRUD Operation and other Common
Operations to be done over a ValueObject ( known as Pojo in Java ).
GenericDAO is a reusable DAO class which can be used generically.
Goal:

In IBM GenericDAO, to add a new DAO, the steps to be done is simply,
  1. Add a valueobject (pojo).
  2. Add a hbm.xml mapping file for the valueobject.
  3. Add the 10-line Spring configuration file for the DAO.
Similarly, in AS3 Project Swiz DAO. We want to attain a similar feet of achievement.
Client Side GenericDAO model:
As we were working on a Client Side language, also we should be managing a persistent object Collection (for every valueObject) .
Usage:
<swiz:Prototype name=”personDAO”
constructorArguments=”{['person',personProcessor]}” type=”{AbstractDAO}”
singleton=”true”/>
Added, How it works in Github: DI Mechanism Link

http://github.com/nsdevaraj/SwizDAO

Generic DAO in AS3

Built an AS3 Project to Work with GenericDAO using Swiz and AS3Signals

The project was inspired by Java Spring Framework:
IBM Generic Dao

The project uses the benefits of DI provided by Swiz 1.0.
The Deferred Instantiation of Swiz builds DAO Object only when [Inject] keyword is used.

Also, uses the latest Spark SkinnableComponent Framework for the View Part with Passive View.

The Source can be downloaded from SwizDAO Git
The below is the code from Swiz Context for a DAO Object:

<swiz:Prototype name=”taskDAO” constructorArguments=”{['task',taskProcessor]}” type=”{AbstractDAO}” singleton=”true”/>

Update Info : http://nsdevaraj.wordpress.com/2010/05/12/project-swiz-dao/

Frameworks Explained (Videos)

The Flex Frameworks Explained in “YouTube”
Parsley
http://bit.ly/ParsleyVideo
Mate
http://bit.ly/MateVideo10
http://bit.ly/MateVideo09
RobotLegs
http://bit.ly/RobotLegsVideo
Cairngorm with UM
http://bit.ly/CairngormUMVideo

The PDF Presentations and Links available from :
http://adamstudio.in/
http://groups.google.com/group/flexatbeach/web/resources-2009

AIR with Flex4 Compilation Bug

“VerifyError: Error #1014: Class flash.text.engine::TextLine could not be found.” – The Error I got when trying to compile MXML with below configurations:

AIR Beta 2 Runtime, Flex 4 SDK, AIR Beta 2 SDK

Solution :
Open the project folder and edit the “.actionScriptProperties” file
Change the compiled flash swf target runtime from htmlPlayerVersion=”9.0.28″ to htmlPlayerVersion=”10.0.0″.

Also make sure your app.xml namespace to be “http://ns.adobe.com/air/application/2.0beta2&#8243;

Speaking at DevSummit

Looking forward to speak at Adobe DevSummit @Chennai 24/Nov & @Hyd 1/Dec on Topic “Integration of Spring with BlazeDS and CairngormUM (Deep Dive)”

The Presentation Document : link &
Presentation

Speaking at Adobe DevSummit

DevSummit

Access Client Machine from AIR on Ease

This is a dream come true.
To run an EXE from AIR, do the following steps:
Step 1:
Install the exe from this Link
Step 2:
Import Flex Project samples, from install dir ex: C:\Program Files\FluorineFx Aperture\Samples
Step 3:
Copy *.dll files (apimaging.dll,apoutlook.dll,apSystem.dll,fluorinepp.dll and msi.dll) to your Flex src directory
Step 4:
Copy your ‘-app.xml’ to ‘C:\Program Files\FluorineFx Aperture\Debug’ location of install dir for debugging or just pack the AIR

Flex@Beach’09

Flex@Beach is being hosted at Chennai on August 8th.
Check the below links:
Agenda Venue @flexatbeach

The Group link to share files and discussions.
The Videos link live on YouTube.

Loading Image / Swf in MAC, AIR

A Quick tip, was stuck today to load an local image / swf inside AIR at MAC OS.
The below is the solution:

var filenotion:String =”;
if(Capabilities.os.search(“Mac”) >= 0) filenotion = “file://”;
Image.source= filenotion +imgFileURI;

Using / Creating Locale for your language

How to do :

1 ) To create resource bundles for different languages and then use the ResourceManager class provided by the Flex API to get the resources.
Just changing the locale of the resource manager will reflect changes in the entire application with the values from the new locale’s resource bundle.

How to Create Locale :

For example if I want to support two locales (en_US and fr_FR) in your application and I my parent folder is named as “Locales”, then I might have following folders. As en_US ,fr_FR

It will be like this :
Locales/en_US , Locales/fr_FR

Steps to do before make the Bundle

Part 1 : SDK

Create folder
1 D:\Program Files\Adobe\Flex Builder 3\sdks\3.2.0\frameworks\projects\framework\bundles \fr_FR
2 D:\Program Files\Adobe\Flex Builder 3\sdks\3.2.0\frameworks\projects\framework\bundles\fr_FR \src

Download and paste
3.http://opensource.adobe.com/svn/opensource/flex/sdk/trunk/frameworks/projects/framework/bundles/fr_FR inside step 2

Create folder :
4 D:\Program Files\Adobe\Flex Builder 3\sdks\3.2.0\frameworks\locale \fr_FR

Execute
5. D:\Program Files\Adobe\Flex Builder 3\sdks\3.2.0

bin\compc -locale=fr_FR -source-path+=frameworks/projects/framework/bundles/fr_FR/src -include-resource-bundles=collections,containers,controls,core,effects,formatters,logging,SharedResources,skins,states,styles,utils,validators -output=frameworks/locale/fr_FR/framework_rb.swc

Part 2 : Project

1. Set System PATH
D:\Program Files\Adobe\Flex Builder 3\sdks\3.2.0\bin
2. create required properties file mainBundle.properties
3. keep that file inside a folder with your locale name ‘fr_FR
4.execute from root path
mxmlc -locale=fr_FR -source-path={locale} -include-resource-bundles=mainBundle,collections,containers,controls,core,effects,skins,styles -output=src/Resources_fr_FR.swf

mxmlc -locale=en_US -source-path={locale} -include-resource-bundles=mainBundle,collections,containers,controls,core,effects,skins,styles -output=src/Resources_en_US.swf

After that place that swf file your Project

Locale/en_US :
Inside we need create the file name like “mainBundle.properties” inside that we need to create like that

welcome_title_text=Welcome,
form_first_name_text=First Name
form_second_name_text=Last Name
form_gender_text=Gender
form_gender_list_male_text=Male
form_gender_list_female_text=Female

Locale/fr_FR :
Inside we need create the file name like “mainBundle.properties” inside that we need to create like that

welcome_title_text=Bienvenue ,
form_first_name_text=Prénom
form_second_name_text=Nom de famille
form_gender_text=Sexe
form_gender_list_male_text=Mâle
form_gender_list_female_text=Femelle

Adding Locales to your Projects
Add the locale to the compiler options.
-locale=en_US,fr_FR

This link, claims to have compiled swc files for most languages : Babel

Flex with Java Collaborative using the Best Architectures of Both

This Post was my overdue subject, I wanted to help with a sample Application using Cairngorm, Spring BlazeDS Integration & Generic DAO.

This might be a heavy subject as it deals with many subjects:

The Source is available at the link: cairnspring

How to use the source effectively?
it is simple, steps below:

  1. Download, Source and Libs
  2. Unzip both and import “CairnSpring”, to your Eclipse
  3. Paste the lib files to “CairnSpring\WebContent\WEB-INF\lib” folder
  4. Import the “db.sql” into your MySQL Db, (change mysql port to 3036, else can be configured to default in “CairnSpring\WebContent\WEB-INF\config\jdbc.properties” file)
  5. In Eclipse, Window -> Preferences -> Web and XML -> XML Catalog -> Add User Specified Entries with below values
    Location : CairnSpring/WebContent/WEB-INF/config/spring-flex-1.0.xsd
    KeyType : Namespace Name
    Key : http://www.springframework.org/schema/flex/spring-flex-1.0.xsd
  6. Start the Tomcat Server with CairnSpring instance (the server host and port can be configured in file “CairnSpring\flex_src\Server.properties”)

Flex with JAVA

The best architectures for java with flex collaboration

spring – with – hibernate

http://www.ibm.com/developerworks/java/library/j-genericdao.html

spring -with – blaze

http://coenraets.org/blog/2009/03/springblazeds-integration-test-drive-m2-update-available/

maven – with – spring – flex

http://docs.codehaus.org/display/ENUNCIATE/Architecture+Guide

AS3 Color Utility Functions

Utility for Color functions, like RGB to CMYK, RGB to HSV, HSV to RGB, ColorTransformation, int color value to RGB and Color Calculations. Gist Link

package
{
import flash.geom.ColorTransform;
public class ColorUtil
{
/**
* RGBColorTransform Create an instance of the information.
* @ Param rgb RGB integer value that indicates (0×000000 – 0xFFFFFF)
* @ Param amount of fill adaptive value (0.0 – 1.0)
* @ Param alpha transparency (0.0 – 1.0)
* @ Return a new instance ColorTransform
* */
public static function colorTransform (rgb: uint = 0, amount: Number = 1.0, alpha: Number = 1.0): ColorTransform
{
amount = (amount> 1)? 1: (amount 1)? 1: (alpha > 16) & 0xff) * amount;
var g: Number = ((rgb>> 8 ) & 0xff) * amount;
var b: Number = (rgb & 0xff) * amount;
var a: Number = 1-amount;
return new ColorTransform (a, a, a, alpha, r, g, b, 0);
}

/**
* Subtraction.
* 2 RGB single number that indicates (0×000000 0xFFFFFF up from) is subtracted from the return numbers.
* @ Param col1 RGB numbers show (0×000000 0xFFFFFF up from)
* @ Param col2 RGB numbers show (0×000000 0xFFFFFF up from)
* @ Return value subtracted Blend
**/
public static function subtract (col1: uint, col2: uint): uint
{
var colA: Array = toRGB (col1);
var colB: Array = toRGB (col2);
var r: uint = Math.max (Math.max (colB [0] – (256-colA [0]), colA [0] – (256-colB [0])), 0);
var g: uint = Math.max (Math.max (colB [1] – (256-colA [1]), colA [1] – (256-colB [1])), 0);
var b: uint = Math.max (Math.max (colB [2] – (256-colA [2]), colA [2] – (256-colB [2])), 0);
return r <<16 | g <<8 | b;
}

/**
* Additive color.
* 2 RGB single number that indicates (0×000000 0xFFFFFF up from) Returns the value of the additive mixture.
* @ Param col1 RGB numbers show (0×000000 0xFFFFFF up from)
* @ Param col2 RGB numbers show (0×000000 0xFFFFFF up from)
* @ Return the additive color
**/
public static function sum (col1: uint, col2: uint): uint
{
var c1: Array = toRGB (col1);
var c2: Array = toRGB (col2);
var r: uint = Math.min (c1 [0] + c2 [0], 255);
var g: uint = Math.min (c1 [1] + c2 [1], 255);
var b: uint = Math.min (c1 [2] + c2 [2], 255);
return r <<16 | g <<8 | b;
}

/**
* Subtractive.
* 2 RGB single number that indicates (0×000000 0xFFFFFF up from) Returns the value of the subtractive color.
* @ Param col1 RGB numbers show (0×000000 0xFFFFFF up from)
* @ Param col2 RGB numbers show (0×000000 0xFFFFFF up from)
* @ Return the subtractive
**/
public static function sub (col1: uint, col2: uint): uint
{
var c1: Array = toRGB (col1);
var c2: Array = toRGB (col2);
var r: uint = Math.max (c1 [0]-c2 [0], 0);
var g: uint = Math.max (c1 [1]-c2 [1], 0);
var b: uint = Math.max (c1 [2]-c2 [2], 0);
return r <<16 | g <<8 | b;
}

/**
* Comparison (dark).
* 2 RGB single number that indicates (0×000000 0xFFFFFF up from) to compare, RGB lower combined returns a numeric value for each number.
* @ Param col1 RGB numbers show (0×000000 0xFFFFFF up from)
* @ Param col2 RGB numbers show (0×000000 0xFFFFFF up from)
* @ Return comparison (dark) values
**/
public static function min (col1: uint, col2: uint): uint
{
var c1: Array = toRGB (col1);
var c2: Array = toRGB (col2);
var r: uint = Math.min (c1 [0], c2 [0]);
var g: uint = Math.min (c1 [1], c2 [1]);
var b: uint = Math.min (c1 [2], c2 [2]);
return r <<16 | g <<8 | b;
}

/**
* Comparison (light).
* 2 RGB single number that indicates (0×000000 0xFFFFFF up from) to compare, RGB values combined with higher returns to their numbers.
* @ Param col1 RGB numbers show (0×000000 0xFFFFFF up from)
* @ Param col2 RGB numbers show (0×000000 0xFFFFFF up from)
* @ Return comparison (light) value
**/
public static function max (col1: uint, col2: uint): uint
{
var c1: Array = toRGB (col1);
var c2: Array = toRGB (col2);
var r: uint = Math.max (c1 [0], c2 [0]);
var g: uint = Math.max (c1 [1], c2 [1]);
var b: uint = Math.max (c1 [2], c2 [2]);
return r <<16 | g <<8 | b;
}

/**
* Values calculated from each RGB * RGB color value.
* @ Param r the red (R) indicating the number (0-255)
* @ Param g green (G) indicates the number (0-255)
* @ Param b blue (B) shows the number (0-255)
* @ Return obtained from the RGB color value for each indicating the number
**/
public static function rgb (r: uint, g: uint, b: uint): uint
{
return r <<16 | g <> 16 & 0xFF;
var g: uint = rgb>> 8 & 0xFF;
var b: uint = rgb & 0xFF;
return [r, g, b];
}

/**
* RGB from the respective figures, HSV sequences in terms of returns.
* RGB values are as follows.
* R – a number from 0 to 255
* G – a number from 0 to 255
* B – a number from 0 to 255
*
* HSV values are as follows.
* H – a number between 360-0
* S – number between 0 and 1.0
* V – number between 0 and 1.0
*
* Can not compute, including alpha.
* @ Param r the red (R) indicating the number (0×00 to 0xFF to)
* @ Param g green (G) indicates the number (0×00 to 0xFF to)
* @ Param b blue (B) shows the number (0×00 to 0xFF to)
* @ Return HSV values into an array of [H, S, V]
**/
public static function RGBtoHSV (r: Number, g: Number, b: Number): Array
{
r / = 255; g / = 255; b / = 255;
var h: Number = 0, s: Number = 0, v: Number = 0;
var x: Number, y: Number;
if (r> = g) x = r; else x = g; if (b> x) x = b;
if (r <= g) y = r; else y = g; if (b <y) y = b;
v = x;
var c: Number = xy;
if (x == 0) s = 0; else s = c / x;
if (s! = 0) {
if (r == x) {
h = (gb) / c;
} else {
if (g == x) {
h = 2 + (br) / c;
} Else {
if (b == x) {
h = 4 + (rg) / c;
}
}
}
h = h * 60;
if (h <0) h = h +360;
}
return [h, s, v];
}
/**
* RGB from the respective figures, HSV sequences in terms of returns.
* RGB values are as follows.
* R – a number from 0 to 255
* G – a number from 0 to 255
* B – a number from 0 to 255
*
* CMYK values are as follows.
* C – a number between 0 to 255 representing cyan
* M – number between 0 to 255 representing magenta
* Y – number between 0 to 255 representing yellow
* K – number between 0 to 255 representing black
*
* Can not compute, including alpha.
* @ Param r the red (R) indicating the number (0×00 to 0xFF to)
* @ Param g green (G) indicates the number (0×00 to 0xFF to)
* @ Param b blue (B) shows the number (0×00 to 0xFF to)
* @ Return CMYK values into an array of [H, S, V]
**/
public static function RGBtoCMYK( r:Number, g:Number, b:Number ):Array
{
var c:Number=0, m:Number=0, y:Number=0, k:Number=0, z:Number=0;
c = 255 – r;
m = 255 – g;
y = 255 – b;
k = 255;

if (c < k)
k=c;
if (m < k)
k=m;
if (y < k)
k=y;
if (k == 255)
{
c=0;
m=0;
y=0;
}else
{
c=Math.round(255*(c-k)/(255-k));
m=Math.round (255*(m-k)/(255-k));
y=Math.round (255*(y-k)/(255-k));
}
return [ c, m, y, k ];
}

/**
* HSV from each of the RGB values to determine a return as an array.
* RGB values are as follows.
* R – a number from 0 to 255
* G – a number from 0 to 255
* B – a number from 0 to 255
*
* HSV values are as follows.
* H – a number between 360-0
* S – number between 0 and 1.0
* V – number between 0 and 1.0
*
* H is replaced with equivalent numbers in the range of the 360-0 that is out of range.
* Can not compute, including alpha.
*
* @ Param h hue (Hue) number that indicates (to 360-0)
* @ Param s the saturation (Saturation) shows the number (0.0 to 1.0)
* @ Param v lightness (Value) indicates the number (0.0 to 1.0)
* @ Return RGB values into an array of [R, G, B]
**/
public static function HSVtoRGB (h: Number, s: Number, v: Number): Array
{
var r: Number = 0, g: Number = 0, b: Number = 0;
var i: Number, x: Number, y: Number, z: Number;
if (s 1) s = 1; if (v 1) v = 1;
h = h% 360; if (h > 0;
x = v * (1 – s); y = v * (1 – s * (h – i)); z = v * (1 – s * (1 – h + i));
switch (i) {
case 0: r = v; g = z; b = x; break;
case 1: r = y; g = v; b = x; break;
case 2: r = x; g = v; b = z; break;
case 3: r = x; g = y; b = v; break;
case 4: r = z; g = x; b = v; break;
case 5: r = v; g = x; b = y; break;
}
return [r * 255>> 0, g * 255>> 0, b * 255>> 0];
}

}
}

SQLLite DBManager for AIR

The code file contains functions for managing SQL Lite Table and Database

Preloader for Flex Application

Save the below code as a Class file and refer the class name as

import mx.preloaders.*;
import flash.events.ProgressEvent;
public class Bar extends DownloadProgressBar
{
public function Bar()
{
super();
// Set the download label.
downloadingLabel=”Downloading…”
// Set the initialization label.
initializingLabel=”Initializing book…”
// Set the minimum display time to 2 seconds.
MINIMUM_DISPLAY_TIME=2000;
}
// Override to return true so progress bar appears
// during initialization.
override protected function showDisplayForInit(elapsedTime:int,
count:int):Boolean {
return true;
}
// Override to return true so progress bar appears during download.
override protected function showDisplayForDownloading(
elapsedTime:int, event:ProgressEvent):Boolean {
return true;
}
}

fileReference.load()

Today, i faced a weird problem of fileReference.load() not working in AIR. Even, in the latest 3.3 SDK. To resolve that, you have to install Flex Builder Update. Then, modify your App.xml into air version 1.5. As, to get the benefits of latest AIR Version.

Otherwise, in AIR: Code gets compiled but when we select a file from system, it throws a error.

Date Util Functiions

Utility functions to find First Day of a month, Relative Date information like “Today”, “Yesterday”

public static function getFirstDayofMonth(fullyear:uint,month:uint):uint
{
var tmp:Date = new Date(fullyear,month,1);
return tmp.getDay();
}

public static function isLeapYear( fullyear:uint ):Boolean
{
var flag:Boolean = false;
if(((fullyear%4==0) && (fullyear%100!=0)) || (fullyear%400==0)) flag = true;
return flag;
}

public static function getWeekName( index:uint , type:uint=0 ):String
{
var week:Array;
if(type==0) week = ["SUNDAY","MONDAY","TUSEDAY","WEDNESDAY","THURSDAY","FRIDAY","SATURDAY"];
else if(type==1) week = ["SUN","MON","TUE","WED","THU","FRI","SAT"];
else week = ["Sun","Mon","Tue","Wed","Thu","Fri","Sat"];
return week[index];
}

public static function getMonthName( index:uint , type:uint=0 ):String
{
var month:Array;
if(type==0) month = ["JANUARY","FEBRUARY","MARCH","APRIL","MAY","JUNE","JULY","AUGUST","SEPTEMBER","OCTOBER","NOVEMBER","DECEMBER"];
else if(type==1) month = ["jan","feb","mar","apr","may","jun","jul","aug","sep","oct","nov","dec"];
else month = ["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"];
return month[index];
}

public static function getRelativeDateName( date:Date, type:uint=0 ):String
{
var d1:Date = new Date();
d1 = new Date(d1.getFullYear(),d1.getMonth(),d1.getDate());
var d2:Date = new Date(date.getFullYear(),date.getMonth(),date.getDate());
if(d11000*60*60*24*7) return “”;
if(type>8||isNaN(type)) type = 0;
var list:Array;
switch(type) {
case 0: case 3:
list = ["TODAY","YESTERDAY"]; break;
case 1: case 4:
list = ["Today","Yesterday"]; break;
case 2: case 5:
list = ["today","yesterday"]; break;
}
var diff:int = d1.getDate()-d2.getDate();
if(diff<=1) return list[diff];
return getWeekName( d2.getDay(), type );
}

Currency/Numeric Formatter

The below custom functions might be of use where you don’t want to use currency formatter or numeric Formatter of AS3

 
public function currencyFormat( number:Number ):String {
var words:Array = String( number ).split( “” ).reverse(); 
  var results:Array = new Array();
 var l:int = words.length;
  for ( var i:int = 0; i < l; i++ ) {
   results.push( words[i] );
   if ( i % 3 == 2 ) {
     results.push( “,” );
   }
   }
   return results.reverse().join( “” );
}

public function prefixZero( number:Number, figure:int ):String {
   var str:String = String( number );
   for ( var i:int = 0; i < figure; i++ ) {
     str = “0″ + str;
   }
   return str.substr( str.length – figure, str.length );
}

ByteArray to BitmapData

The Below code demonstrates the conversion of ByteArray to BitmapData. In the below case, SWF is loaded and converted into BitmapData

private function swfLoad_complete(evt:Event):void {
byteArrayToBitmapData(swf.content.loaderInfo.bytes);
}
private function byteArrayToBitmapData(ba:ByteArray):void {
loader.contentLoaderInfo.addEventListener(Event.COMPLETE, getBitmapData);
loader.loadBytes(ba);
}
private function getBitmapData(e:Event):void {
var content:* = loader.content;
var BMPData:BitmapData = new BitmapData(content.width,content.height);
var UIMatrix:Matrix = new Matrix();
BMPData.draw(content, UIMatrix);
}

Convert Data Types: ArrayCollection, XML, Object, String

The code below demonstrates the data type conversions among basic DataTypes used most in Flex. The ‘init()’ method does to and from conversion for ArrayCollection to XML and XML to ArrayCollection

Object, String, XML, ArrayCollection

 

import mx.collections.ArrayCollection;
import mx.rpc.xml.SimpleXMLEncoder;
import mx.rpc.xml.SimpleXMLDecoder;
import mx.utils.ObjectUtil; 
  private function xmlToArrayCollection(xml:XML):ArrayCollection{                 
            var xmlDoc:XMLDocument = new XMLDocument(xml.toString());
           var decoder:SimpleXMLDecoder = new SimpleXMLDecoder(true);
            var resultObj:Object = decoder.decodeXML(xmlDoc);
            var ac:ArrayCollection =new ArrayCollection(Array(resultObj.root.list.source.item));
            return ac;
}
private function objectToXML(obj:Object):XML {
            var qName:QName = new QName(“root”);
            var xmlDocument:XMLDocument = new XMLDocument();
            var simpleXMLEncoder:SimpleXMLEncoder = new SimpleXMLEncoder(xmlDocument);
            var xmlNode:XMLNode = simpleXMLEncoder.encodeValue(obj, qName, xmlDocument);
            var xml:XML = new XML(xmlDocument.toString());
            return xml;
}
private function objectToArrayCollection(obj:Object):ArrayCollection {
            var ac:ArrayCollection =  new ArrayCollection(obj as Array);
            return ac;

private function arrayCollectionToXML(ac:ArrayCollection):XML{
var xml:XML = objectToXML(ac);
return xml;
}
private function init():void{
  var arr:Array = new Array();
  arr.push({data:0,name:’deva’});
  arr.push({data:1,name:’raj’});
  var ac:ArrayCollection = new ArrayCollection(arr);
  var xml:XML = arrayCollectionToXML(ac);
var newAc:ArrayCollection = xmlToArrayCollection(xml);
trace(newAc[0][0].name);
}
private function objToStr(value:Object,indent:int =0,
                                         refs:Dictionary= null, 
                                         namespaceURIs:Array = null, 
                                         exclude:Array = null):String{
var str:String;
var refCount:int = 0;
if (value is Date)
            {
                return value.toString();
            }
            else if (value is XMLNode)
            {
                return value.toString();
            }
            else if (value is Class)
            {
                return “(” + getQualifiedClassName(value) + “)”;
            }
            else
            {
                var classInfo:Object = ObjectUtil.getClassInfo(value, exclude,
                    { includeReadOnly: true, uris: namespaceURIs });
                var properties:Array = classInfo.properties;
                str = “(” + classInfo.name + “)”;
                if (refs == null)
                    refs = new Dictionary(true);
                var id:Object = refs[value];
                if (id != null)
                {
                    str += “#” + int(id);
                    return str;
                }
                if (value != null)
                {
                    str += “#” + refCount.toString();
                    refs[value] = refCount;
                    refCount++;
                }
                var isArray:Boolean = value is Array;
                var isDict:Boolean = value is Dictionary;
                var prop:*;
                indent += 2;
                for (var j:int = 0; j < properties.length; j++)
                {
                    str = newline(str, indent);
                    prop = properties[j];
                    if (isArray)
                        str += “[";
                    else if (isDict)
                        str += "{";
                    if (isDict)
                    {
                        str += objToStr(prop, indent, refs,
                                                namespaceURIs, exclude);
                    }
                    else
                    {
                        str += prop.toString();
                    }
                    if (isArray)
                        str += "] “;
                    else if (isDict)
                        str += “} = “;
                    else
                        str += ” = “;
                    try
                    {
                        str += objToStr(value[prop], indent, refs,
                                                namespaceURIs, exclude);
                    }
                    catch(e:Error)
                    {
                        str += “?”;
                    }
                }
                indent -= 2;
                return str;
            }
}
private static function newline(str:String, n:int = 0):String
   {
       var result:String = str;
       result += “\n”;
       for (var i:int = 0; i < n; i++)
       {
           result += ” “;
       }
       return result;
   }
/* General function for Conversion (thanks, Krystian Bień)
 public function xmlToArrayCollection(xml:XML):ArrayCollection{
            var temp:String = ‘<items>’ + xml.toString() + ‘</items>’;
            xml = XML(temp);
            var xmlDoc:XMLDocument = new XMLDocument(xml.toString());
            var decoder:SimpleXMLDecoder = new SimpleXMLDecoder(true);
            var resultObj:Object = decoder.decodeXML(xmlDoc);
            var ac:ArrayCollection;
            ac = new ArrayCollection();
            ac.addItem(resultObj.items);
            return ac;                
        }*/

Flex Effects Explorer

I came across the efflex.org. Its so amazing.. someone took effort to make such library.. I compiled a zip with required Lib elements on this link efflex.

AS3 : Basic String function

Some Basic String functions:

public function replaceChars(str:String, Char:String, replace:String) : String
{
var result:String = “”;
for (var i:int = 0; i < str.length; i++) {
if (str.charAt(i) == Char)
{
result += replace;
}
else
{
result += str.charAt(i)
}
}
return result;
}

public function trimWhiteSpace(str:String) : String
{
var pattern:RegExp = /[\s]+/g;
return str.replace(pattern, “”);
}

public function containsAlphaNumeric(str:String) : Boolean
{
var pattern:RegExp = /[^a-zA-Z0-9]/;
return str.search(pattern) != 0;
}

P2P Video Conferencing : Stratus

The adobe labs rocks once again, Stratus. This is a superior technology for P2P communication using RTMFP-capable server. The link does have sample included, example here (w/o DB) and here (w DB) . I have included file sharing along with this.

Licensing Flex / AIR Application

I have came through the thread and this is my solution  to protect the product with a serial key uncrackable.

The solution can be used in both Online browser based / AIR products.

The MD5 class does create a Unique system ID and verifies the MD5 checksum with a foreign key to check whether the user is registered or not.

MD5.registereduser – Boolean returns true, if user is registered.
MD5.skey                      - The Serial key to be used, to register (can store in a db or xml)
MD5.setRegKey(MD5.skey);   – To unlock the product.

Preview Image Loader

Loading Image from local file system using the power of  Flash Player 10, Filereference.load()
Check the Demo the link contains the source file.

CO Binding Util

Like Chemical CoValent Bonding, Bind two Objects of Flex through this
AS3 Utility… ;)  

package
{
import flash.events.Event;
import mx.binding.utils.ChangeWatcher;
public class CovalentBindig
{
public static function Bond(obj1:Object, prop1:String, obj2:Object, prop2:String):void
{
var flag:Boolean = false;
ChangeWatcher.watch(obj1, prop1, function(event:Event):void
{
if(!flag)
{
flag = true;
obj2[prop2] = obj1[prop1];
flag = false;
}
});

ChangeWatcher.watch(obj2, prop2, function(event:Event):void
{
if(!flag)
{
flag = true;
obj1[prop1] = obj2[prop2];
flag = false;
}
});
}
}
}

Dotted Line Util

Dotted Line, Utility Class for AS3 

package {
import flash.display.Graphics;
import flash.geom.Point;
public class DotLine{
public function DotLine( target:Graphics, seg:Number=20, xx:Number=0, yy:Number=0 ):void{
this.target = target;
this.now = new Point( xx, yy );
this.seg = seg;
this.rest = 0;
this.flag = false;
}
public var target : Graphics;
public var seg : Number;
public var now :  Point;
public var rest : Number;
public var flag : Boolean;
public function dotLineTo( xx:Number, yy:Number ):void{
var s: Point = new Point( now.x, now.y );
var e: Point = new Point( xx, yy );
var d:Number = Point.distance( s, e );
now.x = e.x;
now.y = e.y;
rest = (seg * 1 < rest) ? rest – seg * Math.floor( rest / seg ) : rest;
if(d <= rest){
rest -= d;
if(flag){
target.lineTo( e.x, e.y );
flag = (rest == 0) ? false : true;
}
else{
target.moveTo( e.x, e.y );
flag = (rest == 0) ? true : false;
}
return void;
}

var m:Number = 1 / ( d / seg );
var n:Number = 1 / ( d / rest );

for( var i:Number=1-n; 0<i; i-=m ){
var a: Point = Point.interpolate( s, e, i );
if(flag){
target.lineTo( a.x, a.y );
flag = false;
}
else{
target.moveTo( a.x, a.y );
flag = true;
}
if( i – m < 0 ){
var b: Point = Point.interpolate( s, e, i – m );
var c: Point = Point.interpolate( s, e, 0 );
rest = Point.distance( e, b );
if(flag){
target.lineTo( c.x, c.y );
}
else{
target.moveTo( c.x, c.y );
}
}
}
}

}
}

Collision Detection AS3 Util

Collision Detection Utility class for AS3,

Usage: var collide:Rectangle = checkForCollision(obj1, obj2);

package {
import flash.display.BitmapData;
import flash.display.BlendMode;
import flash.display.DisplayObject;
import flash.display.DisplayObjectContainer;
import flash.geom.Matrix;
import flash.geom.ColorTransform;
import flash.geom.Rectangle;

public class CollisionDetection{

public static function checkForCollision(firstObj: DisplayObject,secondObj: DisplayObject):Rectangle
{
var bounds1:Object = firstObj.getBounds(firstObj.root);
var bounds2:Object = secondObj.getBounds(secondObj.root);

if (((bounds1.right < bounds2.left) || (bounds2.right < bounds1.left)) || ((bounds1.bottom < bounds2.top) || (bounds2.bottom < bounds1.top)) ) {
return null;
}

var bounds:Object = {};
bounds.left = Math.max(bounds1.left,bounds2.left);
bounds.right= Math.min(bounds1.right,bounds2.right);
bounds.top = Math.max(bounds1.top,bounds2.top);
bounds.bottom = Math.min(bounds1.bottom,bounds2.bottom);

var w:Number = bounds.right-bounds.left;
var h:Number = bounds.bottom-bounds.top;

if(w < 1 || h < 1)
{
return null;
}

var bitmapData:BitmapData = new BitmapData(w,h,false);

var matrix:Matrix = firstObj.transform.concatenatedMatrix;
matrix.tx -= bounds.left;
matrix.ty -= bounds.top;
bitmapData.draw(firstObj,matrix,new ColorTransform(1,1,1,1,255,-255,-255,255));

matrix = secondObj.transform.concatenatedMatrix;
matrix.tx -= bounds.left;
matrix.ty -= bounds.top;
bitmapData.draw(secondObj,matrix,new ColorTransform(1,1,1,1,255,255,255,255),BlendMode.DIFFERENCE);

var intersection:Rectangle = bitmapData.getColorBoundsRect(0xFFFFFFFF,0xFF00FFFF);

/*try{
bitmapData.dispose();
}catch(e:Error){}*/

if (intersection.width == 0) { return null; }

intersection.x += bounds.left;
intersection.y += bounds.top;

return intersection;
}
}
}

Execute Commands on queue

The AS3 Utility Class to add commands in a queue, the usage and class is below:

/** 
* var commands : CommandsQueue = new CommandsQueue();
* commands.addCommand( this, myFunc );
* commands.addCommand( this, myFunc2, [0,2], this, Event.COMPLETE );
* commands.execute();
*/
package
{
import flash.events.Event;
import flash.events.EventDispatcher;

public class CommandsQueue extends EventDispatcher
{
protected var commands : Array;
protected var _index : Number = 0;
public var onComplete : Function;

public function CommandsQueue():void
{
commands = [];
}
public function addCommand( thisObj : Object, func : Function, params: Array = null , completeEventDispatcher : Object = null, completeEventName : String= null ) : void
{
commands.push({
thisObj : thisObj,
func : func,
completeEventDispatcher : completeEventDispatcher || thisObj,
completeEventName : completeEventName,
params : params
})
}
public function get progress():Number
{
return (commands.length>0)? _index / commands.length * 100 : 0;
}
public function cancel() : void
{
throw new Error(“commandQueue.cancel is not implemented yet”);
}
public function execute() : void
{
doNext();
}
public function get index():int
{
return _index;
}
public function get length():int
{
return commands.length;
}
protected function doNext() : void
{
var act : Object = commands[ _index ];

if( act.completeEventName ){
act.completeEventDispatcher.addEventListener(act.completeEventName, _commandComplete, false, 0, true);
act.func.apply( act.thisObj, act.params );
} else {
act.func.apply( act.thisObj, act.params );
doNextCommand();
}
}
protected function doNextCommand() : void
{
var act : Object = commands[ _index ];

if( act.completeEventName )
act.completeEventDispatcher.removeEventListener(act.completeEventName, _commandComplete);

_index ++;

if( _index == commands.length )
{
commands = []; //remove all registerd command for GC
if( onComplete != null )
onComplete();
dispatchEvent( new Event(Event.COMPLETE) );
}else{
doNext();
}
}
protected function _commandComplete( e : Event ) : void
{
doNextCommand();
}
}

AS3 GarbageCollection Utility

The below class serves as Garbage Collection utility for AS3. You can use it to prevent your applications from memory leakage.

package{
import flash.events.TimerEvent;
import flash.system.System;
import flash.utils.Timer;
public class GCUtil {
private var _timer:Timer;
public function GCUtil(interval_sec:uint = 60) {
_timer = new Timer(interval_sec*1000);
startGC(interval_sec);
}
public static function doGC():void {
System.gc();
}
public function startGC(interval_sec:uint):void {
if (interval_sec > 0) {
_timer.delay = interval_sec*1000;
if (!_timer.running) {
_timer.addEventListener(TimerEvent.TIMER, handleTimer);
_timer.start();
}
} else {
stopGC();
}
}
public function stopGC():void {
if (!_timer.running) {
_timer.removeEventListener(TimerEvent.TIMER, handleTimer);
_timer.stop();
_timer.delay = 0;
}
}
private function handleTimer(te:TimerEvent):void                       {
doGC();
}
}
}

Elearning using Flex

I am glad to announce the first Step for basic requirements of E-Learning using Flex has been achieved.
Basic Requirements met:

  • All Flash player versions starting from Flash Player version 6 to 10, should be loaded. (For support of old elearning courses).
  • Without any memory leak due to loading multiple swf files.
  • Ability to navigate to any particular lesson (SWF).
  • XML Support for loading swf files into a lesson.
  • PreLoader for showing the loading status of individual SWF files
  • Ability to detect events of SWF files (eg: totalframes, swf playing etc.,) 

See the demo of loading a number of animations. The source files include floader.mxmlForcibleLoader.as and XML

Power of FP10

Get your own mp3 from local system played from web. more

AVM1Movie Controller in Flex

Overcome restrictions on an AVM1 SWF file loaded by an AVM2 SWF file:

While trying to control AVM1Movie (Flash Player 8, 9, 10 or older) from flex, we will get the below error message: ”Property stop not found on flash.display.AVM1Movie and there is no default value. ”

To overcome this problem, ForcibleLoader class converts them into latest player versions on runtime. The below is an working example for how to control AVM1Movie from Flex.

<?xml version=”1.0″ encoding=”utf-8″?>
<mx:Application xmlns:mx=”http://www.adobe.com/2006/mxml&#8221; layout=”absolute” initialize=”init()”>
<mx:Script>
<![CDATA[
private var swfURL:String = "AVM1Movie.swf";
private var libMC:MovieClip = new MovieClip();
private function init():void{
var loader:Loader = new Loader();
loader.contentLoaderInfo.addEventListener(Event.COMPLETE, swfComplete);
var fLoader:ForcibleLoader = new ForcibleLoader(loader);
fLoader.load(new URLRequest(swfURL));
swfContainer.addChild(loader);
}
private function swfComplete(event:Event):void{
libMC = event.currentTarget.content as MovieClip;
libMC.gotoAndStop(1);
}
]]>
</mx:Script>
<mx:UIComponent id=”swfContainer”/>
<mx:NumericStepper id=”slide” change=”{libMC.gotoAndStop(slide.value)}”/>
</mx:Application>

Loading flash library asset in Flex

The below is the code to load flash library asset (using linkage name) on Flex.

<?xml version=”1.0″ encoding=”utf-8″?>
<mx:Application xmlns:mx=”http://www.adobe.com/2006/mxml&#8221; creationComplete=”onCreationComplete()” >
<mx:Script>
<![CDATA[
import mx.core.UIComponent;
private function onCreationComplete():void{
var swfLoader:Loader = new Loader();
swfLoader.contentLoaderInfo.addEventListener(Event.COMPLETE, onSWFLoadComplete);
swfLoader.load(new URLRequest("flash.swf"));
}
private function onSWFLoadComplete(event:Event):void{
var tempClass:Class = event.target.applicationDomain.getDefinition("libraryAsset") as Class;
var movieClip:MovieClip = new tempClass() as MovieClip;
var uiComp:UIComponent = new UIComponent();
uiComp.addChild(movieClip);
addChild(uiComp);
}
]]>
</mx:Script>
</mx:Application>


Follow

Get every new post delivered to your Inbox.

Join 436 other followers