[go: up one dir, main page]

Menu

[a88aee]: / XL-Tools.plw  Maximize  Restore  History

Download this file

6662 lines (6399 with data), 309.4 kB

#!/usr/bin/perl
# Perl - v: 5.16.3
#------------------------------------------------------------------------------#
# Tool name     : XL-Tools
# WebSite       : http://le-tools.com/XL-Tools.html
# SourceForge   : https://sourceforge.net/p/xl-tools
# GitHub        : https://github.com/arioux/XL-Tools
# Documentation : http://le-tools.com/XL-ToolsDoc.html
# Description   : Part of the XL-Toolkit, XL-Tools provides a bunch of functions
#                 for list of strings like sorting, converting, replacing, date
#                 and time utilities, etc.
# Creation      : 2015-12-21
# Modified      : 2020-01-12
my $VERSION     = "3.9.1";
# Author        : Alain Rioux (admin@le-tools.com)
#
# Copyright (C) 2015-2020  Alain Rioux (le-tools.com)
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
#
#------------------------------------------------------------------------------#
# Modules
#------------------------------------------------------------------------------#
use strict;
use warnings;
use Math::Int64 qw(string_to_int64);
use String::HexConvert qw(hex_to_ascii ascii_to_hex);
use URI::Escape;
use URI::Escape::JavaScript qw(unescape);
use Encode qw(encode decode);
use HTML::Entities;
use MIME::Base64 ();
use Convert::Base32;
use DateTime;
use DateTime::Format::Duration;
use DateTime::Format::Strptime;
use DateTime::TimeZone;
use Time::Seconds;
use Win32::API();
use Win32::GUI();
use Win32::GUI 1.06 qw(:toolbar ILC_MASK CW_USEDEFAULT);
use Win32::GUI::Grid;
use Win32::Process;
use LWP::UserAgent;
use DBI;
use File::Copy;
use JSON qw(decode_json);
use GIS::Distance::Lite qw(distance);
use threads;
use threads::shared;
use Scalar::Util;
require "XL-ToolsGraph.pl";
require "XL-ToolsLang.pl";
require "XL-ToolsConfig.pl";
require "XL-ToolsLists.pl";
require "XL-ToolsUtils.pl";

#------------------------------------------------------------------------------#
# Global variables
#------------------------------------------------------------------------------#
$ENV{'PERL_LWP_SSL_VERIFY_HOSTNAME'} = 0;
my $PROGDIR = $0;                                                              # Program path
while (chop($PROGDIR) ne "\\") { }                                             # Dir only
my $USERDIR;                                                                   # User path
if (-d "$ENV{'APPDATA'}\\XL-Toolkit\\XL-Tools") { $USERDIR = "$ENV{'APPDATA'}\\XL-Toolkit\\XL-Tools"; }
else                                            { $USERDIR = $PROGDIR;                                }
my $LANG_FILE    = "$USERDIR\\Lang.ini";                                       # Langage file
my $CONFIG_FILE  = "$USERDIR\\XL-Tools.ini";                                   # Configuration file
my $URL_DOC      = "http://le-tools.com/XL-ToolsDoc.html";                     # Online documentation
my %CONFIG       :shared;                                                      # Configuration
my %STR;                                                                       # Strings for GUI
my $ARROW        :shared;                                                      # Arrow pointer
my $HOURGLASS    :shared;                                                      # Hourglass pointer
my $THR_PROCESS;                                                               # Thread for process
my $THR_UPDATE;                                                                # Thread for update
my $LISTNO        = 0;                                                         # For CTRL+A
my $START         = 0;                                                         # Indicate when program is started
my $LIST2_VISIBLE = 0;                                                         # Current state of List 2 (visible or not)
my $SPLIT1_CURR_POS;                                                           # Current pos of split 1, change when splitter is moved
my $SPLIT2_CURR_POS;                                                           # Current pos of split 2, change when splitter is moved
my $TOTAL_SIZE   :shared = 0;                                                  # Total size for download
my %ZONE_MAP = ('ADT'    => '-0300', # Atlantic Daylight Time                  # Ambiguous timezones
                'AST'    => '-0400', # Atlantic Standard Time
                'BST'    => '+0100', # British Summer Time
                'BT'     => '+0600', # Baghdad Time
                'CAT'    => '+0200', # Central Africa Time
                'CCT'    => '+0630', # Cocos Islands Time
                'CDT'    => '-0500', # Central Daylight Time
                'CST'    => '-0600', # Central Standard Time
                'EAST'   => '-0600', # Easter Island Standard Time
                'ECT'    => '-0500', # Ecuador Time
                'EDT'    => '-0400', # Eastern Daylight Time
                'EST'    => '-0500', # Eastern Standard Time
                'FDT'    => '-0100', # Fernando de Noronha Daylight Time
                'FST'    => '-0200', # Fernando de Noronha Standard Time
                'GST'    => '-0200', # South Georgia Time
                'IDT'    => '+0300', # Israel Daylight Time
                'IST'    => '+0200', # Israel Standard Time
                'MET'    => '+0100', # Middle European Time
                'NFT'    => '-0230', # Newfoundland Daylight Time
                'NST'    => '-0330', # Newfoundland Standard Time
                'PST'    => '-0800', # Pacific Standard Time
                'SAST'   => '+0200', # South Africa Standard Time
                'SST'    => '+0800', # Singapore Standard Time
                'WAST'   => '+0200', # West Africa Summer Time
                'WST'    => '+0800', # Western Standard Time}
              );

#------------------------------------------------------------------------------#
# Graphic elements
#------------------------------------------------------------------------------#
my ($winICO, $logoBmp, $logo128Bmp, $fileOpenBmp, $deleteBmp, $viewReportBmp, $downloadBmp,
    $processBmp, $stopBmp, $config32Bmp, $helpBmp, $aboutBmp, $config128Bmp, $fileNewBmp,
    $database16, $import16Bmp, $addCFBmp, $remCFBmp, $editCFBmp, $newCFBmp, $saveCFBmp,
    $cancelCFBmp, $checkBmp, $errorBmp, $left16Bmp, $help16Bmp, $datetime16Bmp, $guess16Bmp,
    $datetimeAdd, $datetimeEdit, $datetimeDel, $useResBmp) = &loadGraph();

#------------------------------------------------------------------------------#
# Strings
#------------------------------------------------------------------------------#
&loadDefaultStr(\%STR);                                                        # Load default language (en)
&loadStr(\%STR, $LANG_FILE) if -e $LANG_FILE and -T $LANG_FILE;                # If language file, load translated strings

#------------------------------------------------------------------------------#
# Main window
#------------------------------------------------------------------------------#
my $screen    = Win32::GUI::GetDesktopWindow(); # Screen resolution
my $scrnX     = Win32::GUI::Width($screen);
my $scrnY     = Win32::GUI::Height($screen);
my $winWidth  = 1080;
my $winHeight = 680;
my $winPosX   = ($scrnX - $winWidth)  / 2;
my $winPosY   = ($scrnY - $winHeight) / 2;
# Keyboard shorcut
my $accel = new Win32::GUI::AcceleratorTable("Ctrl-A"    => "selectAll",
                                             "Ctrl-Down" => "fontSizeS",
                                             "Ctrl-Up"   => "fontSizeB", );
# Main Window
my $win = Win32::GUI::Window->new( -name        => 'winMain'                 ,
                                   -text        => 'XL-Tools'                ,
                                   -background  => [255, 255, 255]           ,
                                   -size        => [$winWidth, $winHeight]   ,
                                   -pos         => [$winPosX , $winPosY]     ,
                                   -minheight   => $winHeight                ,
                                   -minwidth    => $winWidth                 ,
                                   -accel       => $accel                    , );
$win->SetIcon($winICO);
# Fonts
sub LOGPIXELSX() {88}
sub getDPI { return(Win32::GUI::DC->new()->GetDeviceCaps(LOGPIXELSX)); }
my $DPI = &getDPI();
my ($fontGB, $fontGB2, $font10, $font10b, $font10u, $font12, $fontTF);
# Larger size (125% and 150%)
if ($DPI >= 120) {
  $fontGB  = new Win32::GUI::Font(-name => 'Arial', -size => 10, -bold => 1);
  $fontGB2 = new Win32::GUI::Font(-name => 'Arial', -size => 10, -bold => 1, -underline => 1);
  $font10  = new Win32::GUI::Font(-name => 'Arial', -size =>  8);
  $font10b = new Win32::GUI::Font(-name => 'Arial', -size =>  8, -bold => 1);
  $font10u = new Win32::GUI::Font(-name => 'Arial', -size =>  8, -bold => 1, -underline => 1);
  $font12  = new Win32::GUI::Font(-name => 'Arial', -size =>  9);
  $fontTF  = new Win32::GUI::Font(-name => 'Arial', -size =>  8);
# Normal size
} else {
  $fontGB  = new Win32::GUI::Font(-name => 'Arial', -size => 12, -bold => 1);
  $fontGB2 = new Win32::GUI::Font(-name => 'Arial', -size => 12, -bold => 1, -underline => 1);
  $font10  = new Win32::GUI::Font(-name => 'Arial', -size => 10);
  $font10b = new Win32::GUI::Font(-name => 'Arial', -size => 10, -bold => 1);
  $font10u = new Win32::GUI::Font(-name => 'Arial', -size => 10, -bold => 1, -underline => 1);
  $font12  = new Win32::GUI::Font(-name => 'Arial', -size => 11);
  $fontTF  = new Win32::GUI::Font(-name => 'Arial', -size => 10);
}
# Load Pointers
my $loadImage = new Win32::API('user32', 'LoadImage', ['N','N','I','I','I','I'],'N');
$HOURGLASS    = $loadImage->Call(0, 32514, 2, 0, 0, 0x8040);
$ARROW        = $loadImage->Call(0, 32512, 2, 0, 0, 0x8040);
# Header
$win->AddLabel(       -name        => 'lblLogo'             ,
                      -size        => [310,100]             ,
                      -pos         => [  0,  0]             ,
                      -bitmap      => $logoBmp              ,
                      -background  => [255, 255, 255]       , );
$win->AddTabStrip(    -name        => 'Tab'                 ,
                      -size        => [$winWidth-325,100]   ,
                      -pos         => [310,  0]             ,
                      -fixedwidth  => 1                     ,
                      -tabstop     => 1                     ,
                      -background  => [255, 255, 255]       , );
$win->Tab->InsertItem(-text        => $STR{'Tab1'}          , );
$win->Tab->InsertItem(-text        => $STR{'Tab2'}          , );
$win->Tab->InsertItem(-text        => $STR{'Tab3'}          , );
$win->Tab->InsertItem(-text        => $STR{'Tab4'}          , );
$win->Tab->InsertItem(-text        => $STR{'Tab5'}          , );
$win->Tab->SetItemSize(116,20);
# Lists tab
$win->AddCombobox(    -name         => 'cbLists'             ,
                      -size         => [220,100]             ,
                      -pos          => [315, 30]             ,
                      -font         => $font10               ,
                      -dropdownlist => 1                     ,
                      -vscroll      => 1                     , );
$win->cbLists->Add(   $STR{'cbLists1'}  , $STR{'cbLists2'}   ,
                      $STR{'cbLists3'}  , $STR{'cbLists4'}   ,
                      $STR{'cbLists5'}  , $STR{'cbLists6'}   ,
                      $STR{'cbLists7'}  , $STR{'cbLists8'}   ,
                      $STR{'cbLists9'}  , $STR{'cbLists10'}  ,
                      $STR{'cbLists11'} , $STR{'cbLists12'}  ,
                      $STR{'cbLists19'} , $STR{'cbLists13'}  ,
                      $STR{'cbLists14'} , $STR{'cbLists18'}  ,
                      $STR{'cbLists15'} , $STR{'cbLists16'}  ,
                      $STR{'cbLists17'}  , );
$win->AddCheckbox(    -name        => 'chMatchCase'          ,
                      -size        => [ 90, 20]              ,
                      -pos         => [560, 32]              ,
                      -text        => $STR{'MatchCase'}      ,
                      -font        => $font10                ,
                      -background  => [255, 255, 255]        ,
                      -checked     => 1                      , );
$win->AddCheckbox(    -name        => 'chRegex'              ,
                      -size        => [ 80, 20]              ,
                      -pos         => [670, 32]              ,
                      -text        => $STR{'Regex'}          ,
                      -font        => $font10                ,
                      -background  => [255, 255, 255]        ,
                      -checked     => 0                      , );
$win->AddCheckbox(    -name        => 'chEval'               ,
                      -size        => [ 80, 20]              ,
                      -pos         => [760, 32]              ,
                      -text        => $STR{'Eval'}           ,
                      -font        => $font10                ,
                      -background  => [255, 255, 255]        ,
                      -checked     => 0                      ,
                      -disabled    => 1                      , );
$win->AddLabel(       -name        => 'lblWith'              ,
                      -size        => [ 40, 22]              ,
                      -pos         => [315, 67]              ,
                      -background  => [255, 255, 255]        ,
                      -text        => $STR{'With'}.':'       ,
                      -font        => $font10                , );
$win->AddTextfield(   -name        => 'tfWith'               ,
                      -size        => [ 95, 22]              ,
                      -pos         => [360, 65]              , );
$win->AddLabel(       -name        => 'lblColumnsNo'         ,
                      -size        => [ 60, 22]              ,
                      -pos         => [475, 67]              ,
                      -background  => [255, 255, 255]        ,
                      -text        => $STR{'Columns'}.':'    ,
                      -font        => $font10                , );
$win->AddTextfield(   -name        => 'tfColumnsNo'          ,
                      -size        => [ 95, 22]              ,
                      -pos         => [540, 65]              , );
$win->AddLabel(       -name        => 'lblReplace'           ,
                      -size        => [ 80, 22]              ,
                      -pos         => [315, 67]              ,
                      -background  => [255, 255, 255]        ,
                      -text        => $STR{'Replace'}.':'    ,
                      -font        => $font10                , );
$win->AddLabel(       -name        => 'lblReplaceREOk'       ,
                      -size        => [ 87, 24]              ,
                      -pos         => [399, 64]              ,
                      -background  => [  0, 255,   0]        ,
                      -visible     => 0                      , );
$win->AddLabel(       -name        => 'lblReplaceREErr'      ,
                      -size        => [ 87, 24]              ,
                      -pos         => [399, 64]              ,
                      -background  => [255,   0,   0]        ,
                      -visible     => 0                      , );
$win->AddLabel(       -name        => 'lblReplaceREWarn'     ,
                      -size        => [ 87, 24]              ,
                      -pos         => [399, 64]              ,
                      -background  => [255, 255,   0]        ,
                      -visible     => 0                      , );
$win->AddTextfield(   -name        => 'tfReplace'            ,
                      -size        => [ 85, 22]              ,
                      -pos         => [400, 65]              , );
$win->AddLabel(       -name        => 'lblReplBy'            ,
                      -size        => [ 30, 22]              ,
                      -pos         => [660, 67]              ,
                      -background  => [255, 255, 255]        ,
                      -text        => $STR{'By'}.':'         ,
                      -font        => $font10                , );
$win->AddLabel(       -name        => 'lblReplaceByREOk'     ,
                      -size        => [ 87, 24]              ,
                      -pos         => [694, 64]              ,
                      -background  => [  0, 255,   0]        ,
                      -visible     => 0                      , );
$win->AddLabel(       -name        => 'lblReplaceByREErr'    ,
                      -size        => [ 87, 24]              ,
                      -pos         => [694, 64]              ,
                      -background  => [255,   0,   0]        ,
                      -visible     => 0                      , );
$win->AddLabel(       -name        => 'lblReplaceByREWarn'   ,
                      -size        => [ 87, 24]              ,
                      -pos         => [694, 64]              ,
                      -background  => [255, 255,   0]        ,
                      -visible     => 0                      , );
$win->AddTextfield(   -name        => 'tfReplBy'             ,
                      -size        => [ 85, 22]              ,
                      -pos         => [695, 65]              ,
                      -disabled    => 1                      , );
$win->AddRadioButton( -name        => 'rbAll'                ,
                      -size        => [140, 22]              ,
                      -pos         => [550, 30]              ,
                      -background  => [255, 255, 255]        ,
                      -text        => $STR{'all'}            ,
                      -font        => $font10                ,
                      -checked     => 1                      ,
                      -group       => 1                      ,
                      -visible     => 0                      , );
$win->AddRadioButton( -name        => 'rbFirstOnly'          ,
                      -size        => [160, 22]              ,
                      -pos         => [700, 30]              ,
                      -background  => [255, 255, 255]        ,
                      -text        => $STR{'firstOnly'}      ,
                      -font        => $font10                ,
                      -visible     => 0                      , );
$win->AddRadioButton( -name        => 'rbFirstEachWord'      ,
                      -size        => [200, 22]              ,
                      -pos         => [550, 60]              ,
                      -background  => [255, 255, 255]        ,
                      -text        => $STR{'firstEachWord'}  ,
                      -font        => $font10                ,
                      -visible     => 0                      , );
# Sort tab
$win->AddCombobox(    -name         => 'cbSorts'              ,
                      -size         => [220,100]              ,
                      -pos          => [315, 30]              ,
                      -font         => $font10                ,
                      -dropdownlist => 1                      ,
                      -vscroll      => 1                      ,
                      -visible      => 0                      , );
$win->cbSorts->Add(   $STR{'cbSorts1'} , $STR{'cbSorts2'}     ,
                      $STR{'cbSorts3'} , $STR{'cbSorts4'}     ,
                      $STR{'cbSorts5'} , $STR{'cbSorts6'}     , );
$win->AddRadioButton( -name        => 'rbAsc'                 ,
                      -size        => [100, 22]               ,
                      -pos         => [560, 30]               ,
                      -background  => [255, 255, 255]         ,
                      -text        => $STR{'Ascending'}       ,
                      -font        => $font10                 ,
                      -checked     => 1                       ,
                      -group       => 1                       ,
                      -visible     => 0                       , );
$win->AddRadioButton( -name        => 'rbDsc'                 ,
                      -size        => [120, 22]               ,
                      -pos         => [660, 30]               ,
                      -background  => [255, 255, 255]         ,
                      -text        => $STR{'Descending'}      ,
                      -font        => $font10                 ,
                      -visible     => 0                       , );
# Conversion tab
$win->AddCombobox(    -name         => 'cbConv'               ,
                      -size         => [220,100]              ,
                      -pos          => [315, 30]              ,
                      -font         => $font10                ,
                      -dropdownlist => 1                      ,
                      -vscroll      => 1                      ,
                      -visible      => 0                      , );
$win->cbConv->Add(    $STR{'cbConv1'}  , $STR{'cbConv2'}      ,
                      $STR{'cbConv3'}  , $STR{'cbConv4'}      ,
                      $STR{'cbConv5'}  , $STR{'cbConv6'}      ,
                      $STR{'cbConv7'}  , $STR{'cbConv8'}      ,
                      $STR{'cbConv9'}  , $STR{'cbConv10'}     ,
                      $STR{'cbConv11'} , $STR{'cbConv12'}     , );
# Time tab
$win->AddCombobox(    -name         => 'cbTime'               ,
                      -size         => [220,100]              ,
                      -pos          => [315, 30]              ,
                      -font         => $font10                ,
                      -dropdownlist => 1                      ,
                      -vscroll      => 1                      ,
                      -visible      => 0                      , );
$win->cbTime->Add($STR{'cbTime1'}, $STR{'cbTime2'}, $STR{'cbTime3'}, $STR{'cbTime4'});
# Parser
$win->AddLabel(       -name         => 'lblDTParser'          ,
                      -size         => [100, 22]              ,
                      -pos          => [$winWidth-287, 33]    ,
                      -background   => [255, 255, 255]        ,
                      -text         => $STR{'lblDTParser'}.':',
                      -font         => $font10                ,
                      -visible      => 0                      , );
$win->AddCombobox(    -name         => 'cbDTParser'           ,
                      -size         => [ 80,100]              ,
                      -pos          => [$winWidth-227, 30]    ,
                      -font         => $font10                ,
                      -dropdownlist => 1                      ,
                      -vscroll      => 1                      ,
                      -visible      => 0                      , );
$win->cbDTParser->Add($STR{'None'} , $STR{'Before'}, $STR{'After'}, $STR{'Both'});
$win->cbDTParser->SetCurSel(0);
# Input format
$win->AddLabel(       -name         => 'lblInputType'         ,
                      -size         => [ 50, 22]              ,
                      -pos          => [315, 68]              ,
                      -background   => [255, 255, 255]        ,
                      -text         => $STR{'Input'}.':'      ,
                      -font         => $font10                ,
                      -visible      => 0                      , );
$win->AddCombobox(    -name         => 'cbInputTimeType'      ,
                      -size         => [135,100]              ,
                      -pos          => [370, 65]              ,
                      -font         => $font10                ,
                      -dropdownlist => 1                      ,
                      -vscroll      => 1                      ,
                      -visible      => 0                      , );
$win->AddCombobox(    -name         => 'cbInputDTFormat'      ,
                      -size         => [200,100]              ,
                      -pos          => [510, 65]              ,
                      -font         => $font10                ,
                      -dropdownlist => 1                      ,
                      -vscroll      => 1                      ,
                      -visible      => 0                      , );
$win->AddButton(      -name         => 'btnOpenDTDB'          ,
                      -size         => [ 24, 24]              ,
                      -pos          => [712, 65]              ,
                      -font         => $font10                ,
                      -bitmap       => $datetime16Bmp         ,
                      -tip          => "$STR{'Open'} $STR{'DTDB'}",
                      -disabled     => 0                      ,
                      -visible      => 0                      , );
$win->AddButton(      -name         => 'btnInputFormatGuess'  ,
                      -size         => [ 24, 24]              ,
                      -pos          => [738, 65]              ,
                      -bitmap       => $guess16Bmp            ,
                      -tip          => $STR{'btnInputFormatGuessTip'},
                      -disabled     => 1                      ,
                      -visible      => 0                      , );
# Output format 
$win->AddLabel(       -name         => 'lblOutputDTFormat'    ,
                      -size         => [ 55, 22]              ,
                      -pos          => [$winWidth-287, 68]    ,
                      -background   => [255, 255, 255]        ,
                      -text         => $STR{'Output'}.':'     ,
                      -font         => $font10                ,
                      -visible      => 0                      , );
$win->AddCombobox(    -name         => 'cbOutputDTFormat'     ,
                      -size         => [200,100]              ,
                      -pos          => [$winWidth-227, 65]    ,
                      -font         => $font10                ,
                      -dropdownlist => 1                      ,
                      -vscroll      => 1                      ,
                      -visible      => 0                      , );
# Time difference controls
$win->AddCheckbox(    -name         => 'chSingleDate'         ,
                      -size         => [130, 22]              ,
                      -pos          => [550, 30]              ,
                      -text         => $STR{'SingleDate'}.':' ,
                      -font         => $font10                ,
                      -background   => [255, 255, 255]        ,
                      -checked      => 0                      ,
                      -visible      => 0                      , );
$win->AddDateTime(    -name         => 'dtTimeDiffDate'       ,
                      -size         => [ 90, 22]              ,
                      -pos          => [690, 30]              ,
                      -font         => $font10                ,
                      -background   => [255, 255, 255]        ,
                      -format       => 'shortdate'            ,
                      -visible      => 0                      , );
$win->AddDateTime(    -name         => 'dtTimeDiffTime'       ,
                      -size         => [ 80, 22]              ,
                      -pos          => [790, 30]              ,
                      -font         => $font10                ,
                      -background   => [255, 255, 255]        ,
                      -format       => 'time'                 ,
                      -visible      => 0                      , );
$win->AddCombobox(    -name         => 'cbOutputDTDiff'       ,
                      -size         => [100,100]              ,
                      -pos          => [$winWidth-227, 65]    ,
                      -font         => $font10                ,
                      -dropdownlist => 1                      ,
                      -vscroll      => 1                      ,
                      -visible      => 0                      , );
$win->cbOutputDTDiff->Add($STR{'string'} , $STR{'years'}, $STR{'months'},
                          $STR{'weeks'}  , $STR{'days'} , $STR{'hours'} ,
                          $STR{'minutes'}, $STR{'seconds'});
$win->cbOutputDTDiff->SetCurSel(0);
# Add-substract time controls
$win->AddLabel(       -name       => 'lblDeltaYears'          ,
                      -size       => [ 50, 22]                ,
                      -pos        => [540, 33]                ,
                      -background => [255, 255, 255]          ,
                      -text       => ucfirst($STR{'years'}).':',
                      -font       => $font10                  ,
                      -align      => 'right'                  ,
                      -visible    => 0                        , );
$win->AddTextfield(   -name       => 'tfDeltaYears'           ,
                      -size       => [ 45, 24]                ,
                      -pos        => [595, 30]                ,
                      -number     => 1                        ,
                      -align      => 'right'                  ,
                      -visible    => 0                        , );
$win->AddUpDown(      -name       => 'upDownDeltaYears'       ,
                      -visible    => 0                        , );
$win->upDownDeltaYears->SetRange(0,100);
$win->upDownDeltaYears->SetPos(0);
$win->AddLabel(       -name       => 'lblDeltaMonths'         ,
                      -size       => [ 50, 22]                ,
                      -pos        => [645, 33]                ,
                      -background => [255, 255, 255]          ,
                      -text       => ucfirst($STR{'months'}).':',
                      -font       => $font10                  ,
                      -align      => 'right'                  ,
                      -visible    => 0                        , );
$win->AddTextfield(   -name       => 'tfDeltaMonths'          ,
                      -size       => [ 45, 24]                ,
                      -pos        => [700, 30]                ,
                      -number     => 1                        ,
                      -align      => 'right'                  ,
                      -visible    => 0                        , );
$win->AddUpDown(      -name       => 'upDownDeltaMonths'      ,
                      -visible    => 0                        , );
$win->upDownDeltaMonths->SetRange(0,12);
$win->upDownDeltaMonths->SetPos(0);
$win->AddLabel(       -name       => 'lblDeltaDays'           ,
                      -size       => [ 50, 22]                ,
                      -pos        => [745, 33]                ,
                      -background => [255, 255, 255]          ,
                      -text       => ucfirst($STR{'days'}).':',
                      -font       => $font10                  ,
                      -align      => 'right'                  ,
                      -visible    => 0                        , );
$win->AddTextfield(   -name       => 'tfDeltaDays'            ,
                      -size       => [ 45, 24]                ,
                      -pos        => [800, 30]                ,
                      -number     => 1                        ,
                      -align      => 'right'                  ,
                      -visible    => 0                        , );
$win->AddUpDown(      -name       => 'upDownDeltaDays'        ,
                      -visible    => 0                        , );
$win->upDownDeltaDays->SetRange(0,365);
$win->upDownDeltaDays->SetPos(0);
$win->AddLabel(       -name       => 'lblDeltaTime'           ,
                      -size       => [ 50, 22]                ,
                      -pos        => [850, 33]                ,
                      -background => [255, 255, 255]          ,
                      -text       => $STR{'Tab4'}.':'         ,
                      -font       => $font10                  ,
                      -align      => 'right'                  ,
                      -visible    => 0                        , );
$win->AddTextfield(   -name       => 'tfDeltaHours'           ,
                      -size       => [ 45, 24]                ,
                      -pos        => [905, 30]                ,
                      -number     => 1                        ,
                      -align      => 'right'                  ,
                      -visible    => 0                        , );
$win->AddUpDown(      -name       => 'upDownDeltaHours'       ,
                      -visible    => 0                        , );
$win->upDownDeltaHours->SetRange(0,24);
$win->upDownDeltaHours->SetPos(0);
$win->AddLabel(       -name       => 'lblSeparator1'          ,
                      -size       => [ 10, 22]                ,
                      -pos        => [950, 33]                ,
                      -background => [255, 255, 255]          ,
                      -text       => ':'                      ,
                      -font       => $fontGB                  ,
                      -align      => 'center'                 ,
                      -visible    => 0                        , );
$win->AddTextfield(   -name       => 'tfDeltaMinutes'         ,
                      -size       => [  45, 24]               ,
                      -pos        => [ 960, 30]               ,
                      -number     => 1                        ,
                      -align      => 'right'                  ,
                      -visible    => 0                        , );
$win->AddUpDown(      -name       => 'upDownDeltaMinutes'     ,
                      -visible    => 0                        , );
$win->upDownDeltaMinutes->SetRange(0,59);
$win->upDownDeltaMinutes->SetPos(0);
$win->AddLabel(       -name       => 'lblSeparator2'          ,
                      -size       => [  10, 22]               ,
                      -pos        => [1005, 33]               ,
                      -background => [255, 255, 255]          ,
                      -text       => ':'                      ,
                      -font       => $fontGB                  ,
                      -align      => 'center'                 ,
                      -visible    => 0                        , );
$win->AddTextfield(   -name       => 'tfDeltaSecondes'        ,
                      -size       => [  45, 24]               ,
                      -pos        => [1015, 30]               ,
                      -number     => 1                        ,
                      -align      => 'right'                  ,
                      -visible    => 0                        , );
$win->AddUpDown(      -name       => 'upDownDeltaSecondes'    ,
                      -visible    => 0                        , );
$win->upDownDeltaSecondes->SetRange(0,59);
$win->upDownDeltaSecondes->SetPos(0);
# Utils tab
$win->AddCombobox(    -name         => 'cbUtils'              ,
                      -size         => [220,100]              ,
                      -pos          => [315, 30]              ,
                      -font         => $font10                ,
                      -dropdownlist => 1                      ,
                      -vscroll      => 1                      ,
                      -visible      => 0                      , );
$win->cbUtils->Add(   $STR{'cbUtils1'}  , $STR{'cbUtils2'}    ,
                      $STR{'cbUtils3'}  , $STR{'cbUtils4'}    ,
                      $STR{'cbUtils5'}  , $STR{'cbUtils6'}    ,
                      $STR{'cbUtils7'}  , $STR{'cbUtils8'}    ,
                      $STR{'cbUtils9'}  , $STR{'cbUtils10'}   ,
                      $STR{'cbUtils11'} , $STR{'cbUtils13'}   ,
                      $STR{'cbUtils15'} , $STR{'cbUtils14'}   ,
                      $STR{'cbUtils12'} , );
# Resolve MAC Address Options
$win->AddLabel(       -name       => 'lblCurrMACOUIdbDate'    ,
                      -size       => [220, 22]                ,
                      -pos        => [315, 65]                ,
                      -background => [255, 255, 255]          ,
                      -foreground => [204,   0,  51]          ,
                      -font       => $font10                  ,
                      -visible    => 0                        , );
$win->AddButton(      -name       => 'btnMACOUIdbUpdate'      ,
                      -size       => [100, 25]                ,
                      -pos        => [540, 60]                ,
                      -font       => $font10                  ,
                      -visible    => 0                        , );
# GeoIP Options
$win->AddLabel(       -name        => 'lblGeoIPLang'          ,
                      -size        => [100, 22]               ,
                      -pos         => [315, 68]               ,
                      -background  => [255, 255, 255]         ,
                      -text        => $STR{'Language'}.':'    ,
                      -font        => $font10                 ,
                      -visible     => 0                       , );
$win->AddCombobox(    -name        => 'cbGeoIPLang'           ,
                      -dropdownlist => 1                      ,
                      -vscroll     => 1                       ,
                      -size        => [ 60, 80]               ,
                      -pos         => [420, 65]               ,
                      -font        => $font10                 ,
                      -visible     => 0                       , );
$win->cbGeoIPLang->Add('en', 'de', 'es', 'fr', 'ja', 'pt-BR', 'ru', 'zh-CN');
$win->cbGeoIPLang->SetCurSel(0);
$win->AddCheckbox(    -name        => 'chGeoIPOptAll'         ,
                      -size        => [140, 22]               ,
                      -pos         => [545, 30]               ,
                      -text        => $STR{'AllDetails'}      ,
                      -font        => $font10                 ,
                      -background  => [255, 255, 255]         ,
                      -checked     => 1                       ,
                      -visible     => 0                       , );
$win->AddCheckbox(    -name        => 'chAddHeaders'          , # chGeoIPAddHeaders
                      -size        => [140, 22]               ,
                      -pos         => [545, 55]               ,
                      -text        => $STR{'Addheaders'}      ,
                      -font        => $font10                 ,
                      -background  => [255, 255, 255]         ,
                      -checked     => 1                       ,
                      -visible     => 0                       , );
$win->AddGrid(        -name         => 'gridGeoIPOpts'        ,
                      -parent       => $win                   ,
                      -pos          => [690, 30]              ,
                      -size         => [300, 65]              ,
                      -background   => [255, 255, 255]        ,
                      -columns      => 5                      ,
                      -rows         => 2                      ,
                      -fixedrows    => 0                      ,
                      -fixedcolumns => 0                      ,
                      -editable     => 1                      ,
                      -visible      => 0                      , );
$win->gridGeoIPOpts->SetGridLines(0);
$win->gridGeoIPOpts->SetCellText(   0, 0, $STR{'Continent'});
$win->gridGeoIPOpts->SetCellType(   0, 0, GVIT_CHECK );
$win->gridGeoIPOpts->SetCellCheck(  0, 0, 1);
$win->gridGeoIPOpts->SetCellFormat( 0, 0, 4);
$win->gridGeoIPOpts->SetCellText(   1, 0, $STR{'Country'});
$win->gridGeoIPOpts->SetCellType(   1, 0, GVIT_CHECK );
$win->gridGeoIPOpts->SetCellCheck(  1, 0, 1);
$win->gridGeoIPOpts->SetCellFormat( 1, 0, 4);
$win->gridGeoIPOpts->SetCellText(   0, 1, $STR{'countryCode'});
$win->gridGeoIPOpts->SetCellType(   0, 1, GVIT_CHECK );
$win->gridGeoIPOpts->SetCellCheck(  0, 1, 1);
$win->gridGeoIPOpts->SetCellFormat( 0, 1, 4);
$win->gridGeoIPOpts->SetCellText(   1, 1, $STR{'Region'});
$win->gridGeoIPOpts->SetCellType(   1, 1, GVIT_CHECK );
$win->gridGeoIPOpts->SetCellCheck(  1, 1, 1);
$win->gridGeoIPOpts->SetCellFormat( 1, 1, 4);
$win->gridGeoIPOpts->SetCellText(   0, 2, $STR{'regionCode'});
$win->gridGeoIPOpts->SetCellType(   0, 2, GVIT_CHECK );
$win->gridGeoIPOpts->SetCellCheck(  0, 2, 1);
$win->gridGeoIPOpts->SetCellFormat( 0, 2, 4);
$win->gridGeoIPOpts->SetCellText(   1, 2, $STR{'City'});
$win->gridGeoIPOpts->SetCellType(   1, 2, GVIT_CHECK );
$win->gridGeoIPOpts->SetCellCheck(  1, 2, 1);
$win->gridGeoIPOpts->SetCellFormat( 1, 2, 4);
$win->gridGeoIPOpts->SetCellText(   0, 3, $STR{'postalCode'});
$win->gridGeoIPOpts->SetCellType(   0, 3, GVIT_CHECK );
$win->gridGeoIPOpts->SetCellCheck(  0, 3, 1);
$win->gridGeoIPOpts->SetCellFormat( 0, 3, 4);
$win->gridGeoIPOpts->SetCellText(   1, 3, $STR{'GPScoord'});
$win->gridGeoIPOpts->SetCellType(   1, 3, GVIT_CHECK );
$win->gridGeoIPOpts->SetCellCheck(  1, 3, 1);
$win->gridGeoIPOpts->SetCellFormat( 1, 3, 4);
$win->gridGeoIPOpts->SetCellText(   0, 4, $STR{'tzName'});
$win->gridGeoIPOpts->SetCellType(   0, 4, GVIT_CHECK );
$win->gridGeoIPOpts->SetCellCheck(  0, 4, 1);
$win->gridGeoIPOpts->SetCellFormat( 0, 4, 4);
$win->gridGeoIPOpts->SetCellText(   1, 4, $STR{'tzOffset'});
$win->gridGeoIPOpts->SetCellType(   1, 4, GVIT_CHECK );
$win->gridGeoIPOpts->SetCellCheck(  1, 4, 1);
$win->gridGeoIPOpts->SetCellFormat( 1, 4, 4);
$win->gridGeoIPOpts->AutoSize();
# User-Agent Options
$win->AddCheckbox(    -name        => 'chUAOptAll'            ,
                      -size        => [130, 22]               ,
                      -pos         => [545, 30]               ,
                      -text        => $STR{'AllDetails'}      ,
                      -font        => $font10                 ,
                      -background  => [255, 255, 255]         ,
                      -checked     => 1                       ,
                      -visible     => 0                       , );
$win->AddGrid(        -name         => 'gridUAOpts'           ,
                      -parent       => $win                   ,
                      -pos          => [690, 30]              ,
                      -size         => [300, 65]              ,
                      -background   => [255, 255, 255]        ,
                      -columns      => 3                      ,
                      -rows         => 2                      ,
                      -fixedrows    => 0                      ,
                      -fixedcolumns => 0                      ,
                      -editable     => 1                      ,
                      -visible      => 0                      , );
$win->gridUAOpts->SetGridLines(0);
$win->gridUAOpts->SetCellText(  0, 0, $STR{'Type'});
$win->gridUAOpts->SetCellType(  0, 0, GVIT_CHECK );
$win->gridUAOpts->SetCellCheck( 0, 0, 1);
$win->gridUAOpts->SetCellFormat(0, 0, 4);
$win->gridUAOpts->SetCellText(  1, 0, $STR{'uaOS'});
$win->gridUAOpts->SetCellType(  1, 0, GVIT_CHECK );
$win->gridUAOpts->SetCellCheck( 1, 0, 1);
$win->gridUAOpts->SetCellFormat(1, 0, 4);
$win->gridUAOpts->SetCellText(  0, 1, $STR{'uaBrowser'});
$win->gridUAOpts->SetCellType(  0, 1, GVIT_CHECK );
$win->gridUAOpts->SetCellCheck( 0, 1, 1);
$win->gridUAOpts->SetCellFormat(0, 1, 4);
$win->gridUAOpts->SetCellText(  1, 1, $STR{'uaDevice'});
$win->gridUAOpts->SetCellType(  1, 1, GVIT_CHECK );
$win->gridUAOpts->SetCellCheck( 1, 1, 1);
$win->gridUAOpts->SetCellFormat(1, 1, 4);
$win->gridUAOpts->SetCellText(  0, 2, $STR{'uaLang'});
$win->gridUAOpts->SetCellType(  0, 2, GVIT_CHECK );
$win->gridUAOpts->SetCellCheck( 0, 2, 1);
$win->gridUAOpts->SetCellFormat(0, 2, 4);
$win->gridUAOpts->AutoSize();
# Credit Card to Issuing Company Options
$win->AddRadioButton( -name       => 'rbIINLocalDB'           ,
                      -size       => [200, 22]                ,
                      -pos        => [555, 30]                ,
                      -background => [255, 255, 255]          ,
                      -text       => $STR{'IINLocalDB'}       ,
                      -tip        => $STR{'IINLocalDBTip'}    ,
                      -font       => $font10                  ,
                      -checked    => 1                        ,
                      -group      => 1                        ,
                      -visible    => 0                        , );
$win->AddRadioButton( -name       => 'rbBinlist'              ,
                      -size       => [200, 22]                ,
                      -pos        => [555, 60]                ,
                      -background => [255, 255, 255]          ,
                      -text       => $STR{'use'}.' binlist.net',
                      -tip        => $STR{'BinlistTip'}       ,
                      -font       => $font10                  ,
                      -visible    => 0                        , );
