text:
<?xml version="1.0" encoding="utf-8"?>
<!--Generated by crowdin.com-->
<!--
 Copyright (c) 2012 - 2014 Ngewi Fet <ngewif@gmail.com>

 Licensed 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.
-->
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
  <string name="title_create_account">Créer un compte</string>
  <string name="title_edit_account">Éditer le compte</string>
  <string name="info_details">Informations</string>
  <string name="menu_export">Exporter en OFX</string>
  <string name="description_add_transaction_icon">Ajoute une nouvelle transaction à un compte</string>
  <string name="label_no_accounts">Aucun compte à afficher</string>
  <string name="label_account_name">Nom du compte</string>
  <string name="btn_cancel">Annuler</string>
  <string name="btn_save">Sauvegarder</string>
  <string name="btn_test">Test</string>
  <string name="label_passcode">Entrer code</string>
  <string name="toast_wrong_passcode">Mauvais code, veuillez réessayer</string>
  <string name="toast_passcode_set">Code ajouté</string>
  <string name="label_confirm_passcode">Veuillez confirmer vorte code</string>
  <string name="toast_invalid_passcode_confirmation">Code de confirmation invalide. Veuillez réessayer</string>
  <string name="label_transaction_name">Description</string>
  <string name="label_transaction_amount">Montant</string>
  <string name="title_add_transaction">Nouvelle transaction</string>
  <string name="label_no_transactions">Aucune transaction à afficher</string>
  <string name="label_timeanddate">DATE & HEURE</string>
  <string name="label_account">Compte</string>
  <string name="label_debit">DÉBIT</string>
  <string name="label_credit">CRÉDIT</string>
  <string name="title_accounts">Comptes</string>
  <string name="title_transactions">Transactions</string>
  <string name="menu_delete">SUPPRIMER</string>
  <string name="alert_dialog_ok_delete">Supprimer</string>
  <string name="alert_dialog_cancel">Annuler</string>
  <string name="toast_account_deleted">Compte supprimé</string>
  <string name="title_confirm_delete">Confirmer la suppression</string>
  <string name="delete_account_confirmation_message">Toutes les transactions dans ce compte seront aussi supprimées</string>
  <string name="title_edit_transaction">Éditer la transaction</string>
  <string name="label_transaction_description">Note</string>
  <string name="menu_move">DÉPLACER</string>
  <string name="title_selected">%1$d sélectionné(s)</string>
  <string name="label_account_balance">Solde:</string>
  <string name="label_export_destination">Exporter vers:</string>
  <string name="title_export_dialog">Exporter les transactions</string>
  <string name="option_export_all_transactions">Exporter toutes les transactions</string>
  <string name="hint_export_choice">Par défaut, seul les nouvelles transactions depuis le dernier export seront exportées. Cochez cette option pour exporter toutes les transactions</string>
  <string name="toast_export_error">Erreur lors de l\'export des données en %1$s</string>
  <string name="btn_export">Exporter</string>
  <string name="option_delete_after_export">Effacer les transactions apres export</string>
  <string name="hint_delete_after_export">Toutes les transactions exportées seront supprimées aprés l\'export</string>
  <string name="title_settings">Paramètres</string>
  <string-array name="export_destinations">
    <item>Carte SD</item>
    <item>DropBox</item>
    <item>Google Drive</item>
    <item>ownCloud</item>
    <item>Envoyer vers…</item>
  </string-array>
  <string name="btn_move">Déplacer</string>
  <string name="title_move_transactions">Déplacer %1$d transaction(s)</string>
  <string name="label_move_destination">Compte de destination</string>
  <string name="permission_access_sdcard">Accés carte SD</string>
  <string name="toast_incompatible_currency">Impossible de déplacer les transactions.\nLe compte de destination utilise une monnaie différente du compte d\'origine</string>
  <string name="header_general_settings">Général</string>
  <string name="header_about_gnucash">À propos</string>
  <string name="title_choose_currency">Choisisez une monnaie par défaut</string>
  <string name="title_default_currency">Monnaie par défaut</string>
  <string name="summary_default_currency">Monnaie par défaut à assignée aux nouveau comptes</string>
  <string name="label_permission_record_transactions">Permettre l\'enregistrement des transactions dans GnuCash pour Android</string>
  <string name="label_permission_create_accounts">Permettre la création de comptes dans GnuCash pour Android</string>
  <string name="label_permission_group">Vos données GnuCash</string>
  <string name="description_permission_group">Lire et modifier les données GnuCash</string>
  <string name="label_permission_record_transaction">Enregistrer les transactions dans GnuCash</string>
  <string name="label_permission_create_account">Créer comptes dans GnuCash</string>
  <string name="label_display_account">Afficher le compte</string>
  <string name="btn_create_accounts">Créer les comptes</string>
  <string name="title_default_accounts">Choisisez les comptes à créés</string>
  <string name="error_no_accounts">Aucun compte éxistant dans GnuCash.\nCréez un compte avant d\'ajouter un widget</string>
  <string name="title_build_version">Version logiciel</string>
  <string name="title_license">Licence</string>
  <string name="summary_licence_details">Apache License v2.0. Cliquez pour plus de détails</string>
  <string name="title_general_prefs">Général</string>
  <string name="label_widget_configuration">Sélectionner un compte</string>
  <string name="toast_no_transactions_to_export">Il n\'existe pas de transaction disponible pour l\'exportation</string>
  <string name="header_passcode_settings">Code</string>
  <string name="title_passcode_preferences">Préférences code</string>
  <string name="title_passcode_enabled">Code activé</string>
  <string name="title_passcode_disabled">Code désactivé</string>
  <string name="title_change_passcode">Changer le code</string>
  <string name="title_about_gnucash">À propos de GnuCash</string>
  <string name="summary_about_gnucash">A mobile finance management and expense-tracker designed for Android</string>
  <string name="title_about">A propos</string>
  <string name="toast_format_exported_to">Fichier %1$s exporté en :\n</string>
  <string name="title_export_email">GnuCash Android %1$s export</string>
  <string name="description_export_email">GnuCash Android export de </string>
  <string name="header_transaction_settings">Transactions</string>
  <string name="title_transaction_preferences">Préférences des transactions</string>
  <string name="title_account_preferences">Préférences du compte</string>
  <string name="title_default_transaction_type">Type de transaction par défaut</string>
  <string name="summary_default_transaction_type">Le type de transaction à utiliser par défaut, CRÉDIT ou DÉBIT</string>
  <string-array name="transaction_types">
    <item>CRÉDIT</item>
    <item>DÉBIT</item>
  </string-array>
  <string name="msg_delete_all_transactions_confirmation">Êtes vous sûre de vouloir supprimer TOUTES les transactions ?</string>
  <string name="msg_delete_transaction_confirmation">Êtes vous sûre de vouloir supprimer cette transaction ?</string>
  <string name="title_export_preference_category">Exporter</string>
  <string name="title_export_all_transactions">Exporter toutes les transactions</string>
  <string name="title_always_delete_exported_transactions">Supprimer les transactions exportées</string>
  <string name="title_default_export_email">Email d\'export par défaut</string>
  <string name="summary_default_export_email">Email par défaut pour les exports. Vous pourrez toujours le changer lors de votre prochain export.</string>
  <string name="label_double_entry_account">Transfert entre comptes</string>
  <string name="summary_use_double_entry">Toutes les transactions seront transférées d\'un compte à l\'autre</string>
  <string name="title_use_double_entry">Activer les doubles entrée</string>
  <string name="account_balance">Solde</string>
  <string name="toast_no_account_name_entered">Entrer un nom de compte pour créer un compte</string>
  <string name="label_account_currency">Monnaie</string>
  <string name="label_parent_account">Compte parent</string>
  <string name="title_xml_ofx_header">Utiliser l\'entête XML d\'OFX</string>
  <string name="summary_xml_ofx_header">Activez cette option lors d\'un export vers une application tierce autre que GnuCash pour PC</string>
  <string name="title_whats_new">Nouveautées</string>
  <string name="whats_new">
        - Support for multiple different books \n
        - Adds ownCloud as destination for exports\n
        - Compact view for transactions list\n
        - Re-design of passcode lock screen\n
        - Improved handling of scheduled transactions\n
        - Multiple bug fixes and improvements\n
	</string>
  <string name="label_dismiss">Passer</string>
  <string name="toast_transanction_amount_required">Entrez un montant pour sauvegarder la transaction</string>
  <string name="toast_error_edit_multi_currency_transaction">Les transactions multi-devises ne peuvent pas être modifiées</string>
  <string name="menu_import_accounts">Importer des comptes GnuCash</string>
  <string name="btn_import_accounts">Import de comptes</string>
  <string name="toast_error_importing_accounts">Une erreur s\'est produite pendant l\'import de vos comptes GnuCash</string>
  <string name="toast_success_importing_accounts">Comptes GnuCash importés avec succès</string>
  <string name="summary_import_accounts">Importe l\'organisation d\'un compte exporté depuis GnuCash pour PC</string>
  <string name="title_import_accounts">Importer des comptes GnuCash</string>
  <string name="summary_delete_all_accounts">Supprimer tous les comptes dans la base de données. Toutes les transactions seront également supprimés.</string>
  <string name="title_delete_all_accounts">Supprimer tous les comptes</string>
  <string name="header_account_settings">Comptes</string>
  <string name="toast_all_accounts_deleted">Tous les comptes ont été supprimés avec succès</string>
  <string name="confirm_delete_all_accounts">Êtes-vous sûr de vouloir supprimer tous les comptes et toutes les transactions?\nCette opération est définitive !</string>
  <string name="label_account_type">Type de compte</string>
  <string name="summary_delete_all_transactions">Toutes les transactions sur tous les comptes seront supprimées !</string>
  <string name="title_delete_all_transactions">Supprimer toutes les transactions</string>
  <string name="toast_all_transactions_deleted">Toutes les transactions ont été supprimées avec succès !</string>
  <string name="title_progress_importing_accounts">Importation de comptes</string>
  <string name="toast_tap_again_to_confirm_delete">Taper de nouveau pour confirmer. TOUTES les entrées seront supprimées !</string>
  <string name="section_header_transactions">Transactions</string>
  <string name="section_header_subaccounts">Sous-comptes</string>
  <string name="menu_search_accounts">Rechercher</string>
  <string name="title_default_export_format">Format d\'export par défaut</string>
  <string name="summary_default_export_format">Format de fichier à utiliser par défaut pour l\'export des transactions</string>
  <string name="menu_export_transactions">Exporter les transactions…</string>
  <string name="label_recurring_transaction">Récurrence</string>
  <!-- This should be the same name used by GnuCash desktop for imbalance accounts -->
  <string name="imbalance_account_name">Déséquilibre</string>
  <string name="title_progress_exporting_transactions">Exportation des transactions</string>
  <string name="label_no_recurring_transactions">Pas de transactions planifiées à afficher.</string>
  <string name="toast_recurring_transaction_deleted">Transaction récurrente supprimée avec succès</string>
  <string name="label_placeholder_account">Compte de référence</string>
  <string name="label_default_transfer_account">Compte de transfert par défaut</string>
  <plurals name="label_sub_accounts">
    <item quantity="one">%d sous-compte</item>
    <item quantity="other">%d sous-comptes</item>
  </plurals>
  <string-array name="account_type_entry_values">
    <item>ARGENT</item>
    <item>BANQUE</item>
    <item>CARTE DE CREDIT</item>
    <item>AVOIRS</item>
    <item>DETTES</item>
    <item>REVENUS</item>
    <item>FRAIS</item>
    <item>PAYABLE</item>
    <item>RECEVABLE</item>
    <item>FONDS</item>
    <item>DEVISES</item>
    <item>ACTIONS</item>
    <item>FONDS COMMUNS</item>
    <item>TRADING</item>
  </string-array>
  <string-array name="export_formats">
    <item>QIF</item>
    <item>OFX</item>
    <item>XML</item>
  </string-array>
  <!-- Default title for color picker dialog [CHAR LIMIT=30] -->
  <string name="color_picker_default_title">Sélectionnez une couleur</string>
  <!-- Content description for a color square. -->
  <!-- Content description for a selected color square. -->
  <string name="label_account_color_and_type">Couleur de compte & Type</string>
  <string name="label_delete_sub_accounts">Supprimer les sous-comptes</string>
  <string name="title_recent_accounts">Récent</string>
  <string name="title_favorite_accounts">Favoris</string>
  <string name="title_all_accounts">Tous</string>
  <string name="summary_create_default_accounts">Crée une structure de compte GnuCash par défaut couramment utilisé</string>
  <string name="title_create_default_accounts">Crée comptes par défaut</string>
  <string name="msg_confirm_create_default_accounts_setting">A new book will be opened with the default accounts\n\nYour current accounts and transactions will not be modified!</string>
  <string name="menu_scheduled_transactions">Transactions planifiées</string>
  <string name="msg_confirm_create_default_accounts_first_run">Bienvenue sur GnuCash Android!\nVous pouvez soit créer
		une hiérarchie de comptes couramment utilisés, importer votre propre structure de compte GnuCash.\n\nLes deux options sont également
		disponibles dans les paramètres de l\'application de sorte que vous puissiez décider plus tard.</string>
  <string name="title_scheduled_transactions">Transactions planifiées</string>
  <string name="title_select_export_destination">Selectionnez une destination pour l\'export</string>
  <string name="hint_split_memo">Memo</string>
  <string name="label_spend">Dépense</string>
  <string name="label_receive">Reçu</string>
  <string name="label_withdrawal">Retrait</string>
  <string name="label_deposit">Dépôt</string>
  <string name="label_payment">Paiement</string>
  <string name="label_charge">Charge</string>
  <string name="label_decrease">Diminuer</string>
  <string name="label_increase">Augmenter</string>
  <string name="label_income">Revenu</string>
  <string name="label_rebate">Remboursement</string>
  <string name="label_expense">Frais</string>
  <string name="label_bill">Note</string>
  <string name="label_invoice">Facture</string>
  <string name="label_buy">Achat</string>
  <string name="label_sell">Vente</string>
  <string name="label_repeats">Répétitions</string>
  <string name="toast_no_recent_backup">Aucune sauvegarde récente trouvée</string>
  <string name="account_name_opening_balances">Soldes initiaux</string>
  <string name="account_name_equity">Capitaux propres</string>
  <string name="summary_save_opening_balances">Permet d\'enregistrer le solde du compte courant (avant la suppression des transactions) comme le nouveau solde d\'ouverture après la suppression des transactions
    </string>
  <string name="title_save_opening_balances">Enregistrer les soldes des comptes d\'ouverture</string>
  <string name="export_warning_ofx">OFX ne support pas les transactions à double entrée</string>
  <string name="export_warning_qif">Génère un fichier QIF par monnaies</string>
  <string name="title_transaction_splits">Scissions de transaction</string>
  <string name="label_imbalance">Déséquilibre :</string>
  <string name="btn_add_split">Ajouter scission</string>
  <string name="menu_title_favorite">Favori</string>
  <string name="drawer_open">Panneau de navigation ouvert</string>
  <string name="drawer_close">Panneau de navigation fermé</string>
  <string name="title_reports">Rapports</string>
  <string name="title_pie_chart">Diagramme Circulaire</string>
  <string name="title_line_chart">Graphique linéaire</string>
  <string name="title_bar_chart">Histogramme</string>
  <string name="title_report_prefs">Préférences Rapport</string>
  <string name="label_report_currency">Sélectionnez la monnaie</string>
  <string name="title_use_account_color">Couleur du compte dans les rapports</string>
  <string name="summary_use_account_color">Utiliser la couleur du compte dans le diagramme bandes/circulaire</string>
  <string name="header_report_settings">Rapports</string>
  <string name="menu_order_by_size">Tri par taille</string>
  <string name="menu_toggle_legend">Show legend</string>
  <string name="menu_toggle_labels">Show labels</string>
  <string name="menu_toggle_percentage_mode">Montrer pourcentage</string>
  <string name="menu_toggle_average_lines">Show average lines</string>
  <string name="menu_group_smaller_slices">Groupe par petites tranches</string>
  <string name="label_chart_no_data">Aucune données de graphe disponible</string>
  <string name="label_chart_overall">Global</string>
  <string name="label_chart_total">Total</string>
  <string name="label_other_slice">Autre</string>
  <string name="toast_chart_percentage_mode_total">Le pourcentage de la valeur choisie, calculée à partir de la quantité totale</string>
  <string name="toast_chart_percentage_mode_current_bar">Le pourcentage de la valeur choisie, calculée à partir de la quantité depuis le montant de la somme des barres</string>
  <string name="label_save_template">Sauvegarder comme modèle</string>
  <string name="label_delete_account_transactions_description">Ce compte contient des transactions.\nQue voudriez-vous faire avec ces opérations</string>
  <string name="label_delete_account_subaccounts_description">Ce compte contient des transactions.\nQue voudriez-vous faire avec ces sous-comptes</string>
  <string name="label_delete_transactions">Supprimer transactions</string>
  <string name="toast_disable_double_entry_to_save_transaction">Créer et spécifier un compte de transfert OU désactiver les doubles entrées dans les paramètres pour enregistrer la transaction</string>
  <string name="label_tap_to_create_schedule">Appuyez sur pour créer le calendrier</string>
  <string name="title_restore_backup">Restaurer Sauvegarde…</string>
  <string name="header_backup_and_export_settings">Sauvegarde & export</string>
  <string name="title_dropbox_sync_preference">Activer DropBox</string>
  <string name="title_owncloud_sync_preference">Activer ownCloud </string>
  <string name="title_backup_preference_category">Sauvegarde</string>
  <string name="summary_dropbox_sync">Activer export vers DropBox</string>
  <string name="summary_owncloud_sync">Activer export vers owncloud</string>
  <string name="title_select_gnucash_xml_file">Selectionner un fichier GnuCash XML</string>
  <string name="title_backup_prefs">Sauvergarde Préférences</string>
  <string name="title_create_backup_pref">Créer Sauvegarde</string>
  <string name="summary_create_backup_pref">Par défaut les sauvegardes sont sauvegardées sur la carte SD</string>
  <string name="summary_restore_backup_pref">Sélectionner une sauvegarde spécifique à restaurer</string>
  <string name="toast_backup_successful">Sauvegarde réussie</string>
  <string name="toast_backup_failed">Échec de la sauvegarde</string>
  <string name="export_warning_xml">Exporte tous les comptes et les transactions</string>
  <string name="title_google_drive_sync_pref">Activer Google Drive</string>
  <string name="summary_google_drive_sync">Activer export vers Google Drive</string>
  <string name="toast_install_file_manager">Installez un gestionnaire de fichiers pour sélectionner les fichiers</string>
  <string name="title_select_backup_to_restore">Sélectionnez une sauvegarde à restaurer</string>
  <string name="nav_menu_favorites">Favoris</string>
  <string name="nav_menu_open">Ouvrir…</string>
  <string name="nav_menu_reports">Rapports</string>
  <string name="nav_menu_scheduled_transactions">Transactions planifiées</string>
  <string name="nav_menu_export">Export…</string>
  <string name="nav_menu_settings">Paramètres</string>
  <string name="username">Nom d\'utilisateur</string>
  <string name="password">Mot de passe</string>
  <string name="owncloud_pref">ownCloud</string>
  <string name="owncloud_server">https://</string>
  <string name="owncloud_server_invalid">Serveur OC inaccessible</string>
  <string name="owncloud_user_invalid">OC username/password invalid</string>
  <string name="owncloud_dir_invalid">Invalid chars: \\ < > : \" | * ? </string>
  <string name="owncloud_server_ok">OC server OK</string>
  <string name="owncloud_user_ok">OC username/password OK</string>
  <string name="owncloud_dir_ok">Dir name OK</string>
  <plurals name="label_every_x_days">
    <item quantity="one">Journalier</item>
    <item quantity="other">Tous les %d jours</item>
  </plurals>
  <plurals name="label_every_x_weeks">
    <item quantity="one">Hebdomadaire</item>
    <item quantity="other">Tous les %d semaines</item>
  </plurals>
  <plurals name="label_every_x_months">
    <item quantity="one">Mensuel</item>
    <item quantity="other">Tous les %d mois</item>
  </plurals>
  <plurals name="label_every_x_years">
    <item quantity="one">Annuel</item>
    <item quantity="other">Tous les %d ans</item>
  </plurals>
  <string name="title_enable_crashlytics">Activer le rapport de crash</string>
  <string name="msg_enable_crashlytics">Activer pour envoyer aux développeurs d\'amélioration des informations sur les dysfonctionnements (recommandé).
