<commit_before># <@LICENSE>
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements.  See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to you under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License.  You may obtain a copy of the License at:
# 
#     http://www.apache.org/licenses/LICENSE-2.0
# 
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# </@LICENSE>

=head1 NAME

  Mail::SpamAssassin::Util::Progress - Progress bar support for SpamAssassin

=head1 SYNOPSIS

  my $progress = Mail::SpamAssassin::Util::Progress->new({total => 100});

  $msgcount = 0;
  foreach my $message (@messages) {
    # do something here
    $msgcount++;
    $progress->update($msgcount);
  }

  $progress->final();

=head1 DESCRIPTION

This module implements a progress bar for use in SpamAssassin scripts and
modules.  It allows you to create the progress bar, update it and print
out the final results of a particular run.

=cut

package Mail::SpamAssassin::Util::Progress;

use strict;
use warnings;
use bytes;

use constant HAS_TERM_READKEY => eval { require Term::ReadKey };

# Load Time::HiRes if it's available
BEGIN {
  eval { require Time::HiRes };
  Time::HiRes->import( qw(time) ) unless $@;
}

=head2 new

public class (Mail::SpamAssassin::Util::Progress) new (\% $args)

Description:
Creates a new Mail::SpamAssassin::Util::Progress object, valid values for
the $args hashref are:

=over 4

=item total (required)

The total number of messages expected to be processed.  This item is
required.

=item fh [optional]

An optional filehandle may be passed in, otherwise STDERR will be used by
default.

=item term [optional]

The module will attempt to determine if a valid terminal exists on the
filehandle.  This item allows you to override that value.

=back

=cut

sub new {
  my ($class, $args) = @_;
  $class = ref($class) || $class;

  if (!exists($args->{total}) || $args->{total} < 1) {
    warn "progress: must provide a total value > 1";
    return undef;
  }

  my $self = {
	      'total' => $args->{total},
	      'fh' => $args->{fh} || \*STDERR,
	     };

  bless ($self, $class);

  $self->{term} = $args->{term} || -t $self->{fh};

  $self->init_bar(); # this will give us the initial progress bar
  
  return $self;
}

=head2 init_bar

public instance () init_bar()

Description:
This method creates the initial progress bar and is called automatically from new.  In addition
you can call init_bar on an existing object to reset the bar to it's original state.

=cut