# Address to GPS options
$win->AddCheckbox(    -name        => 'chAddr2GPSInc'         ,
                      -size        => [130, 22]               ,
                      -pos         => [545, 30]               ,
                      -text        => $STR{'incAddr'}         ,
                      -font        => $font10                 ,
                      -background  => [255, 255, 255]         ,
                      -checked     => 1                       ,
                      -visible     => 0                       , );
# GPS to Address Options
$win->AddLabel(       -name        => 'lblGPS2AddrZL'         ,
                      -size        => [ 75, 22]               ,
                      -pos         => [315, 68]               ,
                      -background  => [255, 255, 255]         ,
                      -text        => $STR{'ZoomLevel'}.':'   ,
                      -font        => $font10                 ,
                      -visible     => 0                       , );
$win->AddCombobox(    -name        => 'cbGPS2AddrZL'          ,
                      -dropdownlist => 1                      ,
                      -vscroll     => 1                       ,
                      -size        => [140, 80]               ,
                      -pos         => [395, 65]               ,
                      -font        => $font10                 ,
                      -visible     => 0                       , );
$win->cbGPS2AddrZL->Add($STR{'ZoomLevel3'} , $STR{'ZoomLevel5'} , $STR{'ZoomLevel8'} , $STR{'ZoomLevel10'},
                        $STR{'ZoomLevel14'}, $STR{'ZoomLevel16'}, $STR{'ZoomLevel17'}, $STR{'ZoomLevel18'});
$win->cbGPS2AddrZL->SetCurSel(7);
$win->AddCombobox(    -name        => 'cbGPS2AddrOutput'      ,
                      -dropdownlist => 1                      ,
                      -vscroll     => 1                       ,
                      -size        => [140, 80]               ,
                      -pos         => [545, 30]               ,
                      -font        => $font10                 ,
                      -visible     => 0                       , );
$win->cbGPS2AddrOutput->Add($STR{'FullAddress'} , $STR{'AllDetails'} , $STR{'AddressEl'});
$win->cbGPS2AddrOutput->SetCurSel(0);
$win->AddGrid(        -name         => 'gridGPS2AddrOpts'     ,
                      -parent       => $win                   ,
                      -pos          => [690, 30]              ,
                      -size         => [300, 65]              ,
                      -background   => [255, 255, 255]        ,
                      -columns      => 6                      ,
                      -rows         => 2                      ,
                      -fixedrows    => 0                      ,
                      -fixedcolumns => 0                      ,
                      -editable     => 1                      ,
                      -visible      => 0                      , );
$win->gridGPS2AddrOpts->SetGridLines(0);
$win->gridGPS2AddrOpts->SetCellText(   0, 0, lc($STR{'house_number'}));
$win->gridGPS2AddrOpts->SetCellType(   0, 0, GVIT_CHECK );
$win->gridGPS2AddrOpts->SetCellCheck(  0, 0, 1);
$win->gridGPS2AddrOpts->SetCellFormat( 0, 0, 4);
$win->gridGPS2AddrOpts->SetCellText(   1, 0, lc($STR{'road'}));
$win->gridGPS2AddrOpts->SetCellType(   1, 0, GVIT_CHECK );
$win->gridGPS2AddrOpts->SetCellCheck(  1, 0, 1);
$win->gridGPS2AddrOpts->SetCellFormat( 1, 0, 4);
$win->gridGPS2AddrOpts->SetCellText(   0, 1, lc($STR{'neighbourhood'}));
$win->gridGPS2AddrOpts->SetCellType(   0, 1, GVIT_CHECK );
$win->gridGPS2AddrOpts->SetCellCheck(  0, 1, 1);
$win->gridGPS2AddrOpts->SetCellFormat( 0, 1, 4);
$win->gridGPS2AddrOpts->SetCellText(   1, 1, lc($STR{'suburb'}));
$win->gridGPS2AddrOpts->SetCellType(   1, 1, GVIT_CHECK );
$win->gridGPS2AddrOpts->SetCellCheck(  1, 1, 1);
$win->gridGPS2AddrOpts->SetCellFormat( 1, 1, 4);
$win->gridGPS2AddrOpts->SetCellText(   0, 2, lc($STR{'city'}));
$win->gridGPS2AddrOpts->SetCellType(   0, 2, GVIT_CHECK );
$win->gridGPS2AddrOpts->SetCellCheck(  0, 2, 1);
$win->gridGPS2AddrOpts->SetCellFormat( 0, 2, 4);
$win->gridGPS2AddrOpts->SetCellText(   1, 2, lc($STR{'county'}));
$win->gridGPS2AddrOpts->SetCellType(   1, 2, GVIT_CHECK );
$win->gridGPS2AddrOpts->SetCellCheck(  1, 2, 1);
$win->gridGPS2AddrOpts->SetCellFormat( 1, 2, 4);
$win->gridGPS2AddrOpts->SetCellText(   0, 3, lc($STR{'region'}));
$win->gridGPS2AddrOpts->SetCellType(   0, 3, GVIT_CHECK );
$win->gridGPS2AddrOpts->SetCellCheck(  0, 3, 1);
$win->gridGPS2AddrOpts->SetCellFormat( 0, 3, 4);
$win->gridGPS2AddrOpts->SetCellText(   1, 3, lc($STR{'state'}));
$win->gridGPS2AddrOpts->SetCellType(   1, 3, GVIT_CHECK );
$win->gridGPS2AddrOpts->SetCellCheck(  1, 3, 1);
$win->gridGPS2AddrOpts->SetCellFormat( 1, 3, 4);
$win->gridGPS2AddrOpts->SetCellText(   0, 4, lc($STR{'postcode'}));
$win->gridGPS2AddrOpts->SetCellType(   0, 4, GVIT_CHECK );
$win->gridGPS2AddrOpts->SetCellCheck(  0, 4, 1);
$win->gridGPS2AddrOpts->SetCellFormat( 0, 4, 4);
$win->gridGPS2AddrOpts->SetCellText(   1, 4, lc($STR{'country'}));
$win->gridGPS2AddrOpts->SetCellType(   1, 4, GVIT_CHECK );
$win->gridGPS2AddrOpts->SetCellCheck(  1, 4, 1);
$win->gridGPS2AddrOpts->SetCellFormat( 1, 4, 4);
$win->gridGPS2AddrOpts->SetCellText(   0, 5, lc($STR{'country_code'}));
$win->gridGPS2AddrOpts->SetCellType(   0, 5, GVIT_CHECK );
$win->gridGPS2AddrOpts->SetCellCheck(  0, 5, 1);
$win->gridGPS2AddrOpts->SetCellFormat( 0, 5, 4);
$win->gridGPS2AddrOpts->SetCellText(   1, 5, lc($STR{'boundingbox'}));
$win->gridGPS2AddrOpts->SetCellType(   1, 5, GVIT_CHECK );
$win->gridGPS2AddrOpts->SetCellCheck(  1, 5, 1);
$win->gridGPS2AddrOpts->SetCellFormat( 1, 5, 4);
$win->gridGPS2AddrOpts->AutoSize();
# Distance between locations
$win->AddCheckbox(    -name       => 'chSingleLocation'       ,
                      -size       => [180, 22]                ,
                      -pos        => [550, 30]                ,
                      -text       => $STR{'chSingleLocation'}.':',
                      -font       => $font10                  ,
                      -background => [255, 255, 255]          ,
                      -checked    => 0                        ,
                      -visible    => 0                        , );
$win->AddTextfield(   -name       => 'tfSingleLocation'       ,
                      -size       => [300, 24]                ,
                      -pos        => [735, 30]                ,
                      -visible    => 0                        , );
# Customs Functions Options
$win->AddCombobox(    -name         => 'cbCFLists'            ,
                      -size         => [200,100]              ,
                      -pos          => [540, 30]              ,
                      -font         => $font10                ,
                      -dropdownlist => 1                      ,
                      -vscroll      => 1                      ,
                      -visible      => 0                      , );
$win->cbCFLists->Add( $STR{'cbCFLists'}.'...'                 , );
$win->cbCFLists->SetCurSel(0);
$win->AddButton(      -name        => 'btnCFAdd'              ,
                      -size        => [ 24, 24]               ,
                      -pos         => [750, 30]               ,
                      -bitmap      => $addCFBmp               ,
                      -tip         => $STR{'btnCFAdd'}        ,
                      -visible     => 0                       , );
$win->AddButton(      -name        => 'btnCFRem'              ,
                      -size        => [ 24, 24]               ,
                      -pos         => [776, 30]               ,
                      -bitmap      => $remCFBmp               ,
                      -tip         => $STR{'btnCFRem'}        ,
                      -disabled    => 1                       ,
                      -visible     => 0                       , );
$win->AddButton(      -name        => 'btnCFEdit'             ,
                      -size        => [ 24, 24]               ,
                      -pos         => [802, 30]               ,
                      -bitmap      => $editCFBmp              ,
                      -tip         => $STR{'btnCFEdit'}       ,
                      -disabled    => 1                       ,
                      -visible     => 0                       , );
$win->AddButton(      -name        => 'btnCFNew'              ,
                      -size        => [ 24, 24]               ,
                      -pos         => [828, 30]               ,
                      -bitmap      => $newCFBmp               ,
                      -tip         => $STR{'btnCFNew'}        ,
                      -visible     => 0                       , );
$win->AddCheckbox(    -name        => 'chCFMatchCase'         ,
                      -size        => [ 90, 20]               ,
                      -pos         => [540, 68]               ,
                      -text        => $STR{'MatchCase'}       ,
                      -font        => $font10                 ,
                      -background  => [255, 255, 255]         ,
                      -visible     => 0                       , );
$win->AddLabel(       -name        => 'lblCFTitle'            ,
                      -size        => [ 40, 22]               ,
                      -pos         => [315, 68]               ,
                      -background  => [255, 255, 255]         ,
                      -text        => $STR{'Title'}.':'       ,
                      -font        => $font10                 ,
                      -visible     => 0                       , );
$win->AddTextfield(   -name        => 'tfCFTitle'             ,
                      -size        => [175, 24]               ,
                      -pos         => [360, 65]               ,
                      -visible     => 0                       , );
$win->tfCFTitle->SetLimitText(24);
$win->AddButton(      -name        => 'btnCFSave'             ,
                      -size        => [ 24, 24]               ,
                      -pos         => [537, 65]               ,
                      -bitmap      => $saveCFBmp              ,
                      -tip         => $STR{'btnCFSave'}       ,
                      -disabled    => 1                       ,
                      -visible     => 0                       , );
$win->AddButton(      -name        => 'btnCFCancel'           ,
                      -size        => [ 24, 24]               ,
                      -pos         => [563, 65]               ,
                      -bitmap      => $cancelCFBmp            ,
                      -tip         => $STR{'btnCFCancel'}     ,
                      -visible     => 0                       , );
# Lists
$win->AddGroupbox(    -name        => 'gbList1'               ,
                      -title       => 'List 1'                ,
                      -size        => [$winWidth/3.18, $winHeight-200] ,
                      -pos         => [  3,105]               ,
                      -font        => $fontGB                 ,
                      -background  => [255, 255, 255]         , );
$win->AddButton(      -name        => 'btnList1File'          ,
                      -size        => [ 22, 22]               ,
                      -pos         => [  7,125]               ,
                      -bitmap      => $fileOpenBmp            ,
                      -tip         => $STR{'selectFile'}      , );
$win->AddButton(      -name        => 'btnList1Del'           ,
                      -size        => [ 22, 22]               ,
                      -pos         => [ 31,125]               ,
                      -bitmap      => $deleteBmp              ,
                      -tip         => $STR{'ResetContent'}    , );
$win->AddButton(      -name        => 'btnList1UseRes'        ,
                      -size        => [ 22, 22]               ,
                      -pos         => [ 55,125]               ,
                      -bitmap      => $useResBmp              ,
                      -tip         => $STR{'btnList1UseRes'}  ,
                      -disabled    => 1                       , );
$win->AddLabel(       -name        => 'lblList1Count'         ,
                      -size        => [ 60, 22]               ,
                      -pos         => [$winWidth/3.18-68, 128],
                      -background  => [255, 255, 255]         ,
                      -foreground  => [204,   0,  51]         ,
                      -text        => '0'                     ,
                      -align       => 'right'                 ,
                      -font        => $font10b                , );
$win->AddTextfield(   -name        => 'tfList1'               ,
                      -size        => [$winWidth/3.18-12, $winHeight-250] ,
                      -pos         => [  7, 150]              ,
                      -background  => [255, 255, 255]         ,
                      -font        => $fontTF                 ,
                      -multiline   => 1                       ,
                      -hscroll     => 1                       ,
                      -vscroll     => 1                       , );
$win->AddSplitter(    -name        => 'split1'                ,
                      -vertical    => 1                       ,
                      -size        => [  2, $winHeight-190]   ,
                      -pos         => [$winWidth/3.2+7,100]   ,
                      -min         => 300                     ,
                      -max         => $win->ScaleWidth()/2    ,
                      - \&split1                ,
                      -visible     => 0                       , );
$win->AddGroupbox(    -name        => 'gbList2'               ,
                      -title       => 'List 2'                ,
                      -size        => [$winWidth/3.2, $winHeight-200] ,
                      -pos         => [$winWidth/3.2+11,105]  ,
                      -font        => $fontGB                 ,
                      -background  => [255, 255, 255]         ,
                      -visible     => 0                       , );
$win->AddButton(      -name        => 'btnList2File'          ,
                      -size        => [ 22, 22]               ,
                      -pos         => [$winWidth/3.2+15,125]  ,
                      -bitmap      => $fileOpenBmp            ,
                      -tip         => $STR{'selectFile'}      ,
                      -visible     => 0                       , );
$win->AddButton(      -name        => 'btnList2Del'           ,
                      -size        => [ 22, 22]               ,
                      -pos         => [$winWidth/3.2+38,125]  ,
                      -bitmap      => $deleteBmp              ,
                      -tip         => $STR{'ResetContent'}    ,
                      -visible     => 0                       , );
$win->AddLabel(       -name        => 'lblList2Count'         ,
                      -size        => [ 60, 22]               ,
                      -pos         => [$winWidth/3.2+$winWidth/3.2-62, 128],
                      -background  => [255, 255, 255]         ,
                      -foreground  => [204,   0,  51]         ,
                      -text        => '0'                     ,
                      -align       => 'right'                 ,
                      -font        => $font10b                ,
                      -visible     => 0                       , );
$win->AddTextfield(   -name        => 'tfList2'               ,
                      -size        => [$winWidth/3.2-15, $winHeight-250] ,
                      -pos         => [$winWidth/3.2+15, 150] ,
                      -background  => [255, 255, 255]         ,
                      -font        => $fontTF                 ,
                      -multiline   => 1                       ,
                      -hscroll     => 1                       ,
                      -vscroll     => 1                       ,
                      -visible     => 0                       , );
$win->AddSplitter(    -name        => 'split2'                ,
                      -vertical    => 1                       ,
                      -size        => [  2, $winHeight-190]   ,
                      -pos         => [$winWidth/3.2+$winWidth/3.2+12,100],
                      -min         => $winWidth/2             ,
                      -max         => $winWidth-200           ,
                      - \&split2                , );
$win->AddGroupbox(    -name        => 'gbList3'               ,
                      -title       => $STR{'Results'}         ,
                      -size        => [$winWidth/2.98, $winHeight-200] ,
                      -pos         => [$winWidth/3.2+$winWidth/3.2+16,105],
                      -font        => $fontGB                 ,
                      -background  => [255, 255, 255]         , );
$win->AddButton(      -name        => 'btnList3Open'          ,
                      -size        => [ 22, 22]               ,
                      -pos         => [$winWidth/3.2+$winWidth/3.2+17,125],
                      -bitmap      => $viewReportBmp          ,
                      -tip         => $STR{'ViewReport'}      , );
$win->AddCheckbox(    -name        => 'chList3InFile'         ,
                      -size        => [100, 22]               ,
                      -pos         => [$winWidth/3.2+$winWidth/3.2+46,125],
                      -text        => $STR{'resInFile'}       ,
                      -background  => [255, 255, 255]         ,
                      -font        => $font10                 , );
$win->AddLabel(       -name        => 'lblList3Count'         ,
                      -size        => [ 60, 22]               ,
                      -pos         => [$winWidth-87, 128]     ,
                      -background  => [255, 255, 255]         ,
                      -foreground  => [204,   0,  51]         ,
                      -text        => '0'                     ,
                      -align       => 'right'                 ,
                      -font        => $font10b                , );
$win->AddTextfield(   -name        => 'tfList3'               ,
                      -size        => [$winWidth/2.98-5, $winHeight-250] ,
                      -pos         => [$winWidth/3.2+$winWidth/3.2+17, 150] ,
                      -background  => [255, 255, 255]         ,
                      -font        => $fontTF                 ,
                      -multiline   => 1                       ,
                      -hscroll     => 1                       ,
                      -vscroll     => 1                       , );
# Footer
$win->AddLabel(       -name        => 'lblFooter'             ,
                      -size        => [899, 80]               ,
                      -pos         => [  2,$winHeight-95]     ,
                      -valign      => 'top'                   ,
                      -background  => [250, 250, 250]         ,
                      -foreground  => [128, 128, 128]         , );
$win->AddLabel(       -name        => 'lblNotReady'           ,
                      -size        => [170, 22]               ,
                      -pos         => [ 10, $winHeight-75]    ,
                      -background  => [250, 250, 250]         ,
                      -foreground  => [  0, 102, 204]         ,
                      -text        => $STR{'lblNotReady'}     ,
                      -font        => $font10u                ,
                      -notify      => 1                       , );
$win->AddLabel(       -name        => 'lblPbCurr'             ,
                      -size        => [690, 20]               ,
                      -pos         => [ 10, $winHeight-85]    ,
                      -font        => $font10                 ,
                      -truncate    => 1                       ,
                      -background  => [250, 250, 250]         ,
                      -foreground  => [204,   0,  51]         ,
                      -visible     => 0                       , );
$win->AddProgressBar( -name        => 'pb'                    ,
                      -size        => [570, 20]               ,
                      -pos         => [ 10, $winHeight-65]    ,
                      -smooth      => 1                       ,
                      -visible     => 0                       , );
$win->AddLabel(       -name        => 'lblPbCount'            ,
                      -size        => [105, 20]               ,
                      -pos         => [585, $winHeight-63]    ,
                      -font        => $font10                 ,
                      -truncate    => 1                       ,
                      -background  => [250, 250, 250]         ,
                      -foreground  => [204,   0,  51]         ,
                      -visible     => 0                       , );
$win->AddButton(      -name        => 'btnProcess'            ,
                      -size        => [ 40, 40]               ,
                      -pos         => [710,$winHeight-85]     ,
                      -bitmap      => $processBmp             ,
                      -background  => [250, 250, 250]         ,
                      -tip         => $STR{'Process'}         ,
                      -disabled    => 1                       , );
$win->AddButton(      -name        => 'btnStop'               ,
                      -size        => [ 40, 40]               ,
                      -pos         => [710,$winHeight-85]     ,
                      -bitmap      => $stopBmp                ,
                      -background  => [250, 250, 250]         ,
                      -tip         => $STR{'StopProcess'}     ,
                      -visible     => 0                       , );
$win->AddButton(      -name        => 'btnWinConfig'          ,
                      -size        => [ 40, 40]               ,
                      -pos         => [755,$winHeight-85]     ,
                      -bitmap      => $config32Bmp            ,
                      -background  => [250, 250, 250]         ,
                      -tip         => $STR{'Configuration'}   , );
$win->AddButton(      -name        => 'btnHelp'               ,
                      -size        => [ 40, 40]               ,
                      -pos         => [800,$winHeight-85]     ,
                      -bitmap      => $helpBmp                ,
                      -background  => [250, 250, 250]         ,
                      -tip         => $STR{'seeDoc'}          , );
$win->AddButton(      -name        => 'btnAbout'              ,
                      -size        => [ 40, 40]               ,
                      -pos         => [845,$winHeight-85]     ,
                      -bitmap      => $aboutBmp               ,
                      -background  => [250, 250, 250]         ,
                      -tip         => $STR{'About'}           , );

#------------------------------------------------------------------------------#
# Datetime database window
#------------------------------------------------------------------------------#
my $winDTDB = Win32::GUI::Window->new(-name        => 'winDTDB'              ,
                                      -background  => [255, 255, 255]        ,
                                      -parent      => $win                   ,
                                      -text        => $STR{'DTDB'}           ,
                                      -pos         => [$winPosX, $winPosY]   ,
                                      -size        => [$winWidth, 450]       ,
                                      -hasmaximize => 1                      ,
                                      -hasminimize => 1                      ,
                                      -resizable   => 1                      ,
                                      -dialogui    => 1                      , );
$winDTDB->SetIcon($winICO);
# Datetime grid
$winDTDB->AddGrid(        -name         => 'gridDT'                ,
                          -size         => [880,180]               ,
                          -pos          => [  5,  5]               ,
                          -background   => [255, 255, 255]         ,
                          -columns      => 6                       ,
                          -fixedrows    => 1                       ,
                          -fixedcolumns => 0                       ,
                          -editable     => 0                       , );
$winDTDB->AddButton(      -name         => 'btnDTAdd'              ,
                          -size         => [ 30, 30]               ,
                          -pos          => [887,  5]               ,
                          -bitmap       => $datetimeAdd            ,
                          -tip          => $STR{'btnDTAdd'}        ,
                          -tabstop      => 1                       , );
$winDTDB->AddButton(      -name         => 'btnDTEdit'             ,
                          -size         => [ 30, 30]               ,
                          -pos          => [887, 37]               ,
                          -bitmap       => $datetimeEdit           ,
                          -tip          => $STR{'btnDTEdit'}       ,
                          -disabled     => 1                       ,
                          -tabstop      => 1                       , );
$winDTDB->AddButton(      -name         => 'btnDTDel'              ,
                          -size         => [ 30, 30]               ,
                          -pos          => [887, 69]               ,
                          -bitmap       => $datetimeDel            ,
                          -tip          => $STR{'btnDTDel'}        ,
                          -disabled     => 1                       ,
                          -tabstop      => 1                       , );
$winDTDB->AddLabel(       -name         => 'lblDefaultOutput'      ,
                          -size         => [140, 22]               ,
                          -pos          => [  5,303]               ,
                          -background   => [255, 255, 255]         ,
                          -text         => $STR{'defaultOutput'}.':',
                          -font         => $font10                 , );
$winDTDB->AddCombobox(    -name         => 'cbDefaultOutput'       ,
                          -size         => [230,100]               ,
                          -pos          => [150,300]               ,
                          -font         => $font10                 ,
                          -dropdownlist => 1                       ,
                          -vscroll      => 1                       , );

#------------------------------------------------------------------------------#
# Datetime Object window
#------------------------------------------------------------------------------#
my $winDTObj = Win32::GUI::Window->new( -name        => 'winDTObj'             ,
                                        -background  => [255, 255, 255]        ,
                                        -parent      => $win                   ,
                                        -text        => $STR{'winDTObj'}       ,
                                        -pos         => [$winPosX, $winPosY]   ,
                                        -size        => [690, 290]             ,
                                        -hasmaximize => 0                      ,
                                        -hasminimize => 0                      ,
                                        -resizable   => 0                      ,
                                        -dialogui    => 1                      , );
$winDTObj->SetIcon($winICO);
$winDTObj->AddLabel(          -name         => 'lblDTObjSample'        ,
                              -size         => [ 95, 24]               ,
                              -pos          => [  5,  8]               ,
                              -background   => [255, 255, 255]         ,
                              -text         => $STR{'sample'}.':'      ,
                              -font         => $font10                 , );
$winDTObj->AddTextfield(      -name         => 'tfDTObjSample'         ,
                              -size         => [285, 24]               ,
                              -pos          => [100,  5]               ,
                              -tabstop      => 1                       , );
$winDTObj->AddButton(         -name         => 'btnDTObjUseFirst'      ,
                              -size         => [120, 24]               ,
                              -pos          => [390,  5]               ,
                              -text         => '<- '.$STR{'useFirst'}  ,
                              -font         => $font10                 ,
                              -disabled     => 1                       , );
$winDTObj->AddLabel(          -name         => 'lblDTObjPattern'       ,
                              -size         => [ 95, 24]               ,
                              -pos          => [  5, 38]               ,
                              -background   => [255, 255, 255]         ,
                              -text         => $STR{'pattern'}.':'     ,
                              -font         => $font10                 , );
$winDTObj->AddTextfield(      -name         => 'tfDTObjPattern'        ,
                              -size         => [260, 24]               ,
                              -pos          => [100, 35]               ,
                              -tabstop      => 1                       ,
                              -disabled     => 1                       , );
$winDTObj->AddButton(         -name         => 'btnDTObjPatternInsert' ,
                              -size         => [ 24, 24]               ,
                              -pos          => [362, 35]               ,
                              -bitmap       => $left16Bmp              ,
                              -tip          => $STR{'btnPatternAdd'}   ,
                              -disabled     => 1                       , );
$winDTObj->AddCombobox(       -name         => 'cbDTObjPattern'        ,
                              -size         => [260,100]               ,
                              -pos          => [390, 35]               ,
                              -font         => $font10                 ,
                              -dropdownlist => 1                       ,
                              -vscroll      => 1                       ,
                              -disabled     => 1                       , );
$winDTObj->cbDTObjPattern->Add($STR{'pattern1'} , $STR{'pattern2'} , $STR{'pattern3'} ,
                               $STR{'pattern4'} , $STR{'pattern5'} , $STR{'pattern6'} ,
                               $STR{'pattern7'} , $STR{'pattern8'} , $STR{'pattern9'} ,
                               $STR{'pattern10'}, $STR{'pattern11'}, $STR{'pattern22'}, $STR{'pattern12'},
                               $STR{'pattern13'}, $STR{'pattern14'}, $STR{'pattern15'},
                               $STR{'pattern16'}, $STR{'pattern17'}, $STR{'pattern18'},
                               $STR{'pattern19'}, $STR{'pattern20'}, $STR{'pattern21'}, );
$winDTObj->cbDTObjPattern->SetCurSel(0);
$winDTObj->AddButton(         -name         => 'btnDTObjPatternHelp'   ,
                              -size         => [ 24, 24]               ,
                              -pos          => [652, 35]               ,
                              -bitmap       => $help16Bmp              ,
                              -tip          => $STR{'seeDoc'}          , );
$winDTObj->AddLabel(          -name         => 'lblDTObjRegex'         ,
                              -size         => [ 95, 24]               ,
                              -pos          => [  5, 68]               ,
                              -background   => [255, 255, 255]         ,
                              -text         => $STR{'Regex'}.':'       ,
                              -font         => $font10                 , );
$winDTObj->AddLabel(          -name         => 'lblDTObjRegexOk'       ,
                              -size         => [287, 26]               ,
                              -pos          => [ 99, 64]               ,
                              -background   => [  0, 255,   0]         ,
                              -visible      => 0                       , );
$winDTObj->AddLabel(          -name         => 'lblDTObjRegexErr'      ,
                              -size         => [287, 26]               ,
                              -pos          => [ 99, 64]               ,
                              -background   => [255,   0,   0]         ,
                              -visible      => 0                       , );
$winDTObj->AddLabel(          -name         => 'lblDTObjRegexWarn'     ,
                              -size         => [287, 26]               ,
                              -pos          => [ 99, 64]               ,
                              -background   => [255, 255,   0]         ,
                              -visible      => 0                       , );
$winDTObj->AddTextfield(      -name         => 'tfDTObjRegex'          ,
                              -size         => [285, 24]               ,
                              -pos          => [100, 65]               ,
                              -tabstop      => 1                       ,
                              -disabled     => 1                       , );
$winDTObj->AddCheckbox(       -name         => 'chDTObjRegexAuto'      ,
                              -size         => [150, 22]               ,
                              -pos          => [390, 65]               ,
                              -text         => $STR{'matchPattern'}    ,
                              -background   => [255, 255, 255]         ,
                              -font         => $font10                 ,
                              -checked      => 1                       , );
$winDTObj->AddLabel(          -name         => 'lblDTObjTZ'            ,
                              -size         => [ 95, 22]               ,
                              -pos          => [  5, 98]               ,
                              -background   => [255, 255, 255]         ,
                              -text         => $STR{'timezone'}.':'    ,
                              -font         => $font10                 , );
$winDTObj->AddRadioButton(    -name         => 'rbDTObjTZLocal'        ,
                              -size         => [ 70, 22]               ,
                              -pos          => [100, 95]               ,
                              -background   => [255, 255, 255]         ,
                              -text         => $STR{'Local'}           ,
                              -font         => $font10                 ,
                              -checked      => 1                       ,
                              -group        => 1                       , );
$winDTObj->AddRadioButton(    -name         => 'rbDTObjTZUTC'          ,
                              -size         => [ 70, 22]               ,
                              -pos          => [100,125]               ,
                              -background   => [255, 255, 255]         ,
                              -text         => $STR{'UTC'}             ,
                              -font         => $font10                 , );
$winDTObj->AddRadioButton(    -name         => 'rbDTObjTZOtherOffset'  ,
                              -size         => [110, 22]               ,
                              -pos          => [175, 95]               ,
                              -background   => [255, 255, 255]         ,
                              -text         => $STR{'otherOffset'}.':' ,
                              -font         => $font10                 , );
$winDTObj->AddCombobox(       -name         => 'cbDTObjTZOffset'       ,
                              -size         => [ 65,100]               ,
                              -pos          => [290, 95]               ,
                              -font         => $font10                 ,
                              -dropdownlist => 1                       ,
                              -vscroll      => 1                       , );
$winDTObj->cbDTObjTZOffset->Add('+1200','+1130','+1100','+1030','+1000','+0900','+0930','+0800','+0700',
                                '+0630','+0600','+0530','+0500','+0430','+0400','+0330','+0300','+0200',
                                '+0100','+0000','-0100','-0200','-0300','-0330','-0400','-0500','-0600',
                                '-0700','-0800','-0830','-0900','-0930','-1000','-1100','-1200', );
$winDTObj->cbDTObjTZOffset->SetCurSel(19);
$winDTObj->AddRadioButton(    -name         => 'rbDTObjTZOtherName'    ,
                              -size         => [110, 22]               ,
                              -pos          => [175,125]               ,
                              -background   => [255, 255, 255]         ,
                              -text         => $STR{'otherName'}.':'   ,
                              -font         => $font10                 , );
$winDTObj->AddCombobox(       -name         => 'cbDTObjTZName'         ,
                              -size         => [260,100]               ,
                              -pos          => [290,125]               ,
                              -font         => $font10                 ,
                              -dropdownlist => 1                       ,
                              -vscroll      => 1                       , );
$winDTObj->AddLabel(          -name         => 'lblDTObjParsed'        ,
                              -size         => [ 95, 22]               ,
                              -pos          => [  5,158]               ,
                              -background   => [255, 255, 255]         ,
                              -text         => $STR{'Parsed'}.':'      ,
                              -font         => $font10                 , );
$winDTObj->AddLabel(          -name         => 'lblDTObjParsedData'    ,
                              -size         => [400, 22]               ,
                              -pos          => [100,158]               ,
                              -background   => [255, 255, 255]         ,
                              -foreground   => [204,   0,  51]         ,
                              -font         => $font10                 , );
$winDTObj->AddLabel(          -name         => 'lblDTObjUseAs'         ,
                              -size         => [ 95, 22]               ,
                              -pos          => [  5,188]               ,
                              -background   => [255, 255, 255]         ,
                              -text         => $STR{'useAs'}.':'       ,
                              -font         => $font10                 , );
$winDTObj->AddCombobox(       -name         => 'cbDTObjUseAs'          ,
                              -size         => [ 80,100]               ,
                              -pos          => [100,185]               ,
                              -font         => $font10                 ,
                              -dropdownlist => 1                       ,
                              -vscroll      => 1                       , );
$winDTObj->cbDTObjUseAs->Add( $STR{'Input'}, $STR{'Output'}, $STR{'Both'}, $STR{'None'},);
$winDTObj->cbDTObjUseAs->SetCurSel(0);
$winDTObj->AddLabel(          -name         => 'lblDTObjComment'       ,
                              -size         => [ 95, 24]               ,
                              -pos          => [280,188]               ,
                              -background   => [255, 255, 255]         ,
                              -text         => $STR{'comment'}.':'     ,
                              -font         => $font10                 , );
$winDTObj->AddTextfield(      -name         => 'tfDTObjComment'        ,
                              -size         => [285, 24]               ,
                              -pos          => [380,185]               ,
                              -tabstop      => 1                       , );
$winDTObj->AddButton(         -name         => 'btnDTObjNotReady'      ,
                              -size         => [ 30, 30]               ,
                              -pos          => [255,220]               ,
                              -text         => '?'                     ,
                              -font         => $font10                 , );
$winDTObj->AddButton(         -name         => 'btnDTObjAdd'           ,
                              -size         => [ 60, 30]               ,
                              -pos          => [295,220]               ,
                              -text         => $STR{'Add'}             ,
                              -font         => $font10                 ,
                              -disabled     => 1                       ,
                              -visible      => 0                       , );
$winDTObj->AddButton(         -name         => 'btnDTObjEdit'          ,
                              -size         => [ 60, 30]               ,
                              -pos          => [295,220]               ,
                              -text         => $STR{'Edit'}            ,
                              -font         => $font10                 ,
                              -disabled     => 1                       ,
                              -visible      => 0                       , );
$winDTObj->AddButton(         -name         => 'btnDTObjCancel'        ,
                              -size         => [ 70, 30]               ,
                              -pos          => [360,220]               ,
                              -text         => $STR{'Cancel'}          ,
                              -font         => $font10                 , );

#------------------------------------------------------------------------------#
# Config window
#------------------------------------------------------------------------------#
my $winConfig = Win32::GUI::DialogBox->new( -name        => 'winConfig'             ,
                                            -parent      => $win                    ,
                                            -text        => $STR{'Settings'}        ,
                                            -pos         => [$winPosX, $winPosY]    ,
                                            -size        => [750, 385]              ,
                                            -background  => [255, 255, 255]         ,
                                            -hasmaximize => 0                       ,
                                            -hasminimize => 0                       ,
                                            -helpbutton  => 0                       ,
                                            -resizable   => 0                       ,
                                            -dialogui    => 1                       , );
$winConfig->SetIcon($winICO);
$winConfig->AddLabel(     -name         => 'lblLogo'             ,
                          -size         => [128,128]             ,
                          -pos          => [  0,  5]             ,
                          -bitmap       => $config128Bmp         ,
                          -background   => [255, 255, 255]       , );
# Tabstrip
$winConfig->AddTabStrip(            -name         => 'configTab'      ,
                                    -size         => [605,350]        ,
                                    -pos          => [140,  5]        ,
                                    -tabstop      => 1                ,
                                    -font         => $font10          ,
                                    -background   => [255, 255, 255]  , );
$winConfig->configTab->InsertItem(  -text         => $STR{'General'}  , );
$winConfig->configTab->InsertItem(  -text         => $STR{'Databases'} , );
$winConfig->configTab->InsertItem(  -text         => 'XL-ToolKit '.$STR{'Databases'}, );
# General tab - Tool Section
$winConfig->AddLabel(       -name         => 'lblToolShadowT'        ,
                            -size         => [ 80, 22]               ,
                            -pos          => [151, 36]               ,
                            -foreground   => [180, 180, 180]         ,
                            -background   => [255, 255, 255]         ,
                            -text         => $STR{'Tool'}.':'        ,
                            -font         => $fontGB2                , );
$winConfig->AddLabel(       -name         => 'lblToolT'              ,
                            -size         => [ 80, 22]               ,
                            -pos          => [150, 35]               ,
                            -addstyle     => 11                      , # Transparent
                            -foreground   => [204,   0,  51]         ,
                            -text         => $STR{'Tool'}.':'        ,
                            -font         => $fontGB2                , );
$winConfig->AddButton(      -name         => 'btnExportLang'         ,
                            -size         => [125, 24]               ,
                            -pos          => [150, 68]               ,
                            -text         => $STR{'Export'}.'Lang.ini',
                            -font         => $font10                 , );
$winConfig->AddButton(      -name         => 'btnOpenUserDir'        ,
                            -size         => [125, 24]               ,
                            -pos          => [285, 68]               ,
                            -text         => $STR{'OpenUserDir'}.'...',
                            -font         => $font10                 , );
$winConfig->AddButton(      -name         => 'btnCheckUpdate'        ,
                            -size         => [125, 24]               ,
                            -pos          => [150, 98]               ,
                            -text         => $STR{'checkUpdate'}     ,
                            -font         => $font10                 , );
$winConfig->AddCheckbox(    -name         => 'chAutoUpdate'          ,
                            -size         => [200, 20]               ,
                            -pos          => [285,101]               ,
                            -text         => $STR{'AutoUpdateTip'}   ,
                            -background   => [255, 255, 255]         ,
                            -font         => $font10                 ,
                            -tabstop      => 1                       ,
                            -checked      => 1                       , );
# General tab - Functions section
$winConfig->AddLabel(       -name         => 'lblOptFunctionsShadowT',
                            -size         => [120, 22]               ,
                            -pos          => [151,141]               ,
                            -foreground   => [180, 180, 180]         ,
                            -background   => [255, 255, 255]         ,
                            -text         => $STR{'OptFunctions'}.':',
                            -font         => $fontGB2                , );
$winConfig->AddLabel(       -name         => 'lblOptFunctionsT'      ,
                            -size         => [120, 22]               ,
                            -pos          => [150,140]               ,
                            -addstyle     => 11                      , # Transparent
                            -foreground   => [204,   0,  51]         ,
                            -text         => $STR{'OptFunctions'}.':',
                            -font         => $fontGB2                , );
$winConfig->AddCheckbox(    -name         => 'chFullScreen'          ,
                            -size         => [150, 20]               ,
                            -pos          => [285,142]               ,
                            -text         => $STR{'chFullScreen'}    ,
                            -background   => [255, 255, 255]         ,
                            -font         => $font10                 , );
$winConfig->AddCheckbox(    -name         => 'chRememberPos'         ,
                            -size         => [195, 20]               ,
                            -pos          => [490,142]               ,
                            -text         => $STR{'chRememberPos'}   ,
                            -background   => [255, 255, 255]         ,
                            -font         => $font10                 , );
$winConfig->AddLabel(       -name         => 'lblMaxSize1'           ,
                            -size         => [130, 22]               ,
                            -pos          => [150,173]               ,
                            -background   => [255, 255, 255]         ,
                            -text         => $STR{'MaxSize'}.':'     ,
                            -font         => $font10                 , );
$winConfig->AddTextfield(   -name         => 'tfMaxSize'             ,
                            -size         => [ 60, 22]               ,
                            -pos          => [285,170]               , );
$winConfig->AddLabel(       -name         => 'lblMaxSize2'           ,
                            -size         => [ 80, 22]               ,
                            -pos          => [350,173]               ,
                            -background   => [255, 255, 255]         ,
                            -text         => $STR{'chars'}           ,
                            -font         => $font10                 , );
$winConfig->AddButton(      -name         => 'btnChooseFont'         ,
                            -size         => [125, 24]               ,
                            -pos          => [490,170]               ,
                            -text         => $STR{'chooseFont'}.'...',
                            -font         => $font10                 , );
$winConfig->AddLabel(       -name         => 'lblLocalTZ'            ,
                            -size         => [120, 22]               ,
                            -pos          => [150,203]               ,
                            -background   => [255, 255, 255]         ,
                            -text         => $STR{'localTimezone'}.':',
                            -font         => $font10                 , );
