Repository: flex-utilities
Updated Branches:
  refs/heads/develop a338ddf1f -> 2454c94f4


utility that will check MD5s of installer downloads


Project: http://git-wip-us.apache.org/repos/asf/flex-utilities/repo
Commit: http://git-wip-us.apache.org/repos/asf/flex-utilities/commit/2454c94f
Tree: http://git-wip-us.apache.org/repos/asf/flex-utilities/tree/2454c94f
Diff: http://git-wip-us.apache.org/repos/asf/flex-utilities/diff/2454c94f

Branch: refs/heads/develop
Commit: 2454c94f4d04039ee20128301ed21305e9fd6a05
Parents: a338ddf
Author: Alex Harui <aha...@apache.org>
Authored: Tue Jul 29 09:01:50 2014 -0700
Committer: Alex Harui <aha...@apache.org>
Committed: Tue Jul 29 09:02:08 2014 -0700

----------------------------------------------------------------------
 MD5Checker/build.xml              | 127 ++++++++++
 MD5Checker/src/MD5Checker-app.xml | 250 ++++++++++++++++++++
 MD5Checker/src/MD5Checker.mxml    | 414 +++++++++++++++++++++++++++++++++
 3 files changed, 791 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/flex-utilities/blob/2454c94f/MD5Checker/build.xml
----------------------------------------------------------------------
diff --git a/MD5Checker/build.xml b/MD5Checker/build.xml
new file mode 100644
index 0000000..cce74a9
--- /dev/null
+++ b/MD5Checker/build.xml
@@ -0,0 +1,127 @@
+<?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="MD5Checker" basedir="." default="main">
+
+    <!--load environment variables prefixed with env -->
+    <property environment="env"/>
+
+    <!--
+        Properties are immutable so value frozen first time property is set.
+        If FLEX_HOME is not set with -DFLEX_HOME=/path/to/flex/sdk on the ant 
command line
+        use the environment variable, if it exists. Else if windows, use 
FLEX_HOME_WIN
+        else use FLEX_HOME_MAC, which are both defined in build.properties.
+    -->
+    <condition property="FLEX_HOME" value="${env.FLEX_HOME}">
+        <isset property="env.FLEX_HOME" />
+    </condition>
+    <condition property="AIR_HOME" value="${env.AIR_HOME}">
+        <isset property="env.AIR_HOME" />
+    </condition>
+
+    <condition property="theOS" value="Windows">
+               <os family="windows"/>
+    </condition>
+    <condition property="theOS" value="Mac">
+               <os family="mac"/>
+    </condition>
+    <condition property="isMac" value="Mac">
+               <os family="mac"/>
+    </condition>
+
+    <condition property="and_success" value="success" >
+        <and>
+            <matches string="foobar" pattern=".*bar" />
+            <isset property="env.FLEX_HOME" />
+        </and>
+    </condition>
+       
+    <condition property="and_failure" value="success" >
+        <and>
+            <matches string="foobar" pattern=".*bar" />
+            <isset property="env.NONEXISTANT" />
+        </and>
+    </condition>
+       
+    <condition property="or_success" value="success" >
+        <or>
+            <matches string="foobar" pattern=".*bar" />
+            <isset property="env.NONEXISTANT" />
+        </or>
+    </condition>
+       
+    <condition property="or_failure" value="success" >
+        <or>
+            <matches string="foobar" pattern=".*fred" />
+            <isset property="env.NONEXISTANT" />
+        </or>
+    </condition>
+
+    <condition property="should_fail" value="success" >
+        <and>
+            <matches string="foobar" pattern=".*bar" />
+            <not>
+                <isset property="env.FLEX_HOME" />
+            </not>
+        </and>
+    </condition>
+
+       <target name="main" depends="build">
+        <exec executable="${AIR_HOME}/bin/adl.exe" osfamily="windows" 
resultproperty="md5result" failonerror="false">
+            <arg value="-runtime"/>
+            <arg value="${AIR_HOME}/runtimes/air/win"/>
+                       <arg value="${basedir}/src/MD5Checker-app.xml"/>
+        </exec>
+        <exec executable="${AIR_HOME}/bin/adl" osfamily="mac" 
resultproperty="md5result" failonerror="false">
+            <arg value="-runtime"/>
+            <arg value="${AIR_HOME}/runtimes/air/mac"/>
+                       <arg value="${basedir}/src/MD5Checker-app.xml"/>
+                       <arg value="--" />
+                       <arg value="-log=${basedir}/MD5CheckerLog.txt"/>
+        </exec>
+               <loadfile property="md5log" 
srcfile="${basedir}/MD5CheckerLog.txt" />
+               <echo>${md5log}</echo>
+        <fail message="MD5's changed!" >
+            <condition>
+                               <not>
+                                       <equals arg1="0" arg2="${md5result}" />
+                               </not>
+            </condition>
+        </fail>
+    </target>
+    
+    <target name="load-task" >
+        <!-- load the <mxmlc> 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" 
classpath="${FLEX_HOME}/lib/flexTasks.jar"/>
+    </target>
+
+    <target name="build" depends="load-task" description="compile it">
+
+        <!-- compile the basic tests -->
+        <mxmlc fork="true"
+               file="${basedir}/src/MD5Checker.mxml">
+            <jvmarg line="-Xms64m -Xmx384m -ea -Dapple.awt.UIElement=true"/>
+            <load-config filename="${FLEX_HOME}/frameworks/air-config.xml"/>
+            <source-path path-element="${basedir}/../ant_on_air/src" />
+        </mxmlc>
+    </target>
+    
+</project>

