You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@flex.apache.org by ah...@apache.org on 2015/09/12 00:35:31 UTC

git commit: [flex-examples] [refs/heads/develop] - ProductDashboard app

Repository: flex-examples
Updated Branches:
  refs/heads/develop 8ff391f78 -> 7537f95dd


ProductDashboard app


Project: http://git-wip-us.apache.org/repos/asf/flex-examples/repo
Commit: http://git-wip-us.apache.org/repos/asf/flex-examples/commit/7537f95d
Tree: http://git-wip-us.apache.org/repos/asf/flex-examples/tree/7537f95d
Diff: http://git-wip-us.apache.org/repos/asf/flex-examples/diff/7537f95d

Branch: refs/heads/develop
Commit: 7537f95dd95444d024b6d939eaad409a31dbe5d3
Parents: 8ff391f
Author: Alex Harui <ah...@apache.org>
Authored: Fri Sep 11 15:36:06 2015 -0700
Committer: Alex Harui <ah...@apache.org>
Committed: Fri Sep 11 15:36:06 2015 -0700

----------------------------------------------------------------------
 ProductDashboard/build.xml                      | 295 ++++++++++
 ProductDashboard/src/MyInitialView.mxml         | 148 +++++
 ProductDashboard/src/Product.as                 |  56 ++
 ProductDashboard/src/ProjectDashboard.mxml      |  91 +++
 ProductDashboard/src/apple-touch-icon-60.png    | Bin 0 -> 9688 bytes
 ProductDashboard/src/config.json                |  77 +++
 .../src/controllers/MyController.as             | 147 +++++
 ProductDashboard/src/main.css                   |  93 ++++
 ProductDashboard/src/models/MyModel.as          | 558 +++++++++++++++++++
 9 files changed, 1465 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/flex-examples/blob/7537f95d/ProductDashboard/build.xml