$winConfig->AddCombobox(    -name         => 'cbLocalTZ'             ,
                            -size         => [230,100]               ,
                            -pos          => [285,200]               ,
                            -font         => $font10                 ,
                            -dropdownlist => 1                       ,
                            -vscroll      => 1                       , );
$winConfig->AddLabel(       -name         => 'lblOutputLang'         ,
                            -size         => [120, 22]               ,
                            -pos          => [150,233]               ,
                            -background   => [255, 255, 255]         ,
                            -text         => $STR{'defaultLang'}.':' ,
                            -font         => $font10                 , );
$winConfig->AddCombobox(    -name         => 'cbDefaultLang'         ,
                            -size         => [140,100]               ,
                            -pos          => [285,230]               ,
                            -font         => $font10                 ,
                            -dropdownlist => 1                       ,
                            -vscroll      => 1                       , );
$winConfig->AddLabel(       -name         => 'lblOutputCharset'      ,
                            -size         => [120, 22]               ,
                            -pos          => [490,233]               ,
                            -background   => [255, 255, 255]         ,
                            -text         => $STR{'outputCharset'}.':',
                            -font         => $font10                 , );
$winConfig->AddCombobox(    -name         => 'cbOutputCharset'       ,
                            -size         => [100,100]               ,
                            -pos          => [615,230]               ,
                            -font         => $font10                 ,
                            -dropdownlist => 1                       ,
                            -vscroll      => 1                       , );
$winConfig->cbOutputCharset->Add( 'cp1252'     , 'iso-8859-1' , 'iso-8859-2' , 'iso-8859-3' ,
                                  'iso-8859-4' , 'iso-8859-5' , 'iso-8859-6' , 'iso-8859-7' ,
                                  'iso-8859-8' , 'iso-8859-9' , 'iso-8859-10', 'iso-8859-11', 
                                  'iso-8859-13', 'iso-8859-14', 'iso-8859-15', 'iso-8859-16', );
$winConfig->AddLabel(       -name        => 'lblNsLookupTO1'        ,
                            -size        => [130, 22]               ,
                            -pos         => [150,263]               ,
                            -background  => [255, 255, 255]         ,
                            -text        => $STR{'NsLookupTO1'}.':' ,
                            -font        => $font10                 , );
$winConfig->AddTextfield(   -name        => 'tfLookupTO'            ,
                            -size        => [ 30, 22]               ,
                            -pos         => [285,260]               , );
$winConfig->AddLabel(       -name        => 'lblNsLookupTO2'        ,
                            -size        => [ 70, 22]               ,
                            -pos         => [320,263]               ,
                            -background  => [255, 255, 255]         ,
                            -text        => lc($STR{'seconds'})     ,
                            -font        => $font10                 , );
$winConfig->AddLabel(       -name        => 'lblUserAgent'          ,
                            -size        => [130, 22]               ,
                            -pos         => [150,293]               ,
                            -background  => [255, 255, 255]         ,
                            -text        => $STR{'UserAgent'}.':'   ,
                            -font        => $font10                 , );
$winConfig->AddTextfield(   -name        => 'tfUserAgent'           ,
                            -size        => [430, 22]               ,
                            -pos         => [285,290]               , );
$winConfig->AddLabel(       -name        => 'lblNoResultOpt'        ,
                            -size        => [130, 22]               ,
                            -pos         => [150,323]               ,
                            -background  => [255, 255, 255]         ,
                            -text        => $STR{'NoResultOpt'}.':' ,
                            -font        => $font10                 , );
$winConfig->AddRadioButton( -name        => 'rbNoResultOpt1'        ,
                            -size        => [150, 22]               ,
                            -pos         => [285,320]               ,
                            -background  => [255, 255, 255]         ,
                            -text        => $STR{'NoResultOpt1'}    ,
                            -tip         => $STR{'NoResultOpt1Tip'} ,
                            -font        => $font10                 ,
                            -checked     => 1                       ,
                            -group       => 1                       , );
$winConfig->AddRadioButton( -name        => 'rbNoResultOpt2'        ,
                            -size        => [195, 22]               ,
                            -pos         => [440,320]               ,
                            -background  => [255, 255, 255]         ,
                            -text        => $STR{'NoResultOpt2'}    ,
                            -tip         => $STR{'NoResultOpt2Tip'} ,
                            -font        => $font10                 ,
                            -checked     => 0                       , );
# Database tab - MAC OUI Database section
$winConfig->AddLabel(       -name        => 'lblMACOUIDBShadowT'    ,
                            -size        => [250, 22]               ,
                            -pos         => [151, 36]               ,
                            -foreground  => [180, 180, 180]         ,
                            -background  => [255, 255, 255]         ,
                            -text        => $STR{'OUIDB'}.':'       ,
                            -font        => $fontGB2                ,
                            -visible     => 0                       , );
$winConfig->AddLabel(       -name        => 'lblMACOUIDBT'          ,
                            -size        => [250, 22]               ,
                            -pos         => [150, 35]               ,
                            -addstyle    => 11                      , # Transparent
                            -foreground  => [204,   0,  51]         ,
                            -text        => $STR{'OUIDB'}.':'       ,
                            -font        => $fontGB2                ,
                            -visible     => 0                       , );
$winConfig->AddCheckbox(    -name        => 'chMACOUIDBAutoUpt'     ,
                            -size        => [220, 20]               ,
                            -pos         => [495, 38]               ,
                            -background  => [255, 255, 255]         ,
                            -text        => $STR{'AutoUpdateTip'}   ,
                            -font        => $font10                 ,
                            -visible     => 0                       , );
$winConfig->AddTextfield(   -name        => 'tfMACOUIDB'            ,
                            -size        => [532, 22]               ,
                            -pos         => [150, 68]               ,
                            -visible     => 0                       , );
$winConfig->AddButton(      -name        => 'btnMACOUIDB'           ,
                            -size        => [ 22, 22]               ,
                            -pos         => [685, 68]               ,
                            -bitmap      => $fileOpenBmp            ,
                            -tip         => $STR{'selectDBFile'}    ,
                            -visible     => 0                       , );
$winConfig->AddButton(      -name        => 'btnMACOUIDBUpt'        ,
                            -size        => [ 22, 22]               ,
                            -pos         => [708, 68]               ,
                            -bitmap      => $downloadBmp            ,
                            -tip         => $STR{'downloadDB'}      ,
                            -visible     => 0                       , );
# Database tab - GeoIP Database section
$winConfig->AddLabel(       -name        => 'lblGeoIPDBShadowT'     ,
                            -size        => [250, 22]               ,
                            -pos         => [151, 99]               ,
                            -foreground  => [180, 180, 180]         ,
                            -background  => [255, 255, 255]         ,
                            -text        => $STR{'GeoIP'}.':'       ,
                            -font        => $fontGB2                ,
                            -visible     => 0                       , );
$winConfig->AddLabel(       -name        => 'lblGeoIPDBT'           ,
                            -size        => [250, 22]               ,
                            -pos         => [150, 98]               ,
                            -addstyle    => 11                      , # Transparent
                            -foreground  => [204,   0,  51]         ,
                            -text        => $STR{'GeoIP'}.':'       ,
                            -font        => $fontGB2                ,
                            -visible     => 0                       , );
$winConfig->AddTextfield(   -name        => 'tfGeoIPDB'             ,
                            -size        => [532, 22]               ,
                            -pos         => [150,128]               ,
                            -visible     => 0                       , );
$winConfig->AddButton(      -name        => 'btnGeoIPDB'            ,
                            -size        => [ 22, 22]               ,
                            -pos         => [685,128]               ,
                            -bitmap      => $fileOpenBmp            ,
                            -tip         => $STR{'selectDBFile'}    ,
                            -visible     => 0                       , );
$winConfig->AddLabel(       -name        => 'lblGeoIPNotice'        ,
                            -size        => [585, 22]               ,
                            -pos         => [150,155]               ,
                            -background  => [255, 255, 255]         ,
                            -foreground  => [ 80,  80,  80]         ,
                            -text        => $STR{'GeoIPNotice'}     ,
                            -font        => $font10                 , );
# Database tab - Issuer Identification Number (IIN) Database section
$winConfig->AddLabel(       -name        => 'lblIINDBShadowT'       ,
                            -size        => [250, 22]               ,
                            -pos         => [151,180]               ,
                            -foreground  => [180, 180, 180]         ,
                            -background  => [255, 255, 255]         ,
                            -text        => $STR{'IINLocalDB'}.':'  ,
                            -font        => $fontGB2                ,
                            -visible     => 0                       , );
$winConfig->AddLabel(       -name        => 'lblIINDBT'             ,
                            -size        => [250, 22]               ,
                            -pos         => [150,179]               ,
                            -addstyle    => 11                      , # Transparent
                            -foreground  => [204,   0,  51]         ,
                            -text        => $STR{'IINLocalDB'}.':'  ,
                            -font        => $fontGB2                ,
                            -visible     => 0                       , );
$winConfig->AddTextfield(   -name        => 'tfIINDB'               ,
                            -size        => [532, 22]               ,
                            -pos         => [150,210]               ,
                            -visible     => 0                       , );
$winConfig->AddButton(      -name        => 'btnIINDB'              ,
                            -size        => [ 22, 22]               ,
                            -pos         => [685,210]               ,
                            -bitmap      => $fileOpenBmp            ,
                            -tip         => $STR{'selectDBFile'}    ,
                            -visible     => 0                       , );
$winConfig->AddButton(      -name        => 'btnIINDBUpt'           ,
                            -size        => [ 22, 22]               ,
                            -pos         => [708,210]               ,
                            -bitmap      => $downloadBmp            ,
                            -tip         => $STR{'downloadDB'}      ,
                            -visible     => 0                       , );
# Database tab - OpenStreetMap (OSM) Database section
$winConfig->AddLabel(       -name        => 'lblOSMDBShadowT'       ,
                            -size        => [250, 22]               ,
                            -pos         => [151,241]               ,
                            -foreground  => [180, 180, 180]         ,
                            -background  => [255, 255, 255]         ,
                            -text        => $STR{'OSMDB'}.':'       ,
                            -font        => $fontGB2                ,
                            -visible     => 0                       , );
$winConfig->AddLabel(       -name        => 'lblOSMDBT'             ,
                            -size        => [250, 22]               ,
                            -pos         => [150,240]               ,
                            -addstyle    => 11                      , # Transparent
                            -foreground  => [204,   0,  51]         ,
                            -text        => $STR{'OSMDB'}.':'       ,
                            -font        => $fontGB2                ,
                            -visible     => 0                       , );
$winConfig->AddTextfield(   -name        => 'tfOSMDB'               ,
                            -size        => [532, 22]               ,
                            -pos         => [150,270]               ,
                            -visible     => 0                       , );
$winConfig->AddButton(      -name        => 'btnOSMDB'              ,
                            -size        => [ 22, 22]               ,
                            -pos         => [685,270]               ,
                            -bitmap      => $fileOpenBmp            ,
                            -tip         => $STR{'selectDBFile'}    ,
                            -visible     => 0                       , );
$winConfig->AddButton(      -name        => 'btnNewOSMDB'           ,
                            -size        => [ 22, 22]               ,
                            -pos         => [708,270]               ,
                            -bitmap      => $fileNewBmp             ,
                            -tip         => $STR{'createDBTable'}   ,
                            -visible     => 0                       , );
$winConfig->AddLabel(       -name        => 'lblOSMEmail'           ,
                            -size        => [ 75, 22]               ,
                            -pos         => [150,303]               ,
                            -background  => [255, 255, 255]         ,
                            -text        => $STR{'Email'}.':'       ,
                            -font        => $font10                 , );
$winConfig->AddTextfield(   -name        => 'tfOSMEmailDB'          ,
                            -size        => [300, 22]               ,
                            -pos         => [230,300]               ,
                            -visible     => 0                       , );
$winConfig->AddLabel(       -name        => 'lblOSMNotice'          ,
                            -size        => [585, 22]               ,
                            -pos         => [150,328]               ,
                            -background  => [255, 255, 255]         ,
                            -foreground  => [ 80,  80,  80]         ,
                            -text        => $STR{'OSMNotice'}       ,
                            -font        => $font10                 , );
# XL-ToolKit Database tab - XL-Whois database section
$winConfig->AddLabel(       -name        => 'lblXLWHOISDBShadowT'   ,
                            -size        => [250, 22]               ,
                            -pos         => [151, 36]               ,
                            -foreground  => [180, 180, 180]         ,
                            -background  => [255, 255, 255]         ,
                            -text        => $STR{'XLWhois'}.':'     ,
                            -font        => $fontGB2                ,
                            -visible     => 0                       , );
$winConfig->AddLabel(       -name        => 'lblXLWHOISDBT'         ,
                            -size        => [250, 22]               ,
                            -pos         => [150, 35]               ,
                            -addstyle    => 11                      , # Transparent
                            -foreground  => [204,   0,  51]         ,
                            -text        => $STR{'XLWhois'}.':'     ,
                            -font        => $fontGB2                ,
                            -visible     => 0                       , );
$winConfig->AddTextfield(   -name        => 'tfXLWHOISDB'           ,
                            -size        => [532, 22]               ,
                            -pos         => [150, 68]               ,
                            -visible     => 0                       , );
$winConfig->AddButton(      -name        => 'btnXLWHOISDB'          ,
                            -size        => [ 22, 22]               ,
                            -pos         => [685, 68]               ,
                            -bitmap      => $fileOpenBmp            ,
                            -tip         => $STR{'selectDBFile'}    ,
                            -visible     => 0                       , );
# XL-ToolKit Database tab - Datetime database section
$winConfig->AddLabel(       -name        => 'lblDTDBShadowT'        ,
                            -size        => [250, 22]               ,
                            -pos         => [151,104]               ,
                            -foreground  => [180, 180, 180]         ,
                            -background  => [255, 255, 255]         ,
                            -text        => $STR{'Datetime'}.':'    ,
                            -font        => $fontGB2                ,
                            -visible     => 0                       , );
$winConfig->AddLabel(       -name        => 'lblDTDBT'              ,
                            -size        => [250, 22]               ,
                            -pos         => [150,103]               ,
                            -addstyle    => 11                      , # Transparent
                            -foreground  => [204,   0,  51]         ,
                            -text        => $STR{'Datetime'}.':'    ,
                            -font        => $fontGB2                ,
                            -visible     => 0                       , );
$winConfig->AddTextfield(   -name        => 'tfDTDB'                ,
                            -size        => [532, 22]               ,
                            -pos         => [150,133]               ,
                            -visible     => 0                       , );
$winConfig->AddButton(      -name        => 'btnDTDB'               ,
                            -size        => [ 22, 22]               ,
                            -pos         => [685,133]               ,
                            -bitmap      => $fileOpenBmp            ,
                            -tip         => $STR{'selectDBFile'}    ,
                            -visible     => 0                       , );
$winConfig->AddButton(      -name        => 'btnDTDBUpt'            ,
                            -size        => [ 22, 22]               ,
                            -pos         => [708,133]               ,
                            -bitmap      => $downloadBmp            ,
                            -tip         => $STR{'downloadDB'}      ,
                            -visible     => 0                       , );

#------------------------------------------------------------------------------#
# Simple Progress window
#------------------------------------------------------------------------------#
my $winPb  = Win32::GUI::DialogBox->new(-name        => 'winPb'                   ,
                                        -parent      => $winConfig                ,
                                        -text        => $STR{'winPb'}             ,
                                        -pos         => [$winPosX, $winPosY]      ,
                                        -size        => [600, 170]                ,
                                        -background  => [255, 255, 255]           ,
                                        -hasmaximize => 0                         ,
                                        -hasminimize => 1                         ,
                                        -helpbutton  => 0                         ,
                                        -resizable   => 0                         ,
                                        -dialogui    => 1                         , );
$winPb->SetIcon($winICO);
$winPb->AddLabel(       -name        => 'lblLogo2'       ,
                        -size        => [128,128]        ,
                        -pos         => [  0,  5]        ,
                        -bitmap      => $logo128Bmp      , );
$winPb->AddLabel(       -name        => 'lblPbCurr'      ,
                        -size        => [460, 22]        ,
                        -pos         => [140, 25]        ,
                        -font        => $font10          ,
                        -truncate    => 1                ,
                        -background  => [255, 255, 255]  ,
                        -foreground  => [  0, 102, 204]  , );
$winPb->AddProgressBar( -name        => 'pbWinPb'        ,
                        -size        => [355, 22]        ,
                        -pos         => [140, 50]        ,
                        -smooth      => 1                , );
$winPb->AddLabel(       -name        => 'lblCount'       ,
                        -size        => [100, 22]        ,
                        -pos         => [500, 52]        ,
                        -font        => $font10          ,
                        -truncate    => 1                ,
                        -background  => [255, 255, 255]  ,
                        -foreground  => [  0, 102, 204]  , );
$winPb->AddButton(      -name        => 'btnCancel'      ,
                        -text        => $STR{'Cancel'}   ,
                        -font        => $font10          ,
                        -size        => [ 80, 30]        ,
                        -pos         => [300, 95]        ,
                        -cancel      => 1                , );

#------------------------------------------------------------------------------#
# Starting program
#------------------------------------------------------------------------------#
$win->cbLists->SetCurSel(0);
&cbLists_Change();
# Set Datetime grid header
$winDTDB->gridDT->SetCellText(0, 0, $STR{'sample'}  );
$winDTDB->gridDT->SetCellText(0, 1, $STR{'pattern'} );
$winDTDB->gridDT->SetCellText(0, 2, $STR{'Regex'}   );
$winDTDB->gridDT->SetCellText(0, 3, $STR{'timezone'});
$winDTDB->gridDT->SetCellText(0, 4, $STR{'useAs'}   );
$winDTDB->gridDT->SetCellText(0, 5, $STR{'comment'} );
# List of timezone
my @listTZ = DateTime::TimeZone->all_names;
foreach (@listTZ) { $winConfig->cbLocalTZ->Add($_); $winDTObj->cbDTObjTZName->Add($_); }
$winDTObj->cbDTObjTZName->SetCurSel(0);
# List of language
my @lang = DateTime::Locale->ids();
foreach (sort @lang) { $winConfig->cbDefaultLang->Add($_); }
# Load configuration and databases
if (-T $CONFIG_FILE) {
  &loadConfig(\%CONFIG, $CONFIG_FILE, \$winConfig, \$winDTDB, \$win, \$fontTF);
  # Load the Datetime Database
  if ($CONFIG{'DT_DB_FILE'} and -f $CONFIG{'DT_DB_FILE'} and &validSQLiteDB($CONFIG{'DT_DB_FILE'}, 'DT')) {
    &loadDTDB(\$winDTDB, \$winConfig, \$win, \%STR);
    &cbInputDTFormatAddITems();
    $win->cbInputDTFormat->SetCurSel(0);
    &cbOutputDTFormatAddITems();
    $win->cbOutputDTFormat->SetCurSel(0);
    # Default output format
    if (exists($CONFIG{'DEFAULT_OUTPUT'})) { $winDTDB->cbDefaultOutput->SetCurSel($CONFIG{'DEFAULT_OUTPUT'}); }
    else                                   { $winDTDB->cbDefaultOutput->SetCurSel(0); }
  # If don't exist, ask to download it
  } else {
    threads->create(sub {
      # Yes (6), No (7)
      my $answer = Win32::GUI::MessageBox($win, "$STR{'DTDB'} (DT.db) $STR{'NotExistDownload'}?", $STR{'DTDB'}, 0x1024);
      # Answer is Yes
      if ($answer == 6) {
        my ($status, $return) = &downloadDB(\$win, 'DT', $STR{'DTDB'}, "$USERDIR\\DT.db", 'le-tools.com', \$HOURGLASS,
                                            \$ARROW, \%CONFIG, $CONFIG_FILE, \$winConfig, \$winDTDB, \$winPb, \$win, \%STR);
        if ($status) { Win32::GUI::MessageBox($win, "$STR{'DTDB'} $STR{'HasBeenUpdated'}", "XL-Tools $VERSION", 0x40040); }
        else         { Win32::GUI::MessageBox($win, $return, $STR{'Error'}, 0x40010); }
      }
    });
  }
  # Create OSM database if it doesn't exist
  if (!$CONFIG{'OSM_DB'} or !-f $CONFIG{'OSM_DB'} or !&validSQLiteDB($CONFIG{'OSM_DB'}, 'GPS2ADDR')) {
    my $OSMDBFile = "$USERDIR\\OSM.db";
    my $OSMDir    = "$USERDIR\\osm";
    if ($OSMDBFile and &createOSMDB($OSMDBFile)) {
      mkdir($OSMDir) if !-d $OSMDir; # Create subfolder for JSON file
      $winConfig->tfOSMDB->Text($OSMDBFile);
    }
  }
  # Check update for tool and databases?
  if ($CONFIG{'TOOL_AUTO_UPDATE'} or $CONFIG{'MACOUI_DB_AUTO_UPDATE'}) {
    $THR_UPDATE = threads->create(sub { &updateAll($VERSION, $USERDIR, \$HOURGLASS, \$ARROW, \$winConfig,
                                                   \%CONFIG, $CONFIG_FILE, \$winDTDB, \$winPb, \$win, \%STR); });
  }
  # Position the window
  if ($winConfig->chRememberPos->Checked() and exists($CONFIG{'SCREEN_LEFT'}) and exists($CONFIG{'SCREEN_TOP'})) {
    $win->Left($CONFIG{'SCREEN_LEFT'});
    $win->Top($CONFIG{'SCREEN_TOP'});
  }
} else { # Configuration Wizard Window
  my $refWinCW = &createCW();
  # First start of the tool, Load configuration wizard
  $THR_UPDATE = threads->create(sub { &firstStart($refWinCW); });
}
$START = 1;
if ($winConfig->chFullScreen->Checked()) { $win->Show(3); }
else                                     { $win->Show();  }
Win32::GUI::Dialog();

#--------------------------#
sub winMain_Terminate
#--------------------------#
{
  # Remember position
  my $winLeft   = $win->AbsLeft();
  my $winTop    = $win->AbsTop();
  $CONFIG{'SCREEN_LEFT'} = $winLeft;
  $CONFIG{'SCREEN_TOP'}  = $winTop;
  &saveConfig(\%CONFIG, $CONFIG_FILE);
  # Close program
  -1;
  
}  #--- End winMain_Terminate

#--------------------------#
sub winMain_Resize
#--------------------------#
{
  # Header
  $win->Tab->Width($win->ScaleWidth()-308);
  $win->tfWith->Width($win->ScaleWidth()/9.3);
  $win->lblColumnsNo->Left($win->tfWith->Left()+$win->ScaleWidth()/9.3+20);
  $win->tfColumnsNo->Left($win->lblColumnsNo->Left()+70);
  $win->tfColumnsNo->Width($win->ScaleWidth()/9.3);
  $win->lblReplaceREOk->Width($win->ScaleWidth()/5+2);
  $win->lblReplaceREErr->Width($win->ScaleWidth()/5+2);
  $win->lblReplaceREWarn->Width($win->ScaleWidth()/5+2);
  $win->tfReplace->Width($win->ScaleWidth()/5);
  $win->lblReplBy->Left($win->tfReplace->Left()+$win->ScaleWidth()/5+10);
  $win->lblReplaceByREOk->Left($win->tfReplace->Left()+$win->ScaleWidth()/5+44);
  $win->lblReplaceByREOk->Width($win->ScaleWidth()/5+2);
  $win->lblReplaceByREErr->Left($win->tfReplace->Left()+$win->ScaleWidth()/5+44);
  $win->lblReplaceByREErr->Width($win->ScaleWidth()/5+2);
  $win->lblReplaceByREWarn->Left($win->tfReplace->Left()+$win->ScaleWidth()/5+44);
  $win->lblReplaceByREWarn->Width($win->ScaleWidth()/5+2);
  $win->tfReplBy->Left($win->tfReplace->Left()+$win->ScaleWidth()/5+45);
  $win->tfReplBy->Width($win->ScaleWidth()/5);
  $win->cbCFLists->Width($win->ScaleWidth()/4);
  $win->lblDTParser->Left($win->ScaleWidth()-($win->ScaleWidth()/5.25)-65);
  $win->cbDTParser->Left($win->ScaleWidth()-($win->ScaleWidth()/5.25)+40);
  $win->cbInputTimeType->BringWindowToTop(); # Prevent box from disappearing
  $win->cbInputTimeType->SetCurSel($win->cbInputTimeType->GetCurSel());
  $win->cbInputDTFormat->Width($win->ScaleWidth()/4.8);
  $win->cbInputDTFormat->BringWindowToTop(); # Prevent box from disappearing
  $win->cbInputDTFormat->SetCurSel($win->cbInputDTFormat->GetCurSel());
  $win->btnOpenDTDB->Left(510+($win->ScaleWidth()/4.8)+2);
  $win->btnInputFormatGuess->Left(510+($win->ScaleWidth()/4.8)+26);
  $win->lblOutputDTFormat->Left($win->ScaleWidth()-($win->ScaleWidth()/5.25)-65);
  $win->cbOutputDTFormat->Left($win->ScaleWidth()-($win->ScaleWidth()/5.25)-5);
  $win->cbOutputDTFormat->Width($win->ScaleWidth()/5.25);
  $win->cbOutputDTFormat->BringWindowToTop(); # Prevent box from disappearing
  $win->cbOutputDTFormat->SetCurSel($win->cbOutputDTFormat->GetCurSel());
  $win->cbOutputDTDiff->Left($win->ScaleWidth()-($win->ScaleWidth()/5.25)-5);
  $win->cbOutputDTDiff->Width($win->ScaleWidth()/8);
  $win->cbOutputDTDiff->BringWindowToTop(); # Prevent box from disappearing
  $win->cbOutputDTDiff->SetCurSel($win->cbOutputDTFormat->GetCurSel());
  $win->gridGeoIPOpts->Width($win->ScaleWidth()-700);
  $win->gridGeoIPOpts->AutoSize();
  $win->gridGeoIPOpts->ExpandRowsToFit();
  $win->gridGeoIPOpts->ExpandLastColumn();
  $win->gridGPS2AddrOpts->Width($win->ScaleWidth()-700);
  $win->gridGPS2AddrOpts->AutoSize();
  $win->gridGPS2AddrOpts->ExpandRowsToFit();
  $win->gridGPS2AddrOpts->ExpandLastColumn();
  $win->gridUAOpts->Width($win->ScaleWidth()-700);
  $win->gridUAOpts->AutoSize();
  $win->gridUAOpts->ExpandRowsToFit();
  $win->gridUAOpts->ExpandLastColumn();
  $win->cbCFLists->BringWindowToTop(); # Prevent box from disappearing
  $win->cbCFLists->SetCurSel($win->cbCFLists->GetCurSel());
  $win->btnCFAdd->Left($win->cbCFLists->Left()+$win->ScaleWidth()/4+4);
  $win->btnCFRem->Left($win->cbCFLists->Left()+$win->ScaleWidth()/4+30);
  $win->btnCFEdit->Left($win->cbCFLists->Left()+$win->ScaleWidth()/4+56);
  $win->btnCFNew->Left($win->cbCFLists->Left()+$win->ScaleWidth()/4+82);
  $win->tfCFTitle->Width($win->ScaleWidth()/4);
  $win->btnCFSave->Left($win->tfCFTitle->Left()+$win->ScaleWidth()/4+4);
  $win->btnCFCancel->Left($win->tfCFTitle->Left()+$win->ScaleWidth()/4+30);
  # Lists
  # Adjusts splitter position
  my $split1Pos;
  if ($SPLIT1_CURR_POS) {
    $split1Pos = $win->ScaleWidth()/$SPLIT1_CURR_POS;
    $split1Pos = 300 if $split1Pos < 300;
  }
  else {
    $split1Pos       = $win->split1->Left();
    $SPLIT1_CURR_POS = $win->ScaleWidth()/$split1Pos;
  }
  my $split2Pos;
  if ($SPLIT2_CURR_POS) { $split2Pos = $win->ScaleWidth()/$SPLIT2_CURR_POS; }
  else {
    $split2Pos = $win->split2->Left();
    $SPLIT2_CURR_POS = $win->ScaleWidth()/$split2Pos;
  }
  $win->split1->Max($win->ScaleWidth()/2);
  if ($LIST2_VISIBLE) { $win->split2->Min($win->ScaleWidth()/2); }
  else                { $win->split2->Min(300);                  }
  $win->split2->Max($win->ScaleWidth()-200);
  $win->split1->Left($split1Pos);
  $win->split1->Height($win->ScaleHeight()-150);
  $win->split2->Left($split2Pos);
  $win->split2->Height($win->ScaleHeight()-150);
  # List 1
  if ($LIST2_VISIBLE) {
    $win->gbList1->Resize($split1Pos-6, $win->ScaleHeight()-162);
    $win->tfList1->Resize($split1Pos-16, $win->ScaleHeight()-212);
    $win->lblList1Count->Left($split1Pos-70);
  } else {
    $win->gbList1->Resize($split2Pos-6, $win->ScaleHeight()-162);
    $win->tfList1->Resize($split2Pos-16, $win->ScaleHeight()-212);
    $win->lblList1Count->Left($split2Pos-70);
  }
  # List 2
  $win->gbList2->Left($split1Pos+5);
  $win->gbList2->Resize($split2Pos-$split1Pos-7.5, $win->ScaleHeight()-162);
  $win->btnList2File->Left($split1Pos+9);
  $win->btnList2Del->Left($split1Pos+33);
  $win->lblList2Count->Left($split2Pos-70);
  $win->tfList2->Left($split1Pos+9);
  $win->tfList2->Resize($split2Pos-$split1Pos-16, $win->ScaleHeight()-212);
  # List 3
  $win->gbList3->Left($split2Pos+5);
  $win->gbList3->Resize($win->ScaleWidth()-$split2Pos-8, $win->ScaleHeight()-162);
  $win->btnList3Open->Left($split2Pos+9);
  $win->chList3InFile->Left($split2Pos+36);
  $win->lblList3Count->Left($win->ScaleWidth()-70);
  $win->tfList3->Left($split2Pos+9);
  $win->tfList3->Resize($win->ScaleWidth()-$split2Pos-16, $win->ScaleHeight()-212);
  # Footer
  $win->lblFooter->Top($win->ScaleHeight()-55);
  $win->lblFooter->Width($win->ScaleWidth());
  $win->lblNotReady->Top($win->ScaleHeight()-40);
  $win->lblPbCurr->Top($win->ScaleHeight()-48);
  $win->lblPbCurr->Width($win->ScaleWidth()-200);
  $win->pb->Top($win->ScaleHeight()-27);
  $win->pb->Width($win->ScaleWidth()-310);
  $win->lblPbCount->Top($win->ScaleHeight()-25);
  $win->lblPbCount->Left($win->ScaleWidth()-295);
  $win->btnProcess->Move($win->ScaleWidth()-180, $win->ScaleHeight()-45);
  $win->btnStop->Move($win->ScaleWidth()-180, $win->ScaleHeight()-45);
  $win->btnWinConfig->Move($win->ScaleWidth()-135, $win->ScaleHeight()-45);
  $win->btnHelp->Move($win->ScaleWidth()-90, $win->ScaleHeight()-45);
  $win->btnAbout->Move($win->ScaleWidth()-45, $win->ScaleHeight()-45);

}  #--- End winMain_Resize

#--------------------------#
sub split1
#--------------------------#
{
  # Local variables
  my ($s, $left) = @_;
  my $split2Pos  = $win->split2->Left();
  $SPLIT1_CURR_POS = $win->ScaleWidth()/$left;
  # Resize and move
  # List 1
  $win->gbList1->Width($left - 6);
  $win->tfList1->Width($left-16);
  $win->lblList1Count->Left($left-70);
  # List 2
  if ($split2Pos - $left < 100) {
    if ($LIST2_VISIBLE) {
      # Hide List 2 (not enough space)
      $win->gbList2->Hide();
      $win->btnList2File->Hide();
      $win->btnList2Del->Hide();
      $win->lblList2Count->Hide();
      $win->tfList2->Hide();
    }
  } else {
    # Show List 2
    if ($LIST2_VISIBLE) {
      $win->gbList2->Show();
      $win->btnList2File->Show();
      $win->btnList2Del->Show();
      $win->lblList2Count->Show();
      $win->tfList2->Show();
    }
    $win->gbList2->Width($split2Pos - $left - 7.5);
    $win->gbList2->Left($left + 5);
    $win->btnList2File->Left($left+9);
    $win->btnList2Del->Left($left+33);
    $win->lblList2Count->Left($split2Pos-70);
    $win->tfList2->Left($left+9);
    $win->tfList2->Width($split2Pos-$left-16);
  }
  return(1);

}  #--- End split1

#--------------------------#
sub split2
#--------------------------#
{
  # Local variables
  my ($s, $left) = @_;
  my $split1Pos  = $win->split1->Left();
  $SPLIT2_CURR_POS = $win->ScaleWidth()/$left;
  # Resize and move
  # List 2
  if ($left - $split1Pos < 100) {
    if ($LIST2_VISIBLE) {
      # Hide List 2 (not enough space)
      $win->gbList2->Hide();
      $win->btnList2File->Hide();
      $win->btnList2Del->Hide();
      $win->lblList2Count->Hide();
      $win->tfList2->Hide();
    }
  } else {
    # Show List 2
    if ($LIST2_VISIBLE) {
      $win->gbList2->Show();
      $win->btnList2File->Show();
      $win->btnList2Del->Show();
      $win->lblList2Count->Show();
      $win->tfList2->Show();
    }
    $win->gbList2->Width($left - $split1Pos - 7.5);
    $win->lblList2Count->Left($left-70);
    $win->tfList2->Left($split1Pos+9);
    $win->tfList2->Width($left-$split1Pos-16);
  }
  # If List 2 is not visible, adjust List 1
  if (!$LIST2_VISIBLE) {
    $win->gbList1->Width($left - 6);
    $win->tfList1->Width($left-16);
    $win->lblList1Count->Left($left-70);
  }
  # List 3
  $win->gbList3->Width($win->ScaleWidth() - $left - 9);
  $win->gbList3->Left($left + 5);
  $win->btnList3Open->Left($left+9);
  $win->chList3InFile->Left($left+36);
  $win->lblList3Count->Left($win->ScaleWidth()-70);
  $win->tfList3->Left($left+9);
  $win->tfList3->Width($win->ScaleWidth()-$left-16);
  return(1);

}  #--- End split2

#--------------------------#
sub showList2
#--------------------------#
{
  $LIST2_VISIBLE = 1;
  $win->gbList2->Show();
  $win->btnList2File->Show();
  $win->btnList2Del->Show();
  $win->lblList2Count->Show();
  $win->tfList2->Show();
  $win->split1->Show();
  $win->split1->Left($win->ScaleWidth()/3.07586206896552);
  $win->split2->Left($win->ScaleWidth()/1.5405872193437);
  &split1(undef, $win->ScaleWidth()/3.07586206896552);
  &split2(undef, $win->ScaleWidth()/1.5405872193437);
  $win->split2->Min($win->ScaleWidth()/2);
  
}  #--- End showList2

#--------------------------#
sub hideList2
#--------------------------#
{
  $LIST2_VISIBLE = 0;
  $win->tfList2->Text('');
  $win->gbList2->Hide();
  $win->btnList2File->Hide();
  $win->btnList2Del->Hide();
  $win->lblList2Count->Hide();
  $win->tfList2->Hide();
  $win->split1->Hide();
  $win->split1->Left($win->ScaleWidth()/2);
  $win->split2->Left($win->ScaleWidth()/2);
  &split1(undef, $win->ScaleWidth()/2);
  &split2(undef, $win->ScaleWidth()/2);
  $win->split2->Min(300);
  
}  #--- End hideList2

