App-Netdisco

 view release on metacpan or  search on metacpan

Changes  view on Meta::CPAN

  * Run daemons as target binary's owning user (supports run control)
  * Clean up library path fiddling across all scripts
  * Rename housekeeping expiry task to be expire
  * Refactor nbtstat to group probes by device where node was arped
  * Add note about pgtune to install docs

  [BUG FIXES]

  * Suggest installation of perl-core RPM (arguably Red Hat's bug not ours!)
  * FATAL warnings considered harmful
  * Only show STP blocked icon if port is UP
  * Store device model and serial via UTF8 conversion
  * Only set housekeeping default if user has enabled

2.024004 - 2014-03-04

  [BUG FIXES]

  * Fix Login and Logout that were broken with SSL

2.024003_001 - 2014-03-03

lib/App/Netdisco/Backend/Role/Manager.pm  view on Meta::CPAN

package App::Netdisco::Backend::Role::Manager;

use Dancer qw/:moose :syntax :script/;

use List::Util 'sum';
use App::Netdisco::Util::MCE;

use App::Netdisco::Backend::Job;
use App::Netdisco::JobQueue
  qw/jq_locked jq_getsome jq_lock jq_warm_thrusters/;

use Role::Tiny;
use namespace::clean;

sub worker_begin {
  my $self = shift;
  my $wid = $self->wid;

  return debug "mgr ($wid): no need for manager... skip begin"
    if setting('workers')->{'no_manager'};

lib/App/Netdisco/Backend/Role/Manager.pm  view on Meta::CPAN

  # job queue initialisation
  # the expensive parts of this were moved to primeskiplist job
  jq_warm_thrusters;

  # queue a job to rebuild the device action skip list
  $self->{queue}->enqueuep(200,
    App::Netdisco::Backend::Job->new({ job => 0, action => 'primeskiplist' }));

  # requeue jobs locally
  debug "mgr ($wid): searching for jobs booked to this processing node";
  my @jobs = jq_locked;

  if (scalar @jobs) {
      info sprintf "mgr (%s): found %s jobs booked to this processing node",
        $wid, scalar @jobs;
      $self->{queue}->enqueuep(100, @jobs);
  }
}

# creates a 'signature' for each job so that we can check for duplicates ...
# it happens from time to time due to the distributed nature of the job queue

lib/App/Netdisco/DB/ExplicitLocking.pm  view on Meta::CPAN

  );
}

use constant \%lock_modes;

use base 'Exporter';
our @EXPORT = ();
our @EXPORT_OK = (keys %lock_modes);
our %EXPORT_TAGS = (modes => \@EXPORT_OK);