http://git-wip-us.apache.org/repos/asf/flex-utilities/blob/2454c94f/MD5Checker/src/MD5Checker-app.xml
----------------------------------------------------------------------
diff --git a/MD5Checker/src/MD5Checker-app.xml 
b/MD5Checker/src/MD5Checker-app.xml
new file mode 100644
index 0000000..b3f24b1
--- /dev/null
+++ b/MD5Checker/src/MD5Checker-app.xml
@@ -0,0 +1,250 @@
+<?xml version="1.0" encoding="utf-8" standalone="no"?>
+<!--
+ 
+ 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.
+ 
+ -->
+<application xmlns="http://ns.adobe.com/air/application/3.1";>
+
+<!-- Adobe AIR Application Descriptor File Template.
+
+       Specifies parameters for identifying, installing, and launching AIR 
applications.
+
+       xmlns - The Adobe AIR namespace: http://ns.adobe.com/air/application/3.1
+                       The last segment of the namespace specifies the version 
+                       of the AIR runtime required for this application to run.
+                       
+       minimumPatchLevel - The minimum patch level of the AIR runtime required 
to run 
+                       the application. Optional.
+-->
+
+       <!-- A universally unique application identifier. Must be unique across 
all AIR applications.
+       Using a reverse DNS-style name as the id is recommended. (Eg. 
com.example.ExampleApplication.) Required. -->
+       <id>MD5Checker</id>
+
+       <!-- Used as the filename for the application. Required. -->
+       <filename>MD5Checker</filename>
+
+       <!-- The name that is displayed in the AIR application installer. 
+       May have multiple values for each language. See samples or xsd schema 
file. Optional. -->
+       <name>MD5Checker</name>
+       
+       <!-- A string value of the format <0-999>.<0-999>.<0-999> that 
represents application version which can be used to check for application 
upgrade. 
+       Values can also be 1-part or 2-part. It is not necessary to have a 
3-part value.
+       An updated version of application must have a versionNumber value 
higher than the previous version. Required for namespace >= 2.5 . -->
+       <versionNumber>0.0.0</versionNumber>
+                        
+       <!-- A string value (such as "v1", "2.5", or "Alpha 1") that represents 
the version of the application, as it should be shown to users. Optional. -->
+       <!-- <versionLabel></versionLabel> -->
+
+       <!-- Description, displayed in the AIR application installer.
+       May have multiple values for each language. See samples or xsd schema 
file. Optional. -->
+       <!-- <description></description> -->
+
+       <!-- Copyright information. Optional -->
+       <!-- <copyright></copyright> -->
+
+       <!-- Publisher ID. Used if you're updating an application created prior 
to 1.5.3 -->
+       <!-- <publisherID></publisherID> -->
+
+       <!-- Settings for the application's initial window. Required. -->
+       <initialWindow>
+               <!-- The main SWF or HTML file of the application. Required. -->
+               <!-- Note: In Flash Builder, the SWF reference is set 
automatically. -->
+               <content>MD5Checker.swf</content>
+               
+               <!-- The title of the main window. Optional. -->
+               <!-- <title></title> -->
+
+               <!-- The type of system chrome to use (either "standard" or 
"none"). Optional. Default standard. -->
+               <!-- <systemChrome></systemChrome> -->
+
+               <!-- Whether the window is transparent. Only applicable when 
systemChrome is none. Optional. Default false. -->
+               <!-- <transparent></transparent> -->
+
+               <!-- Whether the window is initially visible. Optional. Default 
false. -->
+               <!-- <visible></visible> -->
+
+               <!-- Whether the user can minimize the window. Optional. 
Default true. -->
+               <!-- <minimizable></minimizable> -->
+
+               <!-- Whether the user can maximize the window. Optional. 
Default true. -->
+               <!-- <maximizable></maximizable> -->
+
+               <!-- Whether the user can resize the window. Optional. Default 
true. -->
+               <!-- <resizable></resizable> -->
+
+               <!-- The window's initial width in pixels. Optional. -->
+               <!-- <width></width> -->
+
+               <!-- The window's initial height in pixels. Optional. -->
+               <!-- <height></height> -->
+
+               <!-- The window's initial x position. Optional. -->
+               <!-- <x></x> -->
+
+               <!-- The window's initial y position. Optional. -->
+               <!-- <y></y> -->
+
+               <!-- The window's minimum size, specified as a width/height 
pair in pixels, such as "400 200". Optional. -->
+               <!-- <minSize></minSize> -->
+
+               <!-- The window's initial maximum size, specified as a 
width/height pair in pixels, such as "1600 1200". Optional. -->
+               <!-- <maxSize></maxSize> -->
+
+        <!-- The initial aspect ratio of the app when launched (either 
"portrait" or "landscape"). Optional. Mobile only. Default is the natural 
orientation of the device -->
+
+        <!-- <aspectRatio></aspectRatio> -->
+
+        <!-- Whether the app will begin auto-orienting on launch. Optional. 
Mobile only. Default false -->
+
+        <!-- <autoOrients></autoOrients> -->
+
+        <!-- Whether the app launches in full screen. Optional. Mobile only. 
Default false -->
+
+        <!-- <fullScreen></fullScreen> -->
+
+        <!-- The render mode for the app (either auto, cpu, gpu, or direct). 
Optional. Default auto -->
+
+        <!-- <renderMode></renderMode> -->
+
+               <!-- Whether or not to pan when a soft keyboard is raised or 
lowered (either "pan" or "none").  Optional.  Defaults "pan." -->
+               <!-- <softKeyboardBehavior></softKeyboardBehavior> -->
+       <autoOrients>false</autoOrients>
+        <fullScreen>false</fullScreen>
+        <visible>false</visible>
+    </initialWindow>
+
+       <!-- We recommend omitting the supportedProfiles element, -->
+       <!-- which in turn permits your application to be deployed to all -->
+       <!-- devices supported by AIR. If you wish to restrict deployment -->
+       <!-- (i.e., to only mobile devices) then add this element and list -->
+       <!-- only the profiles which your application does support. -->
+       <!-- <supportedProfiles>desktop extendedDesktop mobileDevice 
extendedMobileDevice</supportedProfiles> -->
+
+       <!-- The subpath of the standard default installation location to use. 
Optional. -->
+       <!-- <installFolder></installFolder> -->
+
+       <!-- The subpath of the Programs menu to use. (Ignored on operating 
systems without a Programs menu.) Optional. -->
+       <!-- <programMenuFolder></programMenuFolder> -->
+
+       <!-- The icon the system uses for the application. For at least one 
resolution,
+       specify the path to a PNG file included in the AIR package. Optional. 
-->
+       <!-- <icon>
+               <image16x16></image16x16>
+               <image32x32></image32x32>
+               <image36x36></image36x36>
+               <image48x48></image48x48>
+               <image57x57></image57x57>
+               <image72x72></image72x72>
+               <image114x114></image114x114>
+               <image128x128></image128x128>
+       </icon> -->
+
+       <!-- Whether the application handles the update when a user 
double-clicks an update version
+       of the AIR file (true), or the default AIR application installer 
handles the update (false).
+       Optional. Default false. -->
+       <!-- <customUpdateUI></customUpdateUI> -->
+       
+       <!-- Whether the application can be launched when the user clicks a 
link in a web browser.
+       Optional. Default false. -->
+       <!-- <allowBrowserInvocation></allowBrowserInvocation> -->
+
+       <!-- Listing of file types for which the application can register. 
Optional. -->
+       <!-- <fileTypes> -->
+
+               <!-- Defines one file type. Optional. -->
+               <!-- <fileType> -->
+
+                       <!-- The name that the system displays for the 
registered file type. Required. -->
+                       <!-- <name></name> -->
+
+                       <!-- The extension to register. Required. -->
+                       <!-- <extension></extension> -->
+                       
+                       <!-- The description of the file type. Optional. -->
+                       <!-- <description></description> -->
+                       
+                       <!-- The MIME content type. -->
+                       <!-- <contentType></contentType> -->
+                       
+                       <!-- The icon to display for the file type. Optional. 
-->
+                       <!-- <icon>
+                               <image16x16></image16x16>
+                               <image32x32></image32x32>
+                               <image48x48></image48x48>
+                               <image128x128></image128x128>
+                       </icon> -->
+                       
+               <!-- </fileType> -->
+       <!-- </fileTypes> -->
+
+    <!-- iOS specific capabilities -->
+       <!-- <iPhone> -->
+               <!-- A list of plist key/value pairs to be added to the 
application Info.plist -->
+               <!-- <InfoAdditions>
+            <![CDATA[
+                <key>UIDeviceFamily</key>
+                <array>
+                    <string>1</string>
+                    <string>2</string>
+                </array>
+                <key>UIStatusBarStyle</key>
+                <string>UIStatusBarStyleBlackOpaque</string>
+                <key>UIRequiresPersistentWiFi</key>
+                <string>YES</string>
+            ]]>
+        </InfoAdditions> -->
+        <!-- A list of plist key/value pairs to be added to the application 
Entitlements.plist -->
+               <!-- <Entitlements>
+            <![CDATA[
+                <key>keychain-access-groups</key>
+                <array>
+                    <string></string>
+                    <string></string>
+                </array>
+            ]]>
+        </Entitlements> -->
+       <!-- Display Resolution for the app (either "standard" or "high"). 
Optional. Default "standard" -->
+       <!-- <requestedDisplayResolution></requestedDisplayResolution> -->
+       <!-- </iPhone> -->
+
+       <!-- Specify Android specific tags that get passed to 
AndroidManifest.xml file. -->
+    <!--<android> -->
+    <!--       <manifestAdditions>
+               <![CDATA[
+                       <manifest android:installLocation="auto">
+                               <uses-permission 
android:name="android.permission.INTERNET"/>
+                               <uses-permission 
android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
+                               <uses-permission 
android:name="android.permission.ACCESS_FINE_LOCATION"/>
+                               <uses-feature android:required="true" 
android:name="android.hardware.touchscreen.multitouch"/>
+                               <application android:enabled="true">
+                                       <activity 
android:excludeFromRecents="false">
+                                               <intent-filter>
+                                                       <action 
android:name="android.intent.action.MAIN"/>
+                                                       <category 
android:name="android.intent.category.LAUNCHER"/>
+                                               </intent-filter>
+                                       </activity>
+                               </application>
+            </manifest>
+               ]]>
+        </manifestAdditions> -->
+           <!-- Color depth for the app (either "32bit" or "16bit"). Optional. 
Default 16bit before namespace 3.0, 32bit after -->
+        <!-- <colorDepth></colorDepth> -->
+    <!-- </android> -->
+       <!-- End of the schema for adding the android specific tags in 
AndroidManifest.xml file -->
+
+</application>