#--------------------------#
sub Tab_Click
#--------------------------#
{
  # Show Lists tab
  if ($win->Tab->SelectedItem() == 0) {
    $win->cbLists->Show();
    $win->cbLists->SetCurSel(0) if $win->cbLists->GetCurSel() == -1;
    &cbLists_Change();
    # Hide Sorting tab
    $win->cbSorts->Hide();
    $win->rbAsc->Hide();
    $win->rbDsc->Hide();
    # Hide Conversion tab
    $win->cbConv->Hide();
    # Hide Time tab
    $win->cbTime->Hide();
    $win->lblDTParser->Hide();
    $win->cbDTParser->Hide();
    $win->lblOutputDTFormat->Hide();
    $win->cbOutputDTFormat->Hide();
    $win->chSingleDate->Hide();
    $win->dtTimeDiffDate->Hide();
    $win->dtTimeDiffTime->Hide();
    $win->cbOutputDTDiff->Hide();
    $win->lblDeltaYears->Hide();
    $win->tfDeltaYears->Hide();
    $win->upDownDeltaYears->Hide();
    $win->lblDeltaMonths->Hide();
    $win->tfDeltaMonths->Hide();
    $win->upDownDeltaMonths->Hide();
    $win->lblDeltaDays->Hide();
    $win->tfDeltaDays->Hide();
    $win->upDownDeltaDays->Hide();
    $win->lblDeltaTime->Hide();
    $win->tfDeltaHours->Hide();
    $win->upDownDeltaHours->Hide();
    $win->lblSeparator1->Hide();
    $win->tfDeltaMinutes->Hide();
    $win->upDownDeltaMinutes->Hide();
    $win->lblSeparator2->Hide();
    $win->tfDeltaSecondes->Hide();
    $win->upDownDeltaSecondes->Hide();
    $win->lblInputType->Hide();
    $win->cbInputTimeType->Hide();
    $win->cbInputDTFormat->Hide();
    $win->btnOpenDTDB->Hide();
    $win->btnInputFormatGuess->Hide();
    # Hide Utils tab
    $win->cbUtils->Hide();
    $win->lblCurrMACOUIdbDate->Hide();
    $win->btnMACOUIdbUpdate->Hide();
    $win->lblGeoIPLang->Hide();
    $win->cbGeoIPLang->Hide();
    $win->chGeoIPOptAll->Hide();
    $win->chAddHeaders->Hide();
    $win->gridGeoIPOpts->Hide();
    $win->chAddr2GPSInc->Hide();
    $win->lblGPS2AddrZL->Hide();
    $win->cbGPS2AddrZL->Hide();
    $win->cbGPS2AddrOutput->Hide();
    $win->gridGPS2AddrOpts->Hide();
    $win->chSingleLocation->Hide();
    $win->tfSingleLocation->Hide();
    $win->chUAOptAll->Hide();
    $win->gridUAOpts->Hide();
    $win->rbIINLocalDB->Hide();
    $win->rbBinlist->Hide();
    $win->cbCFLists->Hide();
    $win->btnCFAdd->Hide();
    $win->btnCFRem->Hide();
    $win->btnCFEdit->Hide();
    $win->btnCFNew->Hide();
    $win->chCFMatchCase->Hide();
    $win->lblCFTitle->Hide();
    $win->tfCFTitle->Hide();
    $win->btnCFSave->Hide();
    $win->btnCFCancel->Hide();
  # Show Sorting tab
  } elsif ($win->Tab->SelectedItem() == 1) {
    $win->lblInputType->Hide();
    $win->cbInputTimeType->Hide();
    $win->cbInputDTFormat->Hide();
    $win->btnOpenDTDB->Hide();
    $win->btnInputFormatGuess->Hide();
    $win->cbInputTimeType->ResetContent();
    $win->cbInputTimeType->Add($STR{'Datetime'});
    $win->cbInputTimeType->SetCurSel(0);
    $win->cbSorts->Show();
    $win->cbSorts->SetCurSel(0) if $win->cbSorts->GetCurSel() == -1;
    $win->rbAsc->Show();
    $win->rbDsc->Show();
    &cbSorts_Change();
    # Hide Lists tab
    $win->cbLists->Hide();
    $win->chMatchCase->Hide();
    $win->chRegex->Hide();
    $win->chEval->Hide();
    $win->lblWith->Hide();
    $win->tfWith->Hide();
    $win->lblColumnsNo->Hide();
    $win->tfColumnsNo->Hide();
    $win->lblReplace->Hide();
    $win->lblReplaceREOk->Hide();
    $win->lblReplaceREErr->Hide();
    $win->lblReplaceREWarn->Hide();
    $win->tfReplace->Hide();
    $win->lblReplBy->Hide();
    $win->lblReplaceByREOk->Hide();
    $win->lblReplaceByREErr->Hide();
    $win->lblReplaceByREWarn->Hide();
    $win->tfReplBy->Hide();
    $win->rbAll->Hide();
    $win->rbFirstOnly->Hide();
    $win->rbFirstEachWord->Hide();
    # Hide Conversion tab
    $win->cbConv->Hide();
    # Hide Time tab
    $win->cbTime->Hide();
    $win->lblDTParser->Hide();
    $win->cbDTParser->Hide();
    $win->lblOutputDTFormat->Hide();
    $win->cbOutputDTFormat->Hide();
    $win->chSingleDate->Hide();
    $win->dtTimeDiffDate->Hide();
    $win->dtTimeDiffTime->Hide();
    $win->cbOutputDTDiff->Hide();
    $win->lblDeltaYears->Hide();
    $win->tfDeltaYears->Hide();
    $win->upDownDeltaYears->Hide();
    $win->lblDeltaMonths->Hide();
    $win->tfDeltaMonths->Hide();
    $win->upDownDeltaMonths->Hide();
    $win->lblDeltaDays->Hide();
    $win->tfDeltaDays->Hide();
    $win->upDownDeltaDays->Hide();
    $win->lblDeltaTime->Hide();
    $win->tfDeltaHours->Hide();
    $win->upDownDeltaHours->Hide();
    $win->lblSeparator1->Hide();
    $win->tfDeltaMinutes->Hide();
    $win->upDownDeltaMinutes->Hide();
    $win->lblSeparator2->Hide();
    $win->tfDeltaSecondes->Hide();
    $win->upDownDeltaSecondes->Hide();
    # Hide Utils tab
    $win->cbUtils->Hide();
    $win->lblCurrMACOUIdbDate->Hide();
    $win->btnMACOUIdbUpdate->Hide();
    $win->lblGeoIPLang->Hide();
    $win->cbGeoIPLang->Hide();
    $win->chGeoIPOptAll->Hide();
    $win->chAddHeaders->Hide();
    $win->gridGeoIPOpts->Hide();
    $win->chUAOptAll->Hide();
    $win->gridUAOpts->Hide();
    $win->rbIINLocalDB->Hide();
    $win->rbBinlist->Hide();
    $win->cbCFLists->Hide();
    $win->btnCFAdd->Hide();
    $win->btnCFRem->Hide();
    $win->btnCFEdit->Hide();
    $win->btnCFNew->Hide();
    $win->chCFMatchCase->Hide();
    $win->lblCFTitle->Hide();
    $win->tfCFTitle->Hide();
    $win->btnCFSave->Hide();
    $win->btnCFCancel->Hide();
    $win->chAddr2GPSInc->Hide();
    $win->lblGPS2AddrZL->Hide();
    $win->cbGPS2AddrZL->Hide();
    $win->cbGPS2AddrOutput->Hide();
    $win->gridGPS2AddrOpts->Hide();
    $win->chSingleLocation->Hide();
    $win->tfSingleLocation->Hide();
  # Show Conversion tab
  } elsif ($win->Tab->SelectedItem() == 2) {
    $win->cbConv->Show();
    &cbConv_Change();
    $win->cbConv->SetCurSel(0) if $win->cbConv->GetCurSel() == -1;
    # Hide Lists tab
    $win->cbLists->Hide();
    $win->chMatchCase->Hide();
    $win->chRegex->Hide();
    $win->chEval->Hide();
    $win->lblWith->Hide();
    $win->tfWith->Hide();
    $win->lblColumnsNo->Hide();
    $win->tfColumnsNo->Hide();
    $win->lblReplace->Hide();
    $win->lblReplaceREOk->Hide();
    $win->lblReplaceREErr->Hide();
    $win->lblReplaceREWarn->Hide();
    $win->tfReplace->Hide();
    $win->lblReplBy->Hide();
    $win->lblReplaceByREOk->Hide();
    $win->lblReplaceByREErr->Hide();
    $win->lblReplaceByREWarn->Hide();
    $win->tfReplBy->Hide();
    $win->rbAll->Hide();
    $win->rbFirstOnly->Hide();
    $win->rbFirstEachWord->Hide();
    # Hide Sorting tab
    $win->cbSorts->Hide();
    $win->rbAsc->Hide();
    $win->rbDsc->Hide();
    # Hide Time tab
    $win->cbTime->Hide();
    $win->lblDTParser->Hide();
    $win->cbDTParser->Hide();
    $win->lblOutputDTFormat->Hide();
    $win->cbOutputDTFormat->Hide();
    $win->chSingleDate->Hide();
    $win->dtTimeDiffDate->Hide();
    $win->dtTimeDiffTime->Hide();
    $win->cbOutputDTDiff->Hide();
    $win->lblDeltaYears->Hide();
    $win->tfDeltaYears->Hide();
    $win->upDownDeltaYears->Hide();
    $win->lblDeltaMonths->Hide();
    $win->tfDeltaMonths->Hide();
    $win->upDownDeltaMonths->Hide();
    $win->lblDeltaDays->Hide();
    $win->tfDeltaDays->Hide();
    $win->upDownDeltaDays->Hide();
    $win->upDownDeltaHours->Hide();
    $win->lblSeparator1->Hide();
    $win->tfDeltaMinutes->Hide();
    $win->upDownDeltaMinutes->Hide();
    $win->lblSeparator2->Hide();
    $win->tfDeltaSecondes->Hide();
    $win->upDownDeltaSecondes->Hide();
    $win->lblDeltaTime->Hide();
    $win->tfDeltaHours->Hide();
    $win->lblInputType->Hide();
    $win->cbInputTimeType->Hide();
    $win->cbInputDTFormat->Hide();
    $win->btnOpenDTDB->Hide();
    $win->btnInputFormatGuess->Hide();
    # Hide Utils tab
    $win->cbUtils->Hide();
    $win->lblCurrMACOUIdbDate->Hide();
    $win->btnMACOUIdbUpdate->Hide();
    $win->lblGeoIPLang->Hide();
    $win->cbGeoIPLang->Hide();
    $win->chGeoIPOptAll->Hide();
    $win->chAddHeaders->Hide();
    $win->gridGeoIPOpts->Hide();
    $win->chUAOptAll->Hide();
    $win->gridUAOpts->Hide();
    $win->rbIINLocalDB->Hide();
    $win->rbBinlist->Hide();
    $win->cbCFLists->Hide();
    $win->btnCFAdd->Hide();
    $win->btnCFRem->Hide();
    $win->btnCFEdit->Hide();
    $win->btnCFNew->Hide();
    $win->chCFMatchCase->Hide();
    $win->lblCFTitle->Hide();
    $win->tfCFTitle->Hide();
    $win->btnCFSave->Hide();
    $win->btnCFCancel->Hide();
    $win->chAddr2GPSInc->Hide();
    $win->lblGPS2AddrZL->Hide();
    $win->cbGPS2AddrZL->Hide();
    $win->cbGPS2AddrOutput->Hide();
    $win->gridGPS2AddrOpts->Hide();
    $win->chSingleLocation->Hide();
    $win->tfSingleLocation->Hide();
  # Show Time tab
  } elsif ($win->Tab->SelectedItem() == 3) {
    $win->cbTime->Show();
    $win->cbTime->SetCurSel(0) if $win->cbTime->GetCurSel() == -1;
    $win->cbInputTimeType->ResetContent();
    $win->cbInputTimeType->Add($STR{'Datetime'}  , $STR{'chromeTime'}, $STR{'LDAPTime'}, $STR{'Filetime'},
                               $STR{'SystemTime'}, $STR{'MacAbsTime'}, $STR{'MacHFS'});
    $win->cbInputTimeType->SetCurSel(0);
    $win->lblInputType->Show();
    $win->cbInputTimeType->Show();
    $win->lblOutputDTFormat->Show();
    $win->cbInputDTFormat->Show();
    $win->btnOpenDTDB->Show();
    $win->btnInputFormatGuess->Show();
    &cbTime_Change();
    # Hide Lists tab
    $win->cbLists->Hide();
    $win->chMatchCase->Hide();
    $win->chRegex->Hide();
    $win->chEval->Hide();
    $win->lblWith->Hide();
    $win->tfWith->Hide();
    $win->lblColumnsNo->Hide();
    $win->tfColumnsNo->Hide();
    $win->lblReplace->Hide();
    $win->lblReplaceREOk->Hide();
    $win->lblReplaceREErr->Hide();
    $win->lblReplaceREWarn->Hide();
    $win->tfReplace->Hide();
    $win->lblReplBy->Hide();
    $win->lblReplaceByREOk->Hide();
    $win->lblReplaceByREErr->Hide();
    $win->lblReplaceByREWarn->Hide();
    $win->tfReplBy->Hide();
    $win->rbAll->Hide();
    $win->rbFirstOnly->Hide();
    $win->rbFirstEachWord->Hide();
    # Hide Sorting tab
    $win->cbSorts->Hide();
    $win->rbAsc->Hide();
    $win->rbDsc->Hide();
    # Hide Conversion tab
    $win->cbConv->Hide();
    # Hide Utils tab
    $win->cbUtils->Hide();
    $win->lblCurrMACOUIdbDate->Hide();
    $win->btnMACOUIdbUpdate->Hide();
    $win->lblGeoIPLang->Hide();
    $win->cbGeoIPLang->Hide();
    $win->chGeoIPOptAll->Hide();
    $win->chAddHeaders->Hide();
    $win->gridGeoIPOpts->Hide();
    $win->chUAOptAll->Hide();
    $win->gridUAOpts->Hide();
    $win->rbIINLocalDB->Hide();
    $win->rbBinlist->Hide();
    $win->cbCFLists->Hide();
    $win->btnCFAdd->Hide();
    $win->btnCFRem->Hide();
    $win->btnCFEdit->Hide();
    $win->btnCFNew->Hide();
    $win->chCFMatchCase->Hide();
    $win->lblCFTitle->Hide();
    $win->tfCFTitle->Hide();
    $win->btnCFSave->Hide();
    $win->btnCFCancel->Hide();
    $win->chAddr2GPSInc->Hide();
    $win->lblGPS2AddrZL->Hide();
    $win->cbGPS2AddrZL->Hide();
    $win->cbGPS2AddrOutput->Hide();
    $win->gridGPS2AddrOpts->Hide();
    $win->chSingleLocation->Hide();
    $win->tfSingleLocation->Hide();
  # Show Utils tab
  } elsif ($win->Tab->SelectedItem() == 4) {
    $win->cbUtils->Show();
    $win->cbUtils->SetCurSel(0) if $win->cbUtils->GetCurSel() == -1;
    &cbUtils_Change();
    # Hide Lists tab
    $win->cbLists->Hide();
    $win->chMatchCase->Hide();
    $win->chRegex->Hide();
    $win->chEval->Hide();
    $win->lblWith->Hide();
    $win->tfWith->Hide();
    $win->lblColumnsNo->Hide();
    $win->tfColumnsNo->Hide();
    $win->lblReplace->Hide();
    $win->lblReplaceREOk->Hide();
    $win->lblReplaceREErr->Hide();
    $win->lblReplaceREWarn->Hide();
    $win->tfReplace->Hide();
    $win->lblReplBy->Hide();
    $win->lblReplaceByREOk->Hide();
    $win->lblReplaceByREErr->Hide();
    $win->lblReplaceByREWarn->Hide();
    $win->tfReplBy->Hide();
    $win->rbAll->Hide();
    $win->rbFirstOnly->Hide();
    $win->rbFirstEachWord->Hide();
    # Hide Sorting tab
    $win->cbSorts->Hide();
    $win->rbAsc->Hide();
    $win->rbDsc->Hide();
    # Hide Conversion tab
    $win->cbConv->Hide();
    # Hide Time tab
    $win->cbTime->Hide();
    $win->lblDTParser->Hide();
    $win->cbDTParser->Hide();
    $win->lblOutputDTFormat->Hide();
    $win->cbOutputDTFormat->Hide();
    $win->chSingleDate->Hide();
    $win->dtTimeDiffDate->Hide();
    $win->dtTimeDiffTime->Hide();
    $win->cbOutputDTDiff->Hide();
    $win->lblDeltaYears->Hide();
    $win->tfDeltaYears->Hide();
    $win->upDownDeltaYears->Hide();
    $win->lblDeltaMonths->Hide();
    $win->tfDeltaMonths->Hide();
    $win->upDownDeltaMonths->Hide();
    $win->lblDeltaDays->Hide();
    $win->tfDeltaDays->Hide();
    $win->upDownDeltaDays->Hide();
    $win->upDownDeltaHours->Hide();
    $win->lblSeparator1->Hide();
    $win->tfDeltaMinutes->Hide();
    $win->upDownDeltaMinutes->Hide();
    $win->lblSeparator2->Hide();
    $win->tfDeltaSecondes->Hide();
    $win->upDownDeltaSecondes->Hide();
    $win->lblDeltaTime->Hide();
    $win->tfDeltaHours->Hide();
    $win->lblInputType->Hide();
    $win->cbInputTimeType->Hide();
    $win->cbInputDTFormat->Hide();
    $win->btnOpenDTDB->Hide();
    $win->btnInputFormatGuess->Hide();
  }
  &isProcessReady(0);

}  #--- End Tab_Click

#--------------------------#
sub cbLists_Change
#--------------------------#
{
  # Local variables
  my $selFunc = $win->cbLists->GetCurSel();
  # Possibles value are 0 = 'No duplicate', 1 = 'Only duplicates', 2 = 'Count items', 3 = 'Count characters',
  # 4 = 'L1-L2', 5 = 'Column to row', 6 = 'Row to column', 7 = 'List to regex', 8 = 'Concat', 9 = 'Split strings',
  # 10 = 'Split and extract', 11 = 'Merge lines', 12 = 'Split and merge', 13 = 'Replace', 14 = 'Reverse string',
  # 15 = 'Transliterate', 16 = 'Lowercase', 17 = 'Uppercase', 18 = 'Add line number'
  
  # Show available options
  
  # Show List 2?
  if ($selFunc == 1 or $selFunc == 4 or $selFunc == 8) { &showList2(); }
  else                                                 { &hideList2(); }
  # Show Match case option?
  if ($selFunc < 3 or $selFunc == 4 or $selFunc == 13) {
    $win->chMatchCase->Checked(1);
    $win->chMatchCase->Show();
  } else {
    $win->chMatchCase->Checked(0);
    $win->chMatchCase->Hide();
  }
  # Show Regex option
  if ($selFunc == 9 or $selFunc == 10 or $selFunc == 12 or $selFunc == 13) { $win->chRegex->Show(); }
  else {
    $win->chRegex->Checked(0);
    $win->chRegex->Hide();
  }
  # Show Eval option
  if ($selFunc == 13) { $win->chEval->Show(); }
  else {
    $win->chEval->Checked(0);
    $win->chEval->Hide();
  }
  # Show With textfield?
  if ($selFunc == 5 or $selFunc == 6 or $selFunc == 8 or $selFunc == 9 or $selFunc == 10 or $selFunc == 12) {
    $win->lblWith->Show();
    $win->tfWith->Show();
  } else {
    $win->lblWith->Hide();
    $win->tfWith->Hide();
  }
  # Show ColumnsNo textfield?
  if ($selFunc == 10 or $selFunc == 11 or $selFunc == 12) {
    $win->lblColumnsNo->Show();
    $win->tfColumnsNo->Show();
  } else {
    $win->lblColumnsNo->Hide();
    $win->tfColumnsNo->Hide();
  }
  # Show Replace-By textfields?
  if ($selFunc == 13 or $selFunc == 15) {
    $win->lblReplace->Show();
    $win->tfReplace->Show();
    $win->lblReplBy->Show();
    $win->tfReplBy->Show();
  } else {
    $win->lblReplace->Hide();
    $win->lblReplaceREOk->Hide();
    $win->lblReplaceREErr->Hide();
    $win->lblReplaceREWarn->Hide();
    $win->tfReplace->Hide();
    $win->tfReplace->Text('');
    $win->lblReplBy->Hide();
    $win->lblReplaceByREOk->Hide();
    $win->lblReplaceByREErr->Hide();
    $win->lblReplaceByREWarn->Hide();
    $win->tfReplBy->Hide();
    $win->tfReplBy->Text('');
  }
  # Show lowercase-uppercase Options
  if ($selFunc == 16 or $selFunc == 17) {
    $win->rbAll->Show();
    $win->rbFirstOnly->Show();
    $win->rbFirstEachWord->Show();
  } else {
    $win->rbAll->Hide();
    $win->rbFirstOnly->Hide();
    $win->rbFirstEachWord->Hide();
  }
  &isProcessReady(0);

}  #--- End cbLists_Change

#--------------------------#
sub tfWith_Change      { &isProcessReady(0); }
sub tfColumnsNo_Change { &isProcessReady(0); }
#--------------------------#

#--------------------------#
sub tfReplace_Change
#--------------------------#
{
  # Test Regex if necessary
  &showReplaceREStatus(\$win) if $win->chRegex->Checked();
  # Enable By textfield
  if ($win->tfReplace->Text) {
    $win->tfReplBy->Enable();
    $win->chEval->Enable() if $win->chRegex->Checked();
  } else {
    $win->tfReplBy->Text('');
    $win->tfReplBy->Disable();
    $win->chEval->Checked(0);
    $win->chEval->Disable();
    $win->lblReplaceByREOk->Hide();
    $win->lblReplaceByREErr->Hide();
    $win->lblReplaceByREWarn->Hide();
  }
  &isProcessReady(0);

}  #--- End tfReplace_Change

#--------------------------#
sub chRegex_Click
#--------------------------#
{
  # Test Regex if necessary
  if ($win->chRegex->Checked()) {
    &showReplaceREStatus(\$win);
    $win->chEval->Enable();
  } else {
    $win->lblReplaceREOk->Hide();
    $win->lblReplaceREErr->Hide();
    $win->lblReplaceREWarn->Hide();
    $win->chEval->Checked(0);
    $win->chEval->Disable();
    $win->lblReplaceByREOk->Hide();
    $win->lblReplaceByREErr->Hide();
    $win->lblReplaceByREWarn->Hide();
  }
  # Revaluate Replacement expression
  &showReplaceByREStatus(\$win) if $win->tfReplBy->Text();
  &isProcessReady(0);

}  #--- End chRegex_Click

#--------------------------#
sub tfReplBy_Change
#--------------------------#
{
  &showReplaceByREStatus(\$win);
  &isProcessReady(0);

}  #--- End tfReplBy_Change

#--------------------------#
sub chEval_Click
#--------------------------#
{
  if ($win->chRegex->Checked()) { &showReplaceByREStatus(\$win); }
  else {
    $win->lblReplaceByREOk->Hide();
    $win->lblReplaceByREErr->Hide();
    $win->lblReplaceByREWarn->Hide();
  }
  &isProcessReady(0);

}  #--- End chEval_Click

#--------------------------#
sub cbSorts_Change
#--------------------------#
{
  # Local variables
  my $selFunc = $win->cbSorts->GetCurSel();
  # Possibles value are 0 = 'Alphabetical order', 1 = 'Numerical order', 2 = 'String length', 3 = 'IPv4 Address', 4 = 'Date and time', 5 = 'Random'
  
  # Hide List 2
  &hideList2();
  # Date and time options
  if ($selFunc == 4) {
    $win->lblInputType->Show();
    $win->cbInputTimeType->Show();
    $win->cbInputDTFormat->Show();
    $win->btnOpenDTDB->Show();
    $win->btnInputFormatGuess->Show();
  } else {
    $win->lblInputType->Hide();
    $win->cbInputTimeType->Hide();
    $win->cbInputDTFormat->Hide();
    $win->btnOpenDTDB->Hide();
    $win->btnInputFormatGuess->Hide();
  }
  # Random
  if ($selFunc == 5) {
    $win->rbAsc->Hide();
    $win->rbDsc->Hide();
  } else {
    $win->rbAsc->Show();
    $win->rbDsc->Show();
  }
  &isProcessReady(0);

}  #--- End cbSorts_Change

#--------------------------#
sub btnOpenDTDB_Click
#--------------------------#
{
  if (my $selRow = ($winDTDB->gridDT->GetSelectedCellRange())[0]) {
    $winDTDB->btnDTEdit->Enable();
    $winDTDB->btnDTDel->Enable();
  } else {
    $winDTDB->btnDTEdit->Disable();
    $winDTDB->btnDTDel->Disable();
  }
  $winDTDB->Center($win);
  $winDTDB->Show();
  $win->Disable();
  return(1);

}  #--- End btnOpenDTDB_Click
  
#--------------------------#
sub btnInputFormatGuess_Click
#--------------------------#
{
  # Guess format of the first item
  if (my $sample = (&findInputDTFormat($win->tfList1->GetLine(0)))[0]) {
    $win->cbInputDTFormat->SetCurSel($win->cbInputDTFormat->FindStringExact($sample));
  # If not found
  } else { Win32::GUI::MessageBox($win, $STR{'formatNotFound'}.'...', $STR{'Error'}, 0x40010); }

}  #--- End btnInputFormatGuess_Click

#--------------------------#
sub findInputDTFormat
#--------------------------#
{
  # Local variables
  my $item = shift;
  # Guess format
  for (my $i = 1; $i < $winDTDB->gridDT->GetRows(); $i++) {
    my $regex = $winDTDB->gridDT->GetCellText($i, 2);
    if ($item =~ /($regex)/i) {
      my $pattern = $winDTDB->gridDT->GetCellText($i, 1);
      # Format
      my $partItem = $1 =~ s/ +/ /gr;
      my $strp     = DateTime::Format::Strptime->new(pattern => $pattern, zone_map => \%ZONE_MAP, locale => $CONFIG{'DEFAULT_LANG'},);
      if (my $dt = $strp->parse_datetime($partItem)) {
        my $timezone;
        $timezone = $winConfig->cbLocalTZ->GetString($winConfig->cbLocalTZ->GetCurSel()) if $winDTDB->gridDT->GetCellText($i, 3) eq 'local';
        return($winDTDB->gridDT->GetCellText($i, 0), $winDTDB->gridDT->GetCellText($i, 1),
               $winDTDB->gridDT->GetCellText($i, 2), $timezone);
      }
    }
  }
  return(0);
  
}  #--- End findInputDTFormat

#--------------------------#
sub infoDTFormat
#--------------------------#
{
  # Local variables
  my $sample = shift;  
  # Guess format
  for (my $i = 1; $i < $winDTDB->gridDT->GetRows(); $i++) {
    my $curSampleRow = $winDTDB->gridDT->GetCellText($i, 0);
    return($winDTDB->gridDT->GetCellText($i, 0), $winDTDB->gridDT->GetCellText($i, 1),
           $winDTDB->gridDT->GetCellText($i, 2), $winDTDB->gridDT->GetCellText($i, 3)) if $curSampleRow eq $sample;
  }
  return(0);
  
}  #--- End infoDTFormat

#--------------------------#
sub gridDT_Click
#--------------------------#
{
  $winDTDB->btnDTEdit->Enable();
  $winDTDB->btnDTDel->Enable();
  return(1);

}  #--- End gridDT_Click

#--------------------------#
sub gridDT_DblClick
#--------------------------#
{
  &btnDTEdit_Click();
  return(1);

}  #--- End gridDT_DblClick

#--------------------------#
sub sortGridDT
#--------------------------#
{
  my ($a, $b) = @_;
  return (length($a) <=> length($b));

}  #--- End sortGridDT

#--------------------------#
sub btnDTAdd_Click
#--------------------------#
{
  # Reset all values
  $winDTObj->tfDTObjSample->Text('');
  $winDTObj->tfDTObjSample->ReadOnly(0);
  $winDTObj->tfDTObjPattern->Text('');
  $winDTObj->cbDTObjPattern->SetCurSel(0);
  $winDTObj->lblDTObjRegexOk->Hide();
  $winDTObj->lblDTObjRegexErr->Hide();
  $winDTObj->lblDTObjRegexWarn->Hide();
  $winDTObj->tfDTObjRegex->Text('');
  $winDTObj->chDTObjRegexAuto->Checked(1);
  $winDTObj->rbDTObjTZLocal->Checked(1);
  $winDTObj->rbDTObjTZUTC->Checked(0);
  $winDTObj->rbDTObjTZOtherOffset->Checked(0);
  $winDTObj->rbDTObjTZOtherName->Checked(0);
  $winDTObj->cbDTObjTZOffset->SetCurSel(0);
  $winDTObj->cbDTObjTZName->SetCurSel(0);
  $winDTObj->lblDTObjParsedData->Text('');
  $winDTObj->cbDTObjUseAs->SetCurSel(0);
  $winDTObj->tfDTObjComment->Text('');
  # Update controls
  my $firstItem = $win->tfList1->GetLine(0);
  if ($firstItem) { $winDTObj->btnDTObjUseFirst->Enable();  }
  else            { $winDTObj->btnDTObjUseFirst->Disable(); }
  $winDTObj->btnDTObjAdd->Show();
  $winDTObj->btnDTObjEdit->Hide();
  $winDTObj->Center($win);
  $winDTObj->Show();
  $winDTDB->Disable();
  return(1);

}  #--- End btnDTAdd_Click

#--------------------------#
sub btnDTEdit_Click
#--------------------------#
{
  # Local variables
  my %useAsInd = ($STR{'Input'} => 0, $STR{'Output'} => 1, $STR{'Both'} => 2, $STR{'None'} => 3);
  # Load the current values
  my $selRow = ($winDTDB->gridDT->GetSelectedCellRange())[0];
  $winDTObj->tfDTObjSample->Text($winDTDB->gridDT->GetCellText($selRow, 0));
  $winDTObj->tfDTObjSample->ReadOnly(1);
  $winDTObj->tfDTObjPattern->Text($winDTDB->gridDT->GetCellText($selRow, 1));
  $winDTObj->tfDTObjRegex->Text($winDTDB->gridDT->GetCellText($selRow, 2));
  my $timezone = $winDTDB->gridDT->GetCellText($selRow, 3);
  if      ($timezone eq 'local') {
    $winDTObj->rbDTObjTZLocal->Checked(1);
    $winDTObj->rbDTObjTZUTC->Checked(0);
    $winDTObj->rbDTObjTZOtherOffset->Checked(0);
    $winDTObj->rbDTObjTZOtherName->Checked(0);
  } elsif ($timezone eq 'UTC') {
    $winDTObj->rbDTObjTZLocal->Checked(0);
    $winDTObj->rbDTObjTZUTC->Checked(1);
    $winDTObj->rbDTObjTZOtherOffset->Checked(0);
    $winDTObj->rbDTObjTZOtherName->Checked(0);
  } elsif ($timezone =~ /[\+\-]?\d{4}/) {
    $winDTObj->rbDTObjTZLocal->Checked(0);
    $winDTObj->rbDTObjTZUTC->Checked(0);
    $winDTObj->rbDTObjTZOtherOffset->Checked(1);
    $winDTObj->rbDTObjTZOtherName->Checked(0);
    $winDTObj->cbDTObjTZOffset->SetCurSel($winDTObj->cbDTObjTZOffset->FindStringExact($timezone));
  } else {
    $winDTObj->rbDTObjTZLocal->Checked(0);
    $winDTObj->rbDTObjTZUTC->Checked(0);
    $winDTObj->rbDTObjTZOtherOffset->Checked(0);
    $winDTObj->rbDTObjTZOtherName->Checked(1);
    $winDTObj->cbDTObjTZName->SetCurSel($winDTObj->cbDTObjTZName->FindStringExact($timezone));
  }
  my $useAsStr = $winDTDB->gridDT->GetCellText($selRow, 4); # 0 = Input, 1 = Output, 2 = Both, 3 = None
  $winDTObj->cbDTObjUseAs->SetCurSel($useAsInd{$useAsStr}) if exists($useAsInd{$useAsStr});
  if ($winDTDB->gridDT->GetCellText($selRow, 5)) { $winDTObj->tfDTObjComment->Text($winDTDB->gridDT->GetCellText($selRow, 5)); }
  else                                           { $winDTObj->tfDTObjComment->Text(''); }
  # Update controls
  $winDTObj->btnDTObjUseFirst->Disable();
  $winDTObj->btnDTObjEdit->Show();
  $winDTObj->btnDTObjAdd->Hide();
  $winDTObj->Center($win);
  $winDTObj->Show();
  $winDTDB->Disable();
  return(1);

}  #--- End btnDTEdit_Click

#--------------------------#
sub tfDTObjSample_Change
#--------------------------#
{
  &isDTObjReady(0);
  
}  #--- End tfDTObjSample_Change

#--------------------------#
sub btnDTObjUseFirst_Click
#--------------------------#
{
  $winDTObj->tfDTObjSample->Text($win->tfList1->GetLine(0));
  &isDTObjReady(0);
  
}  #--- End btnDTObjUseFirst_Click

#--------------------------#
sub btnDTObjPatternInsert_Click
#--------------------------#
{
  # Local variables
  my $patternObjSel = $winDTObj->cbDTObjPattern->GetCurSel();
  my @patterns = ('%B', '%b', '%D', '%d', '%e', '%F', '%H', '%I', '%M', '%m', '%p',
                  '%P', '%R', '%r', '%S', '%T', '%v', '%w', '%Y', '%y', '%Z', '%z', );
  $winDTObj->tfDTObjPattern->Append($patterns[$patternObjSel]);
  &isDTObjReady(0);

}  #--- End btnDTObjPatternInsert_Click

#--------------------------#
sub patternRE
#--------------------------#
{
  # Local variables
  my $formatREStr = shift;
  # Possibles value are:
  my %formatRE = ('%A' => '\w+', # full weekday name, since 3.3 (to fit any language)
                  #'%A' => '(?:Sunday|Monday|Tuesday|Wednesday|Thursday|Friday|Saturday)', # full weekday name
                  '%a' => '\w+', # abbreviated weekday name, since 3.3 (to fit any language)
                  #'%a' => '(?:Sun|Mon|Tue|Wed|Thu|Fri|Sat)', # abbreviated weekday name
                  '%B' => '\w+', # full month name, since 3.3 (to fit any language)
                  #'%B' => '(?:January|February|March|April|May|June|July|August|September|October|November|December)', # full month name
                  '%b' => '\w{3,4}', # abbreviated weekday name, since 3.3 (to fit any language)
                  #'%b' => '(?:Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)', # abbreviated month name
                  '%C' => '\d{2}', # (year / 100) as decimal number; single digits are preceded by a zero.
                  '%D' => '\d{2}\/\d{2}\/\d{2}', # %m/%d/%y
                  '%d' => '\d{2}', # day of the month as a decimal number (01-31)
                  '%e' => '\d{1,2}', # day of the month as a decimal number (1-31); single digits are preceded by a blank.
                  '%F' => '\d{4}\-\d{2}\-\d{2}', # %Y-%m-%d
                  '%H' => '\d{2}'  , # hour (24-hour clock) as a decimal number (00-23)
                  '%I' => '\d{1,2}', # hour (12-hour clock) as a decimal number (01-12)
                  '%j' => '\d{3}'  , # day of the year as a decimal number (001-366)
                  '%k' => '\d{1,2}', # hour (24-hour clock) as a decimal number (0-23); single digits are preceded by a blank.
                  '%l' => '\d{1,2}', # hour (12-hour clock) as a decimal number (1-12); single digits are preceded by a blank.
                  '%M' => '\d{2}'  , # minute as a decimal number (00-59)
                  '%m' => '\d{1,2}', # month as a decimal number (01-12)
                  '%n' => '\n', # newline
                  '%p' => '[AP]\.?M\.?', # national representation of either "ante meridiem" (a.m.)  or "post meridiem" (p.m.)  as appropriate.
                  '%P' => '[ap]\.?m\.?', # national representation of either "ante meridiem" (a.m.)  or "post meridiem" (p.m.)  as appropriate.
                  '%R' => '\d{2}:\d{2}', # %H:%M
                  '%r' => '\d{1,2}:\d{2}:\d{2} [apAP]\.?[mM]\.?', # %I:%M:%S %p
                  '%S' => '\d{2}', # second as a decimal number (00-60)
                  '%s' => '\d{10,13}', # number of seconds since the Epoch
                  '%T' => '\d{2}:\d{2}:\d{2}', # %H:%M:%S
                  '%R' => '\d{2}:\d{2}', # %H:%M
                  '%t' => '\t', # tab
                  '%U' => '\d{2}', # week number of the year (Sunday as the first day of the week) as a decimal number (00-53).
                  '%u' => '[1-7]', # weekday (Monday as the first day of the week) as a decimal number (1-7).
                  '%V' => '\d{2}', # week number of the year (Monday as the first day of the week) as a decimal number (01-53)
                  '%v' => '\d{1,2}\-[a-zA-Z]{3}\-\d{4}', # %e-%b-%Y
                  '%W' => '\d{2}', # week number of the year as a decimal number (00-53).
                  '%w' => '[0-6]', # weekday (Sunday as the first day of the week) as a decimal number (0-6).
                  '%Y' => '\d{4}', # year with century as a decimal number
                  '%y' => '\d{2}', # year without century as a decimal number (00-99)
                  '%Z' => '[a-zA-Z\/]+', # time zone name
                  '%z' => '[\-\+]?\d{4}', # time zone offset from UTC
                  );
  # Convert other format string from strftime format (%) to regex
  foreach my $matchRE (keys %formatRE) { $formatREStr =~ s/$matchRE/$formatRE{$matchRE}/ge; }
  return($formatREStr);

}  #--- End patternRE

#--------------------------#
sub tfDTObjPattern_Change
#--------------------------#
{
  # Local variables
  my $pattern = $winDTObj->tfDTObjPattern->Text();
  if ($pattern =~ /%\w/ and $winDTObj->chDTObjRegexAuto->Checked()) {
    my $regex = patternRE($pattern);
    $winDTObj->tfDTObjRegex->Text($regex);
  }
  &isDTObjReady(0);
  
}  #--- End tfDTObjPattern_Change

#--------------------------#
sub btnDTObjPatternHelp_Click
#--------------------------#
{
  # Open Default browser to a help page on Strftime
  $win->ShellExecute('open', 'http://strftime.net/','','',1) or
  Win32::GUI::MessageBox($win, Win32::FormatMessage(Win32::GetLastError()), $STR{'Error'}, 0x40010);
  
}  #--- End btnDTObjPatternHelp_Click

#--------------------------#
sub tfDTObjRegex_Change { &isDTObjReady(0); }
#--------------------------#

#--------------------------#
sub chDTObjRegexAuto_Click
#--------------------------#
{
  # Local variables
  my $pattern = $winDTObj->tfDTObjPattern->Text();
  if ($pattern =~ /%\w/ and $winDTObj->chDTObjRegexAuto->Checked()) {
    my $regex = patternRE($pattern);
    $winDTObj->tfDTObjRegex->Text($regex);
  }
  &isDTObjReady(0);
  
}  #--- End chDTObjRegexAuto_Click

#--------------------------#
sub isDTObjReady
#--------------------------#
{
  # Local variables
  my $confirm = shift;
  my $nextStep;
  # Sample provided?
  my $sample = $winDTObj->tfDTObjSample->Text();
  if (!$sample) {
    $winDTObj->tfDTObjPattern->Disable();
    $winDTObj->btnDTObjPatternInsert->Disable();
    $winDTObj->cbDTObjPattern->Disable();
    $winDTObj->tfDTObjRegex->Disable();
    $nextStep = $STR{'provideSample'};
  } else {
    $winDTObj->tfDTObjPattern->Enable();
    $winDTObj->btnDTObjPatternInsert->Enable();
    $winDTObj->cbDTObjPattern->Enable();
    # Pattern provided?
    my $pattern = $winDTObj->tfDTObjPattern->Text();
    if ($pattern =~ /%\w/) {
      $winDTObj->tfDTObjRegex->Enable();
      # Regex provided?
      my $regex = $winDTObj->tfDTObjRegex->Text();
      if ($regex) {
        my ($statusRegex, $msg) = &validRegex($regex);
        # Warning
        if      ($statusRegex == 2) {
          $winDTObj->lblDTObjRegexWarn->Show();
          $winDTObj->lblDTObjRegexOk->Hide();
          $winDTObj->lblDTObjRegexErr->Hide();
        # Error
        } elsif ($statusRegex == 1) {
          $winDTObj->lblDTObjRegexErr->Show();
          $winDTObj->lblDTObjRegexOk->Hide();
          $winDTObj->lblDTObjRegexWarn->Hide();
          $nextStep = $STR{'errRegex'};
        # Ok
        } else {
          $winDTObj->lblDTObjRegexOk->Show();
          $winDTObj->lblDTObjRegexErr->Hide();
          $winDTObj->lblDTObjRegexWarn->Hide();
        }
      } else {
        $winDTObj->lblDTObjRegexOk->Hide();
        $winDTObj->lblDTObjRegexErr->Hide();
        $winDTObj->lblDTObjRegexWarn->Hide();
        $nextStep = $STR{'errRegex'};
      }
      # Test regex and pattern
      if (!$nextStep) {
        my $strp = DateTime::Format::Strptime->new(pattern => $pattern, zone_map => \%ZONE_MAP, locale => $CONFIG{'DEFAULT_LANG'},);
        if ($sample =~ /$regex/i and my $parsedPattern = $strp->parse_datetime($sample)) {
          $winDTObj->lblDTObjParsedData->Text($parsedPattern->strftime($pattern));
          # Timezone?
          if ($pattern =~ /%[Zzs]/) {
            $winDTObj->rbDTObjTZLocal->Disable();
            $winDTObj->rbDTObjTZUTC->Disable();
            $winDTObj->rbDTObjTZOtherOffset->Disable();
            $winDTObj->cbDTObjTZOffset->Disable();
            $winDTObj->rbDTObjTZOtherName->Disable();
            $winDTObj->cbDTObjTZName->Disable();
          } else { # No timezone in pattern, must specify
            $winDTObj->rbDTObjTZLocal->Enable();
            $winDTObj->rbDTObjTZUTC->Enable();
            $winDTObj->rbDTObjTZOtherOffset->Enable();
            $winDTObj->cbDTObjTZOffset->Enable();
            $winDTObj->rbDTObjTZOtherName->Enable();
            $winDTObj->cbDTObjTZName->Enable();
          }
        } else { $winDTObj->lblDTObjParsedData->Text(''); }
      }
    } else {
      $winDTObj->tfDTObjRegex->Disable();
      $nextStep = $STR{'providePattern'};
    }
  }
  # Return an error message or enable the button
  if ($nextStep) {
    $winDTObj->btnDTObjAdd->Disable();
    $winDTObj->btnDTObjEdit->Disable();
    $winDTObj->btnDTObjNotReady->Enable();
    Win32::GUI::MessageBox($winDTObj, "$STR{'notReady'}?\n\n$STR{'nextStep'}: $nextStep", $STR{'notReady'}, 0x40040) if $confirm;
  } else {
    $winDTObj->btnDTObjAdd->Enable();
    $winDTObj->btnDTObjEdit->Enable();
    $winDTObj->btnDTObjNotReady->Disable();
  }
  
}  #--- End isDTObjReady

