text:
BEGIN {
	require 'pathname'
	require 'rbconfig'
	require 'uri'
	require 'find'
	require 'pp'
	require 'irb'

	begin
		require 'readline'
		include Readline
	rescue LoadError => e
		$stderr.puts "Faking readline..."
		def readline( prompt )
			$stderr.print prompt.chomp
			return $stdin.gets.chomp
		end
	end

}

### Command-line utility functions
module UtilityFunctions
	include Config

	# The list of regexen that eliminate files from the MANIFEST
	ANTIMANIFEST = [
		/makedist\.rb/,
		/\bCVS\b/,
		/~$/,
		/^#/,
		%r{docs/html},
		%r{docs/man},
		/\bTEMPLATE\.\w+\.tpl\b/,
		/\.cvsignore/,
		/\.s?o$/,
	]

	# Set some ANSI escape code constants (Shamelessly stolen from Perl's
	# Term::ANSIColor by Russ Allbery <rra@stanford.edu> and Zenin <zenin@best.com>
	AnsiAttributes = {
		'clear'      => 0,
		'reset'      => 0,
		'bold'       => 1,
		'dark'       => 2,
		'underline'  => 4,
		'underscore' => 4,
		'blink'      => 5,
		'reverse'    => 7,
		'concealed'  => 8,

		'black'      => 30,   'on_black'   => 40,
		'red'        => 31,   'on_red'     => 41,
		'green'      => 32,   'on_green'   => 42,
		'yellow'     => 33,   'on_yellow'  => 43,
		'blue'       => 34,   'on_blue'    => 44,
		'magenta'    => 35,   'on_magenta' => 45,
		'cyan'       => 36,   'on_cyan'    => 46,
		'white'      => 37,   'on_white'   => 47
	}

	ErasePreviousLine = "\033[A\033[K"

	ManifestHeader = (<<-"EOF").gsub( /^\t+/, '' )
		#
		# Distribution Manifest
		# Created: #{Time::now.to_s}
		#

	EOF

	# A cache of programs found by find_program()
	Programs = {}

	###############
	module_function
	###############

	# Create a string that contains the ANSI codes specified and return it
	def ansi_code( *attributes )
		attributes.flatten!
		# $stderr.puts "Returning ansicode for TERM = %p: %p" %
		# 	[ ENV['TERM'], attributes ]
		return '' unless /(?:vt10[03]|xterm(?:-color)?|linux|screen)/i =~ ENV['TERM']
		attributes = AnsiAttributes.values_at( *attributes ).compact.join(';')

		# $stderr.puts "  attr is: %p" % [attributes]
		if attributes.empty?
			return ''
		else
			return "\e[%sm" % attributes
		end
	end

	### Colorize the given +string+ with the specified +attributes+ and return it, handling line-endings, etc.
	def colorize( string, *attributes )
		ending = string[/(\s)$/] || ''
		string = string.rstrip
		return ansi_code( attributes.flatten ) + string + ansi_code( 'reset' ) + ending
	end

	# Test for the presence of the specified <tt>library</tt>, and output a
	# message describing the test using <tt>nicename</tt>. If <tt>nicename</tt>
	# is <tt>nil</tt>, the value in <tt>library</tt> is used to build a default.
	def test_for_library( library, nicename=nil, progress=false )
		nicename ||= library
		message( "Testing for the #{nicename} library..." ) if progress
		if $LOAD_PATH.detect {|dir|
				File.exists?(File.join(dir,"#{library}.rb")) ||
				File.exists?(File.join(dir,"#{library}.#{CONFIG['DLEXT']}"))
			}
			message( "found.\n" ) if progress
			return true
		else
			message( "not found.\n" ) if progress
			return false
		end
	end

	# Test for the presence of the specified <tt>library</tt>, and output a
	# message describing the problem using <tt>nicename</tt>. If
	# <tt>nicename</tt> is <tt>nil</tt>, the value in <tt>library</tt> is used
	# to build a default. If <tt>raa_url</tt> and/or <tt>download_url</tt> are
	# specified, they are also use to build a message describing how to find the
	# required library. If <tt>fatal</tt> is <tt>true</tt>, a missing library
	# will cause the program to abort.
	def test_for_required_library( library, nicename=nil, raa_url=nil, download_url=nil, fatal=true )
		nicename ||= library
		unless test_for_library( library, nicename )
			msgs = [ "You are missing the required #{nicename} library.\n" ]
			msgs << "RAA: #{raa_url}\n" if raa_url
			msgs << "Download: #{download_url}\n" if download_url
			if fatal
				abort msgs.join('')
			else
				error_message msgs.join('')
			end
		end
		return true
	end

	### Output <tt>msg</tt> as a ANSI-colored program/section header (white on
	### blue).
	def header( msg )
		msg.chomp!
		$stderr.puts ansi_code( 'bold', 'white', 'on_blue' ) + msg + ansi_code( 'reset' )
		$stderr.flush
	end

	### Output <tt>msg</tt> to STDERR and flush it.
	def message( *msgs )
		$stderr.print( msgs.join("\n") )
		$stderr.flush
	end

	### Output +msg+ to STDERR and flush it if $VERBOSE is true.
	def verbose_msg( msg )
		msg.chomp!
		message( msg + "\n" ) if $VERBOSE
	end

	### Output the specified <tt>msg</tt> as an ANSI-colored error message
	### (white on red).
	def error_msg( msg )
		message ansi_code( 'bold', 'white', 'on_red' ) + msg + ansi_code( 'reset' )
	end
	alias :error_message :error_msg

	### Output the specified <tt>msg</tt> as an ANSI-colored debugging message
	### (yellow on blue).
	def debug_msg( msg )
		return unless $DEBUG
		msg.chomp!
		$stderr.puts ansi_code( 'bold', 'yellow', 'on_blue' ) + ">>> #{msg}" + ansi_code( 'reset' )
		$stderr.flush
	end

	### Erase the previous line (if supported by your terminal) and output the
	### specified <tt>msg</tt> instead.
	def replace_msg( msg )
		$stderr.puts
		$stderr.print ErasePreviousLine
		message( msg )
	end
	alias :replace_message :replace_msg

	### Output a divider made up of <tt>length</tt> hyphen characters.
	def divider( length=75 )
		$stderr.puts "\r" + ("-" * length )
	end
	alias :write_line :divider

	### Output the specified <tt>msg</tt> colored in ANSI red and exit with a
	### status of 1.
	def abort( msg )
		print ansi_code( 'bold', 'red' ) + "Aborted: " + msg.chomp + ansi_code( 'reset' ) + "\n\n"
		Kernel.exit!( 1 )
	end

	### Output the specified <tt>prompt_string</tt> as a prompt (in green) and
	### return the user's input with leading and trailing spaces removed.  If a
	### test is provided, the prompt will repeat until the test returns true.
	### An optional failure message can also be passed in.
	def prompt( prompt_string, failure_msg="Try again." ) # :yields: response
		prompt_string.chomp!
		prompt_string << ":" unless /\W$/.match( prompt_string )
		response = nil

		begin
			response = readline( ansi_code('bold', 'green') +
				"#{prompt_string} " + ansi_code('reset') ) || ''
			response.strip!
			if block_given? && ! yield( response )
				error_message( failure_msg + "\n\n" )
				response = nil
			end
		end until response

		return response
	end

	### Prompt the user with the given <tt>prompt_string</tt> via #prompt,
	### substituting the given <tt>default</tt> if the user doesn't input
	### anything.  If a test is provided, the prompt will repeat until the test
	### returns true.  An optional failure message can also be passed in.
	def prompt_with_default( prompt_string, default, failure_msg="Try again." )
		response = nil

		begin
			response = prompt( "%s [%s]" % [ prompt_string, default ] )
			response = default if response.empty?

			if block_given? && ! yield( response )
				error_message( failure_msg + "\n\n" )
				response = nil
			end
		end until response

		return response
	end

	### Display a description of a potentially-dangerous task, and prompt
	### for confirmation. If the user answers with anything that begins
	### with 'y', yield to the block. If +abort_on_decline+ is +true+,
	### any non-'y' answer will fail with an error message.
	def ask_for_confirmation( description, abort_on_decline=true )
		puts description

		answer = prompt_with_default( "Continue?", 'n' ) do |input|
			input =~ /^[yn]/i
		end

		if answer =~ /^y/i
			return yield
		elsif abort_on_decline
			error "Aborted."
			fail
		end

		return false
	end

	### Search for the program specified by the given <tt>progname</tt> in the
	### user's <tt>PATH</tt>, and return the full path to it, or <tt>nil</tt> if
	### no such program is in the path.
	def find_program( progname )
		unless Programs.key?( progname )
			ENV['PATH'].split(File::PATH_SEPARATOR).
				collect {|dir| Pathnanme.new(dir) }.each do |dir|
					file = dir + progname
					if file.executable?
						Programs[ progname ] = file
						break
					end
				end
		end

		return Programs[ progname ].to_s
	end

	### Search for the release version for the project in the specified
	### +directory+ using tags named "RELEASE_<major>_<minor>" if it's a CVS project
	### or the 'project-version' metadata value of the toplevel directory if it's
	### a Subversion project.
	def extract_version( directory='.' )
		release = nil

		Dir::chdir( directory ) do
			if File::directory?( "CVS" )
				verbose_msg( "Project is versioned via CVS. Searching for RELEASE_*_* tags..." )

				if (( cvs = find_program('cvs') ))
					revs = []
					output = %x{cvs log}
					output.scan( /RELEASE_(\d+(?:_\d\w+)*)/ ) {|match|
						rev = $1.split(/_/).collect {|s| Integer(s) rescue 0}
						verbose_msg( "Found %s...\n" % rev.join('.') )
						revs << rev
					}

					release = revs.sort.last
				end

			elsif File::directory?( '.svn' )
				verbose_msg( "Project is versioned via Subversion" )

				if (( svn = find_program('svn') ))
					output = %x{svn pg project-version}.chomp
					unless output.empty?
						verbose_msg( "Using 'project-version' property: %p" % output )
						release = output.split( /[._]/ ).collect {|s| Integer(s) rescue 0}
					end
				end
			end
		end

		return release
	end

	### Find the current release version for the project in the specified
	### +directory+ and return its successor.
	def extract_next_version( directory='.' )
		version = extract_version( directory ) || [0,0,0]
		version.compact!
		version[-1] += 1

		return version
	end

	# Pattern for extracting the name of the project from a Subversion URL
	SVNUrlPath = %r{
		.*/						# Skip all but the last bit
		([^/]+)					# $1 = project name
		/						# Followed by / +
		(?:
			trunk |				# 'trunk'
			(
				branches |		# ...or branches/branch-name
				tags			# ...or tags/tag-name
			)/\w
		)
		$						# bound to the end
	}ix

	### Extract the project name for the given +directory+. The project name is
	### the repository name if it's versioned with CVS, set via the 'project-name'
	### metadata value if versioned with Subversion, or just based on the name of the
	### directory itself if it's not versioned with one of those two systems.
	def extract_project_name( directory='.' )
		name = nil

		Dir::chdir( directory ) do

			# CVS-controlled
			if File::directory?( "CVS" )
				verbose_msg( "Project is versioned via CVS. Using repository name." )
				name = File.open( "CVS/Repository", "r").readline.chomp
				name.sub!( %r{.*/}, '' )

			# Subversion-controlled
			elsif File::directory?( '.svn' )
				verbose_msg( "Project is versioned via Subversion" )

				# If the machine has the svn tool, try to get the project name
				if (( svn = find_program( 'svn' ) ))

					# First try an explicit property
					output = shell_command( svn, 'pg', 'project-name' )
					if !output.empty?
						verbose_msg( "Using 'project-name' property: %p" % output )
						name = output.first.chomp

					# If that doesn't work, try to figure it out from the URL
					elsif (( uri = get_svn_uri() ))
						name = uri.path.sub( SVNUrlPath ) { $1 }
					end
				end
			end

			# Fall back to guessing based on the directory name
			unless name
				name = File::basename(File::dirname( File::expand_path(__FILE__) ))
			end
		end

		return name
	end

	### Extract the Subversion URL from the specified directory and return it as
	### a URI object.
	def get_svn_uri( directory='.' )
		uri = nil

		Dir::chdir( directory ) do
			output = %x{svn info}
			debug_msg( "Using info: %p" % output )

			if /^URL: \s* ( .* )/xi.match( output )
				uri = URI::parse( $1 )
			end
		end

		return uri
	end

	### (Re)make a manifest file in the specified +path+.
	def make_manifest( path="MANIFEST" )
		if File::exists?( path )
			reply = prompt_with_default( "Replace current '#{path}'? [yN]", "n" )
			return false unless /^y/i.match( reply )

			verbose_msg "Replacing manifest at '#{path}'"
		else
			verbose_msg "Creating new manifest at '#{path}'"
		end

		files = []
		verbose_msg( "Finding files...\n" )
		Find::find( Dir::pwd ) do |f|
			Find::prune if File::directory?( f ) &&
				/^\./.match( File::basename(f) )
			verbose_msg( "  found: #{f}\n" )
			files << f.sub( %r{^#{Dir::pwd}/?}, '' )
		end
		files = vet_manifest( files )

		verbose_msg( "Writing new manifest to #{path}..." )
		File::open( path, File::WRONLY|File::CREAT|File::TRUNC ) do |ofh|
			ofh.puts( ManifestHeader )
			ofh.puts( files )
		end
		verbose_msg( "done." )
	end

	### Read the specified <tt>manifest_file</tt>, which is a text file
	### describing which files to package up for a distribution. The manifest
	### should consist of one or more lines, each containing one filename or
	### shell glob pattern.
	def read_manifest( manifest_file="MANIFEST" )
		verbose_msg "Building manifest..."
		raise "Missing #{manifest_file}, please remake it" unless File.exists? manifest_file

		manifest = IO::readlines( manifest_file ).collect {|line|
			line.chomp
		}.select {|line|
			line !~ /^(\s*(#.*)?)?$/
		}

		filelist = []
		for pat in manifest
			verbose_msg "Adding files that match '#{pat}' to the file list"
			filelist |= Dir.glob( pat ).find_all {|f| FileTest.file?(f)}
		end

		verbose_msg "found #{filelist.length} files.\n"
		return filelist
	end

	### Given a <tt>filelist</tt> like that returned by #read_manifest, remove
	### the entries therein which match the Regexp objects in the given
	### <tt>antimanifest</tt> and return the resultant Array.
	def vet_manifest( filelist, antimanifest=ANTIMANIFEST )
		orig_length = filelist.length
		verbose_msg "Vetting manifest..."

		for regex in antimanifest
			verbose_msg "\n\tPattern /#{regex.source}/ removed: " +
				filelist.find_all {|file| regex.match(file)}.join(', ')
			filelist.delete_if {|file| regex.match(file)}
		end

		verbose_msg "removed #{orig_length - filelist.length} files from the list.\n"
		return filelist
	end

	### Combine a call to #read_manifest with one to #vet_manifest.
	def get_vetted_manifest( manifest_file="MANIFEST", antimanifest=ANTIMANIFEST )
		vet_manifest( read_manifest(manifest_file), antimanifest )
	end

	### Given a documentation <tt>catalog_file</tt>, extract the title, if
	### available, and return it. Otherwise generate a title from the name of
	### the CVS module.
	def find_rdoc_title( catalog_file="docs/CATALOG" )

		# Try extracting it from the CATALOG file from a line that looks like:
		# Title: Foo Bar Module
		title = find_catalog_keyword( 'title', catalog_file )

		# If that doesn't work for some reason, use the name of the project.
		title = extract_project_name()

		return title
	end

	### Given a documentation <tt>catalog_file</tt>, extract the name of the file
	### to use as the initally displayed page. If extraction fails, the
	### +default+ will be used if it exists. Returns +nil+ if there is no main
	### file to be found.
	def find_rdoc_main( catalog_file="docs/CATALOG", default="README" )

		# Try extracting it from the CATALOG file from a line that looks like:
		# Main: Foo Bar Module
		main = find_catalog_keyword( 'main', catalog_file )

		# Try to make some educated guesses if that doesn't work
		if main.nil?
			basedir = File::dirname( __FILE__ )
			basedir = File::dirname( basedir ) if /docs$/ =~ basedir

			if File::exists?( File::join(basedir, default) )
				main = default
			end
		end

		return main
	end

	### Given a documentation <tt>catalog_file</tt>, extract an upload URL for
	### RDoc.
	def find_rdoc_upload( catalog_file="docs/CATALOG" )
		find_catalog_keyword( 'upload', catalog_file )
	end

	### Given a documentation <tt>catalog_file</tt>, extract a CVS web frontend
	### URL for RDoc.
	def find_rdoc_cvs_url( catalog_file="docs/CATALOG" )
		find_catalog_keyword( 'webcvs', catalog_file )
	end

	### Find one or more 'accessor' directives in the catalog if they exist and
	### return an Array of them.
	def find_rdoc_accessors( catalog_file="docs/CATALOG" )
		accessors = []
		in_attr_section = false
		indent = ''

		if File::exists?( catalog_file )
			verbose_msg "Extracting accessors from CATALOG file (%s).\n" % catalog_file

			# Read lines from the catalog
			File::foreach( catalog_file ) do |line|
				debug_msg( "  Examining line #{line.inspect}..." )

				# Multi-line accessors
				if in_attr_section
					if /^#\s+([a-z0-9_]+(?:\s*=\s*.*)?)$/i.match( line )
						debug_msg( "    Found accessor: #$1" )
						accessors << $1
						next
					end

					debug_msg( "  End of accessors section." )
					in_attr_section = false

				# Single-line accessor
				elsif /^#\s*Accessors:\s*(\S+)$/i.match( line )
					debug_msg( "  Found single accessors line: #$1" )
					vals = $1.split(/,/).collect {|val| val.strip }
					accessors.replace( vals )

				# Multi-line accessor header
				elsif /^#\s*Accessors:\s*$/i.match( line )
					debug_msg( "  Start of accessors section." )
					in_attr_section = true
				end

			end
		end

		debug_msg( "Found accessors: %s" % accessors.join(",") )
		return accessors
	end

	### Given a documentation <tt>catalog_file</tt>, try extracting the given
	### +keyword+'s value from it. Keywords are lines that look like:
	###   # <keyword>: <value>
	### Returns +nil+ if the catalog file was unreadable or didn't contain the
	### specified +keyword+.
	def find_catalog_keyword( keyword, catalog_file="docs/CATALOG" )
		val = nil

		if File::exists? catalog_file
			verbose_msg "Extracting '#{keyword}' from CATALOG file (%s).\n" % catalog_file
			File::foreach( catalog_file ) do |line|
				debug_msg( "Examining line #{line.inspect}..." )
				val = $1.strip and break if /^#\s*#{keyword}:\s*(.*)$/i.match( line )
			end
		end

		return val
	end

	### Given a documentation <tt>catalog_file</tt>, which is in the same format
	### as that described by #read_manifest, read and expand it, and then return
	### a list of those files which appear to have RDoc documentation in
	### them. If <tt>catalog_file</tt> is nil or does not exist, the MANIFEST
	### file is used instead.
	def find_rdocable_files( catalog_file="docs/CATALOG" )
		startlist = []
		if File.exists? catalog_file
			verbose_msg "Using CATALOG file (%s).\n" % catalog_file
			startlist = get_vetted_manifest( catalog_file )
		else
			verbose_msg "Using default MANIFEST\n"
			startlist = get_vetted_manifest()
		end

		verbose_msg "Looking for RDoc comments in:\n"
		startlist.select {|fn|
			verbose_msg "  #{fn}: "
			found = false
			File::open( fn, "r" ) {|fh|
				fh.each {|line|
					if line =~ /^(\s*#)?\s*=/ || line =~ /:\w+:/ || line =~ %r{/\*}
						found = true
						break
					end
				}
			}

			verbose_msg( (found ? "yes" : "no") + "\n" )
			found
		}
	end

	### Open a file and filter each of its lines through the given block a
	### <tt>line</tt> at a time. The return value of the block is used as the
	### new line, or omitted if the block returns <tt>nil</tt> or
	### <tt>false</tt>.
	def edit_in_place( file, test_mode=false ) # :yields: line
		raise "No block specified for editing operation" unless block_given?

		temp_name = "#{file}.#{$$}"
		File::open( temp_name, File::RDWR|File::CREAT, 0600 ) do |tempfile|
			File::open( file, File::RDONLY ) do |fh|
				fh.each do |line|
					newline = yield( line ) or next
					tempfile.print( newline )
					$stderr.puts "%p -> %p" % [ line, newline ] if
						line != newline
				end
			end
		end

		if test_mode
			File::unlink( temp_name )
		else
			File::rename( temp_name, file )
		end
	end

	### Execute the specified shell <tt>command</tt>, read the results, and
	### return them. Like a %x{} that returns an Array instead of a String.
	def shell_command( *command )
		raise "Empty command" if command.empty?

		cmdpipe = IO::open( '|-' ) or exec( *command )
		return cmdpipe.readlines
	end

	### Execute a block with $VERBOSE set to +false+, restoring it to its
	### previous value before returning.
	def verbose_off
		raise LocalJumpError, "No block given" unless block_given?

		thrcrit = Thread.critical
		oldverbose = $VERBOSE
		begin
			Thread.critical = true
			$VERBOSE = false
			yield
		ensure
			$VERBOSE = oldverbose
			Thread.critical = false
		end
	end

	### Try the specified code block, printing the given
	def try( msg, bind=TOPLEVEL_BINDING )
		result = ''
		if msg =~ /^to\s/
			message "Trying #{msg}...\n"
		else
			message msg + "\n"
		end

		begin
			rval = nil
			if block_given?
				rval = yield
			else
				file, line = caller(1)[0].split(/:/,2)
				rval = eval( msg, bind, file, line.to_i )
			end

			PP.pp( rval, result )

		rescue Exception => err
			if err.backtrace
				nicetrace = err.backtrace.delete_if {|frame|
					/in `(try|eval)'/ =~ frame
				}.join("\n\t")
			else
				nicetrace = "Exception had no backtrace"
			end

			result = err.message + "\n\t" + nicetrace

		ensure
			divider
			message result.chomp + "\n"
			divider
			$stderr.puts
		end
	end

	### Start an IRB session with the specified binding +b+ as the current scope.
	def start_irb_session( b )
		IRB.setup(nil)

		workspace = IRB::WorkSpace.new( b )

		if IRB.conf[:SCRIPT]
			irb = IRB::Irb.new( workspace, IRB.conf[:SCRIPT] )
		else
			irb = IRB::Irb.new( workspace )
		end

		IRB.conf[:IRB_RC].call( irb.context ) if IRB.conf[:IRB_RC]
		IRB.conf[:MAIN_CONTEXT] = irb.context

		trap("SIGINT") do
			irb.signal_handle
		end

		catch(:IRB_EXIT) do
			irb.eval_input
		end
	end

	### Download the file at +sourceuri+ via HTTP and write it to +targetfile+.
	def download( sourceuri, targetfile=nil )
		oldsync = $defout.sync
		$defout.sync = true
		require 'net/http'
		require 'uri'

		targetpath = Pathname.new( targetfile )

		log "Downloading %s to %s" % [sourceuri, targetfile]
		targetpath.open( File::WRONLY|File::TRUNC|File::CREAT, 0644 ) do |ofh|

			url = sourceuri.is_a?( URI ) ? sourceuri : URI.parse( sourceuri )
			downloaded = false
			limit = 5

			until downloaded or limit.zero?
				Net::HTTP.start( url.host, url.port ) do |http|
					req = Net::HTTP::Get.new( url.path )

					http.request( req ) do |res|
						if res.is_a?( Net::HTTPSuccess )
							log "Downloading..."
							res.read_body do |buf|
								ofh.print( buf )
							end
							downloaded = true
							puts "done."

						elsif res.is_a?( Net::HTTPRedirection )
							url = URI.parse( res['location'] )
							log "...following redirection to: %s" % [ url ]
							limit -= 1
							sleep 0.2
							next

						else
							res.error!
						end
					end
				end
			end

		end

		return targetpath
	ensure
		$defout.sync = oldsync
	end

end # module UtilityFunctions

if __FILE__ == $0
	# $DEBUG = true
	include UtilityFunctions

	projname = extract_project_name()
	header "Project: #{projname}"

	ver = extract_version() || [0,0,1]
	puts "Version: %s\n" % ver.join('.')

	if File::directory?( "docs" )
		puts "Rdoc:",
			"  Title: " + find_rdoc_title(),
			"  Main: " + find_rdoc_main(),
			"  Upload: " + find_rdoc_upload(),
			"  VCS URL: " + find_rdoc_cvs_url(),
			"  Accessors: " + find_rdoc_accessors().join(",")
	end

	puts "Manifest:",
		"  " + get_vetted_manifest().join("\n  ")
end


text:
#include "event.hpp"
#include <atomic>
#include <sys/event.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

#include "../time/time.hpp"

namespace EventStatic
{
	static std::atomic<intptr_t> highId_(0);
}

sprawl::threading::Event::Event()
	: m_event(EventStatic::highId_++)
	, m_kqueue(kqueue())
{
	struct kevent event;
	EV_SET(&event, m_event, EVFILT_USER, EV_ADD|EV_CLEAR, NOTE_FFNOP, 0, nullptr);
	kevent(m_kqueue, &event, 1, nullptr, 0, nullptr);
}

sprawl::threading::Event::~Event()
{
	close(m_kqueue);
}

void sprawl::threading::Event::Notify()
{
	fflush(stdout);
	struct kevent event;
	EV_SET(&event, m_event, EVFILT_USER, EV_ADD|EV_CLEAR, NOTE_TRIGGER, 0, nullptr);
	kevent(m_kqueue, &event, 1, nullptr, 0, nullptr);
}

void sprawl::threading::Event::Wait()
{
	fflush(stdout);
	struct kevent event;
	kevent(m_kqueue, nullptr, 0, &event, 1,  nullptr);
}

bool sprawl::threading::Event::WaitFor(int64_t nanoseconds)
{
	if(nanoseconds < 0)
	{
		return false;
	}

	struct timespec ts;
	int64_t sec = sprawl::time::Convert(nanoseconds, sprawl::time::Resolution::Nanoseconds, sprawl::time::Resolution::Seconds);
	int64_t nsec = nanoseconds - sprawl::time::Convert(sec, sprawl::time::Resolution::Seconds, sprawl::time::Resolution::Nanoseconds);

	ts.tv_sec = time_t(sec);
	ts.tv_nsec = long(nsec);

	struct kevent event;
	return (kevent(m_kqueue, nullptr, 0, &event, 1,  &ts) != 0);
}

/*static*/ sprawl::threading::Event* sprawl::threading::Event::WaitMultiple(EventGroup& values)
{
	int multiKqueue = kqueue();

	struct kevent events[256];

	for(ssize_t i = 0; i < values.Size(); ++i)
	{
		Event* event = values[i];
		EV_SET(&events[i], event->m_kqueue, EVFILT_READ, EV_ADD, 0, 0, event);
	}
	kevent(multiKqueue, events, values.Size(), nullptr, 0, nullptr);
	int nret = kevent(multiKqueue, nullptr, 0, events, 256, nullptr);

	for(int i = 0; i < nret; ++i)
	{
		//Clear the signaled state.
		((Event*)(events[i].udata))->Wait();
	}

	Event* ret = (Event*)(events[0].udata);

	close(multiKqueue);

	return ret;
}

/*static*/ sprawl::threading::Event* sprawl::threading::Event::WaitMultipleFor(EventGroup& values, int64_t nanoseconds)
{
	if(nanoseconds < 0)
	{
		return nullptr;
	}

	struct timespec ts;
	int64_t sec = sprawl::time::Convert(nanoseconds, sprawl::time::Resolution::Nanoseconds, sprawl::time::Resolution::Seconds);
	int64_t nsec = nanoseconds - sprawl::time::Convert(sec, sprawl::time::Resolution::Seconds, sprawl::time::Resolution::Nanoseconds);

	ts.tv_sec = time_t(sec);
	ts.tv_nsec = long(nsec);

	int multiKqueue = kqueue();

	struct kevent events[256];

	for(ssize_t i = 0; i < values.Size(); ++i)
	{
		Event* event = values[i];
		EV_SET(&events[i], event->m_kqueue, EVFILT_READ, EV_ADD, 0, 0, event);
	}
	kevent(multiKqueue, events, values.Size(), nullptr, 0, nullptr);
	int nret = kevent(multiKqueue, nullptr, 0, events, 256, &ts);

	for(int i = 0; i < nret; ++i)
	{
		//Clear the signaled state.
		((Event*)(events[i].udata))->Wait();
	}

	Event* ret = nullptr;
	if(nret != 0)
	{
		ret = (Event*)(events[0].udata);
	}

	close(multiKqueue);

	return ret;
}

redpajama_set_name: RedPajamaGithub


text:
var searchData=
[
  ['delete',['Delete',['../classBinarySearchTree.html#a1b7b6c893bd995f99522866a3cee1f04',1,'BinarySearchTree']]],
  ['deletenode_5fleftchild',['DeleteNode_LeftChild',['../classBinarySearchTree.html#ab2d065748a4990ee768f939776cac043',1,'BinarySearchTree']]],
  ['deletenode_5fnochildren',['DeleteNode_NoChildren',['../classBinarySearchTree.html#aeca425d5b9555c92c3d1e58914345321',1,'BinarySearchTree']]],
  ['deletenode_5frightchild',['DeleteNode_RightChild',['../classBinarySearchTree.html#a3ac3177bfb4666659e24d34afaac5626',1,'BinarySearchTree']]],
  ['deletenode_5ftwochildren',['DeleteNode_TwoChildren',['../classBinarySearchTree.html#a96792fe9445a417e3cbd04226a182f40',1,'BinarySearchTree']]],
  ['display',['Display',['../classLinkedList.html#a4c7b93cad0f1e752fe06db3905e60e3f',1,'LinkedList']]]
];


text:
using System.Collections.Generic;
using System.Linq;
using JetBrains.Annotations;
using Orchard.ContentManagement;
using Orchard.ContentManagement.Drivers;
using Orchard.Localization.Models;
using Orchard.Localization.Services;
using Orchard.Localization.ViewModels;

namespace Orchard.Localization.Drivers {
    [UsedImplicitly]
    public class LocalizationPartDriver : ContentPartDriver<LocalizationPart> {
        private const string TemplatePrefix = "Localization";
        private readonly ICultureManager _cultureManager;
        private readonly ILocalizationService _localizationService;
        private readonly IContentManager _contentManager;

        public LocalizationPartDriver(ICultureManager cultureManager, ILocalizationService localizationService, IContentManager contentManager) {
            _cultureManager = cultureManager;
            _localizationService = localizationService;
            _contentManager = contentManager;
        }

        protected override DriverResult Display(LocalizationPart part, string displayType, dynamic shapeHelper) {
            var masterId = part.MasterContentItem != null
                               ? part.MasterContentItem.Id
                               : part.Id;
            return Combined(
                ContentShape("Parts_Localization_ContentTranslations",
                             () => shapeHelper.Parts_Localization_ContentTranslations(MasterId: masterId, Localizations: GetDisplayLocalizations(part, VersionOptions.Published))),
                ContentShape("Parts_Localization_ContentTranslations_Summary",
                             () => shapeHelper.Parts_Localization_ContentTranslations_Summary(MasterId: masterId, Localizations: GetDisplayLocalizations(part, VersionOptions.Published))),
                ContentShape("Parts_Localization_ContentTranslations_SummaryAdmin",
                             () => shapeHelper.Parts_Localization_ContentTranslations_SummaryAdmin(MasterId: masterId, Localizations: GetDisplayLocalizations(part, VersionOptions.Latest)))
                );
        }

        protected override DriverResult Editor(LocalizationPart part, dynamic shapeHelper) {
            var localizations = GetEditorLocalizations(part).ToList();
            var model = new EditLocalizationViewModel {
                SelectedCulture = part.Culture != null ? part.Culture.Culture : null,
                SiteCultures = _cultureManager.ListCultures().Where(s => s != _cultureManager.GetSiteCulture() && !localizations.Select(l => l.Culture.Culture).Contains(s)),
                ContentItem = part,
                MasterContentItem = part.MasterContentItem,
                ContentLocalizations = new ContentLocalizationsViewModel(part) { Localizations = localizations }
            };

            return ContentShape("Parts_Localization_ContentTranslations_Edit",
                () => shapeHelper.EditorTemplate(TemplateName: "Parts/Localization.ContentTranslations.Edit", Model: model, Prefix: TemplatePrefix));
        }

        protected override DriverResult Editor(LocalizationPart part, IUpdateModel updater, dynamic shapeHelper) {
            var model = new EditLocalizationViewModel();
            if (updater != null && updater.TryUpdateModel(model, TemplatePrefix, null, null)) {
                _localizationService.SetContentCulture(part, model.SelectedCulture);
            }

            return Editor(part, shapeHelper);
        }

        private IEnumerable<LocalizationPart> GetDisplayLocalizations(LocalizationPart part, VersionOptions versionOptions) {
            return _localizationService.GetLocalizations(part.ContentItem, versionOptions)
                .Select(c => {
                            var localized = c.ContentItem.As<LocalizationPart>();
                            if (localized.Culture == null)
                                localized.Culture = _cultureManager.GetCultureByName(_cultureManager.GetSiteCulture());
                            return c;
                        }).ToList();
        }

        private IEnumerable<LocalizationPart> GetEditorLocalizations(LocalizationPart part) {
            return _localizationService.GetLocalizations(part.ContentItem, VersionOptions.Latest)
                .Select(c => {
                    var localized = c.ContentItem.As<LocalizationPart>();
                    if (localized.Culture == null)
                        localized.Culture = _cultureManager.GetCultureByName(_cultureManager.GetSiteCulture());
                    return c;
                }).ToList();
        }

        protected override void Importing(LocalizationPart part, ContentManagement.Handlers.ImportContentContext context) {
            var masterContentItem = context.Attribute(part.PartDefinition.Name, "MasterContentItem");
            if (masterContentItem != null) {
                var contentItem = context.GetItemFromSession(masterContentItem);
                if (contentItem != null) {
                    part.MasterContentItem = contentItem;
                }
            }

            var culture = context.Attribute(part.PartDefinition.Name, "Culture");
            if (culture != null) {
                var targetCulture = _cultureManager.GetCultureByName(culture);
                // Add Culture.
                if (targetCulture == null && _cultureManager.IsValidCulture(culture)) {
                    _cultureManager.AddCulture(culture);
                    targetCulture = _cultureManager.GetCultureByName(culture);
                }
                part.Culture = targetCulture;
            }
        }

        protected override void Exporting(LocalizationPart part, ContentManagement.Handlers.ExportContentContext context) {
            if (part.MasterContentItem != null) {
                var masterContentItemIdentity = _contentManager.GetItemMetadata(part.MasterContentItem).Identity;
                context.Element(part.PartDefinition.Name).SetAttributeValue("MasterContentItem", masterContentItemIdentity.ToString());
            }

            if (part.Culture != null) {
                context.Element(part.PartDefinition.Name).SetAttributeValue("Culture", part.Culture.Culture);
            }
        }
    }
}


text:
class ImageToBase64Adapter : public QObject
{
    Q_OBJECT
    Q_PROPERTY(QVariant pixmap READ pixmap WRITE setPixmap NOTIFY pixmapChanged)
    Q_PROPERTY(QString base64Image READ base64Image NOTIFY base64ImageChanged)

public:
    explicit ImageToBase64Adapter(QObject *parent = 0);

    QVariant pixmap() const;
    void setPixmap(QVariant pixmap);

    QString base64Image() const;

signals:
    void pixmapChanged();
    void base64ImageChanged();

private:
    QPixmap m_pixmap;
    QString m_base64Image;
};

#endif // IMAGETOBASE64ADAPTER_H


text:
var app = angular.module('sniprApp');

app.provider('snippets', function() {
    var firebaseUrl = '';
    this.setUrl = function (url) {
        firebaseUrl = url;
    }

    this.$get = ['$firebase', function ($firebase) {
        return $firebase(new Firebase([firebaseUrl, 'snippets'].join('/')));
    }];
});


text:
<?php  namespace Lio\ServiceProviders;

use Illuminate\Support\ServiceProvider;

class ArticleServiceProvider extends ServiceProvider
{
    public function register()
    {
        $this->app->bind('Lio\Articles\Repositories\ArticleRepository', 'Lio\Articles\Repositories\EloquentArticleRepository');
        $this->app->bind('Lio\Articles\Repositories\CommentRepository', 'Lio\Articles\Repositories\EloquentCommentRepository');
    }

    public function provides()
    {
        return [
            'Lio\Articles\Repositories\ArticleRepository',
            'Lio\Articles\Repositories\CommentRepository'
        ];
    }
}


text:
package org.locationtech.geowave.cli.osm.osmfeature.types.attributes;

public interface AttributeType<T> {
  public T convert(Object source);

  public Class getClassType();
}


text:
description: Dans ce TP nous allons découvrir le framework CSS Bootstrap.
---

# Découverte de Bootstrap

Dans ce TP nous allons découvrir le framework CSS Bootstrap.

[Bootstrap](https://getbootstrap.com/)

## Introduction

Bootstrap est un Framework massivement utilisé dans le monde des développeurs Web. Il date maintenant de quelques années, mais celui-ci est mis à jour régulièrement ce qui lui permet d'être toujours à jour et toujours très intéressant. Les créateurs de Bootstrap sont Twitter vous ne serez donc pas vraiment surpris si celui-ci ressemble « sous certains aspects » à l'interface du site Twitter.com.

Bootstrap et très vaste, et très bien documenté le TP n'a pas pour but de vous apprendre « à utiliser Bootstrap », mais plutôt vous faire découvrir celui-ci pour que vous l'utilisiez aussi souvent que possible.

## Création de votre fichier HTML

La première étape est toujours la même. Je vous laisse créer un nouveau fichier HTML avec une structure basique (comprendre HTML 5). :hand: n'oubliez pas d'y mettre la meta permettant de faire du responsive.

::: tip Astuce du chef

Je vous le rappelle votre IDE à une fonctionnalité appelée « EMMET », vous avez donc des raccourcis à votre disposition permettant de gagner pas mal de temps.

![emmet](./res/emmet.png)

:::

## Ajout de Bootstrap

Pour ajouter Bootstrap le plus simple est de **suivre la documentation officielle**. Celle-ci est disponible sur [le site de Bootstrap dans la partie Get Started](https://getbootstrap.com/docs/4.5/getting-started/introduction/#quick-start)

Vous pouvez également remplacer votre fichier HTML vide par [le starter template proposé par Bootstrap](https://getbootstrap.com/docs/4.5/getting-started/introduction/#starter-template)

Je vous laisse valider que votre site fonctionne correctement.

:hand: Vérifier bien qu'il n'y a pas d'erreur réseau lors du chargement de la page (avec l'inspecteur d'élément).

Questions :

- Pourquoi suivre la documentation officielle est très important ?
- Dans le code que vous avez copié. Pouvez-vous me dire à quoi correspond le paramètre `integrity=` ?

## Création d'une « structure » / « Layout »

Maintenant que nous avons une page vide disposant de Bootstrap, je vous propose de créer votre première page Bootstrap. Dans Bootstrap nous avons à notre disposition des « Templates » ou plutôt des « layouts » tout prêt nous permettant de partir d'une base de code déjà faite.

C'est templates [sont disponibles dans le menu de la documentation](https://getbootstrap.com/docs/4.5/examples/).

::: tip Pourquoi ? Quand ?
« Copier ≠ ne pas travailler » nous en avons parlé, mais c'est toujours un rappel important. Dans notre cas, Bootstrap nous propose des templates / gabarit déjà faits. Ils sont là pour :

- Vous faire gagner du temps.
- Améliorer la qualité de vos sites Internet.
- Vous montrer comment intégrer les éléments de Boostrap.

N'hésitez pas à vous en servir dans vos développements. Ils sont [disponible ici](https://getbootstrap.com/docs/4.5/examples)
:::

Faite votre choix, une fois que vous avez choisis regarder le code par exemple avec [du starter Template](https://getbootstrap.com/docs/4.5/examples/starter-template/)

## Mise en place d'une NavBar

La NavBar est un composant très important. Il nous permet de mettre en place une navigation entre nos pages. On la retrouve un peu partout dans le monde du développement, avec Bootstrap nous avons un composant tout prêt pour gérer cette problématique.

Voilà un exemple de NavBar :

```html
<nav class="navbar navbar-expand-md navbar-dark bg-dark fixed-top">
  <a class="navbar-brand" href="#">Navbar</a>
  <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarsExampleDefault" aria-controls="navbarsExampleDefault" aria-expanded="false" aria-label="Toggle navigation">
    <span class="navbar-toggler-icon"></span>
  </button>

  <div class="collapse navbar-collapse" id="navbarsExampleDefault">
    <ul class="navbar-nav mr-auto">
      <li class="nav-item active">
        <a class="nav-link" href="#">Home <span class="sr-only">(current)</span></a>
      </li>
      <li class="nav-item active">
        <a class="nav-link" href="#">Contact</a>
      </li>
  </div>
</nav>
```

La documentation de la NavBar est disponible sur le site. [Je vous laisse la consulter pour plus de détail](https://getbootstrap.com/docs/4.5/components/navbar/)

### À faire

- Mettre en place une navbar sur votre site.

## Mise en place d'une Card

Un autre incontournable dans le développement est l'affichage de « Card » afin de structurer le contenu. Cette approche en Card a été introduite principalement par Google dans la plateforme Android. Mais c'est maintenant un basique dans le développement :

![Card Bootstrap](./res/card.png)

### À faire

- En vous inspirant [du code fourni sur la page](https://getbootstrap.com/docs/4.5/components/card/), mettre en place sur votre page une Card.

## Le responsive

Nous avons vu ensemble que Bootstrap était un framework permettant de gérer le responsive. En utilisant le système [de grid](https://getbootstrap.com/docs/4.5/layout/grid/) nous allons mettre sur notre site une grille de **3 colonnes**.

Nous allons bien évidemment le faire ensemble.

## Mise en place d'un formulaire

L'autre gros avantage de Bootstrap c'est l'aspect « propre » des formulaires. De bases sans que vous n'ayez aucune CSS vos formulaires seront « propre », pour ça rien de spécial à faire il suffit d'utiliser le code d'exemple fourni sur la documentation :

[Exemple ici](https://getbootstrap.com/docs/4.5/components/forms/#form-row)

::: tip Petite remarque

Comme vous avez pu le constater dans l'exemple précédent. La documentation de Bootstrap nous propose de mélanger les form et les grid. Et c'est bien normal, chaque composant est utilisable avec l'ensemble des possibilités des Bootstrap.

:::

### À faire

- En utilisant le code fourni sur le site de Bootstrap. Mettre en place **dans la card** précédemment créée un formulaire de contact.

## Les utilities de Bootstrap

Bootstrap nous propose également des « Utilities », les utilities sont des petites aides CSS, nous permettant de gagner du temps sur des taches récurrentes de mise en forme :

- Exemple [les bordures](https://getbootstrap.com/docs/4.5/utilities/borders/)
- Ou encore [les ombres](https://getbootstrap.com/docs/4.5/utilities/shadows/)
- Ou simplement [les alignements de textes](https://getbootstrap.com/docs/4.5/utilities/text/)

::: tip Je vous vois là !

Pourquoi avoir appris les bases de la CSS ?! C'est si simple en copiant les class de Bootstrap ! Alors, oui c'est simple, mais :

1. Vous avez maintenant les bases pour comprendre.
2. Vous êtes capable de les améliorer, surchargé, personnalisé.

:::

### À faire

- En utilisant les utilities, personnalisez votre page.

## Créer une seconde page dans votre site

Je vous laisse faire cette étape. Quelques règles à respecter cependant :

- Ajouter les liens dans la « NavBar ».
- Avoir une page « home » (nommée `index.html`).

### Ajout du texte

Je vous laisse ajouter un texte sur cette page. Attention à bien utiliser :

- Les class.
- Les balises titre.
- Les balises paragraphe pour le contenu.

### Ajout d'un tableau

Les tableaux, gros sujet les tableaux non ?! Bootstrap va vous simplifier GRANDEMENT la création et surtout le style des tableaux. Rendez-vous sur [la page Tables](https://getbootstrap.com/docs/4.5/content/tables/)

![Les tableaux](./res/tables.png)

Le principe repose sur un ensemble de class. Ça passe du tableau « thème sombre » à « l'alignement ». Bref un vrai gain de temps.

### À faire

- Dans une nouvelle page, mettre en place un tableau et le personnaliser avec les classes de Bootstrap (couleurs, apparence, etc).

## Votre page d'accueil

Votre page d'accueil est très certainement « minimaliste », je vous propose de la rendre plus moderne (c'est très relatif comme notion). Pour ça nous allons utiliser une Cover appelée « Hero »

### Mise en place d'une cover « Hero »

En vous inspirant du code de la page suivante : [https://getbootstrap.com/docs/4.5/examples/cover/](https://getbootstrap.com/docs/4.5/examples/cover/) remplacer la home de votre page par une « Cover ».

::: tip Pas d'idée pour l'image ?

Le plus simple c'est d'aller sur [picsum.photos](https://picsum.photos/), ce site propose des images « d'illustration » utilisable dans vos projets sans problème de droit.

Autre solution [Unsplash](https://unsplash.com/), ce site propose des images _libre de droits_ utilisable dans vos projets.

:::

### Experimenter !

Le but de ce TP est l'expérimentation. N'hésitez pas à modifier, personnaliser, tester des idées. Donc, un fond de type « image », une toolbar avec une marge ou de couleur; rien ne sera assez fou !


text:
#include "config.h"

#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <time.h>
#include <string.h>
#include <ctype.h>

#ifdef HAVE_STDINT_H
#include <stdint.h>
#endif

#include "rbtree.h"
#include "nfdump.h"
#include "nffile.h"
#include "nfx.h"
#include "bookkeeper.h"
#include "nfxstat.h"
#include "collector.h"
#include "exporter.h"
#include "nfnet.h"
#include "netflow_v5_v7.h"
#include "nf_common.h"
#include "util.h"
#include "nflowcache.h"
#include "nfstat.h"

extern int hash_hit;
extern int hash_miss;
extern int hash_skip;
extern extension_map_list_t extension_map_list;

struct flow_element_s {
	uint32_t	offset0;
	uint32_t	offset1;	// set in the netflow record block
	uint64_t	mask;		// mask for value in 64bit word
	uint32_t	shift;		// number of bits to shift right to get final value
};

enum { IS_NUMBER = 1, IS_IPADDR, IS_MACADDR, IS_MPLS_LBL, IS_LATENCY};

struct StatParameter_s {
	char					*statname;		// name of -s option
	char					*HeaderInfo;	// How to name the field in the output header line
	struct flow_element_s	element[2];		// what element(s) in flow record is used for statistics.
											// need 2 elements to be able to get src/dst stats in one stat record
	uint8_t					num_elem;		// number of elements used. 1 or 2
	uint8_t					type;			// Type of element: Number, IP address, MAC address etc.
} StatParameters[] ={
	// flow record stat
	{ "record",	 "",
		{ {0,0, 0,0},										{0,0,0,0} },
			1, 0},

	// 9 possible flow element stats
	{ "srcip",	 "Src IP Addr",
		{ {OffsetSrcIPv6a, OffsetSrcIPv6b, MaskIPv6, 0},	{0,0,0,0} },
			1, IS_IPADDR },

	{ "dstip",	 "Dst IP Addr",
		{ {OffsetDstIPv6a, OffsetDstIPv6b, MaskIPv6, 0},	{0,0,0,0} },
			1, IS_IPADDR },

	{ "ip",	 	"IP Addr",
		{ {OffsetSrcIPv6a, OffsetSrcIPv6b, MaskIPv6, 0},	{OffsetDstIPv6a, OffsetDstIPv6b, MaskIPv6} },
			2, IS_IPADDR },

	{ "nhip",	 "Nexthop IP",
		{ {OffsetNexthopv6a, OffsetNexthopv6b, MaskIPv6, 0},	{0,0,0,0} },
			1, IS_IPADDR },

	{ "nhbip",	 "Nexthop BGP IP",
		{ {OffsetBGPNexthopv6a, OffsetBGPNexthopv6b, MaskIPv6, 0},	{0,0,0,0} },
			1, IS_IPADDR },

	{ "router",	 "Router IP",
		{ {OffsetRouterv6a, OffsetRouterv6b, MaskIPv6, 0},	{0,0,0,0} },
			1, IS_IPADDR },

	{ "srcport", "Src Port",
		{ {0, OffsetPort, MaskSrcPort, ShiftSrcPort}, 		{0,0,0,0} },
			1, IS_NUMBER },

	{ "dstport", "Dst Port",
		{ {0, OffsetPort, MaskDstPort, ShiftDstPort}, 		{0,0,0,0} },
			1, IS_NUMBER },

	{ "port", 	 "Port",
		{ {0, OffsetPort, MaskSrcPort, ShiftSrcPort}, 		{0, OffsetPort, MaskDstPort, ShiftDstPort}},
			2, IS_NUMBER },

	{ "proto", 	 "Protocol",
		{ {0, OffsetProto, MaskProto, ShiftProto}, 			{0,0,0,0} },
			1, IS_NUMBER },

	{ "tos", 	 "Tos",
		{ {0, OffsetTos, MaskTos, ShiftTos}, 				{0,0,0,0} },
			1, IS_NUMBER },

	{ "srctos",  "Tos",
		{ {0, OffsetTos, MaskTos, ShiftTos}, 				{0,0,0,0} },
			1, IS_NUMBER },

	{ "dsttos",	 "Dst Tos",
		{ {0, OffsetDstTos, MaskDstTos, ShiftDstTos},  		{0,0,0,0} },
			1, IS_NUMBER },

	{ "dir",	 "Dir",
		{ {0, OffsetDir, MaskDir, ShiftDir},		  		{0,0,0,0} },
			1, IS_NUMBER },

	{ "srcas",	 "Src AS",
		{ {0, OffsetAS, MaskSrcAS, ShiftSrcAS},		  		{0,0,0,0} },
			1, IS_NUMBER },

	{ "dstas",	 "Dst AS",
		{ {0, OffsetAS, MaskDstAS, ShiftDstAS},  	  		{0,0,0,0} },
			1, IS_NUMBER },

	{ "prevas",	 "Prev AS",
		{ {0, OffsetBGPadj, MaskBGPadjPrev, ShiftBGPadjPrev},		  		{0,0,0,0} },
			1, IS_NUMBER },

	{ "nextas",	 "Next AS",
		{ {0, OffsetBGPadj, MaskBGPadjNext, ShiftBGPadjNext},  	  		{0,0,0,0} },
			1, IS_NUMBER },

	{ "as",	 	 "AS",
		{ {0, OffsetAS, MaskSrcAS, ShiftSrcAS},  	  		{0, OffsetAS, MaskDstAS, ShiftDstAS} },
			2, IS_NUMBER },

	{ "inif", 	 "Input If",
		{ {0, OffsetInOut, MaskInput, ShiftInput}, 			{0,0,0,0} },
			1, IS_NUMBER },

	{ "outif", 	 "Output If",
		{ {0, OffsetInOut, MaskOutput, ShiftOutput},		{0,0,0,0} },
			1, IS_NUMBER },

	{ "if", 	 "In/Out If",
		{ {0, OffsetInOut, MaskInput, ShiftInput},			{0, OffsetInOut, MaskOutput, ShiftOutput} },
			2, IS_NUMBER },

	{ "srcmask",	 "Src Mask",
		{ {0, OffsetMask, MaskSrcMask, ShiftSrcMask},  		{0,0,0,0} },
			1, IS_NUMBER },

	{ "dstmask",	 "Dst Mask",
		{ {0, OffsetMask, MaskDstMask, ShiftDstMask},  		{0,0,0,0} },
			1, IS_NUMBER },

	{ "mask",	 "Mask",
		{ {0, OffsetMask, MaskSrcMask, ShiftSrcMask},  		{0, OffsetMask, MaskDstMask, ShiftDstMask} },
			2, IS_NUMBER },

	{ "srcvlan",	 "Src Vlan",
		{ {0, OffsetVlan, MaskSrcVlan, ShiftSrcVlan},  		{0,0,0,0} },
			1, IS_NUMBER },

	{ "dstvlan",	 "Dst Vlan",
		{ {0, OffsetVlan, MaskDstVlan, ShiftDstVlan},  		{0,0,0,0} },
			1, IS_NUMBER },

	{ "vlan",	 "Vlan",
		{ {0, OffsetVlan, MaskSrcVlan, ShiftSrcVlan},  		{0, OffsetVlan, MaskDstVlan, ShiftDstVlan} },
			2, IS_NUMBER },

	{ "insrcmac",	 "In Src Mac",
		{ {0, OffsetInSrcMAC, MaskMac, 0},  		{0,0,0,0} },
			1, IS_MACADDR },

	{ "outdstmac",	 "Out Dst Mac",
		{ {0, OffsetOutDstMAC, MaskMac, 0},  		{0,0,0,0} },
			1, IS_MACADDR },

	{ "indstmac",	 "In Dst Mac",
		{ {0, OffsetInDstMAC, MaskMac, 0},  		{0,0,0,0} },
			1, IS_MACADDR },

	{ "outsrcmac",	 "Out Src Mac",
		{ {0, OffsetOutSrcMAC, MaskMac, 0},  		{0,0,0,0} },
			1, IS_MACADDR },

	{ "srcmac",	 "Src Mac",
		{ {0, OffsetInSrcMAC, MaskMac, 0},  		{0, OffsetOutSrcMAC, MaskMac, 0}},
			2, IS_MACADDR },

	{ "dstmac",	 "Dst Mac",
		{ {0, OffsetOutDstMAC, MaskMac, 0},  		{0, OffsetInDstMAC, MaskMac, 0} },
			2, IS_MACADDR },

	{ "inmac",	 "In Src Mac",
		{ {0, OffsetInSrcMAC, MaskMac, 0},  		{0, OffsetInDstMAC, MaskMac, 0} },
			1, IS_MACADDR },

	{ "outmac",	 "Out Src Mac",
		{ {0, OffsetOutSrcMAC, MaskMac, 0},  		{0, OffsetOutDstMAC, MaskMac, 0} },
			2, IS_MACADDR },

	{ "mpls1",	 " MPLS lab 1",
		{ {0, OffsetMPLS12, MaskMPLSlabelOdd, 0}, 	{0,0,0,0} },
			1, IS_MPLS_LBL },

	{ "mpls2",	 " MPLS lab 2",
		{ {0, OffsetMPLS12, MaskMPLSlabelEven, 0}, 	{0,0,0,0} },
			1, IS_MPLS_LBL },

	{ "mpls3",	 " MPLS lab 3",
		{ {0, OffsetMPLS34, MaskMPLSlabelOdd, 0}, 	{0,0,0,0} },
			1, IS_MPLS_LBL },

	{ "mpls4",	 " MPLS lab 4",
		{ {0, OffsetMPLS34, MaskMPLSlabelEven, 0}, 	{0,0,0,0} },
			1, IS_MPLS_LBL },

	{ "mpls5",	 " MPLS lab 5",
		{ {0, OffsetMPLS56, MaskMPLSlabelOdd, 0}, 	{0,0,0,0} },
			1, IS_MPLS_LBL },

	{ "mpls6",	 " MPLS lab 6",
		{ {0, OffsetMPLS56, MaskMPLSlabelEven, 0}, 	{0,0,0,0} },
			1, IS_MPLS_LBL },

	{ "mpls7",	 " MPLS lab 7",
		{ {0, OffsetMPLS78, MaskMPLSlabelOdd, 0}, 	{0,0,0,0} },
			1, IS_MPLS_LBL },

	{ "mpls8",	 " MPLS lab 8",
		{ {0, OffsetMPLS78, MaskMPLSlabelEven, 0}, 	{0,0,0,0} },
			1, IS_MPLS_LBL },

	{ "mpls9",	 " MPLS lab 9",
		{ {0, OffsetMPLS910, MaskMPLSlabelOdd, 0}, 	{0,0,0,0} },
			1, IS_MPLS_LBL },

	{ "mpls10",	 "MPLS lab 10",
		{ {0, OffsetMPLS910, MaskMPLSlabelEven, 0}, {0,0,0,0} },
			1, IS_MPLS_LBL },

	{ "cl",	 "Client Latency",
		{ {0, OffsetClientLatency, MaskLatency, 0}, {0,0,0,0} },
			1, IS_LATENCY },

	{ "sl",	 "Server Latency",
		{ {0, OffsetServerLatency, MaskLatency, 0}, {0,0,0,0} },
			1, IS_LATENCY },

	{ "al",	 "  Appl Latency",
		{ {0, OffsetAppLatency, MaskLatency, 0}, {0,0,0,0} },
			1, IS_LATENCY },

	{ NULL, 	 NULL,
		{ {0,0,0,0},	{0,0,0,0} },
			1, 0 }
};

static const uint32_t NumOrders = 6;	// Number of Stats in enum StatTypes

enum CntIndices { FLOWS = 0, INPACKETS, INBYTES, OUTPACKETS, OUTBYTES };

#define MaxStats 16
struct StatRequest_s {
	uint16_t	order_bits;		// bits 0: flows 1: packets 2: bytes 3: pps 4: bps, 5 bpp
	int16_t		StatType;		// value out of enum StatTypes
	uint8_t		order_proto;	// protocol separated statistics
} StatRequest[MaxStats];		// This number should do it for a single run

/*
 * pps, bps and bpp are not directly available in the flow/stat record
 * therefore we need a function to calculate these values
 */
typedef uint64_t (*order_proc_record_t)(FlowTableRecord_t *);
typedef uint64_t (*order_proc_element_t)(StatRecord_t *);

/* order functions */
static inline uint64_t	pps_record(FlowTableRecord_t *record);
static inline uint64_t	bps_record(FlowTableRecord_t *record);
static inline uint64_t	bpp_record(FlowTableRecord_t *record);
static inline uint64_t	tstart_record(FlowTableRecord_t *record);
static inline uint64_t	tend_record(FlowTableRecord_t *record);

static inline uint64_t	pps_element(StatRecord_t *record);
static inline uint64_t	bps_element(StatRecord_t *record);
static inline uint64_t	bpp_element(StatRecord_t *record);

#define ASCENDING 1
#define DESCENDING 0
struct order_mode_s {
	char *string;	// Stat name
	int	 val;		// order bit set results in this value
	int	 direction;	// ascending or descending
	order_proc_record_t  record_function;	// Function to call for record stats
	order_proc_element_t element_function;	// Function to call for element stats
} order_mode[] = {
	{ "flows",    1, DESCENDING, NULL, NULL},	// index 0 needs to correspond with counter array in FlowTableRecord_t
	{ "packets",  2, DESCENDING, NULL, NULL},	// index 1 needs to correspond with counter array in FlowTableRecord_t
	{ "bytes",    4, DESCENDING, NULL, NULL},	// index 2 needs to correspond with counter array in FlowTableRecord_t
	{ "pps", 	  8, DESCENDING, pps_record, pps_element},
	{ "bps", 	 16, DESCENDING, bps_record, bps_element},
	{ "bpp", 	 32, DESCENDING, bpp_record, bpp_element},
	{ "tstart",  64, ASCENDING,  tstart_record, NULL},
	{ "tend",   128, ASCENDING,  tend_record, NULL},
	{ NULL,       0, 0, NULL}
};
#define Default_PrintOrder 1		// order_mode[0].val
static uint32_t	print_order_bits = 0;
static uint32_t	PrintOrder 		 = 0;
static uint32_t	NumStats 		 = 0;

static uint64_t	byte_limit, packet_limit;
static int byte_mode, packet_mode;
enum { NONE = 0, LESS, MORE };

/* function prototypes */
static int ParseStatString(char *str, int16_t	*StatType, int *flow_record_stat, uint16_t *order_proto);

static inline StatRecord_t *stat_hash_lookup(uint64_t *value, uint8_t prot, int hash_num);

static inline StatRecord_t *stat_hash_insert(uint64_t *value, uint8_t prot, int hash_num);

static void Expand_StatTable_Blocks(int hash_num);

inline void PrintSortedFlowcache(SortElement_t *SortList, uint32_t maxindex, int limit_count, int GuessFlowDirection,
	printer_t print_record, int tag, int ascending );

static void PrintStatLine(stat_record_t	*stat, StatRecord_t *StatData, int type, int order_proto, int tag);

static void PrintPipeStatLine(StatRecord_t *StatData, int type, int order_proto, int tag);

static void PrintCvsStatLine(stat_record_t	*stat, StatRecord_t *StatData, int type, int order_proto, int tag);

static inline int TimeMsec_CMP(time_t t1, uint16_t offset1, time_t t2, uint16_t offset2 );

static SortElement_t *StatTopN(int topN, uint32_t *count, int hash_num, int order );

static void SwapFlow(master_record_t *flow_record);

/* locals */
static hash_StatTable *StatTable;
static int initialised = 0;

/* Functions */

#include "nffile_inline.c"
#include "heapsort_inline.c"
#include "applybits_inline.c"

static uint64_t	pps_record(FlowTableRecord_t *record) {
uint64_t		duration;

	/* duration in msec */
	duration = 1000LL*(uint64_t)(record->flowrecord.last - record->flowrecord.first) + (uint64_t)record->flowrecord.msec_last - (uint64_t)record->flowrecord.msec_first;
	if ( duration == 0 )
		return 0;
	else
		return ( 1000LL * (uint64_t)record->counter[INPACKETS] ) / duration;

} // End of pps_record

static uint64_t	bps_record(FlowTableRecord_t *record) {
uint64_t		duration;

	duration = 1000LL*(uint64_t)(record->flowrecord.last - record->flowrecord.first) + (uint64_t)record->flowrecord.msec_last - (uint64_t)record->flowrecord.msec_first;
	if ( duration == 0 )
		return 0;
	else
		return ( 8000LL * (uint64_t)record->counter[INBYTES] ) / duration;	/* 8 bits per Octet - x 1000 for msec */

} // End of bps_record

static uint64_t	bpp_record(FlowTableRecord_t *record) {

	return record->counter[INPACKETS] ? record->counter[INBYTES] / record->counter[INPACKETS] : 0;

} // End of bpp_record

static uint64_t	tstart_record(FlowTableRecord_t *record) {

	return 1000LL * record->flowrecord.first + record->flowrecord.msec_first;

} // End of bpp_record

static uint64_t	tend_record(FlowTableRecord_t *record) {

	return 1000LL * record->flowrecord.last + record->flowrecord.msec_last;

} // End of bpp_record

static uint64_t	pps_element(StatRecord_t *record) {
uint64_t		duration;

	/* duration in msec */
	duration = 1000LL*(uint64_t)(record->last - record->first) + (uint64_t)record->msec_last - (uint64_t)record->msec_first;
	if ( duration == 0 )
		return 0;
	else
		return ( 1000LL * (uint64_t)record->counter[INPACKETS] ) / duration;

} // End of pps_element

static uint64_t	bps_element(StatRecord_t *record) {
uint64_t		duration;

	duration = 1000LL*(uint64_t)(record->last - record->first) + (uint64_t)record->msec_last - (uint64_t)record->msec_first;
	if ( duration == 0 )
		return 0;
	else
		return ( 8000LL * (uint64_t)record->counter[INBYTES] ) / duration;	/* 8 bits per Octet - x 1000 for msec */

} // End of bps_element

static uint64_t	bpp_element(StatRecord_t *record) {

	return record->counter[INPACKETS] ? record->counter[INBYTES] / record->counter[INPACKETS] : 0;

} // End of bpp_element

static inline int TimeMsec_CMP(time_t t1, uint16_t offset1, time_t t2, uint16_t offset2 ) {
    if ( t1 > t2 )
        return 1;
    if ( t2 > t1 )
        return 2;
    // else t1 == t2 - offset is now relevant
    if ( offset1 > offset2 )
        return 1;
    if ( offset2 > offset1 )
        return 2;
    else
        // both times are the same
        return 0;
} // End of TimeMsec_CMP

void SetLimits(int stat, char *packet_limit_string, char *byte_limit_string ) {
char 		*s, c;
uint32_t	len,scale;

	if ( ( stat == 0 ) && ( packet_limit_string || byte_limit_string )) {
		fprintf(stderr,"Options -l and -L do not make sense for plain packet dumps.\n");
		fprintf(stderr,"Use -l and -L together with -s -S or -a.\n");
		fprintf(stderr,"Use netflow filter syntax to limit the number of packets and bytes in netflow records.\n");
		exit(250);
	}
	packet_limit = byte_limit = 0;
	if ( packet_limit_string ) {
		switch ( packet_limit_string[0] ) {
			case '-':
				packet_mode = LESS;
				s = &packet_limit_string[1];
				break;
			case '+':
				packet_mode = MORE;
				s = &packet_limit_string[1];
				break;
			default:
				if ( !isdigit((int)packet_limit_string[0])) {
					fprintf(stderr,"Can't understand '%s'\n", packet_limit_string);
					exit(250);
				}
				packet_mode = MORE;
				s = packet_limit_string;
		}
		len = strlen(packet_limit_string);
		c = packet_limit_string[len-1];
		switch ( c ) {
			case 'B':
			case 'b':
				scale = 1;
				break;
			case 'K':
			case 'k':
				scale = 1000;
				break;
			case 'M':
			case 'm':
				scale = 1000 * 1000;
				break;
			case 'G':
			case 'g':
				scale = 1000 * 1000 * 1000;
				break;
			default:
				scale = 1;
				if ( isalpha((int)c) ) {
					fprintf(stderr,"Can't understand '%c' in '%s'\n", c, packet_limit_string);
					exit(250);
				}
		}
		packet_limit = (uint64_t)atol(s) * (uint64_t)scale;
	}

	if ( byte_limit_string ) {
		switch ( byte_limit_string[0] ) {
			case '-':
				byte_mode = LESS;
				s = &byte_limit_string[1];
				break;
			case '+':
				byte_mode = MORE;
				s = &byte_limit_string[1];
				break;
			default:
				if ( !isdigit((int)byte_limit_string[0])) {
					fprintf(stderr,"Can't understand '%s'\n", byte_limit_string);
					exit(250);
				}
				byte_mode = MORE;
				s = byte_limit_string;
		}
		len = strlen(byte_limit_string);
		c = byte_limit_string[len-1];
		switch ( c ) {
			case 'B':
			case 'b':
				scale = 1;
				break;
			case 'K':
			case 'k':
				scale = 1000;
				break;
			case 'M':
			case 'm':
				scale = 1000 * 1000;
				break;
			case 'G':
			case 'g':
				scale = 1000 * 1000 * 1000;
				break;
			default:
				if ( isalpha((int)c) ) {
					fprintf(stderr,"Can't understand '%c' in '%s'\n", c, byte_limit_string);
					exit(250);
				}
				scale = 1;
		}
		byte_limit = (uint64_t)atol(s) * (uint64_t)scale;
	}

	if ( byte_limit )
		printf("Byte limit: %c %llu bytes\n", byte_mode == LESS ? '<' : '>', (long long unsigned)byte_limit);

	if ( packet_limit )
		printf("Packet limit: %c %llu packets\n", packet_mode == LESS ? '<' : '>', (long long unsigned)packet_limit);

} // End of SetLimits

int Init_StatTable(uint16_t NumBits, uint32_t Prealloc) {
uint32_t maxindex;
int		 hash_num;

	if ( NumBits == 0 || NumBits > 31 ) {
		fprintf(stderr, "Numbits outside 1..31\n");
		exit(255);
	}

	maxindex = (1 << NumBits);

	StatTable = (hash_StatTable *)calloc(NumStats, sizeof(hash_StatTable));
	if ( !StatTable ) {
		fprintf(stderr, "malloc() error in %s line %d: %s\n", __FILE__, __LINE__, strerror(errno) );
		return 0;
	}

	for ( hash_num=0; hash_num<NumStats; hash_num++ ) {
		StatTable[hash_num].IndexMask   = maxindex -1;
		StatTable[hash_num].NumBits     = NumBits;
		StatTable[hash_num].Prealloc    = Prealloc;
		StatTable[hash_num].bucket	  	= (StatRecord_t **)calloc(maxindex, sizeof(StatRecord_t *));
		StatTable[hash_num].bucketcache = (StatRecord_t **)calloc(maxindex, sizeof(StatRecord_t *));
		if ( !StatTable[hash_num].bucket || !StatTable[hash_num].bucketcache ) {
			fprintf(stderr, "malloc() error in %s line %d: %s\n", __FILE__, __LINE__, strerror(errno) );
			return 0;
		}
		StatTable[hash_num].memblock = (StatRecord_t **)calloc(MaxMemBlocks, sizeof(StatRecord_t *));
		if ( !StatTable[hash_num].memblock ) {
			fprintf(stderr, "malloc() error in %s line %d: %s\n", __FILE__, __LINE__, strerror(errno) );
			return 0;
		}
		StatTable[hash_num].memblock[0] = (StatRecord_t *)calloc(Prealloc, sizeof(StatRecord_t));
		if ( !StatTable[hash_num].memblock[0] ) {
			fprintf(stderr, "malloc() error in %s line %d: %s\n", __FILE__, __LINE__, strerror(errno) );
			return 0;
		}

		StatTable[hash_num].NumBlocks = 1;
		StatTable[hash_num].MaxBlocks = MaxMemBlocks;
		StatTable[hash_num].NextBlock = 0;
		StatTable[hash_num].NextElem  = 0;

		if ( StatRequest[hash_num].order_bits == 0 ) {
			StatRequest[hash_num].order_bits = PrintOrder ? order_mode[PrintOrder].val : Default_PrintOrder;
		}
	}

	initialised = 1;
	return 1;

} // End of Init_StatTable

void Dispose_StatTable() {
unsigned int i, hash_num;

	if ( !initialised )
		return;

	for ( hash_num=0; hash_num<NumStats; hash_num++ ) {
		free((void *)StatTable[hash_num].bucket);
		for ( i=0; i<StatTable[hash_num].NumBlocks; i++ )
			free((void *)StatTable[hash_num].memblock[i]);
		free((void *)StatTable[hash_num].memblock);
	}

} // End of Dispose_Tables

int SetStat(char *str, int *element_stat, int *flow_stat) {
int			flow_record_stat = 0;
int16_t 	StatType    = 0;
uint16_t	order_proto = 0;

	if ( NumStats == MaxStats ) {
		fprintf(stderr, "Too many stat options! Stats are limited to %i stats per single run!\n", MaxStats);
		return 0;
	}

	print_order_bits = 0;
	if ( ParseStatString(str, &StatType, &flow_record_stat, &order_proto) ) {
		if ( flow_record_stat ) {
			if ( !print_order_bits )
				print_order_bits = PrintOrder ? order_mode[PrintOrder].val : Default_PrintOrder;
			*flow_stat = 1;
		} else {
			StatRequest[NumStats].StatType 	  = StatType;
			StatRequest[NumStats].order_bits  = print_order_bits;
			StatRequest[NumStats].order_proto = order_proto;
			NumStats++;
			*element_stat = 1;
		}
		return 1;
	} else {
		fprintf(stderr, "Unknown stat: '%s'!\n", str);
		return 0;
	}

} // End of SetStat

static int ParseStatString(char *str, int16_t	*StatType, int *flow_record_stat, uint16_t *order_proto) {
char	*s, *p, *q, *r;
int i=0;

	print_order_bits = 0;
	if ( NumStats >= MaxStats )
		return 0;

	s = strdup(str);
	q = strchr(s, '/');
	if ( q )
		*q = 0;

	*order_proto = 0;
	p = strchr(s, ':');
	if ( p ) {
		*p = 0;
		*order_proto = 1;
	}

	i = 0;
	// check for a valid stat name
	while ( StatParameters[i].statname ) {
		if ( strncasecmp(s, StatParameters[i].statname ,16) == 0 ) {
			// set flag if it's the flow record stat request
			*flow_record_stat = strncasecmp(s, "record", 16) == 0;
			break;
		}
		i++;
	}

	// if so - initialize type and order_bits
 	if ( StatParameters[i].statname ) {
		*StatType = i;
		if ( strncasecmp(StatParameters[i].statname, "proto", 16) == 0 )
			*order_proto = 1;
	} else {
		free(s);
		return 0;
	}

	// no order is given - default order applies;
	if ( !q ) {
		free(s);
		return 1;
	}

	// check if one or more orders are given
	r = ++q;
	if ( ParseListOrder(r, MULTIPLE_LIST_ORDERS ) == 1 ) {
		free(s);
		return 1;
	} else {
		free(s);
		return 0;
	}

} // End of ParseStatString

int ParseListOrder(char *s, int multiple_orders ) {
char *q;
uint32_t order_bits;

	order_bits = 0;
	while ( s ) {
		int i;
		q = strchr(s, '/');
		if ( q && !multiple_orders ) {
			return -1;
		}
		if ( q )
			*q = 0;
		i = 0;
		while ( order_mode[i].string ) {
			if (  strcasecmp(order_mode[i].string, s ) == 0 )
				break;
			i++;
		}
		if ( order_mode[i].string ) {
			order_bits |= order_mode[i].val;
		} else {
			return 0;
		}

		if ( !q ) {
			print_order_bits = order_bits;
			return 1;
		}

		s = ++q;
	}

	// not reached
	return 1;

} // End of ParseListOrder

int Parse_PrintOrder(char *order) {

	PrintOrder = 0;
	while ( order_mode[PrintOrder].string ) {
		if (  strcasecmp(order_mode[PrintOrder].string, order ) == 0 )
			break;
		PrintOrder++;
	}
	if ( !order_mode[PrintOrder].string ) {
		PrintOrder = 0;
		return -1;
	}

	return PrintOrder;

} // End of Parse_PrintOrder

static inline StatRecord_t *stat_hash_lookup(uint64_t *value, uint8_t prot, int hash_num) {
uint32_t		index;
StatRecord_t	*record;

	index = value[1] & StatTable[hash_num].IndexMask;

	if ( StatTable[hash_num].bucket[index] == NULL )
		return NULL;

	record = StatTable[hash_num].bucket[index];
	if ( StatRequest[hash_num].order_proto ) {
		while ( record && ( record->stat_key[1] != value[1] || record->stat_key[0] != value[0] || prot != record->prot ) ) {
			record = record->next;
		}
	} else {
		while ( record && ( record->stat_key[1] != value[1] || record->stat_key[0] != value[0] ) ) {
			record = record->next;
		}
	}
	return record;

} // End of stat_hash_lookup

static void Expand_StatTable_Blocks(int hash_num) {

	if ( StatTable[hash_num].NumBlocks >= StatTable[hash_num].MaxBlocks ) {
		StatTable[hash_num].MaxBlocks += MaxMemBlocks;
		StatTable[hash_num].memblock = (StatRecord_t **)realloc(StatTable[hash_num].memblock,
						StatTable[hash_num].MaxBlocks * sizeof(StatRecord_t *));
		if ( !StatTable[hash_num].memblock ) {
			fprintf(stderr, "realloc() error in %s line %d: %s\n", __FILE__, __LINE__, strerror (errno));
			exit(250);
		}
	}
	StatTable[hash_num].memblock[StatTable[hash_num].NumBlocks] =
			(StatRecord_t *)calloc(StatTable[hash_num].Prealloc, sizeof(StatRecord_t));

	if ( !StatTable[hash_num].memblock[StatTable[hash_num].NumBlocks] ) {
		fprintf(stderr, "calloc() error in %s line %d: %s\n", __FILE__, __LINE__, strerror (errno));
		exit(250);
	}
	StatTable[hash_num].NextBlock = StatTable[hash_num].NumBlocks++;
	StatTable[hash_num].NextElem  = 0;

} // End of Expand_StatTable_Blocks

static inline StatRecord_t *stat_hash_insert(uint64_t *value, uint8_t prot, int hash_num) {
uint32_t		index;
StatRecord_t	*record;

	if ( StatTable[hash_num].NextElem >= StatTable[hash_num].Prealloc )
		Expand_StatTable_Blocks(hash_num);

	record = &(StatTable[hash_num].memblock[StatTable[hash_num].NextBlock][StatTable[hash_num].NextElem]);
	StatTable[hash_num].NextElem++;
	record->next     	= NULL;
	record->stat_key[0] = value[0];
	record->stat_key[1] = value[1];
	record->prot		= prot;

	index = value[1] & StatTable[hash_num].IndexMask;
	if ( StatTable[hash_num].bucket[index] == NULL )
		StatTable[hash_num].bucket[index] = record;
	else
		StatTable[hash_num].bucketcache[index]->next = record;
	StatTable[hash_num].bucketcache[index] = record;

	return record;

} // End of stat_hash_insert

void AddStat(common_record_t *raw_record, master_record_t *flow_record ) {
StatRecord_t		*stat_record;
uint64_t			value[2][2];
int	j, i;

	// for every requested -s stat do
	for ( j=0; j<NumStats; j++ ) {
		int stat   = StatRequest[j].StatType;
		// for the number of elements in this stat type
		for ( i=0; i<StatParameters[stat].num_elem; i++ ) {
			uint32_t offset = StatParameters[stat].element[i].offset1;
			uint64_t mask	= StatParameters[stat].element[i].mask;
			uint32_t shift	= StatParameters[stat].element[i].shift;

			value[i][1] = (((uint64_t *)flow_record)[offset] & mask) >> shift;
			offset = StatParameters[stat].element[i].offset0;
			value[i][0] = offset ? ((uint64_t *)flow_record)[offset] : 0;

			/*
			 * make sure each flow is counted once only
			 * if src and dst have the same values, count it once only
			 */
			if ( i == 1 && value[0][0] == value[1][0] && value[0][1] == value[1][1] ) {
				break;
			}
			stat_record = stat_hash_lookup(value[i], flow_record->prot, j);
			if ( stat_record ) {
				stat_record->counter[INBYTES] 	+= flow_record->dOctets;
				stat_record->counter[INPACKETS] += flow_record->dPkts;

				if ( TimeMsec_CMP(flow_record->first, flow_record->msec_first, stat_record->first, stat_record->msec_first) == 2) {
					stat_record->first 		= flow_record->first;
					stat_record->msec_first = flow_record->msec_first;
				}
				if ( TimeMsec_CMP(flow_record->last, flow_record->msec_last, stat_record->last, stat_record->msec_last) == 1) {
					stat_record->last 		= flow_record->last;
					stat_record->msec_last 	= flow_record->msec_last;
				}
				stat_record->counter[FLOWS]++;

			} else {
				stat_record = stat_hash_insert(value[i], flow_record->prot, j);

				stat_record->counter[INBYTES]   = flow_record->dOctets;
				stat_record->counter[INPACKETS]	= flow_record->dPkts;
				stat_record->first    			= flow_record->first;
				stat_record->msec_first 		= flow_record->msec_first;
				stat_record->last				= flow_record->last;
				stat_record->msec_last			= flow_record->msec_last;
				stat_record->record_flags		= flow_record->flags & 0x1;
				stat_record->counter[FLOWS] 	= 1;
			}
		} // for the number of elements in this stat type
	} // for every requested -s stat

} // End of AddStat

static void PrintStatLine(stat_record_t	*stat, StatRecord_t *StatData, int type, int order_proto, int tag) {
char		proto[16], valstr[40], datestr[64], flows_str[32], byte_str[32], packets_str[32], pps_str[32], bps_str[32];
char tag_string[2];
double		duration, flows_percent, packets_percent, bytes_percent;
uint32_t	bpp;
uint64_t	pps, bps;
time_t		first;
struct tm	*tbuff;

	tag_string[0] = '\0';
	tag_string[1] = '\0';
	switch (type) {
		case NONE:
			break;
		case IS_NUMBER:
			snprintf(valstr, 40, "%llu", (unsigned long long)StatData->stat_key[1]);
			break;
		case IS_IPADDR:
			tag_string[0] = tag ? TAG_CHAR : '\0';
			if ( (StatData->record_flags & 0x1) != 0 ) { // IPv6
				StatData->stat_key[0] = htonll(StatData->stat_key[0]);
				StatData->stat_key[1] = htonll(StatData->stat_key[1]);
				inet_ntop(AF_INET6, StatData->stat_key, valstr, sizeof(valstr));
				if ( ! Getv6Mode() )
					condense_v6(valstr);

			} else {	// IPv4
				uint32_t	ipv4;
				ipv4 = htonl(StatData->stat_key[1]);
				inet_ntop(AF_INET, &ipv4, valstr, sizeof(valstr));
			}
			break;
		case IS_MACADDR: {
			int i;
			uint8_t mac[6];
			for ( i=0; i<6; i++ ) {
				mac[i] = ((unsigned long long)StatData->stat_key[1] >> ( i*8 )) & 0xFF;
			}
			snprintf(valstr, 40, "%.2x:%.2x:%.2x:%.2x:%.2x:%.2x", mac[5], mac[4], mac[3], mac[2], mac[1], mac[0]);
			} break;
		case IS_MPLS_LBL: {
			snprintf(valstr, 40, "%llu", (unsigned long long)StatData->stat_key[1]);
			snprintf(valstr, 40,"%8llu-%1llu-%1llu",
				(unsigned long long)StatData->stat_key[1] >> 4 ,
				((unsigned long long)StatData->stat_key[1] & 0xF ) >> 1,
				(unsigned long long)StatData->stat_key[1] & 1);
			} break;
		case IS_LATENCY: {
			snprintf(valstr, 40, "      %9.3f", (double)((double)StatData->stat_key[1]/1000.0));
		} break;
	}

	valstr[39] = 0;

	format_number(StatData->counter[FLOWS], flows_str, FIXED_WIDTH);
	format_number(StatData->counter[INPACKETS], packets_str, FIXED_WIDTH);
	format_number(StatData->counter[INBYTES], byte_str, FIXED_WIDTH);

	flows_percent   = (double)(StatData->counter[FLOWS] * 100 ) / (double)stat->numflows;
	packets_percent = (double)(StatData->counter[INPACKETS] * 100 ) / (double)stat->numpackets;
	bytes_percent   = (double)(StatData->counter[INBYTES] * 100 ) / (double)stat->numbytes;

	duration = StatData->last - StatData->first;
	duration += ((double)StatData->msec_last - (double)StatData->msec_first) / 1000.0;

	if ( duration != 0 ) {
		pps = (uint64_t)((double)StatData->counter[INPACKETS] / duration);
		bps = (uint64_t)((double)(8 * StatData->counter[INBYTES]) / duration);
	} else {
		pps = bps = 0;
	}

	if (StatData->counter[INPACKETS]) {
		bpp = StatData->counter[INBYTES] / StatData->counter[INPACKETS];
	} else {
		bpp = 0;
	}

	format_number(pps, pps_str, FIXED_WIDTH);
	format_number(bps, bps_str, FIXED_WIDTH);

	first = StatData->first;
	tbuff = localtime(&first);
	if ( !tbuff ) {
		perror("Error time convert");
		exit(250);
	}
	strftime(datestr, 63, "%Y-%m-%d %H:%M:%S", tbuff);

	if ( order_proto ) {
		Proto_string(StatData->prot, proto);
	} else {
		snprintf(proto, 15, "any  ");
		proto[15] = 0;
	}

	if ( Getv6Mode() && ( type == IS_IPADDR ) )
		printf("%s.%03u %9.3f %s %s%39s %8s(%4.1f) %8s(%4.1f) %8s(%4.1f) %8s %8s %5u\n",
				datestr, StatData->msec_first, duration, proto, tag_string, valstr,
				flows_str, flows_percent, packets_str, packets_percent, byte_str, bytes_percent, pps_str, bps_str, bpp );
	else
		printf("%s.%03u %9.3f %s %s%17s %8s(%4.1f) %8s(%4.1f) %8s(%4.1f) %8s %8s %5u\n",
				datestr, StatData->msec_first, duration, proto, tag_string, valstr,
				flows_str, flows_percent, packets_str, packets_percent, byte_str, bytes_percent, pps_str, bps_str, bpp );

} // End of PrintStatLine

static void PrintPipeStatLine(StatRecord_t *StatData, int type, int order_proto, int tag) {
double		duration;
uint32_t	pps, bps, bpp;
uint32_t	sa[4];
int			af;

	sa[0] = sa[1] = sa[2] = sa[3] = 0;
	af = AF_UNSPEC;
	if ( type == IS_IPADDR ) {
		if ( (StatData->record_flags & 0x1) != 0 ) { // IPv6
			StatData->stat_key[0] = htonll(StatData->stat_key[0]);
			StatData->stat_key[1] = htonll(StatData->stat_key[1]);
			af = PF_INET6;

		} else {	// IPv4
			af = PF_INET;
		}
		// Make sure Endian does not screw us up
    	sa[0] = ( StatData->stat_key[0] >> 32 ) & 0xffffffffLL;
    	sa[1] = StatData->stat_key[0] & 0xffffffffLL;
    	sa[2] = ( StatData->stat_key[1] >> 32 ) & 0xffffffffLL;
    	sa[3] = StatData->stat_key[1] & 0xffffffffLL;
	}
	duration = StatData->last - StatData->first;
	duration += ((double)StatData->msec_last - (double)StatData->msec_first) / 1000.0;

	if ( duration != 0 ) {
		pps = (uint32_t)((double)StatData->counter[INPACKETS] / duration);
		bps = (uint32_t)((double)(8 * StatData->counter[INBYTES]) / duration);
	} else {
		pps = bps = 0;
	}

	if ( StatData->counter[INPACKETS] )
		bpp = StatData->counter[INBYTES] / StatData->counter[INPACKETS];
	else
		bpp = 0;

	if ( !order_proto ) {
		StatData->prot = 0;
	}

	if ( type == IS_IPADDR )
		printf("%i|%u|%u|%u|%u|%u|%u|%u|%u|%u|%llu|%llu|%llu|%u|%u|%u\n",
				af, StatData->first, StatData->msec_first ,StatData->last, StatData->msec_last, StatData->prot,
				sa[0], sa[1], sa[2], sa[3], (long long unsigned)StatData->counter[FLOWS],
				(long long unsigned)StatData->counter[INPACKETS], (long long unsigned)StatData->counter[INBYTES],
				pps, bps, bpp);
	else
		printf("%i|%u|%u|%u|%u|%u|%llu|%llu|%llu|%llu|%u|%u|%u\n",
				af, StatData->first, StatData->msec_first ,StatData->last, StatData->msec_last, StatData->prot,
				(long long unsigned)StatData->stat_key[1], (long long unsigned)StatData->counter[FLOWS],
				(long long unsigned)StatData->counter[INPACKETS], (long long unsigned)StatData->counter[INBYTES],
				pps, bps, bpp);

} // End of PrintPipeStatLine

static void PrintCvsStatLine(stat_record_t	*stat, StatRecord_t *StatData, int type, int order_proto, int tag) {
char		proto[16], valstr[40], datestr1[64], datestr2[64];
char tag_string[2];
double		duration, flows_percent, packets_percent, bytes_percent;
uint32_t	i, pps, bps, bpp;
time_t		when;
struct tm	*tbuff;

	tag_string[0] = '\0';
	tag_string[1] = '\0';
	switch (type) {
		case NONE:
			break;
		case IS_NUMBER:
			snprintf(valstr, 40, "%llu", (unsigned long long)StatData->stat_key[1]);
			break;
		case IS_IPADDR:
			tag_string[0] = tag ? TAG_CHAR : '\0';
			if ( (StatData->record_flags & 0x1) != 0 ) { // IPv6
				StatData->stat_key[0] = htonll(StatData->stat_key[0]);
				StatData->stat_key[1] = htonll(StatData->stat_key[1]);
				inet_ntop(AF_INET6, StatData->stat_key, valstr, sizeof(valstr));

			} else {	// IPv4
				uint32_t	ipv4;
				ipv4 = htonl(StatData->stat_key[1]);
				inet_ntop(AF_INET, &ipv4, valstr, sizeof(valstr));
			}
			break;
		case IS_MACADDR: {
			int i;
			uint8_t mac[6];
			for ( i=0; i<6; i++ ) {
				mac[i] = ((unsigned long long)StatData->stat_key[1] >> ( i*8 )) & 0xFF;
			}
			snprintf(valstr, 40, "%.2x:%.2x:%.2x:%.2x:%.2x:%.2x", mac[5], mac[4], mac[3], mac[2], mac[1], mac[0]);
			} break;
		case IS_MPLS_LBL: {
			snprintf(valstr, 40, "%llu", (unsigned long long)StatData->stat_key[1]);
			snprintf(valstr, 40,"%8llu-%1llu-%1llu",
				(unsigned long long)StatData->stat_key[1] >> 4 ,
				((unsigned long long)StatData->stat_key[1] & 0xF ) >> 1,
				(unsigned long long)StatData->stat_key[1] & 1);
			} break;
	}

	valstr[39] = 0;

	flows_percent   = (double)(StatData->counter[FLOWS] * 100 ) / (double)stat->numflows;
	packets_percent = (double)(StatData->counter[INPACKETS] * 100 ) / (double)stat->numpackets;
	bytes_percent   = (double)(StatData->counter[INBYTES] * 100 ) / (double)stat->numbytes;

	duration = StatData->last - StatData->first;
	duration += ((double)StatData->msec_last - (double)StatData->msec_first) / 1000.0;

	if ( duration != 0 ) {
		pps = (uint32_t)((double)StatData->counter[INPACKETS] / duration);
		bps = (uint32_t)((double)(8 * StatData->counter[INBYTES]) / duration);
	} else {
		pps = bps = 0;
	}

	if (StatData->counter[INPACKETS]) {
		bpp = StatData->counter[INBYTES] / StatData->counter[INPACKETS];
	} else {
		bpp = 0;
	}

	when = StatData->first;
	tbuff = localtime(&when);
	if ( !tbuff ) {
		perror("Error time convert");
		exit(250);
	}
	strftime(datestr1, 63, "%Y-%m-%d %H:%M:%S", tbuff);

	when = StatData->last;
	tbuff = localtime(&when);
	if ( !tbuff ) {
		perror("Error time convert");
		exit(250);
	}
	strftime(datestr2, 63, "%Y-%m-%d %H:%M:%S", tbuff);

	if ( order_proto ) {
		Proto_string(StatData->prot, proto);
	} else {
		snprintf(proto, 15, "any  ");
		proto[15] = 0;
	}

	i=0;
	while ( proto[i] ) {
		if ( proto[i] == ' ' )
			proto[i] = '\0';
		i++;
	}

	printf("%s,%s,%.3f,%s,%s,%llu,%.1f,%llu,%.1f,%llu,%.1f,%u,%u,%u\n",
		datestr1, datestr2, duration, proto, valstr,
		(long long unsigned)StatData->counter[FLOWS], flows_percent,
		(long long unsigned)StatData->counter[INPACKETS], packets_percent,
		(long long unsigned)StatData->counter[INBYTES], bytes_percent,
		pps,bps,bpp
	);

} // End of PrintCvsStatLine

void PrintFlowTable(printer_t print_record, uint32_t limitflows, int tag, int GuessDir) {
hash_FlowTable *FlowTable;
FlowTableRecord_t	*r;
master_record_t		*aggr_record_mask;
SortElement_t 		*SortList;
uint32_t 			i;
uint32_t			maxindex, c;
char				*string;

	FlowTable = GetFlowTable();
	aggr_record_mask = GetMasterAggregateMask();
	c = 0;
	maxindex = FlowTable->NumRecords;
	if ( PrintOrder ) {
		// Sort according the date
		SortList = (SortElement_t *)calloc(maxindex, sizeof(SortElement_t));

		if ( !SortList ) {
			fprintf(stderr, "malloc() error in %s line %d: %s\n", __FILE__, __LINE__, strerror (errno));
			return;
		}

		// preset SortList table - still unsorted
		for ( i=0; i<FlowTable->IndexMask; i++ ) {
			r = FlowTable->bucket[i];
			if ( !r )
				continue;

			// foreach elem in this bucket
			while ( r ) {
				// we want to sort only those flows which pass the packet or byte limits
				if ( byte_limit ) {
					if (( byte_mode == LESS && r->counter[INBYTES] >= byte_limit ) ||
						( byte_mode == MORE && r->counter[INBYTES]  <= byte_limit ) ) {
						r = r->next;
						continue;
					}
				}
				if ( packet_limit ) {
					if (( packet_mode == LESS && r->counter[INPACKETS] >= packet_limit ) ||
						( packet_mode == MORE && r->counter[INPACKETS]  <= packet_limit ) ) {
						r = r->next;
						continue;
					}
				}

				if ( order_mode[PrintOrder].record_function ) {
					SortList[c].count  = order_mode[PrintOrder].record_function(r);
				} else
					SortList[c].count  = r->counter[PrintOrder];

				SortList[c].record = (void *)r;
				c++;
				r = r->next;
			}
		}

		maxindex = c;

		if ( c >= 2 )
 			heapSort(SortList, c, 0);

		PrintSortedFlowcache(SortList, maxindex, limitflows, GuessDir,
			print_record, tag, order_mode[PrintOrder].direction);

/*
		if ( limitflows && limitflows < maxindex )
			maxindex = limitflows;
		for ( i = 0; i < maxindex; i++ ) {
			master_record_t	*flow_record;
			common_record_t *raw_record;
			int map_id;

			r = (FlowTableRecord_t *)(SortList[i].record);
			raw_record = &(r->flowrecord);
			map_id = r->map_ref->map_id;

			flow_record = &(extension_map_list.slot[map_id]->master_record);
			ExpandRecord_v2( raw_record, extension_map_list.slot[map_id], flow_record);
			flow_record->dPkts 		= r->counter[INPACKETS];
			flow_record->dOctets 	= r->counter[INBYTES];
			flow_record->out_pkts 	= r->counter[OUTPACKETS];
			flow_record->out_bytes 	= r->counter[OUTBYTES];
			flow_record->aggr_flows 	= r->counter[FLOWS];

			// apply IP mask from aggregation, to provide a pretty output
			if ( FlowTable->has_masks ) {
				flow_record->v6.srcaddr[0] &= FlowTable->IPmask[0];
				flow_record->v6.srcaddr[1] &= FlowTable->IPmask[1];
				flow_record->v6.dstaddr[0] &= FlowTable->IPmask[2];
				flow_record->v6.dstaddr[1] &= FlowTable->IPmask[3];
			}

			if ( aggr_record_mask ) {
				ApplyAggrMask(flow_record, aggr_record_mask);
			}

			if ( GuessDir && ( flow_record->srcport < 1024 && flow_record->dstport > 1024 ) )
				SwapFlow(flow_record);
			print_record((void *)flow_record, &string, tag);
			printf("%s\n", string);
		}
*/
	} else {
		// print them as they came
		c = 0;
		for ( i=0; i<FlowTable->IndexMask; i++ ) {
			r = FlowTable->bucket[i];
			while ( r ) {
				master_record_t	*flow_record;
				common_record_t *raw_record;
				int map_id;

				if ( limitflows && c >= limitflows )
					return;

				// we want to print only those flows which pass the packet or byte limits
				if ( byte_limit ) {
					if (( byte_mode == LESS && r->counter[INBYTES] >= byte_limit ) ||
						( byte_mode == MORE && r->counter[INBYTES]  <= byte_limit ) ) {
						r = r->next;
						continue;
					}
				}
				if ( packet_limit ) {
					if (( packet_mode == LESS && r->counter[INPACKETS] >= packet_limit ) ||
						( packet_mode == MORE && r->counter[INPACKETS]  <= packet_limit ) ) {
						r = r->next;
						continue;
					}
				}

				raw_record = &(r->flowrecord);
				map_id = r->map_ref->map_id;

				flow_record = &(extension_map_list.slot[map_id]->master_record);
				ExpandRecord_v2( raw_record, extension_map_list.slot[map_id], r->exp_ref, flow_record);
				flow_record->dPkts 		= r->counter[INPACKETS];
				flow_record->dOctets 	= r->counter[INBYTES];
				flow_record->out_pkts 	= r->counter[OUTPACKETS];
				flow_record->out_bytes 	= r->counter[OUTBYTES];
				flow_record->aggr_flows = r->counter[FLOWS];

				// apply IP mask from aggregation, to provide a pretty output
				if ( FlowTable->has_masks ) {
					flow_record->v6.srcaddr[0] &= FlowTable->IPmask[0];
					flow_record->v6.srcaddr[1] &= FlowTable->IPmask[1];
					flow_record->v6.dstaddr[0] &= FlowTable->IPmask[2];
					flow_record->v6.dstaddr[1] &= FlowTable->IPmask[3];
				}

				if ( aggr_record_mask ) {
					ApplyAggrMask(flow_record, aggr_record_mask);
				}
				if ( GuessDir && ( flow_record->srcport < 1024 && flow_record->dstport > 1024 ) )
					SwapFlow(flow_record);
				print_record((void *)flow_record, &string, tag);
				printf("%s\n", string);

				c++;
				r = r->next;
			}
		}
	}

} // End of PrintFlowTable

void PrintFlowStat(char *record_header, printer_t print_record, int topN, int tag, int quiet, int cvs_output) {
hash_FlowTable *FlowTable;
FlowTableRecord_t	*r;
master_record_t		*aggr_record_mask;
SortElement_t 		*SortList;
int 				order_index, order_bit, i;
uint32_t			maxindex, c;

	FlowTable = GetFlowTable();
	aggr_record_mask = GetMasterAggregateMask();
	c = 0;
	maxindex = FlowTable->NumRecords;

	// Create the sort array
	SortList = (SortElement_t *)calloc(maxindex, sizeof(SortElement_t));

	if ( !SortList ) {
		fprintf(stderr, "malloc() error in %s line %d: %s\n", __FILE__, __LINE__, strerror (errno));
		return;
	}

	// preset the first stat
	for ( order_index=0; order_index<NumOrders; order_index++ ) {
		order_bit = 1 << order_index;
		if ( print_order_bits & order_bit )
			break;
	}

	// preset SortList table - still unsorted
	for ( i=0; i<FlowTable->IndexMask; i++ ) {
		r = FlowTable->bucket[i];
		if ( !r )
			continue;

		// foreach elem in this bucket
		while ( r ) {
			// we want to sort only those flows which pass the packet or byte limits
			if ( byte_limit ) {
				if (( byte_mode == LESS && r->counter[INBYTES] >= byte_limit ) ||
					( byte_mode == MORE && r->counter[INBYTES]  <= byte_limit ) ) {
					r = r->next;
					continue;
				}
			}
			if ( packet_limit ) {
				if (( packet_mode == LESS && r->counter[INPACKETS] >= packet_limit ) ||
					( packet_mode == MORE && r->counter[INPACKETS]  <= packet_limit ) ) {
					r = r->next;
					continue;
				}
			}

			// As we touch each flow in the list here, fill in the values for the first requested stat
			// often, no more than one stat is requested anyway. This saves time
			if ( order_mode[order_index].record_function ) {
				SortList[c].count  = order_mode[order_index].record_function(r);
			} else
				SortList[c].count  = r->counter[order_index];
			SortList[c].record = (void *)r;
			c++;
			r = r->next;
		}
	}

	maxindex = c;

	if ( !(quiet || cvs_output) )
		printf("Aggregated flows %u\n", maxindex);

	if ( c >= 2 )
 		heapSort(SortList, c, topN);
	if ( !quiet ) {
		if ( !cvs_output )
			printf("Top %i flows ordered by %s:\n", topN, order_mode[order_index].string);
		if ( record_header )
			printf("%s\n", record_header);
	}

	PrintSortedFlowcache(SortList, maxindex, topN, 0, print_record, tag, DESCENDING);

	// process all the remaining stats, if requested
	for ( order_index++ ; order_index<NumOrders; order_index++ ) {
		order_bit = 1 << order_index;
		if ( print_order_bits & order_bit ) {

			for ( i = 0; i < maxindex; i++ ) {
				r = (FlowTableRecord_t *)(SortList[i].record);
				/* if we have some different sort orders, which are not directly available in the FlowTableRecord_t
		 		 * we need to calculate this value first - such as bpp, bps etc.
		 		 */
				if ( order_mode[order_index].record_function ) {
					SortList[i].count  = order_mode[order_index].record_function(r);
				} else
					SortList[i].count  = r->counter[order_index];
			}

			if ( maxindex >= 2 )
 				heapSort(SortList, maxindex, topN);
			if ( !quiet ) {
				if ( !cvs_output )
					printf("Top %i flows ordered by %s:\n", topN, order_mode[order_index].string);
				if ( !record_header )
					printf("%s\n", record_header);
			}
			PrintSortedFlowcache(SortList, maxindex, topN, 0, print_record, tag, DESCENDING);

		}
	}

} // End of PrintFlowStat

inline void PrintSortedFlowcache(SortElement_t *SortList, uint32_t maxindex, int limit_count, int GuessFlowDirection,
	printer_t print_record, int tag, int ascending ) {
hash_FlowTable *FlowTable;
master_record_t		*aggr_record_mask;
int	i, max;

	FlowTable = GetFlowTable();
	aggr_record_mask = GetMasterAggregateMask();

	max = maxindex;
	if ( limit_count && limit_count < maxindex )
		max = limit_count;
	for ( i = 0; i < max; i++ ) {
		master_record_t	*flow_record;
		common_record_t *raw_record;
		FlowTableRecord_t	*r;
		char	*string;
		int map_id, j;

		if ( ascending )
			j = i;
		else
			j = maxindex - 1 - i;

		r = (FlowTableRecord_t *)(SortList[j].record);
		raw_record = &(r->flowrecord);
		map_id = r->map_ref->map_id;

		flow_record = &(extension_map_list.slot[map_id]->master_record);
		ExpandRecord_v2( raw_record, extension_map_list.slot[map_id], r->exp_ref, flow_record);
		flow_record->dPkts 		= r->counter[INPACKETS];
		flow_record->dOctets 	= r->counter[INBYTES];
		flow_record->out_pkts 	= r->counter[OUTPACKETS];
		flow_record->out_bytes 	= r->counter[OUTBYTES];
		flow_record->aggr_flows 	= r->counter[FLOWS];

		// apply IP mask from aggregation, to provide a pretty output
		if ( FlowTable->has_masks ) {
			flow_record->v6.srcaddr[0] &= FlowTable->IPmask[0];
			flow_record->v6.srcaddr[1] &= FlowTable->IPmask[1];
			flow_record->v6.dstaddr[0] &= FlowTable->IPmask[2];
			flow_record->v6.dstaddr[1] &= FlowTable->IPmask[3];
		}

		if ( FlowTable->apply_netbits )
			ApplyNetMaskBits(flow_record, FlowTable->apply_netbits);
		if ( aggr_record_mask )
			ApplyAggrMask(flow_record, aggr_record_mask);

		if ( GuessFlowDirection && ( flow_record->srcport < 1024 && flow_record->dstport > 1024 ) )
			SwapFlow(flow_record);

		print_record((void *)flow_record, &string, tag);
		printf("%s\n", string);
	}

} // End of PrintSortedFlowcache

void PrintElementStat(stat_record_t	*sum_stat, char *record_header, printer_t print_record, int topN, int tag, int quiet, int pipe_output, int cvs_output) {
SortElement_t	*topN_element_list;
uint32_t		numflows, maxindex;
int32_t 		i, j, hash_num, order_index, order_bit;

	numflows = 0;
	// for every requested -s stat do
	for ( hash_num=0; hash_num<NumStats; hash_num++ ) {
		int stat   = StatRequest[hash_num].StatType;
		int order  = StatRequest[hash_num].order_bits;
		int	type = StatParameters[stat].type;
		for ( order_index=0; order_index<NumOrders; order_index++ ) {
			order_bit = 1 << order_index;
			if ( order & order_bit ) {
				topN_element_list = StatTopN(topN, &numflows, hash_num, order_index);

				// this output formating is pretty ugly - and needs to be cleaned up - improved
				if ( !pipe_output && !cvs_output && !quiet  ) {
					printf("Top %i %s ordered by %s:\n",
						topN, StatParameters[stat].HeaderInfo, order_mode[order_index].string);
					//      2005-07-26 20:08:59.197 1553.730      ss    65255   203435   52.2 M      130   281636   268
					if ( Getv6Mode() && (type == IS_IPADDR ))
						printf("Date first seen          Duration Proto %39s    Flows(%%)     Packets(%%)       Bytes(%%)         pps      bps   bpp\n",
							StatParameters[stat].HeaderInfo);
					else
						printf("Date first seen          Duration Proto %17s    Flows(%%)     Packets(%%)       Bytes(%%)         pps      bps   bpp\n",
							StatParameters[stat].HeaderInfo);
				}

				if ( cvs_output ) {
					printf("ts,te,td,pr,val,fl,flP,ipkt,ipktP,ibyt,ibytP,pps,pbs,bpp\n");
				}

				maxindex = ( StatTable[hash_num].NextBlock * StatTable[hash_num].Prealloc ) + StatTable[hash_num].NextElem;
				j = numflows - topN;
				j = j < 0 ? 0 : j;
				if ( topN == 0 )
					j = 0;
				for ( i=numflows-1; i>=j ; i--) {
					//if ( !topN_element_list[i].count )
						//break;

					// Again - ugly output formating - needs to be cleand up
					if ( pipe_output )
						PrintPipeStatLine((StatRecord_t *)topN_element_list[i].record, type,
							StatRequest[hash_num].order_proto, tag);
					else if ( cvs_output )
						PrintCvsStatLine(sum_stat, (StatRecord_t *)topN_element_list[i].record, type,
							StatRequest[hash_num].order_proto, tag);
					else
						PrintStatLine(sum_stat, (StatRecord_t *)topN_element_list[i].record,
							type, StatRequest[hash_num].order_proto, tag);
				}
				free((void *)topN_element_list);
				printf("\n");
			}
		} // for every requested order
	} // for every requested -s stat do
} // End of PrintElementStat

static SortElement_t *StatTopN(int topN, uint32_t *count, int hash_num, int order ) {
SortElement_t 		*topN_list;
StatRecord_t		*r;
unsigned int		i;
uint32_t	   		c, maxindex;

	maxindex  = ( StatTable[hash_num].NextBlock * StatTable[hash_num].Prealloc ) + StatTable[hash_num].NextElem;
	topN_list = (SortElement_t *)calloc(maxindex, sizeof(SortElement_t));

	if ( !topN_list ) {
		perror("Can't allocate Top N lists: \n");
		return NULL;
	}

	// preset topN_list table - still unsorted
	c = 0;
	// Iterate through all buckets
	for ( i=0; i <= StatTable[hash_num].IndexMask; i++ ) {
		r = StatTable[hash_num].bucket[i];
		// foreach elem in this bucket
		while ( r ) {
			// next elem in bucket

			// we want to sort only those flows which pass the packet or byte limits
			if ( byte_limit ) {
				if (( byte_mode == LESS && r->counter[INBYTES] >= byte_limit ) ||
					( byte_mode == MORE && r->counter[INBYTES]  <= byte_limit ) ) {
					r = r->next;
					continue;
				}
			}
			if ( packet_limit ) {
				if (( packet_mode == LESS && r->counter[INPACKETS] >= packet_limit ) ||
					( packet_mode == MORE && r->counter[INPACKETS]  <= packet_limit ) ) {
					r = r->next;
					continue;
				}
			}

			if ( order_mode[order].element_function )
				topN_list[c].count  = order_mode[order].element_function(r);
			else
				topN_list[c].count  = r->counter[order];

			topN_list[c].record = (void *)r;
			r = r->next;
			c++;
		} // foreach element
	}
	*count = c;
	// printf ("Sort %u flows\n", c);

	/*
	for ( i = 0; i < maxindex; i++ )
		printf("%i, %llu %llu\n", i, topN_list[i].count, topN_list[i].record);
	*/

	// Sorting makes only sense, when 2 or more flows are left
	if ( c >= 2 )
 		heapSort(topN_list, c, topN);

	/*
	for ( i = 0; i < maxindex; i++ )
		printf("%i, %llu %llu\n", i, topN_list[i].count, topN_list[i].record);
	*/

	return topN_list;

} // End of StatTopN

static void SwapFlow(master_record_t *flow_record) {
uint64_t _tmp_ip[2];
uint64_t _tmp_l;
uint32_t _tmp;

	_tmp_ip[0] = flow_record->v6.srcaddr[0];
	_tmp_ip[1] = flow_record->v6.srcaddr[1];
	flow_record->v6.srcaddr[0] = flow_record->v6.dstaddr[0];
	flow_record->v6.srcaddr[1] = flow_record->v6.dstaddr[1];
	flow_record->v6.dstaddr[0] = _tmp_ip[0];
	flow_record->v6.dstaddr[1] = _tmp_ip[1];

	_tmp = flow_record->srcport;
	flow_record->srcport = flow_record->dstport;
	flow_record->dstport = _tmp;

	_tmp = flow_record->srcas;
	flow_record->srcas = flow_record->dstas;
	flow_record->dstas = _tmp;

	_tmp = flow_record->input;
	flow_record->input = flow_record->output;
	flow_record->output = _tmp;

	_tmp_l = flow_record->dPkts;
	flow_record->dPkts = flow_record->out_pkts;
	flow_record->out_pkts = _tmp_l;

	_tmp_l = flow_record->dOctets;
	flow_record->dOctets = flow_record->out_bytes;
	flow_record->out_bytes = _tmp_l;

} // End of SwapFlow


text:
package com.adobe.acs.commons.httpcache.exception;

/**
 * Custom exception representing failure condition in accessing JCR repository.
 */
@SuppressWarnings({"serial", "squid:S2166"})
public class HttpCacheRepositoryAccessException extends HttpCacheException {
    public HttpCacheRepositoryAccessException() {
    }

    public HttpCacheRepositoryAccessException(String message) {
        super(message);
    }

    public HttpCacheRepositoryAccessException(String message, Throwable cause) {
        super(message, cause);
    }

    public HttpCacheRepositoryAccessException(Throwable cause) {
        super(cause);
    }

    public HttpCacheRepositoryAccessException(String message, Throwable cause, boolean enableSuppression, boolean
            writableStackTrace) {
        super(message, cause, enableSuppression, writableStackTrace);
    }
}


text:
__author__ = 'vincenzo gulisano'

import pymysql.cursors
from optparse import OptionParser

def open_connection(password):
    connection = pymysql.connect(host='129.16.22.6',
                                 port=8080,
                                 user='root',
                                 password=password,
                                 db='debs_eval',
                                 charset='utf8mb4',
                                 cursorclass=pymysql.cursors.DictCursor)

    return connection

def show_participants(connection):
    with connection.cursor() as cursor:
        sql = "SELECT * FROM participants"
        cursor.execute(sql)

        for row in cursor:
            print(row)

def add_participant(connection, participant, email):
    with connection.cursor() as cursor:
        sql = "INSERT INTO `participants` (`participant_id`, `mail`) VALUES (%s, %s)"
        cursor.execute(sql, (participant, email))
    connection.commit()

def check_if_participant_exists(connection, participant):
    with connection.cursor() as cursor:
        sql = "SELECT COUNT(*) as count FROM participants WHERE participant_id=%s"
        cursor.execute(sql, participant)

    result = cursor.fetchone()
    if int(result['count']) == 1:
        return True

    return False

def is_there_something_to_evaluate(connection):
    with connection.cursor() as cursor:
        sql = "SELECT COUNT(*) as count FROM to_evaluate"
        cursor.execute(sql)

    result = cursor.fetchone()
    if int(result['count']) > 0:
        return True

    return False

def get_next_participant_to_evaluate(connection):
    with connection.cursor() as cursor:
        sql = "SELECT * FROM to_evaluate ORDER BY ts ASC"
        cursor.execute(sql)

    result = cursor.fetchone()
    return result['participant_id']

def check_if_participant_has_pending_evaluation(connection, participant):
    with connection.cursor() as cursor:
        sql = "SELECT COUNT(*) as count FROM to_evaluate WHERE participant_id=%s"
        cursor.execute(sql, participant)

    result = cursor.fetchone()
    if int(result['count']) == 1:
        return True

    return False

def add_participant_to_evaluate(connection, participant, vm_location):
    with connection.cursor() as cursor:
        sql = "INSERT INTO `to_evaluate` (`participant_id`, `vm_location`) VALUES (%s, %s)"
        cursor.execute(sql, (participant, vm_location))
    connection.commit()

def remove_participant_evaluated(connection, participant):
    with connection.cursor() as cursor:
        sql = "DELETE FROM to_evaluate WHERE participant_id=%s"
        cursor.execute(sql, (participant))
    connection.commit()

def add_participant_evaluation(connection, participant, duration, throughput, latency, log):
    with connection.cursor() as cursor:
        sql = "INSERT INTO `evaluated` (`participant_id`, `duration`, `throughput`, `latency`, `log`) " \
              " VALUES (%s,%s,%s,%s,%s)"
        cursor.execute(sql, (participant, duration, throughput, latency, log))
    connection.commit()

def close_connection(connection):
    connection.close()

parser = OptionParser()
parser.add_option("-p", "--password", dest="password",
                  help="DB password", metavar="PASSWORD")

(options, args) = parser.parse_args()

if options.password is None:
    print('A mandatory option (-p, --password) is missing\n')
    parser.print_help()
    exit(-1)

connection = open_connection(options.password)
# add_participant(connection, 'vincenzo', 'vincenzo.gulisano@gmail.com')
show_participants(connection)
print(check_if_participant_exists(connection, 'vincenzo'))
print(check_if_participant_has_pending_evaluation(connection, 'vincenzo'))
add_participant_to_evaluate(connection, 'participant3', 'www.abc.com')
# remove_participant_evaluated(connection, 'participant2')
add_participant_evaluation(connection, 'vincenzo', '132', '12341', '231', 'sda')
print(is_there_something_to_evaluate(connection))
if is_there_something_to_evaluate(connection):
    print(get_next_participant_to_evaluate(connection))
close_connection(connection)