----------------------------------------------------------------------
diff --git a/ProductDashboard/build.xml b/ProductDashboard/build.xml
new file mode 100644
index 0000000..3fce12c
--- /dev/null
+++ b/ProductDashboard/build.xml
@@ -0,0 +1,295 @@
+<?xml version="1.0"?>
+<!--
+
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+-->
+
+<project name="ProjectDashboard" basedir="." default="main">
+    <property environment="env"/>
+    <property name="FLEX_HOME" value="${env.FLEX_HOME}" />
+    <property name="FLEXJS_HOME" value="${env.FLEX_HOME}" />
+    <property name="FALCON_HOME" value="${env.FLEX_HOME}" />
+    <property name="FALCONJX_HOME" value="${env.FLEX_HOME}/js" />
+    
+    <property name="theme_arg" value="-theme=${FLEX_HOME}/frameworks/libs/flat.swc" />
+    <property name="example" value="ProjectDashboard" />
+    
+    <path id="lib.path">
+      <fileset dir="${FALCON_HOME}/lib" includes="falcon-flexTasks.jar"/>
+    </path>
+    
+    <target name="clean" >
+        <delete dir="${basedir}/bin-debug" failonerror="false" />
+        <delete dir="${basedir}/bin" failonerror="false" />
+    </target>
+    
+    <target name="main" depends="compile, compilejs, get-data" />
+    
+    <target name="compile" description="Compiles ${example}">
+        <echo message="Compiling ${example}.swf"/>
+        <echo message="FLEX_HOME: ${FLEX_HOME}"/>
+
+        <!-- Load the <compc> task. We can't do this at the <project> level -->
+        <!-- because targets that run before flexTasks.jar gets built would fail. -->
+        <taskdef resource="flexTasks.tasks" classpathref="lib.path"/>
+        <!-- this is a dummy var placeholder in case some example needs to define a theme
+            then they would set theme_arg=-theme=<path to theme> -->
+        <property name="theme_arg" value="-define=CONFIG::theme,false" />
+        <mxmlc fork="true"
+               file="${basedir}/src/${example}.mxml"
+               output="${basedir}/bin-debug/${example}.swf">
+            <!--<jvmarg line="${mxmlc.jvm.args}"/>-->
+            <arg value="+flexlib=${basedir}/frameworks" />
+            <arg value="-debug" />
+            <arg value="${theme_arg}" />
+            <arg value="-compiler.mxml.children-as-data" />
+            <arg value="-compiler.binding-value-change-event=org.apache.flex.events.ValueChangeEvent" />
+            <arg value="-compiler.binding-value-change-event-kind=org.apache.flex.events.ValueChangeEvent" />
+            <arg value="-compiler.binding-value-change-event-type=valueChange" />
+            <arg value="+playerglobal.version=${playerglobal.version}" />
+            <arg value="+env.PLAYERGLOBAL_HOME=${env.PLAYERGLOBAL_HOME}" />
+        </mxmlc>
+        
+        <html-wrapper 
+            height="100%" 
+            width="100%"
+            bgcolor="#ffffff"
+            name="${example}"
+            versionmajor="11"
+            versionminor="1"
+            versionrevision="0" 
+            output="${basedir}/bin-debug"/> 
+ 
+        <copy todir="${basedir}/bin-debug">
+            <fileset dir="${basedir}/src">
+                <include name="**/*.png" />
+                <include name="**/*.jpg" />
+            </fileset>
+        </copy>
+        <copy todir="${basedir}/bin-debug/fonts">
+            <fileset dir="${FLEX_HOME}/frameworks/fonts">
+                <include name="**/*.swf" />
+            </fileset>
+        </copy>
+    </target>
+    
+    <target name="compilejs" description="Cross-compiles ${example}" unless="no.js">
+        <echo message="Compiling ${example}.js"/>
+        <echo message="FLEX_HOME: ${FLEX_HOME}"/>
+        <echo message="FALCONJX_HOME: ${FALCONJX_HOME}"/>
+        <property name="theme_arg" value="-define=CONFIG::theme,false" />
+
+        <java jar="${FALCONJX_HOME}/lib/mxmlc.jar" resultProperty="errorCode"
+            fork="true">
+            <!--<jvmarg line="${mxmlc.jvm.args}"/>-->
+            <jvmarg line="-Dflexlib=${FLEXJS_HOME}/frameworks}"/>
+            <arg value="+flexlib=${FLEXJS_HOME}/frameworks" />
+            <arg value="-debug" />
+            <arg value="${theme_arg}" />
+            <arg value="-compiler.mxml.children-as-data" />
+            <arg value="-compiler.binding-value-change-event=org.apache.flex.events.ValueChangeEvent" />
+            <arg value="-compiler.binding-value-change-event-kind=org.apache.flex.events.ValueChangeEvent" />
+            <arg value="-compiler.binding-value-change-event-type=valueChange" />
+            <arg value="+playerglobal.version=${playerglobal.version}" />
+            <arg value="+env.PLAYERGLOBAL_HOME=${env.PLAYERGLOBAL_HOME}" />
+            <arg value="-js-output-type=FLEXJS" />
+            <arg value="-sdk-js-lib=${FLEXJS_HOME}/frameworks/js/FlexJS/libs" />
+            <arg value="${basedir}/src/${example}.mxml" />
+        </java>
+        <fail>
+			<condition>
+				<not>
+					<or>
+						<equals arg1="${errorCode}" arg2="0" />
+						<equals arg1="${errorCode}" arg2="2" />
+					</or>
+				</not>
+			</condition>
+		</fail>
+    </target>
+
+
+    <macrodef name="html-wrapper">
+        <attribute name="width"/>
+        <attribute name="height"/>
+        <attribute name="bgcolor"/>
+        <attribute name="name"/>
+        <attribute name="versionmajor"/>
+        <attribute name="versionminor"/>
+        <attribute name="versionrevision"/>
+        <attribute name="output"/>
+            <sequential>
+                <copy toFile="@{output}/@{name}.html" 
+                    file="${FLEXJS_HOME}/templates/swfobject/index.template.html" />
+                <copy toDir="@{output}/history">
+                    <fileset dir="${FLEXJS_HOME}/templates/swfobject/history">
+                        <include name="**"/>
+                    </fileset>
+                </copy>
+                <copy toDir="@{output}">
+                    <fileset dir="${FLEXJS_HOME}/templates/swfobject">
+                        <include name="*"/>
+                        <exclude name="index.template.html"/>
+                    </fileset>
+                </copy>
+                <replace file="@{output}/@{name}.html">
+                    <replacefilter
+                        token="$${title}"
+                        value="@{name}"/>
+                </replace>
+                <replace file="@{output}/@{name}.html">
+                    <replacefilter
+                        token="$${bgcolor}"
+                        value="@{bgcolor}"/>
+                </replace>
+                <replace file="@{output}/@{name}.html">
+                    <replacefilter
+                        token="$${useBrowserHistory}"
+                        value="--"/>
+                </replace>
+                <replace file="@{output}/@{name}.html">
+                    <replacefilter
+                        token="$${version_major}"
+                        value="@{versionmajor}"/>
+                </replace>
+                <replace file="@{output}/@{name}.html">
+                    <replacefilter
+                        token="$${version_minor}"
+                        value="@{versionminor}"/>
+                </replace>
+                <replace file="@{output}/@{name}.html">
+                    <replacefilter
+                        token="$${version_revision}"
+                        value="@{versionrevision}"/>
+                </replace>
+                <replace file="@{output}/@{name}.html">
+                    <replacefilter
+                        token="$${expressInstallSwf}"
+                        value="expressInstall.swf"/>
+                </replace>
+                <replace file="@{output}/@{name}.html">
+                    <replacefilter
+                        token="$${expressInstallSwf}"
+                        value="expressInstall.swf"/>
+                </replace>
+                <replace file="@{output}/@{name}.html">
+                    <replacefilter
+                        token="$${width}"
+                        value="@{width}"/>
+                </replace>
+                <replace file="@{output}/@{name}.html">
+                    <replacefilter
+                        token="$${height}"
+                        value="@{height}"/>
+                </replace>
+                <replace file="@{output}/@{name}.html">
+                    <replacefilter
+                        token="$${application}"
+                        value="@{name}"/>
+                </replace>
+                <replace file="@{output}/@{name}.html">
+                    <replacefilter
+                        token="$${swf}"
+                        value="@{name}"/>
+                </replace>
+        </sequential>
+    </macrodef>
+    
+    <target name="get-data" description="gets data from various sources, sort of like a proxy server">
+        <mkdir dir="${basedir}/bin-debug/archive.apache.org/dist/flex/flexjs" />
+        <mkdir dir="${basedir}/bin-debug/archive.apache.org/dist/flex/installer" />
+        <mkdir dir="${basedir}/bin-debug/archive.apache.org/dist/flex/BlazeDS" />
+        <mkdir dir="${basedir}/bin-debug/archive.apache.org/dist/flex/flexunit" />
+        <mkdir dir="${basedir}/bin-debug/archive.apache.org/dist/flex/squiggly" />
+        <mkdir dir="${basedir}/bin-debug/archive.apache.org/dist/flex/tourdeflex" />
+        <mkdir dir="${basedir}/bin-debug/dist.apache.org/repos/dist/release/flex/flexjs" />
+        <mkdir dir="${basedir}/bin-debug/dist.apache.org/repos/dist/release/flex/installer" />
+        <mkdir dir="${basedir}/bin-debug/dist.apache.org/repos/dist/release/flex/BlazeDS" />
+        <mkdir dir="${basedir}/bin-debug/dist.apache.org/repos/dist/release/flex/flexunit" />
+        <mkdir dir="${basedir}/bin-debug/dist.apache.org/repos/dist/release/flex/squiggly" />
+        <mkdir dir="${basedir}/bin-debug/dist.apache.org/repos/dist/release/flex/tourdeflex" />
+        <mkdir dir="${basedir}/bin-debug/issues.apache.org/jira/rest/api/2" />
+        <get src="http://archive.apache.org/dist/flex/"
+            dest="${basedir}/bin-debug/archive.apache.org/dist/flex/index.html" />
+        <get src="http://archive.apache.org/dist/flex/flexjs/"
+            dest="${basedir}/bin-debug/archive.apache.org/dist/flex/flexjs/index.html" />
+        <get src="http://archive.apache.org/dist/flex/installer/"
+            dest="${basedir}/bin-debug/archive.apache.org/dist/flex/installer/index.html" />
+        <get src="http://archive.apache.org/dist/flex/BlazeDS/"
+            dest="${basedir}/bin-debug/archive.apache.org/dist/flex/BlazeDS/index.html" />
+        <get src="http://archive.apache.org/dist/flex/flexunit/"
+            dest="${basedir}/bin-debug/archive.apache.org/dist/flex/flexunit/index.html" />
+        <get src="http://archive.apache.org/dist/flex/squiggly/"
+            dest="${basedir}/bin-debug/archive.apache.org/dist/flex/squiggly/index.html" />
+        <get src="http://archive.apache.org/dist/flex/tourdeflex/"
+            dest="${basedir}/bin-debug/archive.apache.org/dist/flex/tourdeflex/index.html" />
+        <get src="https://dist.apache.org/repos/dist/release/flex/"
+            dest="${basedir}/bin-debug/dist.apache.org/repos/dist/release/flex/index.html" />
+        <get src="https://dist.apache.org/repos/dist/release/flex/flexjs/"
+            dest="${basedir}/bin-debug/dist.apache.org/repos/dist/release/flex/flexjs/index.html" />
+        <get src="https://dist.apache.org/repos/dist/release/flex/installer/"
+            dest="${basedir}/bin-debug/dist.apache.org/repos/dist/release/flex/installer/index.html" />
+        <get src="https://dist.apache.org/repos/dist/release/flex/BlazeDS/"
+            dest="${basedir}/bin-debug/dist.apache.org/repos/dist/release/flex/BlazeDS/index.html" />
+        <get src="https://dist.apache.org/repos/dist/release/flex/flexunit/"
+            dest="${basedir}/bin-debug/dist.apache.org/repos/dist/release/flex/flexunit/index.html" />
+        <get src="https://dist.apache.org/repos/dist/release/flex/squiggly/"
+            dest="${basedir}/bin-debug/dist.apache.org/repos/dist/release/flex/squiggly/index.html" />
+        <get src="https://dist.apache.org/repos/dist/release/flex/tourdeflex/"
+            dest="${basedir}/bin-debug/dist.apache.org/repos/dist/release/flex/tourdeflex/index.html" />
+        <get src="https://issues.apache.org/jira/rest/api/2/search?jql=project%20%3D%20FLEX%20AND%20status%20%3D%20open"
+            dest="${basedir}/bin-debug/issues.apache.org/jira/rest/api/2/search" />
+        <mkdir dir="${basedir}/bin/js-debug/archive.apache.org/dist/flex/flexjs" />
+        <mkdir dir="${basedir}/bin/js-debug/archive.apache.org/dist/flex/installer" />
+        <mkdir dir="${basedir}/bin/js-debug/archive.apache.org/dist/flex/BlazeDS" />
+        <mkdir dir="${basedir}/bin/js-debug/archive.apache.org/dist/flex/flexunit" />
+        <mkdir dir="${basedir}/bin/js-debug/archive.apache.org/dist/flex/squiggly" />
+        <mkdir dir="${basedir}/bin/js-debug/archive.apache.org/dist/flex/tourdeflex" />
+        <mkdir dir="${basedir}/bin/js-debug/dist.apache.org/repos/dist/release/flex/flexjs" />
+        <mkdir dir="${basedir}/bin/js-debug/dist.apache.org/repos/dist/release/flex/installer" />
+        <mkdir dir="${basedir}/bin/js-debug/dist.apache.org/repos/dist/release/flex/BlazeDS" />
+        <mkdir dir="${basedir}/bin/js-debug/dist.apache.org/repos/dist/release/flex/flexunit" />
+        <mkdir dir="${basedir}/bin/js-debug/dist.apache.org/repos/dist/release/flex/squiggly" />
+        <mkdir dir="${basedir}/bin/js-debug/dist.apache.org/repos/dist/release/flex/tourdeflex" />
+        <mkdir dir="${basedir}/bin/js-debug/issues.apache.org/jira/rest/api/2" />
+        <copy todir="${basedir}/bin/js-debug">
+            <fileset dir="${basedir}/bin-debug">
+                <include name="**/index.html" />
+                <include name="issues.apache.org/jira/rest/api/2/search" />
+            </fileset>
+        </copy>
+        <mkdir dir="${basedir}/bin/js-release/archive.apache.org/dist/flex/flexjs" />
+        <mkdir dir="${basedir}/bin/js-release/archive.apache.org/dist/flex/installer" />
+        <mkdir dir="${basedir}/bin/js-release/archive.apache.org/dist/flex/BlazeDS" />
+        <mkdir dir="${basedir}/bin/js-release/archive.apache.org/dist/flex/flexunit" />
+        <mkdir dir="${basedir}/bin/js-release/archive.apache.org/dist/flex/squiggly" />
+        <mkdir dir="${basedir}/bin/js-release/archive.apache.org/dist/flex/tourdeflex" />
+        <mkdir dir="${basedir}/bin/js-release/dist.apache.org/repos/dist/release/flex/flexjs" />
+        <mkdir dir="${basedir}/bin/js-release/dist.apache.org/repos/dist/release/flex/installer" />
+        <mkdir dir="${basedir}/bin/js-release/dist.apache.org/repos/dist/release/flex/BlazeDS" />
+        <mkdir dir="${basedir}/bin/js-release/dist.apache.org/repos/dist/release/flex/flexunit" />
+        <mkdir dir="${basedir}/bin/js-release/dist.apache.org/repos/dist/release/flex/squiggly" />
+        <mkdir dir="${basedir}/bin/js-release/dist.apache.org/repos/dist/release/flex/tourdeflex" />
+        <mkdir dir="${basedir}/bin/js-release/issues.apache.org/jira/rest/api/2" />
+        <copy todir="${basedir}/bin/js-release">
+            <fileset dir="${basedir}/bin-debug">
+                <include name="**/index.html" />
+                <include name="issues.apache.org/jira/rest/api/2/search" />
+            </fileset>
+        </copy>
+    </target>
+</project>