Aucune information permettant d\'identifier l\'utilisateur ne sera recueillis dans le cadre de ce processus!
    </string>
  <string name="label_export_format">Format</string>
  <string name="toast_backup_folder_not_found">Le répertoire de sauvegarde non trouvé. Vérifiez la carte SD !</string>
  <string name="label_old_passcode">Entrez votre ancien mot de passe</string>
  <string name="label_new_passcode">Entrez votre nouveau code</string>
  <string name="nav_menu_scheduled_backups">Exports planifiés</string>
  <string name="title_scheduled_exports">Exports planifiés</string>
  <string name="label_no_scheduled_exports_to_display">Pas d\'exports planifiés à afficher</string>
  <string name="title_create_export_schedule">Créer un export planifié</string>
  <string name="toast_exported_to">Exporté vers : %1$s</string>
  <string name="toast_legend_too_long">La légende est trop longue</string>
  <string name="hint_account_description">Description du compte</string>
  <string name="label_no_recent_accounts">Aucun comptes récents</string>
  <string name="label_no_favorite_accounts">Aucun comptes favoris</string>
  <string name="nav_menu_scheduled_actions">Actions prévues</string>
  <string name="label_scheduled_action_ended">"Fini, dernière exécution le "</string>
  <string name="label_select_bar_to_view_details">Select a bar to view details</string>
  <string name="btn_wizard_next">Suivant</string>
  <string name="btn_wizard_finish">Terminer</string>
  <string name="wizard_title_default_currency">Monnaie par défaut</string>
  <string name="wizard_title_account_setup">Configuration du Compte</string>
  <string name="wizard_title_select_currency">Sélectionner Monnaie</string>
  <string name="wizard_title_feedback_options">Feedback Options</string>
  <string name="wizard_option_create_default_accounts">Créer des comptes par défaut</string>
  <string name="wizard_option_import_my_accounts">Importer mes comptes</string>
  <string name="wizard_option_let_me_handle_it">Me laisser gérer</string>
  <string name="wizard_option_currency_other">Autre…</string>
  <string name="wizard_option_auto_send_crash_reports">Envoyer automatiquement les rapports de crashs</string>
  <string name="wizard_option_disable_crash_reports">Désactiver les rapports de crashs</string>
  <string name="wizard_btn_back">Retour</string>
  <string name="title_setup_gnucash">Configuration GnuCash</string>
  <string name="wizard_title_welcome_to_gnucash">Bienvenue dans GnuCash</string>
  <string name="msg_wizard_welcome_page">Avant de continuer,\n commencez par configurer quelques options\nPour continuer, appuez sur Suivant</string>
  <string name="title_split_editor">Editeur de découpage</string>
  <string name="toast_error_check_split_amounts">Vérifiez que chaque découpe aient un montant valide avant de sauvgarder!</string>
  <string name="label_error_invalid_expression">Expression invalide!</string>
  <string name="toast_scheduled_recurring_transaction">Transaction planifiée</string>
  <string name="error_exchange_rate_required">Un taux de change est requis</string>
  <string name="error_converted_amount_required">Le montant converti est requis</string>
  <string name="title_transfer_funds">Transfert de Fonds</string>
  <string name="nav_menu_help"><![CDATA[Aide & Feedback]]></string>
  <string name="label_select_pie_slice_to_see_details">Sélectionnez une tranche pour voir les détails</string>
  <string name="label_report_period">Période:</string>
  <string name="label_convert_from">De:</string>
  <string name="label_convert_to">Vers:</string>
  <string name="msg_provide_exchange_rate">Fournissez le montant converti ou le taux de change pour transférer des fonds</string>
  <string name="hint_exchange_rate">Taux de change</string>
  <string name="btn_fetch_quote">Fetch quote</string>
  <string name="hint_converted_amount">Montant converti</string>
  <string name="title_report_sheet">Feuille</string>
  <string name="label_last_3_months_expenses">Dépenses des 3 derniers mois</string>
  <string name="label_total_assets">Actifs Total</string>
  <string name="label_total_liabilities">Dettes Total</string>
  <string name="label_net_worth">Valeur Nette</string>
  <string name="label_assets">Assets</string>
  <string name="label_liabilities">Dettes</string>
  <string name="label_equity">Capitaux propres</string>
  <string name="label_total_liabilities_and_equity"><![CDATA[Total Dettes & Capitaux propres]]></string>
  <string name="label_move_to">Déplacer vers:</string>
  <string name="menu_group_by">Grouper par</string>
  <string name="menu_group_by_month">Mois</string>
  <string name="menu_group_by_quarter">Trimestre</string>
  <string name="menu_group_by_year">Année</string>
  <string name="title_balance_sheet_report">Bilans</string>
  <string name="label_balance_sheet_total">Total:</string>
  <string name="title_google_plus_community">Google+ Community</string>
  <string name="title_translate_gnucash">Translate GnuCash</string>
  <string name="summary_google_plus">Share ideas, discuss changes or report problems</string>
  <string name="summary_translate_gnucash">Translate or proof-read on CrowdIn</string>
  <string name="toast_no_compatible_apps_to_receive_export">No compatible apps to receive the exported transactions!</string>
  <string name="menu_move_transaction">Move…</string>
  <string name="menu_duplicate_transaction">Duplicate</string>
  <string name="nav_menu_budgets">Budgets</string>
  <string name="title_cash_flow_report">Cash Flow</string>
  <string name="title_budgets">Budgets</string>
  <string name="title_use_compact_list">Enable compact view</string>
  <string name="summary_use_compact_list">Enable to always use compact view for transactions list</string>
  <string name="error_invalid_exchange_rate">Invalid exchange rate</string>
  <string name="sample_exchange_rate">e.g. 1 %1$s = x.xx %2$s</string>
  <string name="error_invalid_amount">Invalid amount</string>
  <string-array name="report_time_range">
    <item>Mois actuel</item>
    <item>3 derniers mois</item>
    <item>6 derniers mois</item>
    <item>12 derniers mois</item>
    <item>Tout le temps</item>
    <item>Période…</item>
  </string-array>
  <!-- Passcode lock -->
  <string name="digit_one">1</string>
  <!-- In the English locale, digit 1 has no text on it. This is simply empty space. If your locale has text on digit 1, then translate-->
  <string name="digit_one_text"></string>
  <string name="digit_two">2</string>
  <string name="digit_two_text">ABC</string>
  <string name="digit_three">3</string>
  <string name="digit_three_text">DEF</string>
  <string name="digit_four">4</string>
  <string name="digit_four_text">GHI</string>
  <string name="digit_five">5</string>
  <string name="digit_five_text">JKL</string>
  <string name="digit_six">6</string>
  <string name="digit_six_text">MNO</string>
  <string name="digit_seven">7</string>
  <string name="digit_seven_text">PQRS</string>
  <string name="digit_eight">8</string>
  <string name="digit_eight_text">TUV</string>
  <string name="digit_nine">9</string>
  <string name="digit_nine_text">WXYZ</string>
  <string name="digit_zero">0</string>
  <string name="digit_zero_text">+</string>
  <string name="title_manage_books">Manage Books</string>
  <string name="menu_manage_books">Manage Books…</string>
  <string name="select_chart_to_view_details">Select any part of the chart to view details</string>
  <string name="title_confirm_delete_book">Confirm delete Book</string>
  <string name="msg_all_book_data_will_be_deleted">All accounts and transactions in this book will be deleted!</string>
  <string name="btn_delete_book">Delete Book</string>
  <string name="label_last_export_time">Last Exported:</string>
  <string name="menu_title_enable_sync">Enable Sync</string>
  <string name="menu_title_new_book">New Book</string>
  <string name="toast_transaction_has_no_splits_and_cannot_open">The selected transaction has no splits and cannot be opened</string>
  <string name="label_split_count">%1$d splits</string>
  <string name="label_inside_account_with_name">in %1$s</string>
  <plurals name="book_account_stats">
    <item quantity="one">%d account</item>
    <item quantity="other">%d accounts</item>
  </plurals>
  <plurals name="book_transaction_stats">
    <item quantity="one">%d transaction</item>
    <item quantity="other">%d transactions</item>
  </plurals>
  <string-array name="report_account_types">
    <item>EXPENSE</item>
    <item>INCOME</item>
  </string-array>
  <string name="toast_connected_to_google_drive">Connected to Google Drive</string>
  <string name="toast_unable_to_connect_to_google_drive">Unable to connect to Google Drive</string>
  <string name="toast_enter_amount_to_split">Please enter an amount to split</string>
  <string name="label_export_target_external_service">external service</string>
  <string name="toast_updated_transaction_recurring_schedule">Updated transaction recurring schedule</string>
  <string name="label_export_transactions_since_date">Since</string>
  <string name="switch_export_transactions_from_all_time">All time</string>
  <string name="label_recommend_app">Recommend in Play Store</string>
  <string name="repeat_until_date">until %1$s</string>
  <string name="repeat_on_weekday">on %1$s</string>
  <string name="repeat_x_times">for %1$s times</string>
  <string name="menu_show_compact_view">Compact View</string>
  <string name="book_default_name">Book %1$d</string>