sub txn_do_locked {
  my ($self, $table, $mode, $sub) = @_;
  my $sql_fmt = q{LOCK TABLE %s IN %%s MODE};
  my $schema = $self;

  if ($self->can('result_source')) {
      # ResultSet component
      $sub = $mode;
      $mode = $table;
      $table = $self->result_source->from;
      $schema = $self->result_source->schema;
  }

  $schema->throw_exception('missing Table name to txn_do_locked()')
    unless $table;

  $table = [$table] if ref '' eq ref $table;
  my $table_fmt = join ', ', ('%s' x scalar @$table);
  my $sql = sprintf $sql_fmt, $table_fmt;

  if (ref '' eq ref $mode and $mode) {
      scalar grep {$_ eq $mode} values %lock_modes
        or $schema->throw_exception('bad LOCK_MODE to txn_do_locked()');
  }
  else {
      $sub = $mode;
      $mode = 'ACCESS EXCLUSIVE';
  }

  $schema->txn_do(sub {
      my @params = map {$schema->storage->dbh->quote_identifier($_)} @$table;
      $schema->storage->dbh->do(sprintf $sql, @params, $mode);
      $sub->();

lib/App/Netdisco/DB/ExplicitLocking.pm  view on Meta::CPAN

=head1 SYNOPSIS

In your L<DBIx::Class> schema:

 package My::Schema;
 __PACKAGE__->load_components('+App::Netdisco::DB::ExplicitLocking');

Then, in your application code:

 use App::Netdisco::DB::ExplicitLocking ':modes';
 $schema->txn_do_locked($table, MODE_NAME, sub { ... });

This also works for the ResultSet:

 package My::Schema::ResultSet::TableName;
 __PACKAGE__->load_components('+App::Netdisco::DB::ExplicitLocking');

Then, in your application code:

 use App::Netdisco::DB::ExplicitLocking ':modes';
 $schema->resultset('TableName')->txn_do_locked(MODE_NAME, sub { ... });

=head1 DESCRIPTION

This L<DBIx::Class> component provides an easy way to execute PostgreSQL table
locks before a transaction block.

You can load the component in either the Schema class or ResultSet class (or
both) and then use an interface very similar to C<DBIx::Class>'s C<txn_do()>.

The package also exports constants for each of the table lock modes supported

lib/App/Netdisco/DB/ExplicitLocking.pm  view on Meta::CPAN

=item * C<SHARE_ROW_EXCLUSIVE>

=item * C<EXCLUSIVE>

=item * C<ACCESS_EXCLUSIVE>

=back

=head1 METHODS

=head2 C<< $schema->txn_do_locked($table|\@tables, MODE_NAME?, $subref) >>

This is the method signature used when the component is loaded into your
Schema class. The reason you might want to use this over the ResultSet version
(below) is to specify multiple tables to be locked before the transaction.

The first argument is one or more tables, and is required. Note that these are
the real table names in PostgreSQL, and not C<DBIx::Class> ResultSet aliases
or anything like that.

The mode name is optional, and defaults to C<ACCESS EXCLUSIVE>. You must use
one of the exported constants in this parameter.

Finally pass a subroutine reference, just as you would to the normal
C<DBIx::Class> C<txn_do()> method. Note that additional arguments are not
supported.

=head2 C<< $resultset->txn_do_locked(MODE_NAME?, $subref) >>

This is the method signature used when the component is loaded into your
ResultSet class. If you don't yet have a ResultSet class (which is the default
- normally only Result classes are created) then you can create a stub which
simply loads this component (and inherits from C<DBIx::Class::ResultSet>).

This is the simplest way to use this module if you only want to lock one table
before your transaction block.

The first argument is the optional mode name, which defaults to C<ACCESS

lib/App/Netdisco/JobQueue.pm  view on Meta::CPAN


use Module::Load ();
Module::Load::load
  'App::Netdisco::JobQueue::' . $ENV{ND_QUEUE_ENGINE} => ':all';

use base 'Exporter';
our @EXPORT = ();
our @EXPORT_OK = qw/
  jq_warm_thrusters
  jq_getsome
  jq_locked
  jq_queued
  jq_lock
  jq_defer
  jq_complete
  jq_log
  jq_userlog
  jq_insert
  jq_delete
/;
our %EXPORT_TAGS = ( all => \@EXPORT_OK );

lib/App/Netdisco/JobQueue.pm  view on Meta::CPAN

subroutines.

=head1 EXPORT_OK

=head2 jq_getsome( $num? )

Returns a list of randomly selected queued jobs. Default is to return one job,
unless C<$num> is provided. Jobs are returned as objects which implement the
Netdisco job instance interface (see below).

=head2 jq_locked()

Returns the list of jobs currently booked out to this processing node (denoted
by the local hostname). Jobs are returned as objects which implement the
Netdisco job instance interface (see below).

=head2 jq_queued( $job_type )

Returns a list of IP addresses of devices which currently have a job of the
given C<$job_type> queued (e.g. C<discover>, C<arpnip>, etc).

lib/App/Netdisco/JobQueue/PostgreSQL.pm  view on Meta::CPAN

use App::Netdisco::DB::ExplicitLocking ':modes';

use JSON::PP ();
use Try::Tiny;

use base 'Exporter';
our @EXPORT = ();
our @EXPORT_OK = qw/
  jq_warm_thrusters
  jq_getsome
  jq_locked
  jq_queued
  jq_lock
  jq_defer
  jq_complete
  jq_log
  jq_userlog
  jq_insert
  jq_delete
/;
our %EXPORT_TAGS = ( all => \@EXPORT_OK );

lib/App/Netdisco/JobQueue/PostgreSQL.pm  view on Meta::CPAN

    ]});

  while (my $job = $tasty->next) {
    if ($job->device) {
      # need to handle device discovered since backend daemon started
      # and the skiplist was primed. these should be checked against
      # the various acls and have device_skip entry added if needed,
      # and return false if it should have been skipped.
      my @badactions = get_denied_actions($job->device);
      if (scalar @badactions) {
        schema(vars->{'tenant'})->resultset('DeviceSkip')->txn_do_locked(EXCLUSIVE, sub {
            schema(vars->{'tenant'})->resultset('DeviceSkip')->find_or_create({
              backend => setting('workers')->{'BACKEND'}, device => $job->device,
            },{ key => 'device_skip_pkey' })->add_to_actionset(@badactions);
        });

        # will now not be selected in a future _getsome()
        next if scalar grep {$_ eq $job->action} @badactions;
      }
    }

lib/App/Netdisco/JobQueue/PostgreSQL.pm  view on Meta::CPAN

    }, { for => 'update' })
        ->update({ status => 'info', log => (sprintf 'duplicate of %s', $job->id) });

    debug sprintf 'getsome: cancelled %s duplicate(s) of job %s', ($gone || 0), $job->id;
    push @returned, App::Netdisco::Backend::Job->new({ $job->get_columns });
  }

  return @returned;
}