http://git-wip-us.apache.org/repos/asf/flex-examples/blob/7537f95d/ProductDashboard/src/MyInitialView.mxml
----------------------------------------------------------------------
diff --git a/ProductDashboard/src/MyInitialView.mxml b/ProductDashboard/src/MyInitialView.mxml
new file mode 100644
index 0000000..84db26a
--- /dev/null
+++ b/ProductDashboard/src/MyInitialView.mxml
@@ -0,0 +1,148 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+
+Licensed to the Apache Software Foundation (ASF) under one or more
+contributor license agreements.  See the NOTICE file distributed with
+this work for additional information regarding copyright ownership.
+The ASF licenses this file to You under the Apache License, Version 2.0
+(the "License"); you may not use this file except in compliance with
+the License.  You may obtain a copy of the License at
+
+http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+-->
+<js:ViewBase xmlns:fx="http://ns.adobe.com/mxml/2009"
+				xmlns:js="library://ns.apache.org/flexjs/flat"
+			    width="100%" height="100%" xmlns:ns="library://ns.apache.org/flexjs/basic">
+    <fx:Script>
+        <![CDATA[
+            import models.MyModel;
+            
+            import org.apache.flex.events.Event;
+
+            public static const EVENT_DEV_SUBSCRIBE:String = "devSubscribe";
+            public static const EVENT_DEV_UNSUBSCRIBE:String = "devUnsubscribe";
+            public static const EVENT_DEV_ARCHIVE:String = "devArchive";
+            public static const EVENT_DEV_MAIL:String = "devMail";
+            public static const EVENT_USERS_SUBSCRIBE:String = "usersSubscribe";
+            public static const EVENT_USERS_UNSUBSCRIBE:String = "usersUnsubscribe";
+            public static const EVENT_USERS_ARCHIVE:String = "usersArchive";
+            public static const EVENT_USERS_MAIL:String = "usersMail";
+            public static const EVENT_ISSUES_TRACKER:String = "issuesTracker";
+            public static const EVENT_ISSUES_CREATE:String = "issuesCreate";
+            public static const EVENT_PRODUCT_CHANGED:String = "productChanged";
+            public static const EVENT_DOWNLOAD_PRODUCT:String = "downloadProduct";
+            
+		]]>
+    </fx:Script>
+	<fx:Style source="main.css" />
+    <js:states>
+        <js:State name="hideAll" />        
+        <js:State name="showAll" />        
+    </js:states>
+    <js:beads>
+        <ns:ContainerDataBinding />
+        <js:VerticalLayout />
+    </js:beads>
+    <js:HContainer className="titleContainer">
+        <js:Image id="projectImage" source="{MyModel(applicationModel).projectIcon}" />
+        <js:Label id="projectName" style="fontSize:30" html="{MyModel(applicationModel).projectTitle}" />
+    </js:HContainer>
+    <js:HContainer width="100%" height="50%">
+        <js:Panel title="{MyModel(applicationModel).devListName}" width="45%" height="100%">
+            <js:beads>
+                <js:VerticalLayout />
+            </js:beads>
+<!--            <js:Label id="committers" text="{MyModel(applicationModel).numDevSubscribers + ' Subscribers'}" />-->
+            <js:MultilineLabel id="devFolks" width="100%" text="{'This mailing list is for discussing the development of ' + MyModel(applicationModel).projectName + '.'}" /> 
+            <!--            <js:Label id="committers" text="{MyModel(applicationModel).numCommitters + ' Committers, of which'}" />
+            <js:Label id="pmc" text="{MyModel(applicationModel).numPMC + ' are Project Management Committee members.'}" />-->
+            <js:Container className="buttonAndLabel">
+                <js:beads>
+                    <js:OneFlexibleChildHorizontalLayout flexibleChild="subLabel" />
+                </js:beads>
+                <js:TextButton text="Subscribe" className="mailButton" click="dispatchEvent(new Event(EVENT_DEV_SUBSCRIBE))" />
+                <js:MultilineLabel id="subLabel" text="Just send the email.  No subject or other information is required.  You will receive an email from a robot that you must reply to." />
+            </js:Container> 
+            <js:Container className="buttonAndLabel">
+                <js:beads>
+                    <js:OneFlexibleChildHorizontalLayout flexibleChild="unsubLabel" />
+                </js:beads>
+                <js:TextButton text="Unsubscribe" className="mailButton" click="dispatchEvent(new Event(EVENT_DEV_UNSUBSCRIBE))" />
+                <js:MultilineLabel id="unsubLabel" text="Just send the email.  No subject or other information is required.  Assumes you are sending from the same email you used to subscribe." />
+            </js:Container> 
+            <js:TextButton text="View Past Discussions" className="discussButton" click="dispatchEvent(new Event(EVENT_DEV_ARCHIVE))" />
+            <js:Container className="buttonAndLabel">
+                <js:beads>
+                    <js:OneFlexibleChildHorizontalLayout flexibleChild="sendLabel" />
+                </js:beads>
+                <js:TextButton text="Send us an email" className="mailButton" click="dispatchEvent(new Event(EVENT_DEV_MAIL))" />
+                <js:MultilineLabel id="sendLabel" text="May be delayed waiting for moderator approval if you aren't subscribed." />
+            </js:Container> 
+        </js:Panel>
+        <js:Panel title="{MyModel(applicationModel).usersListName}" width="45%" height="100%" style="marginLeft:10px">
+            <js:beads>
+                <js:VerticalLayout />
+            </js:beads>
+            <!--            <js:Label id="committers" text="{MyModel(applicationModel).numDevSubscribers + ' Subscribers'}" />-->
+            <js:MultilineLabel id="userslist" width="100%" text="{'This mailing list is for questions and answers on how to use ' + MyModel(applicationModel).projectName + '.'}" />
+            <js:Container className="buttonAndLabel">
+                <js:beads>
+                    <js:OneFlexibleChildHorizontalLayout flexibleChild="subUserLabel" />
+                </js:beads>
+                <js:TextButton text="Subscribe" className="mailButton" click="dispatchEvent(new Event(EVENT_USERS_SUBSCRIBE))" />
+                <js:MultilineLabel id="subUserLabel" text="Just send the email.  No subject or other information is required.  You will receive an email from a robot that you must reply to." />
+            </js:Container> 
+            <js:Container className="buttonAndLabel">
+                <js:beads>
+                    <js:OneFlexibleChildHorizontalLayout flexibleChild="unsubUserLabel" />
+                </js:beads>
+                <js:TextButton text="Unsubscribe" className="mailButton" click="dispatchEvent(new Event(EVENT_USERS_UNSUBSCRIBE))" />
+                <js:MultilineLabel id="unsubUserLabel" text="Just send the email.  No subject or other information is required.  Assumes you are sending from the same email you used to subscribe." />
+            </js:Container> 
+            <js:TextButton text="View Past Discussions" className="discussButton" click="dispatchEvent(new Event(EVENT_USERS_ARCHIVE))" />
+            <js:Container className="buttonAndLabel">
+                <js:beads>
+                    <js:OneFlexibleChildHorizontalLayout flexibleChild="askLabel" />
+                </js:beads>
+                <js:TextButton text="Ask us a question" className="mailButton" click="dispatchEvent(new Event(EVENT_USERS_MAIL))" />
+                <js:MultilineLabel id="askLabel" text="May be delayed waiting for moderator approval if you aren't subscribed." />
+            </js:Container> 
+        </js:Panel>
+    </js:HContainer>
+    <js:HContainer width="100%" height="30%" style="marginTop:10px">
+        <js:Panel title="Releases" width="45%"  height="100%">
+            <js:beads>
+                <js:VerticalLayout />
+                <js:LayoutChangeNotifier id="lcn" watchedProperty="{releaseDownloadButton.visible}" />
+            </js:beads>
+            <js:HContainer width="100%">
+                <js:Label className="releaseDropDownLabel" text="Product:" />
+                <js:Label className="releaseDropDownLabel" id="labelReleaseCount" text="{MyModel(applicationModel).releaseCount.toString() + ' Releases:'}"/>
+            </js:HContainer>
+            <js:HContainer>
+                <js:DropDownList className="releaseDropDown" id="productList" dataProvider="{MyModel(applicationModel).productList}" labelField="name"
+                                 selectedIndex="{MyModel(applicationModel).productList == null ? -1 : 0}" change="dispatchEvent(new Event(EVENT_PRODUCT_CHANGED))" />
+                <js:DropDownList className="releaseDropDown" id="releaseList" dataProvider="{MyModel(applicationModel).releases}" selectedIndex="{(MyModel(applicationModel).releases == null) ? -1 : 0}" />
+            </js:HContainer>
+            <js:MultilineLabel style="left:20px;right:20px" text="{MyModel(applicationModel).currentDescription}" />
+            <js:TextButton className="releaseDownloadButton" id="releaseDownloadButton" text="Go to Download Page" click="dispatchEvent(new Event(EVENT_DOWNLOAD_PRODUCT))" 
+                           visible="{MyModel(applicationModel).releases != null}"/>
+        </js:Panel>
+        <js:Panel title="Bugs and Feature Requests" width="45%" height="100%" style="marginLeft:10px" >
+            <js:beads>
+                <js:VerticalLayout />
+            </js:beads>
+            <js:Label id="openIssues" text="{MyModel(applicationModel).numOpenIssues + ' Open Issues'}" />
+            <js:TextButton text="View Bug Reports and Feature Requests" className="issuesButton" click="dispatchEvent(new Event(EVENT_ISSUES_TRACKER))" />
+            <js:TextButton text="Create new Bug Report or Feature Request" className="issuesButton" click="dispatchEvent(new Event(EVENT_ISSUES_CREATE))" />
+        </js:Panel>
+    </js:HContainer>
+    <!--<js:Label id="forks" text="{MyModel(applicationModel).numForks + ' Forks'}" />-->
+</js:ViewBase>