</resources>


text:
	document.getElementById('qrcode').addEventListener('click', function() {
    this.href = document.getElementById("script").toDataURL();
    this.download = 'test.png';
}

redpajama_set_name: RedPajamaGithub


text:
package com.emuneee.nctrafficcams.common;

import android.annotation.SuppressLint;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;

/**
 * Handles common conversions
 *
 * @author Evan
 *
 */
@SuppressLint("SimpleDateFormat")
public class ConversionUtils {
	public final static double MILES_PER_METER = 0.000621371;
	public final static String DATE_FORMAT = "MM/dd hh:mm:ss aaa";
	public final static String ISO_DATE_FORMAT = "yyyy-MM-dd'T'HH:mm:ss.S'Z'";
	/**
	 * Converts milliseconds to a proper time
	 *
	 * @param milliseconds
	 *            time to convert
	 * @return time in the following format, MM/dd hh:mm aaa (ex. 8:45 PM)
	 */
	public static String getDateFromMS(long milliseconds) {
		// Create a DateFormatter object for displaying date in specified
		// format.
		SimpleDateFormat formatter = new SimpleDateFormat(DATE_FORMAT);

		// Create a calendar object that will convert the date and time value in
		// milliseconds to date.
		Calendar calendar = Calendar.getInstance();
		calendar.setTimeInMillis(milliseconds);
		return formatter.format(calendar.getTime()).trim();
	}

	public static Date parseDate(String dateText, String dateFormat) throws ParseException {
		SimpleDateFormat formatter = new SimpleDateFormat(dateFormat);

		Date date = formatter.parse(dateText);

		return date;
	}

	public static double metersToMiles(double meters) {
		double miles = meters * MILES_PER_METER;
		return miles;
	}
}


text:
---
sidebar_label: Working with Silent Renew
sidebar_position: 12
---

# Working with Silent Renew

The tokens can be renewed in two ways:

1. Using silent renew with refresh tokens or
2. Using silent renew with iframes.

Both of these approaches are not perfect and bring some disadvantages. The security best practices for the renew process should be applied as much as possible. See the latest OAuth specs, drafts and recommendations for further information.

## Silent Renew Code Flow with PKCE using refresh tokens

For session renewal with the PKCE flow, no iframes are used by default. Instead, a refresh token is used to obtain a new access token from the auth server. Thus, the renewal only needs to be configured in the app module. Some servers require the `offline_access` scope for this to work which is defined in the OIDC specifications. Other servers do not require this.

Refresh tokens should be rotated and the refresh token should be revoked on a logout using the revocation endpoint.

## Silent Renew Code Flow with PKCE using refresh tokens and no id_token returned in the refresh

When an identity provider does not return an id_token in the refresh, the nonce cannot be validated in the id_token as it is not returned and needs to be deactivated. The following configuration should work for servers not returning an id_token in the refresh.

```typescript
import { NgModule } from '@angular/core';
import { AuthModule, LogLevel } from 'angular-auth-oidc-client';

@NgModule({
  imports: [
    AuthModule.forRoot({
      config: {
        authority: '--idp--',
        redirectUrl: window.location.origin,
        postLogoutRedirectUri: window.location.origin,
        clientId: '--client_id--',
        scope: 'openid profile offline_access',
        responseType: 'code',
        silentRenew: true,
        useRefreshToken: true,
        ignoreNonceAfterRefresh: true, // this is required if the id_token is not returned
        triggerRefreshWhenIdTokenExpired: false, // required when refreshing the browser if id_token is not updated after the first authentication
        // allowUnsafeReuseRefreshToken: true, // this is required if the refresh token is not rotated
        autoUserInfo: false, // if the user endpoint is not supported
        logLevel: LogLevel.Debug,
      },
    }),
  ],
  exports: [AuthModule],
})
export class AuthConfigModule {}
```

## Silent Renew (iframe)

When silent renew is enabled, a DOM event will automatically be installed in the application's host window. The event `oidc-silent-renew-message` accepts a `CustomEvent` instance with the token returned from the OAuth server in its `detail` field. The event handler will send this token to the authorization callback and complete the validation.

Point the `silent_renew_url` property to an HTML file which contains the following script element to enable authorization.

The `renewTimeBeforeTokenExpiresInSeconds` property can be used to start the renew process n-seconds before the tokens expired.

Both the access token and the id_token are used to start this process.

### Silent Renew Code Flow with PKCE (iframe)

```javascript
<script>
window.onload = function () {
  /* The parent window hosts the Angular application */
  const parent = window.parent;
  /* Send the id_token information to the oidc message handler */
  const event = new CustomEvent('oidc-silent-renew-message', { detail: window.location });
  parent.dispatchEvent(event);
};
</script>
```

If you are working with the [Angular CLI](https://angular.io/cli) make sure you add the `silent-renew.html` file to the assets configuration in your `angular.json`. This has already been done for you if you used the `ng add` schematics to install and setup the library.

```json
"assets": [
  "projects/<your-project-here>/src/silent-renew.html",
],
```

### Silent Renew Implicit Flow (iframe)

```javascript
<script>
window.onload = function () {
  /* The parent window hosts the Angular application */
  const parent = window.parent;
  /* Send the id_token information to the oidc message handler */
  const event = new CustomEvent('oidc-silent-renew-message', { detail: window.location.hash.substr(1) });
  parent.dispatchEvent(event);
};
</script>
```

## Security Token Service CSP and CORS

When silent renew is enabled, the lib will attempt to perform a renew before returning the authorization state.
This allows the application to authorize a user, that is already authenticated, without performing redirects.

Silent renew requires CSP configuration on the server to allow iframes and also CORS.


text:
"""
Split ratings.dat into a total of three files, as follows:

From the set of all ratings, divide the set into two files:

* ratings_training.dat

* ratings_test.dat

The ratings are divided by taking approximately 20 percent of a given user's
ratings for testing, and the rest go to training, using random sampling.

Thus, all users should have ratings in both ``ratings_training.dat`` and
``ratings_test.dat``.

Since the training data set is quite large, a smaller file ``ratings_dev.dat``
is created by taking a random sample comprising 20 percent of the user
population, and copying all of the sample population's ratings to
``ratings_dev.dat``. Thus, not all users are represented in
``ratings_dev.dat``, and no rating contained in ``ratings_test.dat`` is
included in any other dataset.
"""

import random
import os

DEV_SAMPLE_SIZE = 200

DIR = os.path.dirname(os.path.abspath(__file__))

def split_ratings():
    """
    For each user, save 20 percent of their ratings to the test dataset.
    """
    test_count = 0
    training_count = 0
    dev_count = 0

    user_ratings = {}  # all ratings, keyed by user
    movie_ratings = {}  # ratings in training dataset, keyed by movie id
    movies = {}  # movie info, keyed by movie id

    # Divide ratings.dat into training and test datasets

    with open(os.path.join(DIR, 'ratings.dat'), 'r') as ratingsfile:
        for line in ratingsfile.readlines():
            user_id = line.split("::", 1)[0]
            if user_id not in user_ratings:
                user_ratings[user_id] = [line]
            else:
                user_ratings[user_id].append(line)

    with open(os.path.join(DIR, 'ratings_test.dat'), 'w') as test_ratings_file:
        with open(os.path.join(DIR, 'ratings_training.dat'), 'w') as training_ratings_file:
            for user in user_ratings.keys():
                ratings = user_ratings[user]
                num_ratings = len(ratings) / 5
                test_data = random.sample(ratings, num_ratings)
                test_data = set(test_data)
                ratings = set(ratings)
                training_data = ratings.difference(test_data)

                for rating in test_data:
                    test_ratings_file.write(rating)
                    test_count += 1

                for rating in training_data:
                    training_ratings_file.write(rating)
                    movie_id = rating.split('::', 2)[1]
                    if movie_id not in movie_ratings:
                        movie_ratings[movie_id] = [rating]
                    else:
                        movie_ratings[movie_id].append(rating)
                    training_count += 1

    # Load all movie data into memory
    with open(os.path.join(DIR, 'movies.dat'), 'r') as movies_file:
        for movie in movies_file:
            movie_id = movie.split('::')[0]
            movies[movie_id] = movie

    # Write out a sample set of movies for development use.
    with open(os.path.join(DIR, 'movies_dev.dat'), 'w') as movies_dev_file:
        with open(os.path.join(DIR, 'ratings_dev.dat'), 'w') as ratings_dev_file:
            sample_movies = random.sample(movies.keys(), DEV_SAMPLE_SIZE)
            for movie_id in sample_movies:
                movies_dev_file.write(movies[movie_id])

                if movie_id in movie_ratings:
                    for rating in movie_ratings[movie_id]:
                        ratings_dev_file.write(rating)
                        dev_count += 1

    print("Added {0} ratings to ratings_test.dat".format(test_count))
    print("Added {0} ratings to ratings_training.dat".format(training_count))
    print("Added {0} ratings to ratings_dev.dat".format(dev_count))

if __name__ == '__main__':
    split_ratings()


text:
require 'spec_helper'

describe "MergeRequests" do
  let(:project) { Factory :project }

  before do
    login_as :user
    project.add_access(@user, :read, :write)
    MergeRequest.observers.enable 'GitlabEngine::ActivityObserver' do
      @merge_request = Factory(:merge_request,
                               :author => @user,
                               :assignee => @user,
                               :project => project)
    end
  end

  describe "GET /merge_requests" do
    before do
      visit project_merge_requests_path(project)
    end

    subject { page }

    it { should have_content(@merge_request.title[0..10]) }
    it { should have_content(@merge_request.target_branch) }
    it { should have_content(@merge_request.source_branch) }
    it { should have_content(@merge_request.assignee.name) }
  end

  describe "GET /merge_request/:id" do
    before do
      visit project_merge_request_path(project, @merge_request)
    end

    subject { page }

    it { should have_content(@merge_request.title[0..10]) }
    it { should have_content(@merge_request.target_branch) }
    it { should have_content(@merge_request.source_branch) }
    it { should have_content(@merge_request.assignee.name) }

    describe "Close merge request" do
      before { click_link "Close" }

      it { should have_content(@merge_request.title[0..10]) }
      it "Show page should inform user that merge request closed" do
        page.should have_content "Closed"
      end
    end
  end

  describe "GET /merge_requests/new" do
    before do
      visit new_project_merge_request_path(project)
      fill_in "merge_request_title", :with => "Merge Request Title"
      select "master", :from => "merge_request_source_branch"
      select "test", :from => "merge_request_target_branch"
      select @user.name, :from => "merge_request_assignee_id"
      click_button "Save"
    end

    it { current_path.should == project_merge_request_path(project, project.merge_requests.last) }

    it "should create merge request" do
      page.should have_content "Close"
      page.should have_content @user.name
    end
  end
end


text:
using System;
using System.Collections;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Windows.Forms;
using System.Diagnostics;
using AnimatGuiCtrls.Collections;

namespace AnimatGuiCtrls.Controls
{
	#region Enumerations

	public enum enumOrientation
	{
		orHorizontal = 0,
		orVertical = 1
	}

	public enum enumScaleMode
	{
		smPoints = 0,
		smPixels = 1,
		smCentimetres = 2,
		smInches = 3
	}

	public enum enumRulerAlignment
	{
		raTopOrLeft,
		raMiddle,
		raBottomOrRight
	}

	public enum enumTimeScale
	{
		MilliSeconds = 0,
		Seconds = 1,
		Minutes = 2,
		Hours = 3
	}

	internal enum Msg
	{
		WM_MOUSEMOVE              = 0x0200,
		WM_MOUSELEAVE             = 0x02A3,
		WM_NCMOUSELEAVE           = 0x02A2,
	}

	#endregion

	/// <summary>
	/// Summary description for TimeRuler.
	/// </summary>
	[ToolboxItem(true)]
	[ToolboxBitmap(typeof(TimeRuler), "Ruler.bmp")]
	public class TimeRuler : System.Windows.Forms.Control, IMessageFilter
	{

		#region Internal Variables

		private float					_Scale;
		private int					_ScaleStartValue;
		private bool				_bDrawLine = false;
		//private bool				_bInControl = false;
		private int					_iMousePosition	= 1;
		private int					_iOldMousePosition = -1;
		private Bitmap				_Bitmap = null;
		private long				_lStartMillisecond = 0;
		private long				_lEndMillisecond = 10000;
		private long				_lCurrentMillisecond = 0;
		private long				_lActualMillisecond = 0;
		private int					_iProgressBarScale = 40;
		private int					_iHeaderOffset = 15;
		private int					_iSideOffset = 5;
		private enumTimeScale		_TimeScale = enumTimeScale.MilliSeconds;
		private bool				_bAutomaticTimeScale = true;
		private bool				_bAutomaticOrientation = true;
		private int[]				_aryIntervals = new int[16] { 1, 2, 5, 10, 20, 50, 100, 200, 500, 1000, 2000, 5000, 10000, 20000, 50000, 100000 };

		protected KeyFrameCollection _aryKeyFrames;

		private bool				_bInsideDraw						= false;
		private KeyFrame		_MovingFrame						= null;
		private KeyFrame		_CurrentFrame						= null;
		private KeyFrame		_SelectedFrame						= null;

		private int					_iDisplaySize						= 0;

		private bool				_bAllowKeyFrameSelection				= true;

		private System.Drawing.Color _CurrentTimeColor = Color.Blue;
		private System.Drawing.Color _ActualTimeColor = Color.LightBlue;

		#endregion

		#region Property variable

		private enumOrientation		_Orientation;
		private enumScaleMode		_ScaleMode;
		private enumRulerAlignment	_RulerAlignment     = enumRulerAlignment.raBottomOrRight;
		private Border3DStyle		_i3DBorderStyle     = Border3DStyle.Etched;
		private int					_iMajorInterval     = 100;
		private int					_iNumberOfDivisions = 10;
		private int					_DivisionMarkFactor = 4;
		private int					_MiddleMarkFactor	= 3;
		private double				_ZoomFactor         = 1;
		private double				_StartValue			= 0;
		private bool				_bMouseTrackingOn   = false;
		private bool				_VerticalNumbers	= true;

		#endregion

		#region Event Arguments

		public class ScaleModeChangedEventArgs : EventArgs
		{
			public enumScaleMode Mode;

			public ScaleModeChangedEventArgs(enumScaleMode Mode) : base()
			{
				this.Mode = Mode;
			}
		}

		public class HooverValueEventArgs : EventArgs
		{
			public double Value;

			public HooverValueEventArgs(double Value) : base()
			{
				this.Value = Value;
			}
		}

		public class KeyFrameEventArgs : EventArgs
		{
			public KeyFrame SelectedKeyFrame;

			public KeyFrameEventArgs(KeyFrame Frame) : base()
			{
				this.SelectedKeyFrame = Frame;
			}
		}

		#endregion

		#region Delegates

		public delegate void ScaleModeChangedEvent(object sender, ScaleModeChangedEventArgs e);
		public delegate void HooverValueEvent(object sender, HooverValueEventArgs e);
		public delegate void KeyFrameSelectedEvent(object sender, KeyFrameEventArgs e);
		public delegate void KeyFrameAddedEvent(object sender, KeyFrameEventArgs e);
		public delegate void KeyFrameRemovedEvent(object sender, KeyFrameEventArgs e);
		public delegate void KeyFrameMovedEvent(object sender, KeyFrameEventArgs e);
		public delegate void KeyFrameMovingEvent(object sender, KeyFrameEventArgs e);
		public delegate void CurrentFrameMovedEvent(object sender, KeyFrameEventArgs e);

		#endregion

		#region Events

		public event ScaleModeChangedEvent ScaleModeChanged;
		public event HooverValueEvent HooverValue;
		public event KeyFrameSelectedEvent KeyFrameSelected;
		public event KeyFrameAddedEvent KeyFrameAdded;
		public event KeyFrameRemovedEvent KeyFrameRemoved;
		public event KeyFrameMovedEvent KeyFrameMoved;
		public event KeyFrameMovingEvent KeyFrameMoving;
		public event CurrentFrameMovedEvent CurrentFrameMoved;

		#endregion

		/// <summary>
		/// Required designer variable.
		/// </summary>
		private System.ComponentModel.Container components = null;

		#region Constrcutors/Destructors

		public TimeRuler()
		{
			base.BackColor = System.Drawing.Color.White;
			base.ForeColor = System.Drawing.Color.Black;

			// This call is required by the Windows.Forms Form Designer.
			InitializeComponent();

			_aryKeyFrames = new KeyFrameCollection(this);
			ScaleMode = enumScaleMode.smPixels;

		}

		#endregion

		#region Methods

		private Point GetMousePosition()
		{
			int X = 0;
			int Y = 0;

			Point pointScreen = Control.MousePosition;
			Point pointClientOrigin = new Point(X, Y);
			pointClientOrigin = PointToScreen(pointClientOrigin);

			Point p = new Point( (pointScreen.X-pointClientOrigin.X), (pointScreen.Y-pointClientOrigin.Y) );
			return p;
		}

		[EditorBrowsable(EditorBrowsableState.Never)]
		public bool PreFilterMessage(ref Message m)
		{
			return false;
		}

//		[EditorBrowsable(EditorBrowsableState.Never)]
//		public bool PreFilterMessage(ref Message m)
//		{
//			if (!this._bMouseTrackingOn) return false;
//
//			if (m.Msg == (int)Msg.WM_MOUSEMOVE)
//			{
//				int X = 0;
//				int Y = 0;
//
//				// The mouse coordinate are measured in screen coordinates because thats what
//				// Control.MousePosition returns.  The Message,LParam value is not used because
//				// it returns the mouse position relative to the control the mouse is over.
//				// Chalk and cheese.
//
//				Point pointScreen = Control.MousePosition;
//
//				// Get the origin of this control in screen coordinates so that later we can
//				// compare it against the mouse point to determine it we've hit this control.
//
//				Point pointClientOrigin = new Point(X, Y);
//				pointClientOrigin = PointToScreen(pointClientOrigin);
//
//				// ...workout the position of the mouse relative to the
//				X = pointScreen.X-pointClientOrigin.X;
//				Y = pointScreen.Y-pointClientOrigin.Y;
//				//Debug.WriteLine("MousePos: (" + X.ToString() + ", " + Y.ToString() + ") Position: " + CalculateMillisecondValue(_iMousePosition).ToString());
//
//				// Determine whether the mouse is within the bounds of the control itself
//				_bInControl = (this.ClientRectangle.Contains(new Point(X, Y)));
//
//				//Only do this stuff if the mouse is inside this control.
//				if(_bInControl)
//				{
//					_bDrawLine = false;
//					_bInControl = false;
//
//					HooverValueEventArgs eHoover = null;
//
//					// Work out whether the mouse is within the Y-axis bounds of a vertital ruler or
//					// within the X-axis bounds of a horizontal ruler
//
//					_bDrawLine = (pointScreen.X >= (pointClientOrigin.X + _iSideOffset)) &&
//						(pointScreen.X <= (pointClientOrigin.X + _iSideOffset + _iDisplaySize)) &&
//						(pointScreen.Y >= (pointClientOrigin.Y + _iSideOffset)) &&
//						(pointScreen.Y <= (pointClientOrigin.Y + _iSideOffset + _iDisplaySize));
//
//					// If the mouse is in valid position...
//					if (_bDrawLine)
//					{
//						// Make the relative mouse position available in pixel relative to this control's origin
//						ChangeMousePosition((this.Orientation == enumOrientation.orHorizontal) ? X : Y);
//						eHoover = new HooverValueEventArgs(CalculateMillisecondValue(_iMousePosition));
//
//					}
//					else
//					{
//						//Debug.WriteLine("MousePos: -1");
//						ChangeMousePosition(-1);
//						eHoover = new HooverValueEventArgs(_iMousePosition);
//					}
//
//					// Paint directly by calling the OnPaint() method.  This way the background is not
//					// hosed by the call to Invalidate() so paining occurs without the hint of a flicker
//					PaintEventArgs e = null;
//					try
//					{
//						e = new PaintEventArgs(this.CreateGraphics(), this.ClientRectangle);
//						OnPaint(e);
//					}
//					finally
//					{
//						e.Graphics.Dispose();
//					}
//
//					OnHooverValue(eHoover);
//				}
//			}
//
//			if ((m.Msg == (int)Msg.WM_MOUSELEAVE) ||
//				(m.Msg == (int)Msg.WM_NCMOUSELEAVE))
//			{
//				_bDrawLine = false;
//				PaintEventArgs paintArgs = null;
//				try
//				{
//					paintArgs = new PaintEventArgs(this.CreateGraphics(), this.ClientRectangle);
//					this.OnPaint(paintArgs);
//				}
//				finally
//				{
//					paintArgs.Graphics.Dispose();
//				}
//			}
//
//			return false;  // Whether or not the message is filtered
//		}

		public double PixelToScaleValue(int iOffset)
		{
			return this.CalculateMillisecondValue(iOffset);
		}

		public int ScaleValueToPixel(double nScaleValue)
		{
			return CalculateMillisecondPixel(nScaleValue);
		}

		#endregion

		#region Component Designer generated code
		/// <summary>
		/// Required method for Designer support - do not modify
		/// the contents of this method with the code editor.
		/// </summary>
		private void InitializeComponent()
		{
			//
			// RulerControl
			//
			this.Name = "TimeRuler";
			this.MouseDown += new System.Windows.Forms.MouseEventHandler(this.RulerControl_MouseDown);
			this.MouseMove += new System.Windows.Forms.MouseEventHandler(this.RulerControl_MouseMove);
			this.MouseUp += new System.Windows.Forms.MouseEventHandler(this.RulerControl_MouseUp);
			this.DoubleClick += new System.EventHandler(this.RulerControl_DoubleClick);
		}
		#endregion

		#region Overrides

		protected override void Dispose( bool disposing )
		{
			if( disposing )
			{
				if(components != null)
				{
					components.Dispose();
				}
			}
			base.Dispose( disposing );
		}

		protected override void OnResize(EventArgs e)
		{
			base.OnResize (e);

			// Take private resize actions here
			_Bitmap = null;
			this.Invalidate();
		}

		public override void Refresh()
		{
			base.Refresh ();
			this.Invalidate();
		}

		[Description("Draws the ruler marks in the scale requested.")]
		protected override void OnPaint(PaintEventArgs e)
		{
			base.OnPaint (e);
			DrawControl(e.Graphics);
		}

		protected override void OnHandleDestroyed(EventArgs e)
		{
			base.OnHandleDestroyed (e);
			try
			{
				if (_bMouseTrackingOn) Application.RemoveMessageFilter(this);
			}
			catch {}
		}

		#endregion

		#region Event Handlers

		private void RulerControl_MouseDown(object sender, System.Windows.Forms.MouseEventArgs e)
		{
			try
			{
				//Debug.WriteLine("MouseDown: (" + e.X.ToString() + ", " + e.Y.ToString() + ")");

				if (e.Button.Equals(MouseButtons.Left) && _bAllowKeyFrameSelection)
				{
					SelectedKeyFrame = _aryKeyFrames.IsHandleClick(e);

					if(_SelectedFrame != null && _SelectedFrame.CanBeMoved(this))
					{
						_MovingFrame = _SelectedFrame;
						_MovingFrame.StartMove(e, this);
					}
				}
			}
			catch {}

		}

		private void RulerControl_MouseMove(object sender, System.Windows.Forms.MouseEventArgs e)
		{
			try
			{
				if(_MovingFrame != null)
				{
					_MovingFrame.MoveFrame(e, this);
					OnKeyFrameMoving(_MovingFrame);
				}
			}
			catch {}
		}

		private void RulerControl_MouseUp(object sender, System.Windows.Forms.MouseEventArgs e)
		{
			try
			{
				//Debug.WriteLine("MouseUp: (" + e.X.ToString() + ", " + e.Y.ToString() + ")");
				if(_MovingFrame != null)
				{
					_MovingFrame.EndMove(e, this);
					OnKeyFrameMoved(_MovingFrame);
					_MovingFrame = null;
				}
			}
			catch {}

			EventArgs eClick = new EventArgs();
			this.OnClick(eClick);
		}

		private void RulerControl_DoubleClick(object sender, System.EventArgs e)
		{

			Point pMousePos = GetMousePosition();
			if( (Control.ModifierKeys & Keys.Control) == Keys.Control )
			{
				if( (Control.ModifierKeys & Keys.Shift) == Keys.Shift )
					RemoveVideoFrame(pMousePos);
				else
					AddVideoFrame(pMousePos);
			}
			else
			{
				if( (Control.ModifierKeys & Keys.Shift) == Keys.Shift )
					RemoveKeyFrame(pMousePos);
				else
					AddKeyFrame(pMousePos);
			}

		}

		internal void OnHooverValue(HooverValueEventArgs e)
		{
			if (HooverValue != null) HooverValue(this, e);
		}

		internal void OnScaleModeChanged(ScaleModeChangedEventArgs e)
		{
			if (ScaleModeChanged != null) ScaleModeChanged(this, e);
		}

		internal void OnKeyFrameSelected(KeyFrame frameSelected)
		{
			KeyFrameEventArgs e = new KeyFrameEventArgs(frameSelected);
			if (KeyFrameSelected != null) KeyFrameSelected(this, e);
		}

		internal void OnKeyFrameAdded(KeyFrame frameSelected)
		{
			KeyFrameEventArgs e = new KeyFrameEventArgs(frameSelected);
			if (KeyFrameAdded != null) KeyFrameAdded(this, e);
		}

		internal void OnKeyFrameRemoved(KeyFrame frameSelected)
		{
			KeyFrameEventArgs e = new KeyFrameEventArgs(frameSelected);
			if (KeyFrameRemoved != null) KeyFrameRemoved(this, e);
		}

		internal void OnKeyFrameMoved(KeyFrame frameSelected)
		{
			KeyFrameEventArgs e = new KeyFrameEventArgs(frameSelected);
			if (KeyFrameMoved != null) KeyFrameMoved(this, e);
		}

		internal void OnKeyFrameMoving(KeyFrame frameSelected)
		{
			KeyFrameEventArgs e = new KeyFrameEventArgs(frameSelected);
			if (KeyFrameMoving != null) KeyFrameMoving(this, e);
		}

		internal void OnCurrentFrameMoved(KeyFrame frameSelected)
		{
			KeyFrameEventArgs e = new KeyFrameEventArgs(frameSelected);
			if (CurrentFrameMoved != null) CurrentFrameMoved(this, e);
		}

		protected override void OnEnter(EventArgs e)
		{
			base.OnEnter (e);
			_bDrawLine = false;
			Invalidate();
		}

		protected override void OnLeave(EventArgs e)
		{
			base.OnLeave (e);
			Invalidate();
		}

		private void ContextMenu_Popup(object sender, EventArgs e)
		{
			//System.Diagnostics.Debug.WriteLine("Popup");
		}

		#endregion

		#region Properties

		internal int HeaderOffset
		{
			get
			{
				return _iHeaderOffset;
			}
		}

		internal int SideOffset
		{
			get
			{
				return _iSideOffset;
			}
		}

		internal int DisplaySize
		{
			get
			{
				return _iDisplaySize;
			}
		}

		public float ScaleOut
		{
			get
			{
				return _Scale;
			}
		}

		[
		DefaultValue(typeof(Border3DStyle),"Etched"),
		Description("The border style use the Windows.Forms.Border3DStyle type"),
		Category("Ruler"),
		]
		public Border3DStyle BorderStyle
		{
			get
			{
				return _i3DBorderStyle;
			}
			set
			{
				_i3DBorderStyle = value;
				RedrawBitmap();
			}
		}

		[Description("Horizontal or vertical layout")]
		[Category("Ruler")]
		public enumOrientation Orientation
		{
			get { return _Orientation; }
			set
			{
				_Orientation = value;
				RedrawBitmap();
			}
		}

		[Description("Determines whether or not the user can select keyframes")]
		[Category("Ruler")]
		public bool AllowKeyFrameSelection
		{
			get { return _bAllowKeyFrameSelection; }
			set
			{
				_bAllowKeyFrameSelection = value;

				if(!_bAllowKeyFrameSelection)
					SelectedKeyFrame = null;
			}
		}

		[Description("The second value where the ruler should start.  Default is zero.")]
		[Category("Ruler")]
		public long StartMillisecond
		{
			get { return _lStartMillisecond; }
			set
			{
				if(value<0)
					throw new System.Exception("The starting time can not be less than zero.");

				_StartValue = (double) value;
				_lStartMillisecond = value;
				_ScaleStartValue = Convert.ToInt32(value * _Scale / _iMajorInterval);  // Convert value to pixels
				RedrawBitmap();
			}
		}

		[Description("The second value where the ruler should end.  Default is 500.")]
		[Category("Ruler")]
		public long EndMillisecond
		{
			get { return _lEndMillisecond; }
			set
			{
				if(value < 0)
					throw new System.Exception("The ending time can not be less than zero.");

				if(value < _lStartMillisecond)
					throw new System.Exception("The ending time can not be less than the starting time.");

				_lEndMillisecond = value;
				RedrawBitmap();
			}
		}

		[Description("This displays the progress bar up to this value of the current second.")]
		[Category("Ruler")]
		public long CurrentMillisecond
		{
			get { return _lCurrentMillisecond; }
			set
			{
				if(value < 0)
					throw new System.Exception("The current second can not be less than zero.");

				_lCurrentMillisecond = value;

				if(_lCurrentMillisecond > _lActualMillisecond)
					_lActualMillisecond = _lCurrentMillisecond;

				if(_CurrentFrame != null)
					_CurrentFrame.SetTimes(value, value);

				if(_lCurrentMillisecond > (_lEndMillisecond*0.7) )
					_lEndMillisecond = (long) (_lCurrentMillisecond * 1.4);

				RedrawBitmap();
			}
		}

		[Description("This gets a string display of the current time.")]
		[Category("Ruler")]
		public String CurrentTime
		{
			get
			{
				String strVal = string.Format("%4.4f",  _lCurrentMillisecond/ (float) GetMillisecondScale(_TimeScale));
				strVal+= GetTimeScaleAbbreviation(_TimeScale);
				return strVal;
			}
		}

		[Description("This is the actual value of how much time has elapsed. The current time property can be moved back into the past.")]
		[Category("Ruler")]
		public long ActualMillisecond
		{
			get { return _lActualMillisecond; }
			set
			{
				if(value < 0)
					throw new System.Exception("The current second can not be less than zero.");

				if(value < _lCurrentMillisecond)
					throw new System.Exception("The actual second can not be less than current second.");

				_lActualMillisecond = value;
				RedrawBitmap();
			}
		}

		[Description("This is the time scale that is to used to draw the ruler. It is defaulted to seconds." +
			 "If AutomaticTimeScale is true then this is the scale that is currently being used.")]
		[Category("Ruler")]
		public enumTimeScale TimeScale
		{
			get { return _TimeScale; }
			set
			{
				if(!_bAutomaticTimeScale)
				{
					_TimeScale = value;
					RedrawBitmap();
				}
			}
		}

		[Description("If this is true then the scale for the time will be automatically calculated based on the number of milliseconds.")]
		[Category("Ruler")]
		public bool AutomaticTimeScale
		{
			get { return _bAutomaticTimeScale; }
			set
			{
				_bAutomaticTimeScale = value;
			}
		}

		[Description("If this is true then the orientation of the ruler will change based on the relative ratio's of the size of the control.")]
		[Category("Ruler")]
		public bool AutomaticOrientation
		{
			get { return _bAutomaticOrientation; }
			set
			{
				_bAutomaticOrientation = value;
			}
		}

		public int MillisecondScale
		{
			get
			{return GetMillisecondScale(_TimeScale);}
		}

		[Description("This sets the color of the progress bar for the current time.")]
		[Category("Ruler")]
		public System.Drawing.Color CurrentTimeColor
		{
			get { return _CurrentTimeColor; }
			set
			{
				_CurrentTimeColor = value;
				RedrawBitmap();
			}
		}

		[Description("This sets the color of the progress bar for the actual time.")]
		[Category("Ruler")]
		public System.Drawing.Color ActualTimeColor
		{
			get { return _ActualTimeColor; }
			set
			{
				_ActualTimeColor = value;
				RedrawBitmap();
			}
		}

		[Description("This determines the percentage width of the progress bar. The default is 40%")]
		[Category("Ruler")]
		public int ProgressBarScale
		{
			get { return _iProgressBarScale; }
			set
			{
				if(value < 1)
					throw new System.Exception("The progress bar scale must be at least 1%.");
				if(value > 100)
					throw new System.Exception("The progress bar scale must be less than or equal to 100%.");

				_iProgressBarScale = value;
				RedrawBitmap();
			}
		}

		public KeyFrameCollection KeyFrames
		{
			get { return _aryKeyFrames; }

			set
			{
				_aryKeyFrames.Clear();
				_aryKeyFrames = value;
				RedrawBitmap();
			}
		}

		[Description("This is the currently selected keyframe.")]
		[Category("Ruler")]
		public KeyFrame SelectedKeyFrame
		{
			get { return _SelectedFrame; }
			set
			{
				if(_SelectedFrame != null)
				{
					_SelectedFrame.Selected = false;
					_SelectedFrame = null;
				}

				_SelectedFrame = value;

				if(_SelectedFrame != null)
					_SelectedFrame.Selected = true;

				OnKeyFrameSelected(_SelectedFrame);

				RedrawBitmap();
			}
		}

		[Description("The ruler scale to use")]
		[Category("Ruler")]
		private enumScaleMode ScaleMode
		{
			get { return _ScaleMode; }
			set
			{
				enumScaleMode iOldScaleMode = _ScaleMode;
				_ScaleMode = value;

				if (_iMajorInterval == DefaultMajorInterval(iOldScaleMode))
				{
					// Set the default Scale and MajorInterval value
					_Scale = DefaultScale(_ScaleMode);
					_iMajorInterval = DefaultMajorInterval(_ScaleMode);

				}
				else
				{
					MajorInterval = _iMajorInterval;
				}

				// Use the current start value (if there is one)
				this.StartMillisecond = (int) this._StartValue;

				ScaleModeChangedEventArgs e = new ScaleModeChangedEventArgs(value);
				this.OnScaleModeChanged(e);
			}
		}

		[Description("The value of the major interval.  When displaying inches, 1 is a typical value.  When displaying Points, 36 or 72 might good values.")]
		[Category("Ruler")]
		public int MajorInterval
		{
			get { return _iMajorInterval; }
			set
			{
				if (value <=0) throw new Exception("The major interval value cannot be less than one");
				_iMajorInterval = value;
				_Scale = ((float) DefaultScale1(_ScaleMode, _ZoomFactor) * _iMajorInterval) / DefaultMajorInterval(_ScaleMode);
				//Debug.WriteLine("DefaultScale: " + DefaultScale(_ScaleMode).ToString() + "  _iMajorInterval: " +
				//								_iMajorInterval.ToString() + "  DefaultMajorInterval: " +  DefaultMajorInterval(_ScaleMode).ToString() +
				//								"  Scale: " + _Scale.ToString());

				RedrawBitmap();
			}
		}

		[Description("How many divisions should be shown between each major interval")]
		[Category("Ruler")]
		public int Divisions
		{
			get { return _iNumberOfDivisions; }
			set
			{
				if (value <=0) throw new Exception("The number of divisions cannot be less than one");
				_iNumberOfDivisions = value;
				RedrawBitmap();
			}
		}

		[Description("The height or width of this control multiplied by the reciprocal of this number will be used to compute the height of the non-middle division marks.")]
		[Category("Ruler")]
		public int DivisionMarkFactor
		{
			get { return _DivisionMarkFactor; }
			set
			{
				if (value <=0) throw new Exception("The Division Mark Factor cannot be less than one");
				_DivisionMarkFactor = value;
				RedrawBitmap();
			}
		}

		[Description("The height or width of this control multiplied by the reciprocal of this number will be used to compute the height of the middle division mark.")]
		[Category("Ruler")]
		public int MiddleMarkFactor
		{
			get { return _MiddleMarkFactor; }
			set
			{
				if (value <=0) throw new Exception("The Middle Mark Factor cannot be less than one");
				_MiddleMarkFactor = value;
				RedrawBitmap();
			}
		}

		[Description("The value of the current mouse position expressed in unit of the scale set (centimetres, inches, etc.")]
		[Category("Ruler")]
		public double ScaleValue
		{
			get {return CalculateValue(_iMousePosition); }
		}

		[Description("true if a line is displayed to track the current position of the mouse and events are generated as the mouse moves.")]
		[Category("Ruler")]
		public bool MouseTrackingOn
		{
			get { return _bMouseTrackingOn; }
			set
			{
				if (value == _bMouseTrackingOn) return;

				if (value)
				{
					// Tracking is being enabled so add the message filter hook
					Application.AddMessageFilter(this);
				}
				else
				{
					// Tracking is being disabled so remove the message filter hook
					Application.RemoveMessageFilter(this);
					ChangeMousePosition(-1);
				}

				_bMouseTrackingOn = value;

				RedrawBitmap();
			}
		}

		[Description("The font used to display the division number")]
		public override Font Font
		{
			get
			{
				return base.Font;
			}
			set
			{
				base.Font = value;
				RedrawBitmap();
			}
		}

		[Description("Return the mouse position as number of pixels from the top or left of the control.  -1 means that the mouse is positioned before or after the control.")]
		[Category("Ruler")]
		public int MouseLocation
		{
			get { return _iMousePosition; }
		}

		[DefaultValue(typeof(Color), "ControlDarkDark")]
		[Description("The color used to lines and numbers on the ruler")]
		public override Color ForeColor
		{
			get
			{
				return base.ForeColor;
			}
			set
			{
				base.ForeColor = value;
				RedrawBitmap();
			}
		}

		[DefaultValue(typeof(Color), "White")]
		[Description("The color used to paint the background of the ruler")]
		public override Color BackColor
		{
			get
			{
				return base.BackColor;
			}
			set
			{
				base.BackColor = value;
				RedrawBitmap();
			}
		}

		[Description("")]
		[Category("Ruler")]
		public bool VerticalNumbers
		{
			get { return _VerticalNumbers; }
			set
			{
				_VerticalNumbers = value;
				RedrawBitmap();
			}
		}

		private double ZoomFactor
		{
			get { return _ZoomFactor; }
			set
			{
				//if ((value < 0) || (value > 50)) throw new Exception("Zoom factor can be between 50% and 200%");
				if (_ZoomFactor == value) return;
				_ZoomFactor = value;
				this.ScaleMode = _ScaleMode;
				RedrawBitmap();
			}
		}

		[Description("Determines how the ruler markings are displayed")]
		[Category("Ruler")]
		public enumRulerAlignment RulerAlignment
		{
			get { return _RulerAlignment; }
			set
			{
				if (_RulerAlignment == value) return;
				_RulerAlignment = value;
				RedrawBitmap();
			}
		}

		#endregion

		#region Private functions

		public void RedrawBitmap()
		{
			if(!_bInsideDraw)
			{
				_Bitmap = null;
				Invalidate();
			}
		}

		private int GetMillisecondScale(enumTimeScale timeScale)
		{
			int iScale = 1;
			switch(timeScale)
			{
				case enumTimeScale.MilliSeconds:
					iScale = 1;
					break;
				case enumTimeScale.Seconds:
					iScale = 1000;
					break;
				case enumTimeScale.Minutes:
					iScale = 60000;
					break;
				case enumTimeScale.Hours:
					iScale = 3600000;
					break;
			}
			return iScale;
		}

		private string GetTimeScaleAbbreviation(enumTimeScale timeScale)
		{
			string strText="";
			switch(timeScale)
			{
				case enumTimeScale.MilliSeconds:
					strText = "(ms)";
					break;
				case enumTimeScale.Seconds:
					strText = "(s)";
					break;
				case enumTimeScale.Minutes:
					strText = "(m)";
					break;
				case enumTimeScale.Hours:
					strText = "(h)";
					break;
			}
			return strText;
		}

		private double CalculateValue(int iOffset)
		{
			if (iOffset < 0) return 0;

			double nValue = ((double)iOffset-Start()) / (double)_Scale * (double)_iMajorInterval;
			return nValue + this._StartValue;
		}

		private long CalculateMillisecondValue(int iOffset)
		{
			double dblVal = CalculateValue(iOffset);
			dblVal = dblVal * GetMillisecondScale(this._TimeScale);
			return (long) dblVal;
		}

		[Description("May not return zero even when a -ve scale number is given as the returned value needs to allow for the border thickness")]
		private int CalculatePixel(double nScaleValue)
		{

			double nValue = nScaleValue - this._StartValue;
			if (nValue < 0) return Start();  // Start is the offset to the actual display area to allow for the border (if any)

			int iOffset = Convert.ToInt32(nValue / (double)_iMajorInterval * (double)_Scale);

			return iOffset + Start();
		}

		private int CalculateMillisecondPixel(double nScaleValue)
		{
			return CalculatePixel((double) nScaleValue/MillisecondScale);
		}

		public void RenderTrackLine(Graphics g)
		{
			if (_bMouseTrackingOn & _bDrawLine)
			{
				int iOffset = Offset();

				// Optionally render Mouse tracking line
				switch(Orientation)
				{
					case enumOrientation.orHorizontal:
						Line(g, _iMousePosition, iOffset, _iMousePosition, Height - iOffset);
						break;
					case enumOrientation.orVertical:
						Line (g, iOffset, _iMousePosition, Width - iOffset, _iMousePosition);
						break;
				}
			}
		}

		public void Clear()
		{
			_aryKeyFrames.Clear();
			ResetTime();
			RedrawBitmap();
		}

		public void ResetTime()
		{
			_lCurrentMillisecond = 0;
			_lActualMillisecond = 0;
			if(_CurrentFrame != null)
				_CurrentFrame.SetTimes(0, 0);
			RedrawBitmap();
		}

		private void RecalculateDivisions()
		{
			if(_bAutomaticTimeScale)
			{
				int iSize = (this.Orientation == enumOrientation.orHorizontal) ? Width : Height;
				int iOptimumDivisions;

				if(iSize>100)
					iOptimumDivisions = iSize/100;
				else
					iOptimumDivisions = 1;

				int iOptimumScale = iSize/iOptimumDivisions;
				int iScale=0, iDiff=0, iInterval=0;
				int iMinDiff = -1, iMinInterval = 1;

				for(int iIndex=0; iIndex<_aryIntervals.Length; iIndex++)
				{
					iInterval = _aryIntervals[iIndex];
					iScale = (DefaultScale(_ScaleMode, _ZoomFactor) * iInterval) / DefaultMajorInterval(_ScaleMode);
					iDiff = Math.Abs(iOptimumScale - iScale);

					if(iDiff < iMinDiff || iMinDiff == -1)
					{
						iMinDiff = iDiff;
						iMinInterval = iInterval;
					}
				}

				if(iMinInterval > 0) MajorInterval = iMinInterval;
				iInterval = (int) _Scale;
			}
		}

		private double CalculateZoomFactor(int iSize, enumTimeScale timeScale)
		{
			double dblZoomFactor = ((float) iSize / (float) ((float) (_lEndMillisecond - _lStartMillisecond)/GetMillisecondScale(timeScale)));
			if(dblZoomFactor > 10000) dblZoomFactor = 10000;
			if(dblZoomFactor < 0.00001) dblZoomFactor = 0.00001;
			return dblZoomFactor;
		}

		private void RecalculateTimeScale()
		{
			//Lets do the calculation for all of the possible time scales and see which one fits bets
			if(_bAutomaticTimeScale)
			{
				int iSize = (this.Orientation == enumOrientation.orHorizontal) ? Width : Height;
				int iOptimumScale = iSize/10;

				double dblZoomFactor = CalculateZoomFactor(iSize, enumTimeScale.MilliSeconds);
				int iMilliScale = DefaultScale(dblZoomFactor) / DefaultMajorInterval();
				int iMilliDiff = Math.Abs(iOptimumScale - iMilliScale);

				dblZoomFactor = CalculateZoomFactor(iSize, enumTimeScale.Seconds);
				int iSecScale = DefaultScale(dblZoomFactor) / DefaultMajorInterval();
				int iSecDiff = Math.Abs(iOptimumScale - iSecScale);

				dblZoomFactor = CalculateZoomFactor(iSize, enumTimeScale.Minutes);
				int iMinScale = DefaultScale(dblZoomFactor) / DefaultMajorInterval();
				int iMinDiff = Math.Abs(iOptimumScale - iMinScale);

				dblZoomFactor = CalculateZoomFactor(iSize, enumTimeScale.Hours);
				int iHourScale = DefaultScale(dblZoomFactor) / DefaultMajorInterval();
				int iHourDiff = Math.Abs(iOptimumScale - iHourScale);

				if( (iSecDiff < iMilliDiff) && (iSecDiff < iMinDiff) && (iSecDiff < iHourDiff) )
					_TimeScale = enumTimeScale.Seconds;
				else if( (iMinDiff < iMilliDiff) && (iMinDiff < iSecDiff) && (iMinDiff < iHourDiff) )
					_TimeScale = enumTimeScale.Minutes;
				else if( (iHourDiff < iMilliDiff) && (iHourDiff < iSecDiff) && (iHourDiff < iMinDiff) )
					_TimeScale = enumTimeScale.Hours;
				else
					_TimeScale = enumTimeScale.MilliSeconds;

				RecalculateZoom();
				RecalculateDivisions();
			}
		}

		private void RecalculateZoom()
		{
			if(_bAutomaticOrientation)
			{
				if(Height > (Width*2) && this._Orientation == enumOrientation.orHorizontal)
					this.Orientation = enumOrientation.orVertical;
				else if(Width > (Height*2) && this._Orientation == enumOrientation.orVertical)
					this.Orientation = enumOrientation.orHorizontal;
			}

			_iDisplaySize = (this.Orientation == enumOrientation.orHorizontal) ? Width : Height;
			_iDisplaySize = _iDisplaySize - (_iSideOffset* 3);

			if(_iDisplaySize > 0)
				ZoomFactor = ((float) _iDisplaySize / (float) ((float) (_lEndMillisecond - _lStartMillisecond)/MillisecondScale));
		}

		private void DrawControl(Graphics graphics)
		{
			if(this.Width == 0 || this.Height == 0)
				return;

			_bInsideDraw = true;
			Graphics g = null;

			if(_CurrentFrame == null)
			{
				_CurrentFrame = new KeyFrameCurrent(_lCurrentMillisecond);
				_aryKeyFrames.Add(_CurrentFrame, true);
			}

			RecalculateZoom();
			RecalculateTimeScale();

			if (_Bitmap == null)
			{

				//Debug.WriteLine("TimeRuler Size: (" + this.Width.ToString() + ", " + this.Height.ToString() + ")");

				// Create a bitmap
				_Bitmap = new Bitmap(this.Width, this.Height);

				g = Graphics.FromImage(_Bitmap);

				try
				{
					// Wash the background with BackColor
					//Lets wash the whole thing out with the parent back color
					g.FillRectangle(new SolidBrush(this.Parent.BackColor), 0, 0, _Bitmap.Width, _Bitmap.Height);

					//Lets only draw the ruler portion of this in the control back color.
					if (this.Orientation == enumOrientation.orHorizontal)
					{
						int iHeight = _Bitmap.Height - _iHeaderOffset;
						g.FillRectangle(new SolidBrush(this.BackColor), _iSideOffset, _iHeaderOffset, _iDisplaySize, iHeight);
						Line(g, _iSideOffset, _iHeaderOffset, (_iDisplaySize + _iSideOffset), _iHeaderOffset);
					}
					else
					{
						int iWidth = _Bitmap.Width - _iHeaderOffset;
						g.FillRectangle(new SolidBrush(this.BackColor), _iHeaderOffset, _iSideOffset, iWidth, _iDisplaySize);
						Line(g, _iHeaderOffset, _iSideOffset, _iHeaderOffset, (_iDisplaySize + _iSideOffset));
					}

					DrawTimeScale(g);
					DrawProgressBars(g);
					_aryKeyFrames.Draw(g);

					// Paint the lines on the image
					int iScale = (int) _Scale;
					int intScale = (int) _Scale;

					int iStart = Start();
					int iEnd = iStart + _iDisplaySize + 1;
					float fltStart = (float) iStart;
					float fltEnd = (float) iEnd;

					int j;
					for(float fltJ = fltStart; fltJ <= fltEnd; fltJ += _Scale)
					{
						j = (int) fltJ;
						int iLeft = (int) _Scale;  // Make an assumption that we're starting at zero or on a major increment
						int jOffset = j+_ScaleStartValue;

						if (_RulerAlignment != enumRulerAlignment.raMiddle)
						{
							if (this.Orientation == enumOrientation.orHorizontal)
								Line(g, j, _iHeaderOffset, j, Height);
							else
								Line (g, _iHeaderOffset, j, Width, j);
						}

						iLeft = intScale;     // Set the for loop increment

						iScale = iLeft;

						int iValue = (((jOffset-iStart)/intScale)+1) * _iMajorInterval;
						DrawValue(g, iValue, j - iStart, iScale);

						int iUsed = 0;

						//Draw small lines
						for(int i = 0; i < _iNumberOfDivisions; i++)
						{
							int iX = Convert.ToInt32(Math.Round((double)(_Scale-iUsed)/(double)(_iNumberOfDivisions - i),0)); // Use a spreading algorithm rather that using expensive floating point numbers
							iUsed += iX;

							if (iUsed >= (intScale-iLeft))
							{
								iX = iUsed+j-(intScale-iLeft);

								// Is it an even number and, if so, is it the middle value?
								bool bMiddleMark = ((_iNumberOfDivisions & 0x1) == 0) & (i+1==_iNumberOfDivisions/2);
								bool bShowMiddleMark = bMiddleMark;
								bool bLastDivisionMark = (i+1 == _iNumberOfDivisions);
								bool bLastAlignMiddleDivisionMark =  bLastDivisionMark & (_RulerAlignment == enumRulerAlignment.raMiddle);
								bool bShowDivisionMark = !bMiddleMark & !bLastAlignMiddleDivisionMark;

								if( _RulerAlignment == enumRulerAlignment.raMiddle || !bLastDivisionMark )
								{
									if (bShowMiddleMark)
									{
										DivisionMark(g, iX, _MiddleMarkFactor);  // Height or Width will be 1/3
									}
									else if (bShowDivisionMark)
									{
										DivisionMark(g, iX, _DivisionMarkFactor);  // Height or Width will be 1/5
									}
								}
							}
						}
					}

					if (_i3DBorderStyle != Border3DStyle.Flat)
						ControlPaint.DrawBorder3D(g, this.ClientRectangle, this._i3DBorderStyle );

				}
				catch(Exception ex)
				{
					System.Diagnostics.Debug.WriteLine(ex.Message);
				}
				finally
				{
					g.Dispose();
				}
			}

			g = graphics;

			try
			{

				// Always draw the bitmap
				g.DrawImage(_Bitmap, this.ClientRectangle);

				RenderTrackLine(g);
			}
			catch(Exception ex)
			{
				System.Diagnostics.Debug.WriteLine(ex.Message);
			}
			finally
			{
				_bInsideDraw = false;
				GC.Collect();
			}

		}

		private void DrawProgressBars(Graphics g)
		{
			DrawProgressBar(g, _lActualMillisecond, new System.Drawing.Drawing2D.HatchBrush(System.Drawing.Drawing2D.HatchStyle.ForwardDiagonal, _CurrentTimeColor, _ActualTimeColor));
			DrawProgressBar(g, _lCurrentMillisecond, new SolidBrush(_CurrentTimeColor));
		}

		private void DrawProgressBar(Graphics g, long lMillisecond, System.Drawing.Brush barBrush)
		{
			float fltProgressBarScale = (float)_iProgressBarScale / 100;

			int iProgressLength = CalculatePixel(((double) lMillisecond/MillisecondScale)) - _iSideOffset;
			int iBmpSize = (this.Orientation == enumOrientation.orHorizontal) ? _Bitmap.Height : _Bitmap.Width;
			iBmpSize = iBmpSize - _iHeaderOffset;

			int iTop = (int) ((iBmpSize - (iBmpSize * fltProgressBarScale))/2) + _iHeaderOffset;
			int iBarThickness = (int) (iBmpSize * fltProgressBarScale);

			if(this.Orientation == enumOrientation.orHorizontal)
				g.FillRectangle(barBrush, _iSideOffset, iTop, iProgressLength, iBarThickness);
			else
				g.FillRectangle(barBrush, iTop, _iSideOffset, iBarThickness, iProgressLength);
		}

		private void DivisionMark(Graphics g, int iPosition, int iProportion)
		{
			// This function is affected by the RulerAlignment setting

			int iMarkStart = 0, iMarkEnd = 0;

			if (this.Orientation == enumOrientation.orHorizontal)
			{

				switch(_RulerAlignment)
				{
					case enumRulerAlignment.raBottomOrRight:
					{
						iMarkStart = Height - (Height - _iHeaderOffset)/iProportion;
						iMarkEnd = Height;
						break;
					}
					case enumRulerAlignment.raMiddle:
					{
						iMarkStart = ((Height - ((Height - _iHeaderOffset)/iProportion) + _iHeaderOffset)/2) - 1;
						iMarkEnd = (iMarkStart + (Height - _iHeaderOffset)/iProportion);
						break;
					}
					case enumRulerAlignment.raTopOrLeft:
					{
						iMarkStart = _iHeaderOffset;
						iMarkEnd = iMarkStart + (Height + _iHeaderOffset)/iProportion;
						break;
					}
				}

				Line(g, iPosition, iMarkStart, iPosition, iMarkEnd);
			}
			else
			{

				switch(_RulerAlignment)
				{
					case enumRulerAlignment.raBottomOrRight:
					{
						iMarkStart = Width - (Width - _iHeaderOffset)/iProportion;
						iMarkEnd = Width;
						break;
					}
					case enumRulerAlignment.raMiddle:
					{
						iMarkStart = ((Width - ((Width - _iHeaderOffset)/iProportion) + _iHeaderOffset)/2) - 1;
						iMarkEnd = (iMarkStart + (Width - _iHeaderOffset)/iProportion);
						break;
					}
					case enumRulerAlignment.raTopOrLeft:
					{
						iMarkStart = _iHeaderOffset;
						iMarkEnd = iMarkStart + (Width + _iHeaderOffset)/iProportion;
						break;
					}
				}

				Line(g, iMarkStart, iPosition, iMarkEnd, iPosition);
			}
		}

		private void DrawTimeScale(Graphics g)
		{
			StringFormat format = new StringFormat(StringFormatFlags.MeasureTrailingSpaces);
			if (_VerticalNumbers)
				format.FormatFlags |= StringFormatFlags.DirectionVertical;

			int iSpaceAvailable;
			//Debug.WriteLine("Scale: " +  _Scale.ToString());
			if (this.Orientation == enumOrientation.orHorizontal)
				iSpaceAvailable = (int) (_Scale*2/3)-2;
			else
				iSpaceAvailable = _Bitmap.Width - _iHeaderOffset - 2;

			string strText = _TimeScale.ToString();
			SizeF size = g.MeasureString(strText, this.Font);

			if(size.Width > iSpaceAvailable ||
				this.Orientation == enumOrientation.orVertical)
			{
				strText = GetTimeScaleAbbreviation(_TimeScale);
				size = g.MeasureString(strText, this.Font);
			}

			Point drawingPoint = new Point(0, 0);
			int iX = 0;
			int iY = 0;

			if (this.Orientation == enumOrientation.orHorizontal)
			{
				switch(_RulerAlignment)
				{
					case enumRulerAlignment.raBottomOrRight:
					{
						iX = 7;
						iY = _iHeaderOffset + 2;
						break;
					}
					case enumRulerAlignment.raMiddle:
					{
						iX = 7;
						iY = _iHeaderOffset + 2;
						break;
					}
					case enumRulerAlignment.raTopOrLeft:
					{
						iX = 7;
						iY = Height - (int)size.Height - 2;
						break;
					}
				}

				drawingPoint = new Point(iX, iY);
				//g.DrawString(strText, this.Font, new SolidBrush(this.ForeColor), drawingPoint, format);
			}
			else
			{
				switch(_RulerAlignment)
				{
					case enumRulerAlignment.raBottomOrRight:
					{
						iX = _iHeaderOffset + 2;
						iY = 7;
						break;
					}
					case enumRulerAlignment.raMiddle:
					{
						iX = _iHeaderOffset + 2;
						iY = 7;
						break;
					}
					case enumRulerAlignment.raTopOrLeft:
					{
						iX = Width - 2 - (int)size.Width;
						iY = 7;
						break;
					}
				}

				drawingPoint = new Point(iX, iY);
			}

			// The drawstring function is common to all operations
			g.DrawString(strText, this.Font, new SolidBrush(this.ForeColor), drawingPoint, format);
		}

		private void DrawValue(Graphics g, int iValue, int iPosition, int iSpaceAvailable)
		{

			// The sizing operation is common to all options
			StringFormat format = new StringFormat(StringFormatFlags.MeasureTrailingSpaces);
			if (_VerticalNumbers)
				format.FormatFlags |= StringFormatFlags.DirectionVertical;

			SizeF size = g.MeasureString((iValue).ToString(), this.Font, iSpaceAvailable, format);

			Point drawingPoint;
			int iX = 0;
			int iY = 0;

			if (this.Orientation == enumOrientation.orHorizontal)
			{
				switch(_RulerAlignment)
				{
					case enumRulerAlignment.raBottomOrRight:
					{
						iX = iPosition + iSpaceAvailable - (int)size.Width - 2;
						iY = _iHeaderOffset + 2;
						break;
					}
					case enumRulerAlignment.raMiddle:
					{
						iX = iPosition + iSpaceAvailable - (int)size.Width/2;
						iY = _iHeaderOffset + (Height - _iHeaderOffset - (int)size.Height)/2 - 2;
						break;
					}
					case enumRulerAlignment.raTopOrLeft:
					{
						iX = iPosition + iSpaceAvailable - (int)size.Width - 2;
						iY = Height - (int)size.Height - 2;
						break;
					}
				}

				drawingPoint = new Point(iX, iY);
			}
			else
			{
				switch(_RulerAlignment)
				{
					case enumRulerAlignment.raBottomOrRight:
					{
						iX = _iHeaderOffset + 2;
						iY = iPosition + iSpaceAvailable - (int)size.Height - 2;
						break;
					}
					case enumRulerAlignment.raMiddle:
					{
						iX = _iHeaderOffset + (Width - _iHeaderOffset - (int)size.Width)/2 - 2;
						iY = iPosition + iSpaceAvailable - (int)size.Height/2;
						break;
					}
					case enumRulerAlignment.raTopOrLeft:
					{
						iX = Width - (_iHeaderOffset + 2) - (int)size.Width;
						iY = iPosition + iSpaceAvailable - (int)size.Height - 2;
						break;
					}
				}

				drawingPoint = new Point(iX, iY);
			}

			// The drawstring function is common to all operations

			g.DrawString(iValue.ToString(), this.Font, new SolidBrush(this.ForeColor), drawingPoint, format);
		}

		private void Line(Graphics g, int x1, int y1, int x2, int y2)
		{
			g.DrawLine(new Pen(new SolidBrush(this.ForeColor)), x1, y1, x2, y2);
		}

		private int DefaultScale()
		{return DefaultScale(_ScaleMode);}

		private int DefaultScale(enumScaleMode iScaleMode)
		{return DefaultScale(iScaleMode, _ZoomFactor);}

		private int DefaultScale(double dblZoomFactor)
		{return DefaultScale(_ScaleMode, dblZoomFactor);}

		private int DefaultScale(enumScaleMode iScaleMode, double dblZoomFactor)
		{
			int iScale = 100;

			// Set scaling
			switch(iScaleMode)
			{
					// Determines the *relative* proportions of each scale
				case enumScaleMode.smPoints:
					iScale = 96;
					break;
				case enumScaleMode.smPixels:
					iScale = 100;
					break;
				case enumScaleMode.smCentimetres:
					iScale = 38;
					break;
				case enumScaleMode.smInches:
					iScale = 96;
					break;
			}

			return Convert.ToInt32((double)iScale * dblZoomFactor);
		}

		private float DefaultScale1(enumScaleMode iScaleMode, double dblZoomFactor)
		{
			int iScale = 100;

			// Set scaling
			switch(iScaleMode)
			{
					// Determines the *relative* proportions of each scale
				case enumScaleMode.smPoints:
					iScale = 96;
					break;
				case enumScaleMode.smPixels:
					iScale = 100;
					break;
				case enumScaleMode.smCentimetres:
					iScale = 38;
					break;
				case enumScaleMode.smInches:
					iScale = 96;
					break;
			}

			return (float) (iScale * dblZoomFactor);
		}

		private int DefaultMajorInterval()
		{return DefaultMajorInterval(_ScaleMode);}

		private int DefaultMajorInterval(enumScaleMode iScaleMode)
		{
			int iInterval = 10;

			// Set scaling
			switch(iScaleMode)
			{
					// Determines the *relative* proportions of each scale
				case enumScaleMode.smPoints:
					iInterval = 72;
					break;
				case enumScaleMode.smPixels:
					iInterval = 100;
					break;
				case enumScaleMode.smCentimetres:
					iInterval = 1;
					break;
				case enumScaleMode.smInches:
					iInterval = 1;
					break;
			}

			return iInterval;
		}

		private int Offset()
		{
			int iOffset = 0;

			switch(this._i3DBorderStyle)
			{
				case Border3DStyle.Flat: iOffset = 0; break;
				case Border3DStyle.Adjust: iOffset = 0; break;
				case Border3DStyle.Sunken: iOffset = 2; break;
				case Border3DStyle.Bump: iOffset = 2; break;
				case Border3DStyle.Etched: iOffset = 2; break;
				case Border3DStyle.Raised: iOffset = 2; break;
				case Border3DStyle.RaisedInner: iOffset = 1; break;
				case Border3DStyle.RaisedOuter: iOffset = 1; break;
				case Border3DStyle.SunkenInner: iOffset = 1; break;
				case Border3DStyle.SunkenOuter: iOffset = 1; break;
				default: iOffset = 0; break;
			}

			return iOffset;
		}

		private int Start()
		{
			int iStart = 0;

			switch(this._i3DBorderStyle)
			{
				case Border3DStyle.Flat: iStart = 0; break;
				case Border3DStyle.Adjust: iStart = 0; break;
				case Border3DStyle.Sunken: iStart = 1; break;
				case Border3DStyle.Bump: iStart = 1; break;
				case Border3DStyle.Etched: iStart = 1; break;
				case Border3DStyle.Raised: iStart = 1; break;
				case Border3DStyle.RaisedInner: iStart = 0; break;
				case Border3DStyle.RaisedOuter: iStart = 0; break;
				case Border3DStyle.SunkenInner: iStart = 0; break;
				case Border3DStyle.SunkenOuter: iStart = 0; break;
				default: iStart = 0; break;
			}
			return (iStart + _iSideOffset);
		}

		private void ChangeMousePosition(int iNewPosition)
		{
			this._iOldMousePosition = this._iMousePosition;
			this._iMousePosition = iNewPosition;
		}

		private void AddKeyFrame(Point pMousePos)
		{
			try
			{
				int iMousePosition = ((this.Orientation == enumOrientation.orHorizontal) ? pMousePos.X : pMousePos.Y);
				long lMillisecond = CalculateMillisecondValue(iMousePosition);

				if( (lMillisecond >= _lStartMillisecond) && (lMillisecond <= _lEndMillisecond) )
				{
					if(lMillisecond <= _lCurrentMillisecond)
						throw new System.Exception("You can not add new keyframes that occur before the current simulation time.");

					KeyFrame keyFrame = new KeyFrame(lMillisecond);
					this.KeyFrames.Add(keyFrame);

					OnKeyFrameAdded(keyFrame);

					SelectedKeyFrame = keyFrame;
				}
			}
			catch(Exception ex)
			{
				MessageBox.Show(ex.Message);
			}
		}

		private void RemoveKeyFrame(Point pMousePos)
		{
			try
			{
				int iMousePosition = ((this.Orientation == enumOrientation.orHorizontal) ? pMousePos.X : pMousePos.Y);
				long lMillisecond = CalculateMillisecondValue(iMousePosition);

				if(lMillisecond <= _lCurrentMillisecond)
					throw new System.Exception("You can not remove keyframes that occur before the current simulation time.");

				KeyFrame keyFrame = _aryKeyFrames.RemoveClosest(KeyFrame.enumKeyFrameType.Snapshot, lMillisecond);

				if(keyFrame != null)
					OnKeyFrameRemoved(keyFrame);
			}
			catch(Exception ex)
			{
				MessageBox.Show(ex.Message);
			}
		}

		private void AddVideoFrame(Point pMousePos)
		{
			try
			{
				int iMousePosition = ((this.Orientation == enumOrientation.orHorizontal) ? pMousePos.X : pMousePos.Y);
				long lMillisecond = CalculateMillisecondValue(iMousePosition);

				if( (lMillisecond >= _lStartMillisecond) && (lMillisecond <= _lEndMillisecond) )
				{
					if(lMillisecond <= _lCurrentMillisecond)
						throw new System.Exception("You can not add new keyframes that occur before the current simulation time.");

					KeyFrame keyFrame = new KeyFrameVideoRange(lMillisecond, lMillisecond + 200);
					this.KeyFrames.Add(keyFrame);

					OnKeyFrameAdded(keyFrame);

					SelectedKeyFrame = keyFrame;
				}
			}
			catch(Exception ex)
			{
				MessageBox.Show(ex.Message);
			}
		}

		private void RemoveVideoFrame(Point pMousePos)
		{
			try
			{
				int iMousePosition = ((this.Orientation == enumOrientation.orHorizontal) ? pMousePos.X : pMousePos.Y);
				long lMillisecond = CalculateMillisecondValue(iMousePosition);

				KeyFrame keyFrame = _aryKeyFrames.RemoveClosest(KeyFrame.enumKeyFrameType.Video, lMillisecond);

				if(keyFrame != null)
					OnKeyFrameRemoved(keyFrame);
			}
			catch(Exception ex)
			{
			MessageBox.Show(ex.Message);
			}
		}

	}

	#endregion

}