<!--
  ~ 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.
  -->
<html lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Apache Flex® Tour De Flex Component Explorer</title>
<script src="AC_OETags.js" language="javascript"></script>
<style type="text/css" media="screen"> 
    html, body  { height:100%; }
    body { margin:0; padding:0; overflow:auto; text-align:center; 
           background-color: #ffffff; }   
    object:focus { outline:none; }
    #flashContent { display:none; }
</style>
<script type="text/javascript" src="swfobject.js"></script>
<script type="text/javascript">
    var swfVersionStr = "11.1.0";
    var xiSwfUrlStr = "";
    var flashvars = {};
    if (swfobject.getQueryParamValue("app") && swfobject.getQueryParamValue("app")) {
 		flashvars.app = swfobject.getQueryParamValue("app");
	}
    var params = {};
    params.quality = "high";
    params.bgcolor = "#ffffff";
    params.allowscriptaccess = "sameDomain";
    params.allowfullscreen = "true";
    var attributes = {};
    attributes.id = "TourDeFlex";
    attributes.name = "TourDeFlex";
    attributes.align = "middle";
    swfobject.embedSWF(
        "explorer.swf", "flashContent", 
        "100%", "100%", 
        swfVersionStr, xiSwfUrlStr, 
        flashvars, params, attributes);
    swfobject.createCSS("#flashContent", "display:block;text-align:left;");
</script>
<!-- Google Analytics -->
<script type="text/javascript">
	var _gaq = _gaq || [];
	_gaq.push(['_setAccount', 'UA-37926454-1']);
	_gaq.push(['_trackPageview']);

	(function() {
		var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
		ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
		var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
	})();
</script>
</head>

<body scroll='no'>
<div id="flashContent">
    <p>
        To view this page ensure that Adobe Flash Player is installed. 
    </p>
    <script type="text/javascript"> 
        var pageHost = ((document.location.protocol == "https:") ? "https://" : "http://"); 
        document.write("<a href='http://www.adobe.com/go/getflashplayer'><img src='" 
                        + pageHost + "www.adobe.com/images/shared/download_buttons/get_flash_player.gif' alt='Get Adobe Flash player' /></a>" ); 
    </script> 
</div>
</body>
</html>