#--------------------------#
sub btnDTObjNotReady_Click { &isDTObjReady(1); }
#--------------------------#

#--------------------------#
sub btnDTObjAdd_Click
#--------------------------#
{
  # Local variables
  my $sample   = $winDTObj->tfDTObjSample->Text();
  my $pattern  = $winDTObj->tfDTObjPattern->Text();
  my $regex    = $winDTObj->tfDTObjRegex->Text();
  my $comment  = $winDTObj->tfDTObjComment->Text();
  $comment     = 'NULL' if !$comment;
  my $useAs    = $winDTObj->cbDTObjUseAs->GetCurSel(); # 0 = Input, 1 = Output, 2 = Both, 3 = None (hidden)
  my @useAsStr = ($STR{'Input'}, $STR{'Output'}, $STR{'Both'}, $STR{'None'});
  my $DTDBFile = $winConfig->tfDTDB->Text();
  my $timezone; # Default timezone, used if not specified in pattern
  # Timezone
  if    ($winDTObj->rbDTObjTZLocal->Checked()) { $timezone = 'local'; } # Local
  elsif ($winDTObj->rbDTObjTZUTC->Checked())   { $timezone = 'UTC';   } # UTC
  elsif ($winDTObj->rbDTObjTZOtherOffset->Checked()) {                  # Other, offset
    $timezone = $winDTObj->cbDTObjTZOffset->GetString($winDTObj->cbDTObjTZOffset->GetCurSel());
  } elsif ($winDTObj->rbDTObjTZOtherName->Checked()) {                # Other, name
    $timezone = $winDTObj->cbDTObjTZName->GetString($winDTObj->cbDTObjTZName->GetCurSel());
  } else { $timezone = 'NULL'; }
  # Select or create Datetime database
  if (!-f $DTDBFile or !&validSQLiteDB($DTDBFile, 'DT')) {
    $DTDBFile = "$USERDIR\\DT.db";
    $winConfig->tfDTDB->Text($DTDBFile) if &createDTDB($DTDBFile);
  }
  # Connect to DB
  my $dsn = "DBI:SQLite:dbname=$DTDBFile";
  if (my $dbh = DBI->connect($dsn, undef, undef, { RaiseError => 1, AutoCommit => 1 })) {
    # Add to database
    # Database: table = DT, Fields = sample, pattern, regex, timezone, use_as, comment
    my $sth = $dbh->prepare("INSERT INTO DT (sample,pattern,regex,timezone,use_as,comment) VALUES(?,?,?,?,?,?)");
    my $rv = $sth->execute($sample, $pattern, $regex, $timezone, $useAs, $comment);
    if ($rv < 0) {
      Win32::GUI::MessageBox($winDTDB, $STR{'errorMsg'}.$DBI::errstr, $STR{'Error'}, 0x40010);
      return(0);
    } else {
      # Add to Grid
      if (my $newLine = $winDTDB->gridDT->InsertRow($sample, -1)) {
        $winDTDB->gridDT->SetCellText($newLine, 0, $sample);
        $winDTDB->gridDT->SetCellText($newLine, 1, $pattern);
        $winDTDB->gridDT->SetCellText($newLine, 2, $regex);
        $winDTDB->gridDT->SetCellText($newLine, 3, $timezone);
        $winDTDB->gridDT->SetCellText($newLine, 4, $useAsStr[$useAs]);
        $winDTDB->gridDT->SetCellText($newLine, 5, $comment) if $comment ne 'NULL';
        # Refresh grid
        $winDTDB->gridDT->SortCells(1, 0, \&sortGridDT);
        $winDTDB->gridDT->AutoSizeColumns();
        $winDTDB->gridDT->ExpandColumnsToFit();
        $winDTDB->gridDT->SetListMode();
        # Add to combobox
        $win->cbInputDTFormat->Add($sample) if $useAs == 0 or $useAs == 2;
        if ($useAs == 1 or $useAs == 2) {
          $win->cbOutputDTFormat->Add($sample);
          $winDTDB->cbDefaultOutput->Add($sample);
        }
        # Final message
        &winDTObj_Terminate();
        Win32::GUI::MessageBox($winDTDB, $STR{'addedDTObj'}, $STR{'DTDB'}, 0x40040);
      } else { Win32::GUI::MessageBox($win, $STR{'errNewLine'}, $STR{'Error'}, 0x40010); }
    }
  }

}  #--- End btnDTObjAdd_Click

#--------------------------#
sub btnDTObjEdit_Click
#--------------------------#
{
  # Local variables
  my $sample   = $winDTObj->tfDTObjSample->Text();
  my $pattern  = $winDTObj->tfDTObjPattern->Text();
  my $regex    = $winDTObj->tfDTObjRegex->Text();
  my $comment  = $winDTObj->tfDTObjComment->Text();
  $comment     = 'NULL' if !$comment;
  my $useAs    = $winDTObj->cbDTObjUseAs->GetCurSel(); # 0 = Input, 1 = Output, 2 = Both, 3 = None (hidden)
  my @useAsStr = ($STR{'Input'}, $STR{'Output'}, $STR{'Both'}, $STR{'None'});
  my $DTDBFile = $winConfig->tfDTDB->Text();
  my $timezone; # Default timezone, used if not specified in pattern
  # Timezone
  if    ($winDTObj->rbDTObjTZLocal->Checked()) { $timezone = 'local'; } # Local
  elsif ($winDTObj->rbDTObjTZUTC->Checked())   { $timezone = 'UTC';   } # UTC
  elsif ($winDTObj->rbDTObjTZOtherOffset->Checked()) {                  # Other, offset
    $timezone = $winDTObj->cbDTObjTZOffset->GetString($winDTObj->cbDTObjTZOffset->GetCurSel());
  } elsif ($winDTObj->rbDTObjTZOtherName->Checked()) {                # Other, name
    $timezone = $winDTObj->cbDTObjTZName->GetString($winDTObj->cbDTObjTZName->GetCurSel());
  } else { $timezone = 'NULL'; }
  # Connect to DB
  my $dsn = "DBI:SQLite:dbname=$DTDBFile";
  if (my $dbh = DBI->connect($dsn, undef, undef, { RaiseError => 1, AutoCommit => 1 })) {
    # Update database
    # Database: table = DT, Fields = sample, pattern, regex, timezone, use_as, comment
    my $sth = $dbh->prepare("UPDATE DT SET pattern = ?, regex = ?, timezone = ?, use_as = ?, comment = ? WHERE ? == sample");
    my $rv  = $sth->execute($pattern, $regex, $timezone, $useAs, $comment, $sample);
    if ($rv < 0) {
      Win32::GUI::MessageBox($winDTDB, $STR{'errorMsg'}.$DBI::errstr, $STR{'Error'}, 0x40010);
      return(0);
    } else {
      # Update Grid
      for (my $i = 1; $i < $winDTDB->gridDT->GetRows(); $i++) {
        my $curSampleRow = $winDTDB->gridDT->GetCellText($i, 0);
        if ($curSampleRow eq $sample) {
          $winDTDB->gridDT->SetCellText($i, 1, $pattern);
          $winDTDB->gridDT->SetCellText($i, 2, $regex);
          $winDTDB->gridDT->SetCellText($i, 3, $timezone);
          $winDTDB->gridDT->SetCellText($i, 4, $useAsStr[$useAs]);
          $winDTDB->gridDT->SetCellText($i, 5, $comment) if $comment ne 'NULL';
          # Refresh grid
          $winDTDB->gridDT->SortCells(1, 0, \&sortGridDT);
          $winDTDB->gridDT->AutoSizeColumns();
          $winDTDB->gridDT->ExpandColumnsToFit();
          $winDTDB->gridDT->SetListMode();
          # Add to combobox
          if ($useAs == 0 or $useAs == 2) { # Add to input
            if ((my $index = $win->cbInputDTFormat->FindStringExact($sample)) > 1) { # Already in Combobox ?
              my $inComboboxSample = $win->cbInputDTFormat->GetString($index);
              $win->cbInputDTFormat->Add($sample) if $inComboboxSample ne $sample;
            } else { $win->cbInputDTFormat->Add($sample); }
          } elsif ((my $index = $win->cbInputDTFormat->FindStringExact($sample)) > 1) {
            my $inComboboxSample = $win->cbInputDTFormat->GetString($index);
            $win->cbInputDTFormat->DeleteString($index) if $inComboboxSample eq $sample;
          }
          if ($useAs == 1 or $useAs == 2) { # Add to output
            if ((my $index = $win->cbOutputDTFormat->FindStringExact($sample)) > 1) { # Already in Combobox ?
              my $inComboboxSample = $win->cbOutputDTFormat->GetString($index);
              if ($inComboboxSample ne $sample) {
                $win->cbOutputDTFormat->Add($sample);
                $winDTDB->cbDefaultOutput->Add($sample);
              }
            } else { $win->cbOutputDTFormat->Add($sample); $winDTDB->cbDefaultOutput->Add($sample); }
          } elsif ((my $index = $win->cbOutputDTFormat->FindStringExact($sample)) > 1) {
            my $inComboboxSample = $win->cbOutputDTFormat->GetString($index);
            if ($inComboboxSample eq $sample) {
              $win->cbOutputDTFormat->DeleteString($index);
              $winDTDB->cbDefaultOutput->DeleteString($index);
            }
          }
          # Final message
          &winDTObj_Terminate();
          Win32::GUI::MessageBox($winDTDB, $STR{'updatedDTObj'}, $STR{'DTDB'}, 0x40040);
          last;
        } 
      }
      &winDTObj_Terminate();
    }
  }

}  #--- End btnDTObjEdit_Click

#--------------------------#
sub btnDTDel_Click
#--------------------------#
{
  # Local variables
  my $DTDBFile = $winConfig->tfDTDB->Text();
  # Get selected row
  my $selRow = ($winDTDB->gridDT->GetSelectedCellRange())[0];
  my $sample = $winDTDB->gridDT->GetCellText($selRow, 0);
  # Delete in Datetime database
  my $dsn = "DBI:SQLite:dbname=$DTDBFile";
  if (my $dbh = DBI->connect($dsn, undef, undef, { RaiseError => 1, AutoCommit => 1 })) {
    my $sth = $dbh->prepare("DELETE FROM DT WHERE sample == ?");
    my $rv = $sth->execute($sample);
    if ($rv < 0) { Win32::GUI::MessageBox($winDTDB, $STR{'errorMsg'}.$DBI::errstr, $STR{'Error'}, 0x40010); }
    else { 
      # Find the entry in grid and delete
      for (my $i = 1; $i < $winDTDB->gridDT->GetRows(); $i++) {
        my $curSampleRow = $winDTDB->gridDT->GetCellText($i, 0);
        if ($curSampleRow eq $sample) {
          $winDTDB->gridDT->DeleteRow($i);
          # Refresh grid
          $winDTDB->gridDT->SortCells(1, 0, \&sortGridDT);
          $winDTDB->gridDT->AutoSizeColumns();
          $winDTDB->gridDT->ExpandColumnsToFit();
          $winDTDB->gridDT->SetListMode();
          # If entry is in combobox, delete it
          $win->cbInputDTFormat->DeleteString($win->cbInputDTFormat->FindStringExact($sample));
          $win->cbOutputDTFormat->DeleteString($win->cbOutputDTFormat->FindStringExact($sample));
          Win32::GUI::MessageBox($winDTDB, $STR{'deletedDTObj'}, $STR{'DTDB'}, 0x40040);
          last;
        }
      }
    }
  }
  
}  #--- End btnDTDel_Click

#--------------------------#
sub btnDTObjCancel_Click { &winDTObj_Terminate(); }
#--------------------------#

#--------------------------#
sub winDTObj_Terminate
#--------------------------#
{
  $winDTObj->Hide();
  $winDTDB->Enable();
  $winDTDB->SetForegroundWindow();
  return(0);

}  #--- End winDTObj_Terminate

#--------------------------#
sub winDTDB_Resize
#--------------------------#
{
  $winDTDB->gridDT->Width($winDTDB->ScaleWidth()-39);
  $winDTDB->gridDT->Height($winDTDB->ScaleHeight()-40);
  $winDTDB->gridDT->AutoSizeColumns();
  $winDTDB->gridDT->ExpandLastColumn();
  $winDTDB->gridDT->Refresh();
  $winDTDB->btnDTAdd->Left($winDTDB->ScaleWidth()-32);
  $winDTDB->btnDTEdit->Left($winDTDB->ScaleWidth()-32);
  $winDTDB->btnDTDel->Left($winDTDB->ScaleWidth()-32);
  $winDTDB->lblDefaultOutput->Top($winDTDB->ScaleHeight()-27);
  $winDTDB->cbDefaultOutput->Top($winDTDB->ScaleHeight()-30);  

}  #--- End winDTDB_Resize

#--------------------------#
sub winDTDB_Terminate
#--------------------------#
{
  $winDTDB->Hide();
  $win->Enable();
  $win->SetForegroundWindow();
  return(0);

}  #--- End winDTDB_Terminate

#--------------------------#
sub cbInputDTFormatAddITems
#--------------------------#
{
  # Local variables
  my @inputFormats;
  # Browse Datetime grid and list available Datetime object for input
  for (my $i = 1; $i < $winDTDB->gridDT->GetRows(); $i++) {
    my $useAs = $winDTDB->gridDT->GetCellText($i, 4);
    push(@inputFormats, $winDTDB->gridDT->GetCellText($i, 0)) if $useAs eq $STR{'Input'} or $useAs eq $STR{'Both'};
  }
  # Update the combobox
  if (scalar(@inputFormats)) {
    $win->cbInputDTFormat->Add($STR{'guessORVar'}); # First is "Guess (or variables)"
    foreach (@inputFormats) { $win->cbInputDTFormat->Add($_); }
  }
  
}  #--- End cbInputDTFormatAddITems

#--------------------------#
sub cbOutputDTFormatAddITems
#--------------------------#
{
  # Local variables
  my @outputFormats;
  # Browse Datetime grid and list available Datetime object for output
  for (my $i = 1; $i < $winDTDB->gridDT->GetRows(); $i++) {
    my $useAs = $winDTDB->gridDT->GetCellText($i, 4);
    push(@outputFormats, $winDTDB->gridDT->GetCellText($i, 0)) if $useAs eq $STR{'Output'} or $useAs eq $STR{'Both'};
  }
  # Update the combobox (Current output and Default output selection)
  if (scalar(@outputFormats)) {
    $win->cbOutputDTFormat->Add($STR{'default'}); # Default
    $winDTDB->cbDefaultOutput->Add($STR{'same'});     # Same as input
    foreach (@outputFormats) { $win->cbOutputDTFormat->Add($_); $winDTDB->cbDefaultOutput->Add($_); }
  }
  
}  #--- End cbOutputDTFormatAddITems

#--------------------------#
sub cbConv_Change
#--------------------------#
{
  &hideList2();
  &isProcessReady(0);

}  #--- End cbConv_Change

#--------------------------#
sub cbTime_Change
#--------------------------#
{
  # Local variables
  my $selFunc = $win->cbTime->GetCurSel();
  # Possibles value are 0 = 'Anytime to Anytime', 1 = 'Time difference', 2 = 'Add time', 3 = 'Substract time'
  
  # Except for 'Anytime to Anytime', all other function operate on Datetime only
  if ($selFunc) {
    $win->cbInputTimeType->ResetContent();
    $win->cbInputTimeType->Add($STR{'Datetime'});
    $win->cbInputTimeType->SetCurSel(0);
    $win->lblDTParser->Hide(); # Parse context
    $win->cbDTParser->Hide();
  } else {
    $win->cbInputTimeType->ResetContent();
    $win->cbInputTimeType->Add($STR{'Datetime'}, $STR{'chromeTime'}, $STR{'LDAPTime'}, $STR{'Filetime'},
                               $STR{'SystemTime'}, $STR{'MacAbsTime'}, $STR{'MacHFS'});
    $win->cbInputTimeType->SetCurSel(0);
    $win->lblDTParser->Show(); # Parse context
    $win->cbDTParser->Show();
  }
  # Time difference options
  if ($selFunc == 1) {
    $win->chSingleDate->Show();
    $win->dtTimeDiffDate->Show();
    $win->dtTimeDiffTime->Show();
    $win->cbOutputDTDiff->Show();
    $win->cbOutputDTFormat->Hide();
    if ($win->chSingleDate->Checked()) { &hideList2(); }
    else                               { &showList2(); }
  } else {
    $win->chSingleDate->Hide();
    $win->dtTimeDiffDate->Hide();
    $win->dtTimeDiffTime->Hide();
    $win->cbOutputDTDiff->Hide();
    $win->cbOutputDTFormat->Show();
    &hideList2();
  }
  # Show Add or substract time controls
  if ($selFunc == 2 or $selFunc == 3) {
    $win->lblDeltaYears->Show();
    $win->tfDeltaYears->Show();
    $win->upDownDeltaYears->Show();
    $win->lblDeltaMonths->Show();
    $win->tfDeltaMonths->Show();
    $win->upDownDeltaMonths->Show();
    $win->lblDeltaDays->Show();
    $win->tfDeltaDays->Show();
    $win->upDownDeltaDays->Show();
    $win->lblDeltaTime->Show();
    $win->tfDeltaHours->Show();
    $win->upDownDeltaHours->Show();
    $win->lblSeparator1->Show();
    $win->tfDeltaMinutes->Show();
    $win->upDownDeltaMinutes->Show();
    $win->lblSeparator2->Show();
    $win->tfDeltaSecondes->Show();
    $win->upDownDeltaSecondes->Show();
  } else {
    $win->lblDeltaYears->Hide();
    $win->tfDeltaYears->Hide();
    $win->upDownDeltaYears->Hide();
    $win->lblDeltaMonths->Hide();
    $win->tfDeltaMonths->Hide();
    $win->upDownDeltaMonths->Hide();
    $win->lblDeltaDays->Hide();
    $win->tfDeltaDays->Hide();
    $win->upDownDeltaDays->Hide();
    $win->lblDeltaTime->Hide();
    $win->tfDeltaHours->Hide();
    $win->upDownDeltaHours->Hide();
    $win->lblSeparator1->Hide();
    $win->tfDeltaMinutes->Hide();
    $win->upDownDeltaMinutes->Hide();
    $win->lblSeparator2->Hide();
    $win->tfDeltaSecondes->Hide();
    $win->upDownDeltaSecondes->Hide();
  }
  &isProcessReady(0);

}  #--- End cbTime_Change

#--------------------------#
sub cbInputTimeType_Change
#--------------------------#
{
  # Possibles value are 0 = 'Datetime', 1 = 'ChromeTime', 2 = 'LDAPTime', 3 = 'Filetime', 4 = 'SystemTime', 5 = 'MacAbsTime', 6 = 'MacHFS'
  if (!$win->cbInputTimeType->GetCurSel()) { $win->cbInputDTFormat->Enable();  } # Datetime
  else                                     { $win->cbInputDTFormat->Disable(); } # Else
  &isProcessReady(0);
  
}  #--- End cbInputTimeType_Change

#--------------------------#
sub cbOutputDTFormat_Change { &isProcessReady(0); }
#--------------------------#

#--------------------------#
sub chSingleDate_Click
#--------------------------#
{
  if ($win->chSingleDate->Checked()) { &hideList2(); } # Hide List 2
  else                               { &showList2(); } # Show List 2
  &isProcessReady(0);

}  #--- End chSingleDate_Click

#--------------------------#
sub cbUtils_Change
#--------------------------#
{
  # Local variables
  my $selFunc  = $win->cbUtils->GetCurSel();
  # Possibles value are 0 = 'NSLookup', 1 = 'CIDR to IP Range', 2 = 'IP Range to CIDR', 3 = 'CIDR to IP list',
  # 4 = 'IP to Arpa', 5 = 'Arpa to IP', 6 = 'Resolve MAC Address', 7 = 'Resolve GeoIP', 8 = 'Resolve ISP',
  # 9 = 'Resolve User-agent', 10 = 'Credit Card to issuing company', 11 = 'Address to GPS coordinates',
  # 12 = 'GPS to address', 13 = 'Distance between locations', 14 = 'Custom functions'
  
  # Show or Hide List 2
  if    ($selFunc != 13)                    { &hideList2(); }
  elsif ($win->chSingleLocation->Checked()) { &hideList2(); }
  else                                      { &showList2(); }
  # Show Resolve MAC Address options
  if   ($selFunc == 6) {
    $win->lblCurrMACOUIdbDate->Show();
    $win->btnMACOUIdbUpdate->Show();
    if (!$win->lblCurrMACOUIdbDate->Text()) {
      my $localMACOUIDB = $winConfig->tfMACOUIDB->Text();
      if (!$localMACOUIDB or !-f $localMACOUIDB) { # No database
        $win->lblCurrMACOUIdbDate->Text($STR{'noDB'});
        $win->btnMACOUIdbUpdate->Text($STR{'Download'}.'...');
      } else { # Show current DB date
        my $localFileT = DateTime->from_epoch(epoch => (stat($localMACOUIDB))[9]);
        $win->lblCurrMACOUIdbDate->Text("$STR{'currDBDate'}: ". $localFileT->ymd());
        $win->btnMACOUIdbUpdate->Text($STR{'Update'}.'...');
      }
    }
  } else { $win->lblCurrMACOUIdbDate->Hide(); $win->btnMACOUIdbUpdate->Hide(); }
  # Add headers option
  if ($selFunc == 7 or $selFunc == 9 or ($selFunc == 12 and $win->cbGPS2AddrOutput->GetCurSel())) {
    $win->chAddHeaders->Show();
  } else { $win->chAddHeaders->Hide(); }
  # Show Resolve GeoIP options
  if   ($selFunc == 7) {
    $win->lblGeoIPLang->Show();
    $win->cbGeoIPLang->Show();
    $win->chGeoIPOptAll->Show();
    $win->gridGeoIPOpts->Show();
  } else {
    $win->lblGeoIPLang->Hide();
    $win->cbGeoIPLang->Hide();
    $win->chGeoIPOptAll->Hide();
    $win->gridGeoIPOpts->Hide();
  }
  # Valid XL-Whois Database
  &tfXLWHOISDB_Change() if $selFunc == 8;
  # Show User-Agent options
  if   ($selFunc == 9) {
    $win->chUAOptAll->Show();
    $win->gridUAOpts->Show();
  } else {
    $win->chUAOptAll->Hide();
    $win->gridUAOpts->Hide();
  }
  # Show Credit Card to Issuing Company options
  if   ($selFunc == 10) { $win->rbIINLocalDB->Show(); $win->rbBinlist->Show(); }
  else                  { $win->rbIINLocalDB->Hide(); $win->rbBinlist->Hide(); }
  # Show Address to GPS options
  if   ($selFunc == 11) { $win->chAddr2GPSInc->Show(); }
  else                  { $win->chAddr2GPSInc->Hide(); }
  # Show GPS to Address options
  if   ($selFunc == 12) {
    $win->lblGPS2AddrZL->Show();
    $win->cbGPS2AddrZL->Show();
    $win->cbGPS2AddrOutput->Show();
    $win->gridGPS2AddrOpts->Show() if $win->cbGPS2AddrOutput->GetCurSel() == 2;
  } else {
    $win->lblGPS2AddrZL->Hide();
    $win->cbGPS2AddrZL->Hide();
    $win->cbGPS2AddrOutput->Hide();
    $win->gridGPS2AddrOpts->Hide();
  }
  # Distance between locations options
  if   ($selFunc == 13) { $win->chSingleLocation->Show(); $win->tfSingleLocation->Show(); }
  else                  { $win->chSingleLocation->Hide(); $win->tfSingleLocation->Hide(); }
  # Custom Functions options
  if   ($selFunc == 14) {
    $win->cbCFLists->Show();
    $win->cbCFLists->Enable();
    $win->btnCFAdd->Show();
    $win->btnCFRem->Show();
    $win->btnCFEdit->Show();
    $win->btnCFNew->Show();
  } else {
    $win->cbCFLists->Hide();
    $win->btnCFAdd->Hide();
    $win->btnCFRem->Hide();
    $win->btnCFEdit->Hide();
    $win->btnCFNew->Hide();
    $win->chCFMatchCase->Hide();
    $win->lblCFTitle->Hide();
    $win->tfCFTitle->Hide();
    $win->btnCFSave->Hide();
    $win->btnCFCancel->Hide();
  }
  &isProcessReady(0);

}  #--- End cbUtils_Change

#--------------------------#
sub btnMACOUIdbUpdate_Click { &btnMACOUIDBUpt_Click(); }
sub rbIINLocalDB_Click      { &isProcessReady(0);      }
sub rbBinlist_Click         { &isProcessReady(0);      }
#--------------------------#

#--------------------------#
sub btnList1File_Click
#--------------------------#
{
  # Show OpenFile dialog window
  my $file = Win32::GUI::GetOpenFileName( -owner         => $win                              ,
                                          -title         => $STR{'selectFile'}                ,
                                          -filter        => ["$STR{'text'} (*.txt)", "*.txt"] ,
                                          -defaultfilter => 0                                 ,
                                          -filemustexist => 1                                 ,
                                          -explorer      => 1                                 , );
  # Text format only
  if ($file and -T $file) {
    $win->tfList1->Enable();
    $win->tfList1->Text('');
    $win->tfList1->Text("$STR{'useFile'}: \"$file\"");
    &tfList1_Change();
  } elsif ($file) { Win32::GUI::MessageBox($win, $STR{'invalidFile'}, $STR{'Error'}, 0x40010); }
  &isProcessReady(0);

}  #--- End btnList1File_Click

#--------------------------#
sub btnList1Del_Click
#--------------------------#
{
  $win->tfList1->Text('');
  $win->tfList1->Enable();
  $win->lblList1Count->Text(0);
  &isProcessReady(0);

}  #--- End btnList1Del_Click

#--------------------------#
sub btnList1UseRes_Click
#--------------------------#
{
  $win->tfList1->Text($win->tfList3->Text()) if $win->tfList3->Text();
  &tfList1_Change();
  &isProcessReady(0);

}  #--- End btnList1UseRes_Click