http://git-wip-us.apache.org/repos/asf/flex-examples/blob/7537f95d/ProductDashboard/src/Product.as
----------------------------------------------------------------------
diff --git a/ProductDashboard/src/Product.as b/ProductDashboard/src/Product.as
new file mode 100644
index 0000000..c66138b
--- /dev/null
+++ b/ProductDashboard/src/Product.as
@@ -0,0 +1,56 @@
+package
+{
+    public class Product
+    {
+        public function Product(data:Object)
+        {
+            this.data = data;
+        }
+        
+        private var data:Object;
+        
+        public function get name():String
+        {
+            return data.name;    
+        }
+        
+        public function get description():String
+        {
+            return data.description;    
+        }
+
+        public function get archiveURL():String
+        {
+            return data.archiveURL;    
+        }
+
+        public function get archivePattern():String
+        {
+            return data.archivePattern;    
+        }
+        
+        public function get releasePattern():String
+        {
+            return data.releasePattern;    
+        }
+        
+        public function get releaseURL():String
+        {
+            return data.releaseURL;    
+        }
+        
+        public function get excludes():Array
+        {
+            return data.excludes;    
+        }
+        
+        public function get releases():Array
+        {
+            return data.releases;    
+        }
+        public function set releases(value:Array):void
+        {
+            data.releases = value;    
+        }
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/flex-examples/blob/7537f95d/ProductDashboard/src/ProjectDashboard.mxml
----------------------------------------------------------------------
diff --git a/ProductDashboard/src/ProjectDashboard.mxml b/ProductDashboard/src/ProjectDashboard.mxml
new file mode 100644
index 0000000..d1558fb
--- /dev/null
+++ b/ProductDashboard/src/ProjectDashboard.mxml
@@ -0,0 +1,91 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+
+Licensed to the Apache Software Foundation (ASF) under one or more
+contributor license agreements.  See the NOTICE file distributed with
+this work for additional information regarding copyright ownership.
+The ASF licenses this file to You under the Apache License, Version 2.0
+(the "License"); you may not use this file except in compliance with
+the License.  You may obtain a copy of the License at
+
+http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+-->
+<js:Application xmlns:fx="http://ns.adobe.com/mxml/2009"
+                   xmlns:local="*"
+                   xmlns:js="library://ns.apache.org/flexjs/basic" 
+                   xmlns:models="models.*" 
+                   xmlns:controllers="controllers.*"
+                   initialize="configService.send()"
+                   >
+    <fx:Script>
+        <![CDATA[
+            import org.apache.flex.net.HTTPHeader;
+            private function fetchData():void
+            {
+                //reporterService.send();
+                issuesService.headers = [ new HTTPHeader("accept", "application/json") ];
+                issuesService.contentData = JSON.stringify({ jql: "project IN (FLEX) AND status IN (open)" });
+                issuesService.send();
+                //githubService.send();
+            }
+            
+            private function issueCountArrived():void
+            {
+                var results:String = issuesService.data;
+                var c:int = results.indexOf("(");
+                var c2:int = results.lastIndexOf(")");
+                var data:Object = JSON.parse(results/*.substring(c+1, c2)*/);
+                trace("issuesArrived");
+                MyModel(model).numOpenIssues = data.total;
+            }
+                        
+            private function ghDataArrived():void
+            {
+                var results:String = githubService.data;
+                var c:int = results.indexOf("(");
+                var c2:int = results.lastIndexOf(")");
+                var data:Object = JSON.parse(results.substring(c+1, c2));
+                trace("githubArrived");
+                MyModel(model).numForks = data.data.forks;
+            }
+
+            private function archiveDataArrived():void
+            {
+                var data:Object = archiveService.json;               
+                trace("archiveArrived");
+            }
+        ]]>
+    </fx:Script>
+    <js:valuesImpl>
+        <js:SimpleCSSValuesImpl />
+    </js:valuesImpl>
+    <js:initialView>
+        <local:MyInitialView />
+    </js:initialView>
+    <js:model>
+        <models:MyModel configService="{configService}" reporterService="{reporterService}" releaseService="{releaseService}" />
+    </js:model>
+    <js:controller>
+        <controllers:MyController />
+    </js:controller>
+    <js:beads>
+        <js:ApplicationDataBinding />
+        <js:CallLaterBead id="callLater" />
+        <js:HTTPService id="reporterService" url="{MyModel(model).reporterURL}" />
+        <js:HTTPService id="configService" url="config.json" complete="callLater.callLater(fetchData)"/>
+        <js:HTTPService id="issuesService" url="{MyModel(model).issueCounterURL}" method="POST" 
+                        contentType="application/json"
+                        complete="issueCountArrived()" />
+        <js:HTTPService id="githubService" url="{MyModel(model).githubURL}" complete="ghDataArrived()" />
+        <js:HTTPService id="archiveService" url="{MyModel(model).archiveURL}" complete="archiveDataArrived()" />
+        <js:HTTPService id="releaseService" />
+        <js:ViewSourceContextMenuOption />
+    </js:beads>
+</js:Application>

http://git-wip-us.apache.org/repos/asf/flex-examples/blob/7537f95d/ProductDashboard/src/apple-touch-icon-60.png
----------------------------------------------------------------------
diff --git a/ProductDashboard/src/apple-touch-icon-60.png b/ProductDashboard/src/apple-touch-icon-60.png
new file mode 100644
index 0000000..2b0d74e
Binary files /dev/null and b/ProductDashboard/src/apple-touch-icon-60.png differ

http://git-wip-us.apache.org/repos/asf/flex-examples/blob/7537f95d/ProductDashboard/src/config.json
----------------------------------------------------------------------
diff --git a/ProductDashboard/src/config.json b/ProductDashboard/src/config.json
new file mode 100644
index 0000000..c916c1d
--- /dev/null
+++ b/ProductDashboard/src/config.json
@@ -0,0 +1,77 @@
+{ "projectName" : "Apache Flex",
+  "projectTitle" : "<span style='font-family:Arial;font-size:30px'>Apache Flex</span><span style='font-size:8px'>®</span>",
+  "projectIcon" : "apple-touch-icon-60.png",
+  "devListName" : "dev@flex.apache.org Mailing List",
+  "devListSubscribeURL" : "mailto:dev-subscribe@flex.apache.org",
+  "devListUnsubscribeURL" : "mailto:dev-unsubscribe@flex.apache.org",
+  "devListURL" : "mailto:dev@flex.apache.org",
+  "devListArchiveURL" : "http://mail-archives.apache.org/mod_mbox/flex-dev/",
+  "usersListName" : "users@flex.apache.org Mailing List",
+  "usersListSubscribeURL" : "mailto:users-subscribe@flex.apache.org",
+  "usersListUnsubscribeURL" : "mailto:users-unsubscribe@flex.apache.org",
+  "usersListURL" : "mailto:users@flex.apache.org",
+  "usersListArchiveURL" : "http://mail-archives.apache.org/mod_mbox/flex-users/",
+  "reporterKey" : "flex",
+  "issuesCreateURL" : "https://issues.apache.org/jira/secure/CreateIssue!default.jspa",
+  "issuesMainURL" : "http://issues.apache.org/jira/issues/?jql=project%20%3D%20FLEX",
+  "issueCounterURL" : "issues.apache.org/jira/rest/api/2/search",
+  "reporterURL" : "https://reporter.apache.org/getjson.py?only=flex",
+  "products" : [{ "name": "Apache Flex SDK",
+                  "description" : "The open source version of the Adobe Flex SDK.  Requires the Adobe Flash Player or Adobe AIR runtimes.",
+                  "archiveURL" : "archive.apache.org/dist/flex/",
+                  "archivePattern" : "http://archive.apache.org/dist/flex/__version__/",
+                  "releaseURL" : "dist.apache.org/repos/dist/release/flex/",
+                  "releasePattern" : "http://www.apache.org/dyn/closer.lua/flex/__version__/",
+                  "excludes" : ["http://www.apache.org/dyn/closer.cgi", "?C=N;O=D", "?C=M;O=A", "?C=S;O=A", "?C=D;O=A", "/dist/", "../", "BlazeDS/", "HEADER.html", "KEYS", "LICENSE", "README.html", "falcon/", "flexjs/", "flexunit/", "installer/", "pixelbender/", "squiggly/", "tourdeflex/"]
+                },
+                { "name": "Apache FlexJS",
+                  "description" : "The next generation of Flex.  Produces HTML/JS/CSS output.",
+                  "archiveURL" : "archive.apache.org/dist/flex/flexjs/",
+                  "archivePattern" : "http://archive.apache.org/dist/flex/flexjs/__version__/",
+                  "releaseURL" : "dist.apache.org/repos/dist/release/flex/flexjs/",
+                  "releasePattern" : "http://www.apache.org/dyn/closer.lua/flex/flexjs/__version__/",
+                  "excludes" : ["http://www.apache.org/dyn/closer.cgi", "?C=N;O=D", "?C=M;O=A", "?C=S;O=A", "?C=D;O=A", "/dist/flex/", "../"]
+                },
+                { "name": "Apache Flex SDK Installer",
+                  "description" : "The installation program for those who use IDEs that support Flex.",
+                  "archiveURL" : "archive.apache.org/dist/flex/installer/",
+                  "archivePattern" : "http://archive.apache.org/dist/flex/installer/__version__/",
+                  "releaseURL" : "dist.apache.org/repos/dist/release/flex/installer/",
+                  "releasePattern" : "http://www.apache.org/dyn/closer.lua/flex/installer/__version__/",
+                  "excludes" : ["http://www.apache.org/dyn/closer.cgi", "?C=N;O=D", "?C=M;O=A", "?C=S;O=A", "?C=D;O=A", "/dist/flex/", "../"]
+                },
+                { "name": "Apache Flex BlazeDS",
+                  "description" : "The open source library for web service development.  Requires the Apache Flex SDK.",
+                  "archiveURL" : "archive.apache.org/dist/flex/BlazeDS/",
+                  "archivePattern" : "http://archive.apache.org/dist/flex/BlazeDS/__version__/",
+                  "releaseURL" : "dist.apache.org/repos/dist/release/flex/BlazeDS/",
+                  "releasePattern" : "http://www.apache.org/dyn/closer.lua/flex/BlazeDS/__version__/",
+                  "excludes" : ["http://www.apache.org/dyn/closer.cgi", "?C=N;O=D", "?C=M;O=A", "?C=S;O=A", "?C=D;O=A", "/dist/flex/", "../"]
+                },
+                { "name": "Apache Flex FlexUnit",
+                  "description" : "The unit testing library for Flex.  Requires the Apache Flex SDK.",
+                  "archiveURL" : "archive.apache.org/dist/flex/flexunit/",
+                  "archivePattern" : "http://archive.apache.org/dist/flex/flexunit/__version__/",
+                  "releaseURL" : "dist.apache.org/repos/dist/release/flex/BlazeDS/",
+                  "releasePattern" : "http://www.apache.org/dyn/closer.lua/flex/BlazeDS/__version__/",
+                  "excludes" : ["http://www.apache.org/dyn/closer.cgi", "?C=N;O=D", "?C=M;O=A", "?C=S;O=A", "?C=D;O=A", "/dist/flex/", "../"]
+                },
+                { "name": "Apache Flex Squiggly",
+                  "description" : "The spell checking library for Flex.  Requires the Apache Flex SDK.",
+                  "archiveURL" : "archive.apache.org/dist/flex/squiggly/",
+                  "archivePattern" : "http://archive.apache.org/dist/flex/squiggly/__version__/",
+                  "releaseURL" : "dist.apache.org/repos/dist/release/flex/squiggly/",
+                  "releasePattern" : "http://www.apache.org/dyn/closer.lua/flex/squiggly/__version__/",
+                  "excludes" : ["http://www.apache.org/dyn/closer.cgi", "?C=N;O=D", "?C=M;O=A", "?C=S;O=A", "?C=D;O=A", "/dist/flex/", "../"]
+                },
+                { "name": "Apache Flex TourDeFlex",
+                  "description" : "The learning content for Flex.  Requires the Apache Flex SDK.",
+                  "archiveURL" : "archive.apache.org/dist/flex/tourdeflex/",
+                  "archivePattern" : "http://archive.apache.org/dist/flex/tourdeflex/__version__/",
+                  "releaseURL" : "dist.apache.org/repos/dist/release/flex/tourdeflex/",
+                  "releasePattern" : "http://www.apache.org/dyn/closer.lua/flex/tourdeflex/__version__/",
+                  "excludes" : ["http://www.apache.org/dyn/closer.cgi", "?C=N;O=D", "?C=M;O=A", "?C=S;O=A", "?C=D;O=A", "/dist/flex/", "../"]
+                }
+                ],
+  "githubURL" : "https://api.github.com/repos/apache/flex-sdk?callback=foo"  
+}

http://git-wip-us.apache.org/repos/asf/flex-examples/blob/7537f95d/ProductDashboard/src/controllers/MyController.as
----------------------------------------------------------------------
diff --git a/ProductDashboard/src/controllers/MyController.as b/ProductDashboard/src/controllers/MyController.as
new file mode 100644
index 0000000..01168b1
--- /dev/null
+++ b/ProductDashboard/src/controllers/MyController.as
@@ -0,0 +1,147 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+//  Licensed to the Apache Software Foundation (ASF) under one or more
+//  contributor license agreements.  See the NOTICE file distributed with
+//  this work for additional information regarding copyright ownership.
+//  The ASF licenses this file to You under the Apache License, Version 2.0
+//  (the "License"); you may not use this file except in compliance with
+//  the License.  You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+//  Unless required by applicable law or agreed to in writing, software
+//  distributed under the License is distributed on an "AS IS" BASIS,
+//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+//  See the License for the specific language governing permissions and
+//  limitations under the License.
+//
+////////////////////////////////////////////////////////////////////////////////
+package controllers
+{
+	import models.MyModel;
+	
+	import org.apache.flex.core.Application;
+	import org.apache.flex.core.BrowserWindow;
+	import org.apache.flex.core.IDocument;
+	import org.apache.flex.events.Event;
+    	
+	public class MyController implements IDocument
+	{
+		public function MyController(app:Application = null)
+		{
+			if (app)
+			{
+				this.app = app as ProjectDashboard;
+				app.addEventListener("viewChanged", viewChangeHandler);
+			}
+		}
+		
+		private var app:ProjectDashboard;
+		
+		private function viewChangeHandler(event:Event):void
+		{
+			app.initialView.addEventListener(MyInitialView.EVENT_PRODUCT_CHANGED, productChangedHandler);
+            app.initialView.addEventListener(MyInitialView.EVENT_DOWNLOAD_PRODUCT, downloadProductHandler);
+            app.initialView.addEventListener(MyInitialView.EVENT_DEV_SUBSCRIBE, devSubscribeHandler);
+            app.initialView.addEventListener(MyInitialView.EVENT_DEV_UNSUBSCRIBE, devUnsubscribeHandler);
+            app.initialView.addEventListener(MyInitialView.EVENT_DEV_ARCHIVE, devArchiveHandler);
+            app.initialView.addEventListener(MyInitialView.EVENT_DEV_MAIL, devMailHandler);
+            app.initialView.addEventListener(MyInitialView.EVENT_USERS_SUBSCRIBE, usersSubscribeHandler);
+            app.initialView.addEventListener(MyInitialView.EVENT_USERS_UNSUBSCRIBE, usersUnsubscribeHandler);
+            app.initialView.addEventListener(MyInitialView.EVENT_USERS_ARCHIVE, usersArchiveHandler);
+            app.initialView.addEventListener(MyInitialView.EVENT_USERS_MAIL, usersMailHandler);
+            app.initialView.addEventListener(MyInitialView.EVENT_ISSUES_TRACKER, issuesTrackerHandler);
+            app.initialView.addEventListener(MyInitialView.EVENT_ISSUES_CREATE, issuesCreateHandler);
+		}
+		
+        private function downloadProductHandler(event:Event):void
+        {
+            var finalURL:String;
+            
+            var p:Product = MyModel(app.model).productList[MyInitialView(app.initialView).productList.selectedIndex];
+            var release:String = p.releases[MyInitialView(app.initialView).releaseList.selectedIndex];
+            var c:int = release.indexOf(MyModel.ARCHIVED);
+            if (c != -1)
+            {
+                release = release.substring(0, c);
+                finalURL = p.archivePattern;
+                finalURL = finalURL.replace(new RegExp("__version__", "g"), release);
+            }
+            else
+            {
+                finalURL = p.releasePattern;
+                finalURL = finalURL.replace(new RegExp("__version__", "g"), release);                    
+            }
+            BrowserWindow.open(finalURL, null)                
+        }
+        
+        private function openBrowserWindow(url:String):void
+        {
+            BrowserWindow.open(url, null);
+        }
+        
+		private function devSubscribeHandler(event:Event):void
+		{
+			openBrowserWindow(MyModel(app.model).devListSubscribeURL);
+		}
+		
+        private function devUnsubscribeHandler(event:Event):void
+        {
+            openBrowserWindow(MyModel(app.model).devListUnsubscribeURL);
+        }
+        
+        private function devArchiveHandler(event:Event):void
+        {
+            openBrowserWindow(MyModel(app.model).devListArchiveURL);
+        }
+        
+        private function devMailHandler(event:Event):void
+        {
+            openBrowserWindow(MyModel(app.model).devListURL);
+        }
+        
+        private function usersSubscribeHandler(event:Event):void
+        {
+            openBrowserWindow(MyModel(app.model).usersListSubscribeURL);
+        }
+        
+        private function usersUnsubscribeHandler(event:Event):void
+        {
+            openBrowserWindow(MyModel(app.model).usersListUnsubscribeURL);
+        }
+        
+        private function usersArchiveHandler(event:Event):void
+        {
+            openBrowserWindow(MyModel(app.model).usersListArchiveURL);
+        }
+        
+        private function usersMailHandler(event:Event):void
+        {
+            openBrowserWindow(MyModel(app.model).usersListURL);
+        }
+        
+        private function issuesTrackerHandler(event:Event):void
+        {
+            openBrowserWindow(MyModel(app.model).issuesMainURL);
+        }
+        
+        private function issuesCreateHandler(event:Event):void
+        {
+            openBrowserWindow(MyModel(app.model).issuesCreateURL);
+        }
+        
+		public function setDocument(document:Object, id:String = null):void
+		{
+			this.app = document as ProjectDashboard;
+			app.addEventListener("viewChanged", viewChangeHandler);
+		}
+        
+        
+        private function productChangedHandler(event:Event):void
+        {
+            var p:Product = MyModel(app.model).productList[MyInitialView(app.initialView).productList.selectedIndex];
+            MyModel(app.model).currentProduct = p;
+        }            
+
+	}
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/flex-examples/blob/7537f95d/ProductDashboard/src/main.css
----------------------------------------------------------------------
diff --git a/ProductDashboard/src/main.css b/ProductDashboard/src/main.css
new file mode 100644
index 0000000..89dd967
--- /dev/null
+++ b/ProductDashboard/src/main.css
@@ -0,0 +1,93 @@
+/*
+////////////////////////////////////////////////////////////////////////////////
+//
+//  Licensed to the Apache Software Foundation (ASF) under one or more
+//  contributor license agreements.  See the NOTICE file distributed with
+//  this work for additional information regarding copyright ownership.
+//  The ASF licenses this file to You under the Apache License, Version 2.0
+//  (the "License"); you may not use this file except in compliance with
+//  the License.  You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+//  Unless required by applicable law or agreed to in writing, software
+//  distributed under the License is distributed on an "AS IS" BASIS,
+//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+//  See the License for the specific language governing permissions and
+//  limitations under the License.
+//
+////////////////////////////////////////////////////////////////////////////////
+*/
+
+@namespace basic "library://ns.apache.org/flexjs/basic";
+
+/*
+//----------------------------
+//  Global styles
+//----------------------------
+*/
+.global {
+    IStatesImpl:            ClassReference("org.apache.flex.core.StatesWithTransitionsImpl");
+}
+
+global {
+    IStatesImpl:            ClassReference("org.apache.flex.core.StatesWithTransitionsImpl");
+}
+
+/*
+//----------------------------
+// Named styles
+//----------------------------
+*/
+#projectName {
+    fontSize:		    30px;
+}
+
+#projectImage {
+    width:              60px;
+    height:             60px;
+}
+
+.titleContainer {
+    height:             60px;
+}
+
+.mailButton {
+    width:             190px;
+}
+
+.releaseDropDown {
+    width:             240px;
+    margin-left:       5px;
+}
+
+.releaseDropDownLabel {
+    width:             240px;
+    margin-left:       5px;
+}
+
+.releaseDownloadButton {
+    width:             240px;
+    margin-left:       5px;
+}
+
+.discussButton {
+    margin-top:        5px;
+    left:              2px;
+    width:             190px;
+}
+
+.issuesButton {
+    margin-top:        5px;
+    left:              2px;
+    width:             390px;
+}
+
+.buttonAndLabel {
+    margin-top:        5px;
+    left:               2px;
+    right:              10px;
+}
+
+
+

http://git-wip-us.apache.org/repos/asf/flex-examples/blob/7537f95d/ProductDashboard/src/models/MyModel.as
----------------------------------------------------------------------
diff --git a/ProductDashboard/src/models/MyModel.as b/ProductDashboard/src/models/MyModel.as
new file mode 100644
index 0000000..141aa6e
--- /dev/null
+++ b/ProductDashboard/src/models/MyModel.as
@@ -0,0 +1,558 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+//  Licensed to the Apache Software Foundation (ASF) under one or more
+//  contributor license agreements.  See the NOTICE file distributed with
+//  this work for additional information regarding copyright ownership.
+//  The ASF licenses this file to You under the Apache License, Version 2.0
+//  (the "License"); you may not use this file except in compliance with
+//  the License.  You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+//  Unless required by applicable law or agreed to in writing, software
+//  distributed under the License is distributed on an "AS IS" BASIS,
+//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+//  See the License for the specific language governing permissions and
+//  limitations under the License.
+//
+////////////////////////////////////////////////////////////////////////////////
+package models
+{
+	import org.apache.flex.events.Event;
+	import org.apache.flex.events.EventDispatcher;
+	import org.apache.flex.net.HTTPService;
+	
+	public class MyModel extends EventDispatcher
+	{
+		public function MyModel()
+		{
+		}
+		
+        public static const ARCHIVED:String = " (Archived)";
+        
+        private var _configService:HTTPService;
+        
+        public function get configService():HTTPService
+        {
+            return _configService;
+        }
+        
+        public function set configService(value:HTTPService):void
+        {
+            if (value != _configService)
+            {
+                _configService = value;
+                _configService.addEventListener(HTTPService.EVENT_COMPLETE, completeHandler);
+                dispatchEvent(new Event("configServiceChanged"));
+            }
+        }
+        
+        private var _reporterService:HTTPService;
+        
+        public function get reporterService():HTTPService
+        {
+            return _reporterService;
+        }
+        
+        public function set reporterService(value:HTTPService):void
+        {
+            if (value != _reporterService)
+            {
+                _reporterService = value;
+                _reporterService.addEventListener(HTTPService.EVENT_COMPLETE, reporterCompleteHandler);
+                dispatchEvent(new Event("reporterServiceChanged"));
+            }
+        }
+        
+        private var _releaseService:HTTPService;
+        
+        public function get releaseService():HTTPService
+        {
+            return _releaseService;
+        }
+        
+        public function set releaseService(value:HTTPService):void
+        {
+            if (value != _releaseService)
+            {
+                _releaseService = value;
+                dispatchEvent(new Event("releaseServiceChanged"));
+            }
+        }
+        
+		private var _projectName:String;
+		
+        [Bindable("projectNameChanged")]
+		public function get projectName():String
+		{
+			return _projectName;
+		}
+		
+		public function set projectName(value:String):void
+		{
+			if (value != _projectName)
+			{
+                _projectName = value;
+				dispatchEvent(new Event("projectNameChanged"));
+			}
+		}
+		
+        private var _projectTitle:String;
+        
+        [Bindable("projectTitleChanged")]
+        public function get projectTitle():String
+        {
+            return _projectTitle;
+        }
+        
+        public function set projectTitle(value:String):void
+        {
+            if (value != _projectTitle)
+            {
+                _projectTitle = value;
+                dispatchEvent(new Event("projectTitleChanged"));
+            }
+        }
+        
+        private var _projectIcon:String;
+        
+        [Bindable("projectIconChanged")]
+        public function get projectIcon():String
+        {
+            return _projectIcon;
+        }
+        
+        public function set projectIcon(value:String):void
+        {
+            if (value != _projectIcon)
+            {
+                _projectIcon = value;
+                dispatchEvent(new Event("projectIconChanged"));
+            }
+        }
+        
+		private var _issueCounterURL:String;
+		
+		[Bindable("issueCounterURLChanged")]
+		public function get issueCounterURL():String
+		{
+			if (_issueCounterURL == null)
+				return "";
+			return _issueCounterURL;
+		}
+		
+		public function set issueCounterURL(value:String):void
+		{
+			if (value != _issueCounterURL)
+			{
+                _issueCounterURL = value;
+				dispatchEvent(new Event("issueCounterURLChanged"));
+			}
+		}
+		
+		private var _githubURL:String = "";
+		
+		[Bindable("githubURLChanged")]
+		public function get githubURL():String
+		{
+			return _githubURL;
+		}
+		
+        public function set githubURL(value:String):void
+        {
+            if (value != _githubURL)
+            {
+                _githubURL = value;
+                dispatchEvent(new Event("githubURLChanged"));
+            }
+        }
+		
+        private var _productList:Array;
+        
+        [Bindable("productListChanged")]
+        public function get productList():Array
+        {
+            return _productList;
+        }
+        
+        public function set productList(value:Array):void
+        {
+            if (value != _productList)
+            {
+                _productList = value;
+                dispatchEvent(new Event("productListChanged"));
+                currentProduct = productList[0];
+            }
+        }
+        
+        private var _currentProduct:Product;
+        
+        [Bindable("currentProductChanged")]
+        public function get currentProduct():Product
+        {
+            return _currentProduct;
+        }
+        
+        public function set currentProduct(value:Product):void
+        {
+            _currentProduct = value;
+            
+            if (value.releases == null)
+                getReleases();
+            else 
+            {
+                releases = value.releases;
+                releaseCount = value.releases.length;
+            }
+            dispatchEvent(new Event("currentProductChanged"));
+        }
+        
+        [Bindable("currentProductChanged")]
+        public function get currentDescription():String
+        {
+            return _currentProduct.description;
+        }
+        
+        private var _reporterURL:String = "";
+        
+        [Bindable("reporterURLChanged")]
+        public function get reporterURL():String
+        {
+            return _reporterURL;
+        }
+        
+        public function set reporterURL(value:String):void
+        {
+            if (value != _reporterURL)
+            {
+                _reporterURL = value;
+                dispatchEvent(new Event("reporterURLChanged"));
+            }
+        }
+        
+		private var _archiveURL:String;
+		
+		[Bindable("archiveURLChanged")]
+		public function get archiveURL():String
+		{
+			return _archiveURL;
+		}
+		
+		public function set archiveURL(value:String):void
+		{
+			if (value != _archiveURL)
+			{
+                _archiveURL = value;
+				dispatchEvent(new Event("archiveURLChanged"));
+			}
+		}
+        
+        private var _numOpenIssues:int;
+        
+        [Bindable("numOpenIssuesChanged")]
+        public function get numOpenIssues():int
+        {
+            return _numOpenIssues;
+        }
+        
+        public function set numOpenIssues(value:int):void
+        {
+            if (value != _numOpenIssues)
+            {
+                _numOpenIssues = value;
+                dispatchEvent(new Event("numOpenIssuesChanged"));
+            }
+        }
+        
+        private var _numForks:int;
+        
+        [Bindable("numForksChanged")]
+        public function get numForks():int
+        {
+            return _numForks;
+        }
+        
+        public function set numForks(value:int):void
+        {
+            if (value != _numForks)
+            {
+                _numForks = value;
+                dispatchEvent(new Event("numForksChanged"));
+            }
+        }
+        
+        private var configData:Object;
+        
+        private function completeHandler(event:Event):void
+        {
+            var svc:HTTPService = HTTPService(event.target);
+            var data:Object = svc.json;
+            configData = data;
+            archiveURL = data['archiveURL'];
+            reporterURL = data['reporterURL'];
+            githubURL = data['githubURL'];
+            issueCounterURL = data['issueCounterURL'];
+            projectName = data['projectName'];
+            projectTitle = data['projectTitle'];
+            projectIcon = data['projectIcon'];
+            reporterKey = data['reporterKey'];
+            productList = createProducts(data['products']);
+            dispatchEvent(new Event("configChanged"));            
+        }
+
+        private var reporterKey:String;
+        
+        private var report:Object;
+        
+        private function reporterCompleteHandler(event:Event):void
+        {
+            var svc:HTTPService = HTTPService(event.target);
+            var headers:Array = svc.responseHeaders;
+            trace(headers);
+            report = svc.json;
+            dispatchEvent(new Event("reportChanged"));            
+        }
+        
+        private var _numPMC:int = -1;
+        
+        [Bindable("reportChanged")]
+        public function get numPMC():int
+        {
+            if (_numPMC < 0)
+            {
+                _numPMC = report["count"][reporterKey][0];
+            }
+            return _numPMC;
+        }
+
+        private var _numCommitters:int = -1;
+        
+        [Bindable("reportChanged")]
+        public function get numCommitters():int
+        {
+            if (_numCommitters < 0)
+            {
+                _numCommitters = report["count"][reporterKey][1];
+            }
+            return _numCommitters;
+        }
+        
+        private var _numDevSubscribers:int = -1;
+        
+        [Bindable("reportChanged")]
+        public function get numDevSubscribers():int
+        {
+            if (_numDevSubscribers < 0)
+            {
+                _numDevSubscribers = countSubscribers(report["mail"][reporterKey][reporterKey + ".apache.org-dev"]);
+            }
+            return _numDevSubscribers;
+        }
+
+        private var _numUsersSubscribers:int = -1;
+        
+        [Bindable("reportChanged")]
+        public function get numUsersSubscribers():int
+        {
+            if (_numUsersSubscribers < 0)
+            {
+                _numUsersSubscribers = countSubscribers(report["mail"][reporterKey][reporterKey + ".apache.org-users"]);
+            }
+            return _numUsersSubscribers;
+        }
+        
+        [Bindable("configChanged")]
+        public function get devListName():String
+        {
+            return configData["devListName"];
+        }
+        
+        [Bindable("configChanged")]
+        public function get devListSubscribeURL():String
+        {
+            return configData["devListSubscribeURL"];
+        }
+        
+        [Bindable("configChanged")]
+        public function get devListUnsubscribeURL():String
+        {
+            return configData["devListUnsubscribeURL"];
+        }
+        
+        [Bindable("configChanged")]
+        public function get devListURL():String
+        {
+            return configData["devListURL"];
+        }
+        
+        [Bindable("configChanged")]
+        public function get devListArchiveURL():String
+        {
+            return configData["devListArchiveURL"];
+        }
+        
+        [Bindable("configChanged")]
+        public function get usersListName():String
+        {
+            return configData["usersListName"];
+        }
+        
+        [Bindable("configChanged")]
+        public function get usersListURL():String
+        {
+            return configData["usersListURL"];
+        }
+        
+        [Bindable("configChanged")]
+        public function get usersListSubscribeURL():String
+        {
+            return configData["usersListSubscribeURL"];
+        }
+        
+        [Bindable("configChanged")]
+        public function get usersListUnsubscribeURL():String
+        {
+            return configData["usersListUnsubscribeURL"];
+        }
+        
+        [Bindable("configChanged")]
+        public function get usersListArchiveURL():String
+        {
+            return configData["usersListArchiveURL"];
+        }
+        
+        [Bindable("configChanged")]
+        public function get issuesMainURL():String
+        {
+            return configData["issuesMainURL"];
+        }
+        
+        [Bindable("configChanged")]
+        public function get issuesCreateURL():String
+        {
+            return configData["issuesCreateURL"];
+        }
+        
+        [Bindable]
+        public var releases;
+        
+        [Bindable]
+        public var releaseCount;
+        
+        private function countSubscribers(data:Object):int
+        {
+            var total:int = 0;
+            for (var p:String in data)
+            {
+                var delta:int = data[p];
+                total += delta;
+            }
+            return total;
+        }
+        
+        private var archiveList:Array;
+        private var releaseList:Array;
+        
+        private function archiveCompleteHandler(event:Event):void
+        {
+            var p:Product = currentProduct;
+            archiveList = findLinks(releaseService.data, p.excludes);
+            releaseService.url = p.releaseURL;
+            releaseService.removeEventListener("complete", archiveCompleteHandler);
+            releaseService.addEventListener("complete", releaseCompleteHandler);
+            releaseService.send();
+        }
+        
+        private function releaseCompleteHandler(event:Event):void
+        {
+            releaseService.removeEventListener("complete", releaseCompleteHandler);
+            var p:Product = currentProduct;
+            releaseList = findLinks(releaseService.data, p.excludes);
+            p.releases = mergeLists();
+            releases = p.releases;
+            releaseCount = p.releases.length;
+        }
+        
+        private function createProducts(data:Array):Array
+        {
+            var n:int = data.length;
+            for (var i:int = 0; i < n; i++)
+            {
+                var obj:Object = data[i];
+                var p:Product = new Product(obj);
+                data[i] = p;
+            }
+            return data;
+        }
+        
+        private function findLinks(s:String, excludes:Array):Array
+        {
+            var arr:Array = [];
+            var c:int = s.indexOf("href=");
+            while (c != -1)
+            {
+                var c2:int = s.indexOf('"', c + 7);
+                var name:String = s.substring(c + 6, c2);
+                if (excludes.indexOf(name) == -1)
+                {
+                    if (name.charAt(name.length - 1) == "/")
+                        name = name.substr(0, name.length - 1);
+                    arr.push(name);
+                }
+                c = s.indexOf("href", c2);
+            }
+            return arr;
+        }
+        
+        private function mergeLists():Array
+        {
+            sortList(releaseList);
+            sortList(archiveList);
+            var n:int = archiveList.length;
+            for (var i:int = 0; i < n; i++)
+            {
+                var r:String = archiveList[i];
+                if (releaseList.indexOf(r) == -1)
+                {
+                    releaseList.push(r + ARCHIVED);
+                }
+            }
+            return releaseList;
+        }
+        
+        private function sortList(arr:Array):Array
+        {
+            return arr.sort(versionCompareFunction);
+        }
+        
+        private function versionCompareFunction(a:String, b:String):int
+        {
+            var aparts:Array = a.split(".");
+            var bparts:Array = b.split(".");
+            var n:int = Math.max(aparts.length, bparts.length);
+            for (var i:int = 0; i < n; i++)
+            {
+                var avalue:int = 0;
+                if (i < aparts.length)
+                    avalue = parseInt(aparts[i]);
+                var bvalue:int = 0;
+                if (i < bparts.length)
+                    bvalue = parseInt(bparts[i]);
+                if (avalue < bvalue)
+                    return 1;
+                if (avalue > bvalue)
+                    return -1;
+            }
+            return 0;
+        }
+        
+        private function getReleases():void
+        {
+            var p:Product = currentProduct;
+            releaseService.url = p.archiveURL;
+            releaseService.addEventListener("complete", archiveCompleteHandler);
+            releaseService.send();
+        }
+
+	}
+}
\ No newline at end of file