http://git-wip-us.apache.org/repos/asf/flex-utilities/blob/2454c94f/MD5Checker/src/MD5Checker.mxml
----------------------------------------------------------------------
diff --git a/MD5Checker/src/MD5Checker.mxml b/MD5Checker/src/MD5Checker.mxml
new file mode 100644
index 0000000..9171cb9
--- /dev/null
+++ b/MD5Checker/src/MD5Checker.mxml
@@ -0,0 +1,414 @@
+<?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.
+
+-->
+<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"
+                       preinitialize="getInvoke()"
+                       applicationComplete="setup()">
+    <fx:Declarations>
+        <!-- Place non-visual elements (e.g., services, value objects) here -->
+    </fx:Declarations>
+    <fx:Script>
+        <![CDATA[
+            import org.apache.flex.crypto.MD5Stream;
+            
+            private static var DEFAULT_READBUFFER_SIZE:int = 2 * 1024 * 1024;
+            private static var GCL:String = "Google Closure Library";
+            
+            private var data:Array = [];
+            
+            private function getInvoke():void {
+                var nativeApplication:NativeApplication = 
NativeApplication.nativeApplication;
+                nativeApplication.addEventListener(InvokeEvent.INVOKE, 
parseArgs);
+            }
+            private var logFileName:String = "MD5CheckerLog.txt";
+            
+            private function parseArgs(event:InvokeEvent):void {
+                for each (var s:String in event.arguments) {
+                    if (s.indexOf("-log=") == 0) {
+                        logFileName = s.substring(5);
+                    }
+                }
+            }
+            
+            // last modified dates and checksum map by url;
+            private var configURL:String = 
"http://flex.apache.org/installer/sdk-installer-config-4.0.xml";;
+            private var fs:FileStream = new FileStream();
+            private var f:File;
+
+            private function setup():void
+            {
+                f = File.documentsDirectory.resolvePath(logFileName);
+                fs.open(f, FileMode.WRITE);
+
+                var urlRequest:URLRequest = new URLRequest(configURL);
+                urlRequest.followRedirects = true;
+                urlRequest.cacheResponse = false;
+                urlRequest.method = URLRequestMethod.GET;
+                xmlLoader.dataFormat = URLLoaderDataFormat.TEXT;
+                xmlLoader.addEventListener(Event.COMPLETE, xmlcompleteHandler);
+                xmlLoader.addEventListener(IOErrorEvent.IO_ERROR, 
xmlerrorHandler);
+                xmlLoader.addEventListener(SecurityErrorEvent.SECURITY_ERROR, 
xmlerrorHandler);
+                xmlLoader.load(urlRequest);
+                progressLabel.text = "Fetching sdk-installer-config-4.0.xml";  
 
+            }
+            
+            private var xml:XML;
+            
+            private function xmlcompleteHandler(event:Event):void
+            {
+                xml = new XML(xmlLoader.data as String);
+                var xmlList:XMLList;
+                
+                var item:Object;
+                
+                xmlList = xml["google-closure-library"];
+                for each (var node:XML in xmlList)
+                {
+                    item = {};
+                    item.label = GCL;
+                    item.url = node.@server.toString() + "/" + 
node.@folder.toString() + "/" + node.@file.toString();
+                    item.md5 = node.@md5.toString();
+                    if (!item.md5)
+                        continue;
+                    item.cacheID = node.@cacheID.toString();
+                    item.node = node;
+                    data.push(item);
+                }
+
+                xmlList = xml.flashsdk.versions.children();
+                for each (node in xmlList)
+                {
+                    item = {};
+                    item.label = "Flash PlayerGlobal " + 
node.@displayVersion.toString();
+                    item.url = node.path.toString() + node.file.toString();
+                    item.md5 = node.md5.toString();
+                    if (!item.md5)
+                        continue;
+                    item.cacheID = node.@cacheID.toString();
+                    item.node = node;
+                    data.push(item);
+                }
+                
+                /*
+                xmlList = xml.airsdk.windows.versions.children();
+                for each (node in xmlList)
+                {
+                    item = {};
+                    item.label = "AIR Windows " + 
node.@displayVersion.toString();
+                    item.url = node.path.toString() + node.file.toString();
+                    item.md5 = node.md5.toString();
+                    if (!item.md5)
+                        continue;
+                    item.cacheID = node.@cacheID.toString();
+                    item.node = node;
+                    data.push(item);
+                }
+                
+                xmlList = xml.airsdk.mac.versions.children();
+                for each (node in xmlList)
+                {
+                    item = {};
+                    item.label = "AIR Mac " + node.@displayVersion.toString();
+                    item.url = node.path.toString() + node.file.toString();
+                    item.md5 = node.md5.toString();
+                    if (!item.md5)
+                        continue;
+                    item.cacheID = node.@cacheID.toString();
+                    item.node = node;
+                    data.push(item);
+                }
+                */
+                dg.dataProvider = new ArrayList(data);
+                checkSums();
+            }
+            
+            private function xmlerrorHandler(event:Event):void
+            {
+                event.preventDefault();
+                fs.writeUTFBytes("Unable to fetch " + configURL);
+                fs.close();
+                this.nativeApplication.exit(-1);
+            }
+            
+
+            private var xmlLoader:URLLoader = new URLLoader();
+            
+            private var current:int;
+            private var lastModified:String;
+            
+            private function checkSums():void
+            {
+                current = 0;
+                checkCurrent();
+            }
+            
+            private var urlHeadLoader:URLLoader = new URLLoader();
+            private var urlLoader:URLLoader = new URLLoader();
+            private var urlLoader2:URLLoader = new URLLoader();
+            
+            private var nodeChanged:Boolean;
+            
+            private function checkCurrent():void
+            {
+                if (current >= data.length)
+                {
+                    fs.close();
+                    this.nativeApplication.exit(nodeChanged ? -1 : 0);
+                    return;
+                }
+                
+                lastModified = null;
+                
+                var urlRequest:URLRequest = new URLRequest(data[current].url);
+                urlRequest.followRedirects = true;
+                urlRequest.cacheResponse = false;
+                urlRequest.method = URLRequestMethod.HEAD;
+                urlHeadLoader.dataFormat = URLLoaderDataFormat.BINARY;
+                urlHeadLoader.addEventListener(Event.COMPLETE, 
headcompleteHandler);
+                
urlHeadLoader.addEventListener(HTTPStatusEvent.HTTP_RESPONSE_STATUS,headstatusHandler);
+                urlHeadLoader.addEventListener(IOErrorEvent.IO_ERROR, 
errorHandler);
+                
urlHeadLoader.addEventListener(SecurityErrorEvent.SECURITY_ERROR, errorHandler);
+                urlHeadLoader.load(urlRequest);
+                progressLabel.text = "Checking " + data[current].url;
+            }
+            
+            private var lastStatus:int;
+            
+            private function headstatusHandler(event:HTTPStatusEvent):void
+            {
+                lastStatus = event.status;
+                if (event.status >= 400) 
+                {
+                    // some problem.  skip, go to next one
+                    current++;
+                    checkCurrent();
+                }
+                else
+                {
+                    var foundLastModified:Boolean = false;
+                    var headers:Array = event.responseHeaders;
+                    for each (var header:URLRequestHeader in headers)
+                    {
+                        if (header.name == "Last-Modified")
+                        {
+                            lastModified = header.value;
+                            foundLastModified = true;
+                        }
+                        else if (header.name == "Etag" && lastModified == null)
+                        {
+                            lastModified = header.value;
+                            foundLastModified = true;
+                        }
+                    }
+                    if (!foundLastModified)
+                    {
+                        trace("no last modified or etag header");
+                    }
+                }
+            }
+
+            private function headcompleteHandler(event:Event):void
+            {
+                if (data[current].cacheID != lastModified)
+                {
+                    download();
+                }
+                else
+                {
+                    current++;
+                    checkCurrent();
+                }
+            }
+            
+            private function download():void
+            {
+                var urlRequest:URLRequest = new URLRequest(data[current].url);
+                urlRequest.followRedirects = true;
+                urlRequest.cacheResponse = false;
+                urlRequest.method = URLRequestMethod.GET;
+                urlLoader.dataFormat = URLLoaderDataFormat.BINARY;
+                urlLoader.addEventListener(Event.COMPLETE, completeHandler);
+                
urlHeadLoader.addEventListener(HTTPStatusEvent.HTTP_RESPONSE_STATUS, 
statusHandler);
+                urlLoader.addEventListener(ProgressEvent.PROGRESS, 
progressHandler);
+                urlLoader.addEventListener(IOErrorEvent.IO_ERROR, 
errorHandler);
+                urlLoader.addEventListener(SecurityErrorEvent.SECURITY_ERROR, 
errorHandler);
+                urlLoader.load(urlRequest);
+                progressLabel.text = "Downloading " + data[current].url;
+            }
+            
+            private function progressHandler(event:ProgressEvent):void
+            {
+                pb.setProgress(event.bytesLoaded, event.bytesTotal);
+                pbCurrent.text = event.bytesLoaded.toString();
+                pbTotal.text = event.bytesTotal.toString();
+            }
+            
+            private function statusHandler(event:HTTPStatusEvent):void
+            {
+                lastStatus = event.status;
+            }
+            
+            private function errorHandler(event:Event):void
+            {
+                event.preventDefault();
+                current++;
+                checkCurrent();
+            }
+            
+            
+            private var md5:MD5Stream;
+            private var ba:ByteArray;
+            
+            private function completeHandler(event:Event):void
+            {
+                if (lastStatus < 300)
+                {
+                    md5 = new MD5Stream();
+                    md5.resetFields();
+                    ba = urlLoader.data as ByteArray;
+                    progressLabel.text = "Computing checksum for " + 
data[current].url;
+                    getSum();
+                }
+                else
+                {
+                    current++;
+                    checkCurrent();                    
+                }
+            }
+            
+            private function getSum():void
+            {
+                if (ba.bytesAvailable < DEFAULT_READBUFFER_SIZE)
+                {
+                    sumComplete();
+                    return;
+                }
+                md5.update(ba, DEFAULT_READBUFFER_SIZE);
+                pb.setProgress(ba.position, ba.length);
+                pbCurrent.text = ba.position.toString();
+                pbTotal.text = ba.length.toString();
+                callLater(getSum);
+            }
+            
+            private var sum:String;
+            
+            private function sumComplete():void
+            {
+                sum = md5.complete(ba, ba.length);
+                retries = 1;
+                redownload();
+            }
+            
+            private function redownload():void
+            {
+                var urlRequest:URLRequest = new URLRequest(data[current].url);
+                urlRequest.followRedirects = true;
+                urlRequest.cacheResponse = false;
+                urlRequest.method = URLRequestMethod.GET;
+                urlLoader2.dataFormat = URLLoaderDataFormat.BINARY;
+                urlLoader2.addEventListener(Event.COMPLETE, recompleteHandler);
+                urlLoader2.addEventListener(ProgressEvent.PROGRESS, 
progressHandler);
+                urlLoader2.addEventListener(IOErrorEvent.IO_ERROR, 
reerrorHandler);
+                urlLoader2.addEventListener(SecurityErrorEvent.SECURITY_ERROR, 
reerrorHandler);
+                urlLoader2.load(urlRequest);
+                progressLabel.text = "Verifying CheckSum (" + 
retries.toString() + ")";
+            }
+            
+            private var retries:int;
+            
+            private function reerrorHandler(event:Event):void
+            {
+                if (retries < 4)
+                    redownload();
+            }
+            
+            private function recompleteHandler(event:Event):void
+            {
+                md5 = new MD5Stream();
+                md5.resetFields();
+                ba = urlLoader2.data as ByteArray;
+                getSum2();
+            }
+            
+            private function getSum2():void
+            {
+                if (ba.bytesAvailable < DEFAULT_READBUFFER_SIZE)
+                {
+                    sumComplete2();
+                    return;
+                }
+                md5.update(ba, DEFAULT_READBUFFER_SIZE);
+                pb.setProgress(ba.position, ba.length);
+                pbCurrent.text = ba.position.toString();
+                pbTotal.text = ba.length.toString();
+                callLater(getSum2);
+            }
+                        
+            private function sumComplete2():void
+            {
+                var sum2:String = md5.complete(ba, ba.length);
+                if (sum == sum2)
+                {
+                    data[current].cacheID = lastModified;
+                    data[current].md5 = sum;
+                    fs.writeUTFBytes("Old Node:\n");
+                    fs.writeUTFBytes(data[current].node.toXMLString() + "\n");
+                    fs.writeUTFBytes("New Node:\n");
+                    data[current].node.@cacheID = lastModified;
+                    if (data[current].label == GCL)
+                        data[current].node.@md5 = sum;
+                    else
+                        data[current].node.md5 = sum;
+                    nodeChanged = true;
+                    fs.writeUTFBytes(data[current].node.toXMLString() + "\n"); 
                       
+                    dg.dataProvider.itemUpdated(data[current]);
+                    current++;
+                    checkCurrent();
+                }
+                else
+                {
+                    sum = sum2;
+                    redownload();
+                }
+            }
+
+        ]]>
+    </fx:Script>
+    <s:VGroup width="100%">
+        <s:DataGrid id="dg" width="100%" height="300">
+            <s:columns>
+                <s:ArrayList>
+                    <s:GridColumn dataField="label" />
+                    <s:GridColumn dataField="url" />
+                    <s:GridColumn dataField="md5" />
+                    <s:GridColumn dataField="cacheID" />
+                </s:ArrayList>
+            </s:columns>
+        </s:DataGrid>
+        <s:Label id="progressLabel" width="100%" />
+        <mx:ProgressBar id="pb" width="100%" mode="manual" />
+        <s:HGroup>
+            <s:Label id="pbCurrent" />
+            <s:Label text="out of" />
+            <s:Label id="pbTotal" />
+        </s:HGroup>
+    </s:VGroup>
+</s:WindowedApplication>

Reply via email to