ArpON-2.0/000755 000765 000024 00000000000 11406411413 012774 5ustar00spikeystaff000000 000000 ArpON-2.0/AUTHORS000644 000765 000024 00000001301 11403225341 014037 0ustar00spikeystaff000000 000000 AUTHOR and DEVELOPER: ===================== - Andrea Di Pasquale aka "spikey" SPECIAL THANKS: =============== - Mariano Graziano aka "emdel" Old web site, he proposed SARPI idea! - Andrea Barberio aka "insomniac" Beta Tester, LD_PRELOAD idea! - Marco Fabre aka "Morpe" Old logo! - Giuseppe Marco Randazzo aka "zeld" CMake, Man page! - Giuseppe Iuculano aka "Derevko" Adjusted man page, added pid file! - Allan Jigpe Eversun aka "jigp" Beta tester! ArpON-2.0/CHANGELOG000644 000765 000024 00000007657 11403225560 014230 0ustar00spikeystaff000000 000000 ArpON 2.0: ========== + Redesign general code + Redesign general output + Added SARPI cache with rw locking + Added SARPI cache from file option + Added support unplug/boot/hibernation/suspension interface (OS' features too) + Added pid file option + Added cmake installation method - Removed Arp sniffer, Arp ping ! Fixed no options output ! Fixed main with BSD option handler ! Fixed getopt_long of missing and invalid option ! Fixed several options names ! Fixed aprintf with localtime integrated ! Fixed device handler of auto and list ! Fixed SIGINT, SIGTERM, SIGQUIT signals with POSIX signals ! Fixed SIGHUP and SIGCONT POSIX signal for daemon reboot ! Fixed sleep() with usleep() for thread suspend ! Fixed rw locking in DARPI and SARPI ! Fixed SARPI/DARPI soft real time for inbound/outbound packets ! Fixed SARPI/DARPI Round Robin detached/joinabled scheduling threads ! Fixed AUTHORS file ! Fixed INSTALL file ! Fixed Makefile file ! Fixed man8/arpon.8 file ! Fixed man8/html/arpon.html file ArpON 1.90: =========== + Added Static linking guide in INSTALL file ! Fixed date structures, device, arp_header, arp_cache, darpi_cache ! Fixed dnet bug for Linux, it returned "No such process" in arp_add() ! Fixed dnet bug for Linux, in arp_delete() ! Fixed makefile ArpON 1.80: =========== ! Fixed bug multithreaded in Arp reply timeout (Arp out traffic) ! Fixed bug in aprintf() with logging mode ! Fixed check file type for pid_file and log_file ! Fixed bug in device automatically ! Fixed arpon's output new style! ! Fixed makefile ArpON 1.72: =========== + Added Linux Gentoo platform support ! Fixed arp_cache_add(), now it works with array ! Fixed bug in darpi, it returned "Unknown error: 0", now it works well ! Fixed bug and output of daemon mode, now it returned 0 to shell ! Fixed global signal handler ArpON 1.70: =========== ! Fixed bug in arp_cache_add(), it returned "No such process" from errno, now arpon works very well, have fun! =) ArpON 1.60: =========== + Added support to multiplexing handle on multi interface + Added DARPI Cache entry timeout + Added Linux Debian platform support ! Fixed arpon's code style, now it is bsd coding style ! Fixed SARPI dyagram in doc/ ! Fixed DARPI dyagram in doc/ ! Fixed man page and html man page ArpON 1.54: =========== ! Fixed makefile ! Fixed network interface list errors ArpON 1.50: =========== ! Fixed Arp request Inbound bug in darpi_realtime_read_packets(), now it works very well :) ArpON 1.44: =========== + Added doc/ directory with SARPI and DARPI diagrams + Added pid file in /var/run/arpon.pid + Added LICENSE file ! Adjusted man page ArpON 1.40: =========== ! Fixed CPU usage, now arpon works well on many cpu architectures, 32 and 64 bit ArpON 1.30: =========== + Added support to pthreads for all platforms + Added real time support for BSD platforms + Added Sanitize environment from LD_PRELOAD attacks ArpON 1.20: =========== ! Linux platform: timeout now works both for ping to host and ping to broadcast ! Makefile now uses dynamic libraries linking ArpON 1.11: =========== + Added NetBSD platform support + Added OpenBSD platform support + Added man page + Added automatic device support in many features + Added CPU priority (TASK MODE) for real time work with nice values (-n, --nice option) for many CPU architectures (little/big endian with 32/64 bits) + Added Logging mode (LOG MODE) (-f, --log-file and -g, --log options) ! Linux platform: changed poll() with select() ! Adjusted arp_ping_set_timeout() ! Many define macro replaced by enum ! Adjusted output style ! Adjusted time with timezone in many features ! Adjusted help summary page ArpON 1.10: =========== ! First ArpON version ! ArpON-2.0/cmake_modules/000755 000765 000024 00000000000 11403231650 015604 5ustar00spikeystaff000000 000000 ArpON-2.0/cmake_uninstall.cmake.in000644 000765 000024 00000001654 11400024636 017563 0ustar00spikeystaff000000 000000 IF(NOT EXISTS "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt") MESSAGE(FATAL_ERROR "Cannot find install manifest: \"@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt\"") ENDIF(NOT EXISTS "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt") FILE(READ "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt" files) STRING(REGEX REPLACE "\n" ";" files "${files}") FOREACH(file ${files}) MESSAGE(STATUS "Uninstalling \"$ENV{DESTDIR}${file}\"") IF(EXISTS "$ENV{DESTDIR}${file}") EXEC_PROGRAM( "@CMAKE_COMMAND@" ARGS "-E remove \"$ENV{DESTDIR}${file}\"" OUTPUT_VARIABLE rm_out RETURN_VALUE rm_retval ) IF(NOT "${rm_retval}" STREQUAL 0) MESSAGE(FATAL_ERROR "Problem when removing \"$ENV{DESTDIR}${file}\"") ENDIF(NOT "${rm_retval}" STREQUAL 0) ELSE(EXISTS "$ENV{DESTDIR}${file}") MESSAGE(STATUS "File \"$ENV{DESTDIR}${file}\" does not exist.") ENDIF(EXISTS "$ENV{DESTDIR}${file}") ENDFOREACH(file) ArpON-2.0/CMakeLists.txt000644 000000 000000 00000010651 11406410763 015176 0ustar00rootwheel000000 000000 # CMakeLists.txt build arpon.c with cmake # # The following variables are set: # CMAKE_C_FLAGS - flags to add to the C compiler for build arpon # CMAKE_LIBS - set the library flags to add to the C compiler for build arpon # CMAKE_INCLUDE - set the include flags to add to the C compiler for build arpon # CMAKE_INSTALL_PREFIX - set the install prefix for arpon. By default # arpon will be installed to /usr/loca/ path. # # # Copyright 2010 zeld@freaknet.org # # Redistribution AND use is allowed according to the terms of the New # BSD license. cmake_minimum_required(VERSION 2.6) project(ArpON) set(AUTHOR "Andrea Di Pasquale" INTERNAL "Author") set(VERSION "2.0") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Werror -ggdb") set(CMAKE_LIBRARY_PATH /usr/lib/;/usr/local/lib/; /opt/local/lib/;/usr/local/lib/libnet11/; /usr/lib/libnet11/;/usr/lib/libnet113/; /usr/local/lib/libnet113/;/usr/lib/libnet-1.1/; /usr/local/lib/libnet-1.1/;/usr/pkg/lib/; /usr/pkg/lib/libnet11;${CMAKE_LIBRARY_PATH}) set(CMAKE_INCLUDE_PATH /usr/include/;/usr/local/include/; /opt/local/include/;/usr/local/include/libnet11/; /usr/include/libnet11/;/usr/include/libnet113/; /usr/local/include/libnet113/;/usr/include/libnet-1.1/; /usr/local/include/libnet-1.1/;/usr/pkg/include; /usr/pkg/include/libnet11;${CMAKE_INCLUDE_PATH}) set(CMAKE_INSTALL_PREFIX "/") include_directories("/usr/include") link_directories("/usr/lib") set(INCLUDE_DIR "/usr/include") set(LIB_DIR "/usr/lib") set(CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake_modules/") find_package(System) find_package(Pthread) find_package(DNET) find_package(NET) find_package(PCAP) add_subdirectory(src) add_subdirectory(man8) add_subdirectory(etc) configure_file("${CMAKE_CURRENT_SOURCE_DIR}/cmake_uninstall.cmake.in" "${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake" IMMEDIATE @ONLY) add_custom_target(uninstall "${CMAKE_COMMAND}" -P "${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake") set(MAJOR_VERSION 2) set(MINOR_VERSION 0) #set(PATCH_VERSION 0) set(ARPON_NAME "arpon") if(EXISTS "${CMAKE_ROOT}/Modules/CPack.cmake") include(InstallRequiredSystemLibraries) set(CPACK_GENERATOR "DEB;RPM;TBZ2;TGZ;STGZ") set(CPACK_PACKAGE_DESCRIPTION "ArpON (Arp handler inspectiON) is a portable handler daemon that make Arp secure in order to avoid Arp Spoofing/Poisoning & co. This is possible using two kinds of anti Arp Poisoning tecniques, the first is based on SARPI or 'Static Arp Inspection', the second on DARPI or 'Dynamic Arp Inspection' approach. Keep in mind other common tools fighting ARP poisoning usually limit their activity only to point out the problem instead of blocking it, ArpON does it using SARPI and DARPI policies. Finally you can use ArpON to pentest some switched/hubbed LAN with/without DHCP protocol, in fact you can disable the daemon in order to use the tools to poison the ARP Cache. Remember it doesn't affect the communication efficiency of the ARP pro‐tocol!") set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "ArpON is a portable handler daemon that make Arp secure in order to avoid Arp Spoofing/Poisoning & co.") set(CPACK_PACKAGE_VENDOR "zeld") set(CPACK_PACKAGE_CONTACT "zeld ") set(CPACK_PACKAGING_INSTALL_PREFIX "${CMAKE_INSTALL_PREFIX}") set(CPACK_PACKAGE_VERSION_MAJOR "${MAJOR_VERSION}") set(CPACK_PACKAGE_VERSION_MINOR "${MINOR_VERSION}") set(CPACK_PACKAGE_VERSION_PATCH "${PATCH_VERSION}") #set(CPACK_PACKAGE_FILE_NAME "${CMAKE_PROJECT_NAME}-${MAJOR_VERSION}.${MINOR_VERSION}.${PATCH_VERSION}") #set(CPACK_SOURCE_PACKAGE_FILE_NAME "${CMAKE_PROJECT_NAME}-${MAJOR_VERSION}.${MINOR_VERSION}.${PATCH_VERSION}") set(CPACK_PACKAGE_FILE_NAME "${CMAKE_PROJECT_NAME}-${MAJOR_VERSION}.${MINOR_VERSION}") set(CPACK_SOURCE_PACKAGE_FILE_NAME "${CMAKE_PROJECT_NAME}-${MAJOR_VERSION}.${MINOR_VERSION}") set(CPACK_DEBIAN_PACKAGE_DEPENDS "libc6 (>= 2.4), libdumbnet1, libnet1 (>= 1.1.2.1), libpcap0.8 (>= 0.9.3-1), lsb-base") set(CPACK_DEBIAN_PACKAGE_SECTION "universe/net") #set(CPACK_RPM_PACKAGE_LICENSE "BSD") #set(CPACK_RPM_PACKAGE_GROUP "Administration Tools") #set(CPACK_RPM_PACKAGE_REQUIRES "") set(CPACK_STRIP_FILES TRUE) set(CPACK_COMPONENTS_ALL Etcfile Man Application) include(CPack) else(EXISTS "${CMAKE_ROOT}/Modules/CPack.cmake") message(FATAL_ERROR "${CMAKE_ROOT}/Modules/CPack.cmake not found! Unable to make package.") endif(EXISTS "${CMAKE_ROOT}/Modules/CPack.cmake") ArpON-2.0/doc/000755 000765 000024 00000000000 11403231656 013547 5ustar00spikeystaff000000 000000 ArpON-2.0/etc/000755 000765 000024 00000000000 11406411423 013550 5ustar00spikeystaff000000 000000 ArpON-2.0/INSTALL000644 000765 000024 00000004471 11400045532 014032 0ustar00spikeystaff000000 000000 ArpON's install: ================ 1) Porting avaible; 2) General options; 3) Static linking; In order to use ArpON you need the following libraries installed in your system: - Pthread - Libpcap - LibNet 1.1 - LibDNet 1) Porting available ArpON is supported on all linux os, Mac OS X, FreeBSD, OpenBSD and NetBSD. There are two method of installation: - cmake method - Makefile method * Cmake method Cmake method can produce automatically the binary packages of debian/ubuntu deb, rpm, sh, tar.gz, tar.bz2 ,stgz To install arpon via cmake follow these commands as root: $ mkdir build $ cd build $ cmake .. $ make $ make install If you want personalize the compilation phase with your custom CFLAGS run cmake with: -DCMAKE_C_FLAGS="-your-personal-cflags" If you have problems with cmake test, run cmake by specifying the library and the include path where to search with: -DCMAKE_INCLUDE_PATH="/path/to/include/" -DCMAKE_LIBRARY_PATH="/path/to/include/" If you want to make a deb,rpm,tar.gz,tbz2,stgz package run after the "make" phase: $ fakeroot cpack . * Makefile method $ make For Linux users: $ make linux For Debian users: $ make debian For Gentoo users: $ make gentoo For Mac OS X users: $ make osx For FreeBSD users: $ make freebsd $ make freebsd_new For NetBSD users: $ make netbsd $ make netbsd_new For OpenBSD users: $ make openbsd $ make openbsd_new 2) General options: Clean with: $ make clean Install with: # sudo make install Or # make install Uninstall with # sudo make install Or # make uninstall Use with: # ./arpon Or # arpon 3) Static linking: ================== If you have problems with make, search the static linking libraries in: - /usr/lib - /usr/local/lib Later, search .a or .so or .dylib of - libpcap - libnet - libdnet Example path of static libraries in my OS system: - /usr/lib/libpcap.a - /usr/lib/libnet.a - /usr/local/lib/libdnet.a Later, open arpon's makefile and modify your OS gcc line. For example, in my OS (Linux) I modify his line From: gcc $(CFLAGS) $(LDFLAGS) $(LIBS_LINUX) -DLINUX -o $(EXEC) $(SOURCE) To: gcc $(CFLAGS) $(LDFLAGS) $(LIBS_LINUX) -DLINUX -o $(EXEC) $(SOURCE) /usr/lib/libpcap.a /usr/lib/libnet.a /usr/local/lib/libdnet.a Save and exit, go: $ make $ sudo make install ArpON-2.0/LICENSE000644 000765 000024 00000002652 11376556527 014034 0ustar00spikeystaff000000 000000 Copyright (C) 2008-2010 Andrea Di Pasquale All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice(s), this list of conditions and the following disclaimer as the first lines of this file unmodified other than the possible addition of one or more copyright notices. 2. Redistributions in binary form must reproduce the above copyright notice(s), this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ArpON-2.0/Makefile000755 000765 000024 00000006070 11377523307 014457 0ustar00spikeystaff000000 000000 SOURCE = src/arpon.c EXEC = src/arpon EXEC_FILE = arpon MAN = man8/arpon.8 FILE = etc/arpon.sarpi CFLAGS += -g -Wall -Werror LDFLAGS += LIBS_LINUX = -lpthread -lpcap -ldnet -lnet -L/usr/local/lib -I/usr/local/include LIBS_DEBIAN = -lpthread -lpcap -ldumbnet -lnet -L/usr/lib -I/usr/include LIBS_GENTOO = -lpthread -lpcap -ldnet -lnet -L/usr/lib -I/usr/include LIBS_OSX = -lpthread -lpcap -ldnet -lnet -L/opt/local/lib/ -I/opt/local/include/ LIBS_FREEBSD = -lpthread -lpcap -ldnet -lnet -L/usr/local/lib -I/usr/local/include -L/usr/local/lib/libnet11 -I/usr/local/include/libnet11 LIBS_FREEBSD_NEW = -lpthread -lpcap -ldnet -lnet -L/usr/local/lib -I/usr/local/include -L/usr/local/lib/libnet113 -I/usr/local/include/libnet113 LIBS_NETBSD = -lpthread -lpcap -ldnet -lnet -L/usr/local/lib -I/usr/local/include -L/usr/lib/libnet11 -I/usr/include/libnet11 LIBS_NETBSD_NEW = -lpthread -lpcap -ldnet -lnet -L/usr/pkg/lib -I/usr/pkg/include -L/usr/pkg/lib/libnet11 -I/usr/pkg/include/libnet11 LIBS_OPENBSD = -lpthread -lpcap -ldnet -lnet -L/usr/local/lib -I/usr/local/include -L/usr/lib/libnet11 -I/usr/include/libnet11 LIBS_OPENBSD_NEW = -lpthread -lpcap -ldnet -lnet -L/usr/local/lib -I/usr/local/include -L/usr/local/lib/libnet-1.1 -I/usr/local/include/libnet-1.1 arpon: @echo "" @echo " Portings avaible:" @echo "" @echo " - Linux run: make linux" @echo " - Linux Debian run: make debian" @echo " - Linux Gentoo run: make gentoo" @echo " - Mac OS X run: make osx" @echo " - FreeBSD run: make freebsd" @echo " - FreeBSD new run: make freebsd_new" @echo " - NetBSD run: make netbsd" @echo " - NetBSD new run: make netbsd_new" @echo " - OpenBSD run: make openbsd" @echo " - OpenBSD new run: make openbsd_new" @echo "" @echo " Have got problems? Read INSTALL file." @echo "" linux: $(SOURCE) gcc $(CFLAGS) $(LDFLAGS) $(LIBS_LINUX) -DLINUX -o $(EXEC) $(SOURCE) debian: $(SOURCE) gcc $(CFLAGS) $(LDFLAGS) $(LIBS_DEBIAN) -DLINUX -DDEBIAN -o $(EXEC) $(SOURCE) gentoo: $(SOURCE) gcc $(CFLAGS) $(LDFLAGS) $(LIBS_GENTOO) -DLINUX -o $(EXEC) $(SOURCE) osx: $(SOURCE) gcc $(CFLAGS) $(LDFLAGS) $(LIBS_OSX) -o $(EXEC) $(SOURCE) freebsd: $(SOURCE) gcc $(CFLAGS) $(LDFLAGS) $(LIBS_FREEBSD) -o $(EXEC) $(SOURCE) freebsd_new: $(SOURCE) gcc $(CFLAGS) $(LDFLAGS) $(LIBS_FREEBSD_NEW) -o $(EXEC) $(SOURCE) netbsd: $(SOURCE) gcc $(CFLAGS) $(LDFLAGS) $(LIBS_NETBSD) -DNETBSD -o $(EXEC) $(SOURCE) netbsd_new: $(SOURCE) gcc $(CFLAGS) $(LDFLAGS) $(LIBS_NETBSD_NEW) -DNETBSD -o $(EXEC) $(SOURCE) /usr/pkg/lib/libnet11/libnet.a openbsd: $(SOURCE) gcc $(CFLAGS) $(LDFLAGS) $(LIBS_OPENBSD) -DOPENBSD -o $(EXEC) $(SOURCE) openbsd_new: $(SOURCE) gcc $(CFLAGS) $(LDFLAGS) $(LIBS_OPENBSD_NEW) -DOPENBSD -o $(EXEC) $(SOURCE) clean: rm -f $(EXEC) install: cp $(EXEC) $(DESTDIR)/sbin cp $(FILE) $(DESTDIR)/etc cp $(MAN) $(DESTDIR)/usr/share/man/man8/ uninstall: rm -f $(DESTDIR)/sbin/$(EXEC_FILE) rm -f $(DESTDIR)/$(FILE) rm -f $(DESTDIR)/usr/share/man/$(MAN) .PHONY: arpon osx freebsd netbsd openbsd linux debian gentoo clean install uninstall ArpON-2.0/man8/000755 000765 000024 00000000000 11406411435 013643 5ustar00spikeystaff000000 000000 ArpON-2.0/src/000755 000765 000024 00000000000 11406411374 013571 5ustar00spikeystaff000000 000000 ArpON-2.0/src/arpon.c000644 000765 000024 00000242024 11406411311 015047 0ustar00spikeystaff000000 000000 /* * Copyright (C) 2008-2010 Andrea Di Pasquale * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice(s), this list of conditions and the following disclaimer as * the first lines of this file unmodified other than the possible * addition of one or more copyright notices. * 2. Redistributions in binary form must reproduce the above copyright * notice(s), this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) BE LIABLE FOR ANY * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH * DAMAGE. * * $ArpON: arpon.c,v 2.0 06/07/2010 15:38:40 Andrea Di Pasquale Exp $ */ #include #include #include #include #include #include #include #include #include #include #ifndef LINUX #include #endif #include #ifdef LINUX #include #endif #ifdef NETBSD #include #elif !defined OPENBSD #include #endif #ifdef LINUX #include #endif #ifdef OPENBSD #include #endif #include #include #ifdef DEBIAN #include #else #include #endif #include #include #include #include #include #include #include #include #include #include #include #include "include/queue.h" #if defined NETBSD || defined OPENBSD || defined LINUX #define octet ether_addr_octet #endif /* struct ether addr. */ #define ERROR(str) aprintf(stderr, 0, " ERROR: %s:%d %s.\n\n", \ __FILE__, __LINE__, str) enum iface_t { IFACE_MANUAL, IFACE_AUTO, IFACE_LIST, IFACE_NULL }; enum cache_t { SARPI_REFRESH, SARPI, DARPI_RESET, DARPI }; enum inspec_t { INSPEC_SARPI, INSPEC_DARPI, INSPEC_NULL }; struct iface { char dev[IF_NAMESIZE]; int dev_offset; struct ether_addr dev_mac; struct in_addr dev_inet4; struct in_addr dev_netmask; }; struct arp_header { /* * Arp header. */ struct arp_hdr ah_header; /* * Ethernet header. */ struct arp_ethip ah_addresses; }; /* * For libdnet. * Required for arp_t fileno. */ struct arp_handle { int fd; int seq; }; struct arp_cache { TAILQ_ENTRY(arp_cache) entries; struct ether_addr ac_mac; struct in_addr ac_ip; }; struct sarpi_cache { TAILQ_ENTRY(sarpi_cache) entries; struct ether_addr sc_mac; struct in_addr sc_ip; }; struct darpi_cache { TAILQ_ENTRY(darpi_cache) entries; struct in_addr dc_ip; }; static int task_mode_cpu_priority(int, int, int); static int task_mode_daemon(void); static FILE *task_mode_pid_open(void); static void task_mode_pid_close(FILE *); static int task_mode_log(void); static FILE *task_mode_log_open(void); static void task_mode_log_close(FILE *); static int iface_manager(void); static int iface_check_uplink(void); static void iface_check_uplink_thread_sigusr1(int); static void *iface_check_uplink_thread(void *); static void iface_set_name(char *); static void iface_unset_name(void); static int iface_check_datalink(char *); static int iface_check_running(void); static int iface_check_online(void); static void iface_check_online_packet(unsigned char *, const struct pcap_pkthdr *, const unsigned char *); static int iface_del_promisc(void); static int iface_get_mac_address(void); static int iface_get_inet4_addresses(void); static void iface_info_print(void); static arp_t *arp_cache_open(void); static void arp_cache_close(arp_t *); static int arp_cache_add(enum cache_t, char *); static int arp_cache_del(enum cache_t, char *); static int arp_cache_del_all(void); static int arp_cache_list_create(const struct arp_entry *, void *); static void arp_cache_list_destroy(void); static void sarpi_set_timeout(char *); static void sarpi_manager_thread_sigusr1(int); static void *sarpi_manager_thread(void *); static int sarpi_realtime(void); static void sarpi_realtime_thread_sigusr1(int); static void *sarpi_realtime_thread(void *); static pcap_t *sarpi_realtime_open_packets(void); static void sarpi_realtime_close_packets(pcap_t *); static void sarpi_realtime_read_packets(unsigned char *, const struct pcap_pkthdr *, const unsigned char *); static int sarpi_cache_file_restore(void); static int sarpi_cache_list_create(const struct arp_entry *, void *); static void sarpi_cache_list_refresh_thread_sigusr1(int); static void *sarpi_cache_list_refresh_thread(void *); static void sarpi_cache_list_destroy(void); static int darpi_set_timeout(char *); static void darpi_manager_thread_sigusr1(int); static void *darpi_manager_thread(void *); static int darpi_realtime(void); static void darpi_realtime_thread_sigusr1(int); static void *darpi_realtime_thread(void *); static pcap_t *darpi_realtime_open_packets(void); static void darpi_realtime_close_packets(pcap_t *); static void darpi_realtime_read_packets(unsigned char *, const struct pcap_pkthdr *, const unsigned char *); static int darpi_realtime_send_packet(struct ether_addr *, struct in_addr *); static int darpi_cache_list_create(struct in_addr *); static void darpi_cache_list_check_thread_sigusr1(int); static void *darpi_cache_list_check_thread(void *); static void darpi_cache_list_destroy(void); static void aprintf(FILE *, int, char *, ...); static void license(void); static void version(void); static void help(void); static int main_signal(void); static void *main_signal_thread(void *); static int main_start(void); static void main_stop(void); /* * iface informations. */ static struct iface dev; /* * Arp cache. */ static struct arp_cache *arp_cache_begin, *arp_cache_next, *arp_cache_pos; static TAILQ_HEAD(, arp_cache) arp_cache_head; /* * SARPI cache. */ static struct sarpi_cache *sarpi_cache_begin, *sarpi_cache_next, *sarpi_cache_pos; static TAILQ_HEAD(, sarpi_cache) sarpi_cache_head; /* * DARPI cache. */ static struct darpi_cache *darpi_cache_begin, *darpi_cache_next, *darpi_cache_pos; static TAILQ_HEAD(, darpi_cache) darpi_cache_head; /* * Signal handler. */ static sigset_t sigse; /* * Thread handler for: * thread[0] = Signal handler * thread[1] = SARPI/DARPI manager * thread[2] = Iface uplink handler * thread[3] = SARPI/DARPI * thread[4] = SARPI/DARPI. */ static pthread_t thread[5]; static pthread_attr_t join_attr, detach_attr; static pthread_rwlock_t rlock, wlock; /* * Default nice value for CPU priority. */ static int cpu_priority = 0; /* * Default pid file. */ static char *pid_file = "/var/run/arpon.pid"; static pid_t pid_main; /* * Default log file. */ static char *log_file = "/var/log/arpon.log"; /* * Default log mode, with -1 is off. */ static int log_mode = -1; /* * Default SARPI cache file. */ static char *sarpi_cache_file = "/etc/arpon.sarpi"; /* * Default Arp cache refresh timeout, 10 minuts. */ static int sarpi_timeout = 10; /* * Default DARPI cache entry timeout, 500 ms. */ static int darpi_timeout = 500; /* * Device name. */ static char *ddev = NULL; /* * Default Iface type. */ static enum iface_t dif = IFACE_NULL; /* * Default Inspection type. */ static enum inspec_t dinspec = INSPEC_NULL; /********************** * Task mode handler: * **********************/ /* * Sets CPU priority for who. */ static int task_mode_cpu_priority(int which, int who, int prio) { if (cpu_priority != 0) { if (setpriority(which, who, prio) < 0) { ERROR(strerror(errno)); return (-1); } } return (0); } /* * Demonize the process. */ static int task_mode_daemon(void) { struct stat stats; FILE *pid_fstream; int fd; if ((pid_fstream = task_mode_pid_open()) == NULL) { return (-1); } if (stat(pid_file, &stats) < 0) { aprintf(stderr, 0, " ERROR: %s\n\n", strerror(errno)); return (-1); } task_mode_pid_close(pid_fstream); if (S_ISREG(stats.st_mode) == 0) { aprintf(stderr, 0, " ERROR: %s is not a regular file.\n\n", pid_file); return (-1); } aprintf(stdout, 1, "Task is forking to background, using %s pid file...\n\n", pid_file); switch (fork()) { case (-1): ERROR(strerror(errno)); return (-1); case (0): break; default: exit(EXIT_SUCCESS); } if (setsid() < 0) { ERROR(strerror(errno)); return (-1); } /* * PID CPU Scheduling. */ if (task_mode_cpu_priority(PRIO_PROCESS, getpid(), cpu_priority) < 0) { return (-1); } /* * Write arpon.pid file. */ if ((pid_fstream = task_mode_pid_open()) == NULL) { kill(pid_main, SIGTERM); exit(EXIT_FAILURE); } fprintf(pid_fstream, "%d\n", (int)getpid()); fflush(pid_fstream); task_mode_pid_close(pid_fstream); if ((fd = open("/dev/null", O_RDWR, 0)) < 0) { ERROR(strerror(errno)); return (-1); } dup2(fd, STDIN_FILENO); dup2(fd, STDOUT_FILENO); if (fd > 2) { close(fd); } return (0); } /* * Open pid file. */ static FILE * task_mode_pid_open(void) { FILE *pid_fstream; if ((pid_fstream = fopen(pid_file, "w+")) == NULL) { aprintf(stderr, 0, " ERROR: %s: %s\n\n", pid_file, strerror(errno)); return (NULL); } return (pid_fstream); } /* * Close pid file. */ static void task_mode_pid_close(FILE *pid_fstream) { if (pid_fstream != NULL) { fclose(pid_fstream); } } /* * Logging mode. */ static int task_mode_log(void) { struct stat stats; FILE *log_fstream; if ((log_fstream = task_mode_log_open()) == NULL) { return (-1); } if (stat(log_file, &stats) < 0) { aprintf(stderr, 0, " ERROR: %s: %s\n\n", log_file, strerror(errno)); return (-1); } task_mode_log_close(log_fstream); if (S_ISREG(stats.st_mode) == 0) { aprintf(stderr, 0, " ERROR: %s is not a regular file.\n\n", log_file); return (-1); } /* * Logging mode: * 0: on * -1: off. */ log_mode = 0; return (0); } /* * Open log file. */ static FILE * task_mode_log_open(void) { FILE *log_fstream; if ((log_fstream = fopen(log_file, "a+")) == NULL) { aprintf(stderr, 0, " ERROR: %s: %s\n\n", log_file, strerror(errno)); return (NULL); } return (log_fstream); } /* * Close log file. */ static void task_mode_log_close(FILE *log_fstream) { if (log_fstream != NULL) { fclose(log_fstream); } } /******************* * iface Handler: * *******************/ /* * Handles the network iface with following modes: * - Manual, * - Automatic (First iface that can to be used), * - Listing eventual network ifaces. * - boot/unplug/hibernation/suspension interface * * Doing the following operations: * - Verifying Datalink * - Selecting the network iface to be used * - Verifying iface running * - Veryfying iface online ready * - Putting down the promiscue flag if found set * - Reading MAC Address * - Reading IP, netmask inet4 addresses * - Printing out network ifaces dates. */ static int iface_manager(void) { char errbuf[PCAP_ERRBUF_SIZE]; pcap_if_t *ifc; if (pcap_findalldevs(&ifc, errbuf) < 0) { ERROR(errbuf); return (-1); } /* * For SARPI and DARPI. */ if (dif == IFACE_NULL) { dif = IFACE_AUTO; } for (; ifc != NULL; ifc = ifc->next) { switch (dif) { case (IFACE_MANUAL): if (strncmp(ddev, ifc->name, IF_NAMESIZE) == 0) { if ((ifc->flags & PCAP_IF_LOOPBACK) == 0) { if (iface_check_datalink(ifc->name) < 0) { aprintf(stderr, 0, " ERROR: %s interface's datalink " \ "is not supported!\n\n", ddev); pcap_freealldevs(ifc); return (-1); } iface_set_name(ifc->name); if (iface_del_promisc() < 0 || iface_get_mac_address() < 0 || iface_get_inet4_addresses() < 0) { pcap_freealldevs(ifc); return (-1); } pcap_freealldevs(ifc); return (0); } else { aprintf(stderr, 0, " ERROR: %s interface is not " \ "supported!\n\n", ddev); pcap_freealldevs(ifc); return (-1); } } break; case (IFACE_AUTO): if ((ifc->flags & PCAP_IF_LOOPBACK) == 0) { if (iface_check_datalink(ifc->name) < 0) { break; } iface_set_name(ifc->name); if (iface_del_promisc() < 0 || iface_get_mac_address() < 0 || iface_get_inet4_addresses() < 0) { iface_unset_name(); break; } pcap_freealldevs(ifc); return (0); } break; case (IFACE_LIST): if ((ifc->flags & PCAP_IF_LOOPBACK) == 0) { if (iface_check_datalink(ifc->name) < 0) { break; } iface_set_name(ifc->name); if (iface_del_promisc() < 0 || iface_get_mac_address() < 0 || iface_get_inet4_addresses() < 0) { pcap_freealldevs(ifc); return (-1); } } break; default: break; } } if (dif == IFACE_MANUAL) { if (strncmp(ddev, dev.dev, IF_NAMESIZE) != 0) { aprintf(stderr, 0, " ERROR: %s interface not found!\n\n", ddev); pcap_freealldevs(ifc); return (-1); } } else if (dif == IFACE_AUTO) { if (dev.dev[0] == '\0') { aprintf(stderr, 0, " ERROR: Interface not found!\n\n"); pcap_freealldevs(ifc); return (-1); } } pcap_freealldevs(ifc); return (0); } /* * Check automatically iface uplink: * - boot * - unplug ethernet/wireless * - hibernation * - suspension */ static int iface_check_uplink(void) { pthread_attr_init(&join_attr); pthread_attr_setschedpolicy(&join_attr, SCHED_RR); /* * Thread 3 joinabled, checks automatically iface uplink. */ if (pthread_create(&thread[2], &join_attr, iface_check_uplink_thread, (void *) NULL) != 0) { ERROR(strerror(errno)); pthread_attr_destroy(&join_attr); return (-1); } pthread_attr_destroy(&join_attr); return (0); } /* * Iface uplink signal handler. */ static void iface_check_uplink_thread_sigusr1(int sig) { pthread_exit((void *) 0); } /* * Check automatically iface uplink. * If uplink is down stops daemon, waits uplink up * and restart the daemon. */ static void * iface_check_uplink_thread(void *arg) { struct sigaction saction; int ret, ret2; #ifdef NETBSD saction.sa_flags = 0; #endif saction.sa_handler = iface_check_uplink_thread_sigusr1; if (sigaction(SIGUSR1, &saction, NULL) < 0) { ERROR(strerror(errno)); pthread_exit((void *) -1); } while (1) { if ((ret = iface_check_running()) < 0) { pthread_exit((void *) -1); } else if (ret > 0) { /* * iface down/suspend. */ while (1) { if ((ret2 = iface_check_running()) < 0) { pthread_exit((void *) -1); } else if (ret2 == 0) { /* * Iface up/restore. * Reboot the daemon. */ kill(0, SIGHUP); break; } /* * Check each 1 second. */ #ifdef NETBSD sleep(1); #else usleep(1000000); #endif } } /* * Iface up. * Check each 1 second. */ #ifdef NETBSD sleep(1); #else usleep(1000000); #endif } pthread_exit((void *) 0); } /* * Sets the network iface. */ static void iface_set_name(char *name) { memset(dev.dev, '\0', IF_NAMESIZE); strncpy(dev.dev, name, IF_NAMESIZE); } /* * Unset the network iface. */ static void iface_unset_name(void) { memset(dev.dev, '\0', IF_NAMESIZE); } /* * Checks the datalink. Accepting EN10MB only * (and so only ethernet and wireless ifaces). */ static int iface_check_datalink(char *devarg) { char errbuf[PCAP_ERRBUF_SIZE]; pcap_t *pcap; int datalink; if ((pcap = pcap_open_live(devarg, BUFSIZ, 0, 0, errbuf)) == NULL) { ERROR(errbuf); return (-1); } if ((datalink = pcap_datalink(pcap)) < 0) { ERROR(pcap_geterr(pcap)); return (-1); } /* * Set network offset if it is * ethernet network iface. */ if (datalink == DLT_EN10MB) { dev.dev_offset = 14; pcap_close(pcap); return (0); } pcap_close(pcap); return (-1); } /* * Checks if iface is running. */ static int iface_check_running(void) { struct ifreq ifr; int sd; if ((sd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { ERROR(strerror(errno)); return (-1); } memset(ifr.ifr_name, '\0', IF_NAMESIZE); strncpy(ifr.ifr_name, dev.dev, IF_NAMESIZE); if (ioctl(sd, SIOCGIFFLAGS, &ifr) < 0) { ERROR(strerror(errno)); close(sd); return (-1); } /* * iface is not running. */ if ((ifr.ifr_flags & IFF_RUNNING) == 0) { close(sd); return (1); } /* * iface running. */ close(sd); return (0); } /* * Wait first packet for online check. */ static int iface_check_online(void) { struct bpf_program compiled_filter; char errbuf[PCAP_ERRBUF_SIZE], *filter = "arp"; pcap_t *pcap; int ret; #ifndef LINUX unsigned int op = 1; #endif if ((pcap = pcap_open_live(dev.dev, BUFSIZ, 0, 0, errbuf)) == NULL) { ERROR(errbuf); return (-1); } #ifndef LINUX /* * BSD, differently from linux does not * support automatic socket soft real time * (Linux Socket Filter). * Therefore on BSD platform it's necessary * to use this I/O Control. */ if (ioctl(pcap_fileno(pcap), BIOCIMMEDIATE, &op) < 0) { ERROR(strerror(errno)); pcap_close(pcap); return (-1); } #endif if (pcap_compile(pcap, &compiled_filter, filter, 0, dev.dev_netmask.s_addr) < 0) { ERROR(pcap_geterr(pcap)); pcap_close(pcap); return (-1); } if (pcap_setfilter(pcap, &compiled_filter) < 0) { ERROR(pcap_geterr(pcap)); pcap_close(pcap); return (-1); } /* * Wait first packet. */ if ((ret = pcap_loop(pcap, 1, iface_check_online_packet, NULL)) < 0) { pcap_freecode(&compiled_filter); switch (ret) { case (-1): ERROR(pcap_geterr(pcap)); pcap_close(pcap); return (-1); case (-2): default: pcap_close(pcap); /* * Offline. */ return (1); } } /* * Online. */ pcap_freecode(&compiled_filter); pcap_close(pcap); return (0); } /* * Wait an Arp packet. */ static void iface_check_online_packet(unsigned char *arg, const struct pcap_pkthdr *header, const unsigned char *packet) { /* * Arp traffic is ok. */ return; } /* * Putting down the promiscue flag if * found set in network iface. */ static int iface_del_promisc(void) { struct ifreq ifr; int sd; if ((sd = socket(AF_INET, SOCK_STREAM, 0)) < 0) { ERROR(strerror(errno)); return (-1); } strncpy(ifr.ifr_name, dev.dev, sizeof(char) * IF_NAMESIZE); ifr.ifr_name[sizeof(char) * strlen(ifr.ifr_name)] = '\0'; if (ioctl(sd, SIOCGIFFLAGS, &ifr) < 0) { ERROR(strerror(errno)); close(sd); return (-1); } if (ifr.ifr_flags & IFF_PROMISC) { /* * Remove Promisc flag */ ifr.ifr_flags &= ~IFF_PROMISC; if (ioctl(sd, SIOCSIFFLAGS, &ifr) < 0) { ERROR(strerror(errno)); close(sd); return (-1); } } close(sd); return (0); } /* * Reading network ifaces hw-MAC address. */ static int iface_get_mac_address(void) { eth_addr_t mac; eth_t *if_eth; int i; if ((if_eth = eth_open(dev.dev)) == NULL) { ERROR(strerror(errno)); return (-1); } if (eth_get(if_eth, &mac) < 0) { ERROR(strerror(errno)); eth_close(if_eth); return (-1); } for (i = 0; i < ETHER_ADDR_LEN; i++) { dev.dev_mac.octet[i] = mac.data[i]; } eth_close(if_eth); return (0); } /* * Checks and saves IPv4 and Netmask network adresses. */ static int iface_get_inet4_addresses(void) { char errbuf_lnet[LIBNET_ERRBUF_SIZE], errbuf_pcap[PCAP_ERRBUF_SIZE]; libnet_t *lnet; bpf_u_int32 network; int ret, ret2, state = 0; /* * Get netmask and IPv4 addresses. * Case of errors, it waits: * - running iface * - IPv4 assigned * - online iface. */ while (1) { dev.dev_netmask.s_addr = 0; if (pcap_lookupnet(dev.dev, &network, &(dev.dev_netmask.s_addr), errbuf_pcap) < 0) { if (dif == IFACE_LIST) { return (0); } else { if (errno == EADDRNOTAVAIL) { /* * Use the state for one first WARNING print. */ if (state == 0) { aprintf(stdout, 1, "WARNING: %s\n", errbuf_pcap); if (dinspec == INSPEC_NULL) { exit(EXIT_FAILURE); } state = 1; } continue; } else { if (dif != IFACE_AUTO) { ERROR(errbuf_pcap); } return (-1); } } } else { /* Checks iface running. * Return: * -1: Error * 0: iface running * 1: iface is not running. */ if ((ret = iface_check_running()) < 0) { return (-1); } /* * iface running. */ else if (ret == 0) { /* * Check iface online with * first packet received. */ if (dif != IFACE_LIST && dinspec != INSPEC_NULL) { aprintf(stdout, 1, "Wait link connection on %s...\n", dev.dev); while (1) { /* * Check iface online. * Return: * -1: Error * 0: Online * 1: Offline */ if ((ret2 = iface_check_online()) < 0) { return (-1); } else if (ret2 == 1) { sleep(1); continue; } else { break; } } } /* * Get IPv4 address. */ if ((lnet = libnet_init(LIBNET_LINK, dev.dev, errbuf_lnet)) == NULL) { if (dif == IFACE_LIST) { return (0); } else { ERROR(errbuf_lnet); return (-1); } } dev.dev_inet4.s_addr = 0; if ((dev.dev_inet4.s_addr = libnet_get_ipaddr4(lnet)) < 0) { ERROR(libnet_geterror(lnet)); return (-1); } libnet_destroy(lnet); break; } /* * iface is not running. */ } /* * Check each 1 second. */ sleep(1); } if (dinspec == INSPEC_NULL) { aprintf(stdout, 1, "dev(%s) ", dev.dev); aprintf(stdout, 0, "inet(%s) ", inet_ntoa(dev.dev_inet4)); aprintf(stdout, 0, "hw(%s)\n", ether_ntoa(&(dev.dev_mac))); switch (dif) { case (IFACE_MANUAL): case (IFACE_AUTO): aprintf(stdout, 0, "\n"); break; case (IFACE_LIST): case (IFACE_NULL): break; } } return (0); } /* * Prints network ifaces informations. * For SARPI and DARPI. */ static void iface_info_print(void) { switch (dinspec) { case (INSPEC_SARPI): aprintf(stdout, 1, "SARPI on "); break; case (INSPEC_DARPI): aprintf(stdout, 1, "DARPI on "); break; case (INSPEC_NULL): break; } aprintf(stdout, 0, "dev(%s) ", dev.dev); aprintf(stdout, 0, "inet(%s) ", inet_ntoa(dev.dev_inet4)); aprintf(stdout, 0, "hw(%s)\n", ether_ntoa(&(dev.dev_mac))); } /******************** * Arp Cache handler: ********************/ /* * Open Arp cache. */ static arp_t * arp_cache_open(void) { arp_t *arp; if ((arp = arp_open()) == NULL) { ERROR(strerror(errno)); return (NULL); } return (arp); } /* * Close Arp cache. */ static void arp_cache_close(arp_t *arp) { arp_close(arp); } /* * Adds Arp cache entry. */ static int arp_cache_add(enum cache_t type, char *arg) { struct arp_entry entry; char c_mac[18], c_ip[16]; arp_t *arp; if ((arp = arp_cache_open()) == NULL) { return (-1); } sscanf(arg, "%15s %17s", c_ip, c_mac); c_mac[sizeof(char) * strlen(c_mac)] = '\0'; c_ip[sizeof(char) * strlen(c_ip)] = '\0'; if (addr_aton(c_mac, &entry.arp_ha) < 0) { ERROR(strerror(errno)); arp_cache_close(arp); return (-1); } if (addr_aton(c_ip, &entry.arp_pa) < 0) { ERROR(strerror(errno)); arp_cache_close(arp); return (-1); } arp_add(arp, &entry); /* * These outputs depends by asked functionally. */ switch (type) { case (SARPI_REFRESH): case (SARPI): case (DARPI): aprintf(stdout, 0, "%s -> %s\n", c_ip, c_mac); break; case (DARPI_RESET): break; } arp_cache_close(arp); return (0); } /* * Search entry in Arp cache, if is found it will delete. */ static int arp_cache_del(enum cache_t type, char *arg) { struct arp_entry entry; arp_t *arp; int i; if ((arp = arp_cache_open()) == NULL) { return (-1); } /* * Read Arp cache. */ if (arp_loop(arp, arp_cache_list_create, NULL) < 0) { arp_cache_close(arp); return (-1); } /* * Search IPv4 or hw-MAC in Arp Cache. */ TAILQ_FOREACH(arp_cache_pos, &arp_cache_head, entries) { if (strcmp(arg, inet_ntoa(arp_cache_pos->ac_ip)) == 0 || strcmp(arg, ether_ntoa(&arp_cache_pos->ac_mac)) == 0) { for (i = 0; i < ETHER_ADDR_LEN; i++) { entry.arp_ha.addr_eth.data[i] = arp_cache_pos->ac_mac.octet[i]; } if (addr_aton(inet_ntoa(arp_cache_pos->ac_ip), &entry.arp_pa) < 0) { ERROR(strerror(errno)); arp_cache_list_destroy(); arp_cache_close(arp); return (-1); } arp_delete(arp, &entry); /* * These output depends by asked functionally. */ switch (type) { case (SARPI_REFRESH): case (SARPI): case (DARPI_RESET): break; case (DARPI): aprintf(stdout, 0, "%s -> %s\n", inet_ntoa(arp_cache_pos->ac_ip), ether_ntoa(&arp_cache_pos->ac_mac)); break; } arp_cache_list_destroy(); arp_cache_close(arp); return (0); } } if (type == DARPI) { aprintf(stdout, 0, "%s\n", arg); arp_cache_list_destroy(); arp_cache_close(arp); return (0); } aprintf(stderr, 0, " ERROR: %s entry not found!\n\n", arg); arp_cache_list_destroy(); arp_cache_close(arp); return (-1); } /* * Delete all found entries in the Arp * cache reading Arp cache tail. */ static int arp_cache_del_all(void) { struct arp_entry entry; arp_t *arp; int i, j = 1; if ((arp = arp_cache_open()) == NULL) { return (-1); } /* * Read Arp cache. */ if (arp_loop(arp, arp_cache_list_create, NULL) < 0) { arp_cache_close(arp); return (-1); } TAILQ_FOREACH(arp_cache_pos, &arp_cache_head, entries) { for (i = 0; i < ETHER_ADDR_LEN; i++) { entry.arp_ha.addr_eth.data[i] = arp_cache_pos->ac_mac.octet[i]; } if (addr_aton(inet_ntoa(arp_cache_pos->ac_ip), &entry.arp_pa) < 0) { ERROR(strerror(errno)); arp_cache_list_destroy(); arp_cache_close(arp); return (-1); } arp_delete(arp, &entry); aprintf(stdout, 1, "%d) %15s -> %17s\n", j++, inet_ntoa(arp_cache_pos->ac_ip), ether_ntoa(&arp_cache_pos->ac_mac)); } arp_cache_list_destroy(); arp_cache_close(arp); return (0); } /* * Create Arp cache tail using one entry or it adds simply a new entry. */ static int arp_cache_list_create(const struct arp_entry *entry, void *arg) { struct ether_addr mac; struct in_addr ip; register int i; for (i = 0; i < ETHER_ADDR_LEN; i++) { mac.octet[i] = entry->arp_ha.addr_eth.data[i]; } ip.s_addr = entry->arp_pa.addr_ip; if (arp_cache_begin == NULL) { TAILQ_INIT(&arp_cache_head); if ((arp_cache_begin = malloc(sizeof(struct arp_cache))) == NULL) { ERROR(strerror(errno)); return (-1); } memcpy(&arp_cache_begin->ac_mac, &mac, sizeof(mac)); memcpy(&arp_cache_begin->ac_ip, &ip, sizeof(ip)); TAILQ_INSERT_HEAD(&arp_cache_head, arp_cache_begin, entries); } else { if ((arp_cache_next = malloc(sizeof(struct arp_cache))) == NULL) { ERROR(strerror(errno)); return (-1); } memcpy(&arp_cache_next->ac_mac, &mac, sizeof(mac)); memcpy(&arp_cache_next->ac_ip, &ip, sizeof(ip)); TAILQ_INSERT_TAIL(&arp_cache_head, arp_cache_next, entries); } return (0); } /* * Destroy Arp cache tail. */ static void arp_cache_list_destroy(void) { while (TAILQ_EMPTY(&arp_cache_head) == 0) { arp_cache_pos = TAILQ_FIRST(&arp_cache_head); TAILQ_REMOVE(&arp_cache_head, arp_cache_pos, entries); free(arp_cache_pos); } } /****************** * SARPI handler: * ******************/ /* * Sets Arp cache timeout for automatic update. */ static void sarpi_set_timeout(char *timeout) { sarpi_timeout = atoi(timeout); } /* * SARPI manager signal handler. */ static void sarpi_manager_thread_sigusr1(int sig) { sarpi_cache_list_destroy(); pthread_exit((void *) 0); } /* * Handles SARPI through two thread for parallelism: * - 1: Update automatically the Arp cache * - 2: Works in soft real time, in other words it * listens to the inbound/outbound arp packets. */ static void * sarpi_manager_thread(void *arg) { struct sigaction saction; #ifdef NETBSD saction.sa_flags = 0; #endif saction.sa_handler = sarpi_manager_thread_sigusr1; if (sigaction(SIGUSR1, &saction, NULL) < 0) { ERROR(strerror(errno)); pthread_exit((void *) -1); } /* * Iface work. */ if (iface_manager() < 0) { pthread_exit((void *) -1); } if (iface_check_uplink() < 0) { pthread_exit((void *) -1); } iface_info_print(); /* * PID Parent CPU Scheduling. */ if (task_mode_cpu_priority(PRIO_PROCESS, getpid(), cpu_priority) < 0) { pthread_exit((void *) -1); } pthread_rwlock_init(&rlock, NULL); pthread_rwlock_init(&wlock, NULL); /* * Arp Cache entries protected from file. */ if (sarpi_cache_file_restore() < 0) { exit(-1); } pthread_attr_init(&detach_attr); pthread_attr_setdetachstate(&detach_attr, PTHREAD_CREATE_DETACHED); pthread_attr_setschedpolicy(&detach_attr, SCHED_RR); /* * Thread 4 detached, update automatically the Arp cache. */ if (pthread_create(&thread[3], &detach_attr, sarpi_cache_list_refresh_thread, (void *) NULL) != 0) { ERROR(strerror(errno)); sarpi_cache_list_destroy(); pthread_exit((void *) -1); } /* * Thread 5 detached, realtime inbound/outbound work. */ if (sarpi_realtime() < 0) { sarpi_cache_list_destroy(); pthread_exit((void *) -1); } pthread_exit((void *) 0); } /* * SARPI Realtime, process Arp reply * inbound/outbound Arp packets. */ static int sarpi_realtime(void) { aprintf(stdout, 1, "Arp Cache refresh timeout: %d %s\n", sarpi_timeout, sarpi_timeout == 1 ? "minut." : "minuts."); aprintf(stdout, 1, "Realtime Protect actived!\n"); pthread_attr_init(&detach_attr); pthread_attr_setdetachstate(&detach_attr, PTHREAD_CREATE_DETACHED); pthread_attr_setschedpolicy(&detach_attr, SCHED_RR); /* * Thread 5 detached, Works in soft real time, in other * words it listens to the inbound/outbound Arp packets. */ if (pthread_create(&thread[4], &detach_attr, sarpi_realtime_thread, (void *) NULL) != 0) { ERROR(strerror(errno)); return (-1); } pthread_attr_destroy(&detach_attr); return (0); } /* * SARPI realtime signal handler. */ static void sarpi_realtime_thread_sigusr1(int sig) { pthread_exit((void *) 0); } /* * Use thread for non blocking to pcap_loop(). */ static void * sarpi_realtime_thread(void *arg) { struct sigaction saction; pcap_t *pcap; #ifdef NETBSD saction.sa_flags = 0; #endif saction.sa_handler = sarpi_realtime_thread_sigusr1; if (sigaction(SIGUSR1, &saction, NULL) < 0) { ERROR(strerror(errno)); pthread_exit((void *) -1); } if ((pcap = sarpi_realtime_open_packets()) == NULL) { pthread_exit((void *) -1); } while (1) { if (pcap_loop(pcap, 1, sarpi_realtime_read_packets, NULL) < 0) { ERROR(pcap_geterr(pcap)); sarpi_realtime_close_packets(pcap); pthread_exit((void *) -1); } } sarpi_realtime_close_packets(pcap); pthread_exit((void *) 0); } /* * Open pcap file descriptor. */ static pcap_t * sarpi_realtime_open_packets(void) { struct bpf_program compiled_filter; char errbuf[PCAP_ERRBUF_SIZE], *filter = "arp"; pcap_t *pcap; #ifndef LINUX unsigned int op = 1; #endif if ((pcap = pcap_open_live(dev.dev, BUFSIZ, 0, 0, errbuf)) == NULL) { ERROR(errbuf); return (NULL); } #ifndef LINUX /* * BSD, differently from linux does not * support automatic socket soft real time * (Linux Socket Filter). * Therefore on BSD platform it's necessary * to use this I/O Control. */ if (ioctl(pcap_fileno(pcap), BIOCIMMEDIATE, &op) < 0) { ERROR(strerror(errno)); return (NULL); } #endif if (pcap_compile(pcap, &compiled_filter, filter, 0, dev.dev_netmask.s_addr) < 0) { ERROR(pcap_geterr(pcap)); sarpi_realtime_close_packets(pcap); return (NULL); } if (pcap_setfilter(pcap, &compiled_filter) < 0) { ERROR(pcap_geterr(pcap)); sarpi_realtime_close_packets(pcap); return (NULL); } pcap_freecode(&compiled_filter); return (pcap); } /* * Close pcap file descriptor. */ static void sarpi_realtime_close_packets(pcap_t *pcap) { pcap_close(pcap); } /* * Reads inbound/outbound packets such as: * - Arp reply/request packets * (it checks destionation/source address). * If Arp reply/request's data like addresses * IPv4 and MAC match a static entry of Arp * cache protected by SARPI, update the * entry using the static one. */ static void sarpi_realtime_read_packets(unsigned char *arg, const struct pcap_pkthdr *header, const unsigned char *packet) { struct ether_addr src_mac, dst_mac; struct arp_header *arp_packet; char c_src_ip[16], c_src_mac[18], c_dst_ip[16], c_dst_mac[18], c_ap_ip[16], entry[34]; int i; /* * Arp Packet. */ arp_packet = (struct arp_header *) (packet + dev.dev_offset); /* * Convert the source MAC/IPv4 to string. */ snprintf(c_src_ip, 16, "%d.%d.%d.%d", arp_packet->ah_addresses.ar_spa[0], arp_packet->ah_addresses.ar_spa[1], arp_packet->ah_addresses.ar_spa[2], arp_packet->ah_addresses.ar_spa[3]); for (i = 0; i < ETHER_ADDR_LEN; i++) { src_mac.octet[i] = arp_packet->ah_addresses.ar_sha[i]; } strncpy(c_src_mac, ether_ntoa(&src_mac), sizeof(char) * 18); c_src_mac[sizeof(char) * strlen(c_src_mac)] = '\0'; /* * Convert the destination MAC/IPv4 to string */ snprintf(c_dst_ip, 16, "%d.%d.%d.%d", arp_packet->ah_addresses.ar_tpa[0], arp_packet->ah_addresses.ar_tpa[1], arp_packet->ah_addresses.ar_tpa[2], arp_packet->ah_addresses.ar_tpa[3]); for (i = 0; i < ETHER_ADDR_LEN; i++) { dst_mac.octet[i] = arp_packet->ah_addresses.ar_tha[i]; } strncpy(c_dst_mac, ether_ntoa(&dst_mac), sizeof(char) * 18); c_dst_mac[sizeof(char) * strlen(c_dst_mac)] = '\0'; /* * In request, possible source address poisoned. * In reply, possible Arp Gratuitous for Arp poisoning. */ if (ntohs(arp_packet->ah_header.ar_op) == ARP_OP_REPLY || ntohs(arp_packet->ah_header.ar_op) == ARP_OP_REQUEST) { /* * Check if we are the destionation address. */ if (strcmp(c_dst_ip, inet_ntoa(dev.dev_inet4)) == 0) { /* * Search Arp reply/request source in SARPI (Arp cache) entries. */ TAILQ_FOREACH(sarpi_cache_pos, &sarpi_cache_head, entries) { /* * Convert MAC/IPv4 to string form. */ memset(c_ap_ip, '\0', sizeof(char) * 16); strncpy(c_ap_ip, inet_ntoa(sarpi_cache_pos->sc_ip), sizeof(char) * 16); c_ap_ip[sizeof(char) * strlen(c_ap_ip)] = '\0'; /* * In request, possible source address poisoned. * In reply, possible Arp Gratuitous for Arp poisoning. * Check if source is found in SARPI Cache. */ if (strcmp(c_src_ip, c_ap_ip) == 0) { /* * Source is Found! We reset static entry. */ switch (ntohs(arp_packet->ah_header.ar_op)) { case (ARP_OP_REPLY): aprintf(stdout, 1, "Reply << Refresh entry "); break; case (ARP_OP_REQUEST): aprintf(stdout, 1, "Request << Refresh entry "); break; } /* * Refresh static Arp Cache entry. */ snprintf(entry, 34, "%15s %17s", inet_ntoa(sarpi_cache_pos->sc_ip), ether_ntoa(&(sarpi_cache_pos->sc_mac))); entry[strlen(entry)] = '\0'; if (arp_cache_add(SARPI, entry) < 0) { exit(EXIT_FAILURE); } return; } } /* * In request, possible source address poisoned. * In reply, possible Arp Gratuitous for Arp poisoning. * Source is not found in SARPI cache. * This entry is not protected by SARPI before * this is not present in SARPI cache. */ switch (ntohs(arp_packet->ah_header.ar_op)) { case (ARP_OP_REPLY): aprintf(stdout, 1, "Reply << Ignore entry "); break; case (ARP_OP_REQUEST): aprintf(stdout, 1, "Request << Ignore entry "); break; } aprintf(stdout, 0, "%s -> %s\n", c_src_ip, c_src_mac); } /* * Check if we are the source address. */ else if (strcmp(c_src_mac, ether_ntoa(&(dev.dev_mac))) == 0 && strcmp(c_src_ip, inet_ntoa(dev.dev_inet4)) == 0) { switch (ntohs(arp_packet->ah_header.ar_op)) { case (ARP_OP_REPLY): aprintf(stdout, 1, "Reply >> Send to "); break; case (ARP_OP_REQUEST): aprintf(stdout, 1, "Request >> Send to "); break; } aprintf(stdout, 0, "%s -> %s\n", c_dst_ip, c_dst_mac); } } } /* * Sets static Arp cache entries from file. * Parsing of example: * * # Example of sarpi.cache * # * 192.168.1.1 aa:bb:cc:dd:ee:ff * ... */ static int sarpi_cache_file_restore(void) { struct addr aip, amac; struct arp_entry entry; char buf[100], ip[16], mac[18]; FILE *fd; int i, j; if ((fd = fopen(sarpi_cache_file, "r")) == NULL) { aprintf(stderr, 0, "\n ERROR: Configure static " \ "Arp Cache entries in %s!\n\n", sarpi_cache_file); return (-1); } aprintf(stdout, 1, "Protects these Arp Cache's entries:\n"); for (i = 1, j = 1; feof(fd) == 0; i++) { if (fgets(buf, 100, fd) == NULL) { break; } /* * Comment or new line. */ if (buf[0] == '#' || buf[0] == '\n') { continue; } /* * Space line and Tab line with no entry. */ if (buf[0] == ' ' || buf[0] == '\t') { if (buf[1] == '#' || buf[1] == '\n' || buf[1] == ' ' || buf[1] == '\t') continue; } memset(ip, '\0', 16); memset(mac, '\0', 18); sscanf(buf, "%15s %17s", ip, mac); if (addr_pton(ip, &aip) < 0) { aprintf(stderr, 0, "\n ERROR: " "It is not IPv4. Reconfigure %s:%d line!\n\n", sarpi_cache_file, i); fclose(fd); return (-1); } else if (addr_pton(mac, &amac) < 0) { aprintf(stderr, 0, "\n ERROR: " "It is not Mac-hw. Reconfigure %s:%d line!\n\n", sarpi_cache_file, i); fclose(fd); return (-1); } aprintf(stdout, 1, "%d) %15s -> %17s\n", j++, ip, mac); memcpy(&(entry.arp_pa), &aip, sizeof(aip)); memcpy(&(entry.arp_ha), &amac, sizeof(amac)); if (sarpi_cache_list_create(&entry, NULL) < 0) { fclose(fd); return (-1); } } aprintf(stdout, 1, "Arp Cache restore from %s...\n", sarpi_cache_file); fclose(fd); return (0); } /* * Adds SARPI cache tail. */ static int sarpi_cache_list_create(const struct arp_entry *entry, void *arg) { struct ether_addr mac; struct in_addr ip; int i; for (i = 0; i < ETHER_ADDR_LEN; i++) { mac.octet[i] = entry->arp_ha.addr_eth.data[i]; } ip.s_addr = entry->arp_pa.addr_ip; pthread_rwlock_wrlock(&wlock); if (sarpi_cache_begin == NULL) { TAILQ_INIT(&sarpi_cache_head); if ((sarpi_cache_begin = malloc(sizeof(struct arp_cache))) == NULL) { ERROR(strerror(errno)); pthread_rwlock_unlock(&wlock); return (-1); } memcpy(&sarpi_cache_begin->sc_mac, &mac, sizeof(mac)); memcpy(&sarpi_cache_begin->sc_ip, &ip, sizeof(ip)); TAILQ_INSERT_HEAD(&sarpi_cache_head, sarpi_cache_begin, entries); pthread_rwlock_unlock(&wlock); return (0); } if ((sarpi_cache_next = malloc(sizeof(struct arp_cache))) == NULL) { ERROR(strerror(errno)); pthread_rwlock_unlock(&wlock); return (-1); } memcpy(&sarpi_cache_next->sc_mac, &mac, sizeof(mac)); memcpy(&sarpi_cache_next->sc_ip, &ip, sizeof(ip)); TAILQ_INSERT_TAIL(&sarpi_cache_head, sarpi_cache_next, entries); pthread_rwlock_unlock(&wlock); return (0); } /* * SARPI cache list signal handler. */ static void sarpi_cache_list_refresh_thread_sigusr1(int sig) { pthread_exit((void *) 0); } /* * During every timeout it updates SARPI * cache static entries in Arp cache. */ static void * sarpi_cache_list_refresh_thread(void *arg) { struct sigaction saction; char entry[34]; int i; #ifdef NETBSD int ret = 0; #endif #ifdef NETBSD saction.sa_flags = 0; #endif saction.sa_handler = sarpi_cache_list_refresh_thread_sigusr1; if (sigaction(SIGUSR1, &saction, NULL) < 0) { ERROR(strerror(errno)); pthread_exit((void *) -1); } for (;;) { /* * Sleep for thread suspend. */ #ifdef NETBSD /* * Convert by seconds to minuts. */ if ((ret = sleep(sarpi_timeout * 60)) < 0) { #else /* * Convert by microseconds to minuts. */ if (usleep((sarpi_timeout * 1000000) * 60) < 0) { #endif ERROR(strerror(errno)); pthread_exit((void *) -1); } #ifdef NETBSD /* * For SIGINT, SIGTERM, SIGQUIT, * It exited. */ if (ret != 0) { pthread_exit((void *) -1); } #endif aprintf(stdout, 1, "Refresh these Arp Cache entries:\n"); /* * Count entries. */ i = 1; pthread_rwlock_rdlock(&rlock); pthread_rwlock_wrlock(&wlock); TAILQ_FOREACH(sarpi_cache_pos, &sarpi_cache_head, entries) { aprintf(stdout, 1, "%d) ", i); /* * Refresh Arp Cache entries. */ snprintf(entry, 34, "%15s %17s", inet_ntoa(sarpi_cache_pos->sc_ip), ether_ntoa(&(sarpi_cache_pos->sc_mac))); entry[strlen(entry)] = '\0'; if (arp_cache_add(SARPI_REFRESH, entry) < 0) { pthread_rwlock_unlock(&wlock); pthread_rwlock_unlock(&rlock); pthread_exit((void *) -1); } i++; } pthread_rwlock_unlock(&wlock); pthread_rwlock_unlock(&rlock); } pthread_exit((void *) 0); } /* * Destroy SARPI cache tail. */ static void sarpi_cache_list_destroy(void) { pthread_rwlock_rdlock(&rlock); while (TAILQ_EMPTY(&sarpi_cache_head) == 0) { pthread_rwlock_wrlock(&wlock); sarpi_cache_pos = TAILQ_FIRST(&sarpi_cache_head); TAILQ_REMOVE(&sarpi_cache_head, sarpi_cache_pos, entries); free(sarpi_cache_pos); pthread_rwlock_unlock(&wlock); } pthread_rwlock_unlock(&rlock); } /****************** * DARPI handler: * ******************/ /* * Set DARPI Cache entry timeout. */ static int darpi_set_timeout(char *timeout) { int val = atoi(timeout); #ifdef NETBSD /* * usleep() for NetBSD required < 1.000.000. */ if ((val * 1000) >= 1000000) { aprintf(stderr, 0, " ERROR: DARPI timeout %d is too large.\n\n", val * 1000); return (-1); } #endif darpi_timeout = val; return (0); } /* * DARPI manager signal handler. */ static void darpi_manager_thread_sigusr1(int sig) { darpi_cache_list_destroy(); pthread_exit((void *) 0); } /* * Handles DARPI, delete all found entries * in the Arp cache to delete some poisoned * hosts then it starts realtime execution * to reads the packets: * - Arp request * - Arp reply. */ static void * darpi_manager_thread(void *arg) { struct sigaction saction; #ifdef NETBSD saction.sa_flags = 0; #endif saction.sa_handler = darpi_manager_thread_sigusr1; if (sigaction(SIGUSR1, &saction, NULL) < 0) { ERROR(strerror(errno)); pthread_exit((void *) -1); } /* * Iface work. */ if (iface_manager() < 0) { pthread_exit((void *) -1); } if (iface_check_uplink() < 0) { pthread_exit((void *) -1); } iface_info_print(); /* * PID CPU Scheduling. */ if (task_mode_cpu_priority(PRIO_PROCESS, getpid(), cpu_priority) < 0) { pthread_exit((void *) -1); } aprintf(stdout, 1, "Deletes these Arp Cache entries:\n"); /* * Delete all Arp Cache entries (Possible entries poisoned). */ if (arp_cache_del_all() < 0) { pthread_exit((void *) -1); } /* * Thread 4 detached, inbound/outbound work. */ if (darpi_realtime() < 0) { pthread_exit((void *) -1); } pthread_exit((void *) 0); } /* * DARPI Realtime execution, process all * inbound/outbound Arp packets. */ static int darpi_realtime(void) { aprintf(stdout, 1, "Cache entry timeout: %d %s\n", darpi_timeout, darpi_timeout == 1 ? "millisecond." : "milliseconds."); aprintf(stdout, 1, "Realtime Protect actived!\n"); pthread_attr_init(&detach_attr); pthread_attr_setdetachstate(&detach_attr, PTHREAD_CREATE_DETACHED); pthread_attr_setschedpolicy(&detach_attr, SCHED_RR); /* * Thread 4 detached, realtime inbound/outbound work. */ if (pthread_create(&thread[3], &detach_attr, darpi_realtime_thread, (void *) NULL) != 0) { ERROR(strerror(errno)); return (-1); } pthread_attr_destroy(&detach_attr); darpi_cache_list_destroy(); return (0); } /* * DARPI realtime signal handler. */ static void darpi_realtime_thread_sigusr1(int sig) { pthread_exit((void *) 0); } /* * Use thread for non blocking to pcap_loop(). */ static void * darpi_realtime_thread(void *arg) { struct sigaction saction; pcap_t *pcap; #ifdef NETBSD saction.sa_flags = 0; #endif saction.sa_handler = darpi_realtime_thread_sigusr1; if (sigaction(SIGUSR1, &saction, NULL) < 0) { ERROR(strerror(errno)); pthread_exit((void *) -1); } if ((pcap = darpi_realtime_open_packets()) == NULL) { pthread_exit((void *) -1); } pthread_rwlock_init(&rlock, NULL); pthread_rwlock_init(&wlock, NULL); while (1) { if (pcap_loop(pcap, 1, darpi_realtime_read_packets, NULL) < 0) { ERROR(pcap_geterr(pcap)); pthread_rwlock_destroy(&wlock); pthread_rwlock_destroy(&rlock); darpi_realtime_close_packets(pcap); pthread_exit((void *) -1); } } pthread_rwlock_destroy(&wlock); pthread_rwlock_destroy(&rlock); darpi_realtime_close_packets(pcap); pthread_exit((void *) 0); } /* * Open pcap file descriptor. */ static pcap_t * darpi_realtime_open_packets(void) { struct bpf_program compiled_filter; char errbuf[PCAP_ERRBUF_SIZE], *filter = "arp"; pcap_t *pcap; #ifndef LINUX unsigned int op = 1; #endif if ((pcap = pcap_open_live(dev.dev, BUFSIZ, 0, 0, errbuf)) == NULL) { ERROR(errbuf); return (NULL); } #ifndef LINUX /* * BSD, differently from linux does not * support automatic socket soft real time * (Linux Socket Filter). * Therefore on BSD platform it's necessary * to use this I/O Control. */ if (ioctl(pcap_fileno(pcap), BIOCIMMEDIATE, &op) < 0) { ERROR(strerror(errno)); return (NULL); } #endif if (pcap_compile(pcap, &compiled_filter, filter, 0, dev.dev_netmask.s_addr) < 0) { ERROR(pcap_geterr(pcap)); darpi_realtime_close_packets(pcap); return (NULL); } if (pcap_setfilter(pcap, &compiled_filter) < 0) { ERROR(pcap_geterr(pcap)); darpi_realtime_close_packets(pcap); return (NULL); } pcap_freecode(&compiled_filter); return (pcap); } /* * Close pcap file descriptor. */ static void darpi_realtime_close_packets(pcap_t *pcap) { pcap_close(pcap); } /* * Reads inbound/outbound packets such as: * - Arp request: * - Checks the source, if it matches us: * Save the destination address in the * DARPI Cache then it will checks the * inbound Arp reply packet. * - Or checks the destination, if it matches us: * Delete source address in Arp cache * (possible address poisoned), * resend Arp request to ex source. * * - Arp reply: * - Checks the source, if it matches us: * Sended. * - Checks the destination, if matches us: * Checks the source address, if it matches * in DARPI cache, they are accepted and * inserted in Arp cache, otherwise they * are rejected and deleted in Arp cache. */ static void darpi_realtime_read_packets(unsigned char *arg, const struct pcap_pkthdr *header, const unsigned char *packet) { struct ether_addr src_mac, dst_mac, dst_mac_req; struct in_addr dst_ip, dst_ip_req; struct arp_header *arp_packet; char c_src_ip[16], c_src_mac[18], c_dst_ip[16], c_dst_mac[18], entry[34]; int i; /* * Arp Packet. */ arp_packet = (struct arp_header *) (packet + dev.dev_offset); /* * Convert source MAC/IPv4 string. */ snprintf(c_src_ip, 16, "%d.%d.%d.%d", arp_packet->ah_addresses.ar_spa[0], arp_packet->ah_addresses.ar_spa[1], arp_packet->ah_addresses.ar_spa[2], arp_packet->ah_addresses.ar_spa[3]); for (i = 0; i < ETHER_ADDR_LEN; i++) { src_mac.octet[i] = arp_packet->ah_addresses.ar_sha[i]; } strncpy(c_src_mac, ether_ntoa(&src_mac), sizeof(char) * 18); c_src_mac[sizeof(char) * strlen(c_src_mac)] = '\0'; /* * Convert destination MAC/IPv4 string. */ snprintf(c_dst_ip, 16, "%d.%d.%d.%d", arp_packet->ah_addresses.ar_tpa[0], arp_packet->ah_addresses.ar_tpa[1], arp_packet->ah_addresses.ar_tpa[2], arp_packet->ah_addresses.ar_tpa[3]); inet_aton(c_dst_ip, &dst_ip); for (i = 0; i < ETHER_ADDR_LEN; i++) { dst_mac.octet[i] = arp_packet->ah_addresses.ar_tha[i]; } strncpy(c_dst_mac, ether_ntoa(&dst_mac), sizeof(char) * 18); c_dst_mac[sizeof(char) * strlen(c_dst_mac)] = '\0'; if (ntohs(arp_packet->ah_header.ar_op) == ARP_OP_REQUEST) { /* * Check if we are the source address. */ if (strcmp(c_src_mac, ether_ntoa(&(dev.dev_mac))) == 0 && strcmp(c_src_ip, inet_ntoa(dev.dev_inet4)) == 0) { aprintf(stdout, 1, "Request >> Add entry "); /* * DARPI Cache Add/Refresh. */ if (darpi_cache_list_create(&dst_ip) < 0) exit(EXIT_FAILURE); pthread_attr_init(&detach_attr); pthread_attr_setdetachstate(&detach_attr, PTHREAD_CREATE_DETACHED); pthread_attr_setschedpolicy(&detach_attr, SCHED_RR); /* * Thread 5 detached, Check each DARPI Cache entry with * timeout, possible host doesn't present in the network. */ pthread_create(&thread[4], &detach_attr, darpi_cache_list_check_thread, (void *) &dst_ip); pthread_attr_destroy(&detach_attr); } /* * Check if we are the destination address. */ else if (strcmp(c_dst_ip, inet_ntoa(dev.dev_inet4)) == 0) { aprintf(stdout, 1, "Request << Delete entry "); /* * Possible source address poisoned. * Delete it from Arp cache and resend a * request to ex source. */ if (arp_cache_del(DARPI, c_src_ip) < 0) exit(EXIT_FAILURE); memcpy(&dst_mac_req, ether_aton("ff:ff:ff:ff:ff:ff"), sizeof(dst_mac_req)); if (inet_aton(c_src_ip, &dst_ip_req) == 0) { aprintf(stderr, 0, " ERROR: %s inet4 address malformed!\n\n", c_src_ip); exit(EXIT_FAILURE); } /* * After darpi will handlers this arp request and reply. */ if (darpi_realtime_send_packet(&dst_mac_req, &dst_ip_req) < 0) exit(EXIT_FAILURE); } } else if (ntohs(arp_packet->ah_header.ar_op) == ARP_OP_REPLY) { /* * Check if we are the source address. */ if (strcmp(c_src_mac, ether_ntoa(&(dev.dev_mac))) == 0 && strcmp(c_src_ip, inet_ntoa(dev.dev_inet4)) == 0) { aprintf(stdout, 1, "Reply >> Send to "); aprintf(stdout, 0, "%s -> %s\n", c_dst_ip, c_dst_mac); } /* * Check if we are the destination address. */ else if (strcmp(c_dst_mac, ether_ntoa(&(dev.dev_mac))) == 0 && strcmp(c_dst_ip, inet_ntoa(dev.dev_inet4)) == 0) { aprintf(stdout, 1, "Reply << "); /* * Possible Arp Gratuitous for Arp Poisoning. * Search entry in DARPI cache, if it matches it * is to inserted in Arp cache, else if it doesn't * exist, it is to deleted from Arp cache. */ TAILQ_FOREACH(darpi_cache_pos, &darpi_cache_head, entries) { if (strcmp(inet_ntoa(darpi_cache_pos->dc_ip), c_src_ip) == 0) { TAILQ_REMOVE(&darpi_cache_head, darpi_cache_pos, entries); free(darpi_cache_pos); aprintf(stdout, 0, "Refresh entry "); memset(entry, '\0', 34); snprintf(entry, 34, "%15s %17s", c_src_ip, c_src_mac); entry[strlen(entry)] = '\0'; if (arp_cache_add(DARPI, entry) < 0) { exit(EXIT_FAILURE); } return; } } aprintf(stdout, 0, "Delete entry \n", c_src_ip); if (arp_cache_del(DARPI, c_src_ip) < 0) { exit(EXIT_FAILURE); } } } } /* * Sends arp request (See Arp request Inbound * in darpi_realtime_read_packets()). */ static int darpi_realtime_send_packet(struct ether_addr *dst_mac, struct in_addr *dst_ip) { char errbuf[LIBNET_ERRBUF_SIZE]; libnet_t *lnet; if ((lnet = libnet_init(LIBNET_LINK, dev.dev, errbuf)) == NULL) { ERROR(errbuf); return (-1); } if (libnet_autobuild_arp(ARPOP_REQUEST, /* * Source MAC address. */ (u_int8_t *) &(dev.dev_mac), /* * Source IPv4 address. */ (u_int8_t *) &(dev.dev_inet4), /* * Destination MAC address. */ (u_int8_t *) dst_mac, /* * Destination InetV4 address. */ (u_int8_t *) dst_ip, lnet ) < 0) { ERROR(libnet_geterror(lnet)); libnet_destroy(lnet); return (-1); } if (libnet_autobuild_ethernet((u_int8_t *) dst_mac, ETHERTYPE_ARP, lnet) < 0) { ERROR(libnet_geterror(lnet)); libnet_destroy(lnet); return (-1); } /* * Sends (Ethernet + Arp) Packet. */ if (libnet_write(lnet) < 0) { ERROR(libnet_geterror(lnet)); libnet_destroy(lnet); return (-1); } libnet_destroy(lnet); return (0); } /* * Create or adds DARPI cache tail. */ static int darpi_cache_list_create(struct in_addr *entry) { struct in_addr ip; ip.s_addr = entry->s_addr; aprintf(stdout, 0, "%s\n", inet_ntoa(*entry)); pthread_rwlock_wrlock(&wlock); if (darpi_cache_begin == NULL) { TAILQ_INIT(&darpi_cache_head); if ((darpi_cache_begin = malloc(sizeof(struct darpi_cache))) == NULL) { ERROR(strerror(errno)); pthread_rwlock_unlock(&wlock); return (-1); } memcpy(&darpi_cache_begin->dc_ip, &ip, sizeof(ip)); TAILQ_INSERT_HEAD(&darpi_cache_head, darpi_cache_begin, entries); pthread_rwlock_unlock(&wlock); return (0); } if ((darpi_cache_next = malloc(sizeof(struct darpi_cache))) == NULL) { ERROR(strerror(errno)); pthread_rwlock_unlock(&wlock); return (-1); } memcpy(&darpi_cache_next->dc_ip, &ip, sizeof(ip)); TAILQ_INSERT_TAIL(&darpi_cache_head, darpi_cache_next, entries); pthread_rwlock_unlock(&wlock); return (0); } /* * DARPI cache list signal handler. */ static void darpi_cache_list_check_thread_sigusr1(int sig) { pthread_exit((void *) 0); } /* * DARPI Cache entry timeout. * When DARPI reads Arp Request Outbound, it writes an * entry in DARPI Cache, if this entry replies with Arp * Reply Inbound it's ok, else if it doesn't replies, * it probably doesn't exist. This timeout in this case, * delete this entry from DARPI Cache. */ static void * darpi_cache_list_check_thread(void *arg) { struct in_addr *entry = (struct in_addr *)arg; struct sigaction saction; char ip[16]; #ifdef NETBSD saction.sa_flags = 0; #endif saction.sa_handler = darpi_cache_list_check_thread_sigusr1; if (sigaction(SIGUSR1, &saction, NULL) < 0) { ERROR(strerror(errno)); pthread_exit((void *) -1); } snprintf(ip, sizeof(char) * 16, "%s", inet_ntoa(*entry)); /* * usleep() for thread suspend. * Convert by microseconds to milliseconds. */ if (usleep(darpi_timeout * 1000) < 0) { ERROR(strerror(errno)); pthread_exit((void *) -1); } pthread_rwlock_rdlock(&rlock); pthread_rwlock_wrlock(&wlock); TAILQ_FOREACH(darpi_cache_pos, &darpi_cache_head, entries) { if (strcmp(inet_ntoa(darpi_cache_pos->dc_ip), ip) == 0) { TAILQ_REMOVE(&darpi_cache_head, darpi_cache_pos, entries); free(darpi_cache_pos); aprintf(stdout, 1, "Reply << Delete timeout entry %s\n", ip); pthread_rwlock_unlock(&wlock); pthread_rwlock_unlock(&rlock); pthread_exit((void *) 0); } } pthread_rwlock_unlock(&wlock); pthread_rwlock_unlock(&rlock); pthread_exit((void *) 0); } /* * Destroy DARPI cache tail. */ static void darpi_cache_list_destroy(void) { pthread_rwlock_rdlock(&rlock); while (TAILQ_EMPTY(&darpi_cache_head) == 0) { pthread_rwlock_wrlock(&wlock); darpi_cache_pos = TAILQ_FIRST(&darpi_cache_head); TAILQ_REMOVE(&darpi_cache_head, darpi_cache_pos, entries); free(darpi_cache_pos); pthread_rwlock_unlock(&wlock); } pthread_rwlock_unlock(&rlock); } /***************** * Misc handler: * *****************/ /* * My printf() with logging mode. */ static void aprintf(FILE *stream, int ltime, char *fmt, ...) { struct tm tm_cur; time_t time_cur; FILE *log_fstream; va_list ap; if (stream != NULL) { if (ltime == 1) { time_cur = time(NULL); tm_cur = *(struct tm *) localtime(&time_cur); fprintf(stream, " %02d:%02d:%02d - ", tm_cur.tm_hour, tm_cur.tm_min, tm_cur.tm_sec); } va_start(ap, fmt); vfprintf(stream, fmt, ap); va_end(ap); } if (log_mode == 0) { if ((log_fstream = task_mode_log_open()) == NULL) { kill(pid_main, SIGTERM); exit(EXIT_FAILURE); } if (ltime == 1) { time_cur = time(NULL); tm_cur = *(struct tm *) localtime(&time_cur); fprintf(log_fstream, " %02d:%02d:%02d - ", tm_cur.tm_hour, tm_cur.tm_min, tm_cur.tm_sec); } va_start(ap, fmt); vfprintf(log_fstream, fmt, ap); va_end(ap); fflush(log_fstream); task_mode_log_close(log_fstream); } } /* * Prints my license. */ static void license(void) { #define COPYRIGHT \ " Copyright (C) 2008-2010 Andrea Di Pasquale \n" \ " All rights reserved.\n" \ "\n" \ " Redistribution and use in source and binary forms, with or without\n" \ " modification, are permitted provided that the following conditions\n" \ " are met:\n" \ " 1. Redistributions of source code must retain the above copyright\n" \ " notice(s), this list of conditions and the following disclaimer as\n" \ " the first lines of this file unmodified other than the possible\n" \ " addition of one or more copyright notices.\n" \ " 2. Redistributions in binary form must reproduce the above copyright\n" \ " notice(s), this list of conditions and the following disclaimer in " \ "the\n" \ " documentation and/or other materials provided with the " \ "distribution.\n" \ "\n" \ " THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY\n"\ " EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE " \ "IMPLIED\n" \ " WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR " \ "PURPOSE ARE\n" \ " DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) BE " \ "LIABLE FOR ANY\n" \ " DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL " \ "DAMAGES\n" \ " (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\n" \ " SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) " \ "HOWEVER\n" \ " CAUSED AND ON ANY THEORY OF LIABILITY, WHETER IN CONTRACT, STRICT\n" \ " LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY " \ "WAY\n" \ " OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF " \ "SUCH\n" \ " DAMAGE.\n\n" printf(COPYRIGHT); #undef COPYRIGHT } /* * Prints version. */ static void version(void) { printf("\n ArpON \"Arp handler inspectiON\" 2.0 " \ "(http://arpon.sourceforge.net)\n\n"); } /* * Prints help summary page. */ static void help(void) { #define HELP \ " Usage: arpon [Options] {SARPI | DARPI}\n" \ "\n" \ " TASK MODE:\n" \ " -n, --nice Sets PID's CPU priority\n" \ " (Default Nice: %d)\n" \ " -p, --pid-file Sets the pid file\n" \ " (Default: %s)\n" \ " -q, --quiet Works in background task\n" \ "\n" \ " LOG MODE:\n" \ " -f, --log-file Sets the log file\n" \ " (Default: %s)\n" \ " -g, --log Works in logging mode\n" \ "\n" \ " INTERFACE:\n" \ " -i, --iface Sets valid interface manually\n" \ " -o, --iface-auto Sets interface automatically\n" \ " -l, --iface-list Prints all valid interfaces\n" \ "\n" \ " STATIC ARP INSPECTION:\n" \ " -c, --sarpi-cache Sets Arp Cache entries from file\n"\ " (Default: %s)\n" \ " -x, --sarpi-timeout Sets Arp Cache refresh timeout\n"\ " (Default: %d minuts)\n" \ " -s, --sarpi Manages Arp Cache statically\n" \ "\n" \ " DYNAMIC ARP INSPECTION:\n" \ " -y, --darpi-timeout Sets Arp Cache entries timeout\n"\ " (Default: %d milliseconds)\n" \ " -d, --darpi Manages Arp Cache dynamically\n" \ "\n" \ " MISC:\n" \ " -e, --license Prints license page\n" \ " -v, --version Prints version number\n" \ " -h, --help Prints help summary page\n" \ "\n" \ " SEE THE MAN PAGE FOR MANY DESCRIPTIONS AND EXAMPLES\n\n" printf(HELP, cpu_priority, pid_file, log_file, sarpi_cache_file, sarpi_timeout, darpi_timeout); #undef HELP } /***************** * Main handler: * *****************/ /* * Main signal handler. */ static int main_signal(void) { pthread_attr_init(&join_attr); pthread_attr_setschedpolicy(&join_attr, SCHED_RR); /* * Thread 1 joinabled, signal handler. */ if (pthread_create(&thread[0], &join_attr, main_signal_thread, (void *) NULL) != 0) { ERROR(strerror(errno)); pthread_attr_destroy(&join_attr); return (-1); } pthread_join(thread[0], NULL); pthread_attr_destroy(&join_attr); return (0); } /* * This thread is main signal handler of: * - SIGINT, SIGTERM, SIGQUIT: Exit * - SIGHUP, SIGCONT: Reboot * and handler for all threads. */ static void * main_signal_thread(void *arg) { int sig; while (1) { sigwait(&sigse, &sig); switch (sig) { case (SIGINT): case (SIGTERM): case (SIGQUIT): switch (dinspec) { case (INSPEC_SARPI): aprintf(stdout, 0, "\r\n SARPI Interrupt...\n\n"); break; case (INSPEC_DARPI): aprintf(stdout, 0, "\r\n DARPI Interrupt...\n\n"); break; case (INSPEC_NULL): break; } exit(-1); case (SIGHUP): case (SIGCONT): /* * Stop all threads and start their (Reboot). * Thread[0] = Signal is not restarted * Thread[1] = SARPI/DARPI manager yes * Thread[2] = Iface uplink yes * Thread[3] = SARPI/DARPI 1° Thread yes * Thread[4] = SARPI/DARPI 2° Thread yes */ main_stop(); if (main_start() < 0) { pthread_exit((void *) -1); } break; default: break; } } pthread_exit((void *) 0); } /* * Start all threads in this order: * - SARPI: * SARPI manager -> Iface uplink -> SARPI 1° & 2° * * - DARPI: * DARPI manager -> Iface uplink -> DARPI 1° & 2° */ static int main_start(void) { pthread_attr_init(&detach_attr); pthread_attr_setdetachstate(&detach_attr, PTHREAD_CREATE_DETACHED); pthread_attr_setschedpolicy(&detach_attr, SCHED_RR); switch (dinspec) { case (INSPEC_SARPI): /* * Thread 2 detached, start SARPI manager. */ if (pthread_create(&thread[1], &detach_attr, sarpi_manager_thread, (void *) NULL) != 0) { ERROR(strerror(errno)); return (-1); } pthread_attr_destroy(&detach_attr); break; case (INSPEC_DARPI): /* * Thread 2 detached, start DARPI manager. */ if (pthread_create(&thread[1], &detach_attr, darpi_manager_thread, (void *) NULL) != 0) { ERROR(strerror(errno)); return (-1); } pthread_attr_destroy(&detach_attr); break; case (INSPEC_NULL): break; } return (0); } /* * Stop these threads: * Thread[0] = Signal handler is not stopped * Thread[1] = SARPI/DARPI manager yes * Thread[2] = Iface uplink yes * Thread[3] = SARPI/DARPI 1°thread yes * Thread[4] = SARPI/DARPI 2° thread yes. */ static void main_stop(void) { int i; for (i = 1; i < 5; i++) { pthread_kill(thread[i], SIGUSR1); } } /* * Main. */ int main(int argc, char *argv[], char *envp[]) { struct option longopts[] = { { "nice", required_argument, NULL, 'n' }, { "pid-file", required_argument, NULL, 'p' }, { "quiet", no_argument, NULL, 'q' }, { "log-file", required_argument, NULL, 'f' }, { "log", no_argument, NULL, 'g' }, { "iface", required_argument, NULL, 'i' }, { "iface-auto", no_argument, NULL, 'o' }, { "iface-list", no_argument, NULL, 'l' }, { "sarpi-cache", required_argument, NULL, 'c' }, { "sarpi-timeout", required_argument, NULL, 'x' }, { "sarpi", no_argument, NULL, 's' }, { "darpi-timeout", required_argument, NULL, 'y' }, { "darpi", no_argument, NULL, 'd' }, { "license", no_argument, NULL, 'e' }, { "version", no_argument, NULL, 'v' }, { "help", no_argument, NULL, 'h' }, { NULL, 0, NULL, 0 } }; int gopt, j; /* * Check if SARPI or DARPI timeout is setted without option. */ j = 0; /* * Sanitize environment from LD_PRELOAD attacks. */ if (getenv("LD_PRELOAD") != NULL) { unsetenv("LD_PRELOAD"); execve(argv[0], argv, envp); } aprintf(stdout, 0, "\n"); if (getuid() != 0x0) { aprintf(stderr, 0, " ERROR: must run as root!\n\n"); return (-1); } if (argc == 1) { aprintf(stderr, 0, " ERROR: Use -h or --help for more information.\n\n"); return (0); } pid_main = getpid(); while ((gopt = getopt_long(argc, argv, "n:p:qf:gi:olc:x:sy:devh", longopts, NULL)) != -1) { switch(gopt) { case ('n'): cpu_priority = atoi(optarg); break; case ('p'): pid_file = optarg; break; case ('q'): if (task_mode_daemon() < 0) { return (-1); } break; case ('f'): log_file = optarg; break; case ('g'): if (task_mode_log() < 0) { return (-1); } break; case ('i'): dif = IFACE_MANUAL; ddev = optarg; break; case ('o'): dif = IFACE_AUTO; break; case ('l'): dif = IFACE_LIST; if (iface_manager() < 0) { return (-1); } aprintf(stdout, 0, "\n"); return (0); case ('c'): sarpi_cache_file = optarg; j = 1; break; case ('x'): sarpi_set_timeout(optarg); j = 1; break; case ('s'): if (dinspec != INSPEC_NULL) { aprintf(stderr, 0, " ERROR: Can't use both DARPI & " \ "SARPI on same interface!\n\n"); return (-1); } dinspec = INSPEC_SARPI; break; case ('y'): if (darpi_set_timeout(optarg) < 0) { return (-1); } j = 2; break; case ('d'): if (dinspec != INSPEC_NULL) { aprintf(stderr, 0, " ERROR: Can't use both SARPI & " \ "DARPI on same interface!\n\n"); return (-1); } dinspec = INSPEC_DARPI; break; case ('e'): license(); return (0); case ('v'): version(); return (0); case ('h'): help(); return (0); case (':'): case ('?'): aprintf(stderr, 0, "\n"); return (-1); default: break; } } argc -= optind; argv += optind; if (dinspec == INSPEC_NULL) { if (j != 0) { switch (j) { case (1): aprintf(stderr, 0, " ERROR: SARPI required " \ "-s option to work!\n\n"); break; case (2): aprintf(stderr, 0, " ERROR: DARPI required " \ "-d option to work!\n\n"); break; } } } else { switch (dinspec) { case (INSPEC_SARPI): if (j == 2) { aprintf(stderr, 0, " ERROR: SARPI doesn't " \ "required DARPI options!\n\n"); return (-1); } break; case (INSPEC_DARPI): if (j == 1) { aprintf(stderr, 0, " ERROR: DARPI doesn't " \ "required SARPI options!\n\n"); return (-1); } break; case (INSPEC_NULL): default: break; } } sigemptyset(&sigse); sigaddset(&sigse, SIGINT); sigaddset(&sigse, SIGTERM); sigaddset(&sigse, SIGQUIT); sigaddset(&sigse, SIGHUP); sigaddset(&sigse, SIGCONT); if (pthread_sigmask(SIG_BLOCK, &sigse, NULL) < 0) { ERROR(strerror(errno)); return (-1); } if (main_start() < 0) { return (-1); } if (main_signal() < 0) { return (-1); } return (0); } /* * EOF. */ ArpON-2.0/src/CMakeLists.txt000644 000000 000000 00000000723 11406410763 015764 0ustar00rootwheel000000 000000 # Compile the arpon.c source code # # Copyright 2010 zeld@freaknet.org # # Redistribution AND use is allowed according to the terms of the New # BSD license. add_executable(arpon arpon.c include/queue.h) if(UBUNTU OR DEBIAN) target_link_libraries(arpon net dumbnet pcap pthread) else() target_link_libraries(arpon net dnet pcap pthread) endif( UBUNTU OR DEBIAN ) install(TARGETS arpon RUNTIME DESTINATION sbin COMPONENT Application) ArpON-2.0/src/include/000755 000765 000024 00000000000 11403231711 015204 5ustar00spikeystaff000000 000000 ArpON-2.0/src/include/queue.h000444 000765 000024 00000040010 11030004201 016456 0ustar00spikeystaff000000 000000 /* * Copyright (c) 1991, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * @(#)queue.h 8.5 (Berkeley) 8/20/94 */ #ifndef _SYS_QUEUE_H_ #define _SYS_QUEUE_H_ /* * This file defines five types of data structures: singly-linked lists, * slingly-linked tail queues, lists, tail queues, and circular queues. * * A singly-linked list is headed by a single forward pointer. The elements * are singly linked for minimum space and pointer manipulation overhead at * the expense of O(n) removal for arbitrary elements. New elements can be * added to the list after an existing element or at the head of the list. * Elements being removed from the head of the list should use the explicit * macro for this purpose for optimum efficiency. A singly-linked list may * only be traversed in the forward direction. Singly-linked lists are ideal * for applications with large datasets and few or no removals or for * implementing a LIFO queue. * * A singly-linked tail queue is headed by a pair of pointers, one to the * head of the list and the other to the tail of the list. The elements are * singly linked for minimum space and pointer manipulation overhead at the * expense of O(n) removal for arbitrary elements. New elements can be added * to the list after an existing element, at the head of the list, or at the * end of the list. Elements being removed from the head of the tail queue * should use the explicit macro for this purpose for optimum efficiency. * A singly-linked tail queue may only be traversed in the forward direction. * Singly-linked tail queues are ideal for applications with large datasets * and few or no removals or for implementing a FIFO queue. * * A list is headed by a single forward pointer (or an array of forward * pointers for a hash table header). The elements are doubly linked * so that an arbitrary element can be removed without a need to * traverse the list. New elements can be added to the list before * or after an existing element or at the head of the list. A list * may only be traversed in the forward direction. * * A tail queue is headed by a pair of pointers, one to the head of the * list and the other to the tail of the list. The elements are doubly * linked so that an arbitrary element can be removed without a need to * traverse the list. New elements can be added to the list before or * after an existing element, at the head of the list, or at the end of * the list. A tail queue may only be traversed in the forward direction. * * A circle queue is headed by a pair of pointers, one to the head of the * list and the other to the tail of the list. The elements are doubly * linked so that an arbitrary element can be removed without a need to * traverse the list. New elements can be added to the list before or after * an existing element, at the head of the list, or at the end of the list. * A circle queue may be traversed in either direction, but has a more * complex end of list detection. * * For details on the use of these macros, see the queue(3) manual page. * * * SLIST LIST STAILQ TAILQ CIRCLEQ * _HEAD + + + + + * _ENTRY + + + + + * _INIT + + + + + * _EMPTY + + + + + * _FIRST + + + + + * _NEXT + + + + + * _PREV - - - + + * _LAST - - + + + * _FOREACH + + - + + * _INSERT_HEAD + + + + + * _INSERT_BEFORE - + - + + * _INSERT_AFTER + + + + + * _INSERT_TAIL - - + + + * _REMOVE_HEAD + - + - - * _REMOVE + + + + + * */ /* * Singly-linked List definitions. */ #define SLIST_HEAD(name, type) \ struct name { \ struct type *slh_first; /* first element */ \ } #define SLIST_ENTRY(type) \ struct { \ struct type *sle_next; /* next element */ \ } /* * Singly-linked List functions. */ #define SLIST_EMPTY(head) ((head)->slh_first == NULL) #define SLIST_FIRST(head) ((head)->slh_first) #define SLIST_FOREACH(var, head, field) \ for((var) = (head)->slh_first; (var); (var) = (var)->field.sle_next) #define SLIST_INIT(head) { \ (head)->slh_first = NULL; \ } #define SLIST_INSERT_AFTER(slistelm, elm, field) do { \ (elm)->field.sle_next = (slistelm)->field.sle_next; \ (slistelm)->field.sle_next = (elm); \ } while (0) #define SLIST_INSERT_HEAD(head, elm, field) do { \ (elm)->field.sle_next = (head)->slh_first; \ (head)->slh_first = (elm); \ } while (0) #define SLIST_NEXT(elm, field) ((elm)->field.sle_next) #define SLIST_REMOVE_HEAD(head, field) do { \ (head)->slh_first = (head)->slh_first->field.sle_next; \ } while (0) #define SLIST_REMOVE(head, elm, type, field) do { \ if ((head)->slh_first == (elm)) { \ SLIST_REMOVE_HEAD((head), field); \ } \ else { \ struct type *curelm = (head)->slh_first; \ while( curelm->field.sle_next != (elm) ) \ curelm = curelm->field.sle_next; \ curelm->field.sle_next = \ curelm->field.sle_next->field.sle_next; \ } \ } while (0) /* * Singly-linked Tail queue definitions. */ #define STAILQ_HEAD(name, type) \ struct name { \ struct type *stqh_first;/* first element */ \ struct type **stqh_last;/* addr of last next element */ \ } #define STAILQ_HEAD_INITIALIZER(head) \ { NULL, &(head).stqh_first } #define STAILQ_ENTRY(type) \ struct { \ struct type *stqe_next; /* next element */ \ } /* * Singly-linked Tail queue functions. */ #define STAILQ_EMPTY(head) ((head)->stqh_first == NULL) #define STAILQ_INIT(head) do { \ (head)->stqh_first = NULL; \ (head)->stqh_last = &(head)->stqh_first; \ } while (0) #define STAILQ_FIRST(head) ((head)->stqh_first) #define STAILQ_LAST(head) (*(head)->stqh_last) #define STAILQ_INSERT_HEAD(head, elm, field) do { \ if (((elm)->field.stqe_next = (head)->stqh_first) == NULL) \ (head)->stqh_last = &(elm)->field.stqe_next; \ (head)->stqh_first = (elm); \ } while (0) #define STAILQ_INSERT_TAIL(head, elm, field) do { \ (elm)->field.stqe_next = NULL; \ *(head)->stqh_last = (elm); \ (head)->stqh_last = &(elm)->field.stqe_next; \ } while (0) #define STAILQ_INSERT_AFTER(head, tqelm, elm, field) do { \ if (((elm)->field.stqe_next = (tqelm)->field.stqe_next) == NULL)\ (head)->stqh_last = &(elm)->field.stqe_next; \ (tqelm)->field.stqe_next = (elm); \ } while (0) #define STAILQ_NEXT(elm, field) ((elm)->field.stqe_next) #define STAILQ_REMOVE_HEAD(head, field) do { \ if (((head)->stqh_first = \ (head)->stqh_first->field.stqe_next) == NULL) \ (head)->stqh_last = &(head)->stqh_first; \ } while (0) #define STAILQ_REMOVE_HEAD_UNTIL(head, elm, field) do { \ if (((head)->stqh_first = (elm)->field.stqe_next) == NULL) \ (head)->stqh_last = &(head)->stqh_first; \ } while (0) #define STAILQ_REMOVE(head, elm, type, field) do { \ if ((head)->stqh_first == (elm)) { \ STAILQ_REMOVE_HEAD(head, field); \ } \ else { \ struct type *curelm = (head)->stqh_first; \ while( curelm->field.stqe_next != (elm) ) \ curelm = curelm->field.stqe_next; \ if((curelm->field.stqe_next = \ curelm->field.stqe_next->field.stqe_next) == NULL) \ (head)->stqh_last = &(curelm)->field.stqe_next; \ } \ } while (0) /* * List definitions. */ #define LIST_HEAD(name, type) \ struct name { \ struct type *lh_first; /* first element */ \ } #define LIST_HEAD_INITIALIZER(head) \ { NULL } #define LIST_ENTRY(type) \ struct { \ struct type *le_next; /* next element */ \ struct type **le_prev; /* address of previous next element */ \ } /* * List functions. */ #define LIST_EMPTY(head) ((head)->lh_first == NULL) #define LIST_FIRST(head) ((head)->lh_first) #define LIST_FOREACH(var, head, field) \ for((var) = (head)->lh_first; (var); (var) = (var)->field.le_next) #define LIST_INIT(head) do { \ (head)->lh_first = NULL; \ } while (0) #define LIST_INSERT_AFTER(listelm, elm, field) do { \ if (((elm)->field.le_next = (listelm)->field.le_next) != NULL) \ (listelm)->field.le_next->field.le_prev = \ &(elm)->field.le_next; \ (listelm)->field.le_next = (elm); \ (elm)->field.le_prev = &(listelm)->field.le_next; \ } while (0) #define LIST_INSERT_BEFORE(listelm, elm, field) do { \ (elm)->field.le_prev = (listelm)->field.le_prev; \ (elm)->field.le_next = (listelm); \ *(listelm)->field.le_prev = (elm); \ (listelm)->field.le_prev = &(elm)->field.le_next; \ } while (0) #define LIST_INSERT_HEAD(head, elm, field) do { \ if (((elm)->field.le_next = (head)->lh_first) != NULL) \ (head)->lh_first->field.le_prev = &(elm)->field.le_next;\ (head)->lh_first = (elm); \ (elm)->field.le_prev = &(head)->lh_first; \ } while (0) #define LIST_NEXT(elm, field) ((elm)->field.le_next) #define LIST_REMOVE(elm, field) do { \ if ((elm)->field.le_next != NULL) \ (elm)->field.le_next->field.le_prev = \ (elm)->field.le_prev; \ *(elm)->field.le_prev = (elm)->field.le_next; \ } while (0) /* * Tail queue definitions. */ #define TAILQ_HEAD(name, type) \ struct name { \ struct type *tqh_first; /* first element */ \ struct type **tqh_last; /* addr of last next element */ \ } #define TAILQ_HEAD_INITIALIZER(head) \ { NULL, &(head).tqh_first } #define TAILQ_ENTRY(type) \ struct { \ struct type *tqe_next; /* next element */ \ struct type **tqe_prev; /* address of previous next element */ \ } /* * Tail queue functions. */ #define TAILQ_EMPTY(head) ((head)->tqh_first == NULL) #define TAILQ_FOREACH(var, head, field) \ for (var = TAILQ_FIRST(head); var; var = TAILQ_NEXT(var, field)) #define TAILQ_FOREACH_REVERSE(var, head, field, headname) \ for (var = TAILQ_LAST(head, headname); \ var; var = TAILQ_PREV(var, headname, field)) #define TAILQ_FIRST(head) ((head)->tqh_first) #define TAILQ_LAST(head, headname) \ (*(((struct headname *)((head)->tqh_last))->tqh_last)) #define TAILQ_NEXT(elm, field) ((elm)->field.tqe_next) #define TAILQ_PREV(elm, headname, field) \ (*(((struct headname *)((elm)->field.tqe_prev))->tqh_last)) #define TAILQ_INIT(head) do { \ (head)->tqh_first = NULL; \ (head)->tqh_last = &(head)->tqh_first; \ } while (0) #define TAILQ_INSERT_HEAD(head, elm, field) do { \ if (((elm)->field.tqe_next = (head)->tqh_first) != NULL) \ (head)->tqh_first->field.tqe_prev = \ &(elm)->field.tqe_next; \ else \ (head)->tqh_last = &(elm)->field.tqe_next; \ (head)->tqh_first = (elm); \ (elm)->field.tqe_prev = &(head)->tqh_first; \ } while (0) #define TAILQ_INSERT_TAIL(head, elm, field) do { \ (elm)->field.tqe_next = NULL; \ (elm)->field.tqe_prev = (head)->tqh_last; \ *(head)->tqh_last = (elm); \ (head)->tqh_last = &(elm)->field.tqe_next; \ } while (0) #define TAILQ_INSERT_AFTER(head, listelm, elm, field) do { \ if (((elm)->field.tqe_next = (listelm)->field.tqe_next) != NULL)\ (elm)->field.tqe_next->field.tqe_prev = \ &(elm)->field.tqe_next; \ else \ (head)->tqh_last = &(elm)->field.tqe_next; \ (listelm)->field.tqe_next = (elm); \ (elm)->field.tqe_prev = &(listelm)->field.tqe_next; \ } while (0) #define TAILQ_INSERT_BEFORE(listelm, elm, field) do { \ (elm)->field.tqe_prev = (listelm)->field.tqe_prev; \ (elm)->field.tqe_next = (listelm); \ *(listelm)->field.tqe_prev = (elm); \ (listelm)->field.tqe_prev = &(elm)->field.tqe_next; \ } while (0) #define TAILQ_REMOVE(head, elm, field) do { \ if (((elm)->field.tqe_next) != NULL) \ (elm)->field.tqe_next->field.tqe_prev = \ (elm)->field.tqe_prev; \ else \ (head)->tqh_last = (elm)->field.tqe_prev; \ *(elm)->field.tqe_prev = (elm)->field.tqe_next; \ } while (0) /* * Circular queue definitions. */ #define CIRCLEQ_HEAD(name, type) \ struct name { \ struct type *cqh_first; /* first element */ \ struct type *cqh_last; /* last element */ \ } #define CIRCLEQ_ENTRY(type) \ struct { \ struct type *cqe_next; /* next element */ \ struct type *cqe_prev; /* previous element */ \ } /* * Circular queue functions. */ #define CIRCLEQ_EMPTY(head) ((head)->cqh_first == (void *)(head)) #define CIRCLEQ_FIRST(head) ((head)->cqh_first) #define CIRCLEQ_FOREACH(var, head, field) \ for((var) = (head)->cqh_first; \ (var) != (void *)(head); \ (var) = (var)->field.cqe_next) #define CIRCLEQ_INIT(head) do { \ (head)->cqh_first = (void *)(head); \ (head)->cqh_last = (void *)(head); \ } while (0) #define CIRCLEQ_INSERT_AFTER(head, listelm, elm, field) do { \ (elm)->field.cqe_next = (listelm)->field.cqe_next; \ (elm)->field.cqe_prev = (listelm); \ if ((listelm)->field.cqe_next == (void *)(head)) \ (head)->cqh_last = (elm); \ else \ (listelm)->field.cqe_next->field.cqe_prev = (elm); \ (listelm)->field.cqe_next = (elm); \ } while (0) #define CIRCLEQ_INSERT_BEFORE(head, listelm, elm, field) do { \ (elm)->field.cqe_next = (listelm); \ (elm)->field.cqe_prev = (listelm)->field.cqe_prev; \ if ((listelm)->field.cqe_prev == (void *)(head)) \ (head)->cqh_first = (elm); \ else \ (listelm)->field.cqe_prev->field.cqe_next = (elm); \ (listelm)->field.cqe_prev = (elm); \ } while (0) #define CIRCLEQ_INSERT_HEAD(head, elm, field) do { \ (elm)->field.cqe_next = (head)->cqh_first; \ (elm)->field.cqe_prev = (void *)(head); \ if ((head)->cqh_last == (void *)(head)) \ (head)->cqh_last = (elm); \ else \ (head)->cqh_first->field.cqe_prev = (elm); \ (head)->cqh_first = (elm); \ } while (0) #define CIRCLEQ_INSERT_TAIL(head, elm, field) do { \ (elm)->field.cqe_next = (void *)(head); \ (elm)->field.cqe_prev = (head)->cqh_last; \ if ((head)->cqh_first == (void *)(head)) \ (head)->cqh_first = (elm); \ else \ (head)->cqh_last->field.cqe_next = (elm); \ (head)->cqh_last = (elm); \ } while (0) #define CIRCLEQ_LAST(head) ((head)->cqh_last) #define CIRCLEQ_NEXT(elm,field) ((elm)->field.cqe_next) #define CIRCLEQ_PREV(elm,field) ((elm)->field.cqe_prev) #define CIRCLEQ_REMOVE(head, elm, field) do { \ if ((elm)->field.cqe_next == (void *)(head)) \ (head)->cqh_last = (elm)->field.cqe_prev; \ else \ (elm)->field.cqe_next->field.cqe_prev = \ (elm)->field.cqe_prev; \ if ((elm)->field.cqe_prev == (void *)(head)) \ (head)->cqh_first = (elm)->field.cqe_next; \ else \ (elm)->field.cqe_prev->field.cqe_next = \ (elm)->field.cqe_next; \ } while (0) #endif /* !_SYS_QUEUE_H_ */ ArpON-2.0/man8/arpon.8000644 000765 000024 00000036176 11406410076 015070 0ustar00spikeystaff000000 000000 .\" $ arpon.8,v 1.54 07/06/2008 15:35:20 zeld Exp $ .\" $ arpon.8.v 2.0 29/03/2010 13:20:19 spikey Exp $ .\" .\" Copyright (c) 2010 Andrea Di Pasquale .\" All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice(s), this list of conditions and the following disclaimer as .\" the first lines of this file unmodified other than the possible .\" addition of one or more copyright notices. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice(s), this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" .\" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY .\" EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED .\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE .\" DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) BE LIABLE FOR ANY .\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES .\" (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR .\" SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER .\" CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH .\" DAMAGE. .\" .\" Standard preamble: .\" ======================================================================== .de Sh \" Subsection heading .br .if t .Sp .ne 5 .PP \fB\\$1\fR .PP .. .de Sp \" Vertical space (when we can't use .PP) .if t .sp .5v .if n .sp .. .de Vb \" Begin verbatim text .ft CW .nf .ne \\$1 .. .de Ve \" End verbatim text .ft R .fi .. .\" Set up some character translations and predefined strings. \*(-- will .\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left .\" double quote, and \*(R" will give a right double quote. | will give a .\" real vertical bar. \*(C+ will give a nicer C++. Capital omega is used to .\" do unbreakable dashes and therefore won't be available. \*(C` and \*(C' .\" expand to `' in nroff, nothing in troff, for use with C<>. .tr \(*W-|\(bv\*(Tr .ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p' .ie n \{\ . ds -- \(*W- . ds PI pi . if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch . if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch . ds L" "" . ds R" "" . ds C` "" . ds C' "" 'br\} .el\{\ . ds -- \|\(em\| . ds PI \(*p . ds L" `` . ds R" '' 'br\} .\" .\" If the F register is turned on, we'll generate index entries on stderr for .\" titles (.TH), headers (.SH), subsections (.Sh), items (.Ip), and index .\" entries marked with X<> in POD. Of course, you'll have to process the .\" output yourself in some meaningful fashion. .if \nF \{\ . de IX . tm Index:\\$1\t\\n%\t"\\$2" .. . nr % 0 . rr F .\} .\" .\" For nroff, turn off justification. Always turn off hyphenation; it makes .\" way too many mistakes in technical documents. .hy 0 .if n .na .\" .\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2). .\" Fear. Run. Save yourself. No user-serviceable parts. . \" fudge factors for nroff and troff .if n \{\ . ds #H 0 . ds #V .8m . ds #F .3m . ds #[ \f1 . ds #] \fP .\} .if t \{\ . ds #H ((1u-(\\\\n(.fu%2u))*.13m) . ds #V .6m . ds #F 0 . ds #[ \& . ds #] \& .\} . \" simple accents for nroff and troff .if n \{\ . ds ' \& . ds ` \& . ds ^ \& . ds , \& . ds ~ ~ . ds / .\} .if t \{\ . ds ' \\k:\h'-(\\n(.wu*8/10-\*(#H)'\'\h"|\\n:u" . ds ` \\k:\h'-(\\n(.wu*8/10-\*(#H)'\`\h'|\\n:u' . ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'^\h'|\\n:u' . ds , \\k:\h'-(\\n(.wu*8/10)',\h'|\\n:u' . ds ~ \\k:\h'-(\\n(.wu-\*(#H-.1m)'~\h'|\\n:u' . ds / \\k:\h'-(\\n(.wu*8/10-\*(#H)'\z\(sl\h'|\\n:u' .\} . \" troff and (daisy-wheel) nroff accents .ds : \\k:\h'-(\\n(.wu*8/10-\*(#H+.1m+\*(#F)'\v'-\*(#V'\z.\h'.2m+\*(#F'.\h'|\\n:u'\v'\*(#V' .ds 8 \h'\*(#H'\(*b\h'-\*(#H' .ds o \\k:\h'-(\\n(.wu+\w'\(de'u-\*(#H)/2u'\v'-.3n'\*(#[\z\(de\v'.3n'\h'|\\n:u'\*(#] .ds d- \h'\*(#H'\(pd\h'-\w'~'u'\v'-.25m'\f2\(hy\fP\v'.25m'\h'-\*(#H' .ds D- D\\k:\h'-\w'D'u'\v'-.11m'\z\(hy\v'.11m'\h'|\\n:u' .ds th \*(#[\v'.3m'\s+1I\s-1\v'-.3m'\h'-(\w'I'u*2/3)'\s-1o\s+1\*(#] .ds Th \*(#[\s+2I\s-2\h'-\w'I'u*3/5'\v'-.3m'o\v'.3m'\*(#] .ds ae a\h'-(\w'a'u*4/10)'e .ds Ae A\h'-(\w'A'u*4/10)'E . \" corrections for vroff .if v .ds ~ \\k:\h'-(\\n(.wu*9/10-\*(#H)'\s-2\u~\d\s+2\h'|\\n:u' .if v .ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'\v'-.4m'^\v'.4m'\h'|\\n:u' . \" for low resolution devices (crt and lpr) .if \n(.H>23 .if \n(.V>19 \ \{\ . ds : e . ds 8 ss . ds o a . ds d- d\h'-1'\(ga . ds D- D\h'-1'\(hy . ds th \o'bp' . ds Th \o'LP' . ds ae ae . ds Ae AE .\} .rm #[ #] #H #V #F C .\" ======================================================================== .\" .\"End of Preamble. Start of man page. .TH arpon 8 "04 April 2010" .SH NAME arpon \- Arp handler inspectiON .SH SYNOPSIS .na .B arpon [ .B \-npqfgiolcxsydevh ] .br .ti +6 [ .B \-n .I Nice value ] [ .B \-p .I Pid file ] .br .ti +6 [ .B \-f .I Log file ] .br .ti +6 [ .B \-i .I Iface ] .br .ti +6 [ .B \-c .I Cache file ] [ .B \-x .I Timeout ] .br .ti +6 [ .B \-y .I Timeout ] .br .ti +8 .br .ad .SH DESCRIPTION .LP ArpON (Arp handler inspectiON) is a portable handler daemon that make Arp secure in order to avoid Arp Spoofing/Poisoning & co. .PP This is possible using two kinds of anti Arp Poisoning tecniques, the first is based on SARPI or "Static Arp Inspection", the second on DARPI or "Dynamic Arp Inspection" approach. .PP SARPI and DARPI protect both bidirectional and distributed attacks. In "Bidirectional protection" is required that ArpON is installed and running on two nodes of the connection attached. In "Distributed protection" is required that ArpON is installed and running on all nodes of the connections attacked. All other nodes whitout ArpON will not be protected from attack. .PP Keep in mind other common tools fighting ARP poisoning usually limit their activity only to point out the problem instead of blocking it, ArpON does it using SARPI and DARPI policies. Finally you can use ArpON to pentest some switched/hubbed LAN with/without DHCP protocol, in fact you can disable the daemon in order to use the tools to poison the ARP Cache. .PP Remember it doesn't affect the communication efficiency of the ARP protocol! .PP .SH OPTIONS .TP .SH TASK MODE .PP .PP .TP \-n (\--nice) Sets PID's CPU priority (Default: 0 nice). .TP \-p (\--pid-file) Sets the pid file (Default /var/run/arpon.pid). .TP \-q (\--quiet) Works in background task. .IP .TP .SH LOG MODE .PP .PP .TP \-f (\--log-file) Sets the log file (Default: /var/log/arpon.log). .TP \-g (\--log) Works in logging mode. .IP .TP .SH DEVICE MANAGER .PP ArpON is an ARP handler and it is able to handle network devices automatically (default) or manually, to print a list of up network interfaces of the system. .PP It identifies the interface's datalink layer you are using but it supports only Ethernet/Wireless as datalink. It sets the netowrk interface and check running, online ready and it deletes the PROMISCUE flag. The online ready checks unplug (virtual and physical), boot, hibernation and suspension OS' features for Ethernet/Wireless card. It handles these features and reset the network interface automatically when it will ready. .PP .PP .TP \-i (\--iface) Sets your Ethernet device manually. .TP \-o (\--iface-auto) Sets Ethernet device automatically. .TP \-l (\--iface-list) Prints all Ethernet devices. .PP .TP .SH STATIC ARP INSPECTION .PP When SARPI starts, it saves statically all the ARP entries it finds in the ARP cache in a static cache called SARPI Cache. Note that you must manage the ARP through the SARPI cache from file feature of ArpON. After the startup, ArpON operations are split in two parallel tasks: .PP \- It automatically updates the ARP cache each time the timeout expires; timeout is simply the expire time of each entry in the ARP cache, defined according to the policy set in the running kernel. Timeout is set by default to 10 minutes, but you can override this value. .PP \- It applies policies to the ARP cache, according to the following three schemes: .PP 1) For each received ARP reply, ArpON checks whether source addresses match an entry in the SARPI cache. In such case, the new entry will overwrite the old one, previously saved in the static cache. Here, ArpON will defend and block ARP Poisoning/Spoofing attacks. .PP 2) For each received ARP request, ArpON checks wheter the source addresses match an entry in the SARPI cache. In such case, the new entry will overwrite the old one, previously saved in the static cache. Here, ArpON will defend and block ARP Poisoning/Spoofing attacks. .PP 3) Every ARP request/reply whose source address doesn't match an entry in the SARPI cache are just ignored. .PP Both these operations are a countermeasure against ARP Poisoning/Spoofing attacks, as SARPI detects and blocks them. SARPI doesn't affect the communication efficiency of the ARP protocol. SARPI just manages a list with static entries, making it an optimal choice in those networks without DHCP. .PP Finally, it's possible to use SARPI as a daemon, using the "TASK MODE" and "LOG MODE" feature of ArpON. It supports daemon exit by SIGINT, SIGTERM, SIGQUIT and daemon reboot by SIGHUP and SIGCONT POSIX signals. .PP .TP \-c (\--sarpi-cache) Sets Arp Cache entries from file (Default: /etc/arpon.sarpi). .TP \-x (\--sarpi-timeout) Sets Arp Cache refresh timeout (Default: 10 minuts). .TP \-s (\--sarpi) Manages Arp Cache statically. .PP .TP .SH DYNAMIC ARP INSPECTION .PP DARPI startup phase consists in cleaning up the ARP cache, deleting all of its entries. This is due because ARP cache may have poisoned entries from the beginning. DARPI handles the so called DARPI cache, applying different policies to different kinds of packets: .PP \- ARP request: It traces ARP requests and follows these rules if traffic is: .PP 1) Outbound: Packets are generated by us. ArpON let them pass, adding an entry with the target to the DARPI cache (see ARP reply - Inbound). On this DARPI cache entry, DARPI sets timeout because if this entry doesn't exist in network, DARPI must to delete it. .PP 2) Inbound: Packets come to us from the network. ArpON refuses the packet, deleting the entry of the source address from the ARP cache, because such packet may be poisoned. Afterwards, the kernel will send an ARP request to the source address, and it will be managed by ArpON through DARPI. Here, ArpON will defend and block ARP Poisoning/Spoofing attacks through the ARP requests. .PP \- ARP reply: It traces the ARP replies, and follows these rules if traffic is: .PP 1) Outbound: Packets are generated by us. ArpON just lets them pass. .PP 2) Inbound: Packets come to us from the network. ArpON checks whether the source address matches an entry in the DARPI cache (see ARP request - Outbound), it lets the packet flow, adding an entry in the ARP cache. Otherwise, if the source address doesn't match any entry in the DARPI cache, ArpON refuses the packet, deleting the entry from the ARP cache. Here ArpON defends and blocks ARP Poisoning/Spoofing attacks through the ARP replies. .PP Both types of packets are used to perform ARP Poisoning/Spoofing attacks, as DARPI detects and blocks them. DARPI doesn't affect the communication efficiency of the ARP protocol. DARPI manages uniquely a list with dynamic entries. Therefore it's an optimal solution in networks having DHCP. .PP Finally, it's possible to use DARPI as a daemon, using the "TASK MODE" and "LOG MODE" feature of ArpON. It supports daemon exit by SIGINT, SIGTERM, SIGQUIT and daemon reboot by SIGHUP and SIGCONT POSIX signals. .PP .TP \-y (\--darpi-timeout) Sets DARPI Cache entry timeout (Default: 500 milliseconds). .TP \-d (\--darpi) Manages Arp Cache dynamically. .PP .TP .SH MISC FEATURES .PP Other. .TP \-e (\--license) Prints license page. .TP \-v (\--version) Prints version number. .TP \-h (\--help) Prints help summary page. .PP .SH EXAMPLES .TP \&- \s-1Static\s0 \s-1ARP\s0 \s-1Inspection:\s0 .PP .Vb 13 \& \& Example of /etc/arpon.sarpi: \& \& # Example of arpon.sarpi \& # \& 192.168.1.1 0:25:53:29:f6:69 \& 172.16.159.1 0:50:56:c0:0:8 \% # \& \& With 1 minut of timeout for arp cache refresh: \& \& # root:ArpON-2.0 $ ./arpon -i en1 -x 1 -s \& \& ArpON "Arp handler inspectiON" 2.0 (http://arpon.sourceforge.net) \& \& 12:55:03 - Wait link connection on en1... \& 12:55:12 - SARPI on dev(en1) inet(192.168.1.4) hw(0:23:6c:7f:28:e7) \& 12:55:12 - Arp Cache restore from /etc/arpon.sarpi... \& 12:55:12 - Protects these Arp Cache's entries: \& 12:55:12 - 1) 192.168.1.1 -> 0:25:53:29:f6:69 \& 12:55:12 - 2) 172.16.159.1 -> 0:50:56:c0:0:8 \& 12:55:12 - Arp Cache refresh timeout: 1 minut. \& 12:55:12 - Realtime Protect actived! \& 12:55:22 - Request << Refresh entry 192.168.1.1 -> 0:25:53:29:f6:69 \& 12:55:22 - Reply >> Send to 192.168.1.1 -> 0:25:53:29:f6:69 \& 12:55:39 - Request >> Send to 192.168.1.1 -> 0:0:0:0:0:0 \& 12:55:39 - Reply << Refresh entry 192.168.1.1 -> 0:25:53:29:f6:69 \& 12:56:03 - Request << Ignore entry 192.168.1.93 -> 0:23:6c:7f:28:e7 \& 12:56:03 - Reply >> Send to 192.168.1.93 -> 0:c:29:3:e5:98 \& 12:56:12 - Refresh these Arp Cache entries: \& 12:56:12 - 1) 192.168.1.1 -> 0:25:53:29:f6:69 \& 12:56:12 - 2) 172.16.159.1 -> 0:50:56:c0:0:8 \& ... \& .Ve .PP .PP \&- \s-1Dynamic\s0 \s-1ARP\s0 \s-1Inspection:\s0 .PP .Vb 13 \& # root:ArpON-2.0 $ ./arpon -i en1 -d \& \& ArpON "Arp handler inspectiON" 2.0 (http://arpon.sourceforge.net) \& \& 14:11:32 - Wait link connection on en1... \& 14:11:41 - DARPI on dev(en1) inet(192.168.1.4) hw(0:23:6c:7f:28:e7) \& 14:11:41 - Deletes these Arp Cache entries: \& 14:11:41 - 1) 192.168.1.1 -> 0:25:53:29:f6:69 \& 14:11:41 - Cache entry timeout: 500 milliseconds. \& 14:11:41 - Realtime Protect actived! \& 14:11:41 - Request << Delete entry 192.168.1.1 -> 0:25:53:29:f6:69 \& 14:11:41 - Reply >> Send to 192.168.1.1 -> 0:25:53:29:f6:69 \& 14:11:41 - Request >> Add entry 192.168.1.1 \& 14:11:41 - Reply << Refresh entry 192.168.1.1 -> 0:25:53:29:f6:69 \& 14:11:49 - Request >> Add entry 192.168.1.5 \& 14:11:49 - Reply << Delete timeout entry 192.168.1.5 \& 14:12:04 - Request >> Add entry 192.168.1.1 \& 14:12:04 - Reply << Refresh entry 192.168.1.1 -> 0:25:53:29:f6:69 \& ... \& .Ve .PP .SH AUTHOR .TP ArpON was writen by: .Vb 1 \& \& Andrea Di Pasquale .PP .PP The current version is available via http: .Vb 1 \& \& http://arpon.sourceforge.net .Ve .PP .SH BUGS .TP Please send problems, bugs, questions, desirable enhancements, patch, source code contributions, etc. to: .Vb 1 \& \& spikey.it@gmail.com .RE ArpON-2.0/man8/CMakeLists.txt000644 000000 000000 00000001325 11406410763 016037 0ustar00rootwheel000000 000000 # Compress man pages # # Copyright 2010 zeld@freaknet.org # # Redistribution AND use is allowed according to the terms of the New # BSD license. set(arpon_man_src "${CMAKE_SOURCE_DIR}/man8/arpon.8") find_program(BZIP_TOOL NAMES bzip2 PATHS /bin /sbin /usr/bin /usr/sbin /usr/local/bin /usr/local/sbin) add_custom_command(OUTPUT ${arpon_man_src}.bz2 COMMAND ${BZIP_TOOL} -c ${arpon_man_src} > ${arpon_man_src}.bz2 DEPENDS ${arpon_man_src} COMMENT "Building arpon man pages.") add_custom_target(arpon_man_src ALL DEPENDS ${arpon_man_src}.bz2) install(FILES ${arpon_man_src}.bz2 DESTINATION "/usr/share/man/man8/" PERMISSIONS OWNER_READ GROUP_READ WORLD_READ COMPONENT Man) ArpON-2.0/man8/html/000755 000765 000024 00000000000 11406411444 014607 5ustar00spikeystaff000000 000000 ArpON-2.0/man8/html/._arpon.html000644 000765 000024 00000000253 11406407456 017041 0ustar00spikeystaff000000 000000 Mac OS X  2yATTR!com.apple.TextEncodingutf-8;134217984ArpON-2.0/man8/html/arpon.html000644 000765 000024 00000027542 11406407456 016636 0ustar00spikeystaff000000 000000 ArpON

ArpON




NAME

       arpon - Arp handler InspectiON

SYNOPSIS

       arpon [ -npqfgiolcxsydevh ]
             [ -n Nice value ] [ -p Pid File ]
             [ -f Log file ]
             [ -i Iface ]
             [ -c Cache file ] [ -x Timeout ]
             [ -y Timeout ]

DESCRIPTION

       ArpON  (Arp handler inspectiON) is a portable handler daemon that make 
       Arp secure in order to avoid Arp Spoofing/Poisoning & co.
       
       This is possible using two kinds of anti Arp Poisoning  tecniques,  the
       first is based on SARPI or "Static Arp Inspection", the second on DARPI
       or "Dynamic Arp Inspection" approach.
       
       SARPI and DARPI protect both bidirectional and distributed attacks.
       In "Bidirectional protection" is required that ArpON is installed and 
       running on two nodes of the connection attached. In "Distributed prote-
       ction" is required that ArpON is installed and running on all nodes of 
       the connections attacked. All other nodes whitout ArpON will not be 
       protected from attack.
       
       Keep in mind other common tools fighting ARP  poisoning  usually  limit
       their  activity  only  to point out the problem instead of blocking it,
       ArpON does it using SARPI and DARPI  policies.   Finally  you  can  use
       ArpON  to  pentest some switched/hubbed LAN with/without DHCP protocol,
       in fact you can disable the daemon in order to use the tools to  poison
       the ARP Cache.
       
       Remember it doesn't affect the communication efficiency of the ARP pro-
       tocol!

OPTIONS

       TASK MODE

       -n (--nice) <Nice Value>
              Sets PID's CPU priority (Default: 0 nice).

       -p (--pid-file) <Pid file>
              Sets the pid file (Default /var/run/arpon.pid).
              
       -q (--quiet)
              Works in background task. 

       LOG MODE

       -f (--log-file) <Log file>
              Sets the log file (Default: /var/log/arpon.log).

       -g (--log)
              Works in logging mode.

       DEVICE MANAGER
       
       ArpON is an ARP handler and it is able to handle network devices  auto-
       matically  (default)  or manually, to print a list of up network inter-
       faces of the system.

       It identifies the interface's datalink layer you are using but it  sup-
       ports only Ethernet/Wireless as datalink. It sets the netowrk interface
       and check running, online ready and it deletes the PROMISCUE flag.  The
       online  ready  checks  unplug (virtual and physical), boot, hibernation
       and suspension OS' features  for  Ethernet/Wireless  card.  It  handles
       these  features  and  reset the network interface automatically when it
       will ready.

       -i (--iface) <Iface>
              Sets your Ethernet device manually.

       -o (--iface-auto)
              Sets Ethernet device automatically.

       -l (--iface-list)
              Prints all Ethernet devices.

       STATIC ARP INSPECTION

       When SARPI starts, it saves statically all the ARP entries it finds  in
       the  ARP cache in a static cache called SARPI Cache. Note that you must
       manage the ARP through the SARPI cache  from  file  feature  of  ArpON.
       After the startup, ArpON operations are split in two parallel tasks:

       - It automatically updates the ARP cache each time the timeout expires;
       timeout is simply the expire time of  each  entry  in  the  ARP  cache,
       defined  according to the policy set in the running kernel.  Timeout is
       set by default to 10 minutes, but you can override this value.

       - It applies policies to the ARP  cache,  according  to  the  following
       three schemes:

       1)  For  each received ARP reply, ArpON checks whether source addresses
       match an entry in the SARPI cache. In such case,  the  new  entry  will
       overwrite  the  old  one,  previously saved in the static cache.  Here,
       ArpON will defend and block ARP Poisoning/Spoofing attacks.

       2) For each received  ARP  request,  ArpON  checks  wheter  the  source
       addresses  match  an  entry  in  the SARPI cache. In such case, the new
       entry will overwrite the old one, previously saved in the static cache.
       Here, ArpON will defend and block ARP Poisoning/Spoofing attacks.

       3)  Every ARP request/reply whose source address doesn't match an entry
       in the SARPI cache are just ignored.

       Both these operations are a countermeasure against ARP Poisoning/Spoof-
       ing attacks, as SARPI detects and blocks them. SARPI doesn't affect the
       communication efficiency of the ARP protocol. SARPI just manages a list
       with  static  entries,  making  it  an optimal choice in those networks
       without DHCP.

       Finally, it's possible to use SARPI as a daemon, using the "TASK  MODE"
       and  "LOG  MODE"  feature of ArpON.  It supports daemon exit by SIGINT,
       SIGTERM, SIGQUIT and daemon reboot by SIGHUP and SIGCONT POSIX signals.

       -c (--sarpi-cache) <Cache file>
              Sets Arp Cache entries from file (Default: /etc/arpon.sarpi)
              
       -x (--sarpi-timeout) <Timeout>
              Sets Arp Cache refresh timeout (Default: 10 minuts).

       -s (--sarpi)
              Manages Arp Cache statically.

       DYNAMIC ARP INSPECTION

       DARPI startup phase consists in cleaning up the ARP cache, deleting all
       of its entries. This is due because ARP cache may have poisoned entries
       from  the beginning.  DARPI handles the so called DARPI cache, applying
       different policies to different kinds of packets:

       - ARP request: It traces ARP requests and follows these rules if  traf-
       fic is:

       1)  Outbound:  Packets are generated by us. ArpON let them pass, adding
       an entry with the target to the DARPI cache (see ARP reply -  Inbound).
       On  this  DARPI  cache  entry, DARPI sets timeout because if this entry
       doesn't exist in network, DARPI must to delete it.

       2) Inbound: Packets come to us from  the  network.  ArpON  refuses  the
       packet,  deleting  the  entry of the source address from the ARP cache,
       because such packet may be poisoned. Afterwards, the kernel  will  send
       an  ARP  request to the source address, and it will be managed by ArpON
       through DARPI.  Here, ArpON will defend and block ARP  Poisoning/Spoof-
       ing attacks through the ARP requests.

       -  ARP  reply:  It  traces  the ARP replies, and follows these rules if
       traffic is:

       1) Outbound: Packets are generated by us. ArpON just lets them pass.

       2) Inbound: Packets come to us from the network. ArpON  checks  whether
       the source address matches an entry in the DARPI cache (see ARP request
       - Outbound), it lets the packet flow, adding an entry in the ARP cache.
       Otherwise,  if  the source address doesn't match any entry in the DARPI
       cache, ArpON refuses the packet, deleting the entry from the ARP cache.
       Here  ArpON  defends  and blocks ARP Poisoning/Spoofing attacks through
       the ARP replies.

       Both types of packets  are  used  to  perform  ARP  Poisoning/Spoofing
       attacks,  as  DARPI  detects  and blocks them. DARPI doesn't affect the
       communication efficiency of the ARP protocol. DARPI manages uniquely  a
       list  with  dynamic entries. Therefore it's an optimal solution in net-
       works having DHCP.

       Finally, it's possible to use DARPI as a daemon, using the "TASK  MODE"
       and  "LOG  MODE"  feature of ArpON.  It supports daemon exit by SIGINT,
       SIGTERM, SIGQUIT and daemon reboot by SIGHUP and SIGCONT POSIX signals.
       
       -y (--darpi-timeout) <Timeout>
              Sets Arp Cache entries timeout (Default: 500 milliseconds).

       -d (--darpi)
              Manages Arp Cache dynamically.

       MISC FEATURES

       -e (--license)
              Prints license page.

       -v (--version)
              Prints version number.

       -h (--help)
              Prints help summary page.

EXAMPLES

       - Static ARP Inspection:

         Example of /etc/arpon.sarpi:

           # Example of arpon.sarpi
           #
           192.168.1.1     0:25:53:29:f6:69
           172.16.159.1    0:50:56:c0:0:8
           #

         With 1 minut of timeout for arp cache refresh:

           # root:ArpON-2.0 $ ./arpon -i en1 -x 1 -s

             ArpON "Arp handler inspectiON" 2.0 (http://arpon.sourceforge.net)

             12:55:03 - Wait link connection on en1...
             12:55:12 - SARPI on dev(en1) inet(192.168.1.4) hw(0:23:6c:7f:28:e7)
             12:55:12 - Arp Cache restore from /etc/arpon.sarpi...
             12:55:12 - Protects these Arp Cache's entries:
             12:55:12 - 1)     192.168.1.1 ->  0:25:53:29:f6:69
             12:55:12 - 2)    172.16.159.1 ->  0:50:56:c0:0:8
             12:55:12 - Arp Cache refresh timeout: 1 minut.
             12:55:12 - Realtime Protect actived!
             12:55:22 - Request << Refresh entry 192.168.1.1 -> 0:25:53:29:f6:69
             12:55:22 - Reply   >> Send to 192.168.1.1 -> 0:25:53:29:f6:69
             12:55:39 - Request >> Send to 192.168.1.1 -> 0:0:0:0:0:0
             12:55:39 - Reply   << Refresh entry 192.168.1.1 -> 0:25:53:29:f6:69
             12:56:03 - Request << Ignore entry 192.168.1.93 -> 0:23:6c:7f:28:e7
             12:56:03 - Reply   >> Send to 192.168.1.93 -> 0:c:29:3:e5:98
             12:56:12 - Refresh these Arp Cache entries:
             12:56:12 - 1) 192.168.1.1 -> 0:25:53:29:f6:69
             12:56:12 - 2) 172.16.159.1 -> 0:50:56:c0:0:8
             ...
           
       - Dynamic ARP Inspection:

           # root:ArpON-2.0 $ ./arpon -i en1 -d

             ArpON "Arp handler inspectiON" 2.0 (http://arpon.sourceforge.net)

             14:11:32 - Wait link connection on en1...
             14:11:41 - DARPI on dev(en1) inet(192.168.1.4) hw(0:23:6c:7f:28:e7)
             14:11:41 - Deletes these Arp Cache entries:
             14:11:41 - 1)     192.168.1.1 ->  0:25:53:29:f6:69
             14:11:41 - Cache entry timeout: 500 milliseconds.
             14:11:41 - Realtime Protect actived!
             14:11:41 - Request << Delete entry 192.168.1.1 -> 0:25:53:29:f6:69
             14:11:41 - Reply   >> Send to 192.168.1.1 --> 0:25:53:29:f6:69
             14:11:41 - Request >> Add entry 192.168.1.1
             14:11:41 - Reply   << Refresh entry 192.168.1.1 -> 0:25:53:29:f6:69
             14:11:49 - Request >> Add entry 192.168.1.5
             14:11:49 - Reply   << Delete timeout entry 192.168.1.5
             14:12:04 - Request >> Add entry 192.168.1.1
             14:12:04 - Reply   << Refresh entry 192.168.1.1 -> 0:25:53:29:f6:69
             ...

AUTHORS

       ArpON was writen by:   
       
               Andrea Di Pasquale <spikey.it@gmail.com>

       The current version is available via http:
       
               http://arpon.sourceforge.net

BUGS

       Please send problems, bugs, questions, desirable  enhancements,  patch,
       source code contributions, etc. to:

              spikey.it@gmail.com


                                 04 April 2010                      arpon(8)

Man(1) output converted with man2html
ArpON-2.0/etc/arpon.sarpi000644 000765 000024 00000000173 11360557717 015750 0ustar00spikeystaff000000 000000 # Example of arpon.sarpi # # Gw 192.168.1.1 00:25:53:29:f6:69 # Spyro virtual 172.16.159.1 0:50:56:c0:0:8 # ArpON-2.0/etc/CMakeLists.txt000644 000000 000000 00000000540 11406410763 015745 0ustar00rootwheel000000 000000 # Install arpon.sarpi # # Copyright 2010 zeld@freaknet.org # # Redistribution AND use is allowed according to the terms of the New # BSD license. set(arpon_etc_src "${CMAKE_SOURCE_DIR}/etc/arpon.sarpi") install(FILES ${arpon_etc_src} DESTINATION "/etc/" PERMISSIONS OWNER_READ GROUP_READ WORLD_READ COMPONENT Etcfile) ArpON-2.0/doc/DARPI.png000644 000765 000024 00000376722 11060110311 015114 0ustar00spikeystaff000000 000000 PNG  IHDRi^NiCCPICC ProfilexWy8?fe%Cʒ-kCc1(DP*RT$dKRY"JDGz~{sr\}9bX!T:܈NK$EYÿ Cİ0ʿQ4W7wDc/F@@@@` T7no|Q$:2 R =_r / WHH/ &\M N]G*o[@C߶ KVDI2 F vlI%c=N!EҢ6 A77PX&W!vGc]cppƗ*nД} V@\ECr۸T/L9 9e5v5MoZZ46S $ Ì~UfZ[kdNiupRtNurs rڷsWwO=c`,'D*AI׎ԎҌV?rpgBL!x''=NnKJ-HKM0ܑŕzű'O(宝zrܙ|gu?_HSQbMq%璭%meY˥*:+*vuFu5LMZLՕ66,ܬn6)6-6_o kUj]UF;};$;->wϭg^fY?x4~\A!ö#<# F=c_+~yk"k/&K(o4龷3~sw,.|hĺziU5ѵ/_+%zﯓ  ˞'?k`pz_ϒQۖ_@~bN5勪xP]ښZ:8]}Q rV4[;g"NE./] x=Sz{o|g~X%(2!TP0p}~]#R%J9ZAB`,>[96~$pCbQRVrL 9*M9]0}dFwfeVрc2Yϟxp2'5zwgr $ ֝?pBaK%֥ܥe=g+U\Q|*ZǵC3jH3gpE#kæc6-ǭ9\6߾p.>Qy7Ss;~^RK{dX쓆APӜagLF+ۿz>>b+;''M}sa:ی,w7 '.1}1b)y9i%kG~_ua`2 ^PVI:G/Cyc1ɂ $yKzI.*"$$wTQaViN fYun ]~ږگtuo 4b752qo-edioeclkAΑqiKhW'75w^}uG{y|*}Ȟ~ZK+RI7ԖМ0j6J?IRFGtc;Ww(!&A8apsbFchLJM4tG*2虺YEs"chlnyO_ Y0\yB¡ He/.\J**/}UV~V[R1TyJU*zT]xRu{}:zW 57]֛Z^ߖz;ݹf\x=^T/~ʼnϷڶmۇ7dQ'+ODIi'AW L4yD%utt(i%FoL8Lûw?Y9Y_G.S 'Z<-J@ %ys!1ұ5&$'$ L9I=jrjp^ڂs S%e~^{ZW:Թ7[ڢ$u<]S[Që֟cy'tMg/D}L[<\}mu__o  /`@G# چBEPhI:]~dtiY\<¸a1cXQE%eKXY ˳ap渇rzqp)rqGs65  06T|9@#T.l!Q䔨-ľI"϶I:o6T{r FJ;aʄsq] ߴ:ºjzAG +150}ߒ*=1vzUΛ\ROzx{ ^œUB)!7C褨M}Sc %R/dgi̞;q''u|sEŤ2ˌWnU^yè^&qyNfGD{at/냵>M?zYars3Zsw3?(|-]>YsMo?oLVAD$8 Uе12)BDb.2bCDRQu)47MC_0203u2-O2b@LuĖaسTp6V-֋l8HIv;Nx-Nmf.n 1o" ~6[7 ?ԋb.'6Gh?+Aj/Mh;԰tLl 22KUJM;)̩5 wjk]eӧT6jdZomqrZצvSǽ.]j=e_&V} z}S .%(衃ѱ"qE'=95q9}[sƋCKPy[+ ZVrZCG㞦֙6CwQ)LR3&=D-> $ ;:Vbx˗T_MqM4|a#ӳ%引k]_忥}i/q(%F66.{MB(@@`a<v 4.D/nmL^ ~ADK LRl@I%nZ9;RA:>"/=_ #1ƶec0 ( 4^  @t B$P !  C$!@S_ L=tUO ld$O߹|/4.0= 4_uȃQ@AW`~{ph9Cð0 `I'TAYII ?fPokyK pHYs   IDATxXT9 G0E51mvn5n6^ns%{{ӽj~šMuw!w-6[h!v!bMg*W*QP_g|82y>39=|F3MSY]Ld'H鑝 =GvN #;@zd'H鑝3E"R̙3gI  UofrˇW_7MӞx| `B3>v͛7??яԃ۷'?^-X󅅅jaro>OD}ї_~y`ґ3߿Hwyk_%oƤ$#;f,/zwDԩSϟ_vJGկR7>sL8j… ޚVѭ.){<{ꩧʺ;MӒ-[6%& zJD{9WU4u:;n*8)>/33ޛ p#LӴ&C" ,P^}B㝝loo<@AAA H~\nNNnW; ?n Y=ZPPPPPSMMfS?S$ B"R^^|Ր#Rd'|O$Rv/_."G YYY]t7pwN #;@zd'H鑝 =i$ KX;#++pdeeq?xssեiu L!΁0RW麞q]w=˗/B%N\}F|4-##G";pQuu#<FǸbŊ - 0up""?OKKKD?ĕR; gΜg~뭷Ν;UNȷx<~ /ַƽD ;wٳggΜzS}'L6!h zS 0~q03H$r/D"NzS 03{^u/w\}{DZDvt׹}CR `*cr}'dŒq0w@Μ9s_ gϞ[o͝;w"L)sݻZO{%8 Av@D䳟͛Ǿ7~vJL){nƍ|>jcǎ|+YZd'.s~pat]5k֝w._ܪ  ;0?Μ9 ^ܹsx{ ;q `GvN #;@zd'H鑝 =GvN #;@zd'H鑝 =GvN #;@zd'H鑝 =GvN #;@zd'H鑝 =Gvt L?iH$.abi6ScdHlRau +Mӆ<i$R"0MSUR"%LdFlz`L$A3%q75Gɍ}_Rynl64M͖%XڍQN^S|PVVEa2?>(ك(}'%q0 Èbr "E"Ñv] ޳0 pEɡz*;E$aAdu]``4{X,a+$QZE&bd'X,FCEaB'`tw9ᰮv]u5e$Rg'W3qӌDѨIPf2Rg4sD"uSENѤNz"LuUpb 0a{aX] &8du-0%II%(+$I81`HkH|L Av iH N ,CvN #;@zd'HHR-U+o(մ݁+ޮC]ci%m *ʑNFo!%ܾR*{'N'Rl nB|2bE"klɋcBƱ "RQkZDdŒymOm'aN'%K-||ɺ֝%2Dh?@4`Hjv~iZ@<D6m|!8lߗm;ɦ-ju@mԴVw޵^Ӵ-O+5MӴ+;{ED:+Ւ-NWLWn4MJ/.6/3lѵd{MӴ k_,%K7u*-ݵD*_?~NOOڮvLnՈ?{@<D"}}}NjooojjώP[HE[ϥ*~HmTԵ5VHqƧ}"j>G*Dն [{zAcGD67iݦefJDD+j*uUGڶHإWȺƎu"%vFDkZiX'R74fQbmam[T54Tގw*D|;k[zz/-۹ EvtNb⪎GBWwEԩS}}}H$_ݎBvlSJgO ¶bU n*vBh:*W2צuHa[iڊExZP!R֡^t'R֟|yNUOTm騫k7XP|=#mJo)mT:I(pBXP b#s[){tȌ[=N0c+hx $l\WF"[ii%"p8&WXZj%5ͳ^G'9$o (\+""y^~5YQ,.H%"^pLDdy}"7$""FLDaQko-s:ٳp oh{:&6,QNp >2\d-s"uGbP(ta{ar҃X*NbPƆ.J߮״mm~Kf %IVϽSw;_Prt4OԕȈED\I6G[;8aF$egd|:Nc {?c+^;`be_]}[>[R!2^w/+~'x.ӆ ?4F^;Rs}ŋ}MHտwы[D6=])lכe_?d(5,(tXla n͓YR!20fa=:۔צ2DS>tBNm{C[}FX"{^G=W5t|iU?т7u< ]E[DζՋ%9O|G#,h6~wdJQrh<(%?Y9""lG dcm.k+x\S2>Lqm`kSR'w2;#3';½=1K3aCݺ>ڱ WGN^H{@2# ׭տtk/m}MF8]=aݝwIӴ9sdffzތ ˥Ơ3}'+s[DkFDyyW›}yнyBF6Lf2^˛w &?d'_mx.03OX]`a2`"aӃc  0aR]WJ J5mw2 *k#XPظPRmH ]]wL`F ;&ʡo}8<LJW[wG$7l;.wcG1K ~|Z^:-㵷\| OGvLdMڍ+D/ZqW喒MJPjto/-4M+(}I~zM4M۸`x%F7;SkN|yJMӴ፯w~\Q4M+Uxr@Tkiwir}egP:_ؼAD6-rsRoy@JMӴ/w]7 ?Ј''utvo4MJ\,h?]m,>N]?D۹x~=.&#HԩS]]]MMMco)Rc_U,"R^Ѻ'bG7Hζ#G*։HMG" # 3|n}mlkmfP<)VlvN-_%"Rb4[+ E|5-U"RXѦ葖"H:UJtP[HqjTC5"RVxH6l;am>:@NŲ 77,X2kmk*(Yu"ꄘf_%#4֫/"MMM]]]ND"x|&ۯ7oC=)o-(i}C|5O,<竟?8E2őqNl4 ]"]"Pc| E /Vdۉ'?/u;:x-y'{eתn8|f˛=y"ԼGLDDo_](Nj^5>Ww*~PK)*ȓYHObD(xi)._ˋO/ϖ~jSA=Um/a=kxeGUz?h<u``2zWhHuw]VϼdуV\]t?LK8dliygRGED}+"HQJ.7O?igَ5KrgߺH$&2BoO ?TU2zCwm=sn/;@##1AiްD \^r]DDݮ^V̺Ms  0!b˞|wHBA y>\D[c{*ʿ?|ɥ=JΨw Et, mlh\Vp֬˺?7sgXÇZc)M i>ޣY$>Nipqqm3C#岲uGHyݑX, hm^8;&"SwRg^ a0Vd'[&ɝ)o7 wH? "',_^uiq/^U|:K.ɔ@ca7;dG/zoz?+cբJ׫EzۿZ\~^xK|/19+gwG/L$SdS݆qo5˚,\2ZV tY@W-a`3B>Y&~keEx%Rßbhwcl+~' ׻[uq^y""Rj-/m[XRP!""eUFVc""?,CqeHᶎ'W拈ÑꉆmE7m;=8Zn/IS~y+x6;ۇWC3MSQ"0 # sΝ={v͚5c(||+g_壷ung{{yyp>yyy+.vH>/'&9yޱ;ad!K{>9yك{ úۭRX}φ^yO2/`ɞ/iF:9#2zc̜loʉKuon~zyυisz.KuA+f(`dםD_n̞]| .yjf/k7O&OwƛW|bw;`8&L'N9ltL퍵 w+d7}ğ2M\'`/^/"yﳺɣzVq<ߘ;GvN #;@zd'H鑝 =GvN 02m$63fV#Fjp";r @h'nuE$vt L*5v]E3lMjp8'ϟp@8ba$ =E@6Muv322f͚.wjJbd'%G멎.vGx<."6t7jvLK@:Nxf͚xnR]' 0;-r< NjI4bx4MK(V04MSMEvr9=z`4t:aa`pxNѤ'5*O(\.W,STpZ]>P'Ep$Էj4vFݮqLӼӜ9s.a MM8% > pEydBdjJ8; cEuR`#;F.':'4S;N7pvzV0%N'ZT!6@N%1dvRyIMqcw KptLJA26HC}oNSIRM7|vr\V0( %&HAvIw!aN~\ H%N?fu٬.GvN #;@zd'H鑝 =[]v%%'MF|  `ԀH$! -(+E,2R_@B `dRJJ$*, Q"U/I4͖+"6MO `H$ N嬪s``CdpldvnlDiiSd(9`J5q09sk8w*A%EE `dpba!SfiH$H8*z+!;tRX,kD"*,%o";V IDAT(N+%opFHa B"R B ՋbhT}D"j[ ZOp%d'TCeH$BvLPf麮?S,:5y2>Y] Db09)EEvX#N ʣh,$Ȫ+;N+/iʣѨ *dj";(N$(WM5rfx<8`uE0K&(UrfmN& z'kA;`,N%$3SX] L`<WΝY5MOuR/V2G۸0"`ǮZ~rw辚j+ vǂ"Ҿ@~hbMz@VPL]ҾKvZU }'k֜}7.R ;'ϿoW2QEg։ǢZ;%[|U>QS(oGb""ch,}Iig}JM4dˡFr/l "l9w1vnUZi%DӴ]]+4pׁ[A o))dH}ʍA9vp_^+kK7>o10+Kq\D:l)ݾ{ KWjZ}[6֫AvLko`0xfM"<uE}-watpwIkZi{$sDz ɜqҿ\'";\:ꭝg$Zu-{W=zCgWV3ϷdA5h8HM??)T4w^XT59Һw r>)bTWlX[5ͳ\tWł {>Nj[w ?[)E=yWUd7=\f @т)O [ܷYjܲjۦ}ふZW.H<>3WP-.>qm-yFڇ+n;@AX,Ͻ~j7y-R^RT~i[W[5['a 4l.PѼ#".qHOugw~  ^!\-Y29gf,NiWq'NhinhV1Y4MmHLw'_1[͒r\ډH,u}"Y2D$""Wkn8_Zj]M ͟@aϭ̹M{@0wNF"rjDb",R9XFD|I:mD ƈrߚh T7bE|'BPҰwvꆊ̖#Cy\Ύ%hF|>S7u=E_q_Qَ?y;ō oe8.?BD_.{ 6lȰC 8$[\3`z^JW;X{z(X,,"cyr7K*$W.#&g'xnm"}䮼-W$ ş׽e3(|鲀Z߭ }[vJEG;.=lù\`Ztܺ9_7\kUM❍[^x#cC[6LV6}~y]`kGw%8拸ɦP,]Dw$"#W,ߺf_\&n=^[)gk'o|!5eRWD|)y8R#8LӴLH$bX$pB__߹sΞ=f͚l O x2svwdybNI,pXwb`ɞ_p7>[" rV|D8;46''';;;33z<p8l6iF<{ۛl\{&}KE\'}_ cNkdf]HӴ1nH$XӘ%/ַ=_X5kGv'4'm4# ̝/-z2``@3GvN #;@zd'H鑝 =[]iiv9BvD"1-cX$pB__߹sΞ=f4'Hc =GvN #;@zd'H鑝4-cGvXFKl|0M͖IL6nvA샆(t h*;. !,'S";1뺮?{{{CP8Fa$ 4'SN=#unNȘ5kVVVVVVu]h=@Zd'4MSn;xTXlGx<-)ΒC p\'##r\dvRJ`#;,3N'v#aiLt: PK,;HVV%/*%5kq:NSK..J:Nn;%FXL س*;Xr’j=eddnEX])Lid'eTpRxd*uZe'5`O^O'抸6jd.MNnqN˨H$t]O$y#x<"{"2{l=.T|J6dӉ ;,S7b=rV8k, >.HaQ20"J/j^d^65)A2N LM'HbR2;n`mr8}dX"2iSUjH 2\?N lV #;@zd'H鑝 =GvN #;@zd'H鑝 =GvN #;@znXitI$Vp4M)ઐ4MR$WYYu0 Q2, y;`|$R"0MSURN;"U\dFlz`L$AUѦ'`J1%q75Gt>M/%vfSm@ 0)>(++0v."6M ƌ^ɡzx0 0bbz4MD"#yivgma0-+9TOeh4:}oa=i{X,a+ԥQI"6NbX4 BVB!3F`NqOj})+nu]WZ]LS຤Nf~,DQusǓ`,N땚<{d)+k. `Nz"L]W7a{aX] F:N*;Y] L3d'8HI%(+R;N Bv!r02\3ຘ#!;MY)u4@vL``vt_+ v+5mZAe0fFoס4w;vgIo&=s$&VYs*_%5i.@}Mlxb}}^9%2؈0W!L1xɟ|>oՃOۑHؾ-%i+K_8tRmY_R4M+(rZ_i+KKCsk e;+~}y`]vjŕ/ZqW喒MJzG\jRKʗ.nU)0^d{}X$i%+F_lT]kjmw0ZEJ:vp_:J@:+_)("뷼p@ do`0xfM"<uE}-watpwIkZi{$sDz a1[M~vGdNK;pZHl*Mom.k{*6Jt5m?jcޑe#^^CA -Xa~UcG[=wD|.]+b=]txe{3Ɗ2usMG~w; w`jZW.tJ# NXHakٶ'{M4-eW!ubm:;uT*d{E5t hϥ*Bm"m=m;}R\Nơu"Z.|f*Cm"ž v9-HmmmSSS{{{WWשS"H<"L4;&'N>X%-15 =iڼ"+;fkÓYr]VdͻpNaMHݼbHKDb-nUxkzwD޺I3|텞7pGs8n.xX$)k-OED+EJ"[ii%"p8&"ƶꢻ94mÏ~sv7 ̹M?t\Dl? /Uegz`NI;EV;/k<BW7Td92urv0'] r]l>P-ŵ~[߶\lKaߗ=u]?:B}Q)Uw;H\l~Et, mlhKG y>\D[c{*ʿ?L}}3"y]Df]<ݿM|."{Pᶟ5DGkBvL)\u9wY/XQ􋓱XXDǂ[oTH xo{PʿyS";w[[`ilJpwʿt2lv.!f#"6["G?Y.;z`7 J6n]ܲS*;߷RϷtxExSAp}*w݈ɽe3(|鲀Z򁵅Rcao{E2E|2K_z֪ "Rq=G dcm.k+V/𔫗f,UY\-r_WϫW}^֛}X,-"ev'k7Q0GDWv1DlCKi󉆝mE7m;sK8sHf⭫9Yx)8拈qK35ܭ]a[$њXx<\]D ?|a)\Ī1] L~JpaHd``  ;wٳk֬ꏘpdπ'3';g`w@FN-F0hn]-sg_o7wǴ9rbu"lﰣd]zOᰡn] qv)+++{^ :$e {pUNq nۓI%59t8)adddX]ȵHdRR)cGvE<9xOe'Ii4Mzc岺kFm(!55!;S!aifh4sH@"/i➑D3af,> D"VW ѐ ѐ ѐ Ѹp8luitX&*>.i#Z]bd''HiBv - ;@Zd'HiBv - ;@Zd'HiBv`ti\P(du!Vb搿N3qMD$/` ;pI"Pc``0 mf3Mfc G4D"aŢh4Ԫx<6V)L@ Q%)y//yyywfϞR~Ř=RS$D"o?gΜ<[ZZzKm N~+EvPCnpFH$׿ԧ>Lnro#H4'!8ԙ!h8޿O?]SSSTTt׾K[l>vN뺮v=Q3ΐh4 BO=/ˆ{=W|˖-rqNeP=uә3g{X,,''g,9{|8 # HeB `3Bj)?ϖٳGׯgu]{|3=B#Ø=J3C۷'?ɪUgk׮-//ۿ[f pqf[@TU?ׅï 3ԚUTALPX)H?j?n}bmVb%k1JVV5y003^TD|>r™).޷oߨQn*SLy7e2L&Cc` /}+,tܹ%%%=8ѣ=ZUUs9OX<``@n2Cl6:nҤI_~Jyzz۷WN駟XA %.@&8Iطz+997ѹT%K ė=` aXe˖[~g?poo7o^lll\\\.d՟0 ?BJ!x1//1%9}tDDFy뭷<<<=|'8ę!~744>|a1ȑ# _՟=B c+8:n_|ŠA\A}gt?bac=A: aXv/ g 8nƌwuŋ>rHd$.-Vf 6dee}W&Lpvg=z^?y[ZZd2YkkD"!"B!WcBt_ee={]+̙?S|#>w.3?GFFJ>8_qqT*'d/;@3CzQQQ BΎfG`H@߄\ψ'8 =NV5;;W__2~y{/($Iwn[jMMMٳgVuvlΜ9z~Ŋr\.KR, g!v~cfZ[[xҥ/;tvoq//{ۛO7aBf!jX,|΢ϛ77d'dS;@_'{ 7|3o޼ŋ2&LΛ7o'q  0f4oYV=m.cطo_tt+}YB!$ {N .MMMMMMfڿ^^ޘ1c]ƞT^^1cƌwnnn2L&!{@ (P=aӅ ^~?eykmmݴiw!:]F;@_Nfsyy^;vl~~~')zf=B'.#m - qiii1f<DBfmvߕgiV'l/dZ8b'qz,vjjjZgϞ9wѣGGsT Woy΁a~Dr"âbCL*_ ZBNqI[D)9Y=8#*()ȸcAТSI˗.yi o:j""2 Qc\>BzzR'K"R Mо{gϞZ,|b7 ӟ 82Cl6:nST]?H:k\SjjH#c S!i%uÖr7qo Q'+Gkn(Kl!]8 C񹥓3ݕN!JZr?v(cF$_Cʺ:#//oʔ)?hdݷ6NL3C˧zj͚5}Z)GN ' (kÎDVDDՑHAl\YǰHY*Td\NDd  s %2l~m_/4 cT^#;;u;~}榦&|#8]f6l6w^paw+#$+[LGPKٝ(!f7/[a#.au|Ŏ#^r:&akF|% Ƅ̢ɔMU1yF!لHjÍ<{INN޴ilfӟ=a;st aZ/_ꫯ9rdʔ)+{ZLu6▟4J7x,ח-n8 Z[[WZlݺur\*JRD v933b ,<CāSnnʕ+7o<|gWJS=u |I||[oY$\]]]\\XգWݡ~NmV…FwwпxxXR86EfY,w}733/ rvz _]y) '{s}g^{5B!$ }ooG ͔)SJJJ-#t:9N%'''--m޽wuK_={>|xzz\.dRՕe]wv@JAE& M% ɓ'+++;u[UUU``s]L*lW-QWWw`@B=68IR T€=SccdڴiS``ݻ?fϸ!ts`yu+G/{>nVqfYGyǟ|_|QTYOlCK3pT*ةYgA f֬Y·2L:<.˳371c؈.8:jn"n6k֬ŋϟ?-*=b'G}ܬP(.$X[„ +|Ӄ-kVfeo8 ݰm.e[8~*Ʊm+wa*^ M-$Kj9㴉[ LDYD2Ruh-q X}xb " 24.m=`cT/.8NX{sQWkk믿|^{-00PÀsӓP?;qwwoiiyhƍrم 6lٲe~Nxv#%)Qeӆ%Dl1E'OJ ϰJ}RTY\V97eѴF-U:,̿"/h8x1D[9]^<~dΚ3QڙB%27@Yɇ/L2{z軚; 8YVVtqvz444̝;7;;W^6l+&]vmܸP?Ɛ+ǡn-pYgtK.]t555lꫯtRK-((ܪ05Q϶%{^ MVXjrڶ'j-se]%w:DO![g[.TOދ%Q}氚P.;tG|?l]R 4u:yxxlՕ,3Cۨ^ygb'85449rBCCOg:yշNt!G}չFCI@o' 0aݘFIHqSo9@p;Ø=p46I]1öL4Gׯ[_t{w捺ƀ7'GѧXD,7xc̙,pz4'aH.LvBK+;x^sssSS[l6fI<~޽{u:]ZZD2`?Y,aSCC$tFǎwГ?>sL??iӦg7 )XP(X0 à~ /-~a\%%|uqq 'M'DDD8M􌼼~zҤI=P NlMpBfGBg=c1Ą ϟoXV[FN셻'8=N aa\j_U1رc۷odN}ԴhѢDFF2ӔzY0f38]a]K.}WJ2//OV;ܜٳg3C N Dngw>l'"Աjܹ~Fꫯ|Ag:vٳPuok-} );@1{]e76m#<׿u޼y~7g=s//o„ YYYnnn~f>{ш;S N ї~F}ʵGssYp寿/:tˣ>2k,OOO'-} o90e{͙3ܻwĉ&91f̘`wwwuoz'T*w{2~^bx7tO%"v`TKAn3L$cn}iS)\]]~a//3gEGG;-dff.]t8p$Ngf:F^p1Rju/WW!vGji'B$c q[kŅ-~ 5FZlٱc֯_֤m۶ÇwROXIz98,}+ŜY`.8q,caWq ĝb_> 26j655e`3 .۷o̘1Jґ5LQQQǏ; NBB&6 z\k;!onnf_qG]I<@`}0?8>xonn]t-\JGmljG%߳!$0Luuu嫯SӧOϚ5KPT*'qf93 B_ӓ}G^}kq7;[9Vŋ}}};/_4MPPVU(vđU_1fMfyq\SSSkk+I$jk#]ktx6<<СC999SNB~7:4i0I0T%"P?@:*Dꦺ.͆ X,s9r6 ~)qyzooo!˨P7 Nq8y6j6T(l={*_?Nl3q駆򂂂wygɒ%W[kaaacƌ42Ctz0HEM}GiiiDD{ァ m_+Ǐd X 5XK%\kew˿Ƕ;sʕ?ƍYCjnn^l٧~O :.-x[ KA=N=lΜ9s̹|G}s˗/4i8x`LNP\M566CNs-}$8.DEE۷zr IDAT/,,,77ӳ se^_YY1; NXV uM/tϨQ{キ~;33<==_~>`ٲe#G|74M_;qVljr6,xv&o\S$:At"V[/FEE̙3}||zJRN 8I$6N @=B$$qv-ZzjlL&[tŋ7o|]wE[[[ =]fcV.T__O- &cn6r⇫-u_;3f())կ~sYfJ_:((h„ ,3890N8 =r ׁᦈ$Nxzz}eeeկ%ɲe-Zf͚ŋ4EPD 8wԫF%%ׯ^Ϟ=Aƒd=ĉV}e---huA)5sկ~+//ȵk._{ݸq3g\'\.gC_)P?t8vbW.vb<<<祗^Z||p!ы#!vbc0zmyz㴎wҥͣkaD#(}陒rر_*vr<ٳ׿!CM݄]{P?\*0%s=ȑ#sss_~?\v}'t@ 5|FP:2[>㸦&'k#:"##˩SٳZ8ڹx9s.\iJ=a2Ctꇛ9,9??o憻͚5`g^vwz KC ckn8Pbijjly׉IRLP(܄u*Wӵ<? /O?if^N"PR N'"Nhv C~>'{A .teOWW^{ӦM4lE81=[HN8"l ڜ[~b ##مӄ&>uT*:$$D޽:'߳gϔ)SPX<*c$N,vr}GP?t ]蜯Kۗ׿'8rlfz)˜=p(CK8]aXSwX+rnH:/ecwR%00+&&&)))999~~G5j83{.DM,2CtAp-Wc;Ynnn&f4iRii|sEDDXBVKR6 LJb·ǡmhhSvxD"dr>IH1z訨?Z>ƍd' )pCqJ{I,9{N<9};v>8Uw}R v`0 ${l&0x]<̫*2P } MI4+N<cr.e#(!̙3 #DDDh4arBI- 0馠~600G~bccxŋ V b'p(65ا;>㻂0 3jX!pcNRTPXɓ'O48T* w: |z݀{P? J-KOMV~111JllL&cOXD5] J e0 !Dr9+'Np[{(~)^lTV1b'jzJ7833>!!xq"]9N&ӳ*^ @'ɦOGDyyyJ*ZO~'+#lxyVqBsa='"<k,!8ND]D^r""}0d\JS ˎ K"\ړ1b{Jr"ꢃfW3M++~z܌o/x>p|%ڎVIgN -M4i֯zrw + |!==)%u)ӆ&Wm Ͽ0=j"P80T'No)y4dXJIDmprNbaD&N3&lF6睸rhq5{ i箔@nE[Iiif5EdDDHWC2KyNck*"R}l_ʊ |,,|g>19z+ "+QKnj\I mRXQfQ`SfѨ GN]?WŹD)3s4*(DDuDwaQj""{! WEqqCWZ/}^yx kHT p\aǒ6&ktcJ9.l mDԄA:ӫYmDDZC5R؏!$caҫ.Ƅ'O;@?eٟDi%ee%%ee%9:*ܾ6Rx |^Hdxe"M/f[}\_V|%a Y"gLM'vcWϻTzs/%C wCex 4[iw/}?iѕ,­۶oc0`āS';b'诪vb5@&P<2έz/Q[<_UBɔNґq{^;uXcRlnʍں*,|FRu~ǿV M!"" OVwZu^i؈DIrˉLWH1S (F\)LHHץEVN'ڸOUH sW%#(% #":w!' ."aʞ[Oˈ'"ҭ_9[B;S!sCnID!1Ʊ_n""?=g5yO}d%9ҰRcSȐֽc^z;@4[j2pikR"=Cw3WבEHzVsLUM[F"߮n!)Gkl*oJrZUռDS+F+CuJōU5RH@Y!=/Oo*., }[$25V]lTrn@vVI~KڧZk4B38&!^ON0p)ߙ7'>0#u9;7݇* Ű;fu3j| _ ~qj9K,osJ+:<7s:tC}ܸVJ!cȴCυn1^s[bڢRKk{\ Jo W.}BD1H,0Z!QFvyItK?6HW!hOsfWp.";q>)֐s\M} E6)`'Rw]z@Oۈ.Zo[o@pя7nJ^Ԗ"{A/.ˎKݒqV`U+,5|_\(q>n6`冕q+RVϮ0VX:9Ruh-q Xm)ϞM"JH2 %DB /׍V{+W=0!DYYm=KYYYD2_ nNk9[2'"K.]u,Y+ ˳W.X%5.8m܆ ;J㸸7\tʳCWZ41Tn`gBzzR'K"R MV_0elĉ̲߭&*>x{Q );:_w 7L^]'s֜,cb!(楧' 2M'>VCO67i`\<"ҭ8Ș>PXJuD)9y2Un禟gk m~X',y/eLH6 .LyHDe CKʳFL[4$-cIZuUD ?'-J5/LBD*wKվ)cE&- Sݙ^[]mjJjo\r% Sh$=} $?{]쏭;E(V*}fH#;y6t#W7R߶jH־dޣCfЙ@:5E-JDw:zjމgT-hؖv ]Dub2"RBwZr04_ ef\_=qVP%¼L+FD KDli_DuVR%0>)">טg[.!N  s %2l>˽}/CmsH""'TqǹѩKgc?|(ۑ t~ɓC vy,6"CSWmhꪐB-Dd]#Oj }x'ꇱi&}'+Q=ʶ()xQCOv6M!]87%~Fᚤ=9w7PG0~HJk:|ȗu4?A %"pጰ+ 95mǞD y5Ơ/|0,d!3tBrǽTX6SDj %.I3&2uNDDRlSS5@fjsDi_g?m[DIrˉLWH1_9LJmEkJ:WfD9Ű'4f[OƑr"^e!Sڅ:?fl@tFf,6"|$$c^N1&M۰dX '&4*,|FetrTdLXSPikBh(cFBz1^QRNi-_[ڌX2'ޘAz~$H!3!#'*H1qN,-75RBؘHs?piN%M};;0 LlJ׬)͌ "" Q9E?6 L߶:lE`u{9B;C l/IF'LOBDrcؙ<6*[DDF)J0ųl^hn-V(""&*h"wNbH>-($F'8FG3F9*+gM^k "شb,j+/]oms֌HCD;wOL&ih'.Λr7LADD!;V],^ӭ*%xy};C"P=fYƆK.]x1** uupsNoooJT*rT*uq P?thiiyRL2nX(/[XU#Q{h1eKmuT>jR]]VT;e+R[[GRDnۓXxD!#b'"UM56Btb(6FR,jțjk%jѻkk[yT]]G>~]tT]Uc!?]ʅ̵___///W.% juV2Zm$Q[aZ ƺB}NJjC!xw'%Ju+ Ͻ.SڝJ,(~:ޙހ f#8հyygAUu`dxϜJCgtb'p(8cs19uiГP?t>TqD|mš di7\աD6: c)qmڡB{hDdڢRu+8wqqA&pqqk `n >H1lΜnDtfWpЮ՗ן-Sm%|]x{ 6Kj\'N,BʼnsvDʚx A,Y+s-DT[QZKDU7.՝)ጥ<{6()"1DD9=*I! ieH] u=m(nmʬ qU\uxZTX8 ]u,qq[R8W\y+CJS{(.tJ u`^e%q.%" 7-XUեkh9W/DZ;puykƅrPaaZrF|]BNJ$LFWIRT*0 qn~p!ޅ);P,#!wpE]ySa D1/==QAr"âbCLڍ;"ҽotMی!ORUXv IDAT'/:lK!]8o:ٶFdDDVDT]AD3mp0=҇mra/l^U+{ڈ,@ڈ4 c Ha?""M-W_Z^x_#؏}x bB;!i&aJd%D1c%##4מh<D"r<RSSfknnvVyyy9\P%T*("@JDƋIqd*FN})wLCD$Q %J̶-TfxO0G+L~i_GJgOȉE($9gE8̑^S9ykqiDD+'{[DD)lL!1 -ֽ̤cS$RQ8Wit4cQȚHAr""M+^QJ(*-&aQ"KV9k m ^1>;qjmU8ͬX֦&oFzVPP벶0 [Jy$Jr9"H\~Q?8r jmll4Luuu.]xbTT#K$ ɭXXJC^{|`oitSx+%Dd*P^_Fj?yjoxKMC-_[]Cm٪O{q;wRTJݝN8ǵ #OR){3rfy}9Ꮇ.-j7de2Y_h1J3zG%Fy<F0P~mIapt5.o7纫kKK *vzۈ gIȬ$`@s+BT O YNOc8S OvWy;s$'jk\[ܒ8X_B@Om/40k*ST\C ۇڧrbSи>RlaÆrJ5dȐ)S-ڸÄ/Yp}_ڸp6.n cq)'\b'Cpcۺu%puvk\!Lg/8g }b'%@c _ qmܾĽLyD=VX,mK`Pܖ0 nSB3oDDlMMM<ϳ.BrVo[ZZ~b' 5Hjn޼YT.\0--A֒W,YERNA 6?UAp;=&NKKa!o:t5""⧟~z뭷rD"HLQ|0Q .&"믉($$\\\\\\HV'` ~!/&\UUyÇ9{9z(XUUeZP uK9/ϣ_අ ny ,h3g?g޽{'O|СW_}O6Eoz b'--l6!j2{}ꩧ?O;]6***//j>(dx/ ׇ >8,pX,x㍽{>s:߳gOrrrZZlfϘcf/ ]\03CfY_ɓG>|O|ш'N[ӓR)#/q4%xgI_}@TU 3{aji5ښjV JmB喘bگ2t+M wS7Rג^0S,Z(\HlMS7QA``02 /3wa49<9܏?`4[Nttttbb+rwkZ6ԨT*O8=|6,|ϷjX,?Ü9sM믿/lկΜ9#PfRv@K;o1̷.XVQ3fL6w t9{oƌ/rWVz'\bZ ˝ w$H5a^rruV\ى4 ⋯?eX643". |4qbIY(+V:pٳsٷoK{N#H7I)!PA>iVkeeE>ӂ#FtFYXXtd&)=iȝG>uԬYzg}vuu+^wuG 5k֩S43Vx3ԥ+;/1'~?|̙>ohu5;_j̙(9f6͌U:^ui"NxNG ԅm]رcc=qe˖<ƍϟc>Vx ԥ[ weN$KWX,UVÇO>͘>}Ç׭[jժt0&JoRP>@D~~~y:-(OD2[S^^xڬHҥKqqqAAAiiiFVj6L=Znpbg[֝;wOڼyWGyg5kVeÂJk҉s)=o6*++gΜ'wߍ :NѨTv;#@t̙_C<85\s믿~̙'OEtd42U[cs꓋߈ G-+prss-ZojϷMV曋-JHH8r?m*&)ĩ.O(//NJ[o3[ ;6˗/x铻_RQ "J:k@aZajݺu뫯}[fxz*99Y`;2ȔNt[j~w=رcx Ol |gȗB| íalWmmmMMMuu+W****++jjjjkkEQw1T*ZjAAA!!!aaaAAAl1+kTi7@N$KO}sss=z7L";//oʔ)=\PPؔ' Һ4;'N~og}vŲե;ST-'CԍX:ʊN*JRi4Vˊ~Dkrt Nj&V}д@1'Dr]]]YYo~Z{0̕+Wl6믿~ײZ:͌RQJ;uipX驶a6kjjm3ZB7_VhZ>zvDD`` +:>^8 a[{lԩF;wק~GC U:]D)Tv^R&'NL2e.'ٽlXjjjfsmm-O'^fl2BRKz=Ai4zvk۵dɒ_~9%%Ef`HLL4ZtRv*Wu邂Kx ?0KQNS{j%,AbxG{<}b6u:Gĕ'4x+p պqݻw7Nfȑ# G}`J+PpC_[8!*=lzuPV\YV[+pjjj{½{p r7ɓ'>_ *.Rz]қ#} $=>'DžGzX>#x/㇕ѐ;jk FDDܹS3ͳgϾ|{#hƍϗSJ;uip18!wINİzO]"wr_ha2RRRx_~Y9FCC۷gddDGGK `NG) SAP񼈟R&vN{؛)Oر{,NLrPfZnf7غuŋ׬YsbN)%'QJ;uiϦ_Ry$.r"a_}˖-{;nfz'xߪt:D)9RPJIKN&tOƻ E̚+%+pXʼn^tɓ'?裾}nv٩S8paaa|VH)9RPF]8GtO_}p'_G g.Xnu:-~}x7xp8{ N 7I)f֥?#K'%% <8>>ĉ.MDld[`Xn G4)qbgȲxp|^ذaȑ#*pK. @N҉d~BQ-˻/YbEOH^xᅿ/<ݻ- '?H7mKzH^Z̙3gv8%NTv8<ӧEQd6ΏIȝ@6X,(+W>xYn̚5k֬\[[vql6IWqF۴Kr(3f̈۽{O.et:ݻ?cƌ/O6O8#fDuuuK,x|ЫW/) .L>=22rݺul&U:R JiWi9*NVuϞ=?|FFFϙ^ٵkWJJʊ+f̘tz?x r𴫜 ߧ 67h4rT6VGꫯ222 hxC(%'QJ;GuiV}Wwvmr7ӣiӦ%$${ۉLԩh[U>)H, oOяl;*S+22O>0`3JKK[]}tOSZZZnnԩS]z.\vw9_4-j!wr:D.bnnOW.=d܌uG zpU1.;m URphA%ڒ,e<{,yWa 7?BXxAC 1:nʪ5Y<2>~I35~uROJ^vۆgXjWc*.g}(ҵIRmܸq x穩KOsr$SKKx!@wׯ_rbTUU]|ٳVܿǞBhSquTŭ-3&G"2+I'"2"YSPZ)RO[ b((ڔDDyO[G3'7''gOQҦ"Ñg!2dQQ]Cp[,'/wMk-g`NO!]DFFKΝtRuubaR.PRy"mZkkk.]tܹÇx㍏>h]]OUBDt eUN4RC1y 9G K6uUPcX`{A>| N3,uʡ{뭷Hӱwrȧd&l|~8qV]d$+h-6.J'2V;8(|b282Qˏ,E˒VUđaŚ"26OGQz`0|S̊jKQъ/.L"RCddSǍbV^F,T2;;9'''?ZEϡO%#ݾe˖{n˖-NPJNvve 5VVV^tٳ۷ok:\ɈsƸ59窋DDD}C""CjzˏlVıǒv\NbRYgc(fcl$ۘFgYZh8iOR3)eMf2""ت=kR D1I˖QLGƇ> \ IDATgϞxbee%XQx화&ǏoY ؍xщEEeeeO&K.u bҋLEF5,.J')XI?Sd$ZvNeܖS M'='!ZCYӉRJYbK5/s8\WvrE":}tYY8pPZjsOՓsnrA]uirx}뭷nxH>:bGt:~_5j޽w}qøG^67=3gFRjbXc[Ed?O]Et&j-Q1D.QhP㫕}n*lAjzrǮ8qbʔ)>`;f'''_W:tO>i˝v?f#N?7xꩧ.]駟ut|0_0(.}7f>?NOc/=uh CVfĤ,A4 ={?լ&yQ4"D"w_[|VcޅGG5<d"3"zhEGG )lG QF1rwNw4:yզe9OM4.ی4qoe=Gq7lrOj`ҥK?CqqO>9sѣG8pc2-`2h>_rC<_˯S Buz{}_ax摊(&~~9]{ӄۯJJJL%%#+7Ps'"4hѣGz-֥Yto u'.iщ,]w%W{|{'88x˗/_x3U׌_81c!RsO'3_RŽZK +_kO6%"2lBTg'ҏSS&n{ࠦړ68~cRsJ_4hC3s?3n!QܚҧǑ\64qn!QL iXܪ'2sgbzAqɝFʕ+SSSGbJ޾/OO57t_|хuٹmX0OC]6- x*hy;,Yv^wbʧNo򲳳oK/׿h5;w܅r[_j+pByuT_Pnqᛯވ Ν;׬ mլQΝ+ȁ\uuu۷K/}G~7 ,N `?!!o7o|yuS3;3e֥˧z*""$"JIϹPm>W" 13F3üj۞5Gu "Jɶ]1f\cL>ƘKHÊ守#"Kyz Q\iQ^JD+r}GeM_CDEխv.G:+bݺu+VPVVVUUܩKp(m;[8$KqVbrʕ+W;}}pPGK|=3`{'444444,,,$$$444888((HӱO[o=[lINNvٯ?Ö6mZLLnmi'yp׳;԰ }݆  6zlF8_n!.** 2:$"\W*[HDKIJvE bEE:͂7\VV@'6mYpVjEsE?~D;CNZӧꂂO?t۶mӦM^OJJ;v#BBBXeNh4*JYӉgn喴)SH^x;g'۩NlpX,fʕ+.\ؾ}{HHȇ~)w{ԥKNZ]]=wk& [ h4ȝG:7㧊T*Zh4M`` {k >|}ݗzj-VZhܸq[lh:xWibZz>V700%N;HFYs fJӧ:6,";\,Q]]]SSc29o&&&xȎ;}z뭬8rVXĖO?u{ui6+aSsl[.(4ŋ}@}ꫩS^{<$QEEdtnˈz`]ZPwoI1oY}KHH8p߾o߾}Ct~{-zN;}C=l=UK ui <744 _#],f( =ZO:o3f HD<ta~A8/s($ɝ[w؃?LP={vOKx!NiyPJ%͠*NRcǎ {׿>b˖-ocbbnfi' ^qRt3ԥ[B] wU:S􉗞ǷzkhhSO=uرW^yECCC3f۷t/Nʒy߃^CJ?Z<߿ٳ}o_Wpp|?A'UWW'$$Ξ=;22200D4q따zԥԥr'tϚ&33g >| SNM4)888!!eVY У.4B2tju˝҅(<`{Çٳ箻pÇ>j([daXK. ;Zi$͠F1}k>ڰaO?=iҤnI8d~SK+pPF] wr58iС!!!?W_}~zd/Zw߽{tSKijYք84^x =^S,nHLL?<<\ӧ㏳g׷B"VWj! ԥQ&ȝifVYj;>Æ ۿM7$o3fzp˭ Hh uiԥr'v#ڽO Ƃ!R4LIH#$f„ Fڱcǽ+_۷/11ȑ#DIYWYxw}=*s5v; uiԥ xNQC:8J!bT.c5eS,lj+BgϞ?S2W_]bŽ;h 8IOʒaqkNו'eپ:kH=2v=.r'Gs lkhhvI^K>V_.J$]X`qM7EEEjm{'&&^wu-!~SKϬq 2HG-q;~RuW r'Q|t}%-]0*WU:~}wG]{kKLRYY9k֬Pi֤y8,g}> pE>qdѽאze.K wat8_|mqzcsϹm/k6mڴnüķ.dwk][(:\䣗ѭPa !wq,^?3 NtHVm{ĥo[Z$C=tYfEEEI'oNNjm\BnZV+ͻfBkH>}ui r'|ֲ؉zSS1ժVWV8oBBFg?t\²P ui<r'iބisjj~$.F A^hm3r}ׯWnZ,54d ;hJhQ{`אy'rP:!wO෷j`EE]1IS*???Z2ZI|)So>;=ztڴizѣ x9s̾}J|#޶'oV~<5; ͷ˵puiB9 xâ[׉uE pu-WAO?{d2{!!!DT]]=cƌSN͙3'<<&VK! DdlR,f,E@ZjGK+N@Vȝwj~ :&)?\J$T̬Y<8lذ0iҤYf,iVpkRxIübaSߚk:v+-xBGԥC!xp+N wg,+VNG{>q,-WP[di9. `ԩ_~NDG5jVt@MxWדdٞQNbuABӭrq ]!Fa{V[.,:[!wOKO f؇Zk:ki-.buwuW>}#,wbK ;WHY"KnXVl6 㸆qgC]Z)Q׍43 ]&Yė:˩Xx"$)aO%]cEzx]Z)3+ r'ץC;@V8M3Mӊ'48NtةDM)a"4tr'*IeT? IDATQӶH|puȝsl5ߡAڔT> ui NУ9%E%_+-v"UD(܍^K>|MEvuDp a2̡0o7Z)MN3Œ͂_gA|4ަlےX]D>}K'2U#v"0VwOOQz7j͛ n]f--l׃I"fmjb{⏰uzֺJ >}z'B',ٜookgL3f7D2F-tӓC7BC$:Uiks6"Ҹ̪""sϓx iSNх IYKJ\N?TS`]wCM$jb:,?iYmgbk| z%C㗦^(.?)8oim|1o DRkЍDikAl.ZCwV.IA]r {%J-YqVdے%JZB37GGG&akD!22(;qaeg?2G ,Q<2>~I3xre|rVw$B>x}e BڬglAbך*ԳxrW6<# * "mZvA| l;o'"d#:y[y"K/Ɔ2qɮgWnX Vi'EG `_1ա.S%+1Ƽ7 ׇȺMIRW[|J-[HDKG>[{" Ovm !6fDWTNsĪ϶f-O]:vmnvzqȭ%"Z}!Ɖ;iSR2sӍ 'NO+$ڋ9Ƴ5j/^i + O\|ss2UBg `2DZ?0']ث>o^I֒ڐiKD5'RԂ' 7.dK?ҼcK#Vn5cw('/wM\V6L[g r6[=ϪDg5ryURAii4wLm%f{Ŭ?]:u>)2#ud/yטUrrR3diD.Dj9VYZ4ܥc/΢NJb=ѲsOMkfTZHm%J=~D3vzhEGG )lG̋GEqZ>n Oy27==KEt2x{ڗHn ӅDDME X? 1ޤg63kF'F-swEWdtOݫƅӝ//>a~T"ZqDμ>5j2e>=BO/l}9D"_k%eY*W׼Cd{h=M賭r2PQ܀Z9'|P:;eʈ~/\y$dMr-Лh\O[C>W""U)j 7DTrԍaFcxPO(߇ 4X =ImY2U6f"C뚺OFDuK17~TA_dbkXDev-nh%zp"";Q&˔:?tԭcOZnҳt};ڈ 7^%&d%J9^ՀI"TY{ׇ4KHDVQG{be6_#>7Š+*r'Q링?TW"4qh+325NO|@?->nuDƲxw'Cٕz0kNDTYY۪cCeE5v%ל" TnDRη؇' VrSw,RQ d5L#;A4:ٷ~}0(AZ6ŞH@PMDaȝ=h>|/oCn=#UKJF#?OG/4"'_&'vT?-DKZcy79iEsim|c|| iCn$*[Y+9ľNDJJˈ(hSTV{^=6iȨ)<%Ld޻*D PBȔ^aմ LvG6/e@ii$'cP#aSA2s?3n!QܚҧэSĤ-%I2"u'bfʤġDdH# AgGK5 <=`H96!JE4heC8ڐ1=7ؼ^yDd}bDj˙w &"E#yP PG눈bV??{ϊF""JI{̠WQbzR꼑/?QyƏ&Y14~qniZ U7i3oJFj#+?7ZG-JZp푧\뉭Բk?>I !w544vZ[[k6\rDOe嵁!QNΗI;\l!Ⰺ6uHTaΝaaa!!!z>00PѰ444l6jjjΗvRi{nZ"u~aE62:$*\(wo=" [lj*pTVV3|e>R^ \L{EY9F۹pvsYYEr Ά/Nhj5/pۃLY5G vQUMCk=Ց5vsYY:wx7uE9:NP飢F1mTޭ}K{z }TVmx@<ޢT-NIwgkCh ods':]Qi@;@;@;@;@;@;3AA]Tr7|??k.P iwc9qz~Mӕk :C!xp+ H> ` tqz.gއk!lB ]ࡣ<C>Uc87Q Rxߟ \RF0[<G_R&#Â6P0v~@za]eP\ÎRjeޠI~ᅥ<9g] ;aHc,;'H&x&= k֓/紤MAMJxat~~~ ͕ZօoԑG=謯{ZLj59&D^x \%|I+0A(%x|c<xtdV Lҽ,c >4&{)olr|e#&*eM>ك/7? M_ y/ iv=Ƒĉ}k^Z HTz >wNPJ 9{d p6ߑ$֗.khe̝Yb!wOvfNci544 r'@T,;jhh`R}}=@JƺV&Ϗ$&???+=I3;xr'S}}n E]L&tޕ+W?5_ȝ<w+ef:xϚvfc| VAVT*(4 wWH?ednvnO{'NuuurG^ԝܡe, х\.1ȝ{di:q a!fԥ1*֭j:"wz4vYc< wPD [[ wnO+VziE1ƹB֥%/ _[0壤;DQEQFh(ώث#w##I'/Y`/|S t>7 Q]ru݄Ϋd5? | `kPw_Vvc) r'1NӲ-d(y~UZhnAT*h (@r'*>-aj5|;)hOZfi4~p^| -q8^{̷^rER(Ok;AW9\WWN^(w];1zx gEȋ 4nGE Ӳf9V>>t`|cӅnXEFNnNVWWJ 遽,9.X,}kzUUĉnt!/RWW~,Dc_b% VIhamO%!]-+N Vw)m]دKr'-<~ZVf-r'|c Pw(VOcaN[vl$Է>o-keigwN;iI:׿N?H;๝;' v/:{3xՑ;/AIENaKuıR w.f8Ivk/ܵ2Z!zɆ+A]2dKNYJ¯QɮgWnX Vi'E""ɃIBt|ޓd?D4rӕ}vNDglAbך*m=[Ixf՝XHxvȝ#w7)u~c=_Q֮OK5fuմ ""(L?qaHM09=I=뉑ݓWȸp &"q1˫.ݳlbkF-1%=1gdS"ۥ[/ly9"3RQHdC<)-1<З.c4UYĒmϻ.=4/U[wȝ8,%Q `X+w߃"HwN+wz4qOj54ߵ$c9-UE$Pbg&?*>AWӄۋ>MDGq":ZP<=Ӵي+3b Ǎ ]=rT"Ui=螳}f2hd7iHMD*JӳTDy+&d)q!BUfF5~}bI3ƅ HC).3 Zɑ<[7h7;t3l-RVr}}\Y VIZfʕ+/_NLLğ,AعsgdddXXXHH^ h4*s%Cg7UQD(6uHTxŜ>k(+C"<ղΗ*mDƯ]Ҫ~{p-E]תHZmo4/)woH}qqq~^ l6jjjZBltFV#F8g\Gn"GʷYUU~͟YѢJmʋTZ׵p_ PѸp|Em;ت~$Z[T\TTTgb1}>Rv8[zne(zL'L_ִ|= j IDATi(B0`0өth xf3 o ?{l $,+hD8Nc y\֎njcocBml86IBȦ x7't#ʃ7+DԕڅNX@,hČ@O@yȣ {^@m/)P^zhi։5|SUۧ$Ǐ=ng?~~Hyyu5青=v^5 LH B-e敾ѕ Ԡ8 ,ػOfr kXM QBUY:%a5x])Vj_\;yı6KdxmPRE%x+̚S$H~We'B~: IaWHw_lQWf5 Ne9h+DbȲD֌<'Sޚ-y8cK^ϦiXϘ'Z.}աm2 &SSB5 X2_q l^24)MMEƻ&OK(sZl M9,0!M u>h(.De;рlbFQY8c]g3m[_qP["\xd9=BS}w`tWsVᶢǁ3_;xlgi9[l0u-s:̵:[rW𛼢(;@-\T* ,޻ݯùHs] "Y_zfi& !ˊYjB[QZNTLזo7ԉz]9vbn1'!ٕܨoy:k=_7_uqrXƶןr*;ϧm矬9~Q!cWĶ;ӯwq /fzg ˻ǞN^3,W-d07B>b֞Q-gy"" H2uX9{qݹ@ =32iY6$QgQv"d9Шvdrد+7s\؅h9T7S;\%Ce'&}2܎mw*EIUrq[x羄Fvtq;EH$y;\ߔk~QîgTnbK>b^d_|}^`B"*D}$ƪ[ ^ Ьl[6/{5P8Sn58wAP*8r_0׹ `'9NUf6u CY͌:ŷlD2rHJJپ}$[_dRw{|6#&_P_GãE烶 UNd r6TBċo.uw}c>2y `lEtT[g~p;OFLƿnt9fAt }U>{2 qD"?N/å?]z Pm}1T'g߉Ewi\].gr-jQzjN_LQ:lehtp]Jkf~Yf/7E_n[LH4ΗJ=dKy<8 e'&aC~&侜˫v|I{CJh>96nF^=PIn1wg_RS9HJ? ѻ)@YA{pzcN4vEvZhٻv מ/lyY!m_7çJ P% 4n$󙰿7R÷n?K+ Zq[7o4o M w=)qM]wq4R9?nrHXWp|V#N,#5-_M#:Tns-%2>^|=?8.q? A[TBh &Y䊻ʌ]|nyTaMT*s8@I&ӿl+y@ʀe?B='[F@ys))/54bS۱ :!UY ry6H5Y';fkMd)^zJ%4>^?mٿU*р`_[.C0@4{MUlm"{IuW@P_-e'[- UG-7^_tV3ӛܨ++. НOЕ=$kDȲQ|!6oZt91,)T Y2M 2E|F@sE[pr\"I띞vNO? GKpMN+q)C/xNB!ʳvH2&IvM OJvL8վU8%!!!66VVThLa3>VIn@r%J!c8SIxMg0uQK.EiBqqq췐RXFD>*)jY&i 5 1)eH&L2Fs-n^Dl. YO?ŠU+BbEv2jaY.t]P!PB!sKgo!;BYOdC#]GىB€!5!e'Zg]&S[ݻg业ީ}Qf_:Zzd$oe'B Nds:,P.b[Z7_Opxo(Ui@-YD'M5&Qv"0D=Yjri 5:VW_Q0^]̼ҷ:i:/Rq\f1Յqwr:NIl+>^WqZC, u&Z<0To8_=p.8,+^s8k$VWZ05W sxExgyZs=D!a@ىglc~ǍޚԹ\oH-G:>7z0s:̵Ժ%f9sPo޸u_Qrږ\oϧhmr | >Svb5?c*ξ?-B1Cb4?ZvpHr` UML', `*GVN4(,͚/sxp/onx /ޯGJvy6>EoLB@ Ֆ^}?jcve=7j\% 07>8klg6/XX5۶^"*9-eC?*7e"縢FTlD^}q ͞d ܟqz_XX CqYGtA/ɞT/}W vuȦ xT FvtNEHX[Y>8$jX]V菽dFϟL82~WQ!#6dZU!e'&د2v\c92ys/9'7"IQry<.[wG7v'py\Vs]&㓍-W+jO@xVj٬mzt5X@$;$Xv!{Rln?&>]ßWL۫gΊ^P0<0 Y:*t78!49N7ִ[ M|>WNoj28{{h:V?Nv¾(ܰa{/7tn+HHIlߦMW }%e϶OAkqju0abՎ/aohPR}'?Kj7'IiYs xˍX0˟^j07x>M\ ^O !Ic'^¡S拚hٻv מ/\Mx#*S'ZCY( &HLXPved7}|WEHDve۴/xN'%N5|) WcCV0_*Gىܖ6loEC;0Q|ȤGNf\r\h.8+Ԑ=lhJ#{><\=oXj35\'NJ2o䚇>E,Py2͎v uT@|;h}E|a|糒:Q5[k: &~>Y7XKCj<Fg`7`2˶/{ ^r߰X3X]֗~hOorۢj]vqyȊ [(;I`Ɇ 6nܸqHj d7nd Y2825ʕ+$yit:?ӉP-i8$-T )ǘ(WkfiSi:>NOذC)4IU,77S=D̂K()% &W;<q--- jZRDGGd2vrU/)1Ya8$[PT2W,zf_4a8!+ʕ+/_z LOO\.555Gh{{wlڴiӦMJR.r Qh!5Yf[F7~7$]3E(TIwP$\orfuI"LZ\7AvlZZBֆŕ#2jS\`̢~'rXRr{Ev= ("ѹsz衰uEGGGGG+M6X\ξaO@ى%PcnJjBȍDn3m#ɢXNr DQ$))&&F&객-r'111J2::2IEN,Lu` A!m%N'L=33iӦ+Wr|ffF$"[ZJ%w&z ONmC##˿gDB,e'r8}YXbSlGI$"ǜgM6dΟC:d2'P D!k#:Ys[!}mfÆ fc8E<;y_2'659 N4{%ZBYAs.e6ND;rXד8o'JR& Xn-O,8IVe'BYl#n嚞zм7x㩧t):j*;\Y% N68]wʕ7" /l6l IW>a+!U?# ?Y%-;"]a˪0 i_VY"E"|^_4TzVe'BY{eNDT#YpzlߵvR_VETff<;0e'r[Z o5d'vc8 TÆ!IYLbOEEE%P؄Tyq#6RGM6) pY?cFu!aqzl\.EѿvNg"] ͌u4NȽ0!e'$\(KdNL("ˏ˲=kЋȂTke^|||p})tD߄v_VKA„YSdNNJmXOB"]"\_ gy)f'G!%Nd, NBNEXX|$Iс=Nk%;mqɥؿ*%8'_!Qv"0D:W.:oQmϿI7/_,5 K.?> NИuY:NKA`w_.r\PYjH-2ClQ#_uR"\Nt~>^^NR_%Ef!ylN,>Ѱg\LZGވ/.y U(B𗊲!e'$w:qbNXpb["3HYG_TTB'@* jT:F.G7*NEQv"$Rh޺Bى,vbKT*:3/V2Q2ǺX|a]O,>јf5oݤw(;BHPv"KNr?'26xoff&pεH-T*\EEm!BN e' CEQdXpZ+\"] -B'BNR/M:1;$ޫL bȉ7^*NnpDHИuYQSd~ N$^]g2a-KNU)5h9˫hu܃l 5Ԝ kmQ̵2r+Y ۤ1/=ʒe,N4WY٣Y^WTed"R}JC{='~`q_Ymִxܮy-Ki͒ߣ͋cv'j(=Dzrg{ RG?glJ :<d(dd} C#2D%ⱃv]CY*nS̯໛U!Z㮎o_Q>OXk;?_+yjAىB€Y6a{rc=N,;E,dUޯ/FAfZm6k] /ibs,Y2v\c(~Ȥ|mƐ7qQtP-ËzRoQwٍcz·Lznf]&8CV9ܒ1]R.5s;dr&m9DS37X'SoRx/BBKI{~:q\~4<ƫ@B4uQ_h*I$/߼7Z>d2˶yW_A&dGV)Lˠf$@{ル!u2%r bzzv;O?tbb"''>Zq\KKKBBBllZVT1112ld {ren~q6Ǥ; M9<^$%Jp!pLkT HnX<#L9&E5R$ $)dǔ܎IAO\kL9q y!lE / /,KQ !7h4D $h=B!]ʾ$L&'$=TH>2&I5H1)JcT MTq7d!ʥPinD!a@ىBxH N!0{#]rk(;)4޺B?B!7Bp wNHĸý'"rսS745;(jїzONIЛq57|ƛZF3Wls4i̟k(ND ;+HH 9>111q˫>u-{M7c29.bZ 6lX{#790{DF P$hi;WKߗ~N~Ғ{CB\ @rh}pas}/n9]{DQv"0DOz2Yn&mmUMEoX]@WY}k͵VHi3~6B"k)5h9+~wvZ?Uqg(OI<-qjw_G=3408ma [=Ɏi 5! V|5@O]g?`)>h82C-c+88zvސ2Ygjy+: o--n 5Zw} 1Y7[š~w-!IHa_Ni#ue'B N$3=)*?]UQRkj V+8 lT{u2JJʤG5V˩£5AWXTּuG9c8NWZSZXz`:f0 ֪@qzik?>USZ g3*-ڍl]g3m[_q@8QQ|oh|$G{GM@9+yʊ>sCB{+߻ǘTpףGM_ud\xd9=B5 X2_q,_;xlgi9[l0uޚԹ\?x(?gsʎYgLE!>-z㮢V)xK_Yvw)r8?up6NkNىH1{닏%|u:ϟliiGRzcyKe`trndV[[@ːl%<:;j kN:V6{|>g@ny,{hlYx/z9NSj|>I VsmsYu@u?7󀮼f.jiھr擡6Sbo@G.}ue1];{k;88xyz/_|C?QRyloq|>OuVGCmچjya`'mۤLk=>fL.f!}8U<_e<6'@gq|MU7YC7kZotYt@IuRy,1xK7>}&ֳkG}嗗~Bo{G$L߉km%NsYNvFx.<럯-~wx1kγ+%S{;8]t|?Vg Şr4Nj]oӧC{vyd^fYz]9vNIJ?7- 0ٻ.f;OQ| {d=ÂpBH֗YScS=7smA9'ܹܮ7OS6 ^ (l[6/-qr tJN࿝D. vo`dNytxi̓JN.O!sD3cܿٞe61-<?qre2;B]珺ك^ٻU]E鬷6 PW\UP/甏KQ-|W7=M=2|D!+ ?ij2F􋿶[j'O~Nγ{DxӸ(\䐹[Z8cKQhxh~q,򰾗3;4/9@#>Z[ M|>WNokg,V&mqy<} =yc [w?]exi5:kQv"$Rh޺BىLJ% Dzċo.uw}c{Epȿsb3c]MзXl6f6Q_K9vȾWB7a fř֠[4{?|swEFV9U@J?c%󙰿7R÷n?Kwnť<XpZ1BrNg6l] @WW 0f YD;IS n3E=?iE_V0ꉏJnWFvҹJM|cl> gȤxgߑE!$ (;S%1$ ӯҎmw޹Kz?T*@v_ɱ/ն`S%sE۫*Qܡ=d#'u3'u4#5B@[ D)0q+ZlRB-@9ʍ₞ג[~ =,h2˶yW_Aސ㸭ٕ%-A[R kO?[\.>+jQv"$Ri}Vd{ه}m-۪"Q7]Z@oQsn7@5E3Zͤ1ՠF/;3Syk`7[2x:`_4|d*8=.}{CqňEK\Ox裴H e$W\$NOOn駟NLL\%M$bs&.`f_=69Tǩ94Mr;Ny|RܭL mIQ 8i$8f.Ηmϧk SIxŒ16)I=%Ad2lAAA)2vI JMu ZZZbccjJd6P?En╸KjVj\V|;;ww,E%8ZPP`Z#]tY\RJ\f*)FT*]ʾ$47,NQ(L;QNbJsi )4I ,/رHh!BcNdR5Ta&qmz*q\^408ma͠Ɋ"饭g_|̩a4κR$sJYa.x0O! ;%ޣG{ݐv`kѺƣg83/p]a}aY"!BN e'JB8;Z V n>k8n 7ΦP@5lgl:VW_Q0^]̼ҷ:i:/q5S6H7Bn!dg3*-ڍ}w՚,/ƿ8쳙6[-F탯8 ((s>74V>=+@Ǧ>ܐPo|^@uG=_:;ynjX6 OL9-_?bΨ7*jM☒!K2/ԳSu[Oae;gliN}-Uq ic2gu`gl9<LE965?eG֢/{[Y+aQv"pȪR䶱;Ӭ}Cm:z|-}}ݵ`+Һ:-m;ec M?@nږ -+oٺKx88 =0`57i5ȭjx[]xSGwGm.+[:jkh%6`3tOoYڛڸ[_[-[ؚM*ٵe'yeUCmچjya`'mۤ賙tmf˾Z}>A]-졎)|Cs LmC糲]Pb}>u@ uL\k @zң倾PlO>qc\U0]oăqVZ@oPwhEoLB@ Ֆ^}?jcve=7j\%ra ɶepq~oD pL(•_{[ d|zG IDATItD'!xO% |L))jce %@u_qUAvNz%]As {BsKrgEIUJ؝{힏]y9ݽ%vK*@)|%!6vSe;!4fo]1{duR=VߠOMTr'r#rtrڗaCf7_Κ8ɘΚ@Ͻ~L=۶8Sn5䲱_Wn82~ rϚm`cgO^k968nKЏMٻ9g,H}rjѐ}ffw.41r;4..39dدR':,dwPTcU&t,'~D5`^^<6ȵKYIQry<.[wG7v~~h߁c^WNH3m6#%[D!a@ىNm?LclLr pqf\|gvk){{uKv[_dRw{|6#&fvLpǗEWi'py\Vs]&㓍-K~zJhz^ gH ݀ԋvvLT[?ǥR7Rv|SEGଓ޺.etoTw&1{ZBߊ_R9ڵOŖ_f;߸OU2ϣ_%`tcQɚ ]w&%U0eoM!$ (;) u0iXz_i¡4Bw{œ]Qil?Pm;?Q[`'0 Wr Plkj}] *)',j/dzIERZ\BRi96$hS/5aص6gW&؎;h9N`}Wl=?8.q? U.`v?k/~ `cr[^ޓ6=8 [ !u3q[+KZ SBg_X<󆥶hU=q Y{_V>G@uܔsܖ}E7,MC%@y^)+~F+!Bc֗HlE־+R >8=/Ut:66w_|Kn(Fy:4XyFAI،悹[s@ǴaG_kyl6{6f O\'x4q{%GG}\CC.qFxF5>444:z<1xc1ar|thht2`Ǽu)D JOUi+Z=o766.8H e$W\$NOOn駟NLL,%cLc8ԔrM*Qc1;SIx*xpLkT HnP)d0gSwR7al!$[㸖XZRbbbe2ن ϼƬh"IWWck WoBnn'շf6Y4Yd*M█BxSU ,:"N(gMR==!^gh UI))BYkǮw ј=BYy=4!Qv"0D!dJf_(;)4WĺBىBnSBo&NA=;0Vk?&Sh9n{CO- {72븻NUNn>U!WnVx弶\g֓;+!e'BM)%+y3p.}_!@uۣ7q<Ϗ\ A?{gq홟sl @IfY;2|/ fEىB€!ܦ$>SW>jqΌL3pq5ګ WVG:fpc8.3xϘ(z[+qڣunxIgHRgG`@o=j*+Z[K 8CM/>U3}4{i:/:OqZCcyՃ >;yO۫CFt3upvpZCͩA`kѺƣwQG6ei9T`ݴے!]6 [ - ݂K.T3$&Ȝ90?**3ԜyWlx͚̜5 Dns} GNx W(;Bŝڥ;٠T// uCS &VTPW57W;#إt_lJeU)v:~2m917$Lo,1͝\xuQ7?QR/_K^c `<MƲ١_.xnM&CsGw))H{b޵h kju gl,U-4'.w:hJAgra :5`y/|aZc]]7icV*%/O^WڮS)ɦ;k'6=@ىB܀('1E  x㜗k4]8y)i}t0hFڒJե/*GdvZJ,7a[rH`>, _5OɇHA>R UKHbE#P-ہ{W7D+a1xyWyq[ @ىOvqڝ!d堘<*P9d9U  oQ8`y0 3y3{Ʉ(7]Tr)d , ;%FIXa*f8@"7y4'T,蒯/rpU>DD ߞ]Uw 1(;BPv"qA:P?zҭG{*cq7;4qP7YVkli{_@[RpXۭ-b9>`j>>.b҄j|{[abK:FŞܸeviիady$1_!e'BxuL'OTռ tVLyT ȁkܗb A1n Lyy\W1?fbg>?rrcΌ1?-Uo*~?SLY? 9Ͱ}yE*5@S㷵&`{ z7iV\%.Jl+,og%i=!B}D!c$I$U!.ڍsz &rcyIņwոL7h52@1gGuv(4'3׍DOLUZX`{zcg)I ݘ#dj x7tנn<}&@ C@Ÿ#t,@J_x?ĢGʛaԻ&! ((fX,f̙3O^|9 ) ___LƲ32CqD;ExKKY2G8ˉz8<[ZZ Qua\ˉV>ʐ P[2@&8*r%K]dUC\555K.tE;P!_!@YeY፠@y|c>LS)aLAىB܀ڝ`\Z$D"裏Ξ=k6ϝ;qyӕ]v=%xyy,+Hr &M$O)Zr~}Crnk6ca7V NMы >58'tO"WKh˲,d2\n;;;xyyIRQ +r k.JRτ |||r0$texd1Or%l* @1=8nAm)q $elݨQ|m6/}٭v@yz m+#Xj=[ MWשpь!rURL&n;QÌI˸0 #4IR\.'L&Jn{qc?Jp ;u0e-Ti6ynnVӶh }]Qj&yqbfζ=3b o^?q#57Y݋!e'2$J;;;yy=n FKӤI=]K,+4= Whz#$ ֕g. ڰ@#:(ߵ1R,㱎r0i埯VIb>2!!@ޒb6> {e'B<+t!WK NK't޳Bpx5x" 1[G*zoT3~ẅk> ǫczO ؀B\8 ܽy2Y,Sh>NpOO/B{L&s8Bo=!8f<]K?ED"Zd2'qsMkRug9qڽU}Ea_0O6\F<{}F C-N\ȧ?S#9bOKo <~xiL: pi7($VBcWTо鵕oNLV60WU2jaSҭ!p~nCXSFKvN!&( J|,/xr[E I-|290Y61 P%i՛S5-˸!&B?Meφ2 2zcY>&"X(0O߬{F Nnt᫼0t8P@.'OQ^=h=a?0}lY@e@wЉ\jvH,grrEֵ-f_`O J|hcuuK~JzPv"S޸B2$L1ZZ^^^jȠHLJ1)qߜeO{ B9v$y2d76Pv"7D]'d'4400݂+2(%f(Pj"dD!n@ى %}(NXeGoK剐!B}ƕ퐌F;!D!n@ !Q!BN e'B!dԣD!n@ىB(;BPv"BF=Nx W(;B!e'BqNdg&??!ĭ uW_2e'Bq}ӦM婩힮!(;j;8IDىO>{ ݃HuEEGGlݺ!'oooO׈\9ooaO! hm\2׿{?vmWtq7!5y{{,Q4qŲ>y!e'B<ڝNdDjSSSZ_WO׋qmqH$䣏>:{l>w\GGq.OWرc՞bYV"r__ &M4Ix][ꌔ! (;رcgywbbb>>r\& e'BqNdr8ׯʒH$FDo>?]2&t:zIRL#'anw8cH@@04 R\.L&Jb=g1+5mڴK-[yT7T*yy'.tN,+4= Whz#Qӿtw}wBB01L NK't޳Bpt5x CC&'T*uD}!dDF_|':uN:'|\1B5> B Lp8zBpF<]D"8d!NDPqq>o߾K/>|r[q?+@ooo^ggNy{ C@5arI+ڝ!dtDFٳg'%%k CddL6{1e~[3XScf+ '%(;2QӸBى8}6ݻw֬Y[jjE_wqatmq7oB* ]Z((C8A9(;B[Pv"#}w}?a!%~!!FUJb:@L”!dtD!#%['d'44$<]$f( ujPv"S޸BىBF/}cͲc' kD!n0Rd tAܝY1D!n@w)2:^U !B}NBȨGىB܀v*BEىOvq<]B(;B\\cueCkBȸEىBJcu=E!(;)go\$.aI (),W]S !d D!np٣GggOj}RF#!2gVQw"D!npIKI& G}Jp[>y頠ϢT*Ϟ=xo=22RRzyyy{{{{{{p QB;BEPv"S޸2$vyy!lڑބWpl6ZZZΞ={ȑqرc>裏>z5xsោBN,vn8nXkFRĉn{ygx өSRRڶn7}+W8fv!D_E?NrjwW.A'{ _?WWW|?+֯_h>Sq%ANr! .INn[a7|_}U &<׿yW_}/Veۅ5ڠ!AىBJڝv;;X{loo+W~6lذaCBBw}'&( !^7 *;N.tpW\I&xFS,Y/8(a8ݼM!jPv"7>{bvgSvH$/±cd2}ݗkXl6fs8›;2h}'BNguU\n￿999g}&L#!$مw"DPq" IDATW SU :sd_ߞ={v;wNr! .o=ӈcX.?OF9tЅpԙBՠD!np*d(+^6 ֭{ǟyqE!?Nx W$;N.;wg&11OV +R!@! (;ARn_e!g}?yٲeGZHC D!AىB܀$Ɇj;`0,YDѼ}F@ =w"DPq$H8yd^^jT wqѣG'Mװ޶!\e'BqNc˲]]]R˲NSH8 p8:;;;;;yw:r|„ ~~~J244o7n>[PfWW׀agϞu]wݞ={nvO׈\of^^^_=]ч!e*'y8Μ9sԩFNwȑӧ߿?++gRɼMܦB;믿4}7wq̙3 .,--]xgk5/!B}ƕA]]]{In+Rw^Z߉aXlijjdžU}݉B܀~~~V8eYD5Lo(quikkkT}P(x!q\qZ? o#5!W!AىB܀B~N0w"},^__ZZJR[ɲ,W!BN #W(((D;yF;t-F7NDЄ 8>ى~z!D!n@N IXQW N!ĝOݫ\֏rŨ޸2Na`iMMo ՚+0L0Y+[zD06)aLeϷ4ŔDd!3rpŴ2 \Hg!d9ήބ^?=]GBFB=ӈ〶Xc4E) WuS^**adC:ZsW]8S ޟYH%˓KJ\~ &'=jZ߉B_G< =iSB&nN[6vgj2Mŵo(0 !LHɊ"B}J5]Rmgo\qwv2(n"}MMuѱX]ʼnd,Z_.j'Jku rL Rf"!>S?;gj(?>7MILAړ~\]֚[So.hT.Uivs*`sUjWk_.xnM>&]aۊjg$ Aį[1[KW bCS)O^ܷX*%/O^WڮS)ɦ;k'6}58Qo=B&}xbҗ_~9~x555vq0*'BB+"8ZW(2k4nV/TxLLd#\u~&.zm<ڒKIl"KJ5s\[,5;k3<% h˶/[ -η @Z竢'hu2P63 q *\l@,あRvowworsU=P37} _gkgT_mGvB ``9/$Z $=5˻ʋ~lܺ>Rq[KnHM;v젦'B$e^z}Q111oւ $ ӗBDN㊻۝$|*a$>360O q Q{Tr)dS{J='/}"H|k+$T14Q)0x3=a>J**&2OT){Ӟ Tw O\<.))U v;qΝ{_{ @rr'|~8fiwr=;J9.6v=O IV hKk\S]EKq/QKUi-~.YWUlu:J8mǀ[.,{oSkwRKK:uƪ;~.s2@[`9]gVzXU俟w$f%~qwɕ+W}Wv{#Gٳvڶ6O2;;ULn'vSXqAb%`-vIm#'W?̘SkY\cŖ-;'M&83xa %7ܨĉG`n8m9th_h4U,Y(x#Tx'@WOTռ Ppe8eypU"iͿS"#Uy~dw 2 e[i-`x?+ୗ!]@B!'L#&fZŋϚ5> __K~ǹ'!Zè޸2BQjgĨD@UoNI:8{m|rr=ruc=S@V"P ͛Y0P@7CgRFg5,~j It튬yo` p.ĵEE K}rQMIڌ(]Y3~XVJȼbû\jQ/o2 gυBa"?)]\J\UZi:%|q3׀(,B?Ihq_i&Npr~kƾ[{h!\A宮.m6[GGb1gΜ9}˯K3bvH,x+,q+8$~3%ٹ} [ZZ:| 9x+K,k':ʀ +ߎf(!\i[ˉv8e%jz.bȚJn|D$P00LQQQPPBdysiӦݻwڴi9JcN NBpz׋JKKg͚5Ȣ=cZvժUr\* ˋ!C8.ds<{b`&$\(Cѯ\1jwWmv" D\8Vo'k׮S0 uwy'11?!\ҘN|頩JC&d ,I0q{㊛Sm5 Ll ["a"6T-$|M ì\]SxW2 0 dZP35@JԦZBMdY0LĚziDft+uD a癁ε!83a&vIh|W_`+Y6,`o1lIKy† R/ߘfAREo1lIX06m(6 !d$47qظ]v ˯^}]wݵxoj&(bq^B ifɓ' CEEEQQ w:l ħꊒJ4F!&X]tNpURRԕd 3h2ԀZzg󴀺n_PK⋪z+)0),/ \ȪWv:68_+}]].@aM{1[(_WX!TVgN @kl7PUz^AN@QQQEE`?yllbߏ!;e^HxxѣGv:rAD!F&,˙3gZZZno>T> 駟~嗳g  "\ngYӵ nPgmrH`>,ꝊMUu9 +*8$?m=-nts^ng.TxLLdJYw163 q *eԳ5e%Tlvk0VЃB%{dTrwZ~&.=*>$;Yo?-O'ߺZ?+S\U.SᵊTԽWj1M UysI1Ru5m\-Oӡۥ?|χDn_>|puuuxx{j?}ؚ{K*J$'D>{㊛9lPVLL3J.Ee7 IGq*I4 oc<*P9) `s \@5kPDtYpU>D9s[CwI$ݻ] e uZQvp̔t&`oN>o /8%6SHl)+O!d$;~9sF׻-8 f͚e0x|p޽'NtAC-88{XXأ>ZSS# r8<ϋkV"4?;M}8  ǜsc ~T\{ Zq{@Jo3<0AxFx?bjCց8}rj\Q=ys+NQmU]'-n`^ur4Kf*UP'&8??k@ucx** \z PGo۷AObOl62EOa+/{j2OWh}'Bh!pr۷ڵk߾}wuxi)))wyc=jWZu~]H ț{3N+ǵhu%!W߽n%H!d0pO~g[[[ õ^:̆o445ZK~, 4Xr"LC[}bɖsaD;BF>18BX֣G.Y$$$( Noȑ#fyŊ?8}9 "DDNGS㖹) i/4'5?lRkDߪ7o+knmom(:B4bnćp8 1N_fFn4h}'BH&pVFVp*//_dO? 6ĉxCßxt5 !<SVGvG'ZBmZn̜̄Xɪr˚M;0 ,W߫,= m72 ,HyKcEa-[6&dsݹaڝ60|Kia> 9~˯D`ncU!⟘!kӖԺwk*aѫ+gݙ %jSQ*\0L¦'x"-  0ujwƮi~oJؒf0k9؃b#YW&Uy;*!+8V; IDATs}ǿ<]ǫ0֭[y?uDgyupv}Pzb8YfAiOg>PP6#o^>7=nycMyv6&<5ړω!qMezcI9nFyie78ţrsB뎟RM9Yf3tT٠T// 5xRvAjqWsذdN$Jkd,=LKto&o_lՕ=wZ_JsqǎSlN>p\w kM7?R^]~I+NTwcT JGY!Df;sKKK92=m-----mjɒ%JKK;w0}0Eg8ěU IHݝ˴% n\y7ԩNٱyk_+Q;}QJ1; Ӛh ~jj֪ , ;NH-lkw$37APA?:/uިTkf+oLQA" ~ Spf jU{Oӡ.9uoTx$=͌¿l\6'z6p5PU='zcQPz M|EEEv*))7VUUUVVVWW cο_f Y !dd鹶8˖-:tP $088888G&32LV> cZ 01Xv_]__I{42x`50K*«ο_Wzg94oUΜ 野G[|; u&D5beA I8Bp* SP屶9Wju8N_č;vhjjl6mĉ_|vT*X}L&BBBv)l:::˖y !⺈nxׯ_ʟwwx)Ig)~cQ ;` ȮN{7?h4*Jx$0^WW09!=t$<7IzQ7%T}^۽sDVR pgUyndf4pȄ6˱ p%,f;ڭMkuUFPil]҆hN|su+SKʏZ9ĄKN:.*-iJNQP=m[vmjjMč|$'5556tf999x?sBDFFz뭡~~~s̹BȐV5??KMMO_1!BhK:~[ z{(릝ݟ}kkLݓؔߵ8!bAfEM}2`L<̷=ȶ}W^yeʕ{Z'aAjoqBggf3'O7 EEE<7k*t:UN.>W 2z5ӷ:NUp4 U@ZyKa.{Wk*l,VPJڝ 5ݩשʨ:2htNT&l/*Cl׫Bcs [^1;@j6g'Ж9ٚ*ٞ)o:ZR˅WI[dt8MUz<}U@tujU^@2B0絲vѐV`t:UTT 'Of&v|Ï=Z"BvjX,'O׿7ucǎ؞Z>TyeyZuV^Vh4VUFYTT_SkMe*@V\ haRZ5TҚNNjzSwRF_:c^m5[ ezcI@QC8]w3?+&&ٳ.穡I)X t:F ӷ5Bq:ֆ%ǾR˺%雍@Z]jM/ir8MjcC>C%pNJմ,z -ip:lB՜Vcj| 4lxғ'OΞ=׿~{v!>!AkAIh^ 괶67RޫvG{Mnr77Z<־]2 }u:ե\G{kSsM ͽ r69ڛz]BsZ|# (;xlgϞ_JKKCBBRSS5gzYh)UY;MtDN=?߯;ӯJ[nLM۲P9jVT !;{~l7TN1O4/n?ᕕMMMN2AihNEB?ټxʀ2 @ Q(zIR( -O 2@^XyHXXXe8+{E* }]e!^0ee+P\BKEfd0Oyc!n´D=:n۶mxL\%Xuo8Tfjmm(/zl/ Ω*m8e l.-%x~ͯ{U ~nau3`Hy%GVdɒ?\XI&N礡 133L]_AM-fwtIS4%Eo2En,7=3DB 'Iqܹs^y7x/X|@DZ Ѕ'dNq}Y ^UMB~za5˧=?kCDP] |D/պ U/ dNZ `ٷ-mt{eb;&VRLOḍ"Q=o2z٢!9%0]l5)UD!%)ZZZ~i!((BDz!" R-e5CDhD,C,왧oV3vTWϽG @VJCEwK*n~JJ{Ǫr慓%h[^-;c"@]d|9 |xZ" 5u꣌[qCL.t:;xddo3{555)Sd2D"VbfT ˲ nB!}\l~/믯ZjЅ!)-P m!aa}6)!} { })W+f@>>>}QFFƣ>[o{BeYVeMXj02*Яxe'B!qS!x]v͞=uRRRΕ+W_~ժUUbt5 !Pv"B8n>};u^<]8x?\[[eB!J8NoooDjw?1!M皚8;zҥK8@L:ȑ#gΜYbO?$N_.DSt !2Pv"B nrj7Yn]~~l&溉gXedȌ`B]L8q޽111СCB|r]6V""gBUq8?-cy:WBB\flܜ"Z pwfl3ޟYK -anzw&&&KrXNS"hANBܹsn&Vm۶\.C~x N㸳gnذ?>rȰ'- tsk2K[m-7F0 &ݯL+rb#""$ O oZfP%a&bCN(U_0 ,XUkx|wMWr!}vE#4C sԇgzV-;xJl=/mǦ0-8m'7Z,`ZGۛ }M4m+ǯq5IIs%$KKYQ(Ca1~<<6mS>jzJ}x. LܼysαynGUP܋Mb'0gϞ=bu)˯wǦgnkjit+U^&pitӭehC/,`C[Z\lUm/[sU]Ggm-^FQ;N~mҲ+7VWάpY_uU|Igggaaɓ'7;M.d' W_,E/^WnG~s{4Iǝ \v9syy+YZ3K.}r[{}~cۓ+.}J"( y ڼ5 >ZҾ5-ppk)!R-g35~Ȋ+~6\c2xrr{wu~~$I,M#%>M.-ًXh<򚯾*EEEzw=0=w`$2 `/ϵ?lYOM#EDyM6:u/&ɋ\Z:S⃦ُwo\t{@KQLS%/QQk_wln htf[ 0;|]]܀k[>nap80 ϙۯ暤g7N4 `b4vr\vf={l0" uuuIII fd2 QrQ'==}Ϟ=j3%"DG___oosΞ={={477[M&RҒEvld{wRf>!Ғ<-R͢OzƯ &~q999IIIIII&)..Nz~x^{իWܹ3JOk!d2N:5y@䈎o(IʄAn)?????^qiii"h6ќ6shp"䴙'"(9m楗T^xMxޟg pE}r!=?r"2(n}'т#9ť[lI}LDGI۪Yj&zn=N"")եo'-ln|i_#=SK.MOOgCv|V)7StBp0$-gIxC@4]~tN9j)))k֬imm-///|f*,\ԝ>I.Be_._Cۿۗ.?8f'{3æ-~Wn"*LD䔈FV+53>*I^J_/\fR>c[L ;Z y9 jY|Rn2o IDAT;ԩSGY;:;mm+/+݅󌒓ieitWR*+cYKw)tԔS$ceP+oZerxe-3DtŜbOCſ7߻K:{d{f!cC9SosYǂ>?b o=%%%Q.pbN$ZؔԸ; lcV|8~j~ڔKqkV=˗^-YDWo񖺧']P6֕Qb*/j ]Z""*mKHYDb(m-s3*WU6<*OD -˖۾nsS,?͢mdQ(A/yϵ^2""˦ϭl.l߾_dw6\4m46" ) NcLeY${ٞsl~)I,^7 EpM:_ "`vQLOO߳gOzz1/Vo;˓x<$IrN`vn }}}}ݟ'O=8$ۻM)if#vl4χ{MNGwҒGtڻmRBJ=ݒ.%-H.q=dJKRoR~GxQ4Lq!䴙qic8!oΜ9W_s=)))';?rKя Ʒ`Xpb׸nI<`6M7<>tvV=h|>ZA Z]wݵo߾̽{Ξ=Š`un˷rV7vIBo @`kݵkWvv_8oNh~'xp XS8_Nz<6yvĮGvzx'6i-ˮvaBL7`Py[oowg\tE#,piE|>_h+rffbŎ;|>V*?Ƕ!b g[~D|l *r/Wx{#~? r?OYYYo3} rћo911[ăS8-6<]3(E&NV ে 4/,y) %(a.s5T's4B>~nPI޽{LIF`225|>Tvx ]!!|0%a)vo qe?lc=7jԣc?| <ƚ[u]%1.+$=hfiѢE˗/|~xg***noN|Kgpu&՛Wxo{!;<~l :@iى;x ΢Iy Fɪll)~.#Ŀ`Y{͔NJJÝ={VE't@~2A)ͫ:))СC/(W8lGaaW\8'>O0,p+$gϲD\03om aXv\ oCp<ʱ&Y%IvDz *pr2A5{삂w}njhhHMMU)Zb w}wbbrgVQ<$Vu:)zQaT;&r(7S~Nƒ/%哔ؙ!&N]KX;r':Oz]FwŲwތ ĀqW]u… <=d2mD>y 8^Y$Wѐs\, xxhbI i`Ier&Hck it_NNN{{7+$_\~}NNΕW^3_6"g[)#Ns|~ 3qgdYvcﷆO"<9́PA??srr#<3ϨQnwqqqccw9cƌypb;d[9ʲӤ^ٸpś\ tgd'Kr&;;b``˟Fn%(: BT){ >W\qEAA~ )*w[nn$%%'6O)< (7Jq>~PFyឩ՞ Z0=B j'ͦMށz{{i2 lRJَ>Ǯ O GAǠ挌w}7=== d:;gΜn<'~,p$Ilܕק\vg[^6eWkpIq؁4㤶ycMb #I hk8p¶e0-.A-_~rŋ_uUlbK N|/r6ĂZ'ci{t vP pWj7@V^AvGw[Ѥu$y睓wYUjsK&(_}jjß?'x_'F~ N}NAQ[/␗!Tzzz& O :j+r vظA1>i49s$$$TWW:thǎ&):sL~~_~YPPʃw2Էl?=6O/ #?*AXz: aI9{ s7,](t:z=ʀIsyICOt]wܻwٳCXO?o1cwtv`o9U)?X8Nv@)kXQREɃaI;~ӓo EPfŊ߮]vegg$vZT=>OONJ| Nx逸z饗n/d2-pb{38)Z XapPr8|ĉU~>d'(Z;=Fl@Nz9mA V7o^bbbyyC~[PPp{碋.ngȶ "!8·0:CE^.@S.!)\.Wpnm F&+WOw;̘1c\GN'~ȩfRXv2$bz?+v ;D CFt: ۙo͘Z[4r>~n?s=lISWO"} $m0 !;D:Q6#]~LHQD"緍ĢERRR/_^YYz-[ߟ3gr?m38)w@~P02Np!švN<>]q'A+FcXZ[[ة9{|q2L~)8Ŧ;ڏ$I8\x`^@v~~ g!;1g.((xM7544=?\{w'&&*wgpb;CNz>8|,ڱ$Xǁrc}@@|/T|':o o _~~,޽{322˻ꪫ.\ F b932"Q T _vA@Tt(QsrrVE^y啕+WK/lW^ye\\\lۈo 65F^ gd'(M;=F~/߱Mr o*p /LKK+))O{wƌqqq~g  )gE#-bG_@Dh4^WшȃNXvFʸi'~(Zi"r_$'(Nh$aSf'6mo NQ r ;DO4XbN$[u:`` d'P.f#~RB-⫒NnÊݟe$oDO}N=O̾=_Vζ!=΃m+n=s0TeVdTѢrL&?mbbbbbbRRRRRRbbbBB[oFþ(oÊP=:j8@B'!T}xLrTx|k#ktlX DP=X z'<,MbAK N`;n{$HLJQçًwn\weׁ BNQGvv?,wN>.Q6+Qy"ުF_[NDv\tvTY/ w A)Zjcs!lO= ķ&7 |C-J'Nj?(}e… 3KIQ 9mmuz~ ;g/Y}quѣ-9e<=놵D{qnӯAmɻvsK[v>rͲ۫H6HjzZok(U;ߔ_PO7PZC)7>߈ovl;x9)p0;0g ٜВ]Uӱ+_óꑥF _d;d1ܶpH}g6rs:^Tڼi;,&VH/e[,N게#;+k37~Ih o#z-6>7OIG/cQTp鋨1}Q1Oƅ+]ξYDDٹ񥸤ˉ%Ddu +BvK"Y:ND5kd_uʄ=tu2LDd#I_re6V odžtCbr(ǵ?NYK󒻊k)AOE7p9QI7$NO},߹ι%vMq 5xUA QnYR$A 0g/v ;ĺv\o 7ZL:D[t<3IDtkQ̗ߛMOv9zڞ/ Ƅt֏?saml*}.'9+b%az^;冁pZ**%"47g2g׵oșp Q%?ascAG߿d5DDy[>DZ[n~AVl"2)Obc;]lv\)*-KP1!:p 0KOO߳gOzz1^W$gΞ={邂~g2syMv:eQ4u9O).mf2Fd02Hwwt)3qAKIIINNNHHোtz.p8vf9sL0TGjjjRRRBB\ve͗]vIq'9m_{P4G0͜Uڊb" j8@LC `F0:d'Ü؁0:d'!;Ld'!;LƝb萝F0q;F0:d'(  ]_4Fr8(5F8/^I9{ $hk/*D/e@ E TYvڅ(jZւD{TCFՊvP~] N_=QYQRFt:v`}m%z} $"rHE7<{ns8C$Y^o{@_?a>(`0LӦMOLLEM|$JVϝ;rn,'lS3KEEN7m4ٜĂr0No’^$Ft$IT=2uȲ`6md2z;9{h8F#ޱzhdwv{$(A$ND,JnI<*NDb*#k;'oARBp׀'MlIV#%OFh4 z CvAxX}l TU h4N6e'rЉODMg0U핔 w=.)@CvU z7 T%;2o}+eXۑK6.zܕCO|St{5ײ,{;P3^F_F#Olv<;t|(R vS ;b#6CIӱց[Wdu'| lĉwa(>gK.@c= =8ɲ̚ju&''r\Ke|bvF#_v &"<8[>4cOPcIq؁4 D|I9Ohķ"dG/чNQJމp㩉U)^n|]z'PAvߝ5%z}$'"2jQ'֎:5+@H ;Dvz%z"TNFQC3lGxw;:ݣ{7^/KU.#՞ى姀&d'}bS;h5N γT+"3J.( M-!Ƣ꽞l!Xڔyy+T{Ư#rqv&AEBNFœX<萝&N `tNCv8ًNCva^@vvb_'zjB 0BV LjƝb@X^kX$0A "hxcȐ @S՞FW )@Bv+RdlMRT9˥vM8FzY|h4>-PQs.+?nssU{AZ-HPJN[xe~醏 jaܔFhZ~ =)H`՞˯ NDp8.QV~G|T1œ؁Vʆ,IIIj(df̘vBٳ>O}p!x7_vBٳ^W; ê](&<5y^Y%Ib+%[iAp\^WӉ\vѢ5`IۭN d'pb'ۭv 8[q*Ȳvp, IDATzt:F)^w]ȅ9{ LJv}/8!;E,#d'0QtrNt](tư#XOѸH畟QDNVY;Ɲ"p{mt!sظ"t\n[](&ʽ"z'YX.G-Cp4ʾł;P !; N툽""{wx)$6GXΡ sb@XzR8F1Yqlr@wj " ;?=(P8{w<k])3W.J>~mGǣv 8>脶chדu]w[#Ü؁V5- 7 )԰FSnlvY" @%hD>e 5G b5 N <[Yx.o(#萝&sb萝F0q;Fۋmɨh ~vGbN:{MP6;; B~]"A؛#91XRa"R*v[E``)v ;D"qۛ궴mY%Hg._!h$wn~&eްju}5 BNIUHn\!1pg,K*W UmD= % BDDr[f(kk?E|l]}p}~ %o+r׾>Kq%^5[*v݃W4TdBNWS DT.+xI(\Umڝ: 5w>LRXEq\6믿lkk۷o_]]0ΦV5_#*vwBiG{u"˖>_keeKw:Rھ{K}ӺȲn)V;Zյ|qt:"*|_#-G6VюýDgX/Wne˖l"ˎ눨h]1Unim&vle׵>RMKt54m)$"l=s Ե4m9n> 18"۷o_[[[gg_m\.㹠JY}>(]LT|R: qcu1U0%+vkz[󈈨zv1+?YYYڥpmri69o}JpL{v?YDDؽꎖc՛^{4qn=l>N;.ڭeǓ DOPr GrtOteWi-l^} g¹;ONykvuy V7fK೚ R=cC]Vgiuf@y;=R$\|Hy\x ({F$"WPa]8p-y[|r뺦/X:hqg[tps`Q< *vlF/Y1ozAd ;0g o^N@A!nv>}~jp-DDT07NAd#$%"r;3_] 3E'" 4.B"K f"DȘW|eRL6y)sMyw=0]tq)7ZL.+qs-"5[82urg9Br$- %Md?B4=U0lrQ =F4""qctRZ8u,'%8ESf 4eKpoxg:I/t+3$m_}UKWE:;lߜ$ 1Pj~Qu8NniܜWWo3>_lXƳ8lYz]%ȟ iCB.Ap 9;"T1kGgm_}eeTpq%/?|l^e`;ɜ}`ɖj~Sޖ&IGYNn+>پ;{TH>e`{G|ɖb~M{}>_o:M{u[MśJY9?[{};g)#*lu 9n> 1(ZP_?d!nWp)Q^ueW0++9 ϿڢQc( 8v) 0/==}Ϟ="@̔z,\~nΞ={邂 }F4s`~L\BJdFq[>4~l>+Ƨ%erO2نAtIddi4E"mi='$]BZy9J3 & uuuIII fd2 Q5טPmӥL6]_a8TqAE=쳋-R 00 }i37Gr6" B#Qε Tq*! u}؁0g-۽#O_Zz)ʱP'т#9F<-ou76*+mr}3]>;`׏.ܱu#kZbS+`-y65:ϒF*_}#wqw낛-)bH/){[#KD4IDdٿcb3et~mޚ]DՍ/yĂ5D r<կ3_vr$]MWΑ\dɽ3~ on2&KljKK ""cކ_Qվ鹃y z"Ѻy1g^FdbboKtrҥß`<[jh+~aKFt)*e|K~y%ʮ'{3YM[įZETx)ǭVj^)|Iz0I0g/v`@lIhmuہ`;q(J8cljǫVř^w[6\f˗] ):Nʓpq3 Tm-ցʾ;1pīb3:[L>ոwVm,llu|lI(acm`ɠSEԙJw$GqpKIzpa7l)uO\h,X`,XYTI]C6i0&}'rOGMi9;3<*}.Vdu@DW\l:P6ϲX729겖s fYrgf[Obʒ=uTlߚ_v򉶷~L+X=}g9Şo&wk)6t/;Bƀ9SosY&a@l1!LDKT sJ^~eY}S 2=kv\)me֑ά]Md)T{ͨ\EDT9YD+n.m铍[Zs3zްR魊VVSh8[MDv?tH[WẒD]Rl}?7R,:>\e̍/#"l: Ϣ ٓvA`Lʲrvf;{ӧ 59o]}FJKKstȔlKIKI۝FY$"&%$Gl$:{Hfc[RԤl2 ( kLDTg[Nܿ?w62%2_nIl$iEQ$"{OwppۄO@NNΆ rrr.L:k89O3ӆ198f`hN819m _V4 dNNZ==zEK/\8d';w[u|+c'Y7GBt V&sb萝F0q;F0qwNCva^@v萝&sb@C] ެ UXA,_A[ #T[cfŁ 5,0;nFeğ$ j- G*)u QV-(]NE|D| z2NK*8l_Q%Iӡ8p+8`}xm#{wXsb@t:ݛoy9rn,^WF#^7 &)>>l6'&&w5#dHVΞ=t:%IubK1qt:h2Mj>@(n4n|5)r9I^|R 2>(`d4z=Nh>ydeFWv"x0q`ڴi&`0wu#+^b.KeEmGF$ϗvAƇXӦMcGvob7uqhz$)rrE8V_G&epBvd'0(#I&pdmGu?ò,|T 2>AaF5څb;ew(;E]W d3諲 Œr|>Φ걩JltBE]vAG5YdbiSSr*[`qqq$A(QWxg xh4:VN |4c`0+Y{<ߝac)))jd|o < R( :oCz^N A'.XEUu>˖vCv`„;30&2;ݣG`HO!DNz0G?%XgC0V)AYS r)ڎ̓O>9gΜgbC"vRSH3Wl16ʆ.n5!!A"\VtJ>giT;Gx^~IXxʩQTM&E8^_  ;khEmGョvAQl):%Xg3UFURs,V502ًN*s˧E0_vA-u5Q4WhBvPTjciݔia)`] ɂS&ًNN0!;@h6d' ;@lBQ@v@v B bƝbLmNN0!;@h` &|d' ;ԆS&ًNN0!;@hbbv`L_3S 0cIyߤfOepxXbA%ؿ(r.…IѰF|HPc9{ B FxؿEQ5߯v&N9Vh4_ϧhd' xp JLLTP/Vw9Vj'd' BN0>UȲ,˲$IUCL1B˥[j=u s; 4`|Nn{ N'K 6Or B F'IrN%["v"Ɲb@$IrCBAp#MøSr:(jZQj RBV`8{X\.f;/v ;@h` FNl=dr{Nj " ;@h ;Ȕ[UOjc NcɲvY 86IJe; 4`dUO,A]"N9 {JNyQ'!8bƝ`8`P["28)].!;@h ;Ԇ sbLmNy BNs; 4`jCv@v؄q؁SLmN ~ BN"ERIECVdTMi;#ON1'&Chԝ!ͮVb8QMu[ZS%GkvwI`Pe'عuWm%u)$J7QQ5*; 4 Ώ'-K5XqW~Yˎ^j,`C[Z|Tϙ93 c~`1ԉ]ZJ]r&Э]y hW5%6n/B%kV˚>!֒jF/R)DdL&$ÐLIG9s~|&?>9pk8zX}eK+_xc ;g//ݺݿh ` 8q>+W^l_LJf9X kdM^\?U}}Yr=wUWӯ[̱Sjj?#?PDD"藀'_vs͔Esk ݹ>@d]5 Ռee5Go] =.K}Rۓ[~kӋ<*_{X _J{C ޑgOAgA E?ZYE"ۮUEQ\ DP_:tY{]8TS՜|/ wttuu4ll%:ҫ"ۮpn_ Gg'Z?wgNHQUs8uX}͓/|qMuD"{r%md<[v?2w_Ęe0>t+!O9ɠ=ʑAvBtzeRTv[*ꎵy</ޙBT{<%y[¢HmSsO<W(s|w\,"f|RWHὅiYE]ooAM$dm}녓!|Aʾ?4/+caY}ì4kE{M/Y|8eQdM7t4jtsBc2j܂ zڢ ׋/}~ٮ"^5_w̝^,"~1;^iw=VT~az߆Eۊ7xjekD'"NjWO|UlY0~cGJ>x`vvvY8ڗ<6mt뭷nڴBtt] @Ν[z~Cmagz[:]顐hzW/jomzCE&0P]ְ}[a{zf*z0<UD$}f3g{kKL\fle;:e(EQ***222RSS^qNSUUJ[~%K֯_ov!wA CK˜y<3gJEi3.zfzOǨWvuz/έzOH h*vK$|md.6 3Ň֕A_Ļc7ݑ]g WCG;{wqώ5](Yr擺Nok:#o߿d+l;Uqر ^o9umG,._䤈W=E%k8u|&a@b,NHw@Tgv<`w"".:/|jkm"o ;tjY~ <4O/Ƨ 8.+Aq,)V?+eO*{roz`g/_I@d\)e[)2`U#'˟^\`̞uWH MXyƾݙ!']"aFr@$Hu,c7u)=|JFPD]!-yq{zOB -@^m*ۢ?q6$.{_1{+@^n6)<_l[[t͕@ЙF5;⚂++>hD:J(sAҽ'e]Ro΄]]mj)gd'@bwdw#Տޱ\>֧D9{o֊tv5"OW7_oڿyHdm}녓!|aEDf0+spZO'.? - u<yŇ} W=@bl6]g'ri3hhcȮ]#Rx~Ik|bGd_E$w浾wNﴘ%=kxHDW}͗cEEm^xÑMkv)[cs Y"NQ=KDĞ쉚GrfsOtcB,;;fQaD o]N__ݝ`0?ܹsWNֿ_5lOLDuգ]Mtv4~͘Bqyԋ4U`0y<7=Mv-,LxV"###55z<t:UU47.X`ƍfqG ex *93mtL2Ug`EIXsAe]Q#.0NĠP3ZavH&9ƭN ;&NAv$ 0AvLmd'@b0j5gd'@bwLmd'@bS d'Ę= ;N+k:NĠN ;6 1N1{Av$ 0WFv$}'đ# ;Qcl6۰?2 1N+68!2}'c d'lPpJII1" /%% K5Avh)%%EUUa< j ,dvO~ .O>3 a]'W///{nم\1ͦn4vO6^uUO'dvɎO? ;FgtTUu:fs8zfrŌp8.kڴi.K4iİ= H .'L'c0p:.NƔp8;vǓfv!WLQp84M'p88 ";섑Eu]uN.7~씞nv!Wz26ZOF|bh0f:N ;ad{===Fp2O_$zj bϢHrGYO'@v$G^1dMzFp\HM6-##BЫwvt: NǧuA #0v#HJJilb5S$\F&55BؠЌCD;NkE( 1Nq`>zhCUhjIvdлS-NH FfGōuܧH$q\x.?h|2:F {= ;섑EwSRRKoΤ8\.(޸h:&%A4咝( 18򊸌=#;ILi2 iDNمQ4Ŷ H N؝Aai2f'קujP@"/Gc c0vܝN`;$ p8zzz̮fdd'@b`Mv=]@v$ D  1k>H N&NuAv5 ;kbgd'@b`M ;#& 1;X d'X}':N ;;1{Av$ D  18 k";Av$}'Xc# ;kX d'X H 1{uAv5wH F;O? ;`d'@b`Md':N ;Y d'X}':N+>H N&Av$ D  1N&N`̞uLbѯ0/~ ]_u ?.+;;;]L4|]nOSD[j|;wq)\ofgg777y/ 5k1cߛ]?߸/YYY]Ѹ馛_= 8qk f ~'NgvQ8HdժUJggg(:z-kv]Gd'ӧof9{{Aeݻ_jww?3fe]%%%ϟo];qD}Y* *i__c=eV=`;tP4,|0*+d |}xAnp8o~Sb4w.jjjZd?lݺ2"?׿{͛7g̮zzzycǎ|?i̮h({>Xc >GvN #;@|d' >GvN #;@|d' >GvN #;@|d' >GvN #;@|0H$2dgv (O##;E$1256$yvuF%6,m6[)Q FFv/2@DLI6Q#EQl6- `hp2RSoo5H___4Y%NK/6)b|>(+$$E)/IT벐ϧjl6. }'ɢ']u]鑤?iPGUU1=(dDv):Z8 &z1zNz{{evE=Y+`(4Np8 &X( uc3Ead'N;G/avENE/MgvEmW]ׇޕEv&ַư=]'}f #5zcbPd'<3(k1FM=F< Ev)޸W].Zh:NR9w@l 0 `H 62p\w$fߊ~NZUF3NƔ"Nq_&c >GvN Km,lz{v S`x{JXj^!p3XdѮHF a/s<-[\9 ܻ@QeGZD?=dAAH몏B+=\GrmQEQ *M}+Cv`X'NC`0`r S.J߹4AD???#ThY!v \+0k\*a߫YzGƪ|{يjG#O,ȺJfW\%S̭`ozbNR(t݁#-ƬM;*(9[\mӁͅ"RpKeST[:E?^nݓ;K(JNR(JκA-!ioxtiކvi9`だGi1S IDAT{ cR."M[6-]tMr~2zѽ F'?WtgG; `<SӭP0 O6TT+]i.o7m Y|mI]?~`~A57dqayh`3n˵"cYۚJ(mE,_d͹euuחBð~MZmI){VwD6d557/}8'ww/_C-?cWebVT|gi]ͮ e7M{g/)~twٝEŻjZBC?` l6ۧ(W41rj[X+%+h`}UUiϕ.t ,6'wy[0 >qIn{2/;Yɴ%T5t f>V7_Hmͻ'n-eGoߐ;ZlE]ejzl$wWǾ<"xk k[W"S)/tvDzb#+Tů8>7pY X"":vӧϜ9vhHmM}q.EQm"Vj%J_RT+NtcK@in u3CD]%=nɯ~֯^9QVS[[oK$s|u^/w/zEkE|]=zEDԬ>+)L߲|̮>N c EQe"77aX `}}}SP( ;::V^-4Ɇ1{ #;@|d' >GvfEok<6"k16Mn4浪1 R4#Ag=]&$/>"&3R$q8#M9]pooq$;y^Ñav!qDHPNg`vN3 j={k攴񤤤]H)vN FFvNH$zu#CsL6-%%e\gh(EO!|h=N02LGlؕm7%gpm<م7MћGDoevNg{{{y) G\.(nBF%Ƥ3ڍql.CtbѠ[9 . YG"IzOK{JG%"`5e/8/+Ygg]`";X #;u;fWd'ƎX #;u;X #;u;Av`;u;X #;u;X #;u;Av`;u;X #;u;X Z`d'ƎX #;u;X #;ub [n??ӧϞ={ƍɥ#`@\wy~_wwwľ2}҂*/[. 0ٴiӎ;&0 ;0*UUU{(n4G?њ5kƻ*|'⫯{FYP(aÆ~Z`"w P(t7\.wM74U&}'8p@GGu[Vq|s{Ƕlkks݉- 0;0755yqM^{0 .k̋0 |ᇟf|{oo|zf!;08#g?(ʘOIIW4d'Fr-tuuyqǓzf!;0yy;Bv GyaAݾrJnS P(t7\.wM74U&}'4r wyھ}; -^G?4ǯ$cU[[rP(;lt LWwy_ľ2}nAAY ++TTT|G.+===//oʕ_W>ͽtIq >GvN #;@|d'dmA>IENDB`ArpON-2.0/doc/SARPI.png000644 000765 000024 00000317020 11060110367 015130 0ustar00spikeystaff000000 000000 PNG  IHDRF_5iCCPICC ProfilexWy8?fe%Cʒ-kCc1(DP*RT$dKRY"JDGz~{sr\}9bX!T:܈NK$EYÿ Cİ0ʿQ4W7wDc/F@@@@` T7no|Q$:2 R =_r / WHH/ &\M N]G*o[@C߶ KVDI2 F vlI%c=N!EҢ6 A77PX&W!vGc]cppƗ*nД} V@\ECr۸T/L9 9e5v5MoZZ46S $ Ì~UfZ[kdNiupRtNurs rڷsWwO=c`,'D*AI׎ԎҌV?rpgBL!x''=NnKJ-HKM0ܑŕzű'O(宝zrܙ|gu?_HSQbMq%璭%meY˥*:+*vuFu5LMZLՕ66,ܬn6)6-6_o kUj]UF;};$;->wϭg^fY?x4~\A!ö#<# F=c_+~yk"k/&K(o4龷3~sw,.|hĺziU5ѵ/_+%zﯓ  ˞'?k`pz_ϒQۖ_@~bN5勪xP]ښZ:8]}Q rV4[;g"NE./] x=Sz{o|g~X%(2!TP0p}~]#R%J9ZAB`,>[96~$pCbQRVrL 9*M9]0}dFwfeVрc2Yϟxp2'5zwgr $ ֝?pBaK%֥ܥe=g+U\Q|*ZǵC3jH3gpE#kæc6-ǭ9\6߾p.>Qy7Ss;~^RK{dX쓆APӜagLF+ۿz>>b+;''M}sa:ی,w7 '.1}1b)y9i%kG~_ua`2 ^PVI:G/Cyc1ɂ $yKzI.*"$$wTQaViN fYun ]~ږگtuo 4b752qo-edioeclkAΑqiKhW'75w^}uG{y|*}Ȟ~ZK+RI7ԖМ0j6J?IRFGtc;Ww(!&A8apsbFchLJM4tG*2虺YEs"chlnyO_ Y0\yB¡ He/.\J**/}UV~V[R1TyJU*zT]xRu{}:zW 57]֛Z^ߖz;ݹf\x=^T/~ʼnϷڶmۇ7dQ'+ODIi'AW L4yD%utt(i%FoL8Lûw?Y9Y_G.S 'Z<-J@ %ys!1ұ5&$'$ L9I=jrjp^ڂs S%e~^{ZW:Թ7[ڢ$u<]S[Që֟cy'tMg/D}L[<\}mu__o  /`@G# چBEPhI:]~dtiY\<¸a1cXQE%eKXY ˳ap渇rzqp)rqGs65  06T|9@#T.l!Q䔨-ľI"϶I:o6T{r FJ;aʄsq] ߴ:ºjzAG +150}ߒ*=1vzUΛ\ROzx{ ^œUB)!7C褨M}Sc %R/dgi̞;q''u|sEŤ2ˌWnU^yè^&qyNfGD{at/냵>M?zYars3Zsw3?(|-]>YsMo?oLVAD$8 Uе12)BDb.2bCDRQu)47MC_0203u2-O2b@LuĖaسTp6V-֋l8HIv;Nx-Nmf.n 1o" ~6[7 ?ԋb.'6Gh?+Aj/Mh;԰tLl 22KUJM;)̩5 wjk]eӧT6jdZomqrZצvSǽ.]j=e_&V} z}S .%(衃ѱ"qE'=95q9}[sƋCKPy[+ ZVrZCG㞦֙6CwQ)LR3&=D-> $ ;:Vbx˗T_MqM4|a#ӳ%引k]_忥}i/q(%F66.{MB(@@`a<v 4.D/nmL^ ~ADK LRl@I%nZ9;RA:>"/=_ #1ƶec0 ( 4^  @t B$P !  C$!@S_ L=tUO ld$O߹|/4.0= 4_uȃQ@AW`~{ph9Cð0 `I'TAYII ?fPokyK pHYs   IDATx{\Tu?9sa` DnPfP j]-`m7veu3V Jkp3/%Vv5uKY 2 pfNa.59\  P3BP=D:CP=D:CP=D:CP=D:CP=^""ɤj 0Js騨u\q9|MC{KD-Y@+ t֭Ϗ\`5kGz-vcA/vGDD׳^z;v ;"'ȿo=H#sk׮|vܹsŋܹѣwq8qC @ *{ɒ%@^`l']vI/q:GJvq4W[[q t@e4Mii);vl8nϞ=^{Ν;f0L&S^hٳgt暎}OmH3dȐ@ pԩ׳qCe-XVXvxo{/,?nիWZZکSz}G&&2}¸Ǐ?͟|=@zG}NDvG%lOzN~~s=סo 0J*sW6l؛o9l0"Znrss6 ] >@}N:5x]vݾw^߿vZ"f3,;vLڔDرcDlC}h ADQXHzXKztHztHztHW ߯t "te%%%3gׯ_ddNׯ̙3ٵ l5 ]Ν;_ݷoߺ0""oꪫڣWtu+>/|Ja0J]UW]uֽ̙6&&ӡ@(tEKx<t$D:"***x'vna:"yX[ H]D C_n0wt$D:"xo1$=xlbW,@1u԰V0,,,'''0+FꪫV\ي+W"!@rΞ=_x{キ0 ]Њ+f̘p8z꩎@{@iΝ<̡CEQ?|xx^/6L"te%%%6mN>rfUW]5~#F(;A+,G"!"!"!"!"!"!"!"!"!"!"!"!"!"!"!"!"Jw@ p_;Wu.+@[ @7( .e8v㸠H!#e8OvCnKMѰF vt |>SHѱEڕƱj5 4-)idwAddҝjkkH#vJw T t|EQEK`\gqtYjlVَ!@H,y<eW ,q:H!ͺz^-=RvXc"ڲnQyM3TmIḔ`s,up @h]C]]qtX6`ceE WttlQ||t2A.TMmv{␇_|!`Unq1uF$"fySm&""zϜ.˿dhw,,Hus.Z(K_\ed_W7F<HmhN#9(\.zϚJ(yp_+Uo}Pڡ;/MJ5ԬEeQă/vhsm˛;Q>%O}z9r+YSfѼdž]utYܟ9zP5y ʁ}S3Z1kx,]9Fȱl杘`р{e쩜9ddAq B iʹ-'{i݅ MZw5&%?~aV"rRҺ>a&2'Qn񫓆 ټalv .FSdW|'N͞>iݞh'N. GW-}u{ \O#:\&Nbir#>[,-!ݹh͝T8Ȟ3/79oVΞ'+l7(# Dd Ǫ%tɭ愻r QHDDeHG't6J~?XCCr:Ν;sLfff{5gdqzu6+O%fHtUW;):flM#e)k>g65Ty㸢(b6  PeUTh5Bnf[6~sPIZ=ϛP "ٱ:p)t_N\"(Lvzta6+h%刕fccccc#E/z9G-vh_ך.Hʲ!֔,Pq˛[0RkZIzQvOF%7n{D~9;(giԛ^v.EMTQc[:t0Jp;}Ґf9n?.J]Db՚lmꢍDD$Vq,Dkߚ)?؃[peL]_C `=#3/^5cU(g%:qȢEgp/ڽSl!jptrhd/A0*^zjVJ(^ET97vhsrንC 3+,D%GJZsDJ;b #^iJ.ٳgNf#5" ݅rg|ю9S DQ@d_8wb<9wΚ{•ú k *5$?mhow<3atБtxe DYP\vCjbPC)vZrN}D>h $m#m$O)8ltl]y'>G4`^{*gh!*6 NOƑ-}m#Yr"p$~ӆr 59W9W@-DnreQGr=(A},z"7l_ſεIFD$za!qǙzeѷ4V&8^Ph%"'Ql f'7^"'ǽo?qSĚ8݈w!@Be 2hժeY>G;Y;[ԭL&KD>ÖƉGV-Zu|TQ&[Wxض$?ȯ?[v~ 3M^cW͟6eոmH0 %[S^)#;WS[^"|mߞVs)%Dn9noISf6l$ޞB7w8k6ӗ<5*M $J:GQ)"<|Cs }?oЀ kρw&@)"+=}vDfNI*Bdϙ7+gϓJK(""*v6ȠcCnx""m bWԤ% +Ag);@2NY ZOD f=_4{Pf7Ȟr;'@}u(t:ϝ;w̙qT;EmjWm$\lHpU;hF^Dm* /XӆDWuY7F~:qWTTeXfsXX`y^ F@afdsav!fxd4یlhŅk5m7zbl/HztHztHm5p\FS_>9DN>s 4VUG*j $0 sZy"BF4 &"||Nt{t744zEQpŊ?"Mk4u:h X,DttҔ+y`0FHzR,"3zd 7LF]ѕIӯJM#z`2Xcx<R]Z\MCp/zhR`+V@!@hHN|>QEQ yd2y<6(]tt"yU@Kuaaal:L@[ @HyN~ivz< Fnݺ)ҮPJulbd2z::hD: ycSl\`0x^6111۴vDӱ9<mH!"K j,cZM|>.**Jvzi|N*@VC8.HIR((z^:3nNΒVe3v B@oe(jM-A`y)/PD: inA Ēt@ yzٓdjHpH)ȢEgp/ڽٯߙDDIpUs28Rᅪ}d?aHOl?ca5z""בs282o9BD$Kޞ:uѲES9KȘJ "y|V."BPA 4Ցv_u-9r2f_eϑaI\ooym3=E$khHT峦9n>pl3xٕ"΃y߶e=yk! HτtZWPE!IG_ U Jce]هk@ĻG&SLG6L+S.G׏ȏ>vnL:G4eo^~޻ I7D9V>1ܵTE::4: ;KS}KG| q<9zыD/y"/Qq#[lX/~Vh;Ycd{ᨇV{8t S,z7dzU|>D[=>ژ60'Vzto7:NzRsyDm'uuu;&\3\{c#TDd4̛Ng܍U ʛ\\Q4%Ӵ!]:'SAN?17t"I)7\5"<\mtrh6;oLJqz%Bt9Q}|Eϔ54Uf kߖ~f{hl5 Z^:opOeɴx 6""N'6td SVu+J^8(}9CC{lۙz䝿#}^ŪU9 sfOz#e g '"m'EDv< CigWkhhp\NܹsgΜOQh䉈W%jnXSUU'ƈhÝ^]j$Qpk]#6U>Nn"D=ڻO{ߴ!~˧ 5q;CH0dѬe%U%˲r|w2-:v.[LN7}-ZLu'{Im;H.~!5{Pn}z>ы7DΨ;6yg(^96ڨ–U "(8d0nMy \O9sozh}{Z͕; =x6C$aOU첑x{ 9qL_ԨN6)(9p8GeDTrpU5A +==ئo:^E[O2 ;%p =g^nrެ=OVl.^+- `x" ≈t/,KKe\YvnQxZ:bPd`uFP;e%{ju<2m|AI""{ʉv  Jv\..gE}>((z^dzv=z͞=|>{2ek(tl45ǵkn߾}ر>h4Zk@ j ~IyaCqNsNڸqf;ydzzf[dIDD:N{U}&^@ݤVnoƍcFD;v숌7n7|Þz A~+HjxnA>cN2^o0 _7?v{<,.JlU^ xAXv/z괴>Ξ3g/~ Ѩyy^j4L!-x<q~iqqA.}?w}1c̙c2 !ͷsO>}/8gΜ?~`XxqLL KuXk*XKj@ s_ }sDggjlld(J{!D:PeyN{777w<߲6y_b'NL`+Xjŋ{q#G۶mrssz!L!@gl1DCCC^^^ii-[V9v zxNMɓ'9"߿޽{&O|Iu؋:?D:R6V \ccW_}~m}%EFFnٲ[nIOO &XzBH^>ϱ<'EO>$''ggnPFjXSr7IXl:bܲeVX~݇ݻwO0!''gԩAw:lsiꫯ{1=9vXZZn_`ADD &3Z:Ds'NsDԫW/?qℴk &B΂ Hl}3fӦMܥM63&==}߾} JXL@P^ l޼',((UjQFuk郂 ZvX1ŋ׬Y' <пÇO>@ .AhPBso*++?ø8{gϞӟ"##e(ea-(&M=ztҤI:S9"+--t&M:z([Z @lU^ [⋌uF Ѹnݺ̌/L`:#Isn{ݺu3g|7rrrO1bĀynݺ]{Nfi@{Z:PA; nE6l&$$(UQQq=ddd<`0t:E @Ӵv̘1ܹs6m֭}lSN7.**W_Z,ա`:@!0'߉'رCuyucǎ &0֡`: ";ia6*]vM0{zl%^oL0a׮]Rcc>&^}$,]w]pիSSSchlٲ%++g}F^yMj4L@BvT .ظ`[8P>Fd2z^ t^ӧOW |jUWSS3a„@ _uU FÆ#tAXK<1hРm۶u;~8%/V6mڠA233_=# Xh4+L@`BF*9sٳyD hӟd*5ܸ8 eS%us.Z(X\Nb՚.XMgDDb 6MNN?zٳg +]cu*td+t청ɓO3?D~uU ҇W}ydOLDD:r86¸[ɕ*LK]'9-h4/rBB}K/3MҺ:,VC *zlnٲeo͛oж$ڸ8΃랙V`q-mg7[_z'+cآcHiU)o=ND.(w?/pt_jmzkv~'~^G&^Cڙ3gnذ/ y;I W kzQ՞?ePLPk+wN)!r{ߓCT0ţ M+<}:t޽{7o=o0'?3)ZǙ{z=Od!GެDsݻo游{',,4^/Uh)|j@ Ē9J5Ç:|Էz{z'+cآcgt:{޺;t(k"9V۶О;sÛo6bĈCf4Y6vk~@WH-#ұ"d 7_l„ f͚>}zGozh}{Z͕; = (DD<9)9g=G>j2f-sB==܄ ~EDDH*<X,/vd밙S s&֕9of 8=B̉ gJMJ&L8zIbbbXX,,:v)06*9:|jZ6#x "`ZL~N"lv[iem/WRt^{=zX:i`tB:9hD:h F#-cJE6 뮳X,߿tRﲟ?(>6m8qbd$B+[B']j֓ DQ/kll&aysmٲfm޼9::ZwzgϞ;vS뮨(LUxNڑyZ &JKAK;v|w~A~tѣG >\rN*neyh49i"tىRv!_a FIII׿um]6--M7wmv77]<&[bx*tAM\Ӳ[g~mhѢ O vQ BAsvtAAuÀ""" ߿rJ^;h%3eʔ>lҤIW_}uŭP SJAҺ Һs}'ff)Z:55~̘1b}Iŭl! 䰖0J2 Id׍;vvO>~kcƌ۷oJJJ6vFCkZ01ÇZwq;3aO[~/;n7sd+ [ZGD`i lP̈́F馛y}͛7Owp)yyyK,;vl޽˶6]<״E:]u <1۲ҺSN[~DD_~eZZT*-tV9hWt-hN^ jGEE=zҥYYYʾիW?#F륝y.hP :Hӽr" kv=**駟޿…  fz7322f[X< SС &^x'//C1(0 M*h:*_ct={$&&nذaذa]vp v[m[N%RN{@Bg y/}=ˏ?xuoŊ<ȑ#lq+!ALU²{ 9gΜ}-YDՆK>駟~ƏߣGm_; @灩wPX^:V0 `KΞ=oܸ1222T=ȨLMMnZ&2J_s, I7KuAeNsǎO޺uއ#G=:::zĈiq+sAWNI &^@y?&aj&FUVVv-ym֭[ޤby=4sl3@B & r-QQQ&M?[%K~ߍ=z(n5 lU>ي<"t"^aBvAז`/tߜ(SNޫZ>8' b0% &W &Ν;|111ʙ3gӧOFEE5[*M:9 Ψق+L:˵s[n/}cƌ>|xm 2!CL@g$/hz[> +HNN޿СC׬Y3v؋?|onV$9V @H+h4<7-e.h;Ĩɓ'Ϛ5kM?]wկ_?y1[Doٲꫯ>ydZZZcc]wv*nwF1F@Xbu^ Vղ@6~]vxqjjRSS:9i\Е!P *HlłiG>swܑf db0N(A5aK눈LHyNt:vKt:`4(48l1;or!Hד~_7L3 n"8y6v0s(BayK_HxjH0b@H'7KDVUzlw]K>ي<jHjQTTHKr v.-h/bܫ(>"""i9J@utaE7(<<=!hbsvtHN*G:D +=@!@.pzjr p9 .Nղ0~t:k@ib.X"t}sa !"!"!"!"!"м@ p_+݅K -H HXߣlzB38h8cgZ~ S"Zn#$'h4~:F!Xh,|>v[A̧tg[A.F!ȜFj 6P'EWZBpi_BXp]7s,|>Qܹs<ϳx~^B>rn3 m4ȿ 6\ 0JIs~_E˖u? qnt:j~LZ3nHQt^8"8N҅oz vtOsG]Y';BRz|t%%HKQ[sӞtpS xԕpI>̠t!haܹs@@ղ._ Γ"|># Jw"rjZ*)Z6 "uiV}Gek t@$"bNZVӉ?1Pw9U HAZKw%?BVl-(v0m0^`QS \g۹:uTQt D:8Ot(#:;DU8 06OY{]m]ٶ-YnQu\Żi[ b-n{wqKvAv dRЙ990ypf{>pV+2EKID&8:+[*1;&Dn% ^u.gbRLan)f60|.e;q9S#C= u9 {7&.zHaumMX7[fܣHG9K=ٗQ&9E/ZL}W@RܸCQ## FzD\La0ꌺPEB&xU=Hq!ggO8CcO/>tl5吐Q'0'ȻV2E^׈qGArW^7\MDŽ"2DHr*#d5سMMRPiu4URCkQUCݖ |RcGMQ#4i{U 0ҞokQcPl AQ<59L9UU{`syJl@ZqMCߜ]eB; ]qqqyy|JOo%EQ{2,(҅tcJH'7e)(6Bn3\ĒnLv(/)k (SCQsi{=۝It۳a.f?[=GVeK.וxEWLl>GU֢(J m %j#BWW(dI(n9lf0{,foW3Tg뭿ʣ(";\<B8?>&caw87LvnӯO߯V@”k <0e&9Me[_x[d)z,n4؝3?NB!$9NQTbRw*Lo3|K,{[QO sZ I>VWS4I36,fW4nP5S+K4w_[X۷:0}\`+oY͏g}hOmef7t춮[jj-m`.[Vq|_BM 3S}I\㤛}SI:`β5ɵ7L0οyE=[z(\6N0#dQ}㊋Lb0z}LLVy>"b܎ͭF &&G?>18o VIc"vܒ&CzE^(:Zw$!>N?l͛Iqڮ7 4puW({]Θx^uzS#b.VmmJ@Eu&8V4i^t#d|cݍھm|̙tJAD8cgLsz}Oo2h~8xcyB3DZNΣ7’7*!D=Ev?X[[[QQQ\\!cSx \$˞ރq{^յ2 &s\^mC*:-\2]34UXU\*W$eeBȰquZ ݛS'6I晃c_/_l)q9?-.bƤvDH}zơQHAUW[=\Ec zKGNقPAXdӮVod8KFC8ERߘg;⛶:OyV[lۿg+qs+nM8s=-yխ+r׋ҭP; s"&1w=ylݷ=)ykW߳89Qǡ$Kع'w{niH?;/|ckHgv\.U!W^:7087K9\pTk7vVoq"6|jon;Q׺쪪V.DUV^7sia8` SQj}ǯm] h+5ιHޭ)֚|[[j!*,ܖi2`ٌX:8m\yE׳mQ^Sc.MK^Hm)֚k^ߒmwg!x];-ܤiӦMm= T<2 5N 9/ G}[塁WBȰܶGz #{nyD`%gY4?d~EbxyQ05Z=PS=bmŠ{wnZq^Hy㙅-{&ז"-ggOX+\b65jo2֒g3!pէ3vl+մݷXp=UZ-mlZ7|QxIo^Ý]t?k*^H`Fw.f-Jr~HZcWYu*'z!FtC.kkokiiikk*1cG q\, NIns Qg%] ck y:m[&.({ð[ }eHKM!f,fωm׹c^ Kg8v:#70JkA;Ck.i#U9WGb%-;@lH:Ȃ2eSjB YndOtނplԓ@sd.Ӛdٺ#y~׺+ww44?4ךr/d߉B[fOmE[>wL?5׹w/,YɽͲQSݛsz;iGŻPi{}{/NpG[V,Ϥbݢ>rÔt/ r+p~]9kLNݺJ;RSΟq+E_QVbj0{ t}d˝+u-ߗ  Es*ݹDXr%:s [͛} ^|c7PG69Np޴b>+yNd=~ ,{8i>&RiE|dݒN7ϴSJʢz S͋Yb}If%_ٽz`~$?xhb[QF﹙(Bo PTh\HYΜԤiZZ`A-{Zy1q jܖ~ī@ΰTUl>(oL34N V?UYLk YfixdYOKt(rXaW㶼>9R= };QU&k8iќF3-i3*H{Sg.]Ô9@}vLi=C:oZdhZȎ1v4 ^*="hXM"@CH?$HqM/-\lsau5w$hBpYAJ)j`7c/ϒ"uz=ן!=.Bl٢8zZQ'|ϩLOQc?PO'.{Y=.#ژ6[Tf?\KQv_=G^w ʼ8@.gl=ױt}ɓ~gA'e$ܸkz>grB1Ki!hr€>;á_,wdG{f-"V>ræ9]ZABF.Θh<'oF# R^' A팉=yrNaf,5Ғ.I2 wmʲj~R̹Bn0w=Qp%3ٛ]*bK.3,ʮ园IMWNbsnV3`_ͅ''\lJI<(b=Yw7&-OyUz]hi~`%^:BƳω>s73^\摏NM޲iQ"}{3o*?ݕ`vsJ\͌ҳ҄+W=e0(v[ ,VQ IDAT߂} 55ӖΊ0g-8պyqf@H϶vlK?rY)I Op{J4t-xr€ۅwi)7E~ꗼP?mL0o_''wʛK{BȘqݍ3'$$L2`0V|D\Hww,ˢ(|>vO:uQyAM7nt$M1NYʼ>[7i㸧]|.7bz:]u{[ܒ!>]by''\ҳW uhق%:cqtNJ&M:nܿHB!rq3o4&p%Dŝ~Z~0qIw!_zj IOL3KI" !̰ OÑE #:(B EQ`%g֭5 !B&tBhp%'֞RHm xks9.wDϜkX&q; Sc+!2$g*ȱW.OyD7cUqϴװrK@ Bz!mp%om/K8,ۏ mjxugF2q{%V6`[j?<;f$s5@nqeuɵv&q%mS+jwndzj[2{{ߒDо9hp%nX[-N5ݓiu}Nȍ7ɳp\^m}@GFBF=N)@qqqEEEmmmccn.m k7(1(n"֢- 0&E5,#? @^UdL6ڨi*i5 ֮(|3,< vEi(N`+0;) 9PfKPTm5EQϮ}I_G2+Ǒiu lkmrj H)V r{?V:}+)2FKaA.PSWEQ%0;H* HZ؍J m %{ ؃[l}qGQ^_rvEQ|d0`7C5;ö9v5%eu__XNCz:fm&!ǮfZt @ZY](-GEaFgܨ =&dI:?8_5|ݓ8NZFӌ%@~kFMӰ(N|z/Kn`rjcN'*3R$h?vmρ~ Оs路%;&?` Qo pğ~m.Ln2󎤛t E:BƳAy~>~xcccmmmEEEqq1҉2OJ&Y: -><kx8fjh)JK'=Y !W+KMKЍxM `-i$k)i$pMj'mU hv3=Wu{oquGi]inc@"!2Xb=Yw7&-OyUDWϚmD_XlH@~]fX{Y]7[?ο֕>ԡEy+:떦~!(|SZeV VR!w>r7k%6_YU`/0RopvފgDڷ/o>^l%.Zafڠm2$tB!!3f[~ 5Ӗ./sN%qԻMyBMʹ%w *6?u͓,K fY7'͟ 캧VzR=ߒd#yY7/ L}qlџ~IO'm@ZW̋e?=kzv[ ,ٿr5V@Zyyqʘ< !duww˲;;;^>uɓ'SSSSbtpW\\0ecbbZ-4r!+Wmm6{{Fdo {N.7bvA(<"w\&Wd4邮ާ~[7i㸧] Кy1x^V4i^tDtB8zc^F]P [3&ݤKqP68Z%ΤtB݌Ue#|f r(B!dPxuC]9(;| z5k8)SѦFjP]tHG vq~`jp u |SO@uPis+y1 .az&5M9 !P$F߅ѡ.<ę=@l@dd(aw^!udPjCow]pWE7P!}?5ر0^)\ѷ1w9za_lz|lEQ{| bbbB]Bhw'U'H7!d$ŇDDz 53. hZ*B#S;qC2y%hu'M^ !gLpB!=tB!a"!BHأHG!(B!=tB!a"!BHأHG!(B!=tB!a"!BHأHG!(B!=tB!a"!BHأHG!(B!=tB!auKQ :uwwaq~%E:B9Ea-PV6D,af8q}~ "!ẻEa/ ~?% 5EDDP#(BؿW.Kpoq_EQ"""Ipt&(g.kɡ. ӑPEB }^:B@ ˲,˒$!|:&~FQH6!!GuE1m\E9 u]HGzS] $SÒ!cE:B9yN.|>HR!DE:6Jtc( \g{zo @ߙ}X%ĉ!9  L@Ǐ766VTTqBYx<&{H+S| X쎒3&Ij(`-jhsOʳ@U0څiE>EQőoQ@[t -P^`L5(_^g/I] 6 Qr0e9UY xJl@ZqMCky`.s48mV᳛WW =&[ݢ(56 U0ns.gmIH7 ˉt!,x% PRVWTո @h8n~wO8Mtrk%`ڔoךcj8n䇐rZFq׀O]3ni4Ӓ6(x-s/f myqJmNN3;sqѳ,>;!u?6\7]qyGM@y-sR-zѰm3}Ώpo7VmA&u%g(&&F<!IXNIIcccʖ-[6BU1G !d:}bq{H+Qr_{ԩJghT6KyҁΘԪU32tq,[l?я0fQ(B‹k/ұJ7Jsd~Dʺ{F0r!ᅟ</xuC] >… 7o:;;NLLLdddAA>PBH?S՚0iҤI&EEEEEEl駟RPB ?SN}'x p8KW]uURR 9(B!aLp4J!2P#B {!BE:B&:n t*1+""b,uBB> !=E1=;!}Ч6!"##C]Xdd$:BHtBY,EFF<<{'"!4Fpi}̙NQ%Ie; /p!y^tX0ydՅRBȘ@uȕb!|&`]BFVD B!"!BHأHG!(B!=tB!a"!BHأHG!(B!=tB!a"!BHأHG!(B!=tB+u IDAT!a"!BHأHG!(B!=tB!a"!BHأHGEQ%qu2(sww7دǩ?B@2Nr }G%IU#B!}B纻@ eY$I\.[ou-|W]]]rn5B8@X $Iŏ>d2? 7`2>cY ! B›:-r $I劊x 77 w^bE y6224K -#/Ea,.{WzWoW(磢"#####'BH8HG K96vuuy{pfs?[n׾<666**J<:#)"jEرcwqyw9g~wN>}wzh!$Q#,~Q?CŲjժ^{-66|7+,7YeR!$LEg? u 2XJD_lVS8[jմiYf͙3ABx%>!ԃ6lذ`vwwkZ0B#!a`~v?nnnKh[n={vnnɓi!$LG!d|TFo_Z0}}{(:Z0A #!cC{fo?p@tt"::ڵk׬Y{:Z0A <2v_ _y啭[ݻ}Ls?+ϟ6Y*AS!c- Qbv/$XĴ`2FP#L0¢(VVV]ڳg;,\<[nB]0Ag 4J C689995é[lٴi- !ϑgΜٱcǑ#G:t5ׄ?z%Kܹ3&&&xM# }BFUb#}6lhkkc9kv{[[۝w_AXv,b15B&tlUſk֬YtC C˼8pСKY磩uЊ~!(,gE7߼{w$&qo{{yfΜ6/!12!V^x_C]ؼy^vN- ZAY}C^?7xuq|;_]&ML<.F21kiiY~{w=9s;֯__LBFE:BHB]իWƆZz5k|>O=- ZAJu1$I(k<>e˖q6Ɍ㸕+W&&&}W_}ܹsoh!ddBB7߼ьj!>N6Vwqoֆ-[iؤ:JuaG4J~GGǃ>x0yxh#6mڴiњ /i< s%'^ rWq xb~|ԩSl ² ,!dQ#  RSSZoxvC7O)L9Z=6{I^4 'ʓ6֗ߑ/~ꪷ~[ӥ~g(~:!dP# -x,bN77~Dv[8޸ {yܘq}OPF2q%#"YGinq}_ԺƤ܊]olsl6+l (7nܘ'qy5ؾ@^2q\rޡ< :׬Y;/BeSY~3gN:rgy&>>Ci̓of= +V."*K6E1BQ( @cLu2|6\ } d(xf@zN]3Kuiߟl/r:u̙3(JaB(B.|>moookko pnEQ$f ]Tij2S|%6G0dI}Ҁ6Esw_֒Um93fdff~Ǐx<ߎR!dX+!ұu1[O'O.:KG &!Â"!)M|?֮];mڴ/W\q.֗&OXGR%16Ix|!zγ*W+eM|t+{!=pČʂ?X;'V}sEM:ꪫLB.E:BȥPcs(]vmzzoۨ3~Ճem\gkuʻ7?΀k+fpXU׮㽗~2mwa}fQv.lLHpqJض O–H-E-Y(|u^ @.Yn}JRNbhۗvjZ0AN%^ԩSmmm_|œO>PVVvh>rEQ|4uiϑE圽nMQ&w9ģ(gE{0;؎kC:=@[ϾfdiДUguP_||O>r:::h!2qJt$d4tvvnܸOo}[`d)̙3OQQQW_}'|AƏ_~Yӱk@/rhoO,_?y|9e 0CW^^~ 7GN܄ &>]]]'N(** mU 96!ب~^3wu]w&_Wb$VDÑ=?|hh4vvv66D td7o^LLӧ-u)t~wvvΝ;7u=Y|FTƏ^z??|>̛7/%2h.?… I34nq$GddG}xX̙3y=؊@+g?{gU .R.w0 \!qFrJ32O*M%V^LS%qQsb*0+Wގ630G9;s}xѣGh x̭ochA#_c2>ח&nuٿBpww3q*bT*`\ D|Ԉ%K 8ի͞a4G/X~ E 07Lb O7Om eaBlV[*34ʫG2 (l*,7hdP~d) Ww'@e NܷDdw~#͝+ 0wm4 4H*ʼnbPJ@8#(ix<ɓ>|GZTg&ǩgo-:*zl)>czRpZ=_>eb&gwSPi\ح{C.)/]>QYסKļ:mhUn"̂kYIIsF%K u' \u254-=ꙙW^9+8`,233P(0aAV# F_CM>ҥK=c%@\ƨP-]9dtfz^xT= $/-07rP crkJ0uS!.^9ϡ=xvB#}O t7zqq{ wȘS6g,x[N̾e=+7=H6WgHQB9owk֬߿@ SG&h VCA,*H$DD$kƌ}ٳI9r @FR*?8aƥ~ Qﭖ 2Lz;k h0HGuӺ78 >. 0L6Nٴiӌ3zEfL,W"喝3sA(Ixd+X,I WWW77Ν;?s.\1bĝ;w9ۿ<K:pFF(¶~RcV ot3o9rd`` uHRWWWҋN$+Cs?Al58+D|p= '*m8u:ZV*JTVVV*JRYUUR~GŭZS*Vpbޣez__ﺅT/A4(K׻2=xJ4@ 4o_[j4D"Ye!Fy[6m4a„G}z1#:~%kHD+ɏS^:A,:H.ԉ<,իWttm v%J)m䄫/o_C LRofwLzI $ݻ7D@bU*$d52B߿ꘘ .DGGwԉ-sEGvtCRp8' )#.Ց-_ꈻJTT'Ncǎ#7;==o˶p9#BYgyLho߾=a„ڱczxx9oBH%A8%F4ٶ5 $j5Muuuuu"!Cplŋj"RD")t*m)+ @n|>aG]i:zF=f̘>lƌ\ { 5j 8ꈘz9%\AG% VBU],:𨼣.00W__v3EF˷m&˻uDs -ψs N5M:{nffܸ~JֱcG) v[A8%F4m `t:VK vvhN8ѣGAqƸq$ѣ===i9H+fRQCp)+ ;nHbRΟ?Ox==={+W|g-a…ҥ x%B`1%OX 4_W[(Zd1W0) 5F&u&5?vXǎ:ԡC޽wN0ۛ9m[IqH$<A׾#bmxC<|`ߤ~:z,sssO8ѿNFg]t&䧋Kc9At5P{]SNTTT#е-^igG>MK%I: >|_϶92}aÆ`Iq+ٶU"NX A8%b14B"h$V%4 0ZV(3|шVq_0u5l_IO<5s˗/_Fnݺk׆Ջ<< wCFUzVU6zjycsI"vJ!9uuS뢢?gᕔWWWGEEyzz֯l%VR* E"vfR> J:&T,T*M1 6,Y`{B!;k#L¤IN>xرA\2a„={=9Gl%s"9> uAIXn'V]`pFѨ́zNpj+*bwxQFyyy=)))QQQ8#G 4I#9h 9}@lJ:2ثaX!wT*РA/rAAAbbbdժUqDD#D=GA,hہ 4UT*b\ޡ F`Xf0w݋XR) U*UiiifffPP_bK3f兇w$s&/ #z)hrKX (t:AgaF#F#0b6dNjkk &LzN2ɓO>cǺvjO0h4N2X۶9I!}@Ztж#`1؀[DmB)z@?gϞ8p#G f+^p!<<_~ n&Hh1vnցi9( C6rh5fq+LP؎:_SO==nܸ͛7Ϟ=JMM}WyS=gs+sX a&hrP!VB4pF0֢,hvcN<23..ʕ+6lhznFevءP(vjswwwuu5s)z>X 堤Ct1݁iZMÅ555dSA{` G޿O?o>TɕJeTTիW;v.`'ϑ`X,X ahrKXPBH3.L6IDcyu&eSL4hɓ'ysǏH$'Od7&a1}HAIXAcG.A;('[ai<&Lp…'x"==}ԨQlN偁Æ #r!oh9,Vi9(!Q4ӖHO9LEDV>?bĈ:DDDlذam۶7|sܸq?8qřTN_I >X堤C}s8elc3fD%: %覫:trʂa;mڴ.]=ǖt!}HAIXT\1k`kOXvs~F^...DQ$.乖 > -%b $Bo\1fouVԵ`zIut:"D"Fqss[` G9=WMR>X堤C,Xg=L&g"t^rQGtbl[SSCP($z6%dV,h->X 堤CZ\PRkDq H$HZ^'I>Otab1Ib|sYBZJ:A &hgHc2ɱ#X ӀAĤ`ЄH:v/"HL6t%IA%  `B(W@@|$vn8(qlL &M uԍG[qP! &D#lD% b A e]rh(Ä&fi g3̖Bebhj NdžF]1hcS ]nzH{bfYRi3oh6y1V^`T۱;P2 mm Z­ohrWWX~ٌ|٣,Yi"aىJ~2}be} 0Kd+4 J9I?m=3[ԳM_=6/=WGz)l^+Icfm)04tn9k~@ydݪm֑և!,X\br :5N edZ0T~zR # wٸg>*7*_)q-}.I괡 A<? wBLZD5f53JIB)(Ten0Pz~ҕOu/n I[,9 _O_6iinH `8ƌ3>wg (3_P(ܞ[T&/_ßZݽoسcezS~:30& H{M qy¿ Fq.0Lʆ^Bt.!iTorFhS ^/:% $BeCRJd߷EfLI*X'0:Cmm`jJ݋nrKi'=ZZnn]b(/- =|~{p/gQ[q äuC*b&_A8mC MAY^V ;˖y 3Myi<|| e# A ,}@Z!6rU߷}|i3`~s؂H},-/%]zOH}?H$xOE8~!.-. wZh :UxfgÙx( q8.ni;Zh :,L:gB =  ÃAAAI  CAqxP! 8<(AAt  J:AA%  ÃAAAI  C,i0! ~[BP!_YB'7%wax,.\|# KA+!F @p@@ooh탥}@Z^i5f9|>8]s > -%b |S {VTTTVVT*Zht:]MMMMM '#ܶm/K|>/$'(:ohgŞ(!Y2 %D"Bl8===9y]bE"H$ruuusssuu%SDK 9db;>pehہ jeizՕhbZ`Knjb1ԮbX, BF8athہbqU $`0kXl0KױcGN^o"VE"D"PH+X 8o @IXz |P(tqqz}J:, -M,-HB!̓dxbk>p.> 6%b191=Ĉ F%]8y]2?4B6Ubv FUW(kTSSc0jkkCI[L;r8 gW(ah4DP($obI+<< c^ę|Sl Apn2> J:9!G }qb0`  CAqxP! 8<(AAt  J:AA%  ÃAAAI  C{# @Vᨒ=?A@I8سgŋ#""~xkkk|h tix@ד?q28$TNjeee/S.]4pK. ZV_]MM .iЋgϞ#J:fFkZV믿N4+77rss==='M믿zDA`z=1F׿;+VxY{をq$L9h9s_Db855矟4ih:\#S^|}qh3Yv3VwK/}K.m˖-KII7oW_}V&řF'H\A쮩!z믳xz>}&MxÇӜhWZ N;w̙3-ZTG)SJk6pΝ;ߛ Ld}ŋs{Mx<nqP^|R4͞={֬Yk׮ƞ{ȑٳgX瞓H$"H P^!=WޡMS?sddd^sСCG{ԩO>wUTVbn(C Yə:uj\\֭[z+ m۶-^xʔ)Iw q8s] qΝ^z|r~=I򊊊͛w]F.@8(;ŤvݻW_-ڳgkB}uX0 z=`1Jzw>{-|={N2孷޺vڈ#L*$`Av1jsIHHxw- rۿhe@,@'3)(--]p=<;+#??̙SLE"QI$͘1ƍ˗/:thǎ٦-K5b꟫x뭷n޼yaoߞ8qb7lN  Ch4Ç'$$l޼yƌ܎𫯾Zhњ5k&NECڔ!n޼/?c1hbbb~m۶u &Ħ4V iӦݻwgdd<\ŋ b̙/Ƃ [F. .(}١Do߾hBq@cR0K#iTݿѢEYYY.]=C tRVV֢E߿OMł AItͮYh4iiisy g}6wܴ4MG|#H 1) =**J(={֮2ٳB0**g(ǂ t֭KII9~3<͢o߾-{aàT3juVxY^|͛7 瞻{oG~ob2 m!~1V-//_d<ةS'hwܙ4iƍIjL հzn;vP(\yΝrʩS:b0iP!6!#m&믿Λ7oС۶mkN{ϟ?}={}hL 4jׯOOO?|p`` c4'*e˖b6oI+++?K._@z/_|ҥ痕:R-Hi}aj].\_\x7˅ jUAd;e??\N:EFF=3\qZ<ieL($'ۻwovvùcѻwoBdɒ7o71NZ̙3?믿~z>0GFFt^{M&uhVs֤έZݻ-2zOyyyddhܼysǎ|G[=#F4iRaa! 2o\AlNUUU+VHMM=w\sr]v%$$TUUaҺC,~1NSǎ{V^G}iӎ=Vu:IQ4߈C?)))tR;={ݹsg֬Yg \!VﻈCeZNNN^|C^|EsΣ)/-----Wx />|8!!aj,ʱ`qzЋGlJ:QZmEEo~#F4͝KB]||ܙ P)4pe+F,njD*wf,tUUrK rytҡC,YRQQAm7Z^|8s0uaCf%o^`8Mq=bsigs  ,Xh FA}Qᮏ(n bԭ[Ϙ1c[n7B7`R AVݲe~!V}J=[j1s /cM<ڵkJmmH$2' X0E0s$zB1a„t(/iG -Jp--~!xf a[nj@ss 0Ln<%a ]*AfeA"1C<1o}ʞzer@ag\ݭX}+f'nY ak V(Y Alwuu=p>+%::L -ů~#m J:yMa9V1k֬_NYҘ9+(= cյKrw> P%ǜC=3 +giP1*krVQ^z׭q>9zX:7+J< '3#ԩ[V̊XpsU1y׮ev_UdlzS3^=ak˟]WVFdUidw裏bbbӱ1L!1nݚ1cV=|K1'#쵪⢬g6֋ZQQAnںqdܴU/^>}[3X0X֭@ ֭ە+WBlZ*++}ҥKtr%KOUTB`~:9['S@5h4Wȓ $h4%IW)H@BU)rd2'ި*H%g1%@. $@.={T Iy FҥoQ\\|޽*ZM,EA;ִʻw9r$ `Ŋt,UyIvMO"+2$Az|\) r]gSn&@eFtJ"u!IyFQ_:F {pfu.]产Ei 1$b%g2.iÇ޽[QQQ]].@qx/]vv\.g0 4(??A9FX3tzv](z{{gggs=V#NjI&ݼيs6q!Ks)|e쁞eVܡPqn+dYFy vG_97fl;X WPׯ_7i0FQC@AcƌȘ4ij!S*MYx@"wرk׮]v  ˳}6)b'|SQ^?3,|-_9 CaJETZy-#pT`m\r@E/ #}e )|sd _-zr>]e2H|pxecoY .{v} `(ܷU8ŋAAA#F֭[ǎ% ,mtwݵkѮ׿%HW pZ ...>>>o-/ѣ;t" H0fW-u7MU!A$YR)ʊ 1clٲe閜w"ms 'L/cmgGe-i W}|dqyoí`}]g $ҸfbK< S^]ʼnQ|"0 '' :9&n`9!!}Vbp,,ꫯbcc-Z4~x7|U"}`V柍+V\"_ׯS=G ˗/OLLjHb'LK"bccы*^ɓ...thr?B`0p5VͳZ w ?Rʊ˗/ggg7;v\|ϔ2rPWUٿ*+))EMW߸e%sKK_w)11qyyy?sqqqYYRt_xzz;OO/q9N0v~+,,\paΝ(2KB dW Zn 槩Ƽٺ<Ug1ɹj`>[V KV*Jܪ$%ƒu`ZP0?ZQAQQ^VJOӗd Fcqn2$Tҍ2}Y^ $W58Lە7 b\p/66~?+**H/bGAnLCnݸTKq@L4)++ u떑1zh^ڵ믿w^\R,z׻~bK=$R_oCKko{ ݻ?<k5\__3FJo߾^{k׮V֮5kVND"/ ={6r8cɽdƌs3f_m|,Zso..}Fy4!dsS^Q. 8x+:(%^|ˋq?aZ?د1s<vo&}uRtaF/4(:9  HǾaE髓f 2C`ܸq͛>}:Idټyo]\} ͛fKÅJAO]V^)K;OeUw_ eϠ,-KV}F1!!aǎڀ===RT*uqqD"ȁC=uʀ8A(lu%ZTVUUU<}t~~Μ93iҤ9Ó;d|3xݵ:MHߺukΝ`}R{^ڵ'J6A// >6H$% "nnnF ۱cC#o3I#n9H$h3># uxyy=n>~ŘQSS/_<22!Gpss#Ul"[Q!J}1G~b5""K. q̙'xĉd҈e` ;t!ML[Ե^:Kl:EEEedd8pÃsCEEEddաC]'HzUX4t:4w\Gm/l߾}ɒ%cƌׯz񑖃ijDQY|7%8S8ŷ#%b.<7As|=<<}dioa…2eJ.]fDf%dM[}~b%7#6io- 6BՑG5jԡC|||~OYYYDDĝ;w6ΏaR#zAIXtHv}ۈ+'N׏7њ;_.4-iDBs L Ћ N{ !E}fö</44~6l؞={ù~Cffiӆ O_v3n@/~i3P!Vbj/'|{oe˸~-e~XXX^zM5h)3zqJЋoz%b=&wI O>III)))"w`%:nΜ9}]TTTΝL5kFAŧicP!-~l,2uǏgffr&,4,,LRM:F1JbȲ(HGtHKjz$6gΜdǏ8p o\Ǐ߳gP~ icP!@P3YF=r/2227<~??rHLV_Q3\AiKP!Y Ϟ1<oРA^^^sνrի~Mjժ?8""G /QxiǠHiMh]/4MyϞ=wQPP{nNA3g^t)::SN .1 ^|#mJ:i"–t>?eʔ'N 2رc\(..0aBmm)S<==MsYvcAGl J:1 ΰ]ta'={vG:t(oŋ} vuu5i@@b貛nzA^|#6ECs_nPK}NO=رcg͚[صk… yК56Yv册&Wɵ>/=ƶ'~h3bIG>Hjkk{L4h s ^.d2//_=??ݺu\F1>>~ [n К5vŦnzѱ,=[}OɁ9ozư@π|:Z!ў?. &5nlw#<wނ}IҶR.**ر#]v7d$9HD(l ȾAd_}Ћ$*78eK:;%P<4~rLhkh4[{y8bqZɓ?#Poܸ1n8D2yd;^v4BM#?6,?z$B^q$GpZ]?xh $}Z.o6lX ߩ&9TѷcQQ!RS-^`lBh0wv>>>V8śŃ^:&#G0:N @]JqP95q31#F8q~/nx۶m{7Gݷob8 mMM`0 6jB,vigЋ94 (Z[[KVݘ4 ϦK1L I M~<==WXqʕ?.[_}޽'O0j4PHNݥh5F;MK:v Xt:Zm1UWWSH~C.fhQ&ip,ʁ6&.::ѣGhŐYEEByfttO)61 ShK,-}]]wrcl&Fz6!_ EFVTҩT*G)F@ m ۍL}4]zǎS.-ǎP(<<< =PnGZVTWWug|spEc&F[^|-CUVU_K4t#UUUS)kĜFݨL:l&GV(4vhPQ >f̘!C7%8yԩSO0 ;B4e71mQA.fQUUES^ 5Dn;h31L6;mNЋ|~pP{C]mzI_aY. [T*sW^'WxZtMf΀32Oȗo($B2dWTTTbbŋ{ݏ?w;vl>}Ht<*u.L^׆ݣn`N#}dیЋD~p8~U4a4IB1V(ʪǷqb߿OpZ}a_$ق|߈^ɢGyg?3Phk  >|gܹ39G= 9!SRT*Uee%^z@;8p-=m&И4n^]]RA **/////xVS^^"^:;]aNGFG]j1qEEE;v駟>|py{M8ݻQQQ^^^ P3mavr1 t:KI!o$X=Nqd9 59@`)#퐈hn+5S ܩe^]:9Icm\.?u'O0駟ƏP(lnS(ƺ H`,;(6^8ÞFGx 0A/?v|SNs/Cjh;$`5di`Waa?! t q;;EW?ÀݻwGDD4vÇϜ9sذa "$-Ņ9F!zںMd0͌_$F+0Fy Z;,]ODxXm[2vZfNe' Lu</((+&&&>>>!!9?>`„ zbQȁ+&2O|mJ8~g@NELewzAܒ̹͒t-Dѐ˚B IDATDrkzP@P * {O XLj̙`Z QExZM.:ii$9=\^|uTWWӛ-,s/Q!Z\XDP ( ::Æ ;zhΝKJJjs=Gze7Qh t-CrH^?[{"Hs3A`꣝k:yIG?j]\\ H{lC-%PI'&O|;v,,,O>aaadMW&=($\t:j iRL!YGXXЗ}`?׶=C? zD M jrbBD"jÇ6l0BP,K$⥓6FQOE-glbi4h?߁@`l9=iJ:c}!ւy~m^:XhxeqŹA{=gaCShR8V`+R; t{a=,1uZ;vcqxZL 7tYM%H$AĜcQ7*Pp84܋(~3lC0ّfak9tG 7WGWSGi ei41z&խz 8F66{ً~oef/@$~DVlIGs$)'j(9Qb4fg hڭqoaE#:xw1`[mv"[pٍ J{#H}P! ]C_g͓<_o ^]KR4di砤ChxJ:fJ+nqnЋ[P!ɢ~ Â,qٍ Nz J:!r>`7͕s4AS~L/[`UA/~{@S^Z6|}цy,4Ww2Ⲳ?*w*-ye@frۜi &W33.>~~>.̒ >p\M/C(Nn{;CΆ'GY ԰mk1MZv h4J!($9 0g*s ᩰE)-PjR!iLO+5&V\ݍp5|Jl pYneD33gf\p<(9~a9̹}>u^K\W쫰DBnXaK H'z`THJ7$Ln_<ҺdANA͉#śrr w?JNIwԳ!i=䗁@t߮"s*u&pMXSX͞n+q7aΚ*H1҉S[7..]^1㭶]5rjNyogny1+f=JRov' 7d{mϩo_oNؘ5Cտ4 [K8+7Z ,T;{c-lacgzl"J_=D!m$6),OHlSv-,úѢKn?]HfG:""鳭+ܾfoQycV DDT}ʽ+9=_+M*+;thonNVP:?gw&fg/=5[v*Ȓ3iږ639,!^>mD+]V^sUz۠-)͒U%혣em]\QhW#e|}xwd){vh_r^bw铈9?\M4;gD/~eCR녱&JJOMKDCڄ%XH~ ↥NLc&h2'nnS?ɮZZ||QZѸo|oDDK?~OWgnlluEuEmN~uVʽ'H4&/s,qw}@y}^=03H(17->qqb1͇ޝ>@c_}}kEJ/Rz Dw{JVU:"ѣ7DmNS֭دoH!*:"}-3FO,Z}"==2B dm!>XJ|N;yD\nm]kǩ2~m]j7-BD^1"Ҷot!* Ԓ֧~"@6sz\MdwUVi\DYR?~YT:V3!3)VE[bxF:""Ib7'#4\KDU;SǤ/j:y,Ҳ=gjh{OK}aDL`IQM Dޯ)pr[HDnTtcݾtQ8Jm"b1Qmo}u}B7QUcۨ:D*u۳J-Gw>Ujk[*T~VEZ*mM$&JrK H'&"3Ue,D{KiWXhD}[2K鉴kCDK *좽ژ\Gu{"U\:C%]V~aJVaVQEX*t栐7CZQjniMCO^H۽tIIDK^M(s`gRs["{ū[ihV;2"cj;[I%B۲![lJy-,(>6-1S,4+Ρ'yhv_Guud4W.H- 8~G>\֖3gΜ>}:##わDJq|IC3x@q Za5Qu8l2F^j86=q7=^gk&ā\=Bt<8l7-m3$no"mb6[%bccfsddN#"ڪd&:l Dl%D2&&]Nmk[Vd<ϣt~pxCR9|u@}m6,ⓒL~M-7|3!!!>>>&&&:::**h4`m$S%qKL z3PCq,M7 }(!B i}g;MԐBzKu>!Rᖈ-CP=D:CP=D:CP=D:CP=D:CP=D:CP=D:Cq.(`aA((ՐXDD #"" BxqRNz7<:b`=#Vc(!?t' +`]EJMR O_$X]j6l}!Pt! Fh.}O|%2iӣu{xh4]s\:j4VKϋ8O<>9>QMB4 # KF yA<#^8'ސyZZZZ[[Ax<^?]iӦ_וVNF1::d2hZ0/8F~J^cc#N nmzyJmw th4FEE昘7sخFRtMvi5.X~xw'?(ۉz`0DEEL&6ʳuWM;V˶|<(>o(쓪jY3At:iCH۶`0 jZ%*+Emw/t:N6=VRoy5rk2ՈvbiZOe4 C@ epHNژQ(J}f)ZXR65z^ <Odd$Kls\(*X^R7 Cddddd^ZV~$[F1?tpF:Xؕ>!X.uJjY>jl-Tp+Puo\YTCb]!vDQMO׋즧vG|؂ulj$E{PV#vJ{:V4vb$ۧJ>aX&)EDD|>y-Eiiv?R9׬Qc`}^/ڥPFǣxu\H'MfYMذ4hΫ.Ttҁ,0H!!c}|P`+~_Z! w$.FBB"ˊ5 'BHvb (XWTovGmzvǦ=^o8F ՈԒHv0|J+{U'N'kEV'uRaG:| tIClW,vHSTermY:>6V#)&/f5\Pe;1j[3R!qg 5I3Ǖf][*;JDfY",2vWO@D~ioA~.~)+vGMO&X9Da)N.*KquCPүl( :ɺ?vC<@>H}FDD"@~d7URI"""mv#""#(Nރu_RSNwe,EDD~"@Xz<ޑr.u9h4A:tb{xw)މlu_R?|PR%qH..&&FFFM;bt.=JSbE*ݮpg5 R eU:%Vx^QEQx<0qjZh4lVنM:q'N|bʚ⧆fMA$T̟y}~ّ)Ffn;.Q@_c&ri QWJiCm#Y7)ԜU aGfʊ')Xy,# L03jxiAj^$iE6DDvn]OJ?Ɠx*p e&Z2>,}9,-}A9^ott(/QyױeGP MdYZp#Gjjjj{QKV/yYGD^1&^gqo&Ǐ9rS0Z~Ov4iJ)A%ӴS7ixI-qo&tTB8lذaq""Y+fU6;~gy*5DGixk*ݬL:Dk6l$ʪ?c[s/Ȣ."GS/vy< Gm9qkO`F0"t@DC 15O#fw)D=<@O48d͡jV>kke{a ̝-qWN:e &Kg['޹ ^fYh%>`lLjTfт (;kqKGfYlfIN \bܭ:\@z{ "'jmmu8MMMgΜ9}tFFunyqț <mE'ƙ;. 8OHH5&)22R<|ub---aԉ52>d  &OV Dt%qofBBB|||LLLtttTThj`DKLjiZ\bR<;.PoJL2lxS@S6wV@T@T@T@T@T@ qu!taLD t).>Gqm[b(X'F/ ! "](؊BlD IDAT'N,~ k 9FtT@ yy`BVԏQhMK y'\\Rt[:N)ZЉ]VeBH9Vj{ƦVA<(>7oӦMϿH!222**l6İ Y@kIXssp:x<~_F*ۉqǢ^7QQQ&l6t:։IX(φH<ϳ`0nKD:WHGDfYץNt74A׳zC(iAӱº,~"Xju:`0FQt:i!c”|۪9v{<׫HWHDqqq.U{CXo(bFRKz펊|Rqݢ(HH#8c l=***22`0H:JwTH֤Py^Q{37|JUy]j?(qY: (K>uZl-aUpANLa;^gJ#M|>˓vvYc˕ JE^d_RcFJHu|ҮZ8c'))؉8:1֏ $š<ձΎmzM(Rc .uv`"K2"|`RjTNLǴZ-  @ʳ!/ yWhX?(V(5bccy]p+6B!#qI^mVՊxJE:e;1j?ҋ3>nϲygC_C%z)IyNHbaf[D:R"Nv|>_@}/E:y"t^:̥% dJT*ҙL&E^:}UH@K;/`9 NdW/y?F"5i3NMvy~P૓RR( d׳bcby£#){W % "@c[4+bHINH|u^yHsaCރI7b|IB s ":J@ߧlccP|0`?x'Fv\ĔUab @Z c%o/CP=D:CP=D:CP=D:CP=D:CP=D:CP=D:CP=D:CP=D:CP=D:CP=D:Chmm ӧ|>[Ч!@;wQSS|nrv8pNKHHسguoWRRts.D:貭[ znݪlw۳gOzzѣG=OCCCZZڮ]n7|sM7=z9sfĉk= <Dz<ty~駟7.|_n attO---]z~ϧ\KTT8T.;bĈ:-h^c .hG/ePJǏSllnW=@i4o[n1L&oiiAk,@)֭ X+ҒKb =X(3}3g?LNNVEb%%%<~nݺO]ӉCB[v0 j )D:C5ASt&tBP=D:PT:HjH)D:C5AStHj*@@M:Hzt&t StHztHt j~n@8BP=D:P TA@@@5P@@5PT D:C@ D:P D:`TTU:`TTU:`@5AP=D:P TA@@@5P@@5PT D:C@ D:P D:`TTU:`TTU:`@5AP=D:P TA@@@5P@@5PT D:C@ D:P D:`TTU:`TTU:`@5AP=D:P TA@@@5P@@5PT D:C@ D:P D:`TTU:`TTU:`@5AP=D:P TA@@@5P@@5PT D:C@ D:P D:`TTU:`TTU:`@5AP=D:P TA@@@5P@@5PT D:C@ D:P D:`.^}:nTE n׮]$R@/}>z1sQFU:`TJJJӏ=JDǎQA$s^W_W2e \$t:tm\.[+݀5mڴ%=Vm_r1z=Np2ܹ߹?͛7o>v_5eCƏ*@tK?ЍvI{>Bnx=6"lct/bXG;Ζ{v:u*//ɎStA>]uUlU}*%}ѲVq뭮;w/?P~ 6|Fhx]B|_|HKZ[[kkklҽkKvءHK@|ʔ)׿Ap\n|J'PYf]y:W0ge[Q}#3gθ)S(PiMNgya?o֎y>77̴ZJA>'/^xO>dֿ?<&&fԩ,aj@A D:[<q\/޹s_4 yyy=ԩSKKKNv\,2J'!w H}X} :Çgdd|/rРA~zO>i&yxA<'eC3fرcGaĉ_|Ż3466bj%*@0t<[o͟?7~w^kС_1cF]]+ױB\6駹?`|Z"B&?ï/ȮFYQQqчz^6+KPz)ϱs,ϵOzKJJf̘q9HOO?p;`vT& \zil+ؗf{'^."""^zѣGϞ={ժUV]VqnCzse[nسg"yN~'٭\!B D: 3 KsykңF:py䑓'O\]H "^!^}GQg]y啥ÇZ׿Yn7E M~&aVn/\gyysHծ_w-;1ZpAP@Hz;wJ73p SNo~;`yv|u@PU <' QRR2u̷z+R^^'dffvL TA 6ynÆ YYY-R߿n6NZ[[+]aS:H "|jll\xW_M0A6v`ضmc=6mڴRv咮0upAt&,ܰlu:?̙3^_~9x`MO=Զm۞|M6+LT*v`PA:]N PVVfZMsΨ(yQ/w}gYf:9D:`@Xc~?`l6ݡtc/СCkAf̘qV: D:w`+~8k;ىhlynјJ[bcc?g}6==}ƍ7x^Z4 qaЗ‹LҙJN<9wLȗu֮"i Dlze 7rqW]_Uc""q6,O7l%<3nXzAvƘx-gZtKDDğ5k̚5kΝDu71 " ˶~VuȑW\qEJdGSKz R,F"Kql[#JN٫ l'(xemL^[h<OsMܛ5գUnөc}ۂfd }[ֶFex=e f,h͕K'<$?&\n{…C-..>~Sh`X^ޛ>}ҭG(6hȆ\Yv~Byyc|bw Fs|laRdb)ײOAtm |tE"yvmMAlĐ+͟?믟6mZuuo~&ZyTs\:P ҥ!sϟ?=Mv[yy'|i1D:`@Rq T"ƍ-Z{-^X6C?sR`96t:92c W_ 2䲵j5.sOT;@w9*pܚKzꩧmOos:n:V ,t ҩݻ?oknnV-!McyN2_|>uԂ$m'Sz!À; 4Sy_|;3466ʯ0!٤ASӧ?/^l6kkknQe$#lڴi=Յk'pqek&s܄9**emY9[fÁ* ,^}bV8Q{8µUv$sqsW:]"Ukke{ab~s=f͚o9Uz TAS>r+GQD:i4XGSRRv/:GS){3Oi]Jf=مYqФR"(C+sfrHV3GDDi܏ 7o.i1q&҂,{X `Ky~vvСCٱj<5d é8N/VEp9soy7|˗_Ztl&h0xIg8MhL!s|?7'%-jkk瞫j֬YW^yeLLLLLl6LFQkZV}ݻwO4iӦM3gΌV9zO>y뭷n@QeDT 8Fxرm۶%'';lýh4 YYh@0 D:%:y.d;vĉM/_ 6fѣcƌo322ꪨHŲ<+)jCzYJt8ǰ)f{??C]Uoد_~܄nbǭw2\ O?otlf3+5ɓ'GGG'''BBD>xORɔ86LADՅk'pqeE"޾l-kpkvYxedn#">;thۿʚqxyGm#Y7)ԜU vyKhc᳍9Ks6*͊;W#Ի99MN-ivyM攭c'*kj5i~9 9 PyY#k(g^I[3rn?9qP'RRR>ӌU<"u4 ^q+@/viǂDOzaRDDDX,{믿~xBX~Ħ#e7.kɼl""JsF57N"&Jm~q97e:}, d-={'9{uT}MTiZw6 |ZQA,y#A"Jݜx9{eoq&J]nȢjcjnDcsƼVbw7W^^>iҤ!Cw}lce,IGt:vVazTA.+-Xncg`:GXI^v2 1cƞ={n'OE)E{Nm^Z3ߓqZcRJk<.LUCDv#Phv/具[ ppn?#KGd֑ˢԙc&[ay\Do0 "j"XUfaIkLf!%\"oovjj-ܒ*SK+::H|1s}"\n|^`}ea:v;>>>==,ˁ^_ v"">.q=sWmNtfyo  Nwr,MM5ʥ%^BDdYy{:n~wݯ_?pltFVV&\[Mz}>|>vvAp:------pܹ366'fLRLtl&h0f( άdžfh $ gZ)21{9> ̙3v؛n)228v@ktt4h3I#ڽ)ʏ=tۆ ***6lؠtCti$yN^{ݻ799?1bDv8x7%&oF(W)NjySRZl0%3%&4HkK< |_|_{wРARMNt&I>m]C+[+@0t'UYĻk&##7ިxw~??F9S;6y]U<\<݀HwҼK;A[~ ZPϨ:u={FcȐ!Jx饗?򗿼kL2>'M[KXE) )J}:)NI.`U v))) ӦM[bSO=ɱc&MzOq\ddVRe99vrK\Zto>IrҦ?ѠlG*ʨ[Y1)znP6RI׎nJ}( l+@WT:l+}~ 64'IN(HsN iri9?93IBP0TvE eMB\_5ÁM)bjZNMM~oZ,pco U:5t s$gvvUp8l4 G P($?&Xe/^vmMMM&M֭[ϝ;7;;[>BX}N\&EB!R!AB.BB!Iؕ hlf|>fs04U0lYD wuWkk7?!??__b@ rW^y4i(]qgX Cx ?O__y啫: Vڹsʕ+ O<'$":͓ρ#ݘv3~ef;F"rQJny:Q0(8Fu9c'0~ ƈdzSSǺ A:ɤ_ξ ?я~[VJšLS3$:>A|>=X`H7=d\ub[E^cO~꣜ZQ7o;3s̝;ws=W=_?ŋvy_JNSRNd_?'%و!ҍ$f5tغtrC 6{]9- +s8Fv~o~Vя~tEZ/X@cgsl9>i? y_8H7;T)߆ `'0$IVnvt}/))/y^z)117Xx3n6y9Mc9!47;73u+"|.btjPN΂Y N扎Qjv˪=u쪨5PUQe6W/8ƪm-ə%J6kŐى\$*$$$9sTC?&ݶݜeuԹkyD7=XB;~Q!A:tH$v2{5[=:sҟ"do͉s 9qރu_niRV'IyWYu! 1F//x|su}?Қj9Zw>k#Z~BE^mywk9 IDATPP*/?f1PN%2蓏ٍ^"H|f!ȃb'WI(3hH/پv=ڻL:ED#*:f"  "8b|sDttlRFjK"1"{y Ϊ g,\e+>wgmiUQ:j! H'?<>H COfUFe"kO57FD:EnJyKWJʨ=$urR{ \ "3Z%9ܸADD>e:TQׁI"掣#= B@"$'-KLvd%q\RQՄunнiRv\$S&4Ps <;˨dZ:g<91a$$JDZ"J>wOM]^; Z3PĢq"|..g|C8>ܹsgϞ9}tII&H6#yO.~OwWlOq80aBZZZRRRRR@d¢" I:=s̩SƺK}|ݞ&(" ]\W 󧦦&''l΃RJO=l~ꩧn~Gfi+ +e" 8W5  fJb"D:H1U:5t1btj f Ayt3PPH1@ "@C*D:Hw) o)1=ڶ F :h =PP]ynL&h~6̥bo\ .{ʣZ7'3ئurD9ѨubhD=@^$Fhd yW, XC%YӺ-tjP d2gΜx<^Jp8fo߾bŊhbvyj ^Q y.v)s&d2={loosEQ $BJnϰ݂d!!!!11Q˵:[ !O 7 fh4fٜ B'ʒ2v2j&&& `Xf A"- ~uugf#=C`}X,W"ؾ`0X,@  0+]vT~RSSJmaKAVfc6Y&െMKErܕ_f~ `?KKKˍMPv~W*5:A@ "l̪&E:vHcj'I(n„ Q~E%6`b$$$l6A؝l%G: ~Z~FJ͗l? P-G:[ "]$xf9 %&&vnZ,`0BsWGEe,B\`S: As&+`~Qtv{Fe(:60mZfrF:B@ ",B!qUX|aa4u%TGXyV`oiTǺ7[r5,Ek现B>vsQH.7t|y5vTc MN`T ^`CAϰ;Ἷz>3*a_&"]h;k(aN>=H7q쐦%IX,rB?%uL&m;Rί<{Lsrr׼H0^=t1*DHlg!a0 : rYLaUOHHHr?ʟD"~YjZ9FH-e,I5%/:"e'EGT ҩRu爈]vS"mOF#3:tG'9,Qn2T`G 1@ "@C*D:tjb" T #02in%~d KuiM@0dٍP($'!Ozrd_NXe=h4*;0z¾@MF:9$ʊ],n%HrFh4B!HDHuѧs  Ҷw{ufuYSV)"|bI`jjbZpŜ9sy8FKr۟9s7~j-ґ"I$I'A~߅diդq%$I"|R.܍0ءV-)s$|>@DQ>,`9QnQLzre. Z+nPN.<~ߏny^d0`0v< ٗK3BO#xo[#ű *z$ 6sI>7|>|<^}'yd[T\D#f@s>˧$c"W4ZO \Q5~0FPPW0CHDQ|tVa@aX$3OֺEq@ME::IMӺE02vTI^QNuZ(&|>ևe/ '6KmRBAr$I^SCF/D\ᣮc U:5cZ7 F& ,m$[]fcmAhW>twi1`]ck[,ϫ{ӊޛ勭>ۛ檦<$j[."?ߨih^IC >RS>oVLȱq}t tC&":v[sBV ʳ\с@+q՜5}Ҥ'MJr;t^%rqgRLD>J?Rni{{_{}oH2ٴQIl_T/ Qs.6n"Dtj2s}iYn^:7q:jutyw頺wc;HDMPW6 9~ܰjܫ Ymy9|#':3´!;.DDbGĦ!ηWj߻z|3~sQ@kSSLd_peޥyVSz~&l)m,bƣO2ip46k{떺VԹqYi-2,㶬hDƩ%99:X{xC 9 Q:=(3YCQgלZ}C%Mt?~퓐9y$";PFD- S;~5YwMoջniϐ'>qlqj_*rߔFGhBjDnD48yRѱOE,M`%xu&/0|˅;?uM77ilmJ"3^' D=rgO&ɖ*>8px%QFa3]%3w' g {KN[lCwA򑶕<]}:@vO?OJ9n|;`_i=X' n'ΝJ!YeD?|D|;\3wN#UlF|'ӅDIjql4RX2oi#A g00yQۇs"Ґ LӆDeޜ,I<}/)7W0oKݵU[')Ņ_ػRq`ϸX`ȸ/BF?="&ˉ]sx " gRo~#b] fM^YSjvnf_)"rS Me3cGeDt#4 ¯NW-9>JWѣgoH׾u=ݰ2ωe|򌢇v=hn7PXU*y6=sf9 rP mDunϹ!i5dr:p5Dz G ZԽ_?Rɉ "'n=r&QB4bKЫĦʉ&=|vZ-'XHfvN s={Z7#J UZ7F*. B@{޾SN\)#$䴋dgdDE'"'rE}-=#OlRoBZnҩXuIq\}}}zzzZZZJJJbbbBBb1L_P($I(^9s2?)DUD$خ'%%l6*@}WZZz}iNG6yɓ/Mֱ_CK[(l#v.&UQYŢKse֤=8K97gþ5@tsfEG<]dځ@\A'gԶ~Lޫ2 ε9xڄqg3Qse;z)Kd|w[חO\b^ 3f\8#Hj_=xߔוmqR::v}zG2ι+7-8nنUOcq\D"vmXƮpu#{}hC1fʲmDL/7,8[mkXf\O5 ~ cPQQͼ%r5_[zh{m~]I^qdWմ6պik)w >;T n!"ܛT_aL<֩wzڪ9gۅs&rX3r*}4Gf59zpKߋ뜹R/iYٳ|l=_1ϭn^ڒYYK5/4~yqn_>A}~hOf9ܾ4HDY J$VhD:5t<(s~uݓWss^zrѭ"̜ؓG9S!s~}|`wՕ8nJ"wN" Q4S/no}K8A4ўLDDs/̵'rɚ>MSD>5l9%Ja6cb8N)&v-E1`G؟ԽuY]Dt|_9k;D"+74vhDǮ5D:o%ns8CcuhܲncrV.!h{Zc#;FXY U:5=䫨ѵ"/4ڧ^{Ӊ3,%"33ɒLGo8ܲM{+{9ц'Jr_5f򝻦fl9zCUuR⧽UǼ#c=t䓛:O*Zj,#7]ܮLJT{dr6*re'?-'~qQnu,Q鍟f;~ny3ot8uK$xnխ#Vծ{i(-D:5}co6ちs!t=[?_RFVȳupѬW1{]KfeЬ:O4}AnCsk~g`r7; ;I5zolvdJCՔCwN'-JpRݳ)"Iikҍl&8ȜU8NN}'UN"zfO) Q ε{8:9Λa{V#54uĞ[ 酳䅃?"2|q>}6Qћݫқ7Ӗϔd˹E«G3Iu&🝊t{k)V97<|qky^r"GzWaCҴqJQNR"fYb$"2x- č`T7pG΂Y=OϤ [݃u0AbJu>im{~'WC=7(5QiIOD"(@)kL!v߶ڗ߰m9c͖H }`W%7 O_gw {a})x{ʹ7 ܳOK[_=-bOg""qv* IDATIw/% \$M5S='Ot%+^_Zpȷ<]1Z,ז6:tTԌxd\`I;f[Zn[USgCXLSscF7ks&8k3D5E؉z|vNg K[YO֯V-'"r񝓈\7ܞɞ x֔QMw $r 2d͸*pjwa`[Y8|6tjpĬX z}}}}}}===N*))Q5ˬ}}̪l{=86`$zԈ=vx2DQ䅋O:-Bz ADQyItw'mI$^Sw`Dק$&&&$$X,ɄX B$z=Ooo3g.I8===))fYVAx7Yp/\Pxұ @%;T(r 6k6(ε슚t& ¨mK͞a9F*D:6|_ VMr\"D:"Lq]$8L^o ="yD@g4' $zbJ*6m`0 c U:5tt}}/{ZiKDt9uĉ'9[̆ms8nsXl$uI2U\nsA{,0,hݢ΄n3^yKzرtci6IO^\tt_Gww뾬StGC%Me5v <4nFHg4=jHc U:5Kʋ5?#ؽޝ8m͎=WI{֔꼵;Mo{y۸o'zFwg-K}X\Gtܟ_2ZO|hٺ$ǫ&Wn<|9%yW}nWUOܼ_?؎)K=2_y&k!Yo}ֶM׾ݏlih-7oްO} nOnnZDph4 0d6- 4Xc. i^`HLLLJBEb4F#{2l6<~*hnd=ݴ%D7P5ǧzt<'zf(-p^!(*ʝlsS/n{qȾёy˒Ӈ^&r-T^D!pd DD|[ok*""*tվ s'Bzᬗo߳մi,Y4cJqkHqm_"v^Ίܦùw8nD{MRa햕smDϴ$-;(-iMyƆm[r:)}=+i|c!'b UXKHHPo6$I?l0RRRj\ybXV՚ R]JNM2Q$ROL"ǭ-3Y&$|" Q4eixaccdv=D$I[Wmzqզڞ//_kURqs 0 >^?رƛ~g_G&=JpQByl6 X#iZјaLvl6V#K~c @ "Qۇsl'p w/Q# )DoZ|:.4{ւ7?]U^r۲+&7%N z /) (':w\-:Ev[#-9.rlܞ5`Rs 17KvȵNbg ˛iS GDMN]~Z\C5C.$۵i_0<`2r.WυD65bWS\呼MʨxӞG>EN˯,k d|KS/`$rrj`0O0Aȧ>\c\CSA}MLd=C E.iiΥ/0u<$+Z^ߙSRԸze5{k'?THSLUDT\l.ydM#""?;yrgYL}+M,%"/NkTrC)uT͛\_5ߐNDp~>h#<|}97$&"r?rΫ|WA?F#c5n+΅B!_4?=BہW9C}X,< xժ0qO|BP ^ԩS%%%k=ݧn_EQwsS6=>wؙN'|^g|>3lrEOtw'mI$/:'_=B=ݽK=S=M IH<ۮiÇos99oW^t^7RRR,|`0ȫJtDtVUUegkycyn5qMosYnݜ9snJw!B}4~e ++hys_HMҲBZam Hksu߉Ns%"ϡ憓(Vy^$^.)P=dm1Ac~HxPX3gRY:Wirⲷ/ +BOipnP c1p8,;v[~%:&!!--Vyڜ\Jmq :̽#쎹-?;uϾB>ۯ`00\ ì,V]ڔKq%K1*D:q9FeYN'. y6cxkrQH$6(C BH`C@ fA= . LR`PPo{I|c ߣm@@H&Ϲ;n \T%#Vb P t C@MMcyr=ZFƮ5ZP"8;rq]{E:tHe"؁D:H'|ؠh4Lo{{{{{{ϝ;/b $Iy!X}+Vh݊K<ϛfAؕ:RRRеn)^A*trJ0Lfj GD,kǐpiX6A% jPtu٨l6L `0g"vZ1$55U&\ٟj `Zfl4XdH'3 lb $y@ _y&Lu.+ű 'G:W̥5x"xt]; p8BrNumעcuSF^pXfNB!tHG F6P9"lZ7ɩNӰ0 N`Du%Tgc7 MuVU&\gM>%y.FF:L,[1,M4_G'iT@ U:59+Ma1LZ7ᒍ ~Fs 7WF;J5̥%T JJtj]C (@0 JA]C`4]C%T`G WPBPH*h`G HJt Ht U:t PP%^Ft U:PB@ vktH;J5D:t s@ U:5tkҁ"(@F;J5 tj@P (@@ U:5Qa J0Q!ҁtj]+(!A]C`4]C%T`G W@]CPP%"(!t `4]\:PB@ "tH;J5D:t *D:5TF;J5D:PB@ vkx%D:5tkvkt*(@0 Jtj@P (@@ U:5Qa`4@P%T`G HJtj]C (@0PPH*(!t `4]+(Jt U:t PP%^A @ "t%"(J;J5 "D:5TF;J5D:PB@ vkx D:5T@ U:5Q!ҁ"(@F;J5̥%T JJtj]C (@0 JA]C`4]C%T`G WPBPH*h`G HJ2f={o6O>d8ֺE'$IwnZo^[4wƌ%K~Ϗs`_ Buuu q`Ą)Sx<s=u |mM&SwwfӶU/~'gϞAs%$$h.A.6'>)Sh$---N?`ݺuJKK_~>ر뮻} #yx|l=vJD(̾P 'N8ne6-Z/k. ,ؿ'"јbh۪'Offf}b{ソomheſ l[U@yg5<93tcNQ ,ǔ >i*+`%:9z Vg D:(aS((jݜxePx΍`E#YTg\qtcN^RX>7s~p ׺EW"@4"Zh||$o9ϡP`lE,#,ϨӺ]rUn֍W3$-_"@4(cn"z#@B$$0=?ʔ9:KXrU>FF(qY rD؃p0 b"@Cyt^ lÁ.Qq!qOT[`| v9~!B%I^t[`%q[vp8\"'D"vo8˩غCԱkM9[cWE.7BǮ]$uV/[Vus1m~zYr8*vIZ"8LtnIx<=;kș)PGJ*jh=yK'μdo͉sl 9qރuu]l-:xҵ-M[ju ƩdyS*ll-QϞ ^%uxKSh DQQd[Mp=nDD79'FDkN\AmgDB;U:EX Dkɓ<ںAkn75+o "I$"_ b |,o퉓"Ƣ0 tc B$z=Ooo3gN:URR{&34""7)z/oJ r5LQi$5)y{&<4xg@o#D tgUF5| 6郭> ):u~S<_dm PLDD&m8y1YSBC8ApP餄VU]B]rʠ!i 봶!5jja) h6f ȕI 6(IDATx<ۭi6G*L Ԣ[Ҵ WUOqqXI`y$t@֋|u?me]0"zɎn]$ԱKQvO?2bO(SG/:(RwG Q~^^xRɅȅ#KxM+}Iܓ6 *`"}wI/DDD8BQ~1s+}lKX;1e&M~7x "ruڰDQ=PE>4̒>\dK0$"-vE$Q#$zouvh>]+JF߷aIPy*6鎈%RQ=[꛻SXAS BGjQ&݇_jKM'[7j ;;Ϟmu_>9b"5<@0ضLH;o"Sh?[kϞmyI.ytH?P LߥJ_U_9^C;%E^j0/d3@EI7"Rsۃ;OFNT6#7T?g;[/hr;"'!#C0:"! T&0hgȶ}aD'\@T6tE9 ""Ν~kl2g`e0yjDdsW|$aQw7_8^)hOb D?tcX#ߦ""[.\9{b_6mD.V;߼fb~mLwվ/~u[q8xQL; ^疊AiO(m}qƆώ7?7OH7NssM/̋o/"Wrr$_kH_z|͟M A{KKJJKZfc|k:]'ZW/~h֚Ρ58{)+ zUo-_w,__VUHDE$xe%:{:䭊-?d>Ip,އ$`NC^|<~h>y࡟z]&rڍdK[#*dO|Z6{)gySE.~nmlŜg0]||K<^GDy,@! 8_"c7:7_4@Q ~տ덧=UjvYTo[ސ7_;SdDNQ*"^޾{Tdgk>^)őmUEv}ÉGa "On<^%g{7v}`R (Jw~ި+7=+.Dtգ}_Rz$l{Ԃ"-n9|䋟?WUR[hUI (|>_AAqݚjk-)[ V#vKfO86mGVWWֽíkkU Os# @vSrW9?wZ~=S vZq_X<8 i{H:``H: G}wG}U=H: G`yy,??W_Fk׮]neΝx 0>$.]f͚TϨb4` bܹsϜ93Mˊ 09n>}z^t:ӦMO9B$E9tݻg̘QXXx\ԩSO zeld@freaknet.org # # Redistribution AND use is allowed according to the terms of the New # BSD license. find_path(LIBDNET_INCLUDE_DIR ${libdnet_h} ${CMAKE_INCLUDE_PATH}) find_path(LIBDNET_LIB_DIR ${libdnet} ${CMAKE_LIBRARY_PATH}) find_library(LIBDNET_LIBRARY NAMES ${libdnet} PATH ${CMAKE_LIBRARY_PATH}) if(LIBDNET_INCLUDE_DIR AND LIBDNET_LIB_DIR AND LIBDNET_LIBRARY ) message(STATUS "Found Libdnet.") if(NOT ${INCLUDE_DIR} MATCHES ${LIBDNET_INCLUDE_DIR}) include_directories(${LIBDNET_INCLUDE_DIR}) set(INCLUDE_DIR "${INCLUDE_DIR} ${LIBDNET_INCLUDE_DIR}") endif(NOT ${INCLUDE_DIR} MATCHES ${LIBDNET_INCLUDE_DIR}) if(NOT ${LIB_DIR} MATCHES ${LIBDNET_LIB_DIR}) link_directories(${LIBDNET_LIB_DIR}) set(LIB_DIR "${LIB_DIR} ${LIBDNET_LIB_DIR}") endif(NOT ${LIB_DIR} MATCHES ${LIBDNET_LIB_DIR}) else(NOT LIBDNET_INCLUDE_DIR OR NOT LIBDNET_LIB_DIR OR NOT LIBDNET_LIBRARY) message(FATAL_ERROR "Could not find libdnet! Please Visit: http://libdnet.sourceforge.net/ or see in the arpon 'INSTALL' file.") endif(LIBDNET_INCLUDE_DIR AND LIBDNET_LIB_DIR AND LIBDNET_LIBRARY) ArpON-2.0/cmake_modules/FindNET.cmake000644 000765 000024 00000002505 11400024563 020037 0ustar00spikeystaff000000 000000 # FindNET search and find the libnet library path # # The following variables are set: # CMAKE_C_FLAGS - flags to add to the C compiler for build arpon # CMAKE_INCLUDE - include path Cflag # CMAKE_LIBS - library path Cflag # # Copyright 2010 zeld@freaknet.org # # Redistribution AND use is allowed according to the terms of the New # BSD license. find_path(LIBNET_INCLUDE_DIR ${libnet_h} ${CMAKE_INCLUDE_PATH}) find_path(LIBNET_LIB_DIR ${libnet} ${CMAKE_LIBRARY_PATH}) find_library(LIBNET_LIBRARY NAMES ${libnet} PATH ${CMAKE_LIBRARY_PATH}) if(LIBNET_INCLUDE_DIR AND LIBNET_LIB_DIR AND LIBNET_LIBRARY ) message(STATUS "Found Libnet.") if(NOT ${INCLUDE_DIR} MATCHES ${LIBNET_INCLUDE_DIR}) set(INCLUDE_DIR "${INCLUDE_DIR} ${LIBNET_INCLUDE_DIR}") include_directories(${LIBNET_INCLUDE_DIR}) endif(NOT ${INCLUDE_DIR} MATCHES ${LIBNET_INCLUDE_DIR}) if(NOT ${LIB_DIR} MATCHES ${LIBNET_LIB_DIR}) link_directories(${LIBNET_LIB_DIR}) set(LIB_DIR "${LIB_DIR} ${LIBNET_LIB_DIR}") endif(NOT ${LIB_DIR} MATCHES ${LIBNET_LIB_DIR}) else(NOT LIBNET_INCLUDE_DIR OR NOT LIBNET_LIB_DIR OR NOT LIBNET_LIBRARY) message(FATAL_ERROR "Could not find libnet-1.1! Please Visit: http://libnet.sourceforge.net/ or see in the arpon 'INSTALL' file") endif(LIBNET_INCLUDE_DIR AND LIBNET_LIB_DIR AND LIBNET_LIBRARY) ArpON-2.0/cmake_modules/FindPCAP.cmake000644 000765 000024 00000002423 11400024563 020133 0ustar00spikeystaff000000 000000 # FindPCAP search and find the libpcap library path # # The following variables are set: # CMAKE_C_FLAGS - flags to add to the C compiler for build arpon # CMAKE_INCLUDE - include path Cflag # CMAKE_LIBS - library path Cflag # # Copyright 2010 zeld@freaknet.org # # Redistribution AND use is allowed according to the terms of the New # BSD license. find_path(PCAP_INCLUDE_DIR ${libpcap_h} ${CMAKE_INCLUDE_PATH}) find_path(PCAP_LIB_DIR ${libpcap} ${CMAKE_LIBRARY_PATH}) find_library(PCAP_LIBRARY NAMES ${libpcap} PATH ${CMAKE_LIBRARY_PATH}) if(PCAP_INCLUDE_DIR AND PCAP_LIB_DIR AND PCAP_LIBRARY ) message(STATUS "Found Libpcap.") if(NOT ${INCLUDE_DIR} MATCHES ${PCAP_INCLUDE_DIR}) include_directories(${PCAP_INCLUDE_DIR}) set(INCLUDE_DIR "${INCLUDE_DIR} ${PCAP_INCLUDE_DIR}") endif(NOT ${INCLUDE_DIR} MATCHES ${PCAP_INCLUDE_DIR}) if(NOT ${LIB_DIR} MATCHES ${PCAP_LIB_DIR}) link_directories(${PCAP_LIB_DIR}) set(LIB_DIR "${LIB_DIR} ${PCAP_LIB_DIR}") endif(NOT ${LIB_DIR} MATCHES ${PCAP_LIB_DIR}) else(NOT PCAP_INCLUDE_DIR OR NOT PCAP_LIB_DIR OR NOT PCAP_LIBRARY) message(FATAL_ERROR " Libpcap not found! Please visit http://www.tcpdump.org/ or see in the arpon 'INSTALL' file.") endif(PCAP_INCLUDE_DIR AND PCAP_LIB_DIR AND PCAP_LIBRARY) ArpON-2.0/cmake_modules/FindPthread.cmake000644 000765 000024 00000002613 11400024563 021000 0ustar00spikeystaff000000 000000 # FindPhtread search and find the libphtread library path and header path # # The following variables are set: # CMAKE_C_FLAGS - flags to add to the C compiler for build arpon # CMAKE_INCLUDE - include path Cflag # CMAKE_LIBS - library path Cflag # # Copyright 2010 zeld@freaknet.org # # Redistribution AND use is allowed according to the terms of the New # BSD license. find_path(PTHREAD_INCLUDE_DIR ${libpthread_h} ${CMAKE_INCLUDE_PATH}) find_path(PTHREAD_LIB_DIR ${libpthread} ${CMAKE_LIBRARY_PATH}) find_library(PTHREAD_LIBRARY NAMES ${libpthread} PATH ${CMAKE_LIBRARY_PATH}) if(PTHREAD_INCLUDE_DIR AND PTHREAD_LIB_DIR AND PTHREAD_LIBRARY ) message(STATUS "Found Libphtread.") if(NOT ${INCLUDE_DIR} MATCHES ${PTHREAD_INCLUDE_DIR}) include_directories(${PTHREAD_INCLUDE_DIR}) set(INCLUDE_DIR "${INCLUDE_DIR} ${PTHREAD_INCLUDE_DIR}") endif(NOT ${INCLUDE_DIR} MATCHES ${PTHREAD_INCLUDE_DIR}) if(NOT ${LIB_DIR} MATCHES ${PTHREAD_LIB_DIR}) link_directories(${PTHREAD_LIB_DIR}) set(LIB_DIR "${LIB_DIR} ${PTHREAD_LIB_DIR}") endif(NOT ${LIB_DIR} MATCHES ${PTHREAD_LIB_DIR}) else(NOT PTHREAD_INCLUDE_DIR OR NOT PTHREAD_LIB_DIR OR NOT PTHREAD_LIBRARY) message(FATAL_ERROR " Libpthread not found! \n Please visit http://www.gnu.org/software/libc/libc.html or see in the arpon 'INSTALL' file.") endif(PTHREAD_INCLUDE_DIR AND PTHREAD_LIB_DIR AND PTHREAD_LIBRARY) ArpON-2.0/cmake_modules/FindSystem.cmake000644 000765 000024 00000007157 11403216216 020706 0ustar00spikeystaff000000 000000 # FindSystem match the operating system and set some # CFLAGS for compile the source code. # # The following variables are set: # CMAKE_C_FLAGS - flags to add to the C compiler for buil arpon # # Copyright 2010 zeld@freaknet.org # # Redistribution AND use is allowed according to the terms of the New # BSD license. macro( DNETH_DEBIAN_UBUNTU ) set( ID_RELEASE ) find_program(LSB_RELEASE NAMES lsb_release PATHS /bin /sbin /usr/bin /usr/sbin /usr/local/bin /usr/local/sbin) if(LSB_RELEASE) execute_process(COMMAND ${LSB_RELEASE} -i OUTPUT_VARIABLE ID_RELEASE) string(REGEX REPLACE ".*:" "" ID_RELEASE "${ID_RELEASE}") if(${ID_RELEASE} MATCHES "Ubuntu") message(STATUS "Linux Distro: ${ID_RELEASE}") set( UBUNTU TRUE ) add_definitions( -DDEBIAN ) elseif(${ID_RELEASE} MATCHES "Debian") message(STATUS "Linux Distro: ${ID_RELEASE}") set( DEBIAN TRUE ) add_definitions( -DDEBIAN ) endif(${ID_RELEASE} MATCHES "Ubuntu") endif( LSB_RELEASE ) endmacro( DNETH_DEBIAN_UBUNTU ) macro( SETHEADERNAME ) if( APPLE OR UNIX) set(libnet_h "libnet.h") if( UBUNTU OR DEBIAN ) set(libdnet_h "dumbnet.h") else() set(libdnet_h "dnet.h") endif( UBUNTU OR DEBIAN ) set(libpcap_h "pcap.h") set(libpthread_h "pthread.h") elseif( WIN32 ) message(FATAL_ERROR "Windows Operating System Not Supported") else( APPLE OR UNIX ) message(FATAL_ERROR "Unknown OS! Unable to detect system library.") endif( APPLE OR UNIX) endmacro( SETHEADERNAME ) macro( SETLIBNAME ) if( APPLE ) set(libnet "libnet.a") set(libdnet "libdnet.a") set(libpcap "libpcap.a") set(libpthread "libpthread.dylib") elseif( UNIX ) set(libnet "libnet.a") set(libpcap "libpcap.a") set(libpthread "libpthread.a") if( UBUNTU OR DEBIAN ) set(libdnet "libdumbnet.a") else() set(libdnet "libdnet.a") endif(UBUNTU OR DEBIAN) elseif( WIN32 ) message(FATAL_ERROR "Windows Operating System Not Supported") else( APPLE ) message(FATAL_ERROR "Unknown OS! Unable to detect system library.") endif( APPLE ) endmacro( SETLIBNAME ) if( APPLE ) # Mac OS X specific code message(STATUS "Operating System Found: OSX") SETHEADERNAME() SETLIBNAME() # include_directories("/opt/local/include") # link_directories("/opt/local/lib/") #set(INCLUDE_DIR "${INCLUDE_DIR} /opt/local/include/") #set(LIB_DIR "${LIB_DIR} /opt/local/lib/") elseif( UNIX ) if(${CMAKE_SYSTEM_NAME} MATCHES "FreeBSD") # FreeBSD specific code message(STATUS "Operating System Found: FreeBSD") SETHEADERNAME() SETLIBNAME() endif(${CMAKE_SYSTEM_NAME} MATCHES "FreeBSD") if(${CMAKE_SYSTEM_NAME} MATCHES "NetBSD") # NetBSD specific code message(STATUS "Operating System Found: NetBSD") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DNETBSD") SETHEADERNAME() SETLIBNAME() endif(${CMAKE_SYSTEM_NAME} MATCHES "NetBSD") if(${CMAKE_SYSTEM_NAME} MATCHES "OpenBSD") # OpenBSD specific code message(STATUS "Operating System Found: OpenBSD") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DOPENBSD") SETHEADERNAME() SETLIBNAME() endif(${CMAKE_SYSTEM_NAME} MATCHES "OpenBSD") if(${CMAKE_SYSTEM_NAME} MATCHES "Linux") # Linux specific code message(STATUS "Operating System: GNU/Linux") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DLINUX") DNETH_DEBIAN_UBUNTU() SETHEADERNAME() SETLIBNAME() endif(${CMAKE_SYSTEM_NAME} MATCHES "Linux") elseif( WIN32 ) message(FATAL_ERROR "Windows Operating System Not Supported") else( APPLE ) message(FATAL_ERROR "Operating System Not Supported") endif( APPLE )