#--------------------------#
sub tfList1_Change
#--------------------------#
{
  # Count items
  my $count = 0;
  my $first = $win->tfList1->GetLine(0);
  my $file;
  # Items are in a file?
  if ($first =~ /^$STR{'useFile'}: \"([^\"]+)\"$/) { $file = $1; }
  if ($file and -T $file) {
    # Items are in a file
    if (open my $fh, '<', $file) {
      while (sysread $fh, my $buffer, 4096) { $count += ($buffer =~ tr/\n//); }
      close($fh);
    } else { Win32::GUI::MessageBox($win, "$STR{'errorReading'}: ".$!, $STR{'Error'}, 0x40010); }
  # Items are in the textfield
  } else { $count = $win->tfList1->GetLineCount(); }
  # Update counter
  $count = 0 if $count == 1 and $win->tfList1->GetLine(0) eq '';
  $win->lblList1Count->Text($count);
  # If New Custom Function
  &validNewFunc(\$win, \%STR) if $win->tfCFTitle->IsVisible();
  &isProcessReady(0);

}  #--- End tfList1_Change

#--------------------------#
sub tfList1_MaxText { Win32::GUI::MessageBox($win, $STR{'maxSizeReached'}, $STR{'Warning'}, 0x40030); } # Popup warning
#--------------------------#

#--------------------------#
sub btnList2File_Click
#--------------------------#
{
  # Show OpenFile dialog window
  my $file = Win32::GUI::GetOpenFileName( -owner         => $win                              ,
                                          -title         => $STR{'selectFile'}                ,
                                          -filter        => ["$STR{'text'} (*.txt)", "*.txt"] ,
                                          -defaultfilter => 0                                 ,
                                          -filemustexist => 1                                 ,
                                          -explorer      => 1                                 , );
  # Text format only
  if ($file and -T $file) {
    $win->tfList2->Enable();
    $win->tfList2->Text('');
    $win->tfList2->Text("$STR{'useFile'}: \"$file\"");
    &tfList2_Change();
  } elsif ($file) { Win32::GUI::MessageBox($win, $STR{'invalidFile'}, $STR{'Error'}, 0x40010); }
  &isProcessReady(0);

}  #--- End btnList2File_Click

#--------------------------#
sub btnList2Del_Click
#--------------------------#
{
  $win->tfList2->Text('');
  $win->tfList2->Enable();
  $win->lblList2Count->Text(0);
  &isProcessReady(0);

}  #--- End btnList2Del_Click

#--------------------------#
sub tfList2_Change
#--------------------------#
{
  # Count items
  my $count = 0;
  my $first = $win->tfList2->GetLine(0);
  my $file;
  # Items are in a file?
  if ($first =~ /^$STR{'useFile'}: \"([^\"]+)\"$/) { $file = $1; }
  if ($file and -T $file) {
    # Items are in a file
    if (open my $fh, '<', $file) {
      while (sysread $fh, my $buffer, 4096) { $count += ($buffer =~ tr/\n//); }
      close($fh);
    } else { Win32::GUI::MessageBox($win, "$STR{'errorReading'}: ".$!, $STR{'Error'}, 0x40010); }
  # Items are in the textfield
  } else { $count = $win->tfList2->GetLineCount(); }
  # Update counter
  $count = 0 if $count == 1 and $win->tfList2->GetLine(0) eq '';
  $win->lblList2Count->Text($count);
  # If New Custom Function
  &validNewFunc(\$win, \%STR) if $win->tfCFTitle->IsVisible();
  &isProcessReady(0);

}  #--- End tfList2_Change

#--------------------------#
sub tfList2_MaxText { Win32::GUI::MessageBox($win, $STR{'maxSizeReached'}, $STR{'Warning'}, 0x40030); } # Popup warning 
#--------------------------#

#--------------------------#
sub btnList3Open_Click
#--------------------------#
{
  # Local variables
  my $file = $win->tfList3->GetLine(0);
  if ($file =~ /^\"([^\"]+)\"$/) { $file = $1; }
  # Open file with default program
  if ($file and -T $file) {
    $win->ShellExecute('open', $file,'','',1) or
    Win32::GUI::MessageBox($win, "$STR{'errorOpening'}: ".Win32::FormatMessage(Win32::GetLastError()), $STR{'Error'}, 0x40010);
  }

}  #--- End btnList3Open_Click

#--------------------------#
sub tfList3_Change
#--------------------------#
{
  if ($win->tfList3->Text()) { $win->btnList1UseRes->Enable();  }
  else                       { $win->btnList1UseRes->Disable(); }
  
}  #--- End tfList3_Change

#--------------------------#
# CTRL + A (Select All)
#--------------------------#
sub tfList1_GotFocus  { $LISTNO = 1; }
sub tfList2_GotFocus  { $LISTNO = 2; }
sub tfList3_GotFocus  { $LISTNO = 3; }
sub tfList1_LostFocus { $LISTNO = 0; }
sub tfList2_LostFocus { $LISTNO = 0; }
sub tfList3_LostFocus { $LISTNO = 0; }

#--------------------------#
sub selectAll_Click
#--------------------------#
{
  if    ($LISTNO == 1) { $win->tfList1->SelectAll(); }
  elsif ($LISTNO == 2) { $win->tfList2->SelectAll(); }
  elsif ($LISTNO == 3) { $win->tfList3->SelectAll(); }
  
}  #--- End selectAll_Click

#--------------------------#
sub fontSizeS_Click
#--------------------------#
{
  if ($LISTNO) {
    # Get current font details
    if (my $currFont = $win->tfList1->GetFont()) {
      my @details = Win32::GUI::Font::Info($currFont);
      # Decrease font size
      my $i = 0;
      foreach (@details) {
        if (/-height/) { $details[$i+1]--; last; }
        $i++;
      }
      $fontTF = new Win32::GUI::Font(@details);
      $win->tfList1->Change(-font => $fontTF);
      $win->tfList1->Update();
      $win->tfList2->Change(-font => $fontTF);
      $win->tfList2->Update();
      $win->tfList3->Change(-font => $fontTF);
      $win->tfList3->Update();
      my $customFont;
      foreach (@details) { $customFont .= $_ . ','; }
      chop($customFont);
      $CONFIG{'TFLIST_FONT'} = $customFont;
      &saveConfig(\%CONFIG, $CONFIG_FILE);
      # Update all textfields
      if    ($LISTNO == 1) { $win->tfList2->SetFocus(); $win->tfList3->SetFocus(); $win->tfList1->SetFocus(); }
      elsif ($LISTNO == 2) { $win->tfList1->SetFocus(); $win->tfList3->SetFocus(); $win->tfList2->SetFocus(); }
      elsif ($LISTNO == 3) { $win->tfList1->SetFocus(); $win->tfList2->SetFocus(); $win->tfList3->SetFocus(); }
    }
  }
  return(1);
  
}  #--- End fontSizeS_Click

#--------------------------#
sub fontSizeB_Click
#--------------------------#
{
  if ($LISTNO) {
    # Get current font details
    if (my $currFont = $win->tfList1->GetFont()) {
      my @details = Win32::GUI::Font::Info($currFont);
      # Increase font size
      my $i = 0;
      foreach (@details) {
        if (/-height/) { $details[$i+1]++; last; }
        $i++;
      }
      $fontTF = new Win32::GUI::Font(@details);
      $win->tfList1->Change(-font => $fontTF);
      $win->tfList1->Update();
      $win->tfList2->Change(-font => $fontTF);
      $win->tfList2->Update();
      $win->tfList3->Change(-font => $fontTF);
      $win->tfList3->Update();
      my $customFont;
      foreach (@details) { $customFont .= $_ . ','; }
      chop($customFont);
      $CONFIG{'TFLIST_FONT'} = $customFont;
      &saveConfig(\%CONFIG, $CONFIG_FILE);
      # Update all textfields
      if    ($LISTNO == 1) { $win->tfList2->SetFocus(); $win->tfList3->SetFocus(); $win->tfList1->SetFocus(); }
      elsif ($LISTNO == 2) { $win->tfList1->SetFocus(); $win->tfList3->SetFocus(); $win->tfList2->SetFocus(); }
      elsif ($LISTNO == 3) { $win->tfList1->SetFocus(); $win->tfList2->SetFocus(); $win->tfList3->SetFocus(); }
    }
  }
  return(1);
  
}  #--- End fontSizeB_Click

#--------------------------#
sub lblNotReady_Click { &isProcessReady(1); }
#--------------------------#

#--------------------------#
sub isProcessReady
#--------------------------#
{
  # Local variables
  my $confirm = shift;
  my $nextStep;
  # Status of List1 and List2
  my $nbrList1 = $win->lblList1Count->Text();
  my $nbrList2 = $win->lblList2Count->Text();
  # Every function require items in List1, except some functions in Lists
  if (!$nbrList1 and $win->Tab->SelectedItem() != 0) { $nextStep = "$STR{'insertList1'} $STR{'seeDoc'}"; }
  else {
    $win->btnInputFormatGuess->Enable();
    # Lists tab selected
    if ($win->Tab->SelectedItem() == 0) {
      my $selFunc = $win->cbLists->GetCurSel();
      # Possibles value are 0 = 'No duplicate', 1 = 'Only duplicates', 2 = 'Count items', 3 = 'Count characters',
      # 4 = 'L1-L2', 5 = 'Column to row', 6 = 'Row to column', 7 = 'List to regex', 8 = 'Concat', 9 = 'Split strings',
      # 10 = 'Split and extract', 11 = 'Merge lines', 12 = 'Split and merge', 13 = 'Replace', 14 = 'Reverse string',
      # 15 = 'Transliterate', 16 = 'Lowercase', 17 = 'Uppercase', 18 = 'Add line number'
      
      # Some functions require items in List 1 or in List 2
      if ($selFunc == 1 or $selFunc == 4 or $selFunc == 8) {
        $nextStep = $STR{'insertLists'} if !$nbrList1 and !$nbrList2;
      # Other require items in List 1 only
      } elsif (!$nbrList1) { $nextStep = $STR{'insertList1'}; }
      # Some functions require a value in With textfield
      if (($selFunc == 9 or $selFunc == 10 or $selFunc == 12) and !$win->tfWith->Text()) {
        $nextStep = "$STR{'insertWith'} $STR{'seeDoc'}";
      }
      # Some functions require a value in Columns textfield
      if (($selFunc == 10 or $selFunc == 11 or $selFunc == 12) and !$win->tfColumnsNo->Text()) {
        $nextStep = "$STR{'insertColumns'} $STR{'seeDoc'}";
      }
      # Replace function require value in Replace textfield
      if (($selFunc == 13 or $selFunc == 15) and !$win->tfReplace->Text()) {
        $nextStep = $STR{'insertReplace'};
      } elsif ($selFunc == 12 and ($win->chRegex->Checked() or $win->chEval->Checked())) { # Valid regex
        # Regex is valid?
        if ($win->chRegex->Checked()) {
          if ($win->tfReplace->Text()) {
            my ($status, $msg) = &validRegex($win->tfReplace->Text());
            if ($status and $status == 1) {
              $nextStep = $STR{'errRegex'} . ' ' . $STR{'errRegexReplace'} . ":\n\n";
              $nextStep .= $msg if $msg;
            }
          }
          # Replacement expression is valid?
          if ($win->tfReplBy->Text()) {
            my ($status, $msg) = &validReplacement(\$win);
            if ($status and $status == 1) {
              $nextStep = $STR{'errBy'} . ' ' . $STR{'errRegexReplaceBy'} . ":\n\n";
              $nextStep .= $msg if $msg;
            }
          }
        }
      }
    # Sorting tab selected
    } elsif ($win->Tab->SelectedItem() == 1) { # No special condition for now
    # Conversion tab selected
    } elsif ($win->Tab->SelectedItem() == 2) { # No special condition for now
    # Time tab selected
    } elsif ($win->Tab->SelectedItem() == 3) {
      my $selFunc = $win->cbTime->GetCurSel();
      # Possibles value are 0 = 'Anytime to Anytime', 1 = 'Time difference', 2 = 'Add time', 3 = 'Substract time'
      
      # If InputType is not a Datetime object, Output format can't be "Same as input"
      # Possibles value are 0 = 'Datetime', 1 = 'ChromeTime', 2 = 'LDAPTime', 3 = 'Filetime', 4 = 'SystemTime', 5 = 'MacAbsTime', 6 = 'MacHFS'
      if ($win->cbInputTimeType->GetCurSel() and !$win->cbOutputDTFormat->GetCurSel() and !$winDTDB->cbDefaultOutput->GetCurSel()) {
        $nextStep = $STR{'setOutputFormat'};
      }
      # 'Time difference' can be used with a single date or with items in List 2
      # If so, number of items in List 1 and List 2 must be the same
      if ($selFunc == 1 and !$win->chSingleDate->Checked()) {
        my $refList1  = &enumItems(\$win->tfList1, \$win, \%STR);
        my $refList2  = &enumItems(\$win->tfList2, \$win, \%STR);
        $nextStep = $STR{'insertSameNbr'} if scalar(@{$refList1}) != scalar(@{$refList2});
      }
    # Utils tab selected
    } elsif ($win->Tab->SelectedItem() == 4) {
      my $selFunc = $win->cbUtils->GetCurSel();
      # Possibles value are 0 = 'NSLookup', 1 = 'CIDR to IP Range', 2 = 'IP Range to CIDR', 3 = 'CIDR to IP list',
      # 4  = 'IP to Arpa', 5 = 'Arpa to IP', 6 = 'Resolve MAC Address', 7 = 'Resolve GeoIP', 8 = 'Resolve ISP',
      # 9  = 'Resolve User-agent', 10 = 'Credit Card to issuing company', 11 = 'Address to GPS coordinates',
      # 12 = 'Address to GPS coordinates', 13 = 'Distance between locations', 14 = 'Custom functions'
      
      # 'Resolve MAC Address' requires MACOUI database
      if    ($selFunc == 6) {
        my $MACOUIDB = $winConfig->tfMACOUIDB->Text();
        $nextStep = "$STR{'validDB1'} $STR{'MACOUIDB'} $STR{'validDB2'} $STR{'seeDoc'}" if !-e $MACOUIDB;
      # 'Resolve GeoIP' requires GeoIP database and at least one detail
      } elsif ($selFunc == 7) {
        my $GeoIPDB = $winConfig->tfGeoIPDB->Text();
        $nextStep = "$STR{'validDB1'} $STR{'GeoIPDB'} $STR{'validDB2'} $STR{'seeDoc'}" if !-e $GeoIPDB;
        # Browse grid and check if at least one checked option
        my $check = 0;
        for (my $i = 0; $i < 5; $i++) {
          $check = 1 if $win->gridGeoIPOpts->GetCellCheck(0, $i) or $win->gridGeoIPOpts->GetCellCheck(1, $i);
        }
        $nextStep = $STR{'checkOpt'} if !$check;
      # 'Resolve ISP' requires XL-Whois database
      } elsif ($selFunc == 8) {
        my $XLWHOISDBFile = $winConfig->tfXLWHOISDB->Text();
        $nextStep = "$STR{'validDB1'} $STR{'XLWhoisDB'} $STR{'validDB2'} $STR{'seeDoc'}" if !-e $XLWHOISDBFile;
      # 'Resolve Useragent' require at least one detail
      } elsif ($selFunc == 9) {
        # Browse grid and check if at least one checked option
        my $check = 0;
        for (my $i = 0; $i < 3; $i++) {
          $check = 1 if $win->gridUAOpts->GetCellCheck(0, $i) or $win->gridUAOpts->GetCellCheck(1, $i);
        }
        $nextStep = $STR{'checkOpt'} if !$check;
      # 'Credit Card to issuing company' requires IIN database if local option is checked
      } elsif ($selFunc == 10 and $win->rbIINLocalDB->Checked()) {
        my $IINFile = $winConfig->tfIINDB->Text();
        $nextStep = "$STR{'validDB1'} $STR{'IINDB'} $STR{'validDB2'} $STR{'seeDoc'}" if !-e $IINFile;
      # 'Address to GPS' and 'GPS to Address' requirements
      } elsif ($selFunc == 11 or $selFunc == 12) {
        if ($selFunc == 12) {
          my $selOutput = $win->cbGPS2AddrOutput->GetString($win->cbGPS2AddrOutput->GetCurSel());
          my $OSMFile   = $winConfig->tfOSMDB->Text();
          $nextStep     = "$STR{'validDB1'} $STR{'OSMDB'} $STR{'validDB2'} $STR{'seeDoc'}" if !-e $OSMFile;
          if ($selOutput and $selOutput eq $STR{'AddressEl'}) {
            # Browse grid and check if at least one checked option
            my $check = 0;
            for (my $i = 0; $i < 6; $i++) {
              $check = 1 if $win->gridGPS2AddrOpts->GetCellCheck(0, $i) or $win->gridGPS2AddrOpts->GetCellCheck(1, $i);
            }
            $nextStep = $STR{'checkOpt'} if !$check;
          }
        }
        $nextStep = $STR{'emailRequired'} if $nbrList1 > 25 and !$CONFIG{'EMAIL'};
      # Distance between locations
      } elsif ($selFunc == 13) {
        if ($win->chSingleLocation->Checked()) {
          if (!$win->tfSingleLocation->Text()) { $nextStep = $STR{'reqLocation'}; }
        } else { # A list of location in list 1 to compare with list 2, must be the same number of items
          my $refList1  = &enumItems(\$win->tfList1, \$win, \%STR);
          my $refList2  = &enumItems(\$win->tfList2, \$win, \%STR);
          $nextStep = $STR{'insertSameNbr'} if scalar(@{$refList1}) != scalar(@{$refList2});
        }
      # In 'Custom functions', a function must be selected, except if we are adding or modifying a function
      } elsif ($selFunc == 14 and !$win->cbCFLists->GetCurSel() and !$win->tfCFTitle->IsVisible()) {
        $nextStep = $STR{'selectFunc'};
      }
    }
  }
  # Return an error message or enable the button
  if ($nextStep) {
    $win->btnInputFormatGuess->Disable();
    $win->btnProcess->Disable();
    $win->lblNotReady->Show();
    Win32::GUI::MessageBox($win, "$STR{'notReady'}?\n\n$STR{'nextStep'}: $nextStep", $STR{'notReady'}, 0x40040) if $confirm;
  } else {
    $win->btnProcess->Enable() if $win->cbCFLists->IsEnabled();
    $win->lblNotReady->Hide();
  }

}  #--- End isProcessReady

#--------------------------#
sub btnProcess_Click
#--------------------------#
{
  # Avoid new thread
  if ($THR_PROCESS and $THR_PROCESS->is_running()) { Win32::GUI::MessageBox($win, $STR{'processRunning'}, $STR{'Error'}, 0x40010); }
  else {
    $THR_PROCESS = threads->create(sub {
      # Thread cancel signal handler
      $SIG{'KILL'} = sub {
        $win->lblPbCurr->Text('');
        $win->pb->SetPos(0);
        $win->lblPbCount->Text('');
        $win->lblPbCurr->Hide();
        $win->pb->Hide();
        $win->lblPbCount->Hide();
        $win->btnProcess->Show();
        $win->btnStop->Hide();
        $win->ChangeCursor($ARROW);
        threads->exit();
      };
      # Thread die signal handler
      $SIG{__DIE__} = sub {
        return if $_ and $_[0] =~ /Invalid version format/;
        return if $_[0] and ($_[0]->isa('GeoIP2::Error::Generic') or $_[0]->isa('GeoIP2::Error::IPAddressNotFound'));
        my $errMsg = (split(/ at /, $_[0]))[0];
        $errMsg    =~ s/[\t\r\n]/ /g;
        $win->lblPbCurr->Text('');
        $win->pb->SetPos(0);
        $win->lblPbCount->Text('');
        $win->lblPbCurr->Hide();
        $win->pb->Hide();
        $win->lblPbCount->Hide();
        $win->btnProcess->Show();
        $win->btnStop->Hide();
        $win->ChangeCursor($ARROW);
        Win32::GUI::MessageBox($win, "$STR{'errorMsg'}: $errMsg", $STR{'Error'}, 0x40010);
        threads->exit();
      };
      # Local variables
      my $refList3;
      # Reset list 3
      $win->tfList3->Text('');
      $win->lblList3Count->Text(0);
      # Gather items
      my $refList1  = &enumItems(\$win->tfList1, \$win, \%STR);
      my $refList2  = &enumItems(\$win->tfList2, \$win, \%STR);
      # Show progress
      $win->lblPbCurr->Text('');
      $win->pb->SetPos(0);
      $win->lblPbCount->Text('');
      $win->lblPbCurr->Show();
      $win->pb->Show();
      $win->lblPbCount->Show();
      $win->lblPbCurr->Text($STR{'startingProcess'}.'...');
      $win->btnProcess->Hide();
      $win->btnStop->Show();
      $win->ChangeCursor($HOURGLASS);
      # Lists tab selected
      if (!$win->Tab->SelectedItem()) {
        my $selFunc = $win->cbLists->GetCurSel();
        # Possibles value are 0 = 'No duplicate', 1 = 'Only duplicates', 2 = 'Count items', 3 = 'Count characters',
        # 4 = 'L1-L2', 5 = 'Column to row', 6 = 'Row to column', 7 = 'List to regex', 8 = 'Concat', 9 = 'Split strings',
        # 10 = 'Split and extract', 11 = 'Merge lines', 12 = 'Split and merge', 13 = 'Replace', 14 = 'Reverse string',
        # 15 = 'Transliterate', 16 = 'Lowercase', 17 = 'Uppercase', 18 = 'Add line number'
        if    (!$selFunc)      { $refList3 = &noDuplicates($refList1, $refList2, \$win, \%STR);    }
        elsif ($selFunc ==  1) { $refList3 = &onlyDuplicates($refList1, $refList2, \$win, \%STR);  }
        elsif ($selFunc ==  2) { $refList3 = &countDuplicates($refList1, $refList2, \$win, \%STR); }
        elsif ($selFunc ==  3) { $refList3 = &countChars($refList1, $refList2, \$win, \%STR);      }
        elsif ($selFunc ==  4) { $refList3 = &L1_less_L2($refList1, $refList2, \$win, \%STR);      }
        elsif ($selFunc ==  5) { $refList3 = &col2row($refList1, $refList2, \$win, \%STR);         }
        elsif ($selFunc ==  6) { $refList3 = &row2col($refList1, $refList2, \$win, \%STR);         }
        elsif ($selFunc ==  7) { $refList3 = &list2regex($refList1, $refList2, \$win, \%STR);      }
        elsif ($selFunc ==  8) { $refList3 = &concatStr($refList1, $refList2, \$win, \%STR);       }
        elsif ($selFunc ==  9) { $refList3 = &splitStr($refList1, $refList2, \$win, \%STR);        }
        elsif ($selFunc == 10) { $refList3 = &splitExtract($refList1, $refList2, \$win, \%STR);    }
        elsif ($selFunc == 11) { $refList3 = &mergeLines($refList1, $refList2, \$win, \%STR);      }
        elsif ($selFunc == 12) { $refList3 = &splitMerge($refList1, $refList2, \$win, \%STR);      }
        elsif ($selFunc == 13) { $refList3 = &replace($refList1, $refList2, \$win, \%STR);         }
        elsif ($selFunc == 14) { $refList3 = &reverseStr($refList1, $refList2, \$win, \%STR);      }
        elsif ($selFunc == 15) { $refList3 = &transliterate($refList1, $refList2, \$win, \%STR);   }
        elsif ($selFunc == 16) { $refList3 = &lowercase($refList1, $refList2, \$win, \%STR);       }
        elsif ($selFunc == 17) { $refList3 = &uppercase($refList1, $refList2, \$win, \%STR);       }
        elsif ($selFunc == 18) { $refList3 = &addLineNumber($refList1, $refList2, \$win, \%STR);   }
      # Sorting tab selected
      } elsif ($win->Tab->SelectedItem() == 1) { $refList3 = &sortingTabFunc($refList1, $refList2);
      # Conversion tab selected
      } elsif ($win->Tab->SelectedItem() == 2) { $refList3 = &conversionTabFunc($refList1, $refList2);
      # Time tab selected
      } elsif ($win->Tab->SelectedItem() == 3) { $refList3 = &timeTabFunc($refList1, $refList2);
      # Utils tab selected
      } elsif ($win->Tab->SelectedItem() == 4) {
        my $selFunc = $win->cbUtils->GetCurSel();
        $refList3 = &utilsTabFunc($refList1, $refList2, \$winConfig, \%CONFIG, $CONFIG_FILE, \$win, \%STR);
      }
      # Progress
      $win->lblPbCurr->Text('');
      $win->pb->SetPos(0);
      $win->lblPbCount->Text('');
      $win->lblPbCurr->Hide();
      $win->pb->Hide();
      $win->lblPbCount->Hide();
      $win->btnProcess->Show();
      $win->btnStop->Hide();      
      $win->ChangeCursor($ARROW);
      # Write resulting list
      &writeResults($refList3, \%CONFIG, \$win, \%STR);
    });
  }

}  #--- End btnProcess_Click

#--------------------------#
sub btnStop_Click
#--------------------------#
{
  # Stop requests
  if ($THR_PROCESS and $THR_PROCESS->is_running()) { $THR_PROCESS->kill('KILL')->detach(); }
  return(1);

}  #--- End btnStop_Click

#--------------------------#
sub btnHelp_Click
#--------------------------#
{
  # Open XL-Tools documentation page with default browser
  $win->ShellExecute('open', $URL_DOC,'','',1) or Win32::GUI::MessageBox($win, Win32::FormatMessage(Win32::GetLastError()), $STR{'Error'}, 0x40010);

}  #--- End btnHelp_Click

#--------------------------#
sub btnAbout_Click
#--------------------------#
{
  # Create the window
  my $winAbout  = Win32::GUI::DialogBox->new( -name        => 'winAbout'                ,
                                              -parent      => $win                      ,
                                              -text        => $STR{'About'}.' XL-Tools' ,
                                              -pos         => [$winPosX, $winPosY]      ,
                                              -size        => [520, 170]                ,
                                              -background  => [255, 255, 255]           ,
                                              -hasmaximize => 0                         ,
                                              -hasminimize => 1                         ,
                                              -helpbutton  => 0                         ,
                                              -resizable   => 0                         ,
                                              -dialogui    => 1                         , );
  $winAbout->SetIcon($winICO);
  # About tab
  $winAbout->AddLabel(  -name        => 'lblLogo128'            ,
                        -size        => [128,128]               ,
                        -pos         => [  0,  5]               ,
                        -background  => [255, 255, 255]         ,
                        -bitmap      => $logo128Bmp             , );
  $winAbout->AddLabel(  -name        => 'lblAbout1'             ,
                        -size        => [ 90, 75]               ,
                        -pos         => [140, 10]               ,
                        -font        => $font10                 ,
                        -background  => [255, 255, 255]         ,
                        -text        => "$STR{'Version'}:\n$STR{'Website'}:\n$STR{'Author'}:\n$STR{'TranslatedBy'}:", );
  $winAbout->AddLabel(  -name        => 'lblAbout2'             ,
                        -size        => [230, 75]               ,
                        -pos         => [235, 10]               ,
                        -font        => $font10b                ,
                        -foreground  => [204,   0,  51]         ,
                        -background  => [255, 255, 255]         ,
                        -text        => "$VERSION\nhttp://www.le-tools.com\nAlain Rioux (admin\@le-tools.com)\n$STR{'translatorName'}", );
  $winAbout->AddLabel(  -name        => 'lblAbout3'             ,
                        -size        => [300, 20]               ,
                        -pos         => [140, 80]               ,
                        -font        => $font10                 ,
                        -background  => [255, 255, 255]         ,
                        -text        => '© Copyright 2015-2020 Alain Rioux', );
  $winAbout->Center($win);
  $winAbout->DoModal();
  return(1);

}  #--- End btnAbout_Click

#--------------------------#
sub sortingTabFunc
#--------------------------#
{
  # Local variables
  my ($refList1, $refList2) = @_;
  push(@{$refList1}, @{$refList2}); # Merge lists
  my $nbrItems = scalar(@{$refList1});
  my $selFunc  = $win->cbSorts->GetCurSel();
  # Possibles value are 0 = 'Alphabetical order', 1 = 'Numerical order', 2 = 'String length', 3 = 'IPv4 Address', 4 = 'Date and time'
  my $order;
  if ($win->rbAsc->Checked()) { $order = 0; } # Ascending
  else                        { $order = 1; } # Descending
  my @items;
  # Sort items
  # Alphabetical
  if    (!$selFunc and !$order) { @items = sort {lc $a cmp lc $b} @{$refList1}; } # Ascending
  elsif (!$selFunc and  $order) { @items = sort {lc $b cmp lc $a} @{$refList1}; } # Descending
  # Numerical
  elsif ($selFunc == 1 and !$order) { # Ascending
    @items = map $_->[0],
              sort { $a->[1] <=> $b->[1] }
                map  [ $_, /(\d+)/ ], @{$refList1};
  } 
  elsif ($selFunc == 1 and  $order) { # Descending
    @items = map $_->[0],
              sort { $b->[1] <=> $a->[1] }
                map  [ $_, /(\d+)/ ], @{$refList1};
  } 
  # String length
  elsif ($selFunc == 2 and !$order) { @items = sort {length($a) <=> length($b)} @{$refList1}; } # Ascending
  elsif ($selFunc == 2 and  $order) { @items = sort {length($b) <=> length($a)} @{$refList1}; } # Descending
  # IPv4 Address
  elsif ($selFunc == 3 and !$order) { # Ascending
    @items = map substr($_, 4) => sort {$a cmp $b} map pack('C4'
                               => /(\d+)\.(\d+)\.(\d+)\.(\d+)/) . $_
                               => @{$refList1};
  }
  elsif ($selFunc == 3 and  $order) { # Descending
    @items = map substr($_, 4) => sort {$b cmp $a} map pack('C4'
                               => /(\d+)\.(\d+)\.(\d+)\.(\d+)/) . $_
                               => @{$refList1};
  }
  # Date and time
  elsif ($selFunc == 4) {
    my ($sample, $pattern, $regex, $timezone);
    # Input Datetime format
    my $inputFormat = $win->cbInputDTFormat->GetString($win->cbInputDTFormat->GetCurSel());
    if ($inputFormat ne $STR{'guessORVar'}) {
      ($sample, $pattern, $regex, $timezone) = &findInputDTFormat($$refList1[0]);
    } else { $sample = $inputFormat; }
    if (!$order) { # Ascending
      @items = map  { $_->[0] }
                sort {$a->[1] cmp $b->[1]}
                  map { [$_, (str2Epoch($_, $sample, $pattern, $regex, 0, $timezone))[0]] } @{$refList1};
    } else       {  # Descending
      @items = map  { $_->[0] }
                sort {$b->[1] cmp $a->[1]}
                  map { [$_, (str2Epoch($_, $sample, $pattern, $regex, 0, $timezone))[0]] } @{$refList1};
    }
  # Random
  } elsif ($selFunc == 5) {
    for (my $i = $nbrItems; $i > 0; $i--) { push(@items, splice(@{$refList1}, rand($i), 1)); }
  }
  # Format results
  my $itemsRes;
  foreach (@items) { s/[\r\n]//g; $itemsRes .= "$_\r\n"; }
  return(\$itemsRes);  
  
}  #--- End sortingTabFunc

#--------------------------#
sub str2Epoch
#--------------------------#
{
  # Local variables
  my ($str, $sample, $pattern, $regex, $parseContext, $timezone) = @_;
  my $strp;
  # Guess Input Datetime format if not unique
  ($sample, $pattern, $regex, $timezone) = &findInputDTFormat($str) if $sample eq $STR{'guessORVar'};
  # Format
  if ($pattern and $str =~ /($regex)/) {
    my $extract = $1;
    my $before;
    my $after;
    $before = $` if $parseContext == 1 or $parseContext == 3;
    $after  = $' if $parseContext == 2 or $parseContext == 3;
    $strp = DateTime::Format::Strptime->new(pattern => $pattern, zone_map => \%ZONE_MAP, locale => $CONFIG{'DEFAULT_LANG'},);
    if (my $dt = $strp->parse_datetime($extract)) {
      my $inputTimezone = $dt->time_zone_long_name();
      $dt->set_time_zone($timezone) if $timezone and $pattern !~ /%s/;
      return($dt->epoch(), $inputTimezone, $pattern, $before, $after);
    } else { return(2); } # Error conversion
  } else { return(1);  } # Invalid input
  
}  #--- End str2Epoch

#--------------------------#
sub conversionTabFunc
#--------------------------#
{
  # Local variables
  my ($refList1, $refList2) = @_;
  push(@{$refList1}, @{$refList2}); # Merge lists
  my $nbrItems    = scalar(@{$refList1});
  my $selFunc     = $win->cbConv->GetCurSel();
  my $noResultOpt = $winConfig->rbNoResultOpt2->Checked();
  # Possibles value are 0 = 'Hex to ASCII', 1 = 'ASCII to Hex', 2 = 'Hex to Base10', 3 = 'Base10 to ASCII', 4 = 'URI Decode',
  # 5 = 'URI Encode', 6 = 'HTML Decode', 7 = 'HTML Encode', 8 = 'Base64 to ASCII', 9 = 'ASCII to Base64', 10 = 'SHA1 - Base32 to Base16',
  # 11 = 'SHA1 - Base16 to Base32'
  my $curr = 0;
  my @items;
  # Progress
  $win->pb->SetRange(0, $nbrItems);
  $win->pb->SetPos(0);
  $win->pb->SetStep(1);
  $win->lblPbCurr->Text($STR{'runningProcess'}.'...');
  $win->lblPbCount->Text("0 / $nbrItems");
  # 0 = 'Hex to ASCII'
  if ($selFunc == 0) {
    foreach my $item (@{$refList1}) {
      $item =~ s/[\r\n]//g;  # Remove any line break
      $item =~ s/[^0-9a-fA-F]//g; # Remove non hexadecimal
      if ($item) {
        #$item =~ s/(?:0x)?((?:[0-9a-fA-F]{2} ?)+)/pack 'H*', $1/ge;
        my $ascii = hex_to_ascii($item);
           $ascii =~ s/[\x00-\x1F\x80-\xFF]/./g; # Remove non printable characters
        push(@items, $ascii);
      } else {
        if ($noResultOpt) { push(@items, $STR{'noInput'}); }
        else { push(@items, undef); }
      }
      # Progress
      $curr++;
      $win->lblPbCount->Text("$curr / $nbrItems");
      $win->pb->StepIt();
    }
  }
  # 1 = 'ASCII to Hex'
  elsif ($selFunc == 1) {
    foreach my $item (@{$refList1}) {
      $item =~ s/[\r\n]//g;  # Remove any line break
      if ($item) {
        my $ascii = ascii_to_hex($item);
        push(@items, $ascii);
      } else {
        if ($noResultOpt) { push(@items, $STR{'noInput'}); }
        else { push(@items, undef); }
      }
      # Progress
      $curr++;
      $win->lblPbCount->Text("$curr / $nbrItems");
      $win->pb->StepIt();
    }
  }
  # 2 = 'Hex to Base10'
  elsif ($selFunc == 2) {
    foreach my $item (@{$refList1}) {
      $item =~ s/[\r\n]//g;  # Remove any line break
      $item =~ s/[^0-9a-fA-F\s]//g;
      if ($item) {
        # Convert string to a array of chars
        my @chars;
        if ($item =~ /\s/) { @chars = split(/\s/    , $item); }
        else               { @chars = split(/(.{1})/, $item); }
        # Keep spaces
        my $newItem = '';
        foreach (@chars) { $newItem .= hex($_) . " " if /[0-9a-fA-F]+/; }
        push(@items, $newItem);
      } else {
        if ($noResultOpt) { push(@items, $STR{'noInput'}); }
        else { push(@items, undef); }
      }
      # Progress
      $curr++;
      $win->lblPbCount->Text("$curr / $nbrItems");
      $win->pb->StepIt();
    }
  }
  # 3 = 'Base10 to ASCII'
  elsif ($selFunc == 3) {
    foreach my $item (@{$refList1}) {
      $item =~ s/[\r\n]//g;  # Remove any line break
      if ($item) {
        my @tab;
        while ($item =~ /(\d{1,3})/) {
          push(@tab, $1);
          my $longLigne = length($item);
          my $long      = length($1);
          my $pos       = index($item, $1);
          my $offset    = $pos+$long;
          $item         = substr($item,$offset,$longLigne-$offset);
        }
        my $newItem;
        foreach (@tab) { $newItem .= chr($_).' '; }
        push(@items, $newItem);
      } else {
        if ($noResultOpt) { push(@items, $STR{'noInput'}); }
        else { push(@items, undef); }
      }
      # Progress
      $curr++;
      $win->lblPbCount->Text("$curr / $nbrItems");
      $win->pb->StepIt();
    }
  }
  # 4 = 'URI Decode'
  elsif ($selFunc == 4) {
    foreach my $item (@{$refList1}) {
      $item =~ s/[\r\n]//g;  # Remove any line break
      if ($item) {
        $item =~ s/ /\%20/g;
        # UTF-8
        my $newItem = uri_unescape($item);
        $newItem = decode('utf8'  , $newItem);
        $newItem = encode('cp1252', $newItem);
        # Unicode
        $newItem =~ s/\\u([0-9a-fA-F]{4})/%u$1/g;
        $newItem = unescape($newItem);
        push(@items, $newItem);
      } else {
        if ($noResultOpt) { push(@items, $STR{'noInput'}); }
        else { push(@items, undef); }
      }
      # Progress
      $curr++;
      $win->lblPbCount->Text("$curr / $nbrItems");
      $win->pb->StepIt();
    }
  }
  # 5 = 'URI Encode'
  elsif ($selFunc == 5) {
    foreach my $item (@{$refList1}) {
      $item =~ s/[\r\n]//g;  # Remove any line break
      if ($item) {
        my $newItem = uri_escape_utf8($item);
        push(@items, $newItem);
      } else {
        if ($noResultOpt) { push(@items, $STR{'noInput'}); }
        else { push(@items, undef); }
      }
      # Progress
      $curr++;
      $win->lblPbCount->Text("$curr / $nbrItems");
      $win->pb->StepIt();
    }
  }
  # 6 = 'HTML Decode'
  elsif ($selFunc == 6) {
    foreach my $item (@{$refList1}) {
      $item =~ s/[\r\n]//g;  # Remove any line break
      if ($item) {
        my $newItem = decode_entities($item);
        push(@items, $newItem);
      } else {
        if ($noResultOpt) { push(@items, $STR{'noInput'}); }
        else { push(@items, undef); }
      }
      # Progress
      $curr++;
      $win->lblPbCount->Text("$curr / $nbrItems");
      $win->pb->StepIt();
    }
  }
  # 7 = 'HTML Encode'
  elsif ($selFunc == 7) {
    foreach my $item (@{$refList1}) {
      $item =~ s/[\r\n]//g;  # Remove any line break
      if ($item) {
        my $newItem = encode_entities($item);
        push(@items, $newItem);
      } else {
        if ($noResultOpt) { push(@items, $STR{'noInput'}); }
        else { push(@items, undef); }
      }
      # Progress
      $curr++;
      $win->lblPbCount->Text("$curr / $nbrItems");
      $win->pb->StepIt();
    }
  }
  # 8 = 'Base64 to ASCII'
  elsif ($selFunc == 8) {
    foreach my $item (@{$refList1}) {
      $item =~ s/[\r\n]//g;  # Remove any line break
      $item =~ s/ //g;
      if ($item) {
        my $newItem = MIME::Base64::decode($item);
        push(@items, $newItem);
      } else {
        if ($noResultOpt) { push(@items, $STR{'noInput'}); }
        else { push(@items, undef); }
      }
      # Progress
      $curr++;
      $win->lblPbCount->Text("$curr / $nbrItems");
      $win->pb->StepIt();
    }
  }
  # 9 = 'ASCII to Base64'
  elsif ($selFunc == 9) {
    foreach my $item (@{$refList1}) {
      $item =~ s/[\r\n]//g;  # Remove any line break
      if ($item) {
        my $newItem = MIME::Base64::encode($item);
        push(@items, $newItem);
      } else {
        if ($noResultOpt) { push(@items, $STR{'noInput'}); }
        else { push(@items, undef); }
      }
      # Progress
      $curr++;
      $win->lblPbCount->Text("$curr / $nbrItems");
      $win->pb->StepIt();
    }
  }
  # 10 = 'SHA1 - Base32 to Base16'
  elsif ($selFunc == 10) {
    foreach my $item (@{$refList1}) {
      $item =~ s/[\r\n]//g;  # Remove any line break
      if ($item and $item =~ /^(\w{32})/) {
        my $newItem = uc(unpack('H*', decode_base32($1)));
        push(@items, $newItem);
      } else {
        if ($noResultOpt) { push(@items, $STR{'noInput'}); }
        else { push(@items, undef); }
      }
      # Progress
      $curr++;
      $win->lblPbCount->Text("$curr / $nbrItems");
      $win->pb->StepIt();
    }
  }
  # 11 = 'SHA1 - Base16 to Base32'
  elsif ($selFunc == 11) {
    foreach my $item (@{$refList1}) {
      $item =~ s/[\r\n]//g;  # Remove any line break
      if ($item and $item =~ /^(\w{40})/) {
        my $newItem = uc(encode_base32(pack('H40', $1)));
        push(@items, $newItem);
      } else {
        if ($noResultOpt) { push(@items, $STR{'noInput'}); }
        else { push(@items, undef); }
      }
      # Progress
      $curr++;
      $win->lblPbCount->Text("$curr / $nbrItems");
      $win->pb->StepIt();
    }
  }
  # Format results
  my $itemsRes;
  foreach (@items) { $itemsRes .= $_ if $_; $itemsRes .= "\r\n"; }
  return(\$itemsRes);
  
}  #--- End conversionTabFunc

#--------------------------#
sub timeTabFunc
#--------------------------#
{
  # Local variables
  my ($refList1, $refList2) = @_;
  my $selFunc           = $win->cbTime->GetCurSel(); # Possibles value are 0 = 'Anytime to Anytime', 1 = 'Time difference',
                                                     #                     2 = 'Add time'          , 3 = 'Substract time'
  my $noResultOpt       = $winConfig->rbNoResultOpt2->Checked(); 
  my $selInputType      = $win->cbInputTimeType->GetCurSel(); # Possibles value are 0 = 'Datetime', 1 = 'ChromeTime', 2 = 'LDAPTime'  ,
                                                              #                     3 = 'Filetime', 4 = 'SystemTime', 5 = 'MacAbsTime',
                                                              #                     6 = 'MacHFS'
  my $localTZ           = $winConfig->cbLocalTZ->GetString($winConfig->cbLocalTZ->GetCurSel());
  my $selOutputDTFormat = $win->cbOutputDTFormat->GetCurSel();
  my ($sample, $pattern, $regex, $timezone); # Input
  my ($outPutPattern, $outputTZ);            # Output
  my $sameAsInput       = 0;                 # If == 1, don't use outputPattern, use input pattern instead
  my $parseContext      = $win->cbDTParser->GetCurSel(); # Possibles value are 0 = None, 1 = Before, 2 = After, 3 = Both
  my $curr              = 0;
  my @items;
  # Merge lists (except time difference)
  push(@{$refList1}, @{$refList2}) if $selFunc != 1;
  # Input Datetime format
  if (!$selInputType) {
    my $inputFormat = $win->cbInputDTFormat->GetString($win->cbInputDTFormat->GetCurSel());
    if ($inputFormat ne $STR{'guessORVar'}) {
      ($sample, $pattern, $regex, $timezone) = &findInputDTFormat($$refList1[0]);
    } else { $sample = $inputFormat; }
  }
  # Output format
  if (!$selOutputDTFormat) { # Default selected
    my $index = $winDTDB->cbDefaultOutput->GetCurSel();
    if (!$index) {
      if ($pattern and $timezone) {
        $outPutPattern = $pattern;
        $outputTZ      = $timezone;
      } else { $sameAsInput = 1; }
    } else {
      ($outPutPattern, $outputTZ) = (&infoDTFormat($winDTDB->cbDefaultOutput->GetString($index)))[1,3];
      $outputTZ = $localTZ if $outputTZ eq 'local';
    }
  } else {
    ($outPutPattern, $outputTZ) = (&infoDTFormat($win->cbOutputDTFormat->GetString($win->cbOutputDTFormat->GetCurSel())))[1,3];
    $outputTZ = $localTZ if $outputTZ eq 'local';
  }
  # Progress
  my $nbrItems = scalar(@{$refList1});
  $win->pb->SetRange(0, $nbrItems);
  $win->pb->SetPos(0);
  $win->pb->SetStep(1);
  $win->lblPbCurr->Text($STR{'runningProcess'}.'...');
  $win->lblPbCount->Text("0 / $nbrItems");
  # 0 = 'Anytime to Anytime'
  if (!$selFunc) {
    foreach my $item (@{$refList1}) {
      $item =~ s/[\r\n]//g;  # Remove any line break
      if ($item) {
        my ($epoch, $inputTimezone, $before, $after);
        # Datetime Input
        if (!$selInputType) {
          if ($pattern) {
            ($epoch, $inputTimezone, $pattern, $before, $after) = &str2Epoch($item, $sample, $pattern, $regex, $parseContext, $timezone);
          } else {
            ($epoch, $inputTimezone, $pattern, $before, $after) = &str2Epoch($item, $sample, undef   , undef , $parseContext, undef    );
          }
        # ChromeTime Input
        } elsif ($selInputType == 1) {
          if ($item =~ /([0-9]{17})/) {
            $epoch  = ($1/1000000)-11644473600; # Convert to unixtime
            $before = $` if $parseContext == 1 or $parseContext == 3;
            $after  = $' if $parseContext == 2 or $parseContext == 3;
          } else { $epoch  = 1;  } # Invalid input
        # LDAPTime Input
        } elsif ($selInputType == 2) {
          if ($item =~ /([0-9]{18})/) {
            $epoch  = ($1/10000000)-11644473600; # Convert to unixtime
            $before = $` if $parseContext == 1 or $parseContext == 3;
            $after  = $' if $parseContext == 2 or $parseContext == 3;
          } else { $epoch  = 1;  } # Invalid input
        # Windows FILETIME (64 bits hexadecimal) (Ex.: 88 33 9d cb 38 36 d0 01)
        } elsif ($selInputType == 3) {
          my $extract;
          if ($item =~ /((?:[0-9a-fA-F]{2} ?){7}[0-9a-fA-F]{2})/) {
            $extract = $1;
            $before = $` if $parseContext == 1 or $parseContext == 3;
            $after  = $' if $parseContext == 2 or $parseContext == 3;
          } else { $epoch  = 1;  } # Invalid input
          if ($extract) {
            $extract =~ s/ //g; # Remove space
            my $int64bits = string_to_int64(join('', reverse(split(/([0-9a-fA-F]{2})/, $extract))), 16); # All-in-one!
            $epoch = int(($int64bits-116444736000000000)/10000000); # Convert to unixtime
          }
        # Windows SYSTEMTIME (128 bits hexadecimal, ex.: D9070B00010002000600090013000000)
        } elsif ($selInputType == 4) {
          my $extract;
          if ($item =~ /((?:[0-9a-fA-F]{2} ?){15}[0-9a-fA-F]{2})/) {
            $extract = $1;
            $before = $` if $parseContext == 1 or $parseContext == 3;
            $after  = $' if $parseContext == 2 or $parseContext == 3;
          } else { $epoch  = 1;  } # Invalid input
          if ($extract) {
            $extract =~ s/ //g; # Remove space
            my @parts = split(/([0-9a-fA-F]{4} ?)/, $extract);
            my $y   = hex(join('', reverse(split(/([0-9a-fA-F]{2})/, $parts[1]))));
            my $m   = hex(join('', reverse(split(/([0-9a-fA-F]{2})/, $parts[3]))));
            my $d   = hex(join('', reverse(split(/([0-9a-fA-F]{2})/, $parts[7]))));
            my $h   = hex(join('', reverse(split(/([0-9a-fA-F]{2})/, $parts[9]))));
            my $min = hex(join('', reverse(split(/([0-9a-fA-F]{2})/, $parts[11]))));
            my $s   = hex(join('', reverse(split(/([0-9a-fA-F]{2})/, $parts[13]))));
            my $dt    = DateTime->new(year       => $y    ,
                                      month      => $m    ,
                                      day        => $d    ,
                                      hour       => $h    ,
                                      minute     => $min  ,
                                      second     => $s    ,
                                      time_zone  => $localTZ, );
            $epoch = $dt->epoch; # Convert to unixtime
          }
        # Mac Absolute time Input (01/01/2001)
        } elsif ($selInputType == 5) {
          if ($item =~ /([0-9]+)/) {
            $epoch  = $1 + 978307200; # Adjust to unixtime
            $before = $` if $parseContext == 1 or $parseContext == 3;
            $after  = $' if $parseContext == 2 or $parseContext == 3;
          } else { $epoch  = 1;  } # Invalid input
        # Mac HFS+ Input (01/01/1904)
        } elsif ($selInputType == 6) {
          if ($item =~ /([0-9]+)/) {
            $epoch  = $1 - 2082844800; # Adjust to unixtime
            $before = $` if $parseContext == 1 or $parseContext == 3;
            $after  = $' if $parseContext == 2 or $parseContext == 3;
          } else { $epoch  = 1;  } # Invalid input
        }
        # Convert to output
        if      ($epoch == 1) {
          if ($noResultOpt) { push(@items, $STR{'invalidInput'}); }
          else { push(@items, undef); }
        } elsif ($epoch == 2) {
          if ($noResultOpt) { push(@items, $STR{'errorConversion'}); }
          else { push(@items, undef); }
        } else {
          if (my $dt = DateTime->from_epoch(epoch => $epoch)) {
            if ($sameAsInput) { $inputTimezone = $localTZ if $inputTimezone eq 'floating'; $dt->set_time_zone($inputTimezone); }
            else              { $dt->set_time_zone($outputTZ); }
            $dt->set(locale => $CONFIG{'DEFAULT_LANG'});
            my $newItem;
            $newItem .= $before if $before;
            if ($sameAsInput) { $newItem .= $dt->strftime($pattern);       }
            else              { $newItem .= $dt->strftime($outPutPattern); }
            $newItem .= $after  if $after;
            push(@items, encode($CONFIG{'OUTPUT_CHARSET'}, $newItem));
          } else {
            if ($noResultOpt) { push(@items, $STR{'errorConversion'}); }
            else { push(@items, undef); }
          }
        }
      } else {
        if ($noResultOpt) { push(@items, $STR{'noInput'}); }
        else { push(@items, undef); }
      }
      # Progress
      $curr++;
      $win->lblPbCount->Text("$curr / $nbrItems");
      $win->pb->StepIt();
    }
  }
  # 1 = 'Time difference'
  elsif ($selFunc == 1) {
    my $timeDiff;
    my $dt2;
    # Local timezone
    $localTZ  = $winConfig->cbLocalTZ->GetString($winConfig->cbLocalTZ->GetCurSel());
    $outputTZ = DateTime::TimeZone->new(name => $localTZ);
    # If "Use a single date" option is checked
    if ($win->chSingleDate->Checked()) {
      my ($d, $m, $y)   = $win->dtTimeDiffDate->GetDate();
      my ($h, $min, $s) = $win->dtTimeDiffTime->GetTime();
      $dt2              = DateTime->new(year => $y, month  => $m  , day   => $d,
                                        hour => $h, minute => $min, second => $s, time_zone => $outputTZ);
      push(@{$refList1}, @{$refList2}); # Merge lists
    }
    my $outputFormat = $win->cbOutputDTDiff->GetCurSel(); # Formats : 0 = string, 1 = years, 2 = months, 3 = weeks, 4 = days,  5 = hours, 6 = minutes, 7 = seconds
    foreach my $item (@{$refList1}) {
      $item =~ s/[\r\n]//g;  # Remove any line break
      if ($item) {
        # Gather date in list 2
        if (!$win->chSingleDate->Checked() and my $item2 = $$refList2[$curr]) {
          $item2 =~ s/[\r\n]//g;  # Remove any line break
          if ($item2) {
            my ($epoch, $inputTimezone, $before, $after);
            if ($pattern) { ($epoch, $inputTimezone, $pattern, $before, $after) = &str2Epoch($item2, $sample, $pattern, $regex, $parseContext, $timezone); }
            else          { ($epoch, $inputTimezone, $pattern, $before, $after) = &str2Epoch($item2, $sample, undef   , undef , $parseContext, undef    ); }
            if ($epoch) {
              $dt2 = DateTime->from_epoch(epoch => $epoch);
              $dt2->set_time_zone($outputTZ);
            }
          }
        }
        # Gather date in list 1 and calculate difference
        if ($dt2) {
          my $dt1;
          my ($epoch, $inputTimezone, $before, $after);
          if ($pattern) { ($epoch, $inputTimezone, $pattern, $before, $after) = &str2Epoch($item, $sample, $pattern, $regex, $parseContext, $timezone); }
          else          { ($epoch, $inputTimezone, $pattern, $before, $after) = &str2Epoch($item, $sample, undef   , undef , $parseContext, undef    ); }
          if ($epoch) {
            $dt1 = DateTime->from_epoch(epoch => $epoch);
            $dt1->set_time_zone($outputTZ);
          }
          if ($dt1 and $dt2) {
            my $oldestDT = $dt1->epoch < $dt2->epoch ? $dt1 : $dt2;
            my $d = DateTime::Format::Duration->new(pattern   => "%Y $STR{'years'}, %m $STR{'months'}, %e $STR{'days'}, %H $STR{'hours'}, %M $STR{'minutes'}, %S $STR{'seconds'}",
                                                    normalize => 1,
                                                    base      => $oldestDT
                                                    );
            my $diffInSec = $dt1->subtract_datetime_absolute($dt2);
            if ($outputFormat) { # Absolute values
              my $val = Time::Seconds->new($diffInSec->{seconds});
              if    ($outputFormat == 1) { push(@items, abs(int($val->years)));   }
              elsif ($outputFormat == 2) { push(@items, abs(int($val->months)));  }
              elsif ($outputFormat == 3) { push(@items, abs(int($val->weeks)));   }
              elsif ($outputFormat == 4) { push(@items, abs(int($val->days)));    }
              elsif ($outputFormat == 5) { push(@items, abs(int($val->hours)));   }
              elsif ($outputFormat == 6) { push(@items, abs(int($val->minutes))); }
              elsif ($outputFormat == 7) { push(@items, abs(int($val->seconds))); }
            } else { push(@items, $d->format_duration($diffInSec)); } # Output string (normalized)
          } else {
            if ($noResultOpt) { push(@items, $STR{'errorConversion'}); }
            else { push(@items, undef); }
          }
        } else {
          if ($noResultOpt) { push(@items, $STR{'invalidInput'}); }
          else { push(@items, undef); }
        }
      } else {
        if ($noResultOpt) { push(@items, $STR{'noInput'}); }
        else { push(@items, undef); }
      }
      # Progress
      $curr++;
      $win->lblPbCount->Text("$curr / $nbrItems");
      $win->pb->StepIt();
    }
  }
  
  # 2 = 'Add time' and 3 = 'Substract time'
  elsif ($selFunc == 2 or $selFunc == 3) {
    my $offsetY     = $win->tfDeltaYears->Text();
    my $offsetM     = $win->tfDeltaMonths->Text();
    my $offsetD     = $win->tfDeltaDays->Text();
    my $offsetH     = $win->tfDeltaHours->Text();
    my $offsetMin   = $win->tfDeltaMinutes->Text();
    my $offsetS     = $win->tfDeltaSecondes->Text();
    my $offset      = DateTime::Duration->new(years   => $offsetY  ,
                                              months  => $offsetM  ,
                                              days    => $offsetD  ,
                                              hours   => $offsetH  ,
                                              minutes => $offsetMin,
                                              seconds => $offsetS  , );
    foreach my $item (@{$refList1}) {
      $item =~ s/[\r\n]//g;  # Remove any line break
      if ($item) {
        my ($epoch, $inputTimezone, $before, $after);
        if ($pattern) { ($epoch, $inputTimezone, $pattern, $before, $after) = &str2Epoch($item, $sample, $pattern, $regex, $parseContext, $timezone); }
        else          { ($epoch, $inputTimezone, $pattern, $before, $after) = &str2Epoch($item, $sample, undef   , undef , $parseContext, undef    ); }
        if      ($epoch == 1) {
          if ($noResultOpt) { push(@items, $STR{'invalidInput'}); }
          else { push(@items, undef); }
        } elsif ($epoch == 2) {
          if ($noResultOpt) { push(@items, $STR{'errorConversion'}); }
          else { push(@items, undef); }
        } elsif ($epoch) {
          my $dt = DateTime->from_epoch(epoch => $epoch);
          if ($sameAsInput) { $inputTimezone = $localTZ if $inputTimezone eq 'floating'; $dt->set_time_zone($inputTimezone); }
          else              { $dt->set_time_zone($outputTZ);      }
          $dt->set(locale => $CONFIG{'DEFAULT_LANG'});
          if ($selFunc == 2) { $dt->add_duration($offset);      }
          else               { $dt->subtract_duration($offset); }
          # Output
          my $newItem;
          $newItem .= $before if $before;
          if ($sameAsInput) { $newItem .= $dt->strftime($pattern);       }
          else              { $newItem .= $dt->strftime($outPutPattern); }
          $newItem .= $after  if $after;
          push(@items, encode($CONFIG{'OUTPUT_CHARSET'}, $newItem));
        }
      } else {
        if ($noResultOpt) { push(@items, $STR{'noInput'}); }
        else { push(@items, undef); }
      }
      # Progress
      $curr++;
      $win->lblPbCount->Text("$curr / $nbrItems");
      $win->pb->StepIt();
    }
  }
  # Format results
  my $itemsRes;
  foreach (@items) { $itemsRes .= $_ if $_; $itemsRes .= "\r\n"; }
  return(\$itemsRes);
  
}  #--- End timeTabFunc

#--------------------------#
sub cbCFLists_Change
#--------------------------#
{
  # Local variables
  my $selFuncStr = $win->cbCFLists->GetString($win->cbCFLists->GetCurSel());
  if ($selFuncStr and $selFuncStr ne $STR{'cbCFLists'}.'...') {
    $win->chCFMatchCase->Show();
    $win->btnCFRem->Enable();
    $win->btnCFEdit->Enable();
  } else {
    $win->chCFMatchCase->Hide();
    $win->btnCFRem->Disable();
    $win->btnCFEdit->Disable();
  }
  &isProcessReady(0);

}  #--- End cbCFLists_Change

#--------------------------#
sub chGeoIPOptAll_Click
#--------------------------#
{
  if ($win->chGeoIPOptAll->Checked()) {
    for (my $i = 0; $i < 5; $i++) {
      $win->gridGeoIPOpts->SetCellCheck(0, $i, 1);
      $win->gridGeoIPOpts->SetCellCheck(1, $i, 1);
    }
  } else {
    for (my $i = 0; $i < 5; $i++) {
      $win->gridGeoIPOpts->SetCellCheck(0, $i, 0);
      $win->gridGeoIPOpts->SetCellCheck(1, $i, 0);
    }
  }
  &isProcessReady(0);
  
}  #--- End chGeoIPOptAll_Click

#--------------------------#
sub chUAOptAll_Click
#--------------------------#
{
  if ($win->chUAOptAll->Checked()) {
    for (my $i = 0; $i < 3; $i++) {
      $win->gridUAOpts->SetCellCheck(0, $i, 1);
      $win->gridUAOpts->SetCellCheck(1, $i, 1);
    }
  } else {
    for (my $i = 0; $i < 3; $i++) {
      $win->gridUAOpts->SetCellCheck(0, $i, 0);
      $win->gridUAOpts->SetCellCheck(1, $i, 0);
    }
  }
  &isProcessReady(0);
  
}  #--- End chUAOptAll_Click

#--------------------------#
sub cbGPS2AddrOutput_Change
#--------------------------#
{
  # Local variables
  my $selOutput = $win->cbGPS2AddrOutput->GetString($win->cbGPS2AddrOutput->GetCurSel());
  if ($selOutput and $selOutput eq $STR{'AddressEl'}) {
    $win->gridGPS2AddrOpts->Show();
    $win->chAddHeaders->Show();
  } else {
    $win->gridGPS2AddrOpts->Hide();
    $win->chAddHeaders->Hide();
  }
  &isProcessReady(0);

}  #--- End cbGPS2AddrOutput_Change

#--------------------------#
sub gridGeoIPOpts_Click     { &isProcessReady(0); }
sub gridGPS2AddrOpts_Click  { &isProcessReady(0); }
sub gridUAOpts_Click        { &isProcessReady(0); }
sub tfSingleLocation_Change { &isProcessReady(0); }
#--------------------------#

#--------------------------#
sub chSingleLocation_Click
#--------------------------#
{
  if ($win->chSingleLocation->Checked()) { &hideList2(); } # Hide List 2
  else                                   { &showList2(); } # Show List 2
  &isProcessReady(0);

}  #--- End chSingleLocation_Click

#--------------------------#
sub btnCFAdd_Click
#--------------------------#
{
  # Show OpenFile dialog window
  if (my $CFDBFile = Win32::GUI::GetOpenFileName( -owner         => $win                              ,
                                                  -title         => $STR{'selectDBFile'}              ,
                                                  -filter        => [$STR{'dbFile'}.' - .db', '*.db'] ,
                                                  -filemustexist => 1                                 ,
                                                  -explorer      => 1                                 , )) {
    if (-f $CFDBFile and &validCFDB($CFDBFile)) {
      # Connect to DB
      my $dsn = "DBI:SQLite:dbname=$CFDBFile";
      if (my $dbh = DBI->connect($dsn, undef, undef, { RaiseError => 1, AutoCommit => 1 })) {
        my $sth = $dbh->prepare("SELECT title FROM TITLE");
        my $rv  = $sth->execute();
        my @fields = $sth->fetchrow_array();
        if (scalar(@fields) > 0) {
          my $title = join('',@fields);
          $sth->finish();
          $dbh->disconnect();
          # Copy to the Customs folder
          my $pathQuoted = quotemeta($USERDIR);
          if ($CFDBFile !~ /$pathQuoted\\Customs/) {
            mkdir("$USERDIR\\Customs") if !-d "$USERDIR\\Customs";
            my $funcFileName = pop @{[split m|\\|, $CFDBFile]};
            # Do not overwrite if already exists
            if (!-e "$USERDIR\\Customs\\$funcFileName") {
              $CFDBFile = "$USERDIR\\Customs\\$funcFileName" if copy($CFDBFile, "$USERDIR\\Customs\\$funcFileName");
            }
          }
          # Verify that the title doesn't already exist
          if (&validUniqueCFName($title, \$win)) {
            # Update window and config
            my $j = 1;
            while (exists($CONFIG{'CF'.$j})) { $j++; }
            $CONFIG{'CF'.$j} = $title.'|'.$CFDBFile;
            &saveConfig(\%CONFIG, $CONFIG_FILE);
            $win->cbCFLists->Add($title);
            Win32::GUI::MessageBox($win, $STR{'funcAdded'}, "XL-Tools $VERSION", 0x40040);
          # Function must be modified
          } else {
            Win32::GUI::MessageBox($win, $STR{'funcExists'}, $STR{'Warning'}, 0x40030);
            &editCF($title, $CFDBFile, \$HOURGLASS, \$ARROW, \$win, \%STR);
          }
        } else { Win32::GUI::MessageBox($win, $STR{'funcNoTitle'}, $STR{'Error'}, 0x40010); }
      } else { Win32::GUI::MessageBox($win, $STR{'errorConnectDB'}, $STR{'Error'}, 0x40010); }
    } else { Win32::GUI::MessageBox($win, $STR{'invalidFile'}, $STR{'Error'}, 0x40010); }
  }
  return(1);

}  #--- End btnCFAdd_Click
  
#--------------------------#
sub btnCFRem_Click
#--------------------------#
{
  # Local variables
  my $selFuncStr = $win->cbCFLists->GetString($win->cbCFLists->GetCurSel());
  my ($title, $dbFile, $index);
  # Ask a confirmation
  my $answer = Win32::GUI::MessageBox($win, "$STR{'remConfirm'} \"$selFuncStr\" $STR{'func'}?", $STR{'remConfirmT'}, 0x40024);
  if ($answer == 6) {
    # Gather path to database
    if ($selFuncStr and $selFuncStr ne $STR{'cbCFLists'}.'...') {
      my $j = 1;
      while (exists($CONFIG{'CF'.$j})) {
        my $selFuncStrQuoted = quotemeta($selFuncStr);
        if ($CONFIG{'CF'.$j} =~ /$selFuncStrQuoted\|/) {
          ($title, $dbFile) = split(/\|/, $CONFIG{'CF'.$j});
          $index = $j;
          delete($CONFIG{'CF'.$j});
          &saveConfig(\%CONFIG, $CONFIG_FILE);
          last;
        }
        $j++;
      }
      # Update index (Ex.: if CF3 is deleted, CF4 becomes CF3, CF5 becomes CF 4 and so on)
      $j++;
      while (exists($CONFIG{'CF'.$j})) {
        my $k = $j-1;
        $CONFIG{'CF'.$k} = $CONFIG{'CF'.$j};
        $j++;
      }
      $j--;
      delete($CONFIG{'CF'.$j}); # Remove the last one
      &saveConfig(\%CONFIG, $CONFIG_FILE);
    }
    # Remove function from list
    $win->cbCFLists->DeleteString($index) if $index;
    # Ask confirmation to delete the file
    $answer = Win32::GUI::MessageBox($win, "$STR{'delConfirm'}?", $STR{'delConfirmT'}, 0x40024);
    # Delete the file
    if ($answer == 6) {
      unlink($dbFile) if -e $dbFile;
      Win32::GUI::MessageBox($win, $STR{'funcDeleted'}, "XL-Tools $VERSION", 0x40040) if !-e $dbFile;
    }
    $win->cbCFLists->SetCurSel(0);
  }

}  #--- End btnCFRem_Click

#--------------------------#
sub btnCFEdit_Click
#--------------------------#
{
  # Local variables
  my $selFuncStr = $win->cbCFLists->GetString($win->cbCFLists->GetCurSel());
  my ($title, $dbFile);
  # Gather path to database
  if ($selFuncStr and $selFuncStr ne $STR{'cbCFLists'}.'...') {
    my $j = 1;
    while (exists($CONFIG{'CF'.$j})) {
      my $selFuncStrQuoted = quotemeta($selFuncStr);
      if ($CONFIG{'CF'.$j} =~ /$selFuncStrQuoted\|/) {
        ($title, $dbFile) = split(/\|/, $CONFIG{'CF'.$j});
        last;
      }
      $j++;
    }
    &editCF($title, $dbFile, \$HOURGLASS, \$ARROW, \$win, \%STR);
  }

}  #--- End btnCFEdit_Click

#--------------------------#
sub btnCFNew_Click
#--------------------------#
{
  # Show options and message
  $win->lblCFTitle->Show();
  $win->tfCFTitle->Show();
  $win->btnCFSave->Show();
  $win->btnCFCancel->Show();
  $win->chCFMatchCase->Hide();
  $win->cbCFLists->Disable();
  $win->btnProcess->Disable();
  # Show List 2
  &showList2();

}  #--- End btnCFNew_Click

#--------------------------#
sub tfCFTitle_Change { &validNewFunc(\$win, \%STR); }
#--------------------------#

#--------------------------#
sub btnCFSave_Click
#--------------------------#
{
  threads->create(sub {
    # Local variables
    my $title     = $win->tfCFTitle->Text();
    my $refList1  = &enumItems(\$win->tfList1, \$win, \%STR);
    my $refList2  = &enumItems(\$win->tfList2, \$win, \%STR);
    my $nbrItems1 = scalar(@{$refList1});
    my $nbrItems2 = scalar(@{$refList2});
    my $dbFile;
    my $indexCF;
    # Verify if function already exists
    my $j = 1;
    while (exists($CONFIG{'CF'.$j})) {
      my $titleQuoted = quotemeta($title);
      if ($CONFIG{'CF'.$j} =~ /$titleQuoted\|/) {
        $dbFile  = (split(/\|/, $CONFIG{'CF'.$j}))[1];
        $indexCF = $j;
        last;
      }
      $j++;
    }
    # List 1 must not contain duplicates
    my %items;
    my $containsDuplicate;
    foreach my $item (@{$refList1}) {
      if (exists($items{$item})) { $containsDuplicate = 1; last; }
      else { $items{$item} = 1; }
    }
    # Error duplicates
    if ($containsDuplicate) { Win32::GUI::MessageBox($win, $STR{'CFErrorDupl'}, $STR{'Error'}, 0x40010); }
    else {
      # If function already exist, confirm replacement
      if ($dbFile and -f $dbFile) {
        my $answer = Win32::GUI::MessageBox($win, "$STR{'funcExists2'}?", $STR{'replConfirmT'}, 0x40024);
        if ($answer == 6) { # If function exists, we modify the database
          &modCF($title, $dbFile, $indexCF, $refList1, $refList2, $nbrItems1, $nbrItems2, \$HOURGLASS, \$ARROW,
                 \$win, \%STR);
        } else { return(); } # Cancel
      # If function doesn't exist, we create a new one
      } else { &newCF($title, $refList1, $refList2, $nbrItems1, $nbrItems2, $USERDIR, \$HOURGLASS, \$ARROW,
                      \%CONFIG, $CONFIG_FILE, \$win, \%STR); }
      # Clean Lists and Hide control
      $win->tfCFTitle->Text('');
      $win->tfList1->Text('');
      $win->tfList2->Text('');
      $win->lblCFTitle->Hide();
      $win->tfCFTitle->Hide();
      $win->btnCFSave->Hide();
      $win->btnCFCancel->Hide();
      $win->cbCFLists->Enable();
      $win->btnProcess->Enable();
      $win->chCFMatchCase->Show() if $win->cbCFLists->GetCurSel() > 0;
      &tfList1_Change();
      &tfList2_Change();
      # Hide List 2
      &hideList2();
    }
  });

}  #--- End btnCFSave_Click

#--------------------------#
sub btnCFCancel_Click
#--------------------------#
{
  # Clean Lists and Hide control
  $win->tfCFTitle->Text('');
  $win->tfList1->Text('');
  $win->tfList2->Text('');
  $win->lblCFTitle->Hide();
  $win->tfCFTitle->Hide();
  $win->btnCFSave->Hide();
  $win->btnCFCancel->Hide();
  $win->cbCFLists->Enable();
  $win->btnProcess->Enable();
  $win->chCFMatchCase->Show() if $win->cbCFLists->GetCurSel() > 0;
  &tfList1_Change();
  &tfList2_Change();
  # Hide List 2
  &hideList2();
  
}  #--- End btnCFCancel_Click

#--------------------------#
sub btnCancel_Click
#--------------------------#
{
  # Stop requests
  $THR_UPDATE->kill('KILL')->detach() if $THR_UPDATE and $THR_UPDATE->is_running();
  return(1);

}  #--- End btnCancel_Click

#--------------------------#
sub createCW
#--------------------------#
{
  # Create Config Wizard Window
  my $winCW  = Win32::GUI::DialogBox->new(-name        => 'winCW'                   ,
                                          -parent      => $win                      , # May be open from many Window
                                          -text        => $STR{'winCW'}             ,
                                          -pos         => [$winPosX, $winPosY]      ,
                                          -size        => [400, 195]                ,
                                          -background  => [255, 255, 255]           ,
                                          -hasmaximize => 0                         ,
                                          -hasminimize => 1                         ,
                                          -helpbutton  => 0                         ,
                                          -resizable   => 0                         ,
                                          -dialogui    => 1                         , );
  $winCW->SetIcon($winICO);
  $winCW->AddLabel(     -name        => 'lblConfigLogo'       ,
                        -size        => [128,128]             ,
                        -pos         => [  0,  5]             ,
                        -bitmap      => $config128Bmp         , );
  $winCW->AddLabel(     -name        => 'lblSetGenOpt'        ,
                        -size        => [220, 22]             ,
                        -pos         => [140, 10]             ,
                        -font        => $font10               ,
                        -text        => $STR{'SetGenOpt'}.'...',
                        -background  => [255, 255, 255]       ,
                        -foreground  => [  0, 102, 204]       ,
                        -visible     => 0                     , );
  $winCW->AddLabel(     -name        => 'lblSetGenOptDone'    ,
                        -size        => [ 20, 20]             ,
                        -pos         => [365, 10]             ,
                        -bitmap      => $checkBmp             ,
                        -background  => [255, 255, 255]       ,
                        -visible     => 0                     , );
  $winCW->AddLabel(     -name        => 'lblLocXLWhoisDB'     ,
                        -size        => [220, 22]             ,
                        -pos         => [140, 30]             ,
                        -font        => $font10               ,
                        -text        => "$STR{'Locate'} $STR{'XLWhoisDB'}...",
                        -background  => [255, 255, 255]       ,
                        -foreground  => [  0, 102, 204]       ,
                        -visible     => 0                     , );
  $winCW->AddLabel(     -name        => 'lblLocXLWhoisDBDone' ,
                        -size        => [ 20, 20]             ,
                        -pos         => [365, 30]             ,
                        -bitmap      => $checkBmp             ,
                        -background  => [255, 255, 255]       ,
                        -visible     => 0                     , );
  $winCW->AddLabel(     -name        => 'lblLocXLWhoisDBError',
                        -size        => [ 20, 20]             ,
                        -pos         => [365, 30]             ,
                        -bitmap      => $errorBmp             ,
                        -background  => [255, 255, 255]       ,
                        -visible     => 0                     , );
  $winCW->AddLabel(     -name        => 'lblDLIINDB'          ,
                        -size        => [220, 22]             ,
                        -pos         => [140, 50]             ,
                        -font        => $font10               ,
                        -text        => "$STR{'Locate'} $STR{'IINDB'}...",
                        -background  => [255, 255, 255]       ,
                        -foreground  => [  0, 102, 204]       ,
                        -visible     => 0                     , );
  $winCW->AddLabel(     -name        => 'lblDLIINDBDone'      ,
                        -size        => [ 20, 20]             ,
                        -pos         => [365, 50]             ,
                        -bitmap      => $checkBmp             ,
                        -background  => [255, 255, 255]       ,
                        -visible     => 0                     , );
  $winCW->AddLabel(     -name        => 'lblDLIINDBError'     ,
                        -size        => [ 20, 20]             ,
                        -pos         => [365, 50]             ,
                        -bitmap      => $errorBmp             ,
                        -background  => [255, 255, 255]       ,
                        -visible     => 0                     , );
  $winCW->AddLabel(     -name        => 'lblDLDTDB'           ,
                        -size        => [220, 22]             ,
                        -pos         => [140, 70]             ,
                        -font        => $font10               ,
                        -text        => "$STR{'Locate'} $STR{'DTDB'}...",
                        -background  => [255, 255, 255]       ,
                        -foreground  => [  0, 102, 204]       ,
                        -visible     => 0                     , );
  $winCW->AddLabel(     -name        => 'lblDLDTDBDone'       ,
                        -size        => [ 20, 20]             ,
                        -pos         => [365, 70]             ,
                        -bitmap      => $checkBmp             ,
                        -background  => [255, 255, 255]       ,
                        -visible     => 0                     , );
  $winCW->AddLabel(     -name        => 'lblDLDTDBError'      ,
                        -size        => [ 20, 20]             ,
                        -pos         => [365, 70]             ,
                        -bitmap      => $errorBmp             ,
                        -background  => [255, 255, 255]       ,
                        -visible     => 0                     , );
  $winCW->AddLabel(     -name        => 'lblDLGeoIPDB'        ,
                        -size        => [220, 22]             ,
                        -pos         => [140, 90]             ,
                        -font        => $font10               ,
                        -text        => "$STR{'Locate'} $STR{'GeoIPDB'}...",
                        -background  => [255, 255, 255]       ,
                        -foreground  => [  0, 102, 204]       ,
                        -visible     => 0                     , );
  $winCW->AddLabel(     -name        => 'lblDLGeoIPDBDone'    ,
                        -size        => [ 20, 20]             ,
                        -pos         => [365, 90]             ,
                        -bitmap      => $checkBmp             ,
                        -background  => [255, 255, 255]       ,
                        -visible     => 0                     , );
  $winCW->AddLabel(     -name        => 'lblDLGeoIPDBError'   ,
                        -size        => [ 20, 20]             ,
                        -pos         => [365, 90]             ,
                        -bitmap      => $errorBmp             ,
                        -background  => [255, 255, 255]       ,
                        -visible     => 0                     , );
  $winCW->AddLabel(     -name        => 'lblDLMACOUIDB'       ,
                        -size        => [220, 22]             ,
                        -pos         => [140,110]             ,
                        -font        => $font10               ,
                        -text        => "$STR{'Locate'} $STR{'MACOUIDB'}...",
                        -background  => [255, 255, 255]       ,
                        -foreground  => [  0, 102, 204]       ,
                        -visible     => 0                     , );
  $winCW->AddLabel(     -name        => 'lblDLMACOUIDBDone'   ,
                        -size        => [ 20, 20]             ,
                        -pos         => [365,110]             ,
                        -bitmap      => $checkBmp             ,
                        -background  => [255, 255, 255]       ,
                        -visible     => 0                     , );
  $winCW->AddLabel(     -name        => 'lblDLMACOUIDBError'  ,
                        -size        => [ 20, 20]             ,
                        -pos         => [365,110]             ,
                        -bitmap      => $errorBmp             ,
                        -background  => [255, 255, 255]       ,
                        -visible     => 0                     , );
  return(\$winCW);

}  #--- End createCW

#--------------------------#
sub firstStart
#--------------------------#
{
  # Local variables
  my $refWinCW = shift;
  # Thread 'cancellation' signal handler
  $SIG{'KILL'} = sub {
    # Delete temp files if converting was in progress
    if (-e $winConfig->tfMACOUIDB->Text().'-journal') {
      my $localMACOUIDB = $winConfig->tfMACOUIDB->Text();
      unlink($localMACOUIDB.'-journal');
      unlink($localMACOUIDB);
    }
    $win->ChangeCursor($ARROW);
    # Turn off progress bar
    $winPb->lblPbCurr->Text('');
    $winPb->lblCount->Text('');
    $winPb->pbWinPb->SetPos(0);
    $winPb->Hide();
    $$refWinCW->Hide();
    Win32::GUI::MessageBox($win, $STR{'configSetPart'}, "XL-Tools $VERSION", 0x40040);
    threads->exit();
  };
  # Thread 'die' signal handler
  $SIG{__DIE__} = sub {
    # Delete temp files if converting was in progress
    if (-e $winConfig->tfMACOUIDB->Text().'-journal') {
      my $localMACOUIDB = $winConfig->tfMACOUIDB->Text();
      unlink($localMACOUIDB.'-journal');
      unlink($localMACOUIDB);
    }
    my $errMsg = (split(/ at /,$_[0]))[0];
    chomp($errMsg);
    $errMsg =~ s/[\t\r\n]/ /g;
    $win->ChangeCursor($ARROW);
    # Turn off progress bar
    $winPb->lblPbCurr->Text('');
    $winPb->lblCount->Text('');
    $winPb->pbWinPb->SetPos(0);
    $winPb->Hide();
    $$refWinCW->Hide();
    Win32::GUI::MessageBox($win, "$STR{'errorMsg'}: $errMsg", $STR{'Error'}, 0x40010);
  };
  # Yes (6), No (7)
  my $answer = Win32::GUI::MessageBox($win, $STR{'firstStart'}, $STR{'Settings'}, 0x1024);
  if ($answer == 6) {
    my $dir;
    # Use default directory? (program directory)
    $answer = Win32::GUI::MessageBox($win, $STR{'defaultDir'}.'('.$USERDIR.')?', $STR{'Settings'}, 0x1024);
    # Answer is no, open popup to let user choose a different location
    if ($answer == 7) {
      # Select a folder
      $dir = Win32::GUI::BrowseForFolder( -owner      => $$refWinCW               ,
                                          -title      => $STR{'selectFolder'}.':' ,
                                          -folderonly => 1                        ,
                                          -newui      => 1                        ,
                                          -directory  => $USERDIR                 , );
    # Answer is yes, use default dir
    } else { $dir = $USERDIR; }
    # Selected folder
    if ($dir and -d $dir) {
      $$refWinCW->Top($win->Top()+5);
      $$refWinCW->Left($win->Left()+310);
      $$refWinCW->Show();
      # Set General options
      $$refWinCW->lblSetGenOpt->Show();
      # Tool
      $winConfig->chAutoUpdate->Checked(1);      
      $CONFIG{'TOOL_AUTO_UPDATE'} = 1;
      # Functions
      $winConfig->tfMaxSize->Text(5000000); # Set Max Size (List) to 5 000 000 chars
      $CONFIG{'MAX_SIZE_LIST'} = 5000000;
      $winConfig->tfLookupTO->Text(10); # Set Nslookup timeout to 10 seconds
      $CONFIG{'NSLOOKUP_TIMEOUT'} = 10;
      $winConfig->tfUserAgent->Text('XL-Tools (http://www.le-tools.com)'); # Set default User-Agent
      $CONFIG{'USERAGENT'} = 'XL-Tools (http://www.le-tools.com)';
      $winConfig->rbNoResultOpt1->Checked(1); # Set "When no result" to "Leave a blank"
      $winConfig->rbNoResultOpt2->Checked(0);
      $winConfig->chMACOUIDBAutoUpt->Checked(0); # Uncheck auto update for MACOUI Database
      $CONFIG{'MACOUI_DB_AUTO_UPDATE'} = 0;
      &saveConfig(\%CONFIG, $CONFIG_FILE);
      $$refWinCW->lblSetGenOptDone->Show();
      # Select the XL-Whois DB
      my $defaultPath = "$ENV{'APPDATA'}\\XL-Toolkit\\XL-Whois\\Whois.db";
      my $XLWHOISDBFile;
      $$refWinCW->lblLocXLWhoisDB->Show();
      if (-f $defaultPath) { $XLWHOISDBFile = $defaultPath; }
      else {
        # Is XL-Whois installed on this system?
        $answer = Win32::GUI::MessageBox($$refWinCW, $STR{'XLWhoisExists'}.'?', $STR{'Settings'}, 0x1024);
        # Answer is yes, select the XL-Whois database
        if ($answer == 6) {
          $XLWHOISDBFile = Win32::GUI::GetOpenFileName( -title         => $STR{'locXLWhoisDB'}.':',
                                                        -filter        => [$STR{'dbFile'}.' (*.db)', '.db'],
                                                        -filemustexist => 1                       ,
                                                        -file          => 'Whois.db'              ,
                                                        -explorer      => 1                       , );
        }
      }
      if ($XLWHOISDBFile and -f $XLWHOISDBFile) {
        $winConfig->tfXLWHOISDB->Text($XLWHOISDBFile);
        $CONFIG{'XLWHOIS_DB_FILE'} = $XLWHOISDBFile;
        $$refWinCW->lblLocXLWhoisDBDone->Show();
      } else { $$refWinCW->lblLocXLWhoisDBError->Show(); }
      # Download or select Database files
      my ($status, $return);
      # Download IINDB Database
      $$refWinCW->lblDLIINDB->Show();
      $defaultPath = "$ENV{'APPDATA'}\\XL-Toolkit\\XL-Parser\\IIN.db";
      if (-f $defaultPath and &validSQLiteDB($defaultPath, 'IIN')) { # Database exists in XL-Parser user dir
        $winConfig->tfIINDB->Text($defaultPath);
        $$refWinCW->lblDLIINDBDone->Show();
      } else {
        $$refWinCW->lblDLIINDB->Text("$STR{'Downloading'} $STR{'IINDB'}");
        ($status, $return) = &downloadDB($refWinCW, 'IIN', $STR{'IINDB'}, "$dir\\IIN.db", 'le-tools.com', \$HOURGLASS,
                                         \$ARROW, \%CONFIG, $CONFIG_FILE, \$winConfig, \$winDTDB, \$winPb, \$win, \%STR);
        if ($status) { $$refWinCW->lblDLIINDBDone->Show(); } # Success
        else { # Error
          $$refWinCW->lblDLIINDBError->Show();
          Win32::GUI::MessageBox($$refWinCW, $return, $STR{'Error'}, 0x40010);
        }
      }
      if ($return) { 
        $$refWinCW->lblDLIINDBError->Show();
        Win32::GUI::MessageBox($win, $return, $STR{'Error'}, 0x40010);
      } else { $$refWinCW->lblDLIINDBDone->Show(); }
      &saveConfig(\%CONFIG, $CONFIG_FILE);
      # Download DTDB Database
      $$refWinCW->lblDLDTDB->Show();
      $defaultPath = "$ENV{'APPDATA'}\\XL-Toolkit\\XL-Parser\\DT.db";
      if (-f $defaultPath and &validSQLiteDB($defaultPath, 'DT')) { # Valid DTDB in XL-Parser user dir
        $winConfig->tfDTDB->Text($defaultPath);
        &loadDTDB(\$winDTDB, \$winConfig, \$refWinCW, \%STR);
        &cbInputDTFormatAddITems();
        $win->cbInputDTFormat->SetCurSel(0);
        &cbOutputDTFormatAddITems();
        $win->cbOutputDTFormat->SetCurSel(0);
        $$refWinCW->lblDLDTDBDone->Show();
      } else { # No DTDB, download it
        $$refWinCW->lblDLDTDB->Text("$STR{'Downloading'} $STR{'DTDB'}");
        ($status, $return) = &downloadDB($refWinCW, 'DT', $STR{'DTDB'}, "$dir\\DT.db", 'le-tools.com', \$HOURGLASS, \$ARROW,
                                         \%CONFIG, $CONFIG_FILE, \$winConfig, \$winDTDB, \$winPb, \$win, \%STR);
        if ($status) { $$refWinCW->lblDLDTDBDone->Show(); } # Success
        else { # Error
          $$refWinCW->lblDLDTDBError->Show();
          Win32::GUI::MessageBox($$refWinCW, $return, $STR{'Error'}, 0x40010);
        }
      }
      my $index = 0;
      my $localTZ;
      eval     { $localTZ = DateTime::TimeZone->new(name => 'local'); }; # Find local timezone
      if (!$@) { $index = $winConfig->cbLocalTZ->FindStringExact($localTZ->{name}); }
      else     { $index = 107; } # Default is America/New_York
      $winConfig->cbLocalTZ->SetCurSel($index);
      $CONFIG{'LOCAL_TIMEZONE'} = $index;
      $winConfig->cbDefaultLang->SetCurSel($winConfig->cbDefaultLang->FindStringExact('en-US')); # Default language to en-US
      $CONFIG{'DEFAULT_LANG'}   = 'en-US';
      $winConfig->cbOutputCharset->SetCurSel(0); # Set default charset to cp1252
      $CONFIG{'OUTPUT_CHARSET'} = 'cp1252';
      &saveConfig(\%CONFIG, $CONFIG_FILE);
      # GeoIP Database
      $$refWinCW->lblDLGeoIPDB->Show();
      $defaultPath = &findXLTKfile('GeoIPDB');
      if (-f $defaultPath and &validGeoIPDB($defaultPath)) {
        $winConfig->tfGeoIPDB->Text($defaultPath);
        $$refWinCW->lblDLGeoIPDBDone->Show();
      } else {
        $$refWinCW->lblDLGeoIPDBError->Show();
        Win32::GUI::MessageBox($$refWinCW, $return, $STR{'Error'}, 0x40010);
      }
      # Download MACOUI Database
      $$refWinCW->lblDLMACOUIDB->Show();
      $defaultPath = "$ENV{'APPDATA'}\\XL-Toolkit\\XL-Parser\\oui.db";
      if (-f $defaultPath and &validSQLiteDB($defaultPath, 'MACOUI')) { # Database exists in XL-Parser user dir, check if update available
        $winConfig->tfMACOUIDB->Text($defaultPath);
        $$refWinCW->lblDLMACOUIDB->Text("$STR{'Update'} $STR{'MACOUIDB'}");
        &updateDB(1, 'MACOUI', $STR{'MACOUIDB'}, $winConfig->tfMACOUIDB->Text(), 'ieee.org', 'oui.db', $USERDIR, \$HOURGLASS, \$ARROW,
                  \%CONFIG, $CONFIG_FILE, \$winConfig, \$winDTDB, \$winPb, \$win, \%STR);
        $$refWinCW->lblDLMACOUIDBDone->Show();
      } else {
        $$refWinCW->lblDLMACOUIDB->Text("$STR{'Downloading'} $STR{'MACOUIDB'}");
        ($status, $return) = &downloadDB($refWinCW, 'MACOUI', $STR{'MACOUIDB'}, "$dir\\oui.db", 'ieee.org', \$HOURGLASS, \$ARROW,
                                         \%CONFIG, $CONFIG_FILE, \$winConfig, \$winDTDB, \$winPb, \$win, \%STR);
        if ($status) { $$refWinCW->lblDLMACOUIDBDone->Show(); } # Success
        else { # Error
          $$refWinCW->lblDLMACOUIDBError->Show();
          Win32::GUI::MessageBox($$refWinCW, $return, $STR{'Error'}, 0x40010);
        }
      }
      &saveConfig(\%CONFIG, $CONFIG_FILE);
      # Close Configuration Wizard
      $$refWinCW->Hide();
      $win->ChangeCursor($ARROW);
      Win32::GUI::MessageBox($win, $STR{'configSet'}, "XL-Tools $VERSION", 0x40040);
    }
  }

}  #--- End firstStart

#--------------------------#
sub findXLTKfile
#--------------------------#
{
  my $file = shift;
  my $defPath;
  if ($file eq 'GeoIPDB') {
    if      (-e "$ENV{'APPDATA'}\\XL-Toolkit\\XL-Parser\\GeoLite2-City.mmdb") { # In XL-Parser dir
      $defPath = "$ENV{'APPDATA'}\\XL-Toolkit\\XL-Parser\\GeoLite2-City.mmdb";
    } elsif (-e "$ENV{'APPDATA'}\\XL-Toolkit\\XL-Whois\\GeoLite2-City.mmdb" ) { # In XL-Whois dir
      $defPath = "$ENV{'APPDATA'}\\XL-Toolkit\\XL-Whois\\GeoLite2-City.mmdb";
    } elsif (-e "$ENV{'PROGRAMDATA'}\\Maxmind\\GeoIPUpdate\\GeoIP\\GeoLite2-City.mmdb" ) { # Default Maxmind GeoIP dir
      $defPath = "$ENV{'PROGRAMDATA'}\\Maxmind\\GeoIPUpdate\\GeoIP\\GeoLite2-City.mmdb";
    }
    return($defPath) if $defPath;
  }
  return('');

}  #--- End findXLTKfile

#--------------------------#
sub btnWinConfig_Click
#--------------------------#
{
  # Show Config window with General Tab
  $winConfig->configTab->SetCurSel(0);
  &configTab_Click;
  $winConfig->Center();
  $winConfig->DoModal();

}  #--- End btnWinConfig_Click

#--------------------------#
sub configTab_Click
#--------------------------#
{
  # Show General tab
  if (!$winConfig->configTab->SelectedItem()) {
    # General tab
    $winConfig->lblToolShadowT->Show();
    $winConfig->lblToolT->Show();
    $winConfig->btnCheckUpdate->Show();
    $winConfig->chAutoUpdate->Show();
    $winConfig->btnExportLang->Show();
    $winConfig->btnOpenUserDir->Show();
    $winConfig->lblOptFunctionsShadowT->Show();
    $winConfig->lblOptFunctionsT->Show();
    $winConfig->chFullScreen->Show();
    $winConfig->chRememberPos->Show();
    $winConfig->lblMaxSize1->Show();
    $winConfig->tfMaxSize->Show();
    $winConfig->lblMaxSize2->Show();
    $winConfig->btnChooseFont->Show();
    $winConfig->lblLocalTZ->Show();
    $winConfig->cbLocalTZ->Show();
    $winConfig->lblOutputLang->Show();
    $winConfig->cbDefaultLang->Show();
    $winConfig->lblOutputCharset->Show();
    $winConfig->cbOutputCharset->Show();    
    $winConfig->lblNsLookupTO1->Show();
    $winConfig->tfLookupTO->Show();
    $winConfig->lblNsLookupTO2->Show();
    $winConfig->lblUserAgent->Show();
    $winConfig->tfUserAgent->Show();
    $winConfig->lblNoResultOpt->Show();
    $winConfig->rbNoResultOpt1->Show();
    $winConfig->rbNoResultOpt2->Show();
    # Databases tab
    $winConfig->lblMACOUIDBShadowT->Hide();
    $winConfig->lblMACOUIDBT->Hide();
    $winConfig->chMACOUIDBAutoUpt->Hide();
    $winConfig->tfMACOUIDB->Hide();
    $winConfig->btnMACOUIDB->Hide();
    $winConfig->btnMACOUIDBUpt->Hide();
    $winConfig->lblGeoIPDBShadowT->Hide();
    $winConfig->lblGeoIPDBT->Hide();
    $winConfig->tfGeoIPDB->Hide();
    $winConfig->btnGeoIPDB->Hide();
    $winConfig->lblGeoIPNotice->Hide();
    $winConfig->lblIINDBShadowT->Hide();
    $winConfig->lblIINDBT->Hide();
    $winConfig->tfIINDB->Hide();
    $winConfig->btnIINDB->Hide();
    $winConfig->btnIINDBUpt->Hide();
    $winConfig->lblOSMDBShadowT->Hide();
    $winConfig->lblOSMDBT->Hide();
    $winConfig->tfOSMDB->Hide();
    $winConfig->btnOSMDB->Hide();
    $winConfig->btnNewOSMDB->Hide();
    $winConfig->lblOSMEmail->Hide();
    $winConfig->tfOSMEmailDB->Hide();
    $winConfig->lblOSMNotice->Hide();
    # XL-Toolkit databases tab
    $winConfig->lblXLWHOISDBShadowT->Hide();
    $winConfig->lblXLWHOISDBT->Hide();
    $winConfig->tfXLWHOISDB->Hide();
    $winConfig->btnXLWHOISDB->Hide();
    $winConfig->lblDTDBShadowT->Hide();
    $winConfig->lblDTDBT->Hide();
    $winConfig->tfDTDB->Hide();
    $winConfig->btnDTDB->Hide();
    $winConfig->btnDTDBUpt->Hide();
  # Show Databases tab
  } elsif ($winConfig->configTab->SelectedItem() == 1) {
    # Databases tab
    $winConfig->lblMACOUIDBShadowT->Show();
    $winConfig->lblMACOUIDBT->Show();
    $winConfig->chMACOUIDBAutoUpt->Show();
    $winConfig->tfMACOUIDB->Show();
    $winConfig->btnMACOUIDB->Show();
    $winConfig->btnMACOUIDBUpt->Show();
    $winConfig->lblGeoIPDBShadowT->Show();
    $winConfig->lblGeoIPDBT->Show();
    $winConfig->tfGeoIPDB->Show();
    $winConfig->btnGeoIPDB->Show();
    $winConfig->lblGeoIPNotice->Show();
    $winConfig->lblIINDBShadowT->Show();
    $winConfig->lblIINDBT->Show();
    $winConfig->tfIINDB->Show();
    $winConfig->btnIINDB->Show();
    $winConfig->btnIINDBUpt->Show();
    $winConfig->lblOSMDBShadowT->Show();
    $winConfig->lblOSMDBT->Show();
    $winConfig->tfOSMDB->Show();
    $winConfig->btnOSMDB->Show();
    $winConfig->btnNewOSMDB->Show();
    $winConfig->lblOSMEmail->Show();
    $winConfig->tfOSMEmailDB->Show();
    $winConfig->lblOSMNotice->Show();
    # General tab
    $winConfig->lblToolShadowT->Hide();
    $winConfig->lblToolT->Hide();
    $winConfig->btnCheckUpdate->Hide();
    $winConfig->chAutoUpdate->Hide();
    $winConfig->btnExportLang->Hide();
    $winConfig->btnOpenUserDir->Hide();
    $winConfig->lblOptFunctionsShadowT->Hide();
    $winConfig->lblOptFunctionsT->Hide();
    $winConfig->chFullScreen->Hide();
    $winConfig->chRememberPos->Hide();
    $winConfig->lblMaxSize1->Hide();
    $winConfig->tfMaxSize->Hide();
    $winConfig->lblLocalTZ->Hide();
    $winConfig->cbLocalTZ->Hide();
    $winConfig->lblOutputLang->Hide();
    $winConfig->cbDefaultLang->Hide();
    $winConfig->lblOutputCharset->Hide();
    $winConfig->cbOutputCharset->Hide();    
    $winConfig->lblMaxSize2->Hide();
    $winConfig->btnChooseFont->Hide();
    $winConfig->lblNsLookupTO1->Hide();
    $winConfig->tfLookupTO->Hide();
    $winConfig->lblNsLookupTO2->Hide();
    $winConfig->lblUserAgent->Hide();
    $winConfig->tfUserAgent->Hide();
    $winConfig->lblNoResultOpt->Hide();
    $winConfig->rbNoResultOpt1->Hide();
    $winConfig->rbNoResultOpt2->Hide();
    # XL-Toolkit databases tab
    $winConfig->lblXLWHOISDBShadowT->Hide();
    $winConfig->lblXLWHOISDBT->Hide();
    $winConfig->tfXLWHOISDB->Hide();
    $winConfig->btnXLWHOISDB->Hide();
    $winConfig->lblDTDBShadowT->Hide();
    $winConfig->lblDTDBT->Hide();
    $winConfig->tfDTDB->Hide();
    $winConfig->btnDTDB->Hide();
    $winConfig->btnDTDBUpt->Hide();
  # Show XL-Toolkit databases tab
  } elsif ($winConfig->configTab->SelectedItem() == 2) {
    # XL-Toolkit databases tab
    $winConfig->lblXLWHOISDBShadowT->Show();
    $winConfig->lblXLWHOISDBT->Show();
    $winConfig->tfXLWHOISDB->Show();
    $winConfig->btnXLWHOISDB->Show();
    $winConfig->lblDTDBShadowT->Show();
    $winConfig->lblDTDBT->Show();
    $winConfig->tfDTDB->Show();
    $winConfig->btnDTDB->Show();
    $winConfig->btnDTDBUpt->Show();
    # General tab
    $winConfig->lblToolShadowT->Hide();
    $winConfig->lblToolT->Hide();
    $winConfig->btnCheckUpdate->Hide();
    $winConfig->chAutoUpdate->Hide();
    $winConfig->btnExportLang->Hide();
    $winConfig->btnOpenUserDir->Hide();
    $winConfig->lblOptFunctionsShadowT->Hide();
    $winConfig->lblOptFunctionsT->Hide();
    $winConfig->chFullScreen->Hide();
    $winConfig->chRememberPos->Hide();
    $winConfig->lblMaxSize1->Hide();
    $winConfig->tfMaxSize->Hide();
    $winConfig->lblLocalTZ->Hide();
    $winConfig->cbLocalTZ->Hide();
    $winConfig->lblOutputLang->Hide();
    $winConfig->cbDefaultLang->Hide();
    $winConfig->lblOutputCharset->Hide();
    $winConfig->cbOutputCharset->Hide();    
    $winConfig->lblMaxSize2->Hide();
    $winConfig->btnChooseFont->Hide();
    $winConfig->lblNsLookupTO1->Hide();
    $winConfig->tfLookupTO->Hide();
    $winConfig->lblNsLookupTO2->Hide();
    $winConfig->lblUserAgent->Hide();
    $winConfig->tfUserAgent->Hide();
    $winConfig->lblNoResultOpt->Hide();
    $winConfig->rbNoResultOpt1->Hide();
    $winConfig->rbNoResultOpt2->Hide();
    # Databases tab
    $winConfig->lblMACOUIDBShadowT->Hide();
    $winConfig->lblMACOUIDBT->Hide();
    $winConfig->chMACOUIDBAutoUpt->Hide();
    $winConfig->tfMACOUIDB->Hide();
    $winConfig->btnMACOUIDB->Hide();
    $winConfig->btnMACOUIDBUpt->Hide();
    $winConfig->lblGeoIPDBShadowT->Hide();
    $winConfig->lblGeoIPDBT->Hide();
    $winConfig->tfGeoIPDB->Hide();
    $winConfig->btnGeoIPDB->Hide();
    $winConfig->lblGeoIPNotice->Hide();
    $winConfig->lblIINDBShadowT->Hide();
    $winConfig->lblIINDBT->Hide();
    $winConfig->tfIINDB->Hide();
    $winConfig->btnIINDB->Hide();
    $winConfig->btnIINDBUpt->Hide();
    $winConfig->lblOSMDBShadowT->Hide();
    $winConfig->lblOSMDBT->Hide();
    $winConfig->tfOSMDB->Hide();
    $winConfig->btnOSMDB->Hide();
    $winConfig->btnNewOSMDB->Hide();
    $winConfig->lblOSMEmail->Hide();
    $winConfig->tfOSMEmailDB->Hide();
    $winConfig->lblOSMNotice->Hide();
  }

}  #--- End configTab_Click

#--------------------------#
sub btnCheckUpdate_Click { &updateTool(1, $VERSION, \$winConfig, \$win, \%STR); }
#--------------------------#

#--------------------------#
sub chAutoUpdate_Click
#--------------------------#
{
  # Save the choice
  if ($winConfig->chAutoUpdate->Checked()) {
    $CONFIG{'TOOL_AUTO_UPDATE'} = 1;
    &saveConfig(\%CONFIG, $CONFIG_FILE);
  } else {
    $CONFIG{'TOOL_AUTO_UPDATE'} = 0;
    &saveConfig(\%CONFIG, $CONFIG_FILE);
  }

}  #--- End chAutoUpdate_Click

#--------------------------#
sub btnExportLang_Click
#--------------------------#
{
  # Save strings in Lang.ini
  open(LANG, ">$LANG_FILE");
  flock(LANG, 2);
  foreach my $cle (keys %STR) { print LANG "$cle = $STR{$cle}\n"; }
  close(LANG);
  $win->ShellExecute('open', $LANG_FILE,'','',1); # Open the page

}  #--- End btnExportLang_Click

#--------------------------#
sub btnOpenUserDir_Click
#--------------------------#
{
  # Open Window Explorer
  Win32::Process::Create(my $ProcessObj, "$ENV{'WINDIR'}\\explorer.exe", "explorer $USERDIR", 0, NORMAL_PRIORITY_CLASS, ".") if -d $USERDIR;

}  #--- End btnOpenUserDir_Click

#--------------------------#
sub chFullScreen_Click
#--------------------------#
{
  # Save the choice
  if ($winConfig->chFullScreen->Checked()) {
    $CONFIG{'FULL_SCREEN'} = 1;
    &saveConfig(\%CONFIG, $CONFIG_FILE);
  } else {
    $CONFIG{'FULL_SCREEN'} = 0;
    &saveConfig(\%CONFIG, $CONFIG_FILE);
  }

}  #--- End chFullScreen_Click

#--------------------------#
sub chRememberPos_Click
#--------------------------#
{
  # Save the choice
  if ($winConfig->chRememberPos->Checked()) {
    $CONFIG{'REMEMBER_POS'} = 1;
    &saveConfig(\%CONFIG, $CONFIG_FILE);
  } else {
    $CONFIG{'REMEMBER_POS'} = 0;
    &saveConfig(\%CONFIG, $CONFIG_FILE);
  }

}  #--- End chRememberPos_Click

#--------------------------#
sub tfMaxSize_Change
#--------------------------#
{
  # Remember
  if (my $maxSize = $winConfig->tfMaxSize->Text()) {
    $CONFIG{'MAX_SIZE_LIST'} = $maxSize;
    &saveConfig(\%CONFIG, $CONFIG_FILE);
  }

}  #--- End tfMaxSize_Change

#--------------------------#
sub btnChooseFont_Click
#--------------------------#
{
  # Show Choose Font dialog
  my @font = Win32::GUI::ChooseFont(-owner  => $winConfig, $fontTF->Info() );
  if ($#font) {
    $fontTF = new Win32::GUI::Font(@font);
    $win->tfList1->Change(-font => $fontTF);
    $win->tfList1->Update();
    $win->tfList2->Change(-font => $fontTF);
    $win->tfList2->Update();
    $win->tfList3->Change(-font => $fontTF);
    $win->tfList3->Update();
    my $customFont;
    foreach (@font) { $customFont .= $_ . ','; }
    chop($customFont);
    $CONFIG{'TFLIST_FONT'} = $customFont;
    &saveConfig(\%CONFIG, $CONFIG_FILE);
  }
  return(1);

}  #--- End btnChooseFont_Click

#--------------------------#
sub tfLookupTO_Change
#--------------------------#
{
  # Local variables
  my $lookupTO = $winConfig->tfLookupTO->Text();
  # Remember
  if ($lookupTO) {
    $CONFIG{'NSLOOKUP_TIMEOUT'} = $lookupTO;
    &saveConfig(\%CONFIG, $CONFIG_FILE);
  }

}  #--- End tfLookupTO_Change

#--------------------------#
sub rbNoResultOpt1_Click
#--------------------------#
{
  # Save the choice
  if ($winConfig->rbNoResultOpt1->Checked()) {
    $CONFIG{'NO_RESULT_OPT'} = 1;
    &saveConfig(\%CONFIG, $CONFIG_FILE);
  } else {
    $CONFIG{'NO_RESULT_OPT'} = 2;
    &saveConfig(\%CONFIG, $CONFIG_FILE);
  }

}  #--- End rbNoResultOpt1_Click

#--------------------------#
sub rbNoResultOpt2_Click
#--------------------------#
{
  # Save the choice
  if ($winConfig->rbNoResultOpt1->Checked()) {
    $CONFIG{'NO_RESULT_OPT'} = 1;
    &saveConfig(\%CONFIG, $CONFIG_FILE);
  } else {
    $CONFIG{'NO_RESULT_OPT'} = 2;
    &saveConfig(\%CONFIG, $CONFIG_FILE);
  }

}  #--- End rbNoResultOpt2_Click

#--------------------------#
sub tfUserAgent_Change
#--------------------------#
{
  # Remember
  if (my $userAgent = $winConfig->tfUserAgent->Text()) {
    $CONFIG{'USERAGENT'} = $userAgent;
    &saveConfig(\%CONFIG, $CONFIG_FILE);
  }

}  #--- End tfUserAgent_Change

#--------------------------#
sub cbLocalTZ_Change
#--------------------------#
{
  # Remember
  $CONFIG{'LOCAL_TIMEZONE'} = $winConfig->cbLocalTZ->GetCurSel();
  &saveConfig(\%CONFIG, $CONFIG_FILE);
  
}  #--- End cbLocalTZ_Change

#--------------------------#
sub cbDefaultLang_Change
#--------------------------#
{
  # Remember
  $CONFIG{'DEFAULT_LANG'} = $winConfig->cbDefaultLang->GetString($winConfig->cbDefaultLang->GetCurSel());
  &saveConfig(\%CONFIG, $CONFIG_FILE);
  
}  #--- End cbDefaultLang_Change

#--------------------------#
sub cbOutputCharset_Change
#--------------------------#
{
  # Remember
  $CONFIG{'OUTPUT_CHARSET'} = $winConfig->cbOutputCharset->GetString($winConfig->cbOutputCharset->GetCurSel());
  &saveConfig(\%CONFIG, $CONFIG_FILE);
  
}  #--- End cbOutputCharset_Change

#--------------------------#
sub cbDefaultOutput_Change
#--------------------------#
{
  # Remember
  $CONFIG{'DEFAULT_OUTPUT'} = $winDTDB->cbDefaultOutput->GetCurSel();
  &saveConfig(\%CONFIG, $CONFIG_FILE);
  
}  #--- End cbDefaultOutput_Change

#--------------------------#
sub chMACOUIDBAutoUpt_Click
#--------------------------#
{
  # Save the choice
  if ($winConfig->chMACOUIDBAutoUpt->Checked() == 1) {
    $CONFIG{'MACOUI_DB_AUTO_UPDATE'} = 1;
    &saveConfig(\%CONFIG, $CONFIG_FILE);
  } else {
    $CONFIG{'MACOUI_DB_AUTO_UPDATE'} = 0;
    &saveConfig(\%CONFIG, $CONFIG_FILE);
  }

}  #--- End chMACOUIDBAutoUpt_Click

#--------------------------#
sub tfMACOUIDB_Change
#--------------------------#
{
  # Local variables
  my $MACOUIDBFile = $winConfig->tfMACOUIDB->Text();
  # Remember
  if ($MACOUIDBFile and -f $MACOUIDBFile and &validSQLiteDB($MACOUIDBFile, 'MACOUI')) {
    $CONFIG{'MACOUI_DB_FILE'} = $MACOUIDBFile;
    &saveConfig(\%CONFIG, $CONFIG_FILE);
  } else {
    delete($CONFIG{'MACOUI_DB_FILE'});
    &saveConfig(\%CONFIG, $CONFIG_FILE);
    if ($MACOUIDBFile) {
      $winConfig->tfMACOUIDB->Text('');
      Win32::GUI::MessageBox($win, $STR{'invalidFile'}, $STR{'Error'}, 0x40010) if $START;
    }
  }

}  #--- End tfMACOUIDB_Change

#--------------------------#
sub btnMACOUIDB_Click
#--------------------------#
{
  # Local variables
  my $lastDir = $winConfig->tfMACOUIDB->Text();
  my $MACOUIDBFile;
  # Show OpenFile dialog window
  if ($lastDir) {
    my(@parts) = split(/\\/, $lastDir);
    if (pop(@parts) =~ /\./) { while ($lastDir =~ /[^\\]$/) { chop($lastDir); } }
    $MACOUIDBFile = Win32::GUI::GetOpenFileName(-owner         => $winConfig              ,
                                                -title         => $STR{'selectDBFile'}.':',
                                                -filter        => [$STR{'dbFile'}.' (*.db)', '.db'],
                                                -filemustexist => 1                       ,
                                                -directory     => $lastDir                ,
                                                -file          => 'OUI.db'                ,
                                                -explorer      => 1                       , );
  } else {
    $MACOUIDBFile = Win32::GUI::GetOpenFileName(-owner         => $winConfig              ,
                                                -title         => $STR{'selectDBFile'}.':',
                                                -filter        => [$STR{'dbFile'}.' (*.db)', '.db'],
                                                -filemustexist => 1                       ,
                                                -file          => 'OUI.db'                ,
                                                -explorer      => 1                       , );
  }
  # Selected file
  $winConfig->tfMACOUIDB->Text($MACOUIDBFile) if $MACOUIDBFile and -f $MACOUIDBFile;
  return(1);

}  #--- End btnMACOUIDB_Click

#--------------------------#
sub btnMACOUIDBUpt_Click
#--------------------------#
{
  if ($THR_UPDATE and $THR_UPDATE->is_running()) { Win32::GUI::MessageBox($win, $STR{'processRunning'}, $STR{'Error'}, 0x40010); }
  else {
    $THR_UPDATE = threads->create(sub {
      # Thread 'cancellation' signal handler
      $SIG{'KILL'} = sub {
        # Delete temp files if converting was in progress
        if (-e $winConfig->tfMACOUIDB->Text().'-journal') {
          my $localMACOUIDB = $winConfig->tfMACOUIDB->Text();
          unlink($localMACOUIDB.'-journal');
          unlink($localMACOUIDB);
        }
        $win->ChangeCursor($ARROW);
        # Turn off progress bar
        $winPb->lblPbCurr->Text('');
        $winPb->lblCount->Text('');
        $winPb->pbWinPb->SetPos(0);
        $winPb->Hide();
        threads->exit();
      };
      # Thread 'die' signal handler
      $SIG{__DIE__} = sub {
        # Delete temp files if converting was in progress
        if (-e $winConfig->tfMACOUIDB->Text().'-journal') {
          my $localMACOUIDB = $winConfig->tfMACOUIDB->Text();
          unlink($localMACOUIDB.'-journal');
          unlink($localMACOUIDB);
        }
        my $errMsg = (split(/ at /,$_[0]))[0];
        chomp($errMsg);
        $errMsg =~ s/[\t\r\n]/ /g;
        $win->ChangeCursor($ARROW);
        # Turn off progress bar
        $winPb->lblPbCurr->Text('');
        $winPb->lblCount->Text('');
        $winPb->pbWinPb->SetPos(0);
        $winPb->Hide();
        Win32::GUI::MessageBox($win, "$STR{'errorMsg'}: $errMsg", $STR{'Error'}, 0x40010);
      };
      &updateDB(1, 'MACOUI', $STR{'MACOUIDB'}, $winConfig->tfMACOUIDB->Text(), 'ieee.org', 'oui.db', $USERDIR, \$HOURGLASS, \$ARROW,
                \%CONFIG, $CONFIG_FILE, \$winConfig, \$winDTDB, \$winPb, \$win, \%STR);
    });
  }
  return(1);
  
}  #--- End btnMACOUIDBUpt_Click

#--------------------------#
sub tfGeoIPDB_Change
#--------------------------#
{
  # Local variables
  my $GeoIPDBFile = $winConfig->tfGeoIPDB->Text();
  # Remember
  if ($GeoIPDBFile and -f $GeoIPDBFile and &validGeoIPDB($GeoIPDBFile)) {
    $CONFIG{'GEOIP_DB_FILE'} = $GeoIPDBFile;
    &saveConfig(\%CONFIG, $CONFIG_FILE);
  } else {
    delete($CONFIG{'GEOIP_DB_FILE'});
    &saveConfig(\%CONFIG, $CONFIG_FILE);
    if ($GeoIPDBFile) {
      $winConfig->tfGeoIPDB->Text('');
      Win32::GUI::MessageBox($winConfig, $STR{'invalidFile'}, $STR{'Error'}, 0x40010) if $START;
    }
  }

}  #--- End tfGeoIPDB_Change

#--------------------------#
sub btnGeoIPDB_Click
#--------------------------#
{
  # Local variables
  my $lastDir = $winConfig->tfGeoIPDB->Text();
  my $GeoIPDBFile;
  # Show OpenFile dialog window
  if ($lastDir) {
    my(@parts) = split(/\\/, $lastDir);
    if (pop(@parts) =~ /\./) { while ($lastDir =~ /[^\\]$/) { chop($lastDir); } }
    $GeoIPDBFile = Win32::GUI::GetOpenFileName( -owner         => $winConfig                ,
                                                -title         => $STR{'selectDBFile'}.':'  ,
                                                -filter        => [$STR{'dbFile'}.' (*.mmdb)', '.mmdb'],
                                                -filemustexist => 1                         ,
                                                -directory     => $lastDir                  ,
                                                -file          => 'GeoLite2-City.mmdb'      ,
                                                -explorer      => 1                         , );
  } else {
    $GeoIPDBFile = Win32::GUI::GetOpenFileName( -owner         => $winConfig                ,
                                                -title         => $STR{'selectDBFile'}.':'  ,
                                                -filter        => [$STR{'dbFile'}.' (*.mmdb)', '.mmdb'],
                                                -filemustexist => 1                         ,
                                                -file          => 'GeoLite2-City.mmdb'      ,
                                                -explorer      => 1                         , );
  }
  # Selected file
  $winConfig->tfGeoIPDB->Text($GeoIPDBFile) if $GeoIPDBFile and -f $GeoIPDBFile;
  return(1);

}  #--- End btnGeoIPDB_Click

#--------------------------#
sub tfXLWHOISDB_Change
#--------------------------#
{
  # Local variables
  my $XLWHOISDBFile = $winConfig->tfXLWHOISDB->Text();
  # Remember
  if ($XLWHOISDBFile and -f $XLWHOISDBFile and &validSQLiteDB($XLWHOISDBFile, 'WHOIS_DB')) {
    $CONFIG{'XLWHOIS_DB_FILE'} = $XLWHOISDBFile;
    &saveConfig(\%CONFIG, $CONFIG_FILE);
  } else {
    delete($CONFIG{'XLWHOIS_DB_FILE'});
    &saveConfig(\%CONFIG, $CONFIG_FILE);
    if ($XLWHOISDBFile) {
      $winConfig->tfXLWHOISDB->Text('');
      Win32::GUI::MessageBox($win, $STR{'invalidFile'}, $STR{'Error'}, 0x40010) if $START;
    }
  }

}  #--- End tfXLWHOISDB_Change

#--------------------------#
sub btnXLWHOISDB_Click
#--------------------------#
{
  # Local variables
  my $lastDir = $winConfig->tfXLWHOISDB->Text();
  my $XLWHOISDBFile;
  # Show OpenFile dialog window
  if ($lastDir) {
    my(@parts) = split(/\\/, $lastDir);
    if (pop(@parts) =~ /\./) { while ($lastDir =~ /[^\\]$/) { chop($lastDir); } }
    $XLWHOISDBFile = Win32::GUI::GetOpenFileName( -owner         => $winConfig                 ,
                                                  -title         => $STR{'selectDBFile'}.':'   ,
                                                  -filter        => [$STR{'dbFile'}.' (*.db)', '.db'],
                                                  -filemustexist => 1                          ,
                                                  -directory     => $lastDir                   ,
                                                  -file          => 'Whois.db'                 ,
                                                  -explorer      => 1                          , );
  } else {
    $XLWHOISDBFile = Win32::GUI::GetOpenFileName( -owner         => $winConfig                 ,
                                                  -title         => $STR{'selectDBFile'}.':'   ,
                                                  -filter        => [$STR{'dbFile'}.' (*.db)', '.db'],
                                                  -filemustexist => 1                          ,
                                                  -file          => 'Whois.db'                 ,
                                                  -explorer      => 1                          , );
  }
  # Selected file
  $winConfig->tfXLWHOISDB->Text($XLWHOISDBFile);
  return(1);

}  #--- End btnXLWHOISDB_Click

#--------------------------#
sub tfIINDB_Change
#--------------------------#
{
  # Local variables
  my $IINDBFile = $winConfig->tfIINDB->Text();
  # Remember
  if ($IINDBFile and -f $IINDBFile and &validSQLiteDB($IINDBFile, 'IIN')) {
    $CONFIG{'IIN_DB_FILE'} = $IINDBFile;
    &saveConfig(\%CONFIG, $CONFIG_FILE);
  } else {
    delete($CONFIG{'IIN_DB_FILE'});
    &saveConfig(\%CONFIG, $CONFIG_FILE);
    if ($IINDBFile) {
      $winConfig->tfIINDB->Text('');
      Win32::GUI::MessageBox($win, $STR{'invalidFile'}, $STR{'Error'}, 0x40010) if $START;
    }
  }

}  #--- End tfIINDB_Change

#--------------------------#
sub btnIINDB_Click
#--------------------------#
{
  # Local variables
  my $lastDir = $winConfig->tfIINDB->Text();
  my $IINDBFile;
  # Show OpenFile dialog window
  if ($lastDir) {
    my(@parts) = split(/\\/, $lastDir);
    if (pop(@parts) =~ /\./) { while ($lastDir =~ /[^\\]$/) { chop($lastDir); } }
    $IINDBFile = Win32::GUI::GetOpenFileName( -owner         => $winConfig                 ,
                                              -title         => $STR{'selectDBFile'}.':'   ,
                                              -filter        => [$STR{'dbFile'}.' (*.db)', '.db'],
                                              -filemustexist => 1                          ,
                                              -directory     => $lastDir                   ,
                                              -file          => 'IIN.db'                   ,
                                              -explorer      => 1                          , );
  } else {
    $IINDBFile = Win32::GUI::GetOpenFileName( -owner         => $winConfig                 ,
                                              -title         => $STR{'selectDBFile'}.':'   ,
                                              -filter        => [$STR{'dbFile'}.' (*.db)', '.db'],
                                              -filemustexist => 1                          ,
                                              -file          => 'IIN.db'                   ,
                                              -explorer      => 1                          , );
  }
  # Selected file
  if ($IINDBFile and -f $IINDBFile) {
    $winConfig->tfIINDB->Text($IINDBFile);
    $CONFIG{'IIN_DB_FILE'} = $IINDBFile;
  }
  return(1);

}  #--- End btnIINDB_Click

#--------------------------#
sub btnIINDBUpt_Click
#--------------------------#
{
  if ($THR_UPDATE and $THR_UPDATE->is_running()) { Win32::GUI::MessageBox($win, $STR{'processRunning'}, $STR{'Error'}, 0x40010); }
  else {
    $THR_UPDATE = threads->create(sub {
      # Thread 'cancellation' signal handler
      $SIG{'KILL'} = sub {
        $win->ChangeCursor($ARROW);
        # Turn off progress bar
        $winPb->lblPbCurr->Text('');
        $winPb->lblCount->Text('');
        $winPb->pbWinPb->SetPos(0);
        $winPb->Hide();
        threads->exit();
      };
      # Thread 'die' signal handler
      $SIG{__DIE__} = sub {
        my $errMsg = (split(/ at /,$_[0]))[0];
        chomp($errMsg);
        $errMsg =~ s/[\t\r\n]/ /g;
        $win->ChangeCursor($ARROW);
        # Turn off progress bar
        $winPb->lblPbCurr->Text('');
        $winPb->lblCount->Text('');
        $winPb->pbWinPb->SetPos(0);
        $winPb->Hide();
        Win32::GUI::MessageBox($win, "$STR{'errorMsg'}: $errMsg", $STR{'Error'}, 0x40010);
      };
      my ($status, $return) = &downloadDB(\$winConfig, 'IIN', $STR{'IINDB'}, "$USERDIR\\IIN.db", 'le-tools.com', \$HOURGLASS,
                                          \$ARROW, \%CONFIG, $CONFIG_FILE, \$winConfig, \$winDTDB, \$winPb, \$win, \%STR);
      if ($status) { Win32::GUI::MessageBox($winConfig, "$STR{'IINDB'} $STR{'HasBeenUpdated'}", "XL-Tools $VERSION", 0x40040); }
      else         { Win32::GUI::MessageBox($winConfig, $return, $STR{'Error'}, 0x40010); }
    });
  }
  return(1);
  
}  #--- End btnIINDBUpt_Click

#--------------------------#
sub tfOSMDB_Change
#--------------------------#
{
  # Local variables
  my $OSMDBFile = $winConfig->tfOSMDB->Text();
  # Remember
  if ($OSMDBFile and -f $OSMDBFile and &validSQLiteDB($OSMDBFile, 'GPS2ADDR')) {
    $CONFIG{'OSM_DB'} = $OSMDBFile;
    &saveConfig(\%CONFIG, $CONFIG_FILE);
  } else {
    delete($CONFIG{'OSM_DB'});
    &saveConfig(\%CONFIG, $CONFIG_FILE);
    if ($OSMDBFile) {
      $winConfig->tfOSMDB->Text('');
      Win32::GUI::MessageBox($win, $STR{'invalidFile'}, $STR{'Error'}, 0x40010) if $START == 1;
    }
  }

}  #--- End tfOSMDB_Change

#--------------------------#
sub btnOSMDB_Click
#--------------------------#
{
  # Local variables
  my $lastDir = $winConfig->tfOSMDB->Text();
  $lastDir    = $USERDIR if !$lastDir and $USERDIR;
  my $OSMDBFile;
  # Show OpenFile dialog window
  if ($lastDir) {
    my (@parts) = split(/\\/, $lastDir);
    if (pop(@parts) =~ /\./) { while ($lastDir =~ /[^\\]$/) { chop($lastDir); } }
    $OSMDBFile = Win32::GUI::GetOpenFileName( -owner         => $winConfig              ,
                                              -title         => $STR{'selectDBFile'}.':',
                                              -filter        => [$STR{'dbFile'}.' (*.db)', '.db'],
                                              -filemustexist => 1                       ,
                                              -directory     => $lastDir                ,
                                              -file          => 'OSM.db'                ,
                                              -explorer      => 1                       , );
  } else {
    $OSMDBFile = Win32::GUI::GetOpenFileName( -owner         => $winConfig              ,
                                              -title         => $STR{'selectDBFile'}.':',
                                              -filter        => [$STR{'dbFile'}.' (*.db)', '.db'],
                                              -filemustexist => 1                       ,
                                              -file          => 'OSM.db'                ,
                                              -explorer      => 1                       , );
  }
  # Selected file
  $winConfig->tfOSMDB->Text($OSMDBFile) if $OSMDBFile and -f $OSMDBFile;
  return(1);

}  #--- End btnOSMDB_Click

#--------------------------#
sub btnNewOSMDB_Click
#--------------------------#
{
  # Local variables
  my $lastDir = $winConfig->tfOSMDB->Text();
  $lastDir    = $USERDIR if !$lastDir and $USERDIR;
  my $OSMDBFile;
  # Show SaveFileWindow for database
  if ($lastDir) {
    my (@parts) = split(/\\/, $lastDir);
    if (pop(@parts) =~ /\./) { while ($lastDir =~ /[^\\]$/) { chop($lastDir); } }
    $OSMDBFile = Win32::GUI::GetSaveFileName( -owner           => $winConfig                       ,
                                              -title           => $STR{'selPathDB'}.':'            ,
                                              -file            => 'OSM.db'                         ,
                                              -filter          => [$STR{'dbFile'}.' (*.db)', '.db'],
                                              -directory       => $lastDir                         ,
                                              -overwriteprompt => 1                                , );
  } else {
    $OSMDBFile = Win32::GUI::GetSaveFileName( -owner           => $winConfig                       ,
                                              -title           => $STR{'selPathDB'}.':'            ,
                                              -file            => 'OSM.db'                         ,
                                              -filter          => [$STR{'dbFile'}.' (*.db)', '.db'],
                                              -overwriteprompt => 1                                , );
    
  }
  if ($OSMDBFile and &createOSMDB($OSMDBFile)) {
    my $dbFolder = $OSMDBFile;
    while ($dbFolder =~ /[^\\]$/) { chop($dbFolder); }
    mkdir("$dbFolder\\osm") if !-d "$dbFolder\\osm"; # Create subfolder for JSON file
    Win32::GUI::MessageBox($winConfig, $STR{'createdDB'}, $STR{'OSMDB'}, 0x40040);
    $winConfig->tfOSMDB->Text($OSMDBFile);
  }
  return(1);
  
}  #--- End btnNewOSMDB_Click

#--------------------------#
sub createOSMDB
#--------------------------#
{
  # Local variables
  my $OSMDBFile = shift;
  # Create a new database
	$OSMDBFile = encode('utf8', $OSMDBFile);
  my $dsn = "DBI:SQLite:dbname=$OSMDBFile";
  my $dbh = DBI->connect($dsn, undef, undef, { RaiseError => 1, AutoCommit => 1 }) or return(0);
  # Create main table
  # Bounding box: lat_s, lat_n, lon_w, lon_e
  # Original query: lat, lon
  my $stmt = qq(CREATE TABLE IF NOT EXISTS GPS2ADDR
                (lat        REAL   NOT NULL,
                 lon        REAL   NOT NULL,
                 lat_s      REAL   NOT NULL,
                 lat_n      REAL   NOT NULL,
                 lon_w      REAL   NOT NULL,
                 lon_e      REAL   NOT NULL,
                 zoom_level TEXT   NOT NULL,
                 jsonFile   TEXT   NOT NULL,
                 PRIMARY KEY (lat, lon, zoom_level)));
  my $rv = $dbh->do($stmt);
  $dbh->disconnect();
  return(0) if $rv < 0;
  return(1);
  
}  #--- End createOSMDB

#--------------------------#
sub tfOSMEmailDB_Change
#--------------------------#
{
  # Remember
  if (my $email = $winConfig->tfOSMEmailDB->Text()) {
    $CONFIG{'EMAIL'} = $email;
    &saveConfig(\%CONFIG, $CONFIG_FILE);
  }

}  #--- End tfUserAgent_Change

#--------------------------#
sub tfDTDB_Change
#--------------------------#
{
  # Local variables
  my $DTDBFile = $winConfig->tfDTDB->Text();
  # Remember
  if ($DTDBFile and -f $DTDBFile and &validSQLiteDB($DTDBFile, 'DT')) {
    $CONFIG{'DT_DB_FILE'} = $DTDBFile;
    &saveConfig(\%CONFIG, $CONFIG_FILE);
  } else {
    delete($CONFIG{'DT_DB_FILE'});
    &saveConfig(\%CONFIG, $CONFIG_FILE);
    if ($DTDBFile) {
      $winConfig->tfDTDB->Text('');
      Win32::GUI::MessageBox($win, $STR{'invalidFile'}, $STR{'Error'}, 0x40010) if $START;
    }
  }

}  #--- End tfDTDB_Change

#--------------------------#
sub btnDTDB_Click
#--------------------------#
{
  # Local variables
  my $lastDir = $winConfig->tfDTDB->Text();
  my $DTDBFile;
  # Show OpenFile dialog window
  if ($lastDir) {
    my(@parts) = split(/\\/, $lastDir);
    if (pop(@parts) =~ /\./) { while ($lastDir =~ /[^\\]$/) { chop($lastDir); } }
    $DTDBFile = Win32::GUI::GetOpenFileName(  -owner         => $winConfig                 ,
                                              -title         => $STR{'selectDBFile'}.':'   ,
                                              -filter        => [$STR{'dbFile'}.' (*.db)', '.db'],
                                              -filemustexist => 1                          ,
                                              -directory     => $lastDir                   ,
                                              -file          => 'DT.db'                    ,
                                              -explorer      => 1                          , );
  } else {
    $DTDBFile = Win32::GUI::GetOpenFileName(  -owner         => $winConfig                 ,
                                              -title         => $STR{'selectDBFile'}.':'   ,
                                              -filter        => [$STR{'dbFile'}.' (*.db)', '.db'],
                                              -filemustexist => 1                          ,
                                              -file          => 'DT.db'                    ,
                                              -explorer      => 1                          , );
  }
  # Selected file
  if ($DTDBFile and -f $DTDBFile) {
    $winConfig->tfDTDB->Text($DTDBFile);
    $CONFIG{'DT_DB_FILE'} = $DTDBFile;
  }
  return(1);

}  #--- End btnDTDB_Click

#--------------------------#
sub btnDTDBUpt_Click
#--------------------------#
{
  if ($THR_UPDATE and $THR_UPDATE->is_running()) { Win32::GUI::MessageBox($winConfig, $STR{'processRunning'}, $STR{'Error'}, 0x40010); }
  else {
    $THR_UPDATE = threads->create(sub {
      # Thread 'cancellation' signal handler
      $SIG{'KILL'} = sub {
        $winConfig->ChangeCursor($ARROW);
        # Turn off progress bar
        $winPb->lblPbCurr->Text('');
        $winPb->lblCount->Text('');
        $winPb->pbWinPb->SetPos(0);
        $winPb->Hide();
        threads->exit();
      };
      # Thread 'die' signal handler
      $SIG{__DIE__} = sub {
        my $errMsg = (split(/ at /,$_[0]))[0];
        chomp($errMsg);
        $errMsg =~ s/[\t\r\n]/ /g;
        $winConfig->ChangeCursor($ARROW);
        # Turn off progress bar
        $winPb->lblPbCurr->Text('');
        $winPb->lblCount->Text('');
        $winPb->pbWinPb->SetPos(0);
        $winPb->Hide();
        Win32::GUI::MessageBox($winConfig, "$STR{'errorMsg'}: $errMsg", $STR{'Error'}, 0x40010);
      };
      my ($status, $return) = &downloadDB(\$winConfig, 'DT', $STR{'DTDB'}, "$USERDIR\\DT.db", 'le-tools.com', \$HOURGLASS,
                                          \$ARROW, \%CONFIG, $CONFIG_FILE, \$winConfig, \$winDTDB, \$winPb, \$win, \%STR);
      if ($status) { Win32::GUI::MessageBox($winConfig, "$STR{'DTDB'} $STR{'HasBeenUpdated'}", "XL-Tools $VERSION", 0x40040); }
      else         { Win32::GUI::MessageBox($winConfig, $return, $STR{'Error'}, 0x40010); }
    });
  }
  return(1);
  
}  #--- End btnDTDBUpt_Click