sub jq_locked {
  my @returned = ();
  my $rs = schema(vars->{'tenant'})->resultset('Admin')->search({
    status  => 'queued',
    backend => setting('workers')->{'BACKEND'},
    started => \[q/> (LOCALTIMESTAMP - ?::interval)/, setting('jobs_stale_after')],
  });

  while (my $job = $rs->next) {
      push @returned, App::Netdisco::Backend::Job->new({ $job->get_columns });
  }

lib/App/Netdisco/JobQueue/PostgreSQL.pm  view on Meta::CPAN

  # arpnip (and every other action) will be prevented on the device.

  # seeing as defer is only triggered by an SNMP connect failure, this
  # behaviour seems reasonable, to me (or desirable, perhaps).

  # the deferrable_actions setting exists as a workaround to this behaviour
  # should it be needed by any action (that is, per-device action but
  # do not increment deferrals count and simply try to run again).

  try {
    schema(vars->{'tenant'})->resultset('DeviceSkip')->txn_do_locked(EXCLUSIVE, sub {
      if ($job->device
          and not scalar grep { $job->action eq $_ }
                              @{ setting('deferrable_actions') || [] }) {

        schema(vars->{'tenant'})->resultset('DeviceSkip')->find_or_create({
          backend => setting('workers')->{'BACKEND'}, device => $job->device,
        },{ key => 'device_skip_pkey' })->increment_deferrals;
      }

      debug sprintf 'defer: job %s', ($job->id || 'unknown');

lib/App/Netdisco/JobQueue/PostgreSQL.pm  view on Meta::CPAN

  my $job = shift;
  my $happy = false;

  # lock db row and update to show job is done/error

  # now that SNMP connect failures are deferrals and not errors, any complete
  # status, whether success or failure, indicates an SNMP connect. reset the
  # connection failures counter to forget about occasional connect glitches.

  try {
    schema(vars->{'tenant'})->resultset('DeviceSkip')->txn_do_locked(EXCLUSIVE, sub {
      if ($job->device and not $job->is_offline) {
        schema(vars->{'tenant'})->resultset('DeviceSkip')->find_or_create({
          backend => setting('workers')->{'BACKEND'}, device => $job->device,
        },{ key => 'device_skip_pkey' })->update({ deferrals => 0 });
      }

      schema(vars->{'tenant'})->resultset('Admin')
        ->search({ job => $job->id }, { for => 'update' })
        ->update({
          status => $job->status,

lib/App/Netdisco/Web/Plugin/AdminTask/JobQueue.pm  view on Meta::CPAN

ajax '/ajax/content/admin/jobqueue' => require_role admin => sub {
    content_type('text/html');

    my @backends = schema(vars->{'tenant'})->resultset('DeviceSkip')
        ->search({device => '255.255.255.255'})->hri->all;

    my $num_backends = scalar @backends;
    my $tot_workers  = 0;
    $tot_workers += $_->{deferrals} for @backends;

    my $jq_locked = schema(vars->{'tenant'})->resultset('Admin')
      ->search({status => 'queued', backend => { '!=' => undef }})->count();

    my $jq_backlog = schema(vars->{'tenant'})->resultset('Admin')
      ->search({status => 'queued', backend => undef })->count();

    my $jq_done = schema(vars->{'tenant'})->resultset('Admin')
      ->search({status => 'done'})->count();

    my $jq_errored = schema(vars->{'tenant'})->resultset('Admin')
      ->search({status => 'error'})->count();

lib/App/Netdisco/Web/Plugin/AdminTask/JobQueue.pm  view on Meta::CPAN

        backend => { '!=' => undef },
        started => \[q/<= (LOCALTIMESTAMP - ?::interval)/, setting('jobs_stale_after')],
    })->count();

    my $jq_total = schema(vars->{'tenant'})->resultset('Admin')->count();

    template 'ajax/admintask/jobqueue.tt', {
      num_backends => commify($num_backends || '?'),
      tot_workers  => commify($tot_workers || '?'),

      jq_running => commify($jq_locked - $jq_stale),
      jq_backlog => commify($jq_backlog),
      jq_done => commify($jq_done),
      jq_errored => commify($jq_errored),
      jq_stale => commify($jq_stale),
      jq_total => commify($jq_total),

      results => [ jq_log ],
    }, { layout => undef };
};

lib/App/Netdisco/Web/Plugin/AdminTask/TimedOutDevices.pm  view on Meta::CPAN


register_admin_task({
  tag => 'timedoutdevices',
  label => 'SNMP Connect Failures',
});

ajax '/ajax/control/admin/timedoutdevices/del' => require_role admin => sub {
    send_error('Missing backend', 400) unless param('backend');
    send_error('Missing device',  400) unless param('device');

    schema(vars->{'tenant'})->resultset('DeviceSkip')->txn_do_locked(EXCLUSIVE, sub {
      schema(vars->{'tenant'})->resultset('DeviceSkip')->find_or_create({
        backend => param('backend'), device => param('device'),
      },{ key => 'device_skip_pkey' })->update({ deferrals => 0 });
    });
};

ajax '/ajax/content/admin/timedoutdevices' => require_role admin => sub {
    my @set = schema(vars->{'tenant'})->resultset('DeviceSkip')->search({
      deferrals => { '>' => 0 },
      device => { '!=' => '255.255.255.255' },

lib/App/Netdisco/Web/Plugin/AdminTask/UndiscoveredNeighbors.pm  view on Meta::CPAN

use App::Netdisco::Web::Plugin;

register_admin_task(
    {   tag          => 'undiscoveredneighbors',
        label        => 'Undiscovered Neighbors',
        provides_csv => 1,
    }
);

# just to note a problem with this query:
# using DeviceSkip to see if discover is blocked, but that table only shows
# blocked actions on backends not permitted, so there may be a backend running
# that permits the action, we would not know.

get '/ajax/content/admin/undiscoveredneighbors' => require_role admin => sub {
    my @results
        = schema(vars->{'tenant'})->resultset('Virtual::UndiscoveredNeighbors')->hri->all;
    return unless scalar @results;

    if ( request->is_ajax ) {
        template 'ajax/admintask/undiscoveredneighbors.tt',
            { results => \@results, },

lib/App/Netdisco/Web/Plugin/Report/PortBlocking.pm  view on Meta::CPAN


use Dancer ':syntax';
use Dancer::Plugin::DBIC;
use Dancer::Plugin::Auth::Extensible;

use App::Netdisco::Web::Plugin;

register_report(
    {   category     => 'Port',
        tag          => 'portblocking',
        label        => 'Blocked - Spanning Tree',
        provides_csv => 1,
        api_endpoint => 1,
    }
);

get '/ajax/content/report/portblocking' => require_login sub {
    my @results = schema(vars->{'tenant'})->resultset('Device')->search(
        { 'stp' => [ 'blocking', 'broken' ], 'up' => { '!=', 'down' } },
        {   select       => [ 'ip', 'dns', 'name' ],
            join         => ['ports'],

lib/App/Netdisco/Worker/Plugin/Discover/Properties.pm  view on Meta::CPAN

          $deviceports{$sub}->{slave_of} = $parent;
      }
  }

  # update num_ports
  $device->num_ports( scalar values %deviceports );

  # support for Hooks
  vars->{'hook_data'}->{'ports'} = [values %deviceports];

  schema('netdisco')->resultset('DevicePort')->txn_do_locked(ACCESS_EXCLUSIVE, sub {
    my $coder = JSON::PP->new->utf8(0)->allow_nonref(1)->allow_unknown(1);

    # backup the custom_fields
    my %fields = map  {($_->{port} => $coder->decode(Encode::encode('UTF-8',$_->{custom_fields} || '{}')))}
                 grep {exists $deviceports{$_->{port}}}
                      $device->ports
                             ->search(undef, {columns => [qw/port custom_fields/]})
                             ->hri->all;

    my %ok_fields = map {$_ => 1}

lib/App/Netdisco/Worker/Plugin/Expire.pm  view on Meta::CPAN


  # also have to clean up node_ip that have no correspoding node
  schema('netdisco')->resultset('NodeIp')->search({
    mac => { -in => schema('netdisco')->resultset('NodeIp')->search(
      { port => undef },
      { join => 'nodes', select => [{ distinct => 'me.mac' }], }
    )->as_query },
  })->delete;

  if (setting('expire_jobs') and setting('expire_jobs') > 0) {
      schema('netdisco')->txn_do_locked('admin', EXCLUSIVE, sub {
        schema('netdisco')->resultset('Admin')->search({
          entered => \[q/< (LOCALTIMESTAMP - ?::interval)/,
              (setting('expire_jobs') * 86400)],
        })->delete();
      });
  }

  if (setting('expire_userlog') and setting('expire_userlog') > 0) {
      schema('netdisco')->txn_do_locked('admin', EXCLUSIVE, sub {
        schema('netdisco')->resultset('UserLog')->search({
          creation => \[q/< (LOCALTIMESTAMP - ?::interval)/,
              (setting('expire_userlog') * 86400)],
        })->delete();
      });
  }

  # now update stats
  update_stats();

share/config.yml  view on Meta::CPAN

        vendor,
        os,
        version
      FROM
        ranked_devices
      WHERE
        rn = 1
      ORDER BY
        device_name, serial
  - tag: portserrordisabled
    label: 'Blocked - Error-Disabled'
    category: Port
    columns:
      - { ip: Device, _searchable: true }
      - { dns: DNS }
      - { port: Port }
      - { name: Description }
      - { reason: Reason }
    query: |
      SELECT dp.ip, d.dns, dp.port, dp.name, properties.error_disable_cause AS reason
        FROM device_port dp

share/contrib/raddb/dictionary.shiva  view on Meta::CPAN

VALUE	Shiva-Disconnect-Reason Remote			1
VALUE	Shiva-Disconnect-Reason Error			2
VALUE	Shiva-Disconnect-Reason Idle-Timeout		3
VALUE	Shiva-Disconnect-Reason Session-Timeout		4
VALUE	Shiva-Disconnect-Reason Admin-Disconnect	5
VALUE	Shiva-Disconnect-Reason Dialback		6
VALUE	Shiva-Disconnect-Reason Virtual-Connection	7
VALUE	Shiva-Disconnect-Reason Bandwidth-On-Demand	8
VALUE	Shiva-Disconnect-Reason Failed-Authentication	9
VALUE	Shiva-Disconnect-Reason Preempted		10
VALUE	Shiva-Disconnect-Reason Blocked			11
VALUE	Shiva-Disconnect-Reason Tariff-Management	12
VALUE	Shiva-Disconnect-Reason Backup			13

#	Shiva Function Values

VALUE	Shiva-Function		Unknown			0
VALUE	Shiva-Function		Dialin			1
VALUE	Shiva-Function		Dialout			2
VALUE	Shiva-Function		Lan-To-Lan		3

share/contrib/raddb/dictionary.usr  view on Meta::CPAN

VALUE	USR-Call-Event-Code			noFreeIGW	      10
VALUE	USR-Call-Event-Code			igwRejectCall	      11
VALUE	USR-Call-Event-Code			igwSetupTimeout	      12
VALUE	USR-Call-Event-Code			noFreeTdmts	      13
VALUE	USR-Call-Event-Code			bcReject	      14
VALUE	USR-Call-Event-Code			ieReject	      15
VALUE	USR-Call-Event-Code			chidReject	      16
VALUE	USR-Call-Event-Code			progReject	      17
VALUE	USR-Call-Event-Code			callingPartyReject    18
VALUE	USR-Call-Event-Code			calledPartyReject     19
VALUE	USR-Call-Event-Code			blocked		      20
VALUE	USR-Call-Event-Code			analogBlocked	      21
VALUE	USR-Call-Event-Code			digitalBlocked	      22
VALUE	USR-Call-Event-Code			outOfService	      23
VALUE	USR-Call-Event-Code			busy		      24
VALUE	USR-Call-Event-Code			congestion	      25
VALUE	USR-Call-Event-Code			protocolError	      26 
VALUE	USR-Call-Event-Code			noFreeBchannel	      27
VALUE	USR-Call-Event-Code			inOutCallCollision    28
VALUE	USR-Call-Event-Code			inCallArrival		29
VALUE	USR-Call-Event-Code			outCallArrival		30
VALUE	USR-Call-Event-Code			inCallConnect		31
VALUE	USR-Call-Event-Code			outCallConnect		32

share/public/css/smoothness/jquery-ui.custom.min.css  view on Meta::CPAN

/*! jQuery UI - v1.10.3 - 2013-05-06
* http://jqueryui.com
* Includes: jquery.ui.core.css, jquery.ui.autocomplete.css, jquery.ui.menu.css
* To view and modify this theme, visit http://jqueryui.com/themeroller/?ffDefault=Verdana%2CArial%2Csans-serif&fwDefault=normal&fsDefault=1.1em&cornerRadius=4px&bgColorHeader=cccccc&bgTextureHeader=highlight_soft&bgImgOpacityHeader=75&borderColorHead...
* Copyright 2013 jQuery Foundation and other contributors Licensed MIT */.ui-helper-hidden{display:none}.ui-helper-hidden-accessible{border:0;clip:rect(0 0 0 0);height:1px;margin:-1px;overflow:hidden;padding:0;position:absolute;width:1px}.ui-helper-r...

share/public/javascripts/jquery-latest.min.js  view on Meta::CPAN

/*! jQuery v1.12.4 | (c) jQuery Foundation | jquery.org/license */
!function(a,b){"object"==typeof module&&"object"==typeof module.exports?module.exports=a.document?b(a,!0):function(a){if(!a.document)throw new Error("jQuery requires a window with a document");return b(a)}:b(a)}("undefined"!=typeof window?window:this...
}return c}function Q(a){var b;for(b in a)if(("data"!==b||!n.isEmptyObject(a[b]))&&"toJSON"!==b)return!1;return!0}function R(a,b,d,e){if(M(a)){var f,g,h=n.expando,i=a.nodeType,j=i?n.cache:a,k=i?a[h]:a[h]&&h;if(k&&j[k]&&(e||j[k].data)||void 0!==d||"str...
marginLeft:0},function(){return a.getBoundingClientRect().left}):0))+"px":void 0}),n.each({margin:"",padding:"",border:"Width"},function(a,b){n.cssHooks[a+b]={expand:function(c){for(var d=0,e={},f="string"==typeof c?c.split(" "):[c];4>d;d++)e[a+V[d]+...
padding:"inner"+a,content:b,"":"outer"+a},function(c,d){n.fn[d]=function(d,e){var f=arguments.length&&(c||"boolean"!=typeof d),g=c||(d===!0||e===!0?"margin":"border");return Y(this,function(b,c,d){var e;return n.isWindow(b)?b.document.documentElement...

share/public/javascripts/jquery.floatThead.js  view on Meta::CPAN

        throw new Error('jQuery.floatThead must be run on a table that contains a <thead> element');
      }
      var headerFloated = false;
      var scrollingTop, scrollingBottom;
      var scrollbarOffset = {vertical: 0, horizontal: 0};
      var scWidth = scrollbarWidth();
      var lastColumnCount = 0; //used by columnNum()
      var $scrollContainer = opts.scrollContainer($table) || $([]); //guard against returned nulls

      var useAbsolutePositioning = opts.useAbsolutePositioning;
      if(useAbsolutePositioning == null){ //defaults: locked=true, !locked=false
        useAbsolutePositioning = opts.scrollContainer($table).length;
      }
      var $caption = $table.find("caption");
      var haveCaption = $caption.length == 1;
      if(haveCaption){
        var captionAlignTop = ($caption.css("caption-side") || $caption.attr("align") || "top") === "top";
      }

      var $fthGrp = $('<fthfoot style="display:table-footer-group;"/>');

      var locked = $scrollContainer.length > 0;
      var wrappedContainer = false; //used with absolute positioning enabled. did we need to wrap the scrollContainer/table with a relative div?
      var $wrapper = $([]); //used when absolute positioning enabled - wraps the table and the float container
      var absoluteToFixedOnScroll = ieVersion <= 9 && !locked && useAbsolutePositioning; //on ie using absolute positioning doesnt look good with window scrolling, so we change positon to fixed on scroll, and then change it back to absolute when done...
      var $floatTable = $("<table/>");
      var $floatColGroup = $("<colgroup/>");
      var $tableColGroup = $table.find('colgroup:first');
      var existingColGroup = true;
      if($tableColGroup.length == 0){
        $tableColGroup = $("<colgroup/>");
        existingColGroup = false;
      }
      var $fthRow = $('<fthrow style="display:table-row;height:0;"/>'); //created unstyled elements
      var $floatContainer = $('<div style="overflow: hidden;"></div>');

share/public/javascripts/jquery.floatThead.js  view on Meta::CPAN

          var positionCss = $container.css('position');
          var relativeToScrollContainer = (positionCss == "relative" || positionCss == "absolute");
          if(!relativeToScrollContainer || alwaysWrap){
            var css = {"paddingLeft": $container.css('paddingLeft'), "paddingRight": $container.css('paddingRight')};
            $floatContainer.css(css);
            $container = $container.wrap("<div class='"+opts.floatWrapperClass+"' style='position: relative; clear:both;'></div>").parent();
            wrappedContainer = true;
          }
          return $container;
        };
        if(locked){
          $wrapper = makeRelative($scrollContainer, true);
          $wrapper.append($floatContainer);
        } else {
          $wrapper = makeRelative($table);
          $table.after($floatContainer);
        }
      } else {
        $table.after($floatContainer);
      }

share/public/javascripts/jquery.floatThead.js  view on Meta::CPAN

        });
        $sizerRow.outerHeight(headerHeight);
        $sizerCells.outerHeight(headerHeight);
      }


      function setFloatWidth(){
        var tableWidth = $table.outerWidth();
        var width = $scrollContainer.width() || tableWidth;
        $floatContainer.width(width - scrollbarOffset.vertical);
        if(locked){
          var percent = 100 * tableWidth / (width - scrollbarOffset.vertical);
          $floatTable.css('width', percent+'%');
        } else {
          $floatTable.outerWidth(tableWidth);
        }
      }

      function updateScrollingOffsets(){
        scrollingTop = (util.isFunction(opts.scrollingTop) ? opts.scrollingTop($table) : opts.scrollingTop) || 0;
        scrollingBottom = (util.isFunction(opts.scrollingBottom) ? opts.scrollingBottom($table) : opts.scrollingBottom) || 0;

share/public/javascripts/jquery.floatThead.js  view on Meta::CPAN

        var scrollingContainerTop = $scrollContainer.scrollTop();

        //this floatEnd calc was moved out of the returned function because we assume the table height doesnt change (otherwise we must reinit by calling calculateFloatContainerPosFn)
        var floatEnd;
        var tableContainerGap = 0;
        var captionHeight = haveCaption ? $caption.outerHeight(true) : 0;
        var captionScrollOffset = captionAlignTop ? captionHeight : -captionHeight;

        var floatContainerHeight = $floatContainer.height();
        var tableOffset = $table.offset();
        if(locked){
          var containerOffset = $scrollContainer.offset();
          tableContainerGap = tableOffset.top - containerOffset.top + scrollingContainerTop;
          if(haveCaption && captionAlignTop){
            tableContainerGap += captionHeight;
          }
        } else {
          floatEnd = tableOffset.top - scrollingTop - floatContainerHeight + scrollingBottom + scrollbarOffset.horizontal;
        }
        var windowTop = $window.scrollTop();
        var windowLeft = $window.scrollLeft();

share/public/javascripts/jquery.floatThead.js  view on Meta::CPAN

          } else if(eventType == 'windowScrollDone'){
            return null; //event is fired when they stop scrolling. ignore it if not 'absoluteToFixedOnScroll'
          }

          tableOffset = $table.offset();
          if(haveCaption && captionAlignTop){
            tableOffset.top += captionHeight;
          }
          var top, left, tableHeight;

          if(locked && useAbsolutePositioning){ //inner scrolling, absolute positioning
            if (tableContainerGap >= scrollingContainerTop) {
              var gap = tableContainerGap - scrollingContainerTop;
              gap = gap > 0 ? gap : 0;
              top = gap;
            } else {
              top = wrappedContainer ? 0 : scrollingContainerTop;
              //headers stop at the top of the viewport
            }
            left = 0;
          } else if(!locked && useAbsolutePositioning) { //window scrolling, absolute positioning
            tableHeight = $table.outerHeight();
            if(windowTop > floatEnd + tableHeight + captionScrollOffset){
              top = tableHeight - floatContainerHeight + captionScrollOffset; //scrolled past table
            } else if (tableOffset.top > windowTop + scrollingTop) {
              top = 0; //scrolling to table
              unfloat();
            } else {
              top = scrollingTop + windowTop - tableOffset.top + tableContainerGap + (captionAlignTop ? captionHeight : 0);
              refloat(); //scrolling within table. header floated
            }
            left =  0;
          } else if(locked && !useAbsolutePositioning){ //inner scrolling, fixed positioning
            if (tableContainerGap > scrollingContainerTop) {
              top = tableOffset.top - windowTop;
              unfloat();
            } else {
              top = tableOffset.top + scrollingContainerTop  - windowTop - tableContainerGap;
              refloat();
              //headers stop at the top of the viewport
            }
            left = tableOffset.left + scrollContainerLeft - windowLeft;
          } else if(!locked && !useAbsolutePositioning) { //window scrolling, fixed positioning
            tableHeight = $table.outerHeight();
            if(windowTop > floatEnd + tableHeight + captionScrollOffset){
              top = tableHeight + scrollingTop - windowTop + floatEnd + captionScrollOffset;
              //scrolled past the bottom of the table
            } else if (tableOffset.top > windowTop + scrollingTop) {
              top = tableOffset.top - windowTop;
              refloat();
              //scrolled past the top of the table
            } else {
              //scrolling within the table

share/public/javascripts/jquery.floatThead.js  view on Meta::CPAN

        repositionFloatContainer = repositionFloatContainerFn();
        repositionFloatContainer(calculateFloatContainerPos('resize'), true, true);
      };
      var reflowEvent = util.debounce(function(){
        calculateScrollBarSize();
        updateScrollingOffsets();
        ensureReflow();
        calculateFloatContainerPos = calculateFloatContainerPosFn();
        repositionFloatContainer(calculateFloatContainerPos('reflow'), true);
      }, 1);
      if(locked){ //internal scrolling
        if(useAbsolutePositioning){
          $scrollContainer.on(eventName('scroll'), containerScrollEvent);
        } else {
          $scrollContainer.on(eventName('scroll'), containerScrollEvent);
          $window.on(eventName('scroll'), windowScrollEvent);
        }
      } else { //window scrolling
        $window.on(eventName('scroll'), windowScrollEvent);
      }

share/public/swagger-ui/swagger-ui-bundle.js  view on Meta::CPAN

/*!
 * https://github.com/Starcounter-Jack/JSON-Patch
 * (c) 2017 Joachim Wester
 * MIT license
 */function o(e,t){return r.call(e,t)}function i(e){if(Array.isArray(e)){for(var t=new Array(e.length),n=0;n<t.length;n++)t[n]=""+n;return t}if(Object.keys)return Object.keys(e);t=[];for(var r in e)o(e,r)&&t.push(r);return t}function a(e){return-1===...
/*!
 * cookie
 * Copyright(c) 2012-2014 Roman Shtylman
 * Copyright(c) 2015 Douglas Christopher Wilson
 * MIT Licensed
 */t.parse=function(e,t){if("string"!=typeof e)throw new TypeError("argument str must be a string");for(var n={},o=t||{},a=e.split(i),s=o.decode||r,l=0;l<a.length;l++){var c=a[l],f=c.indexOf("=");if(!(f<0)){var p=c.substr(0,f).trim(),d=c.substr(++f,c...
/*!
 * repeat-string <https://github.com/jonschlinkert/repeat-string>
 *
 * Copyright (c) 2014-2015, Jon Schlinkert.
 * Licensed under the MIT License.
 */var r,o="";e.exports=function(e,t){if("string"!=typeof e)throw new TypeError("expected a string");if(1===t)return e;if(2===t)return e+e;var n=e.length*t;if(r!==e||void 0===r)r=e,o="";else if(o.length>=n)return o.substr(0,n);for(;n>o.length&&t>1;)1...
/*!
 * Autolinker.js
 * 0.15.3
 *
 * Copyright(c) 2015 Gregory Jacobs <greg@greg-jacobs.com>
 * MIT Licensed. http://www.opensource.org/licenses/mit-license.php
 *
 * https://github.com/gregjacobs/Autolinker.js
 */
var e,t,n,r,o=function(e){o.Util.assign(this,e)};return o.prototype={constructor:o,urls:!0,email:!0,twitter:!0,newWindow:!0,stripPrefix:!0,truncate:void 0,className:"",htmlParser:void 0,matchParser:void 0,tagBuilder:void 0,link:function(e){for(var t=...

share/public/swagger-ui/swagger-ui-bundle.js.map  view on Meta::CPAN

{"version":3,"sources":["webpack:///webpack/universalModuleDefinition","webpack:///webpack/bootstrap 396b8c743e9ffbc09e47","webpack:///./node_modules/react/react.js","webpack:///./node_modules/prop-types/index.js","webpack:///./node_modules/babel-run...

share/public/swagger-ui/swagger-ui.css  view on Meta::CPAN

.swagger-ui{
  /*! normalize.css v7.0.0 | MIT License | github.com/necolas/normalize.css */font-family:sans-serif;color:#3b4151}.swagger-ui html{line-height:1.15;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%}.swagger-ui body{margin:0}.swagger-ui article...
/*# sourceMappingURL=swagger-ui.css.map*/

share/public/swagger-ui/swagger-ui.js  view on Meta::CPAN

(function webpackUniversalModuleDefinition(root,factory){if(typeof exports==="object"&&typeof module==="object")module.exports=factory(require("deep-extend"),require("immutable"),require("css.escape"),require("memoizee"),require("stream"),require("ba...
/*!
 * The buffer module from node.js, for the browser.
 *
 * @author   Feross Aboukhadijeh <feross@feross.org> <http://feross.org>
 * @license  MIT
 */
var base64=__webpack_require__(383);var ieee754=__webpack_require__(384);var isArray=__webpack_require__(385);exports.Buffer=Buffer;exports.SlowBuffer=SlowBuffer;exports.INSPECT_MAX_BYTES=50;Buffer.TYPED_ARRAY_SUPPORT=global.TYPED_ARRAY_SUPPORT!==und...
//# sourceMappingURL=swagger-ui.js.map

share/public/swagger-ui/swagger-ui.js.map  view on Meta::CPAN

{"version":3,"sources":["webpack:///webpack/universalModuleDefinition","webpack:///webpack/bootstrap fb516ccd71e38bfe6f58","webpack:///external \"react\"","webpack:///external \"prop-types\"","webpack:///./node_modules/babel-runtime/helpers/classCall...

xt/21-check_acl_no_ipaddr_only.t  view on Meta::CPAN

  use_ok( 'App::Netdisco::Util::DNS', 'hostname_from_ip' );
}

use Dancer qw/:script !pass/;

# this is needed so that test works in github action container
# and actually ends up cutting out live DNS anyway 👍
config->{'dns'} = { 'ETCHOSTS' => { localhost => [ [ '127.0.0.1' ] ] } };

config->{'dns'}->{'no'} = ['::1','fe80::/10','127.0.0.0/8','169.254.0.0/16'];
is(hostname_from_ip('127.0.0.1'), undef, '127.0.0.1 blocked');

config->{'dns'}->{'no'} = ['::1','fe80::/10','169.254.0.0/16'];
is(hostname_from_ip('127.0.0.1'), 'localhost', '127.0.0.1 allowed');

done_testing;



( run in 0.953 second using v1.01-cache-2.11-cpan-49f99fa48dc )