sub init_bar {
  my ($self) = @_;

  my $fh = $self->{fh};

  $self->{prev_num_done} = 0; # 0 for now, maybe allow this to be passed in
  $self->{num_done} = 0; # 0 for now, maybe allow this to be passed in

  $self->{avg_msgs_per_sec} = undef;

  $self->{start_time} = time();
  $self->{prev_time} = $self->{start_time};

  return unless ($self->{term});

  my $term_size;

  # If they have set the COLUMNS environment variable, respect it and move on
  if ($ENV{COLUMNS}) {
    $term_size = $ENV{COLUMNS};
  }

  # The ideal case would be if they happen to have Term::ReadKey installed
  if (!defined($term_size) && HAS_TERM_READKEY) {
    my $term_readkey_term_size;
    eval { $term_readkey_term_size = (Term::ReadKey::GetTerminalSize($self->{fh}))[0] };
    unless ($@) { # an error will just keep the default
      # GetTerminalSize might have returned an empty array, so check the
      # value and set if it exists, if not we keep the default
      $term_size = $term_readkey_term_size if ($term_readkey_term_size);
    }
  }

  # only viable on Unix based OS, so exclude windows, etc here
  if (!defined($term_size) && $^O !~ /^(mswin|dos|os2)/oi) {
    my $data = `stty -a`;
    if ($data =~ /columns (\d+)/) {
      $term_size = $1;
    }
  }
  # only viable on Unix based OS, so exclude windows, etc here
  if (!defined($term_size) && $^O !~ /^(mswin|dos|os2)/oi) {
    my $data = `tput cols`;
    if ($data =~ /^(\d+)/) {
      $term_size = $1;
    }
  }

  # fall back on the default
  if (!defined($term_size)) {
    $term_size = 80;
  }


  # Adjust the bar size based on what all is going to print around it,
  # do not forget the trailing space. Here is what we have to deal with
  #1234567890123456789012345678901234567
  # XXX% [] XXX.XX msgs/sec XXmXXs LEFT
  # XXX% [] XXX.XX msgs/sec XXmXXs DONE
  $self->{bar_size} = $term_size - 37;
<commit_msg>bug 5261: only try to match terminal size w/ regexp if variable is defined<commit_after># <@LICENSE>
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements.  See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to you under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License.  You may obtain a copy of the License at:
# 
#     http://www.apache.org/licenses/LICENSE-2.0
# 
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# </@LICENSE>

=head1 NAME

  Mail::SpamAssassin::Util::Progress - Progress bar support for SpamAssassin

=head1 SYNOPSIS

  my $progress = Mail::SpamAssassin::Util::Progress->new({total => 100});

  $msgcount = 0;
  foreach my $message (@messages) {
    # do something here
    $msgcount++;
    $progress->update($msgcount);
  }

  $progress->final();

=head1 DESCRIPTION

This module implements a progress bar for use in SpamAssassin scripts and
modules.  It allows you to create the progress bar, update it and print
out the final results of a particular run.

=cut

package Mail::SpamAssassin::Util::Progress;

use strict;
use warnings;
use bytes;

use constant HAS_TERM_READKEY => eval { require Term::ReadKey };

# Load Time::HiRes if it's available
BEGIN {
  eval { require Time::HiRes };
  Time::HiRes->import( qw(time) ) unless $@;
}

=head2 new

public class (Mail::SpamAssassin::Util::Progress) new (\% $args)

Description:
Creates a new Mail::SpamAssassin::Util::Progress object, valid values for
the $args hashref are:

=over 4

=item total (required)

The total number of messages expected to be processed.  This item is
required.

=item fh [optional]

An optional filehandle may be passed in, otherwise STDERR will be used by
default.

=item term [optional]

The module will attempt to determine if a valid terminal exists on the
filehandle.  This item allows you to override that value.

=back

=cut

sub new {
  my ($class, $args) = @_;
  $class = ref($class) || $class;

  if (!exists($args->{total}) || $args->{total} < 1) {
    warn "progress: must provide a total value > 1";
    return undef;
  }

  my $self = {
	      'total' => $args->{total},
	      'fh' => $args->{fh} || \*STDERR,
	     };

  bless ($self, $class);

  $self->{term} = $args->{term} || -t $self->{fh};

  $self->init_bar(); # this will give us the initial progress bar
  
  return $self;
}

=head2 init_bar

public instance () init_bar()

Description:
This method creates the initial progress bar and is called automatically from new.  In addition
you can call init_bar on an existing object to reset the bar to it's original state.

=cut

sub init_bar {
  my ($self) = @_;

  my $fh = $self->{fh};

  $self->{prev_num_done} = 0; # 0 for now, maybe allow this to be passed in
  $self->{num_done} = 0; # 0 for now, maybe allow this to be passed in

  $self->{avg_msgs_per_sec} = undef;

  $self->{start_time} = time();
  $self->{prev_time} = $self->{start_time};

  return unless ($self->{term});

  my $term_size;

  # If they have set the COLUMNS environment variable, respect it and move on
  if ($ENV{COLUMNS}) {
    $term_size = $ENV{COLUMNS};
  }

  # The ideal case would be if they happen to have Term::ReadKey installed
  if (!defined($term_size) && HAS_TERM_READKEY) {
    my $term_readkey_term_size;
    eval { $term_readkey_term_size = (Term::ReadKey::GetTerminalSize($self->{fh}))[0] };
    unless ($@) { # an error will just keep the default
      # GetTerminalSize might have returned an empty array, so check the
      # value and set if it exists, if not we keep the default
      $term_size = $term_readkey_term_size if ($term_readkey_term_size);
    }
  }

  # only viable on Unix based OS, so exclude windows, etc here
  if ($^O !~ /^(mswin|dos|os2)/i) {
    if (!defined $term_size) {
      my $data = `stty -a`;
      if (defined $data && $data =~ /columns (\d+)/) {
        $term_size = $1;
      }
    }

    if (!defined $term_size) {
      my $data = `tput cols`;
      if (defined $data && $data =~ /^(\d+)/) {
        $term_size = $1;
      }
    }
  }

  # fall back on the default
  if (!defined($term_size)) {
    $term_size = 80;
  }


  # Adjust the bar size based on what all is going to print around it,
  # do not forget the trailing space. Here is what we have to deal with
  #1234567890123456789012345678901234567
  # XXX% [] XXX.XX msgs/sec XXmXXs LEFT
  # XXX% [] XXX.XX msgs/sec XXmXXs DONE
  $self->{bar_size} = $term_size - 37;

{'fraction_non_alphanumeric': 0.1198137609932747, 'fraction_numerical': 0.01396792550439731, 'mean_word_length': 3.5723746452223275, 'pattern_counts': {'":': 0, '<': 9, '<?xml version=': 0, '>': 61, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3732382', 'n_tokens_mistral': 3275, 'n_tokens_neox': 3087, 'n_words': 1173}