public static bool InstallGame( string gameTitle, string gameVersion, ProgressDelegate listener, ICancellable cancelObject )
        {
            var downloadPath = GetDownloadPath( gameTitle, gameVersion );
            var installPath = GetInstallPath( gameTitle, gameVersion );
            if( File.Exists( downloadPath ) )
            {
                try
                {
                    using( var zipFile = new ZipFile( downloadPath ) )
                    {
                        // Delete old install
                        if( Directory.Exists( installPath ) )
                        {
                            Directory.Delete( installPath, true );
                        }
                        Directory.CreateDirectory( installPath );

                        // Extract new install
                        int totalFiles = zipFile.Entries.Count;
                        int filesInstalled = 0;
                        int lastProgress = 0;
                        listener.Invoke( 0 );
                        foreach( var entry in zipFile.Entries )
                        {
                            // Extract the file
                            var entryInstallPath = Path.Combine( installPath, entry.FileName );
                            if( entry.IsDirectory )
                            {
                                Directory.CreateDirectory( entryInstallPath );
                            }
                            else
                            {
                                Directory.CreateDirectory( Path.GetDirectoryName( entryInstallPath ) );
                                using( var file = File.OpenWrite( entryInstallPath ) )
                                {
                                    try
                                    {
                                        using( var reader = new ProgressStream( entry.OpenReader(), -1, delegate {
                                            // TODO: Emit progress during installation of large individual files?
                                        }, cancelObject ) )
                                        {
                                            try
                                            {
                                                reader.CopyTo( file );
                                                if( Program.Platform == Platform.Linux ||
                                                    Program.Platform == Platform.OSX )
                                                {
                                                    Mono.Unix.Native.Syscall.chmod(
                                                        entryInstallPath,
                                                        Mono.Unix.Native.FilePermissions.ACCESSPERMS
                                                    );
                                                }
                                            }
                                            finally
                                            {
                                                reader.Close();
                                            }
                                        }
                                    }
                                    finally
                                    {
                                        file.Close();
                                    }
                                }
                            }

                            // Check for cancellation
                            if( cancelObject.Cancelled )
                            {
                                throw new IOCancelledException();
                            }

                            // Notify the progress listener
                            filesInstalled++;
                            int progress = (filesInstalled * 100) / totalFiles;
                            if( progress != lastProgress )
                            {
                                listener.Invoke( progress );
                                lastProgress = progress;
                            }
                        }
                    }
                    return true;
                }
                catch( IOException )
                {
                    if( Directory.Exists( installPath ) )
                    {
                        Directory.Delete( installPath, true );
                    }
                    return false;
                }
                catch( ZipException )
                {
                    if( Directory.Exists( installPath ) )
                    {
                        Directory.Delete( installPath, true );
                    }
                    return false;
                }
            }
            return false;
        }
        public static bool ExtractEmbeddedGame( ProgressDelegate listener, ICancellable cancelObject )
        {
            string gameTitle, gameVersion, gameURL, username, password;
            if( GetEmbeddedGameInfo( out gameTitle, out gameVersion, out gameURL, out username, out password ) && gameVersion != null )
            {
                var downloadPath = GetDownloadPath( gameTitle, gameVersion );
                try
                {
                    var assembly = Assembly.GetExecutingAssembly();
                    var stream = assembly.GetManifestResourceStream( "EmbeddedGame." + Program.Platform + ".zip" );
                    if( stream == null )
                    {
                        stream =  assembly.GetManifestResourceStream( "EmbeddedGame.zip" );
                    }
                    if( stream != null )
                    {
                        using( stream )
                        {
                            try
                            {
                                using( var progressStream = new ProgressStream( stream, -1, listener, cancelObject ) )
                                {
                                    // Delete old download
                                    if( File.Exists( downloadPath ) )
                                    {
                                        File.Delete( downloadPath );
                                    }

                                    // Create new download
                                    try
                                    {
                                        Directory.CreateDirectory( Path.GetDirectoryName( downloadPath ) );
                                        using( var output = File.OpenWrite( downloadPath ) )
                                        {
                                            try
                                            {
                                                progressStream.CopyTo( output );
                                            }
                                            finally
                                            {
                                                output.Close();
                                            }
                                        }
                                    }
                                    finally
                                    {
                                        progressStream.Close();
                                    }
                                }
                            }
                            finally
                            {
                                stream.Close();
                            }
                        }
                        return true;
                    }
                    return false;
                }
                catch( IOException )
                {
                    if( File.Exists( downloadPath ) )
                    {
                        File.Delete( downloadPath );
                    }
                    return false;
                }
            }
            return false;
        }
        public static bool DownloadGame( string gameTitle, string gameVersion, string url, string username, string password, ProgressDelegate listener, ICancellable cancelObject, out bool o_authFailure, out string o_customMessage )
        {
            if( url == null )
            {
                o_authFailure = false;
                o_customMessage = null;
                return false;
            }

            var downloadPath = GetDownloadPath( gameTitle, gameVersion );
            try
            {
                var request = HttpWebRequest.Create( url );
                request.Timeout = 15000;
                if( username != null && password != null )
                {
                    request.Credentials = new NetworkCredential( username, password );
                }
                using( var response = request.GetResponse() )
                {
                    // Read the message
                    o_customMessage = response.Headers.Get( "X-IndieLauncher-Message" );

                    // Read the content
                    using( var stream = new ProgressStream( response.GetResponseStream(), response.ContentLength, listener, cancelObject ) )
                    {
                        try
                        {
                            // Delete old download
                            if( File.Exists( downloadPath ) )
                            {
                                File.Delete( downloadPath );
                            }

                            // Create new download
                            Directory.CreateDirectory( Path.GetDirectoryName( downloadPath ) );
                            using( var output = File.OpenWrite( downloadPath ) )
                            {
                                try
                                {
                                    stream.CopyTo( output );
                                }
                                finally
                                {
                                    output.Close();
                                }
                            }
                        }
                        finally
                        {
                            stream.Close();
                        }
                    }
                }
                o_authFailure = false;
                return true;
            }
            catch( IOException )
            {
                if( File.Exists( downloadPath ) )
                {
                    File.Delete( downloadPath );
                }
                o_customMessage = null;
                o_authFailure = false;
                return false;
            }
            catch( WebException e )
            {
                if( File.Exists( downloadPath ) )
                {
                    File.Delete( downloadPath );
                }
                if( e.Response != null )
                {
                    o_customMessage = e.Response.Headers.Get( "X-IndieLauncher-Message" );
                    if( ((HttpWebResponse)e.Response).StatusCode == HttpStatusCode.Unauthorized )
                    {
                        o_authFailure = true;
                    }
                    else
                    {
                        o_authFailure = false;
                    }
                }
                else
                {
                    o_customMessage = null;
                    o_authFailure = false;
                }
                return false;
            }
        }
 public static RSSFile Download( string url, ProgressDelegate listener, ICancellable cancelObject )
 {
     try
     {
         var request = HttpWebRequest.Create( url );
         request.Timeout = 15000;
         using( var response = request.GetResponse() )
         {
             using( var stream = new ProgressStream( response.GetResponseStream(), response.ContentLength, listener, cancelObject ) )
             {
                 try
                 {
                     return new RSSFile( stream );
                 }
                 finally
                 {
                     stream.Close();
                 }
             }
         }
     }
     catch( IOException )
     {
         return null;
     }
     catch( WebException )
     {
         return null;
     }
 }